DWARFDebugInfo.cpp revision 341825
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      DWARFUnit *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      DWARFUnitSP cu_sp;
101      const auto &debug_info_data = m_dwarf2Data->get_debug_info_data();
102      while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, debug_info_data,
103                                                &offset))) {
104        m_compile_units.push_back(cu_sp);
105
106        offset = cu_sp->GetNextCompileUnitOffset();
107      }
108    }
109  }
110}
111
112size_t DWARFDebugInfo::GetNumCompileUnits() {
113  ParseCompileUnitHeadersIfNeeded();
114  return m_compile_units.size();
115}
116
117DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) {
118  DWARFUnit *cu = NULL;
119  if (idx < GetNumCompileUnits())
120    cu = m_compile_units[idx].get();
121  return cu;
122}
123
124bool DWARFDebugInfo::ContainsCompileUnit(const DWARFUnit *cu) const {
125  // Not a verify efficient function, but it is handy for use in assertions to
126  // make sure that a compile unit comes from a debug information file.
127  CompileUnitColl::const_iterator end_pos = m_compile_units.end();
128  CompileUnitColl::const_iterator pos;
129
130  for (pos = m_compile_units.begin(); pos != end_pos; ++pos) {
131    if (pos->get() == cu)
132      return true;
133  }
134  return false;
135}
136
137bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset(
138    dw_offset_t offset, const DWARFUnitSP &cu_sp) {
139  return offset < cu_sp->GetOffset();
140}
141
142DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
143                                                 uint32_t *idx_ptr) {
144  DWARFUnitSP cu_sp;
145  uint32_t cu_idx = DW_INVALID_INDEX;
146  if (cu_offset != DW_INVALID_OFFSET) {
147    ParseCompileUnitHeadersIfNeeded();
148
149    // Watch out for single compile unit executable as they are pretty common
150    const size_t num_cus = m_compile_units.size();
151    if (num_cus == 1) {
152      if (m_compile_units[0]->GetOffset() == cu_offset) {
153        cu_sp = m_compile_units[0];
154        cu_idx = 0;
155      }
156    } else if (num_cus) {
157      CompileUnitColl::const_iterator end_pos = m_compile_units.end();
158      CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
159      CompileUnitColl::const_iterator pos = std::upper_bound(
160          begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset);
161      if (pos != begin_pos) {
162        --pos;
163        if ((*pos)->GetOffset() == cu_offset) {
164          cu_sp = *pos;
165          cu_idx = std::distance(begin_pos, pos);
166        }
167      }
168    }
169  }
170  if (idx_ptr)
171    *idx_ptr = cu_idx;
172  return cu_sp.get();
173}
174
175DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) {
176  if (die_ref.cu_offset == DW_INVALID_OFFSET)
177    return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
178  else
179    return GetCompileUnit(die_ref.cu_offset);
180}
181
182DWARFUnit *
183DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
184  ParseCompileUnitHeadersIfNeeded();
185
186  DWARFUnitSP cu_sp;
187
188  // Watch out for single compile unit executable as they are pretty common
189  const size_t num_cus = m_compile_units.size();
190  if (num_cus == 1) {
191    if (m_compile_units[0]->ContainsDIEOffset(die_offset))
192      return m_compile_units[0].get();
193  } else if (num_cus) {
194    CompileUnitColl::const_iterator end_pos = m_compile_units.end();
195    CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
196    CompileUnitColl::const_iterator pos = std::upper_bound(
197        begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset);
198    if (pos != begin_pos) {
199      --pos;
200      if ((*pos)->ContainsDIEOffset(die_offset))
201        return (*pos).get();
202    }
203  }
204
205  return nullptr;
206}
207
208DWARFDIE
209DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) {
210  DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset);
211  if (cu)
212    return cu->GetDIE(die_offset);
213  return DWARFDIE();
214}
215
216//----------------------------------------------------------------------
217// GetDIE()
218//
219// Get the DIE (Debug Information Entry) with the specified offset.
220//----------------------------------------------------------------------
221DWARFDIE
222DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
223  DWARFUnit *cu = GetCompileUnit(die_ref);
224  if (cu)
225    return cu->GetDIE(die_ref.die_offset);
226  return DWARFDIE(); // Not found
227}
228
229