DWARFDebugInfo.cpp revision 327952
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/Host/PosixApi.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Utility/RegularExpression.h"
18#include "lldb/Utility/Stream.h"
19
20#include "DWARFCompileUnit.h"
21#include "DWARFDebugAranges.h"
22#include "DWARFDebugAranges.h"
23#include "DWARFDebugInfo.h"
24#include "DWARFDebugInfoEntry.h"
25#include "DWARFFormValue.h"
26#include "LogChannelDWARF.h"
27
28using namespace lldb;
29using namespace lldb_private;
30using namespace std;
31
32//----------------------------------------------------------------------
33// Constructor
34//----------------------------------------------------------------------
35DWARFDebugInfo::DWARFDebugInfo()
36    : m_dwarf2Data(NULL), m_compile_units(), m_cu_aranges_ap() {}
37
38//----------------------------------------------------------------------
39// SetDwarfData
40//----------------------------------------------------------------------
41void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) {
42  m_dwarf2Data = dwarf2Data;
43  m_compile_units.clear();
44}
45
46DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() {
47  if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) {
48    Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
49
50    m_cu_aranges_ap.reset(new DWARFDebugAranges());
51    const DWARFDataExtractor &debug_aranges_data =
52        m_dwarf2Data->get_debug_aranges_data();
53    if (debug_aranges_data.GetByteSize() > 0) {
54      if (log)
55        log->Printf(
56            "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from "
57            ".debug_aranges",
58            m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
59      m_cu_aranges_ap->Extract(debug_aranges_data);
60    }
61
62    // Make a list of all CUs represented by the arange data in the file.
63    std::set<dw_offset_t> cus_with_data;
64    for (size_t n = 0; n < m_cu_aranges_ap.get()->GetNumRanges(); n++) {
65      dw_offset_t offset = m_cu_aranges_ap.get()->OffsetAtIndex(n);
66      if (offset != DW_INVALID_OFFSET)
67        cus_with_data.insert(offset);
68    }
69
70    // Manually build arange data for everything that wasn't in the
71    // .debug_aranges table.
72    bool printed = false;
73    const size_t num_compile_units = GetNumCompileUnits();
74    for (size_t idx = 0; idx < num_compile_units; ++idx) {
75      DWARFCompileUnit *cu = GetCompileUnitAtIndex(idx);
76
77      dw_offset_t offset = cu->GetOffset();
78      if (cus_with_data.find(offset) == cus_with_data.end()) {
79        if (log) {
80          if (!printed)
81            log->Printf(
82                "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing",
83                m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
84          printed = true;
85        }
86        cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_ap.get());
87      }
88    }
89
90    const bool minimize = true;
91    m_cu_aranges_ap->Sort(minimize);
92  }
93  return *m_cu_aranges_ap.get();
94}
95
96void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() {
97  if (m_compile_units.empty()) {
98    if (m_dwarf2Data != NULL) {
99      lldb::offset_t offset = 0;
100      DWARFCompileUnitSP cu_sp;
101      while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) {
102        m_compile_units.push_back(cu_sp);
103
104        offset = cu_sp->GetNextCompileUnitOffset();
105      }
106    }
107  }
108}
109
110size_t DWARFDebugInfo::GetNumCompileUnits() {
111  ParseCompileUnitHeadersIfNeeded();
112  return m_compile_units.size();
113}
114
115DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) {
116  DWARFCompileUnit *cu = NULL;
117  if (idx < GetNumCompileUnits())
118    cu = m_compile_units[idx].get();
119  return cu;
120}
121
122bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const {
123  // Not a verify efficient function, but it is handy for use in assertions
124  // to make sure that a compile unit comes from a debug information file.
125  CompileUnitColl::const_iterator end_pos = m_compile_units.end();
126  CompileUnitColl::const_iterator pos;
127
128  for (pos = m_compile_units.begin(); pos != end_pos; ++pos) {
129    if (pos->get() == cu)
130      return true;
131  }
132  return false;
133}
134
135bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset(
136    dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) {
137  return offset < cu_sp->GetOffset();
138}
139
140DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
141                                                 uint32_t *idx_ptr) {
142  DWARFCompileUnitSP cu_sp;
143  uint32_t cu_idx = DW_INVALID_INDEX;
144  if (cu_offset != DW_INVALID_OFFSET) {
145    ParseCompileUnitHeadersIfNeeded();
146
147    // Watch out for single compile unit executable as they are pretty common
148    const size_t num_cus = m_compile_units.size();
149    if (num_cus == 1) {
150      if (m_compile_units[0]->GetOffset() == cu_offset) {
151        cu_sp = m_compile_units[0];
152        cu_idx = 0;
153      }
154    } else if (num_cus) {
155      CompileUnitColl::const_iterator end_pos = m_compile_units.end();
156      CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
157      CompileUnitColl::const_iterator pos = std::upper_bound(
158          begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset);
159      if (pos != begin_pos) {
160        --pos;
161        if ((*pos)->GetOffset() == cu_offset) {
162          cu_sp = *pos;
163          cu_idx = std::distance(begin_pos, pos);
164        }
165      }
166    }
167  }
168  if (idx_ptr)
169    *idx_ptr = cu_idx;
170  return cu_sp.get();
171}
172
173DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) {
174  if (die_ref.cu_offset == DW_INVALID_OFFSET)
175    return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
176  else
177    return GetCompileUnit(die_ref.cu_offset);
178}
179
180DWARFCompileUnit *
181DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
182  ParseCompileUnitHeadersIfNeeded();
183
184  DWARFCompileUnitSP cu_sp;
185
186  // Watch out for single compile unit executable as they are pretty common
187  const size_t num_cus = m_compile_units.size();
188  if (num_cus == 1) {
189    if (m_compile_units[0]->ContainsDIEOffset(die_offset))
190      return m_compile_units[0].get();
191  } else if (num_cus) {
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(
195        begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset);
196    if (pos != begin_pos) {
197      --pos;
198      if ((*pos)->ContainsDIEOffset(die_offset))
199        return (*pos).get();
200    }
201  }
202
203  return nullptr;
204}
205
206DWARFDIE
207DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) {
208  DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset);
209  if (cu)
210    return cu->GetDIE(die_offset);
211  return DWARFDIE();
212}
213
214//----------------------------------------------------------------------
215// GetDIE()
216//
217// Get the DIE (Debug Information Entry) with the specified offset.
218//----------------------------------------------------------------------
219DWARFDIE
220DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
221  DWARFCompileUnit *cu = GetCompileUnit(die_ref);
222  if (cu)
223    return cu->GetDIE(die_ref.die_offset);
224  return DWARFDIE(); // Not found
225}
226
227//----------------------------------------------------------------------
228// Parse
229//
230// Parses the .debug_info section and uses the .debug_abbrev section
231// and various other sections in the SymbolFileDWARF class and calls the
232// supplied callback function each time a compile unit header, or debug
233// information entry is successfully parsed. This function can be used
234// for different tasks such as parsing the file contents into a
235// structured data, dumping, verifying and much more.
236//----------------------------------------------------------------------
237void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback,
238                           void *userData) {
239  if (dwarf2Data) {
240    lldb::offset_t offset = 0;
241    uint32_t depth = 0;
242    DWARFDebugInfoEntry die;
243
244    DWARFCompileUnitSP cu;
245    while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) {
246      const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
247
248      depth = 0;
249      // Call the callback function with no DIE pointer for the compile unit
250      // and get the offset that we are to continue to parse from
251      offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData);
252
253      // Make sure we are within our compile unit
254      if (offset < next_cu_offset) {
255        // We are in our compile unit, parse starting at the offset
256        // we were told to parse
257        bool done = false;
258        while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) {
259          // Call the callback function with DIE pointer that falls within the
260          // compile unit
261          offset =
262              callback(dwarf2Data, cu.get(), &die, offset, depth, userData);
263
264          if (die.IsNULL()) {
265            if (depth)
266              --depth;
267            else
268              done = true; // We are done with this compile unit!
269          } else if (die.HasChildren())
270            ++depth;
271        }
272      }
273
274      // Make sure the offset returned is valid, and if not stop parsing.
275      // Returning DW_INVALID_OFFSET from this callback is a good way to end
276      // all parsing
277      if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
278        break;
279
280      // Make sure we start on a proper
281      offset = next_cu_offset;
282    }
283  }
284}
285
286typedef struct DumpInfo {
287  DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth)
288      : strm(init_strm), die_offset(off), recurse_depth(depth),
289        found_depth(UINT32_MAX), found_die(false), ancestors() {}
290  Stream *strm;
291  const uint32_t die_offset;
292  const uint32_t recurse_depth;
293  uint32_t found_depth;
294  bool found_die;
295  std::vector<DWARFDebugInfoEntry> ancestors;
296
297  DISALLOW_COPY_AND_ASSIGN(DumpInfo);
298} DumpInfo;
299
300//----------------------------------------------------------------------
301// DumpCallback
302//
303// A callback function for the static DWARFDebugInfo::Parse() function
304// that gets called each time a compile unit header or debug information
305// entry is successfully parsed.
306//
307// This function dump DWARF information and obey recurse depth and
308// whether a single DIE is to be dumped (or all of the data).
309//----------------------------------------------------------------------
310static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data,
311                                DWARFCompileUnit *cu, DWARFDebugInfoEntry *die,
312                                const dw_offset_t next_offset,
313                                const uint32_t curr_depth, void *userData) {
314  DumpInfo *dumpInfo = (DumpInfo *)userData;
315  Stream *s = dumpInfo->strm;
316  bool show_parents =
317      s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors);
318
319  if (die) {
320    // Are we dumping everything?
321    if (dumpInfo->die_offset == DW_INVALID_OFFSET) {
322      // Yes we are dumping everything. Obey our recurse level though
323      if (curr_depth < dumpInfo->recurse_depth)
324        die->Dump(dwarf2Data, cu, *s, 0);
325    } else {
326      // We are dumping a specific DIE entry by offset
327      if (dumpInfo->die_offset == die->GetOffset()) {
328        // We found the DIE we were looking for, dump it!
329        if (show_parents) {
330          s->SetIndentLevel(0);
331          const uint32_t num_ancestors = dumpInfo->ancestors.size();
332          if (num_ancestors > 0) {
333            for (uint32_t i = 0; i < num_ancestors - 1; ++i) {
334              dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0);
335              s->IndentMore();
336            }
337          }
338        }
339
340        dumpInfo->found_depth = curr_depth;
341
342        die->Dump(dwarf2Data, cu, *s, 0);
343
344        // Note that we found the DIE we were looking for
345        dumpInfo->found_die = true;
346
347        // Since we are dumping a single DIE, if there are no children we are
348        // done!
349        if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
350          return DW_INVALID_OFFSET; // Return an invalid address to end parsing
351      } else if (dumpInfo->found_die) {
352        // Are we done with all the children?
353        if (curr_depth <= dumpInfo->found_depth)
354          return DW_INVALID_OFFSET;
355
356        // We have already found our DIE and are printing it's children. Obey
357        // our recurse depth and return an invalid offset if we get done
358        // dumping all of the children
359        if (dumpInfo->recurse_depth == UINT32_MAX ||
360            curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
361          die->Dump(dwarf2Data, cu, *s, 0);
362      } else if (dumpInfo->die_offset > die->GetOffset()) {
363        if (show_parents)
364          dumpInfo->ancestors.back() = *die;
365      }
366    }
367
368    // Keep up with our indent level
369    if (die->IsNULL()) {
370      if (show_parents)
371        dumpInfo->ancestors.pop_back();
372
373      if (curr_depth <= 1)
374        return cu->GetNextCompileUnitOffset();
375      else
376        s->IndentLess();
377    } else if (die->HasChildren()) {
378      if (show_parents) {
379        DWARFDebugInfoEntry null_die;
380        dumpInfo->ancestors.push_back(null_die);
381      }
382      s->IndentMore();
383    }
384  } else {
385    if (cu == NULL)
386      s->PutCString("NULL - cu");
387    // We have a compile unit, reset our indent level to zero just in case
388    s->SetIndentLevel(0);
389
390    // See if we are dumping everything?
391    if (dumpInfo->die_offset == DW_INVALID_OFFSET) {
392      // We are dumping everything
393      if (cu) {
394        cu->Dump(s);
395        return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this
396                                        // Compile Unit
397      } else {
398        return DW_INVALID_OFFSET;
399      }
400    } else {
401      if (show_parents) {
402        dumpInfo->ancestors.clear();
403        dumpInfo->ancestors.resize(1);
404      }
405
406      // We are dumping only a single DIE possibly with it's children and
407      // we must find it's compile unit before we can dump it properly
408      if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) {
409        // Not found, maybe the DIE offset provided wasn't correct?
410        //  *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << "
411        //  was not found." << endl;
412        return DW_INVALID_OFFSET;
413      } else {
414        // See if the DIE is in this compile unit?
415        if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) {
416          return next_offset;
417          //  // We found our compile unit that contains our DIE, just skip to
418          //  dumping the requested DIE...
419          //  return dumpInfo->die_offset;
420        } else {
421          // Skip to the next compile unit as the DIE isn't in the current one!
422          if (cu) {
423            return cu->GetNextCompileUnitOffset();
424          } else {
425            return DW_INVALID_OFFSET;
426          }
427        }
428      }
429    }
430  }
431
432  // Just return the current offset to parse the next CU or DIE entry
433  return next_offset;
434}
435
436//----------------------------------------------------------------------
437// Dump
438//
439// Dump the information in the .debug_info section to the specified
440// ostream. If die_offset is valid, a single DIE will be dumped. If the
441// die_offset is invalid, all the DWARF information will be dumped. Both
442// cases will obey a "recurse_depth" or how deep to traverse into the
443// children of each DIE entry. A recurse_depth of zero will dump all
444// compile unit headers. A recurse_depth of 1 will dump all compile unit
445// headers and the DW_TAG_compile unit tags. A depth of 2 will also
446// dump all types and functions.
447//----------------------------------------------------------------------
448void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data,
449                          const uint32_t die_offset,
450                          const uint32_t recurse_depth) {
451  DumpInfo dumpInfo(s, die_offset, recurse_depth);
452  s->PutCString(".debug_info contents");
453  if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) {
454    if (die_offset == DW_INVALID_OFFSET)
455      s->PutCString(":\n");
456    else {
457      s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
458      if (recurse_depth != UINT32_MAX)
459        s->Printf(" recursing %u levels deep.", recurse_depth);
460      s->EOL();
461    }
462  } else {
463    s->PutCString(": < EMPTY >\n");
464    return;
465  }
466  DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
467}
468
469//----------------------------------------------------------------------
470// Dump
471//
472// Dump the contents of this DWARFDebugInfo object as has been parsed
473// and/or modified after it has been parsed.
474//----------------------------------------------------------------------
475void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset,
476                          const uint32_t recurse_depth) {
477  DumpInfo dumpInfo(s, die_offset, recurse_depth);
478
479  s->PutCString("Dumping .debug_info section from internal representation\n");
480
481  CompileUnitColl::const_iterator pos;
482  uint32_t curr_depth = 0;
483  ParseCompileUnitHeadersIfNeeded();
484  for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) {
485    DWARFCompileUnit *cu = pos->get();
486    DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo);
487
488    const DWARFDIE die = cu->DIE();
489    if (die)
490      die.Dump(s, recurse_depth);
491  }
492}
493