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 //        ObjectFile *objfile = NULL;
53 //        if (address.GetModule())
54 //            objfile = address.GetModule()->GetObjectFile();
55 //        return target->ReadMemory (addr_type, addr, dst, dst_len, error, objfile);
56 //    }
57 //    return 0;
58 //}
59 
60 static size_t
61 ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
62 {
63     if (exe_scope == NULL)
64         return 0;
65 
66     Target *target = exe_scope->CalculateTarget();
67     if (target)
68     {
69         Error error;
70         return target->ReadMemory (address, dst, dst_len, error);
71     }
72     return 0;
73 }
74 
75 static bool
76 GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
77 {
78     byte_order = eByteOrderInvalid;
79     addr_size = 0;
80     if (exe_scope == NULL)
81         return false;
82 
83     Process *process = exe_scope->CalculateProcess();
84     if (process)
85     {
86         byte_order = process->GetByteOrder();
87         addr_size = process->GetAddressByteSize();
88     }
89 
90     if (byte_order == eByteOrderInvalid || addr_size == 0)
91     {
92         Module *module = address.GetModule();
93         if (module)
94         {
95             byte_order = module->GetArchitecture().GetDefaultEndian();
96             addr_size = module->GetArchitecture().GetAddressByteSize();
97         }
98     }
99     return byte_order != eByteOrderInvalid && addr_size != 0;
100 }
101 
102 static uint64_t
103 ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
104 {
105     uint64_t uval64 = 0;
106     if (exe_scope == NULL || byte_size > sizeof(uint64_t))
107     {
108         success = false;
109         return 0;
110     }
111     uint64_t buf;
112 
113     success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
114     if (success)
115     {
116         ByteOrder byte_order = eByteOrderInvalid;
117         uint32_t addr_size = 0;
118         if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
119         {
120             DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
121             uint32_t offset = 0;
122             uval64 = data.GetU64(&offset);
123         }
124         else
125             success = false;
126     }
127     return uval64;
128 }
129 
130 static bool
131 ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
132 {
133     if (exe_scope == NULL)
134         return false;
135 
136 
137     bool success = false;
138     addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
139     if (success)
140     {
141         Process *process = exe_scope->CalculateProcess();
142         if (process && process->IsAlive())
143         {
144             if (!process->ResolveLoadAddress (deref_addr, deref_so_addr))
145             {
146                 deref_so_addr.SetSection(NULL);
147                 deref_so_addr.SetOffset(deref_addr);
148             }
149         }
150         else
151         {
152             Target *target = exe_scope->CalculateTarget();
153             if (target == NULL)
154                 return false;
155 
156             if (!target->GetImages().ResolveFileAddress(deref_addr, deref_so_addr))
157             {
158                 deref_so_addr.SetSection(NULL);
159                 deref_so_addr.SetOffset(deref_addr);
160             }
161         }
162         return true;
163     }
164     return false;
165 }
166 
167 static bool
168 DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
169 {
170     if (exe_scope == NULL)
171         return 0;
172     std::vector<uint8_t> buf(byte_size, 0);
173 
174     if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
175     {
176         ByteOrder byte_order = eByteOrderInvalid;
177         uint32_t addr_size = 0;
178         if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
179         {
180             DataExtractor data (buf.data(), buf.size(), byte_order, addr_size);
181 
182             data.Dump (strm,
183                        0,                 // Start offset in "data"
184                        eFormatHex,        // Print as characters
185                        buf.size(),        // Size of item
186                        1,                 // Items count
187                        UINT32_MAX,        // num per line
188                        LLDB_INVALID_ADDRESS,// base address
189                        0,                 // bitfield bit size
190                        0);                // bitfield bit offset
191 
192             return true;
193         }
194     }
195     return false;
196 }
197 
198 
199 static size_t
200 ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
201 {
202     if (exe_scope == NULL)
203         return 0;
204     const size_t k_buf_len = 256;
205     char buf[k_buf_len+1];
206     buf[k_buf_len] = '\0'; // NULL terminate
207 
208     // Byte order and adderss size don't matter for C string dumping..
209     DataExtractor data (buf, sizeof(buf), eByteOrderHost, 4);
210     size_t total_len = 0;
211     size_t bytes_read;
212     Address curr_address(address);
213     strm->PutChar ('"');
214     while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
215     {
216         size_t len = strlen(buf);
217         if (len == 0)
218             break;
219         if (len > bytes_read)
220             len = bytes_read;
221 
222         data.Dump (strm,
223                    0,                 // Start offset in "data"
224                    eFormatChar,       // Print as characters
225                    1,                 // Size of item (1 byte for a char!)
226                    len,               // How many bytes to print?
227                    UINT32_MAX,        // num per line
228                    LLDB_INVALID_ADDRESS,// base address
229                    0,                 // bitfield bit size
230 
231                    0);                // bitfield bit offset
232 
233         total_len += bytes_read;
234 
235         if (len < k_buf_len)
236             break;
237         curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
238     }
239     strm->PutChar ('"');
240     return total_len;
241 }
242 
243 Address::Address () :
244     m_section (NULL),
245     m_offset (LLDB_INVALID_ADDRESS)
246 {
247 }
248 
249 Address::Address (const Address& rhs) :
250     m_section (rhs.m_section),
251     m_offset (rhs.m_offset)
252 {
253 }
254 
255 Address::Address (const Section* section, addr_t offset) :
256     m_section (section),
257     m_offset (offset)
258 {
259 }
260 
261 Address::Address (addr_t address, const SectionList * sections) :
262     m_section (NULL),
263     m_offset (LLDB_INVALID_ADDRESS)
264 {
265     ResolveAddressUsingFileSections(address, sections);
266 }
267 
268 const Address&
269 Address::operator= (const Address& rhs)
270 {
271     if (this != &rhs)
272     {
273         m_section = rhs.m_section;
274         m_offset = rhs.m_offset;
275     }
276     return *this;
277 }
278 
279 bool
280 Address::IsValid() const
281 {
282     return m_offset != LLDB_INVALID_ADDRESS;
283 }
284 
285 bool
286 Address::IsSectionOffset() const
287 {
288     return m_section != NULL && IsValid();
289 }
290 
291 bool
292 Address::ResolveAddressUsingFileSections (addr_t addr, const SectionList *sections)
293 {
294     if (sections)
295         m_section = sections->FindSectionContainingFileAddress(addr).get();
296     else
297         m_section = NULL;
298 
299     if (m_section != NULL)
300     {
301         assert( m_section->ContainsFileAddress(addr) );
302         m_offset = addr - m_section->GetFileAddress();
303         return true;    // Successfully transformed addr into a section offset address
304     }
305 
306     m_offset = addr;
307     return false;       // Failed to resolve this address to a section offset value
308 }
309 
310 //bool
311 //Address::ResolveAddressUsingLoadSections (addr_t addr, const SectionList *sections)
312 //{
313 //    if (sections)
314 //        m_section = sections->FindSectionContainingLoadAddress(addr).get();
315 //    else
316 //        m_section = NULL;
317 //
318 //    if (m_section != NULL)
319 //    {
320 //        assert( m_section->ContainsLoadAddress(addr) );
321 //        m_offset = addr - m_section->GetLoadBaseAddress();
322 //        return true;    // Successfully transformed addr into a section offset address
323 //    }
324 //
325 //    m_offset = addr;
326 //    return false;       // Failed to resolve this address to a section offset value
327 //}
328 //
329 Module *
330 Address::GetModule () const
331 {
332     if (m_section)
333         return m_section->GetModule();
334     return NULL;
335 }
336 
337 //addr_t
338 //Address::Address() const
339 //{
340 //  addr_t addr = GetLoadAddress();
341 //  if (addr != LLDB_INVALID_ADDRESS)
342 //      return addr;
343 //  return GetFileAddress();
344 //}
345 //
346 
347 addr_t
348 Address::GetFileAddress () const
349 {
350     if (m_section != NULL)
351     {
352         addr_t sect_file_addr = m_section->GetFileAddress();
353         if (sect_file_addr == LLDB_INVALID_ADDRESS)
354         {
355             // Section isn't resolved, we can't return a valid file address
356             return LLDB_INVALID_ADDRESS;
357         }
358         // We have a valid file range, so we can return the file based
359         // address by adding the file base address to our offset
360         return sect_file_addr + m_offset;
361     }
362     // No section, we just return the offset since it is the value in this case
363     return m_offset;
364 }
365 
366 addr_t
367 Address::GetLoadAddress (Process *process) const
368 {
369     if (m_section != NULL)
370     {
371         if (process)
372         {
373             addr_t sect_load_addr = m_section->GetLoadBaseAddress (process);
374 
375             if (sect_load_addr != LLDB_INVALID_ADDRESS)
376             {
377                 // We have a valid file range, so we can return the file based
378                 // address by adding the file base address to our offset
379                 return sect_load_addr + m_offset;
380             }
381         }
382        // The section isn't resolved or no process was supplied so we can't
383        // return a valid file address.
384        return LLDB_INVALID_ADDRESS;
385     }
386     // No section, we just return the offset since it is the value in this case
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::Clear()
400 {
401     m_section = NULL;
402     m_offset = LLDB_INVALID_ADDRESS;
403 }
404 
405 
406 bool
407 Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const
408 {
409     // If the section was NULL, only load address is going to work.
410     if (m_section == NULL)
411         style = DumpStyleLoadAddress;
412 
413     Process *process = NULL;
414     if (exe_scope)
415         process = exe_scope->CalculateProcess();
416     // If addr_byte_size is UINT32_MAX, then determine the correct address
417     // byte size for the process or default to the size of addr_t
418     if (addr_size == UINT32_MAX)
419     {
420         if (process)
421             addr_size = process->GetAddressByteSize ();
422         else
423             addr_size = sizeof(addr_t);
424     }
425 
426     lldb_private::Address so_addr;
427     switch (style)
428     {
429     case DumpStyleSectionNameOffset:
430         if (m_section != NULL)
431         {
432             m_section->DumpName(s);
433             s->Printf (" + %llu", m_offset);
434         }
435         else
436         {
437             s->Address(m_offset, addr_size);
438         }
439         break;
440 
441     case DumpStyleSectionPointerOffset:
442         s->Printf("(Section *)%.*p + ", (int)sizeof(void*) * 2, m_section);
443         s->Address(m_offset, addr_size);
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, DumpStyleInvalid, addr_size);
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, DumpStyleInvalid, addr_size);
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                                 Target *target = exe_scope->CalculateTarget();
620                                 if (target)
621                                 {
622                                     target->GetImages().ResolveSymbolContextForAddress (so_addr,
623                                                                                         eSymbolContextEverything,
624                                                                                         pointer_sc);
625                                     if (pointer_sc.function || pointer_sc.symbol)
626                                     {
627                                         s->PutCString(": ");
628                                         pointer_sc.DumpStopContext(s, process, so_addr, false);
629                                     }
630                                 }
631                             }
632                         }
633                     }
634                     break;
635                 }
636             }
637 
638             if (!showed_info)
639             {
640                 if (module)
641                 {
642                     lldb_private::SymbolContext sc;
643                     module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
644                     if (sc.function || sc.symbol)
645                     {
646                         bool show_stop_context = true;
647                         if (sc.function == NULL && sc.symbol != NULL)
648                         {
649                             // If we have just a symbol make sure it is in the right section
650                             if (sc.symbol->GetAddressRangePtr())
651                             {
652                                 if (sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() != GetSection())
653                                     show_stop_context = false;
654                             }
655                         }
656                         if (show_stop_context)
657                         {
658                             // We have a function or a symbol from the same
659                             // sections as this address.
660                             sc.DumpStopContext(s, process, *this, true);
661                         }
662                         else
663                         {
664                             // We found a symbol but it was in a different
665                             // section so it isn't the symbol we should be
666                             // showing, just show the section name + offset
667                             Dump (s, exe_scope, DumpStyleSectionNameOffset);
668                         }
669                     }
670                 }
671             }
672         }
673         else
674         {
675             if (fallback_style != DumpStyleInvalid)
676                 return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
677             return false;
678         }
679         break;
680 
681     case DumpStyleDetailedSymbolContext:
682         if (IsSectionOffset())
683         {
684             lldb::AddressType addr_type = eAddressTypeLoad;
685             addr_t addr = GetLoadAddress (process);
686             if (addr == LLDB_INVALID_ADDRESS)
687             {
688                 addr = GetFileAddress();
689                 addr_type = eAddressTypeFile;
690             }
691 
692             lldb_private::Module *module = GetModule();
693             if (module)
694             {
695                 lldb_private::SymbolContext sc;
696                 module->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
697                 if (sc.function || sc.symbol)
698                 {
699                     if (sc.function == NULL && sc.symbol != NULL)
700                     {
701                         // If we have just a symbol make sure it is in the right section
702                         if (sc.symbol->GetAddressRangePtr() && sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetSection() == GetSection())
703                         {
704                             sc.GetDescription(s, eDescriptionLevelBrief, process);
705                             break;
706                         }
707                     }
708                 }
709             }
710         }
711         if (fallback_style != DumpStyleInvalid)
712             return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
713         return false;
714         break;
715     }
716 
717     return true;
718 }
719 
720 //Stream& operator << (Stream& s, const Address& so_addr)
721 //{
722 //    so_addr.Dump(&s, Address::DumpStyleSectionNameOffset);
723 //    return s;
724 //}
725 //
726 void
727 Address::CalculateSymbolContext (SymbolContext *sc)
728 {
729     sc->Clear();
730     // Absolute addresses don't have enough information to reconstruct even their target.
731     if (m_section == NULL)
732         return;
733 
734     if (m_section->GetModule())
735     {
736         sc->module_sp = m_section->GetModule()->GetSP();
737         if (sc->module_sp)
738             sc->module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextEverything, *sc);
739     }
740 }
741 
742 void
743 Address::DumpSymbolContext (Stream *s)
744 {
745     SymbolContext sc;
746     CalculateSymbolContext (&sc);
747     sc.Dump (s, NULL);
748 }
749 
750 void
751 Address::DumpDebug(Stream *s) const
752 {
753     *s << (void *)this << ": " << "Address";
754     if (m_section != NULL)
755     {
756         *s << ", section = " << (void *)m_section << " (" << m_section->GetName() << "), offset = " << m_offset;
757     }
758     else
759     {
760         *s << ", vm_addr = " << m_offset;
761     }
762     s->EOL();
763 }
764 
765 int
766 Address::CompareFileAddress (const Address& a, const Address& b)
767 {
768     addr_t a_file_addr = a.GetFileAddress();
769     addr_t b_file_addr = b.GetFileAddress();
770     if (a_file_addr < b_file_addr)
771         return -1;
772     if (a_file_addr > b_file_addr)
773         return +1;
774     return 0;
775 }
776 
777 
778 int
779 Address::CompareLoadAddress (const Address& a, const Address& b, Process *process)
780 {
781     assert (process != NULL);
782     addr_t a_load_addr = a.GetLoadAddress (process);
783     addr_t b_load_addr = b.GetLoadAddress (process);
784     if (a_load_addr < b_load_addr)
785         return -1;
786     if (a_load_addr > b_load_addr)
787         return +1;
788     return 0;
789 }
790 
791 int
792 Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
793 {
794     Module *a_module = a.GetModule ();
795     Module *b_module = b.GetModule ();
796     if (a_module < b_module)
797         return -1;
798     if (a_module > b_module)
799         return +1;
800     // Modules are the same, just compare the file address since they should
801     // be unique
802     addr_t a_file_addr = a.GetFileAddress();
803     addr_t b_file_addr = b.GetFileAddress();
804     if (a_file_addr < b_file_addr)
805         return -1;
806     if (a_file_addr > b_file_addr)
807         return +1;
808     return 0;
809 }
810 
811 
812 size_t
813 Address::MemorySize () const
814 {
815     // Noting special for the memory size of a single Address object,
816     // it is just the size of itself.
817     return sizeof(Address);
818 }
819 
820 
821 /// The only comparisons that make sense are the load addresses
822 //bool
823 //lldb::operator< (const Address& lhs, const Address& rhs)
824 //{
825 //    lldb::addr_t lhs_addr = lhs.GetLoadAddress();
826 //    lldb::addr_t rhs_addr = rhs.GetLoadAddress();
827 //
828 //    if (lhs_addr == rhs_addr)
829 //    {
830 //        lhs_addr = lhs.GetFileAddress();
831 //        rhs_addr = rhs.GetFileAddress();
832 //    }
833 //    return lhs_addr < rhs_addr;
834 //}
835 //
836 //bool
837 //lldb::operator<=    (const Address& lhs, const Address& rhs)
838 //{
839 //    lldb::addr_t lhs_addr = lhs.GetLoadAddress();
840 //    lldb::addr_t rhs_addr = rhs.GetLoadAddress();
841 //
842 //    if (lhs_addr == rhs_addr)
843 //    {
844 //        lhs_addr = lhs.GetFileAddress();
845 //        rhs_addr = rhs.GetFileAddress();
846 //    }
847 //    return lhs_addr <= rhs_addr;
848 //}
849 //
850 //bool
851 //lldb::operator> (const Address& lhs, const Address& rhs)
852 //{
853 //    lldb::addr_t lhs_addr = lhs.GetLoadAddress();
854 //    lldb::addr_t rhs_addr = rhs.GetLoadAddress();
855 //
856 //    if (lhs_addr == rhs_addr)
857 //    {
858 //        lhs_addr = lhs.GetFileAddress();
859 //        rhs_addr = rhs.GetFileAddress();
860 //    }
861 //    return lhs_addr > rhs_addr;
862 //}
863 //
864 //bool
865 //lldb::operator>=    (const Address& lhs, const Address& rhs)
866 //{
867 //    lldb::addr_t lhs_addr = lhs.GetLoadAddress();
868 //    lldb::addr_t rhs_addr = rhs.GetLoadAddress();
869 //
870 //    if (lhs_addr == rhs_addr)
871 //    {
872 //        lhs_addr = lhs.GetFileAddress();
873 //        rhs_addr = rhs.GetFileAddress();
874 //    }
875 //    return lhs_addr >= rhs_addr;
876 //}
877 //
878 
879 // The operator == checks for exact equality only (same section, same offset)
880 bool
881 lldb_private::operator== (const Address& a, const Address& rhs)
882 {
883     return  a.GetSection() == rhs.GetSection() &&
884             a.GetOffset()  == rhs.GetOffset();
885 }
886 // The operator != checks for exact inequality only (differing section, or
887 // different offset)
888 bool
889 lldb_private::operator!= (const Address& a, const Address& rhs)
890 {
891     return  a.GetSection() != rhs.GetSection() ||
892             a.GetOffset()  != rhs.GetOffset();
893 }
894 
895 bool
896 Address::IsLinkedAddress () const
897 {
898     return m_section && m_section->GetLinkedSection();
899 }
900 
901 
902 void
903 Address::ResolveLinkedAddress ()
904 {
905     if (m_section)
906     {
907         const Section *linked_section = m_section->GetLinkedSection();
908         if (linked_section)
909         {
910             m_offset += m_section->GetLinkedOffset();
911             m_section = linked_section;
912         }
913     }
914 }
915