Symbol.cpp revision 263363
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/ModuleSpec.h"
14#include "lldb/Core/Section.h"
15#include "lldb/Core/Stream.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Symbol/Symtab.h"
18#include "lldb/Symbol/Function.h"
19#include "lldb/Target/Process.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Symbol/SymbolVendor.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
26
27Symbol::Symbol() :
28    SymbolContextScope (),
29    m_uid (UINT32_MAX),
30    m_type_data (0),
31    m_type_data_resolved (false),
32    m_is_synthetic (false),
33    m_is_debug (false),
34    m_is_external (false),
35    m_size_is_sibling (false),
36    m_size_is_synthesized (false),
37    m_size_is_valid (false),
38    m_demangled_is_synthesized (false),
39    m_type (eSymbolTypeInvalid),
40    m_mangled (),
41    m_addr_range (),
42    m_flags ()
43{
44}
45
46Symbol::Symbol
47(
48    uint32_t symID,
49    const char *name,
50    bool name_is_mangled,
51    SymbolType type,
52    bool external,
53    bool is_debug,
54    bool is_trampoline,
55    bool is_artificial,
56    const lldb::SectionSP &section_sp,
57    addr_t offset,
58    addr_t size,
59    bool size_is_valid,
60    uint32_t flags
61) :
62    SymbolContextScope (),
63    m_uid (symID),
64    m_type_data (0),
65    m_type_data_resolved (false),
66    m_is_synthetic (is_artificial),
67    m_is_debug (is_debug),
68    m_is_external (external),
69    m_size_is_sibling (false),
70    m_size_is_synthesized (false),
71    m_size_is_valid (size_is_valid || size > 0),
72    m_demangled_is_synthesized (false),
73    m_type (type),
74    m_mangled (ConstString(name), name_is_mangled),
75    m_addr_range (section_sp, offset, size),
76    m_flags (flags)
77{
78}
79
80Symbol::Symbol
81(
82    uint32_t symID,
83    const char *name,
84    bool name_is_mangled,
85    SymbolType type,
86    bool external,
87    bool is_debug,
88    bool is_trampoline,
89    bool is_artificial,
90    const AddressRange &range,
91    bool size_is_valid,
92    uint32_t flags
93) :
94    SymbolContextScope (),
95    m_uid (symID),
96    m_type_data (0),
97    m_type_data_resolved (false),
98    m_is_synthetic (is_artificial),
99    m_is_debug (is_debug),
100    m_is_external (external),
101    m_size_is_sibling (false),
102    m_size_is_synthesized (false),
103    m_size_is_valid (size_is_valid || range.GetByteSize() > 0),
104    m_demangled_is_synthesized (false),
105    m_type (type),
106    m_mangled (ConstString(name), name_is_mangled),
107    m_addr_range (range),
108    m_flags (flags)
109{
110}
111
112Symbol::Symbol(const Symbol& rhs):
113    SymbolContextScope (rhs),
114    m_uid (rhs.m_uid),
115    m_type_data (rhs.m_type_data),
116    m_type_data_resolved (rhs.m_type_data_resolved),
117    m_is_synthetic (rhs.m_is_synthetic),
118    m_is_debug (rhs.m_is_debug),
119    m_is_external (rhs.m_is_external),
120    m_size_is_sibling (rhs.m_size_is_sibling),
121    m_size_is_synthesized (false),
122    m_size_is_valid (rhs.m_size_is_valid),
123    m_demangled_is_synthesized (rhs.m_demangled_is_synthesized),
124    m_type (rhs.m_type),
125    m_mangled (rhs.m_mangled),
126    m_addr_range (rhs.m_addr_range),
127    m_flags (rhs.m_flags)
128{
129}
130
131const Symbol&
132Symbol::operator= (const Symbol& rhs)
133{
134    if (this != &rhs)
135    {
136        SymbolContextScope::operator= (rhs);
137        m_uid = rhs.m_uid;
138        m_type_data = rhs.m_type_data;
139        m_type_data_resolved = rhs.m_type_data_resolved;
140        m_is_synthetic = rhs.m_is_synthetic;
141        m_is_debug = rhs.m_is_debug;
142        m_is_external = rhs.m_is_external;
143        m_size_is_sibling = rhs.m_size_is_sibling;
144        m_size_is_synthesized = rhs.m_size_is_sibling;
145        m_size_is_valid = rhs.m_size_is_valid;
146        m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
147        m_type = rhs.m_type;
148        m_mangled = rhs.m_mangled;
149        m_addr_range = rhs.m_addr_range;
150        m_flags = rhs.m_flags;
151    }
152    return *this;
153}
154
155void
156Symbol::Clear()
157{
158    m_uid = UINT32_MAX;
159    m_mangled.Clear();
160    m_type_data = 0;
161    m_type_data_resolved = false;
162    m_is_synthetic = false;
163    m_is_debug = false;
164    m_is_external = false;
165    m_size_is_sibling = false;
166    m_size_is_synthesized = false;
167    m_size_is_valid = false;
168    m_demangled_is_synthesized = false;
169    m_type = eSymbolTypeInvalid;
170    m_flags = 0;
171    m_addr_range.Clear();
172}
173
174bool
175Symbol::ValueIsAddress() const
176{
177    return m_addr_range.GetBaseAddress().GetSection().get() != NULL;
178}
179
180ConstString
181Symbol::GetReExportedSymbolName() const
182{
183    if (m_type == eSymbolTypeReExported)
184    {
185        // For eSymbolTypeReExported, the "const char *" from a ConstString
186        // is used as the offset in the address range base address. We can
187        // then make this back into a string that is the re-exported name.
188        intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset();
189        if (str_ptr != 0)
190            return ConstString((const char *)str_ptr);
191        else
192            return GetName();
193    }
194    return ConstString();
195}
196
197FileSpec
198Symbol::GetReExportedSymbolSharedLibrary() const
199{
200    if (m_type == eSymbolTypeReExported)
201    {
202        // For eSymbolTypeReExported, the "const char *" from a ConstString
203        // is used as the offset in the address range base address. We can
204        // then make this back into a string that is the re-exported name.
205        intptr_t str_ptr = m_addr_range.GetByteSize();
206        if (str_ptr != 0)
207            return FileSpec((const char *)str_ptr, false);
208    }
209    return FileSpec();
210}
211
212bool
213Symbol::SetReExportedSymbolName(const ConstString &name)
214{
215    if (m_type == eSymbolTypeReExported)
216    {
217        // For eSymbolTypeReExported, the "const char *" from a ConstString
218        // is used as the offset in the address range base address.
219        m_addr_range.GetBaseAddress().SetOffset((intptr_t)name.GetCString());
220        return true;
221    }
222    return false;
223
224}
225
226bool
227Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec)
228{
229    if (m_type == eSymbolTypeReExported)
230    {
231        // For eSymbolTypeReExported, the "const char *" from a ConstString
232        // is used as the offset in the address range base address.
233        m_addr_range.SetByteSize((intptr_t)ConstString(fspec.GetPath().c_str()).GetCString());
234        return true;
235    }
236    return false;
237
238}
239
240uint32_t
241Symbol::GetSiblingIndex() const
242{
243    return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
244}
245
246bool
247Symbol::IsTrampoline () const
248{
249    return m_type == eSymbolTypeTrampoline;
250}
251
252bool
253Symbol::IsIndirect () const
254{
255    return m_type == eSymbolTypeResolver;
256}
257
258void
259Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const
260{
261    s->Printf("id = {0x%8.8x}", m_uid);
262
263    if (m_addr_range.GetBaseAddress().GetSection())
264    {
265        if (ValueIsAddress())
266        {
267            const lldb::addr_t byte_size = GetByteSize();
268            if (byte_size > 0)
269            {
270                s->PutCString (", range = ");
271                m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
272            }
273            else
274            {
275                s->PutCString (", address = ");
276                m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
277            }
278        }
279        else
280            s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
281    }
282    else
283    {
284        if (m_size_is_sibling)
285            s->Printf (", sibling = %5" PRIu64, m_addr_range.GetBaseAddress().GetOffset());
286        else
287            s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
288    }
289    if (m_mangled.GetDemangledName())
290        s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString());
291    if (m_mangled.GetMangledName())
292        s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString());
293
294}
295
296void
297Symbol::Dump(Stream *s, Target *target, uint32_t index) const
298{
299//  s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
300//  s->Indent();
301//  s->Printf("Symbol[%5u] %6u %c%c %-12s ",
302    s->Printf("[%5u] %6u %c%c%c %-12s ",
303              index,
304              GetID(),
305              m_is_debug ? 'D' : ' ',
306              m_is_synthetic ? 'S' : ' ',
307              m_is_external ? 'X' : ' ',
308              GetTypeAsString());
309
310    // Make sure the size of the symbol is up to date before dumping
311    GetByteSize();
312
313    if (ValueIsAddress())
314    {
315        if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress))
316            s->Printf("%*s", 18, "");
317
318        s->PutChar(' ');
319
320        if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress))
321            s->Printf("%*s", 18, "");
322
323        const char *format = m_size_is_sibling ?
324                            " Sibling -> [%5llu] 0x%8.8x %s\n":
325                            " 0x%16.16" PRIx64 " 0x%8.8x %s\n";
326        s->Printf(  format,
327                    GetByteSize(),
328                    m_flags,
329                    m_mangled.GetName().AsCString(""));
330    }
331    else if (m_type == eSymbolTypeReExported)
332    {
333        s->Printf ("                                                         0x%8.8x %s",
334                   m_flags,
335                   m_mangled.GetName().AsCString(""));
336
337        ConstString reexport_name = GetReExportedSymbolName();
338        intptr_t shlib = m_addr_range.GetByteSize();
339        if (shlib)
340            s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());
341        else
342            s->Printf(" -> %s\n", reexport_name.GetCString());
343    }
344    else
345    {
346        const char *format = m_size_is_sibling ?
347                            "0x%16.16" PRIx64 "                    Sibling -> [%5llu] 0x%8.8x %s\n":
348                            "0x%16.16" PRIx64 "                    0x%16.16" PRIx64 " 0x%8.8x %s\n";
349        s->Printf(  format,
350                    m_addr_range.GetBaseAddress().GetOffset(),
351                    GetByteSize(),
352                    m_flags,
353                    m_mangled.GetName().AsCString(""));
354    }
355}
356
357uint32_t
358Symbol::GetPrologueByteSize ()
359{
360    if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver)
361    {
362        if (!m_type_data_resolved)
363        {
364            m_type_data_resolved = true;
365
366            const Address &base_address = m_addr_range.GetBaseAddress();
367            Function *function = base_address.CalculateSymbolContextFunction();
368            if (function)
369            {
370                // Functions have line entries which can also potentially have end of prologue information.
371                // So if this symbol points to a function, use the prologue information from there.
372                m_type_data = function->GetPrologueByteSize();
373            }
374            else
375            {
376                ModuleSP module_sp (base_address.GetModule());
377                SymbolContext sc;
378                if (module_sp)
379                {
380                    uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address,
381                                                                                         eSymbolContextLineEntry,
382                                                                                         sc);
383                    if (resolved_flags & eSymbolContextLineEntry)
384                    {
385                        // Default to the end of the first line entry.
386                        m_type_data = sc.line_entry.range.GetByteSize();
387
388                        // Set address for next line.
389                        Address addr (base_address);
390                        addr.Slide (m_type_data);
391
392                        // Check the first few instructions and look for one that has a line number that is
393                        // different than the first entry. This is also done in Function::GetPrologueByteSize().
394                        uint16_t total_offset = m_type_data;
395                        for (int idx = 0; idx < 6; ++idx)
396                        {
397                            SymbolContext sc_temp;
398                            resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp);
399                            // Make sure we got line number information...
400                            if (!(resolved_flags & eSymbolContextLineEntry))
401                                break;
402
403                            // If this line number is different than our first one, use it and we're done.
404                            if (sc_temp.line_entry.line != sc.line_entry.line)
405                            {
406                                m_type_data = total_offset;
407                                break;
408                            }
409
410                            // Slide addr up to the next line address.
411                            addr.Slide (sc_temp.line_entry.range.GetByteSize());
412                            total_offset += sc_temp.line_entry.range.GetByteSize();
413                            // If we've gone too far, bail out.
414                            if (total_offset >= m_addr_range.GetByteSize())
415                                break;
416                        }
417
418                        // Sanity check - this may be a function in the middle of code that has debug information, but
419                        // not for this symbol.  So the line entries surrounding us won't lie inside our function.
420                        // In that case, the line entry will be bigger than we are, so we do that quick check and
421                        // if that is true, we just return 0.
422                        if (m_type_data >= m_addr_range.GetByteSize())
423                            m_type_data = 0;
424                    }
425                    else
426                    {
427                        // TODO: expose something in Process to figure out the
428                        // size of a function prologue.
429                        m_type_data = 0;
430                    }
431                }
432            }
433        }
434        return m_type_data;
435    }
436    return 0;
437}
438
439bool
440Symbol::Compare(const ConstString& name, SymbolType type) const
441{
442    if (type == eSymbolTypeAny || m_type == type)
443        return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name;
444    return false;
445}
446
447#define ENUM_TO_CSTRING(x)  case eSymbolType##x: return #x;
448
449const char *
450Symbol::GetTypeAsString() const
451{
452    switch (m_type)
453    {
454    ENUM_TO_CSTRING(Invalid);
455    ENUM_TO_CSTRING(Absolute);
456    ENUM_TO_CSTRING(Code);
457    ENUM_TO_CSTRING(Resolver);
458    ENUM_TO_CSTRING(Data);
459    ENUM_TO_CSTRING(Trampoline);
460    ENUM_TO_CSTRING(Runtime);
461    ENUM_TO_CSTRING(Exception);
462    ENUM_TO_CSTRING(SourceFile);
463    ENUM_TO_CSTRING(HeaderFile);
464    ENUM_TO_CSTRING(ObjectFile);
465    ENUM_TO_CSTRING(CommonBlock);
466    ENUM_TO_CSTRING(Block);
467    ENUM_TO_CSTRING(Local);
468    ENUM_TO_CSTRING(Param);
469    ENUM_TO_CSTRING(Variable);
470    ENUM_TO_CSTRING(VariableType);
471    ENUM_TO_CSTRING(LineEntry);
472    ENUM_TO_CSTRING(LineHeader);
473    ENUM_TO_CSTRING(ScopeBegin);
474    ENUM_TO_CSTRING(ScopeEnd);
475    ENUM_TO_CSTRING(Additional);
476    ENUM_TO_CSTRING(Compiler);
477    ENUM_TO_CSTRING(Instrumentation);
478    ENUM_TO_CSTRING(Undefined);
479    ENUM_TO_CSTRING(ObjCClass);
480    ENUM_TO_CSTRING(ObjCMetaClass);
481    ENUM_TO_CSTRING(ObjCIVar);
482    ENUM_TO_CSTRING(ReExported);
483    default:
484        break;
485    }
486    return "<unknown SymbolType>";
487}
488
489void
490Symbol::CalculateSymbolContext (SymbolContext *sc)
491{
492    // Symbols can reconstruct the symbol and the module in the symbol context
493    sc->symbol = this;
494    if (ValueIsAddress())
495        sc->module_sp = GetAddress().GetModule();
496    else
497        sc->module_sp.reset();
498}
499
500ModuleSP
501Symbol::CalculateSymbolContextModule ()
502{
503    if (ValueIsAddress())
504        return GetAddress().GetModule();
505    return ModuleSP();
506}
507
508Symbol *
509Symbol::CalculateSymbolContextSymbol ()
510{
511    return this;
512}
513
514void
515Symbol::DumpSymbolContext (Stream *s)
516{
517    bool dumped_module = false;
518    if (ValueIsAddress())
519    {
520        ModuleSP module_sp (GetAddress().GetModule());
521        if (module_sp)
522        {
523            dumped_module = true;
524            module_sp->DumpSymbolContext(s);
525        }
526    }
527    if (dumped_module)
528        s->PutCString(", ");
529
530    s->Printf("Symbol{0x%8.8x}", GetID());
531}
532
533lldb::addr_t
534Symbol::GetByteSize () const
535{
536    return m_addr_range.GetByteSize();
537}
538
539Symbol *
540Symbol::ResolveReExportedSymbol (Target &target)
541{
542    ConstString reexport_name (GetReExportedSymbolName());
543    if (reexport_name)
544    {
545        ModuleSpec module_spec;
546        ModuleSP module_sp;
547        module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
548        if (module_spec.GetFileSpec())
549        {
550            // Try searching for the module file spec first using the full path
551            module_sp = target.GetImages().FindFirstModule(module_spec);
552            if (!module_sp)
553            {
554                // Next try and find the module by basename in case environment
555                // variables or other runtime trickery causes shared libraries
556                // to be loaded from alternate paths
557                module_spec.GetFileSpec().GetDirectory().Clear();
558                module_sp = target.GetImages().FindFirstModule(module_spec);
559            }
560        }
561
562        if (module_sp)
563        {
564            lldb_private::SymbolContextList sc_list;
565            module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list);
566            const size_t num_scs = sc_list.GetSize();
567            if (num_scs > 0)
568            {
569                for (size_t i=0; i<num_scs; ++i)
570                {
571                    lldb_private::SymbolContext sc;
572                    if (sc_list.GetContextAtIndex(i, sc))
573                    {
574                        if (sc.symbol->IsExternal())
575                            return sc.symbol;
576                    }
577                }
578            }
579        }
580    }
581    return NULL;
582}
583