1//===-- DWARFDebugPubnames.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 "DWARFDebugPubnames.h"
11
12#include "lldb/Core/Stream.h"
13#include "lldb/Core/Timer.h"
14
15#include "DWARFDebugInfo.h"
16#include "DWARFDIECollection.h"
17#include "DWARFFormValue.h"
18#include "DWARFCompileUnit.h"
19#include "LogChannelDWARF.h"
20#include "SymbolFileDWARF.h"
21
22
23using namespace lldb;
24using namespace lldb_private;
25
26DWARFDebugPubnames::DWARFDebugPubnames() :
27    m_sets()
28{
29}
30
31bool
32DWARFDebugPubnames::Extract(const DWARFDataExtractor& data)
33{
34    Timer scoped_timer (__PRETTY_FUNCTION__,
35                        "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")",
36                        (uint64_t)data.GetByteSize());
37    Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
38    if (log)
39        log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize());
40
41    if (data.ValidOffset(0))
42    {
43        lldb::offset_t offset = 0;
44
45        DWARFDebugPubnamesSet set;
46        while (data.ValidOffset(offset))
47        {
48            if (set.Extract(data, &offset))
49            {
50                m_sets.push_back(set);
51                offset = set.GetOffsetOfNextEntry();
52            }
53            else
54                break;
55        }
56        if (log)
57            Dump (log);
58        return true;
59    }
60    return false;
61}
62
63
64bool
65DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
66{
67    Timer scoped_timer (__PRETTY_FUNCTION__,
68                        "DWARFDebugPubnames::GeneratePubnames (data = %p)",
69                        static_cast<void*>(dwarf2Data));
70
71    Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
72    if (log)
73        log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)",
74                    static_cast<void*>(dwarf2Data));
75
76    m_sets.clear();
77    DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
78    if (debug_info)
79    {
80        uint32_t cu_idx = 0;
81        const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
82        for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
83        {
84
85            DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
86
87            DWARFFormValue::FixedFormSizes fixed_form_sizes =
88                DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize(),
89                                                                 cu->IsDWARF64());
90
91            bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
92
93            DWARFDIECollection dies;
94            const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) +
95                                     cu->AppendDIEsWithTag (DW_TAG_variable, dies);
96
97            dw_offset_t cu_offset = cu->GetOffset();
98            DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
99
100            size_t die_idx;
101            for (die_idx = 0; die_idx < die_count; ++die_idx)
102            {
103                DWARFDIE die = dies.GetDIEAtIndex(die_idx);
104                DWARFAttributes attributes;
105                const char *name = NULL;
106                const char *mangled = NULL;
107                bool add_die = false;
108                const size_t num_attributes = die.GetDIE()->GetAttributes(die.GetCU(), fixed_form_sizes, attributes);
109                if (num_attributes > 0)
110                {
111                    uint32_t i;
112
113                    dw_tag_t tag = die.Tag();
114
115                    for (i=0; i<num_attributes; ++i)
116                    {
117                        dw_attr_t attr = attributes.AttributeAtIndex(i);
118                        DWARFFormValue form_value;
119                        switch (attr)
120                        {
121                        case DW_AT_name:
122                            if (attributes.ExtractFormValueAtIndex(i, form_value))
123                                name = form_value.AsCString();
124                            break;
125
126                        case DW_AT_MIPS_linkage_name:
127                        case DW_AT_linkage_name:
128                            if (attributes.ExtractFormValueAtIndex(i, form_value))
129                                mangled = form_value.AsCString();
130                            break;
131
132                        case DW_AT_low_pc:
133                        case DW_AT_ranges:
134                        case DW_AT_entry_pc:
135                            if (tag == DW_TAG_subprogram)
136                                add_die = true;
137                            break;
138
139                        case DW_AT_location:
140                            if (tag == DW_TAG_variable)
141                            {
142                                DWARFDIE parent_die = die.GetParent();
143                                while ( parent_die )
144                                {
145                                    switch (parent_die.Tag())
146                                    {
147                                    case DW_TAG_subprogram:
148                                    case DW_TAG_lexical_block:
149                                    case DW_TAG_inlined_subroutine:
150                                        // Even if this is a function level static, we don't add it. We could theoretically
151                                        // add these if we wanted to by introspecting into the DW_AT_location and seeing
152                                        // if the location describes a hard coded address, but we don't want the performance
153                                        // penalty of that right now.
154                                        add_die = false;
155                                        parent_die.Clear();  // Terminate the while loop.
156                                        break;
157
158                                    case DW_TAG_compile_unit:
159                                        add_die = true;
160                                        parent_die.Clear();  // Terminate the while loop.
161                                        break;
162
163                                    default:
164                                        parent_die = parent_die.GetParent();   // Keep going in the while loop.
165                                        break;
166                                    }
167                                }
168                            }
169                            break;
170                        }
171                    }
172                }
173
174                if (add_die && (name || mangled))
175                {
176                    pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), mangled ? mangled : name);
177                }
178            }
179
180            if (pubnames_set.NumDescriptors() > 0)
181            {
182                m_sets.push_back(pubnames_set);
183            }
184
185            // Keep memory down by clearing DIEs if this generate function
186            // caused them to be parsed
187            if (clear_dies)
188                cu->ClearDIEs (true);
189        }
190    }
191    if (m_sets.empty())
192        return false;
193    if (log)
194        Dump (log);
195    return true;
196}
197
198bool
199DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
200{
201    m_sets.clear();
202    DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
203    if (debug_info)
204    {
205        uint32_t cu_idx = 0;
206        const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
207        for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
208        {
209            DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
210            DWARFDIECollection dies;
211            const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
212            dw_offset_t cu_offset = cu->GetOffset();
213            DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
214
215            size_t die_idx;
216            for (die_idx = 0; die_idx < die_count; ++die_idx)
217            {
218                DWARFDIE die = dies.GetDIEAtIndex (die_idx);
219                const char *name = die.GetName();
220
221                if (name)
222                    pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), name);
223            }
224
225            if (pubnames_set.NumDescriptors() > 0)
226            {
227                m_sets.push_back(pubnames_set);
228            }
229        }
230    }
231    return !m_sets.empty();
232}
233
234void
235DWARFDebugPubnames::Dump(Log *s) const
236{
237    if (m_sets.empty())
238        s->PutCString("< EMPTY >\n");
239    else
240    {
241        const_iterator pos;
242        const_iterator end = m_sets.end();
243
244        for (pos = m_sets.begin(); pos != end; ++pos)
245            (*pos).Dump(s);
246    }
247}
248
249bool
250DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
251{
252    const_iterator pos;
253    const_iterator end = m_sets.end();
254
255    die_offsets.clear();
256
257    for (pos = m_sets.begin(); pos != end; ++pos)
258    {
259        (*pos).Find(name, ignore_case, die_offsets);
260    }
261
262    return !die_offsets.empty();
263}
264
265bool
266DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
267{
268    const_iterator pos;
269    const_iterator end = m_sets.end();
270
271    die_offsets.clear();
272
273    for (pos = m_sets.begin(); pos != end; ++pos)
274    {
275        (*pos).Find(regex, die_offsets);
276    }
277
278    return !die_offsets.empty();
279}
280