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 DataExtractor& 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                        dwarf2Data);
70
71    Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
72    if (log)
73        log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data);
74
75    m_sets.clear();
76    DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
77    if (debug_info)
78    {
79
80        const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data();
81
82        uint32_t cu_idx = 0;
83        const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
84        for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
85        {
86
87            DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
88
89            const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize());
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                const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
104                DWARFDebugInfoEntry::Attributes attributes;
105                const char *name = NULL;
106                const char *mangled = NULL;
107                bool add_die = false;
108                const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, 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(dwarf2Data, i, form_value))
123                                name = form_value.AsCString(debug_str);
124                            break;
125
126                        case DW_AT_MIPS_linkage_name:
127                        case DW_AT_linkage_name:
128                            if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
129                                mangled = form_value.AsCString(debug_str);
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                                const DWARFDebugInfoEntry* parent_die = die->GetParent();
143                                while ( parent_die != NULL )
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//                                      if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
156//                                      {
157//                                          // If we have valid block data, then we have location expression bytes
158//                                          // that are fixed (not a location list).
159//                                          const uint8_t *block_data = form_value.BlockData();
160//                                          if (block_data)
161//                                          {
162//                                              uint32_t block_length = form_value.Unsigned();
163//                                              if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
164//                                              {
165//                                                  if (block_data[0] == DW_OP_addr)
166//                                                      add_die = true;
167//                                              }
168//                                          }
169//                                      }
170                                        parent_die = NULL;  // Terminate the while loop.
171                                        break;
172
173                                    case DW_TAG_compile_unit:
174                                        add_die = true;
175                                        parent_die = NULL;  // Terminate the while loop.
176                                        break;
177
178                                    default:
179                                        parent_die = parent_die->GetParent();   // Keep going in the while loop.
180                                        break;
181                                    }
182                                }
183                            }
184                            break;
185                        }
186                    }
187                }
188
189                if (add_die && (name || mangled))
190                {
191                    pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name);
192                }
193            }
194
195            if (pubnames_set.NumDescriptors() > 0)
196            {
197                m_sets.push_back(pubnames_set);
198            }
199
200            // Keep memory down by clearing DIEs if this generate function
201            // caused them to be parsed
202            if (clear_dies)
203                cu->ClearDIEs (true);
204        }
205    }
206    if (m_sets.empty())
207        return false;
208    if (log)
209        Dump (log);
210    return true;
211}
212
213bool
214DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
215{
216    m_sets.clear();
217    DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
218    if (debug_info)
219    {
220        uint32_t cu_idx = 0;
221        const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
222        for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
223        {
224            DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
225            DWARFDIECollection dies;
226            const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
227            dw_offset_t cu_offset = cu->GetOffset();
228            DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
229
230            size_t die_idx;
231            for (die_idx = 0; die_idx < die_count; ++die_idx)
232            {
233                const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
234                const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL);
235
236                if (name)
237                {
238                    pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name);
239                }
240            }
241
242            if (pubnames_set.NumDescriptors() > 0)
243            {
244                m_sets.push_back(pubnames_set);
245            }
246        }
247    }
248    return !m_sets.empty();
249}
250
251void
252DWARFDebugPubnames::Dump(Log *s) const
253{
254    if (m_sets.empty())
255        s->PutCString("< EMPTY >\n");
256    else
257    {
258        const_iterator pos;
259        const_iterator end = m_sets.end();
260
261        for (pos = m_sets.begin(); pos != end; ++pos)
262            (*pos).Dump(s);
263    }
264}
265
266bool
267DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
268{
269    const_iterator pos;
270    const_iterator end = m_sets.end();
271
272    die_offsets.clear();
273
274    for (pos = m_sets.begin(); pos != end; ++pos)
275    {
276        (*pos).Find(name, ignore_case, die_offsets);
277    }
278
279    return !die_offsets.empty();
280}
281
282bool
283DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
284{
285    const_iterator pos;
286    const_iterator end = m_sets.end();
287
288    die_offsets.clear();
289
290    for (pos = m_sets.begin(); pos != end; ++pos)
291    {
292        (*pos).Find(regex, die_offsets);
293    }
294
295    return !die_offsets.empty();
296}
297