blob: e2481e133fa47035a87124c593e131f2976de772 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Address.cpp ---------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Core/Address.h"
11#include "lldb/Core/Module.h"
12#include "lldb/Core/Section.h"
13#include "lldb/Symbol/ObjectFile.h"
14#include "lldb/Target/Process.h"
15#include "lldb/Target/Target.h"
16
17using namespace lldb;
18using namespace lldb_private;
19
20static size_t
21ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
22{
23 if (exe_scope == NULL)
24 return 0;
25
26 lldb::AddressType addr_type = eAddressTypeInvalid;
27 addr_t addr = LLDB_INVALID_ADDRESS;
28
29 Process *process = exe_scope->CalculateProcess();
30
31 if (process && process->IsAlive())
32 {
33 addr = address.GetLoadAddress(process);
34 if (addr != LLDB_INVALID_ADDRESS)
35 addr_type = eAddressTypeLoad;
36 }
37
38 if (addr == LLDB_INVALID_ADDRESS)
39 {
40 addr = address.GetFileAddress();
41 if (addr != LLDB_INVALID_ADDRESS)
42 addr_type = eAddressTypeFile;
43 }
44
45 if (addr_type == eAddressTypeInvalid)
46 return false;
47
48 Target *target = exe_scope->CalculateTarget();
49 if (target)
50 {
51 Error error;
52 return target->ReadMemory (addr_type, addr, dst, dst_len, error, NULL);
53 }
54 return 0;
55}
56
57static bool
58GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
59{
60 byte_order = eByteOrderInvalid;
61 addr_size = 0;
62 if (exe_scope == NULL)
63 return false;
64
65 Process *process = exe_scope->CalculateProcess();
66 if (process)
67 {
68 byte_order = process->GetByteOrder();
69 addr_size = process->GetAddressByteSize();
70 }
71
72 if (byte_order == eByteOrderInvalid || addr_size == 0)
73 {
74 Module *module = address.GetModule();
75 if (module)
76 {
77 byte_order = module->GetArchitecture().GetDefaultEndian();
78 addr_size = module->GetArchitecture().GetAddressByteSize();
79 }
80 }
81 return byte_order != eByteOrderInvalid && addr_size != 0;
82}
83
84static uint64_t
85ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
86{
87 uint64_t uval64 = 0;
88 if (exe_scope == NULL || byte_size > sizeof(uint64_t))
89 {
90 success = false;
91 return 0;
92 }
93 uint64_t buf;
94
95 success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
96 if (success)
97 {
98 ByteOrder byte_order = eByteOrderInvalid;
99 uint32_t addr_size = 0;
100 if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
101 {
102 DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
103 uint32_t offset = 0;
104 uval64 = data.GetU64(&offset);
105 }
106 else
107 success = false;
108 }
109 return uval64;
110}
111
112static bool
113ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
114{
115 if (exe_scope == NULL)
116 return false;
117
118
119 bool success = false;
120 addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
121 if (success)
122 {
123 Process *process = exe_scope->CalculateProcess();
124 if (process && process->IsAlive())
125 {
126 if (!process->ResolveLoadAddress (deref_addr, deref_so_addr))
127 {
128 deref_so_addr.SetSection(NULL);
129 deref_so_addr.SetOffset(deref_addr);
130 }
131 }
132 else
133 {
134 Target *target = exe_scope->CalculateTarget();
135 if (target == NULL)
136 return false;
137
138 if (!target->GetImages().ResolveFileAddress(deref_addr, deref_so_addr))
139 {
140 deref_so_addr.SetSection(NULL);
141 deref_so_addr.SetOffset(deref_addr);
142 }
143 }
144 return true;
145 }
146 return false;
147}
148
149static bool
150DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
151{
152 if (exe_scope == NULL)
153 return 0;
154 std::vector<uint8_t> buf(byte_size, 0);
155
156 if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
157 {
158 ByteOrder byte_order = eByteOrderInvalid;
159 uint32_t addr_size = 0;
160 if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
161 {
162 DataExtractor data (buf.data(), buf.size(), byte_order, addr_size);
163
164 data.Dump (strm,
165 0, // Start offset in "data"
166 eFormatHex, // Print as characters
167 buf.size(), // Size of item
168 1, // Items count
169 UINT32_MAX, // num per line
170 LLDB_INVALID_ADDRESS,// base address
171 0, // bitfield bit size
172 0); // bitfield bit offset
173
174 return true;
175 }
176 }
177 return false;
178}
179
180
181static size_t
182ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
183{
184 if (exe_scope == NULL)
185 return 0;
186 const size_t k_buf_len = 256;
187 char buf[k_buf_len+1];
188 buf[k_buf_len] = '\0'; // NULL terminate
189
190 // Byte order and adderss size don't matter for C string dumping..
191 DataExtractor data (buf, sizeof(buf), eByteOrderHost, 4);
192 size_t total_len = 0;
193 size_t bytes_read;
194 Address curr_address(address);
195 strm->PutChar ('"');
196 while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
197 {
198 size_t len = strlen(buf);
199 if (len == 0)
200 break;
201 if (len > bytes_read)
202 len = bytes_read;
203
204 data.Dump (strm,
205 0, // Start offset in "data"
206 eFormatChar, // Print as characters
207 1, // Size of item (1 byte for a char!)
208 len, // How many bytes to print?
209 UINT32_MAX, // num per line
210 LLDB_INVALID_ADDRESS,// base address
211 0, // bitfield bit size
212
213 0); // bitfield bit offset
214
215 total_len += bytes_read;
216
217 if (len < k_buf_len)
218 break;
219 curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
220 }
221 strm->PutChar ('"');
222 return total_len;
223}
224
225Address::Address () :
226 m_section (NULL),
227 m_offset (LLDB_INVALID_ADDRESS)
228{
229}
230
231Address::Address (const Address& rhs) :
232 m_section (rhs.m_section),
233 m_offset (rhs.m_offset)
234{
235}
236
237Address::Address (const Section* section, addr_t offset) :
238 m_section (section),
239 m_offset (offset)
240{
241}
242
243Address::Address (addr_t address, const SectionList * sections) :
244 m_section (NULL),
245 m_offset (LLDB_INVALID_ADDRESS)
246{
247 ResolveAddressUsingFileSections(address, sections);
248}
249
250Address::~Address ()
251{
252}
253
254
255const Address&
256Address::operator= (const Address& rhs)
257{
258 if (this != &rhs)
259 {
260 m_section = rhs.m_section;
261 m_offset = rhs.m_offset;
262 }
263 return *this;
264}
265
266bool
267Address::IsValid() const
268{
269 return m_offset != LLDB_INVALID_ADDRESS;
270}
271
272bool
273Address::IsSectionOffset() const
274{
275 return m_section != NULL && IsValid();
276}
277
278bool
279Address::ResolveAddressUsingFileSections (addr_t addr, const SectionList *sections)
280{
281 if (sections)
282 m_section = sections->FindSectionContainingFileAddress(addr).get();
283 else
284 m_section = NULL;
285
286 if (m_section != NULL)
287 {
288 assert( m_section->ContainsFileAddress(addr) );
289 m_offset = addr - m_section->GetFileAddress();
290 return true; // Successfully transformed addr into a section offset address
291 }
292
293 m_offset = addr;
294 return false; // Failed to resolve this address to a section offset value
295}
296
297//bool
298//Address::ResolveAddressUsingLoadSections (addr_t addr, const SectionList *sections)
299//{
300// if (sections)
301// m_section = sections->FindSectionContainingLoadAddress(addr).get();
302// else
303// m_section = NULL;
304//
305// if (m_section != NULL)
306// {
307// assert( m_section->ContainsLoadAddress(addr) );
308// m_offset = addr - m_section->GetLoadBaseAddress();
309// return true; // Successfully transformed addr into a section offset address
310// }
311//
312// m_offset = addr;
313// return false; // Failed to resolve this address to a section offset value
314//}
315//
316Module *
317Address::GetModule () const
318{
319 if (m_section)
320 return m_section->GetModule();
321 return NULL;
322}
323
324const Section*
325Address::GetSection () const
326{
327 return m_section;
328}
329
330
331//addr_t
332//Address::Address() const
333//{
334// addr_t addr = GetLoadAddress();
335// if (addr != LLDB_INVALID_ADDRESS)
336// return addr;
337// return GetFileAddress();
338//}
339//
340
341addr_t
342Address::GetFileAddress () const
343{
344 if (m_section != NULL)
345 {
346 addr_t sect_file_addr = m_section->GetFileAddress();
347 if (sect_file_addr == LLDB_INVALID_ADDRESS)
348 {
349 // Section isn't resolved, we can't return a valid file address
350 return LLDB_INVALID_ADDRESS;
351 }
352 // We have a valid file range, so we can return the file based
353 // address by adding the file base address to our offset
354 return sect_file_addr + m_offset;
355 }
356 // No section, we just return the offset since it is the value in this case
357 return m_offset;
358}
359
360addr_t
361Address::GetLoadAddress (Process *process) const
362{
363 if (m_section != NULL)
364 {
365 if (process)
366 {
367 addr_t sect_load_addr = m_section->GetLoadBaseAddress (process);
368
369 if (sect_load_addr != LLDB_INVALID_ADDRESS)
370 {
371 // We have a valid file range, so we can return the file based
372 // address by adding the file base address to our offset
373 return sect_load_addr + m_offset;
374 }
375 }
376 // The section isn't resolved or no process was supplied so we can't
377 // return a valid file address.
378 return LLDB_INVALID_ADDRESS;
379 }
380 // No section, we just return the offset since it is the value in this case
381 return m_offset;
382}
383
384addr_t
385Address::GetOffset () const
386{
387 return m_offset;
388}
389
390bool
391Address::SetOffset (addr_t offset)
392{
393 bool changed = m_offset != offset;
394 m_offset = offset;
395 return changed;
396}
397
398void
399Address::SetSection (const Section* section)
400{
401 m_section = section;
402}
403
404void
405Address::Clear()
406{
407 m_section = NULL;
408 m_offset = LLDB_INVALID_ADDRESS;
409}
410
411
412bool
413Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style) const
414{
415 // If the section was NULL, only load address is going to work.
416 if (m_section == NULL)
417 style = DumpStyleLoadAddress;
418
419 Process *process = NULL;
420 if (exe_scope)
421 process = exe_scope->CalculateProcess();
422 int addr_size = sizeof (addr_t);
423 if (process)
424 addr_size = process->GetAddressByteSize ();
425
426 lldb_private::Address so_addr;
427
428 switch (style)
429 {
430 case DumpStyleSectionNameOffset:
431 if (m_section != NULL)
432 {
433 m_section->DumpName(s);
434 s->Printf (" + %llu", m_offset);
435 }
436 else
437 {
438 s->Printf("0x%16.16llx", m_offset);
439 }
440 break;
441
442 case DumpStyleSectionPointerOffset:
443 s->Printf("(Section *)%.*p + 0x%16.16llx", (int)sizeof(void*) * 2, m_section, m_offset);
444 break;
445
446 case DumpStyleModuleWithFileAddress:
447 s->Printf("%s[", m_section->GetModule()->GetFileSpec().GetFilename().AsCString());
448 // Fall through
449 case DumpStyleFileAddress:
450 {
451 addr_t file_addr = GetFileAddress();
452 if (file_addr == LLDB_INVALID_ADDRESS)
453 {
454 if (fallback_style != DumpStyleInvalid)
455 return Dump (s, exe_scope, fallback_style);
456 return false;
457 }
458 s->Address (file_addr, addr_size);
459 if (style == DumpStyleModuleWithFileAddress)
460 s->PutChar(']');
461 }
462 break;
463
464 case DumpStyleLoadAddress:
465 {
466 addr_t load_addr = GetLoadAddress (process);
467 if (load_addr == LLDB_INVALID_ADDRESS)
468 {
469 if (fallback_style != DumpStyleInvalid)
470 return Dump (s, exe_scope, fallback_style);
471 return false;
472 }
473 s->Address (load_addr, addr_size);
474 }
475 break;
476
477 case DumpStyleResolvedDescription:
478 if (IsSectionOffset())
479 {
480 lldb::AddressType addr_type = eAddressTypeLoad;
481 addr_t addr = GetLoadAddress (process);
482 if (addr == LLDB_INVALID_ADDRESS)
483 {
484 addr = GetFileAddress();
485 addr_type = eAddressTypeFile;
486 }
487
488 uint32_t pointer_size = 4;
489 lldb_private::Module *module = GetModule();
490 if (process)
491 pointer_size = process->GetAddressByteSize();
492 else if (module)
493 pointer_size = module->GetArchitecture().GetAddressByteSize();
494
495 bool showed_info = false;
496 const Section *section = GetSection();
497 if (section)
498 {
499 SectionType sect_type = section->GetSectionType();
500 switch (sect_type)
501 {
502 case eSectionTypeDataCString:
503 // Read the C string from memory and display it
504 showed_info = true;
505 ReadCStringFromMemory (exe_scope, *this, s);
506 break;
507
508 case eSectionTypeDataCStringPointers:
509 {
510 if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
511 {
512#if VERBOSE_OUTPUT
513 s->PutCString("(char *)");
514 so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
515 s->PutCString(": ");
516#endif
517 showed_info = true;
518 ReadCStringFromMemory (exe_scope, so_addr, s);
519 }
520 }
521 break;
522
523 case eSectionTypeDataObjCMessageRefs:
524 {
525 if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
526 {
527 if (so_addr.IsSectionOffset())
528 {
529 lldb_private::SymbolContext func_sc;
530 process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
531 eSymbolContextEverything,
532 func_sc);
533 if (func_sc.function || func_sc.symbol)
534 {
535 showed_info = true;
536#if VERBOSE_OUTPUT
537 s->PutCString ("(objc_msgref *) -> { (func*)");
538 so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
539#else
540 s->PutCString ("{ ");
541#endif
542 Address cstr_addr(*this);
543 cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
544 func_sc.DumpStopContext(s, process, so_addr, true);
545 if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
546 {
547#if VERBOSE_OUTPUT
548 s->PutCString("), (char *)");
549 so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
550 s->PutCString(" (");
551#else
552 s->PutCString(", ");
553#endif
554 ReadCStringFromMemory (exe_scope, so_addr, s);
555 }
556#if VERBOSE_OUTPUT
557 s->PutCString(") }");
558#else
559 s->PutCString(" }");
560#endif
561 }
562 }
563 }
564 }
565 break;
566
567 case eSectionTypeDataObjCCFStrings:
568 {
569 Address cfstring_data_addr(*this);
570 cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size));
571 if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr))
572 {
573#if VERBOSE_OUTPUT
574 s->PutCString("(CFString *) ");
575 cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
576 s->PutCString(" -> @");
577#else
578 s->PutChar('@');
579#endif
580 if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription))
581 showed_info = true;
582 }
583 }
584 break;
585
586 case eSectionTypeData4:
587 // Read the 4 byte data and display it
588 showed_info = true;
589 s->PutCString("(uint32_t) ");
590 DumpUInt (exe_scope, *this, 4, s);
591 break;
592
593 case eSectionTypeData8:
594 // Read the 8 byte data and display it
595 showed_info = true;
596 s->PutCString("(uint64_t) ");
597 DumpUInt (exe_scope, *this, 8, s);
598 break;
599
600 case eSectionTypeData16:
601 // Read the 16 byte data and display it
602 showed_info = true;
603 s->PutCString("(uint128_t) ");
604 DumpUInt (exe_scope, *this, 16, s);
605 break;
606
607 case eSectionTypeDataPointers:
608 // Read the pointer data and display it
609 {
610 if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
611 {
612 s->PutCString ("(void *)");
613 so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
614
615 showed_info = true;
616 if (so_addr.IsSectionOffset())
617 {
618 lldb_private::SymbolContext pointer_sc;
619 process->GetTarget().GetImages().ResolveSymbolContextForAddress (so_addr,
620 eSymbolContextEverything,
621 pointer_sc);
622 if (pointer_sc.function || pointer_sc.symbol)
623 {
624 s->PutCString(": ");
625 pointer_sc.DumpStopContext(s, process, so_addr, false);
626 }
627 }
628 }
629 }
630 break;
631 }
632 }
633
634 if (!showed_info)
635 {
636 if (module)
637 {
638 lldb_private::SymbolContext sc;
639 module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
640 if (sc.function || sc.symbol)
641 {
642 bool show_stop_context = true;
643 if (sc.function == NULL && sc.symbol != NULL)
644 {
645 // If we have just a symbol make sure it is in the right section
646 if (sc.symbol->GetAddressRangePtr())
647 {
648 if (sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() != GetSection())
649 show_stop_context = false;
650 }
651 }
652 if (show_stop_context)
653 {
654 // We have a function or a symbol from the same
655 // sections as this address.
656 sc.DumpStopContext(s, process, *this, false);
657 }
658 else
659 {
660 // We found a symbol but it was in a different
661 // section so it isn't the symbol we should be
662 // showing, just show the section name + offset
663 Dump (s, exe_scope, DumpStyleSectionNameOffset);
664 }
665 }
666 }
667 }
668 }
669 else
670 {
671 if (fallback_style != DumpStyleInvalid)
672 return Dump (s, exe_scope, fallback_style);
673 return false;
674 }
675 break;
676 }
677
678 return true;
679}
680
681//Stream& operator << (Stream& s, const Address& so_addr)
682//{
683// so_addr.Dump(&s, Address::DumpStyleSectionNameOffset);
684// return s;
685//}
686//
687void
688Address::CalculateSymbolContext (SymbolContext *sc)
689{
690 sc->Clear();
691 // Absolute addresses don't have enough information to reconstruct even their target.
692 if (m_section == NULL)
693 return;
694
695 if (m_section->GetModule())
696 {
697 sc->module_sp = m_section->GetModule()->GetSP();
698 if (sc->module_sp)
699 sc->module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextEverything, *sc);
700 }
701}
702
703void
704Address::DumpSymbolContext (Stream *s)
705{
706 SymbolContext sc;
707 CalculateSymbolContext (&sc);
708 sc.Dump (s, NULL);
709}
710
711void
712Address::DumpDebug(Stream *s) const
713{
714 *s << (void *)this << ": " << "Address";
715 if (m_section != NULL)
716 {
717 *s << ", section = " << (void *)m_section << " (" << m_section->GetName() << "), offset = " << m_offset;
718 }
719 else
720 {
721 *s << ", vm_addr = " << m_offset;
722 }
723 s->EOL();
724}
725
726int
727Address::CompareFileAddress (const Address& a, const Address& b)
728{
729 addr_t a_file_addr = a.GetFileAddress();
730 addr_t b_file_addr = b.GetFileAddress();
731 if (a_file_addr < b_file_addr)
732 return -1;
733 if (a_file_addr > b_file_addr)
734 return +1;
735 return 0;
736}
737
738
739int
740Address::CompareLoadAddress (const Address& a, const Address& b, Process *process)
741{
742 assert (process != NULL);
743 addr_t a_load_addr = a.GetLoadAddress (process);
744 addr_t b_load_addr = b.GetLoadAddress (process);
745 if (a_load_addr < b_load_addr)
746 return -1;
747 if (a_load_addr > b_load_addr)
748 return +1;
749 return 0;
750}
751
752int
753Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
754{
755 Module *a_module = a.GetModule ();
756 Module *b_module = b.GetModule ();
757 if (a_module < b_module)
758 return -1;
759 if (a_module > b_module)
760 return +1;
761 // Modules are the same, just compare the file address since they should
762 // be unique
763 addr_t a_file_addr = a.GetFileAddress();
764 addr_t b_file_addr = b.GetFileAddress();
765 if (a_file_addr < b_file_addr)
766 return -1;
767 if (a_file_addr > b_file_addr)
768 return +1;
769 return 0;
770}
771
772
773size_t
774Address::MemorySize () const
775{
776 // Noting special for the memory size of a single Address object,
777 // it is just the size of itself.
778 return sizeof(Address);
779}
780
781
782/// The only comparisons that make sense are the load addresses
783//bool
784//lldb::operator< (const Address& lhs, const Address& rhs)
785//{
786// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
787// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
788//
789// if (lhs_addr == rhs_addr)
790// {
791// lhs_addr = lhs.GetFileAddress();
792// rhs_addr = rhs.GetFileAddress();
793// }
794// return lhs_addr < rhs_addr;
795//}
796//
797//bool
798//lldb::operator<= (const Address& lhs, const Address& rhs)
799//{
800// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
801// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
802//
803// if (lhs_addr == rhs_addr)
804// {
805// lhs_addr = lhs.GetFileAddress();
806// rhs_addr = rhs.GetFileAddress();
807// }
808// return lhs_addr <= rhs_addr;
809//}
810//
811//bool
812//lldb::operator> (const Address& lhs, const Address& rhs)
813//{
814// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
815// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
816//
817// if (lhs_addr == rhs_addr)
818// {
819// lhs_addr = lhs.GetFileAddress();
820// rhs_addr = rhs.GetFileAddress();
821// }
822// return lhs_addr > rhs_addr;
823//}
824//
825//bool
826//lldb::operator>= (const Address& lhs, const Address& rhs)
827//{
828// lldb::addr_t lhs_addr = lhs.GetLoadAddress();
829// lldb::addr_t rhs_addr = rhs.GetLoadAddress();
830//
831// if (lhs_addr == rhs_addr)
832// {
833// lhs_addr = lhs.GetFileAddress();
834// rhs_addr = rhs.GetFileAddress();
835// }
836// return lhs_addr >= rhs_addr;
837//}
838//
839
840// The operator == checks for exact equality only (same section, same offset)
841bool
842lldb_private::operator== (const Address& a, const Address& rhs)
843{
844 return a.GetSection() == rhs.GetSection() &&
845 a.GetOffset() == rhs.GetOffset();
846}
847// The operator != checks for exact inequality only (differing section, or
848// different offset)
849bool
850lldb_private::operator!= (const Address& a, const Address& rhs)
851{
852 return a.GetSection() != rhs.GetSection() ||
853 a.GetOffset() != rhs.GetOffset();
854}
855
856bool
857Address::IsLinkedAddress () const
858{
859 return m_section && m_section->GetLinkedSection();
860}
861
862
863void
864Address::ResolveLinkedAddress ()
865{
866 if (m_section)
867 {
868 const Section *linked_section = m_section->GetLinkedSection();
869 if (linked_section)
870 {
871 m_offset += m_section->GetLinkedOffset();
872 m_section = linked_section;
873 }
874 }
875}