summaryrefslogtreecommitdiffstats
path: root/lldb/source/Core/Address.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Address.cpp')
-rw-r--r--lldb/source/Core/Address.cpp875
1 files changed, 875 insertions, 0 deletions
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
new file mode 100644
index 00000000000..e2481e133fa
--- /dev/null
+++ b/lldb/source/Core/Address.cpp
@@ -0,0 +1,875 @@
+//===-- Address.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static size_t
+ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
+{
+ if (exe_scope == NULL)
+ return 0;
+
+ lldb::AddressType addr_type = eAddressTypeInvalid;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ Process *process = exe_scope->CalculateProcess();
+
+ if (process && process->IsAlive())
+ {
+ addr = address.GetLoadAddress(process);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeLoad;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = address.GetFileAddress();
+ if (addr != LLDB_INVALID_ADDRESS)
+ addr_type = eAddressTypeFile;
+ }
+
+ if (addr_type == eAddressTypeInvalid)
+ return false;
+
+ Target *target = exe_scope->CalculateTarget();
+ if (target)
+ {
+ Error error;
+ return target->ReadMemory (addr_type, addr, dst, dst_len, error, NULL);
+ }
+ return 0;
+}
+
+static bool
+GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
+{
+ byte_order = eByteOrderInvalid;
+ addr_size = 0;
+ if (exe_scope == NULL)
+ return false;
+
+ Process *process = exe_scope->CalculateProcess();
+ if (process)
+ {
+ byte_order = process->GetByteOrder();
+ addr_size = process->GetAddressByteSize();
+ }
+
+ if (byte_order == eByteOrderInvalid || addr_size == 0)
+ {
+ Module *module = address.GetModule();
+ if (module)
+ {
+ byte_order = module->GetArchitecture().GetDefaultEndian();
+ addr_size = module->GetArchitecture().GetAddressByteSize();
+ }
+ }
+ return byte_order != eByteOrderInvalid && addr_size != 0;
+}
+
+static uint64_t
+ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
+{
+ uint64_t uval64 = 0;
+ if (exe_scope == NULL || byte_size > sizeof(uint64_t))
+ {
+ success = false;
+ return 0;
+ }
+ uint64_t buf;
+
+ success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
+ if (success)
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
+ uint32_t offset = 0;
+ uval64 = data.GetU64(&offset);
+ }
+ else
+ success = false;
+ }
+ return uval64;
+}
+
+static bool
+ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
+{
+ if (exe_scope == NULL)
+ return false;
+
+
+ bool success = false;
+ addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
+ if (success)
+ {
+ Process *process = exe_scope->CalculateProcess();
+ if (process && process->IsAlive())
+ {
+ if (!process->ResolveLoadAddress (deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(deref_addr);
+ }
+ }
+ else
+ {
+ Target *target = exe_scope->CalculateTarget();
+ if (target == NULL)
+ return false;
+
+ if (!target->GetImages().ResolveFileAddress(deref_addr, deref_so_addr))
+ {
+ deref_so_addr.SetSection(NULL);
+ deref_so_addr.SetOffset(deref_addr);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool
+DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
+{
+ if (exe_scope == NULL)
+ return 0;
+ std::vector<uint8_t> buf(byte_size, 0);
+
+ if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (buf.data(), buf.size(), byte_order, addr_size);
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatHex, // Print as characters
+ buf.size(), // Size of item
+ 1, // Items count
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static size_t
+ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
+{
+ if (exe_scope == NULL)
+ return 0;
+ const size_t k_buf_len = 256;
+ char buf[k_buf_len+1];
+ buf[k_buf_len] = '\0'; // NULL terminate
+
+ // Byte order and adderss size don't matter for C string dumping..
+ DataExtractor data (buf, sizeof(buf), eByteOrderHost, 4);
+ size_t total_len = 0;
+ size_t bytes_read;
+ Address curr_address(address);
+ strm->PutChar ('"');
+ while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
+ {
+ size_t len = strlen(buf);
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+
+ 0); // bitfield bit offset
+
+ total_len += bytes_read;
+
+ if (len < k_buf_len)
+ break;
+ curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
+ }
+ strm->PutChar ('"');
+ return total_len;
+}
+
+Address::Address () :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+}
+
+Address::Address (const Address& rhs) :
+ m_section (rhs.m_section),
+ m_offset (rhs.m_offset)
+{
+}
+
+Address::Address (const Section* section, addr_t offset) :
+ m_section (section),
+ m_offset (offset)
+{
+}
+
+Address::Address (addr_t address, const SectionList * sections) :
+ m_section (NULL),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+ ResolveAddressUsingFileSections(address, sections);
+}
+
+Address::~Address ()
+{
+}
+
+
+const Address&
+Address::operator= (const Address& rhs)
+{
+ if (this != &rhs)
+ {
+ m_section = rhs.m_section;
+ m_offset = rhs.m_offset;
+ }
+ return *this;
+}
+
+bool
+Address::IsValid() const
+{
+ return m_offset != LLDB_INVALID_ADDRESS;
+}
+
+bool
+Address::IsSectionOffset() const
+{
+ return m_section != NULL && IsValid();
+}
+
+bool
+Address::ResolveAddressUsingFileSections (addr_t addr, const SectionList *sections)
+{
+ if (sections)
+ m_section = sections->FindSectionContainingFileAddress(addr).get();
+ else
+ m_section = NULL;
+
+ if (m_section != NULL)
+ {
+ assert( m_section->ContainsFileAddress(addr) );
+ m_offset = addr - m_section->GetFileAddress();
+ return true; // Successfully transformed addr into a section offset address
+ }
+
+ m_offset = addr;
+ return false; // Failed to resolve this address to a section offset value
+}
+
+//bool
+//Address::ResolveAddressUsingLoadSections (addr_t addr, const SectionList *sections)
+//{
+// if (sections)
+// m_section = sections->FindSectionContainingLoadAddress(addr).get();
+// else
+// m_section = NULL;
+//
+// if (m_section != NULL)
+// {
+// assert( m_section->ContainsLoadAddress(addr) );
+// m_offset = addr - m_section->GetLoadBaseAddress();
+// return true; // Successfully transformed addr into a section offset address
+// }
+//
+// m_offset = addr;
+// return false; // Failed to resolve this address to a section offset value
+//}
+//
+Module *
+Address::GetModule () const
+{
+ if (m_section)
+ return m_section->GetModule();
+ return NULL;
+}
+
+const Section*
+Address::GetSection () const
+{
+ return m_section;
+}
+
+
+//addr_t
+//Address::Address() const
+//{
+// addr_t addr = GetLoadAddress();
+// if (addr != LLDB_INVALID_ADDRESS)
+// return addr;
+// return GetFileAddress();
+//}
+//
+
+addr_t
+Address::GetFileAddress () const
+{
+ if (m_section != NULL)
+ {
+ addr_t sect_file_addr = m_section->GetFileAddress();
+ if (sect_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ // Section isn't resolved, we can't return a valid file address
+ return LLDB_INVALID_ADDRESS;
+ }
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_file_addr + m_offset;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetLoadAddress (Process *process) const
+{
+ if (m_section != NULL)
+ {
+ if (process)
+ {
+ addr_t sect_load_addr = m_section->GetLoadBaseAddress (process);
+
+ if (sect_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_load_addr + m_offset;
+ }
+ }
+ // The section isn't resolved or no process was supplied so we can't
+ // return a valid file address.
+ return LLDB_INVALID_ADDRESS;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetOffset () const
+{
+ return m_offset;
+}
+
+bool
+Address::SetOffset (addr_t offset)
+{
+ bool changed = m_offset != offset;
+ m_offset = offset;
+ return changed;
+}
+
+void
+Address::SetSection (const Section* section)
+{
+ m_section = section;
+}
+
+void
+Address::Clear()
+{
+ m_section = NULL;
+ m_offset = LLDB_INVALID_ADDRESS;
+}
+
+
+bool
+Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style) const
+{
+ // If the section was NULL, only load address is going to work.
+ if (m_section == NULL)
+ style = DumpStyleLoadAddress;
+
+ Process *process = NULL;
+ if (exe_scope)
+ process = exe_scope->CalculateProcess();
+ int addr_size = sizeof (addr_t);
+ if (process)
+ addr_size = process->GetAddressByteSize ();
+
+ lldb_private::Address so_addr;
+
+ switch (style)
+ {
+ case DumpStyleSectionNameOffset:
+ if (m_section != NULL)
+ {
+ m_section->DumpName(s);
+ s->Printf (" + %llu", m_offset);
+ }
+ else
+ {
+ s->Printf("0x%16.16llx", m_offset);
+ }
+ break;
+
+ case DumpStyleSectionPointerOffset:
+ s->Printf("(Section *)%.*p + 0x%16.16llx", (int)sizeof(void*) * 2, m_section, m_offset);
+ break;
+
+ case DumpStyleModuleWithFileAddress:
+ s->Printf("%s[", m_section->GetModule()->GetFileSpec().GetFilename().AsCString());
+ // Fall through
+ case DumpStyleFileAddress:
+ {
+ addr_t file_addr = GetFileAddress();
+ if (file_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style);
+ return false;
+ }
+ s->Address (file_addr, addr_size);
+ if (style == DumpStyleModuleWithFileAddress)
+ s->PutChar(']');
+ }
+ break;
+
+ case DumpStyleLoadAddress:
+ {
+ addr_t load_addr = GetLoadAddress (process);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style);
+ return false;
+ }
+ s->Address (load_addr, addr_size);
+ }
+ break;
+
+ case DumpStyleResolvedDescription:
+ if (IsSectionOffset())
+ {
+ lldb::AddressType addr_type = eAddressTypeLoad;
+ addr_t addr = GetLoadAddress (process);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ addr = GetFileAddress();
+ addr_type = eAddressTypeFile;
+ }
+
+ uint32_t pointer_size = 4;
+ lldb_private::Module *module = GetModule();
+ if (process)
+ pointer_size = process->GetAddressByteSize();
+ else if (module)
+ pointer_size = module->GetArchitecture().GetAddressByteSize();
+
+ bool showed_info = false;
+ const Section *section = GetSection();
+ if (section)
+ {
+ SectionType sect_type = section->GetSectionType();
+ switch (sect_type)
+ {
+ case eSectionTypeDataCString:
+ // Read the C string from memory and display it
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, *this, s);
+ break;
+
+ case eSectionTypeDataCStringPointers:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(": ");
+#endif
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCMessageRefs:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ if (so_addr.IsSectionOffset())
+ {
+ lldb_private::SymbolContext func_sc;
+ process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ func_sc);
+ if (func_sc.function || func_sc.symbol)
+ {
+ showed_info = true;
+#if VERBOSE_OUTPUT
+ s->PutCString ("(objc_msgref *) -> { (func*)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+#else
+ s->PutCString ("{ ");
+#endif
+ Address cstr_addr(*this);
+ cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
+ func_sc.DumpStopContext(s, process, so_addr, true);
+ if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("), (char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" (");
+#else
+ s->PutCString(", ");
+#endif
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+#if VERBOSE_OUTPUT
+ s->PutCString(") }");
+#else
+ s->PutCString(" }");
+#endif
+ }
+ }
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCCFStrings:
+ {
+ Address cfstring_data_addr(*this);
+ cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size));
+ if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(CFString *) ");
+ cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" -> @");
+#else
+ s->PutChar('@');
+#endif
+ if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription))
+ showed_info = true;
+ }
+ }
+ break;
+
+ case eSectionTypeData4:
+ // Read the 4 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint32_t) ");
+ DumpUInt (exe_scope, *this, 4, s);
+ break;
+
+ case eSectionTypeData8:
+ // Read the 8 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint64_t) ");
+ DumpUInt (exe_scope, *this, 8, s);
+ break;
+
+ case eSectionTypeData16:
+ // Read the 16 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint128_t) ");
+ DumpUInt (exe_scope, *this, 16, s);
+ break;
+
+ case eSectionTypeDataPointers:
+ // Read the pointer data and display it
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ s->PutCString ("(void *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+
+ showed_info = true;
+ if (so_addr.IsSectionOffset())
+ {
+ lldb_private::SymbolContext pointer_sc;
+ process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ pointer_sc);
+ if (pointer_sc.function || pointer_sc.symbol)
+ {
+ s->PutCString(": ");
+ pointer_sc.DumpStopContext(s, process, so_addr, false);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (!showed_info)
+ {
+ if (module)
+ {
+ lldb_private::SymbolContext sc;
+ module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ bool show_stop_context = true;
+ if (sc.function == NULL && sc.symbol != NULL)
+ {
+ // If we have just a symbol make sure it is in the right section
+ if (sc.symbol->GetAddressRangePtr())
+ {
+ if (sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() != GetSection())
+ show_stop_context = false;
+ }
+ }
+ if (show_stop_context)
+ {
+ // We have a function or a symbol from the same
+ // sections as this address.
+ sc.DumpStopContext(s, process, *this, false);
+ }
+ else
+ {
+ // We found a symbol but it was in a different
+ // section so it isn't the symbol we should be
+ // showing, just show the section name + offset
+ Dump (s, exe_scope, DumpStyleSectionNameOffset);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style);
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+//Stream& operator << (Stream& s, const Address& so_addr)
+//{
+// so_addr.Dump(&s, Address::DumpStyleSectionNameOffset);
+// return s;
+//}
+//
+void
+Address::CalculateSymbolContext (SymbolContext *sc)
+{
+ sc->Clear();
+ // Absolute addresses don't have enough information to reconstruct even their target.
+ if (m_section == NULL)
+ return;
+
+ if (m_section->GetModule())
+ {
+ sc->module_sp = m_section->GetModule()->GetSP();
+ if (sc->module_sp)
+ sc->module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextEverything, *sc);
+ }
+}
+
+void
+Address::DumpSymbolContext (Stream *s)
+{
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ sc.Dump (s, NULL);
+}
+
+void
+Address::DumpDebug(Stream *s) const
+{
+ *s << (void *)this << ": " << "Address";
+ if (m_section != NULL)
+ {
+ *s << ", section = " << (void *)m_section << " (" << m_section->GetName() << "), offset = " << m_offset;
+ }
+ else
+ {
+ *s << ", vm_addr = " << m_offset;
+ }
+ s->EOL();
+}
+
+int
+Address::CompareFileAddress (const Address& a, const Address& b)
+{
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+int
+Address::CompareLoadAddress (const Address& a, const Address& b, Process *process)
+{
+ assert (process != NULL);
+ addr_t a_load_addr = a.GetLoadAddress (process);
+ addr_t b_load_addr = b.GetLoadAddress (process);
+ if (a_load_addr < b_load_addr)
+ return -1;
+ if (a_load_addr > b_load_addr)
+ return +1;
+ return 0;
+}
+
+int
+Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
+{
+ Module *a_module = a.GetModule ();
+ Module *b_module = b.GetModule ();
+ if (a_module < b_module)
+ return -1;
+ if (a_module > b_module)
+ return +1;
+ // Modules are the same, just compare the file address since they should
+ // be unique
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+size_t
+Address::MemorySize () const
+{
+ // Noting special for the memory size of a single Address object,
+ // it is just the size of itself.
+ return sizeof(Address);
+}
+
+
+/// The only comparisons that make sense are the load addresses
+//bool
+//lldb::operator< (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr < rhs_addr;
+//}
+//
+//bool
+//lldb::operator<= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr <= rhs_addr;
+//}
+//
+//bool
+//lldb::operator> (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr > rhs_addr;
+//}
+//
+//bool
+//lldb::operator>= (const Address& lhs, const Address& rhs)
+//{
+// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
+// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
+//
+// if (lhs_addr == rhs_addr)
+// {
+// lhs_addr = lhs.GetFileAddress();
+// rhs_addr = rhs.GetFileAddress();
+// }
+// return lhs_addr >= rhs_addr;
+//}
+//
+
+// The operator == checks for exact equality only (same section, same offset)
+bool
+lldb_private::operator== (const Address& a, const Address& rhs)
+{
+ return a.GetSection() == rhs.GetSection() &&
+ a.GetOffset() == rhs.GetOffset();
+}
+// The operator != checks for exact inequality only (differing section, or
+// different offset)
+bool
+lldb_private::operator!= (const Address& a, const Address& rhs)
+{
+ return a.GetSection() != rhs.GetSection() ||
+ a.GetOffset() != rhs.GetOffset();
+}
+
+bool
+Address::IsLinkedAddress () const
+{
+ return m_section && m_section->GetLinkedSection();
+}
+
+
+void
+Address::ResolveLinkedAddress ()
+{
+ if (m_section)
+ {
+ const Section *linked_section = m_section->GetLinkedSection();
+ if (linked_section)
+ {
+ m_offset += m_section->GetLinkedOffset();
+ m_section = linked_section;
+ }
+ }
+}
OpenPOWER on IntegriCloud