1 //===-- 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 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 static size_t
21 ReadBytes (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 
57 static bool
58 GetByteOrderAndAddressSize (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 
84 static uint64_t
85 ReadUIntMax64 (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 
112 static bool
113 ReadAddress (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 
149 static bool
150 DumpUInt (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 
181 static size_t
182 ReadCStringFromMemory (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 
225 Address::Address () :
226     m_section (NULL),
227     m_offset (LLDB_INVALID_ADDRESS)
228 {
229 }
230 
231 Address::Address (const Address& rhs) :
232     m_section (rhs.m_section),
233     m_offset (rhs.m_offset)
234 {
235 }
236 
237 Address::Address (const Section* section, addr_t offset) :
238     m_section (section),
239     m_offset (offset)
240 {
241 }
242 
243 Address::Address (addr_t address, const SectionList * sections) :
244     m_section (NULL),
245     m_offset (LLDB_INVALID_ADDRESS)
246 {
247     ResolveAddressUsingFileSections(address, sections);
248 }
249 
250 Address::~Address ()
251 {
252 }
253 
254 
255 const Address&
256 Address::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 
266 bool
267 Address::IsValid() const
268 {
269     return m_offset != LLDB_INVALID_ADDRESS;
270 }
271 
272 bool
273 Address::IsSectionOffset() const
274 {
275     return m_section != NULL && IsValid();
276 }
277 
278 bool
279 Address::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 //
316 Module *
317 Address::GetModule () const
318 {
319     if (m_section)
320         return m_section->GetModule();
321     return NULL;
322 }
323 
324 const Section*
325 Address::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 
341 addr_t
342 Address::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 
360 addr_t
361 Address::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 
384 addr_t
385 Address::GetOffset () const
386 {
387     return m_offset;
388 }
389 
390 bool
391 Address::SetOffset (addr_t offset)
392 {
393     bool changed = m_offset != offset;
394     m_offset = offset;
395     return changed;
396 }
397 
398 void
399 Address::SetSection (const Section* section)
400 {
401     m_section = section;
402 }
403 
404 void
405 Address::Clear()
406 {
407     m_section = NULL;
408     m_offset = LLDB_INVALID_ADDRESS;
409 }
410 
411 
412 bool
413 Address::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 //
687 void
688 Address::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 
703 void
704 Address::DumpSymbolContext (Stream *s)
705 {
706     SymbolContext sc;
707     CalculateSymbolContext (&sc);
708     sc.Dump (s, NULL);
709 }
710 
711 void
712 Address::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 
726 int
727 Address::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 
739 int
740 Address::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 
752 int
753 Address::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 
773 size_t
774 Address::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)
841 bool
842 lldb_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)
849 bool
850 lldb_private::operator!= (const Address& a, const Address& rhs)
851 {
852     return  a.GetSection() != rhs.GetSection() ||
853             a.GetOffset()  != rhs.GetOffset();
854 }
855 
856 bool
857 Address::IsLinkedAddress () const
858 {
859     return m_section && m_section->GetLinkedSection();
860 }
861 
862 
863 void
864 Address::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 }
876