DWARFDebugInfo.cpp revision 296417
1//===-- DWARFDebugInfo.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 "SymbolFileDWARF.h"
11
12#include <algorithm>
13#include <set>
14
15#include "lldb/Core/RegularExpression.h"
16#include "lldb/Core/Stream.h"
17#include "lldb/Symbol/ObjectFile.h"
18
19#include "DWARFDebugAranges.h"
20#include "DWARFDebugInfo.h"
21#include "DWARFCompileUnit.h"
22#include "DWARFDebugAranges.h"
23#include "DWARFDebugInfoEntry.h"
24#include "DWARFFormValue.h"
25#include "LogChannelDWARF.h"
26
27using namespace lldb;
28using namespace lldb_private;
29using namespace std;
30
31//----------------------------------------------------------------------
32// Constructor
33//----------------------------------------------------------------------
34DWARFDebugInfo::DWARFDebugInfo() :
35    m_dwarf2Data(NULL),
36    m_compile_units(),
37    m_cu_aranges_ap ()
38{
39}
40
41//----------------------------------------------------------------------
42// SetDwarfData
43//----------------------------------------------------------------------
44void
45DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data)
46{
47    m_dwarf2Data = dwarf2Data;
48    m_compile_units.clear();
49}
50
51
52DWARFDebugAranges &
53DWARFDebugInfo::GetCompileUnitAranges ()
54{
55    if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data)
56    {
57        Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
58
59        m_cu_aranges_ap.reset (new DWARFDebugAranges());
60        const DWARFDataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data();
61        if (debug_aranges_data.GetByteSize() > 0)
62        {
63            if (log)
64                log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges",
65                             m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
66            m_cu_aranges_ap->Extract (debug_aranges_data);
67
68        }
69
70        // Make a list of all CUs represented by the arange data in the file.
71        std::set<dw_offset_t> cus_with_data;
72        for (size_t n=0;n<m_cu_aranges_ap.get()->GetNumRanges();n++)
73        {
74            dw_offset_t offset = m_cu_aranges_ap.get()->OffsetAtIndex(n);
75            if (offset != DW_INVALID_OFFSET)
76                cus_with_data.insert (offset);
77        }
78
79        // Manually build arange data for everything that wasn't in the .debug_aranges table.
80        bool printed = false;
81        const size_t num_compile_units = GetNumCompileUnits();
82        for (size_t idx = 0; idx < num_compile_units; ++idx)
83        {
84            DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
85
86            dw_offset_t offset = cu->GetOffset();
87            if (cus_with_data.find(offset) == cus_with_data.end())
88            {
89                if (log)
90                {
91                    if (!printed)
92                        log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing",
93                                     m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
94                    printed = true;
95                }
96                cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get());
97            }
98        }
99
100        const bool minimize = true;
101        m_cu_aranges_ap->Sort (minimize);
102    }
103    return *m_cu_aranges_ap.get();
104}
105
106void
107DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded()
108{
109    if (m_compile_units.empty())
110    {
111        if (m_dwarf2Data != NULL)
112        {
113            lldb::offset_t offset = 0;
114            const DWARFDataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data();
115            while (debug_info_data.ValidOffset(offset))
116            {
117                DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data));
118                // Out of memory?
119                if (cu_sp.get() == NULL)
120                    break;
121
122                if (cu_sp->Extract(debug_info_data, &offset) == false)
123                    break;
124
125                m_compile_units.push_back(cu_sp);
126
127                offset = cu_sp->GetNextCompileUnitOffset();
128            }
129        }
130    }
131}
132
133size_t
134DWARFDebugInfo::GetNumCompileUnits()
135{
136    ParseCompileUnitHeadersIfNeeded();
137    return m_compile_units.size();
138}
139
140DWARFCompileUnit*
141DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx)
142{
143    DWARFCompileUnit* cu = NULL;
144    if (idx < GetNumCompileUnits())
145        cu = m_compile_units[idx].get();
146    return cu;
147}
148
149bool
150DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const
151{
152    // Not a verify efficient function, but it is handy for use in assertions
153    // to make sure that a compile unit comes from a debug information file.
154    CompileUnitColl::const_iterator end_pos = m_compile_units.end();
155    CompileUnitColl::const_iterator pos;
156
157    for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
158    {
159        if (pos->get() == cu)
160            return true;
161    }
162    return false;
163}
164
165bool
166DWARFDebugInfo::OffsetLessThanCompileUnitOffset (dw_offset_t offset, const DWARFCompileUnitSP& cu_sp)
167{
168    return offset < cu_sp->GetOffset();
169}
170
171DWARFCompileUnit *
172DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr)
173{
174    DWARFCompileUnitSP cu_sp;
175    uint32_t cu_idx = DW_INVALID_INDEX;
176    if (cu_offset != DW_INVALID_OFFSET)
177    {
178        ParseCompileUnitHeadersIfNeeded();
179
180        // Watch out for single compile unit executable as they are pretty common
181        const size_t num_cus = m_compile_units.size();
182        if (num_cus == 1)
183        {
184            if (m_compile_units[0]->GetOffset() == cu_offset)
185            {
186                cu_sp = m_compile_units[0];
187                cu_idx = 0;
188            }
189        }
190        else if (num_cus)
191        {
192            CompileUnitColl::const_iterator end_pos = m_compile_units.end();
193            CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
194            CompileUnitColl::const_iterator pos = std::upper_bound(begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset);
195            if (pos != begin_pos)
196            {
197                --pos;
198                if ((*pos)->GetOffset() == cu_offset)
199                {
200                    cu_sp = *pos;
201                    cu_idx = std::distance(begin_pos, pos);
202                }
203            }
204        }
205    }
206    if (idx_ptr)
207        *idx_ptr = cu_idx;
208    return cu_sp.get();
209}
210
211DWARFCompileUnit *
212DWARFDebugInfo::GetCompileUnitContainingDIE (const DIERef& die_ref)
213{
214    dw_offset_t search_offset = die_ref.die_offset;
215    bool is_cu_offset = false;
216    if (m_dwarf2Data->GetID() == 0 && die_ref.cu_offset != DW_INVALID_OFFSET)
217    {
218        is_cu_offset = true;
219        search_offset = die_ref.cu_offset;
220    }
221
222    DWARFCompileUnitSP cu_sp;
223    if (search_offset != DW_INVALID_OFFSET)
224    {
225        ParseCompileUnitHeadersIfNeeded();
226
227        // Watch out for single compile unit executable as they are pretty common
228        const size_t num_cus = m_compile_units.size();
229        if (num_cus == 1)
230        {
231            if ((is_cu_offset && m_compile_units[0]->GetOffset() == search_offset) ||
232                (!is_cu_offset && m_compile_units[0]->ContainsDIEOffset(search_offset)))
233            {
234                cu_sp = m_compile_units[0];
235            }
236        }
237        else if (num_cus)
238        {
239            CompileUnitColl::const_iterator end_pos = m_compile_units.end();
240            CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
241            CompileUnitColl::const_iterator pos = std::upper_bound(begin_pos, end_pos, search_offset, OffsetLessThanCompileUnitOffset);
242            if (pos != begin_pos)
243            {
244                --pos;
245                if ((is_cu_offset && (*pos)->GetOffset() == search_offset) ||
246                    (!is_cu_offset && (*pos)->ContainsDIEOffset(search_offset)))
247                {
248                    cu_sp = *pos;
249                }
250            }
251        }
252    }
253    return cu_sp.get();
254}
255
256//----------------------------------------------------------------------
257// GetDIE()
258//
259// Get the DIE (Debug Information Entry) with the specified offset.
260//----------------------------------------------------------------------
261DWARFDIE
262DWARFDebugInfo::GetDIE(const DIERef& die_ref)
263{
264    DWARFCompileUnit *cu = GetCompileUnitContainingDIE(die_ref);
265    if (cu)
266        return cu->GetDIE (die_ref.die_offset);
267    return DWARFDIE();    // Not found
268}
269
270//----------------------------------------------------------------------
271// Parse
272//
273// Parses the .debug_info section and uses the .debug_abbrev section
274// and various other sections in the SymbolFileDWARF class and calls the
275// supplied callback function each time a compile unit header, or debug
276// information entry is successfully parsed. This function can be used
277// for different tasks such as parsing the file contents into a
278// structured data, dumping, verifying and much more.
279//----------------------------------------------------------------------
280void
281DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData)
282{
283    if (dwarf2Data)
284    {
285        lldb::offset_t offset = 0;
286        uint32_t depth = 0;
287        DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data));
288        if (cu.get() == NULL)
289            return;
290        DWARFDebugInfoEntry die;
291
292        while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset))
293        {
294            const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
295
296            depth = 0;
297            // Call the callback function with no DIE pointer for the compile unit
298            // and get the offset that we are to continue to parse from
299            offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData);
300
301            // Make sure we are within our compile unit
302            if (offset < next_cu_offset)
303            {
304                // We are in our compile unit, parse starting at the offset
305                // we were told to parse
306                bool done = false;
307                while (!done && die.Extract(dwarf2Data, cu.get(), &offset))
308                {
309                    // Call the callback function with DIE pointer that falls within the compile unit
310                    offset = callback(dwarf2Data, cu.get(), &die, offset, depth, userData);
311
312                    if (die.IsNULL())
313                    {
314                        if (depth)
315                            --depth;
316                        else
317                            done = true;    // We are done with this compile unit!
318                    }
319                    else if (die.HasChildren())
320                        ++depth;
321                }
322            }
323
324            // Make sure the offset returned is valid, and if not stop parsing.
325            // Returning DW_INVALID_OFFSET from this callback is a good way to end
326            // all parsing
327            if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
328                break;
329
330            // See if during the callback anyone retained a copy of the compile
331            // unit other than ourselves and if so, let whomever did own the object
332            // and create a new one for our own use!
333            if (!cu.unique())
334                cu.reset(new DWARFCompileUnit(dwarf2Data));
335
336
337            // Make sure we start on a proper
338            offset = next_cu_offset;
339        }
340    }
341}
342
343typedef struct DumpInfo
344{
345    DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
346        strm(init_strm),
347        die_offset(off),
348        recurse_depth(depth),
349        found_depth(UINT32_MAX),
350        found_die(false),
351        ancestors()
352    {
353    }
354    Stream* strm;
355    const uint32_t die_offset;
356    const uint32_t recurse_depth;
357    uint32_t found_depth;
358    bool found_die;
359    std::vector<DWARFDebugInfoEntry> ancestors;
360
361    DISALLOW_COPY_AND_ASSIGN(DumpInfo);
362} DumpInfo;
363
364//----------------------------------------------------------------------
365// DumpCallback
366//
367// A callback function for the static DWARFDebugInfo::Parse() function
368// that gets called each time a compile unit header or debug information
369// entry is successfully parsed.
370//
371// This function dump DWARF information and obey recurse depth and
372// whether a single DIE is to be dumped (or all of the data).
373//----------------------------------------------------------------------
374static dw_offset_t DumpCallback
375(
376    SymbolFileDWARF* dwarf2Data,
377    DWARFCompileUnit* cu,
378    DWARFDebugInfoEntry* die,
379    const dw_offset_t next_offset,
380    const uint32_t curr_depth,
381    void* userData
382)
383{
384    DumpInfo* dumpInfo = (DumpInfo*)userData;
385    Stream *s = dumpInfo->strm;
386    bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors);
387
388    if (die)
389    {
390        // Are we dumping everything?
391        if (dumpInfo->die_offset == DW_INVALID_OFFSET)
392        {
393            // Yes we are dumping everything. Obey our recurse level though
394            if (curr_depth < dumpInfo->recurse_depth)
395                die->Dump(dwarf2Data, cu, *s, 0);
396        }
397        else
398        {
399            // We are dumping a specific DIE entry by offset
400            if (dumpInfo->die_offset == die->GetOffset())
401            {
402                // We found the DIE we were looking for, dump it!
403                if (show_parents)
404                {
405                    s->SetIndentLevel(0);
406                    const uint32_t num_ancestors = dumpInfo->ancestors.size();
407                    if (num_ancestors > 0)
408                    {
409                        for (uint32_t i=0; i<num_ancestors-1; ++i)
410                        {
411                            dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0);
412                            s->IndentMore();
413                        }
414                    }
415                }
416
417                dumpInfo->found_depth = curr_depth;
418
419                die->Dump(dwarf2Data, cu, *s, 0);
420
421                // Note that we found the DIE we were looking for
422                dumpInfo->found_die = true;
423
424                // Since we are dumping a single DIE, if there are no children we are done!
425                if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
426                    return DW_INVALID_OFFSET;   // Return an invalid address to end parsing
427            }
428            else if (dumpInfo->found_die)
429            {
430                // Are we done with all the children?
431                if (curr_depth <= dumpInfo->found_depth)
432                    return DW_INVALID_OFFSET;
433
434                // We have already found our DIE and are printing it's children. Obey
435                // our recurse depth and return an invalid offset if we get done
436                // dumping all of the children
437                if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
438                    die->Dump(dwarf2Data, cu, *s, 0);
439            }
440            else if (dumpInfo->die_offset > die->GetOffset())
441            {
442                if (show_parents)
443                    dumpInfo->ancestors.back() = *die;
444            }
445        }
446
447        // Keep up with our indent level
448        if (die->IsNULL())
449        {
450            if (show_parents)
451                dumpInfo->ancestors.pop_back();
452
453            if (curr_depth <= 1)
454                return cu->GetNextCompileUnitOffset();
455            else
456                s->IndentLess();
457        }
458        else if (die->HasChildren())
459        {
460            if (show_parents)
461            {
462                DWARFDebugInfoEntry null_die;
463                dumpInfo->ancestors.push_back(null_die);
464            }
465            s->IndentMore();
466        }
467    }
468    else
469    {
470        if (cu == NULL)
471            s->PutCString("NULL - cu");
472        // We have a compile unit, reset our indent level to zero just in case
473        s->SetIndentLevel(0);
474
475        // See if we are dumping everything?
476        if (dumpInfo->die_offset == DW_INVALID_OFFSET)
477        {
478            // We are dumping everything
479            if (cu)
480            {
481                cu->Dump(s);
482                return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
483            }
484            else
485            {
486                return DW_INVALID_OFFSET;
487            }
488        }
489        else
490        {
491            if (show_parents)
492            {
493                dumpInfo->ancestors.clear();
494                dumpInfo->ancestors.resize(1);
495            }
496
497            // We are dumping only a single DIE possibly with it's children and
498            // we must find it's compile unit before we can dump it properly
499            if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset())
500            {
501                // Not found, maybe the DIE offset provided wasn't correct?
502            //  *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
503                return DW_INVALID_OFFSET;
504            }
505            else
506            {
507                // See if the DIE is in this compile unit?
508                if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
509                {
510                    // This DIE is in this compile unit!
511                    if (s->GetVerbose())
512                        cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
513
514                    return next_offset;
515                //  // We found our compile unit that contains our DIE, just skip to dumping the requested DIE...
516                //  return dumpInfo->die_offset;
517                }
518                else
519                {
520                    // Skip to the next compile unit as the DIE isn't in the current one!
521                    if (cu)
522                    {
523                        return cu->GetNextCompileUnitOffset();
524                    }
525                    else
526                    {
527                        return DW_INVALID_OFFSET;
528                    }
529                }
530            }
531        }
532    }
533
534    // Just return the current offset to parse the next CU or DIE entry
535    return next_offset;
536}
537
538//----------------------------------------------------------------------
539// Dump
540//
541// Dump the information in the .debug_info section to the specified
542// ostream. If die_offset is valid, a single DIE will be dumped. If the
543// die_offset is invalid, all the DWARF information will be dumped. Both
544// cases will obey a "recurse_depth" or how deep to traverse into the
545// children of each DIE entry. A recurse_depth of zero will dump all
546// compile unit headers. A recurse_depth of 1 will dump all compile unit
547// headers and the DW_TAG_compile unit tags. A depth of 2 will also
548// dump all types and functions.
549//----------------------------------------------------------------------
550void
551DWARFDebugInfo::Dump
552(
553    Stream *s,
554    SymbolFileDWARF* dwarf2Data,
555    const uint32_t die_offset,
556    const uint32_t recurse_depth
557)
558{
559    DumpInfo dumpInfo(s, die_offset, recurse_depth);
560    s->PutCString(".debug_info contents");
561    if (dwarf2Data->get_debug_info_data().GetByteSize() > 0)
562    {
563        if (die_offset == DW_INVALID_OFFSET)
564            s->PutCString(":\n");
565        else
566        {
567            s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
568            if (recurse_depth != UINT32_MAX)
569                s->Printf(" recursing %u levels deep.", recurse_depth);
570            s->EOL();
571        }
572    }
573    else
574    {
575        s->PutCString(": < EMPTY >\n");
576        return;
577    }
578    DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
579}
580
581
582//----------------------------------------------------------------------
583// Dump
584//
585// Dump the contents of this DWARFDebugInfo object as has been parsed
586// and/or modified after it has been parsed.
587//----------------------------------------------------------------------
588void
589DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth)
590{
591    DumpInfo dumpInfo(s, die_offset, recurse_depth);
592
593    s->PutCString("Dumping .debug_info section from internal representation\n");
594
595    CompileUnitColl::const_iterator pos;
596    uint32_t curr_depth = 0;
597    ParseCompileUnitHeadersIfNeeded();
598    for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos)
599    {
600        DWARFCompileUnit *cu = pos->get();
601        DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo);
602
603        const DWARFDIE die = cu->DIE();
604        if (die)
605            die.Dump(s, recurse_depth);
606    }
607}
608
609
610//----------------------------------------------------------------------
611// FindCallbackString
612//
613// A callback function for the static DWARFDebugInfo::Parse() function
614// that gets called each time a compile unit header or debug information
615// entry is successfully parsed.
616//
617// This function will find the die_offset of any items whose DW_AT_name
618// matches the given string
619//----------------------------------------------------------------------
620typedef struct FindCallbackStringInfoTag
621{
622    const char* name;
623    bool ignore_case;
624    RegularExpression* regex;
625    vector<dw_offset_t>& die_offsets;
626} FindCallbackStringInfo;
627
628static dw_offset_t FindCallbackString
629(
630    SymbolFileDWARF* dwarf2Data,
631    DWARFCompileUnit* cu,
632    DWARFDebugInfoEntry* die,
633    const dw_offset_t next_offset,
634    const uint32_t curr_depth,
635    void* userData
636)
637{
638    FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData;
639
640    if (die)
641    {
642        const char* die_name = die->GetName(dwarf2Data, cu);
643        if (die_name)
644        {
645            if (info->regex)
646            {
647                if (info->regex->Execute(die_name))
648                    info->die_offsets.push_back(die->GetOffset());
649            }
650            else
651            {
652                if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0)
653                    info->die_offsets.push_back(die->GetOffset());
654            }
655        }
656    }
657
658    // Just return the current offset to parse the next CU or DIE entry
659    return next_offset;
660}
661
662//----------------------------------------------------------------------
663// Find
664//
665// Finds all DIE that have a specific DW_AT_name attribute by manually
666// searching through the debug information (not using the
667// .debug_pubnames section). The string must match the entire name
668// and case sensitive searches are an option.
669//----------------------------------------------------------------------
670bool
671DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const
672{
673    die_offsets.clear();
674    if (name && name[0])
675    {
676        FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets };
677        DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
678    }
679    return !die_offsets.empty();
680}
681
682//----------------------------------------------------------------------
683// Find
684//
685// Finds all DIE that have a specific DW_AT_name attribute by manually
686// searching through the debug information (not using the
687// .debug_pubnames section). The string must match the supplied regular
688// expression.
689//----------------------------------------------------------------------
690bool
691DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const
692{
693    die_offsets.clear();
694    FindCallbackStringInfo info = { NULL, false, &re, die_offsets };
695    DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
696    return !die_offsets.empty();
697}
698