1 //===-- Symbol.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/Symbol/Symbol.h"
11 
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Core/Stream.h"
15 #include "lldb/Symbol/ObjectFile.h"
16 #include "lldb/Symbol/Symtab.h"
17 #include "lldb/Symbol/Function.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Symbol/SymbolVendor.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 
Symbol()26 Symbol::Symbol() :
27     SymbolContextScope (),
28     m_uid (UINT32_MAX),
29     m_type_data (0),
30     m_type_data_resolved (false),
31     m_is_synthetic (false),
32     m_is_debug (false),
33     m_is_external (false),
34     m_size_is_sibling (false),
35     m_size_is_synthesized (false),
36     m_size_is_valid (false),
37     m_demangled_is_synthesized (false),
38     m_type (eSymbolTypeInvalid),
39     m_mangled (),
40     m_addr_range (),
41     m_flags ()
42 {
43 }
44 
Symbol(uint32_t symID,const char * name,bool name_is_mangled,SymbolType type,bool external,bool is_debug,bool is_trampoline,bool is_artificial,const lldb::SectionSP & section_sp,addr_t offset,addr_t size,bool size_is_valid,uint32_t flags)45 Symbol::Symbol
46 (
47     uint32_t symID,
48     const char *name,
49     bool name_is_mangled,
50     SymbolType type,
51     bool external,
52     bool is_debug,
53     bool is_trampoline,
54     bool is_artificial,
55     const lldb::SectionSP &section_sp,
56     addr_t offset,
57     addr_t size,
58     bool size_is_valid,
59     uint32_t flags
60 ) :
61     SymbolContextScope (),
62     m_uid (symID),
63     m_type_data (0),
64     m_type_data_resolved (false),
65     m_is_synthetic (is_artificial),
66     m_is_debug (is_debug),
67     m_is_external (external),
68     m_size_is_sibling (false),
69     m_size_is_synthesized (false),
70     m_size_is_valid (size_is_valid || size > 0),
71     m_demangled_is_synthesized (false),
72     m_type (type),
73     m_mangled (ConstString(name), name_is_mangled),
74     m_addr_range (section_sp, offset, size),
75     m_flags (flags)
76 {
77 }
78 
Symbol(uint32_t symID,const char * name,bool name_is_mangled,SymbolType type,bool external,bool is_debug,bool is_trampoline,bool is_artificial,const AddressRange & range,bool size_is_valid,uint32_t flags)79 Symbol::Symbol
80 (
81     uint32_t symID,
82     const char *name,
83     bool name_is_mangled,
84     SymbolType type,
85     bool external,
86     bool is_debug,
87     bool is_trampoline,
88     bool is_artificial,
89     const AddressRange &range,
90     bool size_is_valid,
91     uint32_t flags
92 ) :
93     SymbolContextScope (),
94     m_uid (symID),
95     m_type_data (0),
96     m_type_data_resolved (false),
97     m_is_synthetic (is_artificial),
98     m_is_debug (is_debug),
99     m_is_external (external),
100     m_size_is_sibling (false),
101     m_size_is_synthesized (false),
102     m_size_is_valid (size_is_valid || range.GetByteSize() > 0),
103     m_demangled_is_synthesized (false),
104     m_type (type),
105     m_mangled (ConstString(name), name_is_mangled),
106     m_addr_range (range),
107     m_flags (flags)
108 {
109 }
110 
Symbol(const Symbol & rhs)111 Symbol::Symbol(const Symbol& rhs):
112     SymbolContextScope (rhs),
113     m_uid (rhs.m_uid),
114     m_type_data (rhs.m_type_data),
115     m_type_data_resolved (rhs.m_type_data_resolved),
116     m_is_synthetic (rhs.m_is_synthetic),
117     m_is_debug (rhs.m_is_debug),
118     m_is_external (rhs.m_is_external),
119     m_size_is_sibling (rhs.m_size_is_sibling),
120     m_size_is_synthesized (false),
121     m_size_is_valid (rhs.m_size_is_valid),
122     m_demangled_is_synthesized (rhs.m_demangled_is_synthesized),
123     m_type (rhs.m_type),
124     m_mangled (rhs.m_mangled),
125     m_addr_range (rhs.m_addr_range),
126     m_flags (rhs.m_flags)
127 {
128 }
129 
130 const Symbol&
operator =(const Symbol & rhs)131 Symbol::operator= (const Symbol& rhs)
132 {
133     if (this != &rhs)
134     {
135         SymbolContextScope::operator= (rhs);
136         m_uid = rhs.m_uid;
137         m_type_data = rhs.m_type_data;
138         m_type_data_resolved = rhs.m_type_data_resolved;
139         m_is_synthetic = rhs.m_is_synthetic;
140         m_is_debug = rhs.m_is_debug;
141         m_is_external = rhs.m_is_external;
142         m_size_is_sibling = rhs.m_size_is_sibling;
143         m_size_is_synthesized = rhs.m_size_is_sibling;
144         m_size_is_valid = rhs.m_size_is_valid;
145         m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
146         m_type = rhs.m_type;
147         m_mangled = rhs.m_mangled;
148         m_addr_range = rhs.m_addr_range;
149         m_flags = rhs.m_flags;
150     }
151     return *this;
152 }
153 
154 void
Clear()155 Symbol::Clear()
156 {
157     m_uid = UINT32_MAX;
158     m_mangled.Clear();
159     m_type_data = 0;
160     m_type_data_resolved = false;
161     m_is_synthetic = false;
162     m_is_debug = false;
163     m_is_external = false;
164     m_size_is_sibling = false;
165     m_size_is_synthesized = false;
166     m_size_is_valid = false;
167     m_demangled_is_synthesized = false;
168     m_type = eSymbolTypeInvalid;
169     m_flags = 0;
170     m_addr_range.Clear();
171 }
172 
173 bool
ValueIsAddress() const174 Symbol::ValueIsAddress() const
175 {
176     return m_addr_range.GetBaseAddress().GetSection().get() != NULL;
177 }
178 
179 uint32_t
GetSiblingIndex() const180 Symbol::GetSiblingIndex() const
181 {
182     return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
183 }
184 
185 bool
IsTrampoline() const186 Symbol::IsTrampoline () const
187 {
188     return m_type == eSymbolTypeTrampoline;
189 }
190 
191 bool
IsIndirect() const192 Symbol::IsIndirect () const
193 {
194     return m_type == eSymbolTypeResolver;
195 }
196 
197 void
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target) const198 Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const
199 {
200     s->Printf("id = {0x%8.8x}", m_uid);
201 
202     if (m_addr_range.GetBaseAddress().GetSection())
203     {
204         if (ValueIsAddress())
205         {
206             const lldb::addr_t byte_size = GetByteSize();
207             if (byte_size > 0)
208             {
209                 s->PutCString (", range = ");
210                 m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
211             }
212             else
213             {
214                 s->PutCString (", address = ");
215                 m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
216             }
217         }
218         else
219             s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
220     }
221     else
222     {
223         if (m_size_is_sibling)
224             s->Printf (", sibling = %5" PRIu64, m_addr_range.GetBaseAddress().GetOffset());
225         else
226             s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
227     }
228     if (m_mangled.GetDemangledName())
229         s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString());
230     if (m_mangled.GetMangledName())
231         s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString());
232 
233 }
234 
235 void
Dump(Stream * s,Target * target,uint32_t index) const236 Symbol::Dump(Stream *s, Target *target, uint32_t index) const
237 {
238 //  s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
239 //  s->Indent();
240 //  s->Printf("Symbol[%5u] %6u %c%c %-12s ",
241     s->Printf("[%5u] %6u %c%c%c %-12s ",
242               index,
243               GetID(),
244               m_is_debug ? 'D' : ' ',
245               m_is_synthetic ? 'S' : ' ',
246               m_is_external ? 'X' : ' ',
247               GetTypeAsString());
248 
249     // Make sure the size of the symbol is up to date before dumping
250     GetByteSize();
251 
252     if (ValueIsAddress())
253     {
254         if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress))
255             s->Printf("%*s", 18, "");
256 
257         s->PutChar(' ');
258 
259         if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress))
260             s->Printf("%*s", 18, "");
261 
262         const char *format = m_size_is_sibling ?
263                             " Sibling -> [%5llu] 0x%8.8x %s\n":
264                             " 0x%16.16" PRIx64 " 0x%8.8x %s\n";
265         s->Printf(  format,
266                     GetByteSize(),
267                     m_flags,
268                     m_mangled.GetName().AsCString(""));
269     }
270     else
271     {
272         const char *format = m_size_is_sibling ?
273                             "0x%16.16" PRIx64 "                    Sibling -> [%5llu] 0x%8.8x %s\n":
274                             "0x%16.16" PRIx64 "                    0x%16.16" PRIx64 " 0x%8.8x %s\n";
275         s->Printf(  format,
276                     m_addr_range.GetBaseAddress().GetOffset(),
277                     GetByteSize(),
278                     m_flags,
279                     m_mangled.GetName().AsCString(""));
280     }
281 }
282 
283 uint32_t
GetPrologueByteSize()284 Symbol::GetPrologueByteSize ()
285 {
286     if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver)
287     {
288         if (!m_type_data_resolved)
289         {
290             m_type_data_resolved = true;
291 
292             const Address &base_address = m_addr_range.GetBaseAddress();
293             Function *function = base_address.CalculateSymbolContextFunction();
294             if (function)
295             {
296                 // Functions have line entries which can also potentially have end of prologue information.
297                 // So if this symbol points to a function, use the prologue information from there.
298                 m_type_data = function->GetPrologueByteSize();
299             }
300             else
301             {
302                 ModuleSP module_sp (base_address.GetModule());
303                 SymbolContext sc;
304                 if (module_sp)
305                 {
306                     uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address,
307                                                                                          eSymbolContextLineEntry,
308                                                                                          sc);
309                     if (resolved_flags & eSymbolContextLineEntry)
310                     {
311                         // Default to the end of the first line entry.
312                         m_type_data = sc.line_entry.range.GetByteSize();
313 
314                         // Set address for next line.
315                         Address addr (base_address);
316                         addr.Slide (m_type_data);
317 
318                         // Check the first few instructions and look for one that has a line number that is
319                         // different than the first entry. This is also done in Function::GetPrologueByteSize().
320                         uint16_t total_offset = m_type_data;
321                         for (int idx = 0; idx < 6; ++idx)
322                         {
323                             SymbolContext sc_temp;
324                             resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp);
325                             // Make sure we got line number information...
326                             if (!(resolved_flags & eSymbolContextLineEntry))
327                                 break;
328 
329                             // If this line number is different than our first one, use it and we're done.
330                             if (sc_temp.line_entry.line != sc.line_entry.line)
331                             {
332                                 m_type_data = total_offset;
333                                 break;
334                             }
335 
336                             // Slide addr up to the next line address.
337                             addr.Slide (sc_temp.line_entry.range.GetByteSize());
338                             total_offset += sc_temp.line_entry.range.GetByteSize();
339                             // If we've gone too far, bail out.
340                             if (total_offset >= m_addr_range.GetByteSize())
341                                 break;
342                         }
343 
344                         // Sanity check - this may be a function in the middle of code that has debug information, but
345                         // not for this symbol.  So the line entries surrounding us won't lie inside our function.
346                         // In that case, the line entry will be bigger than we are, so we do that quick check and
347                         // if that is true, we just return 0.
348                         if (m_type_data >= m_addr_range.GetByteSize())
349                             m_type_data = 0;
350                     }
351                     else
352                     {
353                         // TODO: expose something in Process to figure out the
354                         // size of a function prologue.
355                         m_type_data = 0;
356                     }
357                 }
358             }
359         }
360         return m_type_data;
361     }
362     return 0;
363 }
364 
365 bool
Compare(const ConstString & name,SymbolType type) const366 Symbol::Compare(const ConstString& name, SymbolType type) const
367 {
368     if (type == eSymbolTypeAny || m_type == type)
369         return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name;
370     return false;
371 }
372 
373 #define ENUM_TO_CSTRING(x)  case eSymbolType##x: return #x;
374 
375 const char *
GetTypeAsString() const376 Symbol::GetTypeAsString() const
377 {
378     switch (m_type)
379     {
380     ENUM_TO_CSTRING(Invalid);
381     ENUM_TO_CSTRING(Absolute);
382     ENUM_TO_CSTRING(Code);
383     ENUM_TO_CSTRING(Data);
384     ENUM_TO_CSTRING(Trampoline);
385     ENUM_TO_CSTRING(Runtime);
386     ENUM_TO_CSTRING(Exception);
387     ENUM_TO_CSTRING(SourceFile);
388     ENUM_TO_CSTRING(HeaderFile);
389     ENUM_TO_CSTRING(ObjectFile);
390     ENUM_TO_CSTRING(CommonBlock);
391     ENUM_TO_CSTRING(Block);
392     ENUM_TO_CSTRING(Local);
393     ENUM_TO_CSTRING(Param);
394     ENUM_TO_CSTRING(Variable);
395     ENUM_TO_CSTRING(VariableType);
396     ENUM_TO_CSTRING(LineEntry);
397     ENUM_TO_CSTRING(LineHeader);
398     ENUM_TO_CSTRING(ScopeBegin);
399     ENUM_TO_CSTRING(ScopeEnd);
400     ENUM_TO_CSTRING(Additional);
401     ENUM_TO_CSTRING(Compiler);
402     ENUM_TO_CSTRING(Instrumentation);
403     ENUM_TO_CSTRING(Undefined);
404     ENUM_TO_CSTRING(ObjCClass);
405     ENUM_TO_CSTRING(ObjCMetaClass);
406     ENUM_TO_CSTRING(ObjCIVar);
407     default:
408         break;
409     }
410     return "<unknown SymbolType>";
411 }
412 
413 void
CalculateSymbolContext(SymbolContext * sc)414 Symbol::CalculateSymbolContext (SymbolContext *sc)
415 {
416     // Symbols can reconstruct the symbol and the module in the symbol context
417     sc->symbol = this;
418     if (ValueIsAddress())
419         sc->module_sp = GetAddress().GetModule();
420     else
421         sc->module_sp.reset();
422 }
423 
424 ModuleSP
CalculateSymbolContextModule()425 Symbol::CalculateSymbolContextModule ()
426 {
427     if (ValueIsAddress())
428         return GetAddress().GetModule();
429     return ModuleSP();
430 }
431 
432 Symbol *
CalculateSymbolContextSymbol()433 Symbol::CalculateSymbolContextSymbol ()
434 {
435     return this;
436 }
437 
438 void
DumpSymbolContext(Stream * s)439 Symbol::DumpSymbolContext (Stream *s)
440 {
441     bool dumped_module = false;
442     if (ValueIsAddress())
443     {
444         ModuleSP module_sp (GetAddress().GetModule());
445         if (module_sp)
446         {
447             dumped_module = true;
448             module_sp->DumpSymbolContext(s);
449         }
450     }
451     if (dumped_module)
452         s->PutCString(", ");
453 
454     s->Printf("Symbol{0x%8.8x}", GetID());
455 }
456 
457 lldb::addr_t
GetByteSize() const458 Symbol::GetByteSize () const
459 {
460     return m_addr_range.GetByteSize();
461 }
462 
463