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 DataExtractor &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        else
70        {
71            if (log)
72                log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing",
73                             m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
74            const size_t num_compile_units = GetNumCompileUnits();
75            const bool clear_dies_if_already_not_parsed = true;
76            for (size_t idx = 0; idx < num_compile_units; ++idx)
77            {
78                DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
79                if (cu)
80                    cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed);
81            }
82        }
83
84        const bool minimize = true;
85        m_cu_aranges_ap->Sort (minimize);
86    }
87    return *m_cu_aranges_ap.get();
88}
89
90
91//----------------------------------------------------------------------
92// LookupAddress
93//----------------------------------------------------------------------
94bool
95DWARFDebugInfo::LookupAddress
96(
97    const dw_addr_t address,
98    const dw_offset_t hint_die_offset,
99    DWARFCompileUnitSP& cu_sp,
100    DWARFDebugInfoEntry** function_die,
101    DWARFDebugInfoEntry** block_die
102)
103{
104
105    if (hint_die_offset != DW_INVALID_OFFSET)
106        cu_sp = GetCompileUnit(hint_die_offset);
107    else
108    {
109        DWARFDebugAranges &cu_aranges = GetCompileUnitAranges ();
110        const dw_offset_t cu_offset = cu_aranges.FindAddress (address);
111        cu_sp = GetCompileUnit(cu_offset);
112    }
113
114    if (cu_sp.get())
115    {
116        if (cu_sp->LookupAddress(address, function_die, block_die))
117            return true;
118        cu_sp.reset();
119    }
120    else
121    {
122        // The hint_die_offset may have been a pointer to the actual item that
123        // we are looking for
124        DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp);
125        if (die_ptr)
126        {
127            if (cu_sp.get())
128            {
129                if (function_die || block_die)
130                    return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die);
131
132                // We only wanted the compile unit that contained this address
133                return true;
134            }
135        }
136    }
137    return false;
138}
139
140
141void
142DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded()
143{
144    if (m_compile_units.empty())
145    {
146        if (m_dwarf2Data != NULL)
147        {
148            lldb::offset_t offset = 0;
149            const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data();
150            while (debug_info_data.ValidOffset(offset))
151            {
152                DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data));
153                // Out of memory?
154                if (cu_sp.get() == NULL)
155                    break;
156
157                if (cu_sp->Extract(debug_info_data, &offset) == false)
158                    break;
159
160                m_compile_units.push_back(cu_sp);
161
162                offset = cu_sp->GetNextCompileUnitOffset();
163            }
164        }
165    }
166}
167
168size_t
169DWARFDebugInfo::GetNumCompileUnits()
170{
171    ParseCompileUnitHeadersIfNeeded();
172    return m_compile_units.size();
173}
174
175DWARFCompileUnit*
176DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx)
177{
178    DWARFCompileUnit* cu = NULL;
179    if (idx < GetNumCompileUnits())
180        cu = m_compile_units[idx].get();
181    return cu;
182}
183
184bool
185DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const
186{
187    // Not a verify efficient function, but it is handy for use in assertions
188    // to make sure that a compile unit comes from a debug information file.
189    CompileUnitColl::const_iterator end_pos = m_compile_units.end();
190    CompileUnitColl::const_iterator pos;
191
192    for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
193    {
194        if (pos->get() == cu)
195            return true;
196    }
197    return false;
198}
199
200
201static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b)
202{
203    return a->GetOffset() < b->GetOffset();
204}
205
206
207static int
208CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem)
209{
210    const dw_offset_t key_cu_offset = *(dw_offset_t*) key;
211    const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset();
212    if (key_cu_offset < cu_offset)
213        return -1;
214    if (key_cu_offset > cu_offset)
215        return 1;
216    return 0;
217}
218
219DWARFCompileUnitSP
220DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr)
221{
222    DWARFCompileUnitSP cu_sp;
223    uint32_t cu_idx = DW_INVALID_INDEX;
224    if (cu_offset != DW_INVALID_OFFSET)
225    {
226        ParseCompileUnitHeadersIfNeeded();
227
228        DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset);
229        if (match)
230        {
231            cu_sp = *match;
232            cu_idx = match - &m_compile_units[0];
233        }
234    }
235    if (idx_ptr)
236        *idx_ptr = cu_idx;
237    return cu_sp;
238}
239
240DWARFCompileUnitSP
241DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset)
242{
243    DWARFCompileUnitSP cu_sp;
244    if (die_offset != DW_INVALID_OFFSET)
245    {
246        ParseCompileUnitHeadersIfNeeded();
247
248        CompileUnitColl::const_iterator end_pos = m_compile_units.end();
249        CompileUnitColl::const_iterator pos;
250
251        for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
252        {
253            dw_offset_t cu_start_offset = (*pos)->GetOffset();
254            dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset();
255            if (cu_start_offset <= die_offset && die_offset < cu_end_offset)
256            {
257                cu_sp = *pos;
258                break;
259            }
260        }
261    }
262    return cu_sp;
263}
264
265//----------------------------------------------------------------------
266// Compare function DWARFDebugAranges::Range structures
267//----------------------------------------------------------------------
268static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
269{
270    return die1.GetOffset() < die2.GetOffset();
271}
272
273
274//----------------------------------------------------------------------
275// GetDIE()
276//
277// Get the DIE (Debug Information Entry) with the specified offset.
278//----------------------------------------------------------------------
279DWARFDebugInfoEntry*
280DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
281{
282    DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
283    if (cu_sp_ptr)
284        *cu_sp_ptr = cu_sp;
285    if (cu_sp.get())
286        return cu_sp->GetDIEPtr(die_offset);
287    return NULL;    // Not found in any compile units
288}
289
290DWARFDebugInfoEntry*
291DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle)
292{
293    assert (cu_handle);
294    DWARFDebugInfoEntry* die = NULL;
295    if (*cu_handle)
296        die = (*cu_handle)->GetDIEPtr(die_offset);
297
298    if (die == NULL)
299    {
300        DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset));
301        if (cu_sp.get())
302        {
303            *cu_handle = cu_sp.get();
304            die = cu_sp->GetDIEPtr(die_offset);
305        }
306    }
307    if (die == NULL)
308        *cu_handle = NULL;
309    return die;
310}
311
312
313const DWARFDebugInfoEntry*
314DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
315{
316    DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
317    if (cu_sp_ptr)
318        *cu_sp_ptr = cu_sp;
319    if (cu_sp.get())
320        return cu_sp->GetDIEPtrContainingOffset(die_offset);
321
322    return NULL;    // Not found in any compile units
323
324}
325
326//----------------------------------------------------------------------
327// DWARFDebugInfo_ParseCallback
328//
329// A callback function for the static DWARFDebugInfo::Parse() function
330// that gets parses all compile units and DIE's into an internate
331// representation for further modification.
332//----------------------------------------------------------------------
333
334static dw_offset_t
335DWARFDebugInfo_ParseCallback
336(
337    SymbolFileDWARF* dwarf2Data,
338    DWARFCompileUnitSP& cu_sp,
339    DWARFDebugInfoEntry* die,
340    const dw_offset_t next_offset,
341    const uint32_t curr_depth,
342    void* userData
343)
344{
345    DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData;
346    DWARFCompileUnit* cu = cu_sp.get();
347    if (die)
348    {
349        cu->AddDIE(*die);
350    }
351    else if (cu)
352    {
353        debug_info->AddCompileUnit(cu_sp);
354    }
355
356    // Just return the current offset to parse the next CU or DIE entry
357    return next_offset;
358}
359
360//----------------------------------------------------------------------
361// AddCompileUnit
362//----------------------------------------------------------------------
363void
364DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu)
365{
366    m_compile_units.push_back(cu);
367}
368
369/*
370void
371DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die)
372{
373    m_die_array.push_back(die);
374}
375*/
376
377
378
379
380//----------------------------------------------------------------------
381// Parse
382//
383// Parses the .debug_info section and uses the .debug_abbrev section
384// and various other sections in the SymbolFileDWARF class and calls the
385// supplied callback function each time a compile unit header, or debug
386// information entry is successfully parsed. This function can be used
387// for different tasks such as parsing the file contents into a
388// structured data, dumping, verifying and much more.
389//----------------------------------------------------------------------
390void
391DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData)
392{
393    if (dwarf2Data)
394    {
395        lldb::offset_t offset = 0;
396        uint32_t depth = 0;
397        DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data));
398        if (cu.get() == NULL)
399            return;
400        DWARFDebugInfoEntry die;
401
402        while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset))
403        {
404            const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
405
406            depth = 0;
407            // Call the callback function with no DIE pointer for the compile unit
408            // and get the offset that we are to continue to parse from
409            offset = callback(dwarf2Data, cu, NULL, offset, depth, userData);
410
411            // Make sure we are within our compile unit
412            if (offset < next_cu_offset)
413            {
414                // We are in our compile unit, parse starting at the offset
415                // we were told to parse
416                bool done = false;
417                while (!done && die.Extract(dwarf2Data, cu.get(), &offset))
418                {
419                    // Call the callback function with DIE pointer that falls within the compile unit
420                    offset = callback(dwarf2Data, cu, &die, offset, depth, userData);
421
422                    if (die.IsNULL())
423                    {
424                        if (depth)
425                            --depth;
426                        else
427                            done = true;    // We are done with this compile unit!
428                    }
429                    else if (die.HasChildren())
430                        ++depth;
431                }
432            }
433
434            // Make sure the offset returned is valid, and if not stop parsing.
435            // Returning DW_INVALID_OFFSET from this callback is a good way to end
436            // all parsing
437            if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
438                break;
439
440            // See if during the callback anyone retained a copy of the compile
441            // unit other than ourselves and if so, let whomever did own the object
442            // and create a new one for our own use!
443            if (!cu.unique())
444                cu.reset(new DWARFCompileUnit(dwarf2Data));
445
446
447            // Make sure we start on a proper
448            offset = next_cu_offset;
449        }
450    }
451}
452
453typedef struct DumpInfo
454{
455    DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
456        strm(init_strm),
457        die_offset(off),
458        recurse_depth(depth),
459        found_depth(UINT32_MAX),
460        found_die(false),
461        ancestors()
462    {
463    }
464    Stream* strm;
465    const uint32_t die_offset;
466    const uint32_t recurse_depth;
467    uint32_t found_depth;
468    bool found_die;
469    std::vector<DWARFDebugInfoEntry> ancestors;
470
471    DISALLOW_COPY_AND_ASSIGN(DumpInfo);
472} DumpInfo;
473
474//----------------------------------------------------------------------
475// DumpCallback
476//
477// A callback function for the static DWARFDebugInfo::Parse() function
478// that gets called each time a compile unit header or debug information
479// entry is successfully parsed.
480//
481// This function dump DWARF information and obey recurse depth and
482// whether a single DIE is to be dumped (or all of the data).
483//----------------------------------------------------------------------
484static dw_offset_t DumpCallback
485(
486    SymbolFileDWARF* dwarf2Data,
487    DWARFCompileUnitSP& cu_sp,
488    DWARFDebugInfoEntry* die,
489    const dw_offset_t next_offset,
490    const uint32_t curr_depth,
491    void* userData
492)
493{
494    DumpInfo* dumpInfo = (DumpInfo*)userData;
495
496    const DWARFCompileUnit* cu = cu_sp.get();
497
498    Stream *s = dumpInfo->strm;
499    bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors);
500
501    if (die)
502    {
503        // Are we dumping everything?
504        if (dumpInfo->die_offset == DW_INVALID_OFFSET)
505        {
506            // Yes we are dumping everything. Obey our recurse level though
507            if (curr_depth < dumpInfo->recurse_depth)
508                die->Dump(dwarf2Data, cu, *s, 0);
509        }
510        else
511        {
512            // We are dumping a specific DIE entry by offset
513            if (dumpInfo->die_offset == die->GetOffset())
514            {
515                // We found the DIE we were looking for, dump it!
516                if (show_parents)
517                {
518                    s->SetIndentLevel(0);
519                    const uint32_t num_ancestors = dumpInfo->ancestors.size();
520                    if (num_ancestors > 0)
521                    {
522                        for (uint32_t i=0; i<num_ancestors-1; ++i)
523                        {
524                            dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0);
525                            s->IndentMore();
526                        }
527                    }
528                }
529
530                dumpInfo->found_depth = curr_depth;
531
532                die->Dump(dwarf2Data, cu, *s, 0);
533
534                // Note that we found the DIE we were looking for
535                dumpInfo->found_die = true;
536
537                // Since we are dumping a single DIE, if there are no children we are done!
538                if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
539                    return DW_INVALID_OFFSET;   // Return an invalid address to end parsing
540            }
541            else if (dumpInfo->found_die)
542            {
543                // Are we done with all the children?
544                if (curr_depth <= dumpInfo->found_depth)
545                    return DW_INVALID_OFFSET;
546
547                // We have already found our DIE and are printing it's children. Obey
548                // our recurse depth and return an invalid offset if we get done
549                // dumping all the the children
550                if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
551                    die->Dump(dwarf2Data, cu, *s, 0);
552            }
553            else if (dumpInfo->die_offset > die->GetOffset())
554            {
555                if (show_parents)
556                    dumpInfo->ancestors.back() = *die;
557            }
558        }
559
560        // Keep up with our indent level
561        if (die->IsNULL())
562        {
563            if (show_parents)
564                dumpInfo->ancestors.pop_back();
565
566            if (curr_depth <= 1)
567                return cu->GetNextCompileUnitOffset();
568            else
569                s->IndentLess();
570        }
571        else if (die->HasChildren())
572        {
573            if (show_parents)
574            {
575                DWARFDebugInfoEntry null_die;
576                dumpInfo->ancestors.push_back(null_die);
577            }
578            s->IndentMore();
579        }
580    }
581    else
582    {
583        if (cu == NULL)
584            s->PutCString("NULL - cu");
585        // We have a compile unit, reset our indent level to zero just in case
586        s->SetIndentLevel(0);
587
588        // See if we are dumping everything?
589        if (dumpInfo->die_offset == DW_INVALID_OFFSET)
590        {
591            // We are dumping everything
592            cu->Dump(s);
593            return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
594        }
595        else
596        {
597            if (show_parents)
598            {
599                dumpInfo->ancestors.clear();
600                dumpInfo->ancestors.resize(1);
601            }
602
603            // We are dumping only a single DIE possibly with it's children and
604            // we must find it's compile unit before we can dump it properly
605            if (dumpInfo->die_offset < cu->GetFirstDIEOffset())
606            {
607                // Not found, maybe the DIE offset provided wasn't correct?
608            //  *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
609                return DW_INVALID_OFFSET;
610            }
611            else
612            {
613                // See if the DIE is in this compile unit?
614                if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
615                {
616                    // This DIE is in this compile unit!
617                    if (s->GetVerbose())
618                        cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
619
620                    return next_offset;
621                //  // We found our compile unit that contains our DIE, just skip to dumping the requested DIE...
622                //  return dumpInfo->die_offset;
623                }
624                else
625                {
626                    // Skip to the next compile unit as the DIE isn't in the current one!
627                    return cu->GetNextCompileUnitOffset();
628                }
629            }
630        }
631    }
632
633    // Just return the current offset to parse the next CU or DIE entry
634    return next_offset;
635}
636
637//----------------------------------------------------------------------
638// Dump
639//
640// Dump the information in the .debug_info section to the specified
641// ostream. If die_offset is valid, a single DIE will be dumped. If the
642// die_offset is invalid, all the DWARF information will be dumped. Both
643// cases will obey a "recurse_depth" or how deep to traverse into the
644// children of each DIE entry. A recurse_depth of zero will dump all
645// compile unit headers. A recurse_depth of 1 will dump all compile unit
646// headers and the DW_TAG_compile unit tags. A depth of 2 will also
647// dump all types and functions.
648//----------------------------------------------------------------------
649void
650DWARFDebugInfo::Dump
651(
652    Stream *s,
653    SymbolFileDWARF* dwarf2Data,
654    const uint32_t die_offset,
655    const uint32_t recurse_depth
656)
657{
658    DumpInfo dumpInfo(s, die_offset, recurse_depth);
659    s->PutCString(".debug_info contents");
660    if (dwarf2Data->get_debug_info_data().GetByteSize() > 0)
661    {
662        if (die_offset == DW_INVALID_OFFSET)
663            s->PutCString(":\n");
664        else
665        {
666            s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
667            if (recurse_depth != UINT32_MAX)
668                s->Printf(" recursing %u levels deep.", recurse_depth);
669            s->EOL();
670        }
671    }
672    else
673    {
674        s->PutCString(": < EMPTY >\n");
675        return;
676    }
677    DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
678}
679
680
681//----------------------------------------------------------------------
682// Dump
683//
684// Dump the contents of this DWARFDebugInfo object as has been parsed
685// and/or modified after it has been parsed.
686//----------------------------------------------------------------------
687void
688DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth)
689{
690    DumpInfo dumpInfo(s, die_offset, recurse_depth);
691
692    s->PutCString("Dumping .debug_info section from internal representation\n");
693
694    CompileUnitColl::const_iterator pos;
695    uint32_t curr_depth = 0;
696    ParseCompileUnitHeadersIfNeeded();
697    for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos)
698    {
699        const DWARFCompileUnitSP& cu_sp = *pos;
700        DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo);
701
702        const DWARFDebugInfoEntry* die = cu_sp->DIE();
703        if (die)
704            die->Dump(m_dwarf2Data, cu_sp.get(), *s, recurse_depth);
705    }
706}
707
708
709//----------------------------------------------------------------------
710// FindCallbackString
711//
712// A callback function for the static DWARFDebugInfo::Parse() function
713// that gets called each time a compile unit header or debug information
714// entry is successfully parsed.
715//
716// This function will find the die_offset of any items whose DW_AT_name
717// matches the given string
718//----------------------------------------------------------------------
719typedef struct FindCallbackStringInfoTag
720{
721    const char* name;
722    bool ignore_case;
723    RegularExpression* regex;
724    vector<dw_offset_t>& die_offsets;
725} FindCallbackStringInfo;
726
727static dw_offset_t FindCallbackString
728(
729    SymbolFileDWARF* dwarf2Data,
730    DWARFCompileUnitSP& cu_sp,
731    DWARFDebugInfoEntry* die,
732    const dw_offset_t next_offset,
733    const uint32_t curr_depth,
734    void* userData
735)
736{
737    FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData;
738    const DWARFCompileUnit* cu = cu_sp.get();
739
740    if (die)
741    {
742        const char* die_name = die->GetName(dwarf2Data, cu);
743        if (die_name)
744        {
745            if (info->regex)
746            {
747                if (info->regex->Execute(die_name))
748                    info->die_offsets.push_back(die->GetOffset());
749            }
750            else
751            {
752                if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0)
753                    info->die_offsets.push_back(die->GetOffset());
754            }
755        }
756    }
757
758    // Just return the current offset to parse the next CU or DIE entry
759    return next_offset;
760}
761
762//----------------------------------------------------------------------
763// Find
764//
765// Finds all DIE that have a specific DW_AT_name attribute by manually
766// searching through the debug information (not using the
767// .debug_pubnames section). The string must match the entire name
768// and case sensitive searches are an option.
769//----------------------------------------------------------------------
770bool
771DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const
772{
773    die_offsets.clear();
774    if (name && name[0])
775    {
776        FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets };
777        DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
778    }
779    return !die_offsets.empty();
780}
781
782//----------------------------------------------------------------------
783// Find
784//
785// Finds all DIE that have a specific DW_AT_name attribute by manually
786// searching through the debug information (not using the
787// .debug_pubnames section). The string must match the supplied regular
788// expression.
789//----------------------------------------------------------------------
790bool
791DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const
792{
793    die_offsets.clear();
794    FindCallbackStringInfo info = { NULL, false, &re, die_offsets };
795    DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
796    return !die_offsets.empty();
797}
798