LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DWARFUnit.cpp
Go to the documentation of this file.
1 //===-- DWARFUnit.cpp -----------------------------------------------------===//
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 "DWARFUnit.h"
11 #include "DWARFContext.h"
13 #include "llvm/Support/Dwarf.h"
14 #include "llvm/Support/Path.h"
15 #include <cstdio>
16 
17 using namespace llvm;
18 using namespace dwarf;
19 
21  StringRef RS, StringRef SS, StringRef SOS, StringRef AOS,
22  const RelocAddrMap *M, bool LE)
23  : Abbrev(DA), InfoSection(IS), AbbrevSection(AS), RangeSection(RS),
24  StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
25  RelocMap(M), isLittleEndian(LE) {
26  clear();
27 }
28 
30 }
31 
33  uint64_t &Result) const {
34  uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize;
35  if (AddrOffsetSection.size() < Offset + AddrSize)
36  return false;
37  DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize);
38  Result = DA.getAddress(&Offset);
39  return true;
40 }
41 
43  uint32_t &Result) const {
44  // FIXME: string offset section entries are 8-byte for DWARF64.
45  const uint32_t ItemSize = 4;
46  uint32_t Offset = Index * ItemSize;
47  if (StringOffsetSection.size() < Offset + ItemSize)
48  return false;
49  DataExtractor DA(StringOffsetSection, isLittleEndian, 0);
50  Result = DA.getU32(&Offset);
51  return true;
52 }
53 
54 bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
55  Length = debug_info.getU32(offset_ptr);
56  Version = debug_info.getU16(offset_ptr);
57  uint64_t abbrOffset = debug_info.getU32(offset_ptr);
58  AddrSize = debug_info.getU8(offset_ptr);
59 
60  bool lengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
61  bool versionOK = DWARFContext::isSupportedVersion(Version);
62  bool abbrOffsetOK = AbbrevSection.size() > abbrOffset;
63  bool addrSizeOK = AddrSize == 4 || AddrSize == 8;
64 
65  if (!lengthOK || !versionOK || !addrSizeOK || !abbrOffsetOK)
66  return false;
67 
68  Abbrevs = Abbrev->getAbbreviationDeclarationSet(abbrOffset);
69  return true;
70 }
71 
72 bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
73  clear();
74 
75  Offset = *offset_ptr;
76 
77  if (debug_info.isValidOffset(*offset_ptr)) {
78  if (extractImpl(debug_info, offset_ptr))
79  return true;
80 
81  // reset the offset to where we tried to parse from if anything went wrong
82  *offset_ptr = Offset;
83  }
84 
85  return false;
86 }
87 
88 bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
89  DWARFDebugRangeList &RangeList) const {
90  // Require that compile unit is extracted.
91  assert(DieArray.size() > 0);
92  DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize);
93  uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
94  return RangeList.extract(RangesData, &ActualRangeListOffset);
95 }
96 
98  Offset = 0;
99  Length = 0;
100  Version = 0;
101  Abbrevs = 0;
102  AddrSize = 0;
103  BaseAddr = 0;
104  RangeSectionBase = 0;
105  AddrOffsetSectionBase = 0;
106  clearDIEs(false);
107  DWO.reset();
108 }
109 
111  extractDIEsIfNeeded(true);
112  if (DieArray.empty())
113  return 0;
114  return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0);
115 }
116 
118  extractDIEsIfNeeded(true);
119  const uint64_t FailValue = -1ULL;
120  if (DieArray.empty())
121  return FailValue;
122  return DieArray[0]
123  .getAttributeValueAsUnsignedConstant(this, DW_AT_GNU_dwo_id, FailValue);
124 }
125 
126 void DWARFUnit::setDIERelations() {
127  if (DieArray.empty())
128  return;
129  DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front();
130  DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back();
131  DWARFDebugInfoEntryMinimal *curr_die;
132  // We purposely are skipping the last element in the array in the loop below
133  // so that we can always have a valid next item
134  for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) {
135  // Since our loop doesn't include the last element, we can always
136  // safely access the next die in the array.
137  DWARFDebugInfoEntryMinimal *next_die = curr_die + 1;
138 
139  const DWARFAbbreviationDeclaration *curr_die_abbrev =
140  curr_die->getAbbreviationDeclarationPtr();
141 
142  if (curr_die_abbrev) {
143  // Normal DIE
144  if (curr_die_abbrev->hasChildren())
145  next_die->setParent(curr_die);
146  else
147  curr_die->setSibling(next_die);
148  } else {
149  // NULL DIE that terminates a sibling chain
150  DWARFDebugInfoEntryMinimal *parent = curr_die->getParent();
151  if (parent)
152  parent->setSibling(next_die);
153  }
154  }
155 
156  // Since we skipped the last element, we need to fix it up!
157  if (die_array_begin < die_array_end)
158  curr_die->setParent(die_array_begin);
159 }
160 
161 void DWARFUnit::extractDIEsToVector(
162  bool AppendCUDie, bool AppendNonCUDies,
163  std::vector<DWARFDebugInfoEntryMinimal> &Dies) const {
164  if (!AppendCUDie && !AppendNonCUDies)
165  return;
166 
167  // Set the offset to that of the first DIE and calculate the start of the
168  // next compilation unit header.
169  uint32_t Offset = getFirstDIEOffset();
170  uint32_t NextCUOffset = getNextUnitOffset();
172  uint32_t Depth = 0;
173  bool IsCUDie = true;
174 
175  while (Offset < NextCUOffset && DIE.extractFast(this, &Offset)) {
176  if (IsCUDie) {
177  if (AppendCUDie)
178  Dies.push_back(DIE);
179  if (!AppendNonCUDies)
180  break;
181  // The average bytes per DIE entry has been seen to be
182  // around 14-20 so let's pre-reserve the needed memory for
183  // our DIE entries accordingly.
184  Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
185  IsCUDie = false;
186  } else {
187  Dies.push_back(DIE);
188  }
189 
190  const DWARFAbbreviationDeclaration *AbbrDecl =
192  if (AbbrDecl) {
193  // Normal DIE
194  if (AbbrDecl->hasChildren())
195  ++Depth;
196  } else {
197  // NULL DIE.
198  if (Depth > 0)
199  --Depth;
200  if (Depth == 0)
201  break; // We are done with this compile unit!
202  }
203  }
204 
205  // Give a little bit of info if we encounter corrupt DWARF (our offset
206  // should always terminate at or before the start of the next compilation
207  // unit header).
208  if (Offset > NextCUOffset)
209  fprintf(stderr, "warning: DWARF compile unit extends beyond its "
210  "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), Offset);
211 }
212 
213 size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
214  if ((CUDieOnly && DieArray.size() > 0) ||
215  DieArray.size() > 1)
216  return 0; // Already parsed.
217 
218  bool HasCUDie = DieArray.size() > 0;
219  extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
220 
221  if (DieArray.empty())
222  return 0;
223 
224  // If CU DIE was just parsed, copy several attribute values from it.
225  if (!HasCUDie) {
226  uint64_t BaseAddr =
227  DieArray[0].getAttributeValueAsAddress(this, DW_AT_low_pc, -1ULL);
228  if (BaseAddr == -1ULL)
229  BaseAddr = DieArray[0].getAttributeValueAsAddress(this, DW_AT_entry_pc, 0);
230  setBaseAddress(BaseAddr);
231  AddrOffsetSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
232  this, DW_AT_GNU_addr_base, 0);
233  RangeSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
234  this, DW_AT_GNU_ranges_base, 0);
235  }
236 
237  setDIERelations();
238  return DieArray.size();
239 }
240 
241 DWARFUnit::DWOHolder::DWOHolder(object::ObjectFile *DWOFile)
242  : DWOFile(DWOFile),
243  DWOContext(cast<DWARFContext>(DIContext::getDWARFContext(DWOFile))),
244  DWOU(0) {
245  if (DWOContext->getNumDWOCompileUnits() > 0)
246  DWOU = DWOContext->getDWOCompileUnitAtIndex(0);
247 }
248 
249 bool DWARFUnit::parseDWO() {
250  if (DWO.get() != 0)
251  return false;
252  extractDIEsIfNeeded(true);
253  if (DieArray.empty())
254  return false;
255  const char *DWOFileName =
256  DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, 0);
257  if (DWOFileName == 0)
258  return false;
259  const char *CompilationDir =
260  DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, 0);
261  SmallString<16> AbsolutePath;
262  if (sys::path::is_relative(DWOFileName) && CompilationDir != 0) {
263  sys::path::append(AbsolutePath, CompilationDir);
264  }
265  sys::path::append(AbsolutePath, DWOFileName);
266  object::ObjectFile *DWOFile =
268  if (!DWOFile)
269  return false;
270  // Reset DWOHolder.
271  DWO.reset(new DWOHolder(DWOFile));
272  DWARFUnit *DWOCU = DWO->getUnit();
273  // Verify that compile unit in .dwo file is valid.
274  if (DWOCU == 0 || DWOCU->getDWOId() != getDWOId()) {
275  DWO.reset();
276  return false;
277  }
278  // Share .debug_addr and .debug_ranges section with compile unit in .dwo
279  DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
280  DWOCU->setRangesSection(RangeSection, RangeSectionBase);
281  return true;
282 }
283 
284 void DWARFUnit::clearDIEs(bool KeepCUDie) {
285  if (DieArray.size() > (unsigned)KeepCUDie) {
286  // std::vectors never get any smaller when resized to a smaller size,
287  // or when clear() or erase() are called, the size will report that it
288  // is smaller, but the memory allocated remains intact (call capacity()
289  // to see this). So we need to create a temporary vector and swap the
290  // contents which will cause just the internal pointers to be swapped
291  // so that when temporary vector goes out of scope, it will destroy the
292  // contents.
293  std::vector<DWARFDebugInfoEntryMinimal> TmpArray;
294  DieArray.swap(TmpArray);
295  // Save at least the compile unit DIE
296  if (KeepCUDie)
297  DieArray.push_back(TmpArray.front());
298  }
299 }
300 
301 void
303  bool clear_dies_if_already_not_parsed,
304  uint32_t CUOffsetInAranges) {
305  // This function is usually called if there in no .debug_aranges section
306  // in order to produce a compile unit level set of address ranges that
307  // is accurate. If the DIEs weren't parsed, then we don't want all dies for
308  // all compile units to stay loaded when they weren't needed. So we can end
309  // up parsing the DWARF and then throwing them all away to keep memory usage
310  // down.
311  const bool clear_dies = extractDIEsIfNeeded(false) > 1 &&
312  clear_dies_if_already_not_parsed;
313  DieArray[0].buildAddressRangeTable(this, debug_aranges, CUOffsetInAranges);
314  bool DWOCreated = parseDWO();
315  if (DWO.get()) {
316  // If there is a .dwo file for this compile unit, then skeleton CU DIE
317  // doesn't have children, and we should instead build address range table
318  // from DIEs in the .debug_info.dwo section of .dwo file.
319  DWO->getUnit()->buildAddressRangeTable(
320  debug_aranges, clear_dies_if_already_not_parsed, CUOffsetInAranges);
321  }
322  if (DWOCreated && clear_dies_if_already_not_parsed)
323  DWO.reset();
324 
325  // Keep memory down by clearing DIEs if this generate function
326  // caused them to be parsed.
327  if (clear_dies)
328  clearDIEs(true);
329 }
330 
332 DWARFUnit::getSubprogramForAddress(uint64_t Address) {
333  extractDIEsIfNeeded(false);
334  for (size_t i = 0, n = DieArray.size(); i != n; i++)
335  if (DieArray[i].isSubprogramDIE() &&
336  DieArray[i].addressRangeContainsAddress(this, Address)) {
337  return &DieArray[i];
338  }
339  return 0;
340 }
341 
344  // First, find a subprogram that contains the given address (the root
345  // of inlined chain).
346  const DWARFUnit *ChainCU = 0;
347  const DWARFDebugInfoEntryMinimal *SubprogramDIE =
348  getSubprogramForAddress(Address);
349  if (SubprogramDIE) {
350  ChainCU = this;
351  } else {
352  // Try to look for subprogram DIEs in the DWO file.
353  parseDWO();
354  if (DWO.get()) {
355  SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address);
356  if (SubprogramDIE)
357  ChainCU = DWO->getUnit();
358  }
359  }
360 
361  // Get inlined chain rooted at this subprogram DIE.
362  if (!SubprogramDIE)
364  return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address);
365 }
virtual ~DWARFUnit()
Definition: DWARFUnit.cpp:29
size_t size() const
size - Get the string size.
Definition: StringRef.h:113
void setBaseAddress(uint64_t base_addr)
Definition: DWARFUnit.h:120
bool is_relative(const Twine &path)
Is path relative?
Definition: Path.cpp:628
DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(const DWARFUnit *U, const uint64_t Address) const
bool extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const
Definition: DWARFUnit.cpp:88
uint32_t getNextUnitOffset() const
Definition: DWARFUnit.h:109
enable_if_c<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type cast(const Y &Val)
Definition: Casting.h:224
bool isValidOffset(uint32_t offset) const
bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const
Definition: DWARFUnit.cpp:42
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:372
uint32_t getU32(uint32_t *offset_ptr) const
const char * getCompilationDir()
Definition: DWARFUnit.cpp:110
static ObjectFile * createObjectFile(StringRef ObjectPath)
Create ObjectFile from path.
Definition: ObjectFile.cpp:79
uint64_t getDWOId()
Definition: DWARFUnit.cpp:117
uint32_t getFirstDIEOffset() const
Definition: DWARFUnit.h:108
const DWARFAbbreviationDeclarationSet * getAbbreviationDeclarationSet(uint64_t cu_abbr_offset) const
DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(uint64_t Address)
Definition: DWARFUnit.cpp:343
void setSibling(DWARFDebugInfoEntryMinimal *sibling)
bool extract(DataExtractor data, uint32_t *offset_ptr)
const DWARFAbbreviationDeclaration * getAbbreviationDeclarationPtr() const
DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data.
void reset(T *P=0)
Definition: OwningPtr.h:51
uint8_t getU8(uint32_t *offset_ptr) const
void setRangesSection(StringRef RS, uint32_t Base)
Definition: DWARFUnit.h:79
Definition: DIE.h:109
void buildAddressRangeTable(DWARFDebugAranges *debug_aranges, bool clear_dies_if_already_not_parsed, uint32_t CUOffsetInAranges)
Definition: DWARFUnit.cpp:302
T * get() const
Definition: OwningPtr.h:72
int fprintf(FILE *stream, const char *format, ...);
bool extract(DataExtractor debug_info, uint32_t *offset_ptr)
Definition: DWARFUnit.cpp:72
size_t getDebugInfoSize() const
Size in bytes of the .debug_info data associated with this compile unit.
Definition: DWARFUnit.h:111
uint16_t getU16(uint32_t *offset_ptr) const
uint64_t getAddress(uint32_t *offset_ptr) const
bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const
Definition: DWARFUnit.cpp:32
void setParent(DWARFDebugInfoEntryMinimal *parent)
static bool isSupportedVersion(unsigned version)
Definition: DWARFContext.h:162
virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr)
Definition: DWARFUnit.cpp:54
DWARFDebugInfoEntryMinimal * getParent()
uint32_t getOffset() const
Definition: DWARFUnit.h:105
DWARFUnit(const DWARFDebugAbbrev *DA, StringRef IS, StringRef AS, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, const RelocAddrMap *M, bool LE)
Definition: DWARFUnit.cpp:20
bool extractFast(const DWARFUnit *U, uint32_t *OffsetPtr)
void setAddrOffsetSection(StringRef AOS, uint32_t Base)
Definition: DWARFUnit.h:75