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
22using namespace lldb;
23using namespace lldb_private;
24
25
26Symbol::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
45Symbol::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
79Symbol::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
111Symbol::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
130const Symbol&
131Symbol::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
154void
155Symbol::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
173bool
174Symbol::ValueIsAddress() const
175{
176    return m_addr_range.GetBaseAddress().GetSection().get() != NULL;
177}
178
179uint32_t
180Symbol::GetSiblingIndex() const
181{
182    return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
183}
184
185bool
186Symbol::IsTrampoline () const
187{
188    return m_type == eSymbolTypeTrampoline;
189}
190
191bool
192Symbol::IsIndirect () const
193{
194    return m_type == eSymbolTypeResolver;
195}
196
197void
198Symbol::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
235void
236Symbol::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
283uint32_t
284Symbol::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
365bool
366Symbol::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
375const char *
376Symbol::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
413void
414Symbol::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
424ModuleSP
425Symbol::CalculateSymbolContextModule ()
426{
427    if (ValueIsAddress())
428        return GetAddress().GetModule();
429    return ModuleSP();
430}
431
432Symbol *
433Symbol::CalculateSymbolContextSymbol ()
434{
435    return this;
436}
437
438void
439Symbol::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
457lldb::addr_t
458Symbol::GetByteSize () const
459{
460    return m_addr_range.GetByteSize();
461}
462
463