LLVM  3.7.0
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 
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  parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(),
23  C.isLittleEndian());
24 }
25 
27  const DWARFSection &DWOSection) {
28  parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(),
31 }
32 
34  const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
35  StringRef SOS, StringRef AOS, bool LE,
36  const DWARFUnitSectionBase &UnitSection)
37  : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS),
38  StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
39  isLittleEndian(LE), UnitSection(UnitSection) {
40  clear();
41 }
42 
44 }
45 
47  uint64_t &Result) const {
48  uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize;
49  if (AddrOffsetSection.size() < Offset + AddrSize)
50  return false;
51  DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize);
52  Result = DA.getAddress(&Offset);
53  return true;
54 }
55 
57  uint32_t &Result) const {
58  // FIXME: string offset section entries are 8-byte for DWARF64.
59  const uint32_t ItemSize = 4;
60  uint32_t Offset = Index * ItemSize;
61  if (StringOffsetSection.size() < Offset + ItemSize)
62  return false;
63  DataExtractor DA(StringOffsetSection, isLittleEndian, 0);
64  Result = DA.getU32(&Offset);
65  return true;
66 }
67 
68 bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
69  Length = debug_info.getU32(offset_ptr);
70  Version = debug_info.getU16(offset_ptr);
71  uint64_t AbbrOffset = debug_info.getU32(offset_ptr);
72  AddrSize = debug_info.getU8(offset_ptr);
73 
74  bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
75  bool VersionOK = DWARFContext::isSupportedVersion(Version);
76  bool AddrSizeOK = AddrSize == 4 || AddrSize == 8;
77 
78  if (!LengthOK || !VersionOK || !AddrSizeOK)
79  return false;
80 
81  Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset);
82  return Abbrevs != nullptr;
83 }
84 
85 bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
86  clear();
87 
88  Offset = *offset_ptr;
89 
90  if (debug_info.isValidOffset(*offset_ptr)) {
91  if (extractImpl(debug_info, offset_ptr))
92  return true;
93 
94  // reset the offset to where we tried to parse from if anything went wrong
95  *offset_ptr = Offset;
96  }
97 
98  return false;
99 }
100 
101 bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
102  DWARFDebugRangeList &RangeList) const {
103  // Require that compile unit is extracted.
104  assert(DieArray.size() > 0);
105  DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize);
106  uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
107  return RangeList.extract(RangesData, &ActualRangeListOffset);
108 }
109 
111  Offset = 0;
112  Length = 0;
113  Version = 0;
114  Abbrevs = nullptr;
115  AddrSize = 0;
116  BaseAddr = 0;
117  RangeSectionBase = 0;
118  AddrOffsetSectionBase = 0;
119  clearDIEs(false);
120  DWO.reset();
121 }
122 
124  extractDIEsIfNeeded(true);
125  if (DieArray.empty())
126  return nullptr;
127  return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr);
128 }
129 
131  extractDIEsIfNeeded(true);
132  const uint64_t FailValue = -1ULL;
133  if (DieArray.empty())
134  return FailValue;
135  return DieArray[0]
136  .getAttributeValueAsUnsignedConstant(this, DW_AT_GNU_dwo_id, FailValue);
137 }
138 
139 void DWARFUnit::setDIERelations() {
140  if (DieArray.size() <= 1)
141  return;
142 
143  std::vector<DWARFDebugInfoEntryMinimal *> ParentChain;
144  DWARFDebugInfoEntryMinimal *SiblingChain = nullptr;
145  for (auto &DIE : DieArray) {
146  if (SiblingChain) {
147  SiblingChain->setSibling(&DIE);
148  }
149  if (const DWARFAbbreviationDeclaration *AbbrDecl =
150  DIE.getAbbreviationDeclarationPtr()) {
151  // Normal DIE.
152  if (AbbrDecl->hasChildren()) {
153  ParentChain.push_back(&DIE);
154  SiblingChain = nullptr;
155  } else {
156  SiblingChain = &DIE;
157  }
158  } else {
159  // NULL entry terminates the sibling chain.
160  SiblingChain = ParentChain.back();
161  ParentChain.pop_back();
162  }
163  }
164  assert(SiblingChain == nullptr || SiblingChain == &DieArray[0]);
165  assert(ParentChain.empty());
166 }
167 
168 void DWARFUnit::extractDIEsToVector(
169  bool AppendCUDie, bool AppendNonCUDies,
170  std::vector<DWARFDebugInfoEntryMinimal> &Dies) const {
171  if (!AppendCUDie && !AppendNonCUDies)
172  return;
173 
174  // Set the offset to that of the first DIE and calculate the start of the
175  // next compilation unit header.
176  uint32_t DIEOffset = Offset + getHeaderSize();
177  uint32_t NextCUOffset = getNextUnitOffset();
179  uint32_t Depth = 0;
180  bool IsCUDie = true;
181 
182  while (DIEOffset < NextCUOffset && DIE.extractFast(this, &DIEOffset)) {
183  if (IsCUDie) {
184  if (AppendCUDie)
185  Dies.push_back(DIE);
186  if (!AppendNonCUDies)
187  break;
188  // The average bytes per DIE entry has been seen to be
189  // around 14-20 so let's pre-reserve the needed memory for
190  // our DIE entries accordingly.
191  Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
192  IsCUDie = false;
193  } else {
194  Dies.push_back(DIE);
195  }
196 
197  if (const DWARFAbbreviationDeclaration *AbbrDecl =
199  // Normal DIE
200  if (AbbrDecl->hasChildren())
201  ++Depth;
202  } else {
203  // NULL DIE.
204  if (Depth > 0)
205  --Depth;
206  if (Depth == 0)
207  break; // We are done with this compile unit!
208  }
209  }
210 
211  // Give a little bit of info if we encounter corrupt DWARF (our offset
212  // should always terminate at or before the start of the next compilation
213  // unit header).
214  if (DIEOffset > NextCUOffset)
215  fprintf(stderr, "warning: DWARF compile unit extends beyond its "
216  "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), DIEOffset);
217 }
218 
219 size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
220  if ((CUDieOnly && DieArray.size() > 0) ||
221  DieArray.size() > 1)
222  return 0; // Already parsed.
223 
224  bool HasCUDie = DieArray.size() > 0;
225  extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
226 
227  if (DieArray.empty())
228  return 0;
229 
230  // If CU DIE was just parsed, copy several attribute values from it.
231  if (!HasCUDie) {
232  uint64_t BaseAddr =
233  DieArray[0].getAttributeValueAsAddress(this, DW_AT_low_pc, -1ULL);
234  if (BaseAddr == -1ULL)
235  BaseAddr = DieArray[0].getAttributeValueAsAddress(this, DW_AT_entry_pc, 0);
236  setBaseAddress(BaseAddr);
237  AddrOffsetSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
238  this, DW_AT_GNU_addr_base, 0);
239  RangeSectionBase = DieArray[0].getAttributeValueAsSectionOffset(
240  this, DW_AT_ranges_base, 0);
241  // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
242  // skeleton CU DIE, so that DWARF users not aware of it are not broken.
243  }
244 
245  setDIERelations();
246  return DieArray.size();
247 }
248 
249 DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath)
250  : DWOFile(), DWOContext(), DWOU(nullptr) {
251  auto Obj = object::ObjectFile::createObjectFile(DWOPath);
252  if (!Obj)
253  return;
254  DWOFile = std::move(Obj.get());
255  DWOContext.reset(
256  cast<DWARFContext>(new DWARFContextInMemory(*DWOFile.getBinary())));
257  if (DWOContext->getNumDWOCompileUnits() > 0)
258  DWOU = DWOContext->getDWOCompileUnitAtIndex(0);
259 }
260 
261 bool DWARFUnit::parseDWO() {
262  if (DWO.get())
263  return false;
264  extractDIEsIfNeeded(true);
265  if (DieArray.empty())
266  return false;
267  const char *DWOFileName =
268  DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, nullptr);
269  if (!DWOFileName)
270  return false;
271  const char *CompilationDir =
272  DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr);
273  SmallString<16> AbsolutePath;
274  if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) {
275  sys::path::append(AbsolutePath, CompilationDir);
276  }
277  sys::path::append(AbsolutePath, DWOFileName);
278  DWO = llvm::make_unique<DWOHolder>(AbsolutePath);
279  DWARFUnit *DWOCU = DWO->getUnit();
280  // Verify that compile unit in .dwo file is valid.
281  if (!DWOCU || DWOCU->getDWOId() != getDWOId()) {
282  DWO.reset();
283  return false;
284  }
285  // Share .debug_addr and .debug_ranges section with compile unit in .dwo
286  DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
287  uint32_t DWORangesBase = DieArray[0].getRangesBaseAttribute(this, 0);
288  DWOCU->setRangesSection(RangeSection, DWORangesBase);
289  return true;
290 }
291 
292 void DWARFUnit::clearDIEs(bool KeepCUDie) {
293  if (DieArray.size() > (unsigned)KeepCUDie) {
294  // std::vectors never get any smaller when resized to a smaller size,
295  // or when clear() or erase() are called, the size will report that it
296  // is smaller, but the memory allocated remains intact (call capacity()
297  // to see this). So we need to create a temporary vector and swap the
298  // contents which will cause just the internal pointers to be swapped
299  // so that when temporary vector goes out of scope, it will destroy the
300  // contents.
301  std::vector<DWARFDebugInfoEntryMinimal> TmpArray;
302  DieArray.swap(TmpArray);
303  // Save at least the compile unit DIE
304  if (KeepCUDie)
305  DieArray.push_back(TmpArray.front());
306  }
307 }
308 
310  const auto *U = getUnitDIE();
311  if (U == nullptr)
312  return;
313  // First, check if unit DIE describes address ranges for the whole unit.
314  const auto &CUDIERanges = U->getAddressRanges(this);
315  if (!CUDIERanges.empty()) {
316  CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
317  return;
318  }
319 
320  // This function is usually called if there in no .debug_aranges section
321  // in order to produce a compile unit level set of address ranges that
322  // is accurate. If the DIEs weren't parsed, then we don't want all dies for
323  // all compile units to stay loaded when they weren't needed. So we can end
324  // up parsing the DWARF and then throwing them all away to keep memory usage
325  // down.
326  const bool ClearDIEs = extractDIEsIfNeeded(false) > 1;
327  DieArray[0].collectChildrenAddressRanges(this, CURanges);
328 
329  // Collect address ranges from DIEs in .dwo if necessary.
330  bool DWOCreated = parseDWO();
331  if (DWO.get())
332  DWO->getUnit()->collectAddressRanges(CURanges);
333  if (DWOCreated)
334  DWO.reset();
335 
336  // Keep memory down by clearing DIEs if this generate function
337  // caused them to be parsed.
338  if (ClearDIEs)
339  clearDIEs(true);
340 }
341 
343 DWARFUnit::getSubprogramForAddress(uint64_t Address) {
344  extractDIEsIfNeeded(false);
345  for (const DWARFDebugInfoEntryMinimal &DIE : DieArray) {
346  if (DIE.isSubprogramDIE() &&
347  DIE.addressRangeContainsAddress(this, Address)) {
348  return &DIE;
349  }
350  }
351  return nullptr;
352 }
353 
356  // First, find a subprogram that contains the given address (the root
357  // of inlined chain).
358  const DWARFUnit *ChainCU = nullptr;
359  const DWARFDebugInfoEntryMinimal *SubprogramDIE =
360  getSubprogramForAddress(Address);
361  if (SubprogramDIE) {
362  ChainCU = this;
363  } else {
364  // Try to look for subprogram DIEs in the DWO file.
365  parseDWO();
366  if (DWO.get()) {
367  SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address);
368  if (SubprogramDIE)
369  ChainCU = DWO->getUnit();
370  }
371  }
372 
373  // Get inlined chain rooted at this subprogram DIE.
374  if (!SubprogramDIE)
376  return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address);
377 }
virtual StringRef getAddrSection()=0
virtual ~DWARFUnit()
Definition: DWARFUnit.cpp:43
size_t size() const
size - Get the string size.
Definition: StringRef.h:113
void setBaseAddress(uint64_t base_addr)
Definition: DWARFUnit.h:194
virtual StringRef getStringOffsetDWOSection()=0
virtual StringRef getRangeDWOSection()=0
bool is_relative(const Twine &path)
Is path relative?
Definition: Path.cpp:664
std::vector< std::pair< uint64_t, uint64_t > > DWARFAddressRangesVector
DWARFAddressRangesVector - represents a set of absolute address ranges.
void collectAddressRanges(DWARFAddressRangesVector &CURanges)
Definition: DWARFUnit.cpp:309
virtual uint32_t getHeaderSize() const
Size in bytes of the unit header.
Definition: DWARFUnit.h:140
DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, bool LE, const DWARFUnitSectionBase &UnitSection)
Definition: DWARFUnit.cpp:33
DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(const DWARFUnit *U, const uint64_t Address) const
Get inlined chain for a given address, rooted at the current DIE.
bool extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const
extractRangeList - extracts the range list referenced by this compile unit from .debug_ranges section...
Definition: DWARFUnit.cpp:101
uint32_t getNextUnitOffset() const
Definition: DWARFUnit.h:185
const DWARFDebugAbbrev * getDebugAbbrevDWO()
Get a pointer to the parsed dwo abbreviations object.
virtual StringRef getStringDWOSection()=0
bool isValidOffset(uint32_t offset) const
Test the validity of offset.
bool getStringOffsetSectionItem(uint32_t Index, uint32_t &Result) const
Definition: DWARFUnit.cpp:56
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:443
uint32_t getU32(uint32_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
const char * getCompilationDir()
Definition: DWARFUnit.cpp:123
uint64_t getDWOId()
Definition: DWARFUnit.cpp:130
virtual StringRef getRangeSection()=0
DWARFDebugInfoEntryInlinedChain getInlinedChainForAddress(uint64_t Address)
getInlinedChainForAddress - fetches inlined chain for a given address.
Definition: DWARFUnit.cpp:355
void parse(DWARFContext &C, const DWARFSection &Section)
Definition: DWARFUnit.cpp:20
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:25
const DWARFDebugAbbrev * getDebugAbbrev()
Get a pointer to the parsed DebugAbbrev object.
bool addressRangeContainsAddress(const DWARFUnit *U, const uint64_t Address) const
bool extract(DataExtractor data, uint32_t *offset_ptr)
DWARFContextInMemory is the simplest possible implementation of a DWARFContext.
Definition: DWARFContext.h:222
const DWARFAbbreviationDeclaration * getAbbreviationDeclarationPtr() const
const DWARFAbbreviationDeclarationSet * getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const
DWARFDebugInfoEntryMinimal - A DIE with only the minimum required data.
uint8_t getU8(uint32_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
DIE - A structured debug information entry.
Definition: DIE.h:623
bool extract(DataExtractor debug_info, uint32_t *offset_ptr)
Definition: DWARFUnit.cpp:85
DWARFContext This data structure is the top level entity that deals with dwarf debug information pars...
Definition: DWARFContext.h:39
uint16_t getU16(uint32_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
uint64_t getAddress(uint32_t *offset_ptr) const
Extract an pointer from *offset_ptr.
void parseDWO(DWARFContext &C, const DWARFSection &DWOSection)
Definition: DWARFUnit.cpp:26
bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const
Definition: DWARFUnit.cpp:46
static bool isSupportedVersion(unsigned version)
Definition: DWARFContext.h:207
void setSibling(const DWARFDebugInfoEntryMinimal *Sibling)
virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr)
Definition: DWARFUnit.cpp:68
uint32_t getOffset() const
Definition: DWARFUnit.h:184
Base class for all DWARFUnitSection classes.
Definition: DWARFUnit.h:35
bool isSubprogramDIE() const
Returns true if DIE represents a subprogram (not inlined).
const DWARFDebugInfoEntryMinimal * getUnitDIE(bool ExtractUnitDIEOnly=true)
Definition: DWARFUnit.h:198
static ErrorOr< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Create ObjectFile from path.
Definition: ObjectFile.cpp:102
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:40
virtual StringRef getStringSection()=0
bool extractFast(const DWARFUnit *U, uint32_t *OffsetPtr)
Extracts a debug info entry, which is a child of a given unit, starting at a given offset...
virtual bool isLittleEndian() const =0
DWARFDebugInfoEntryInlinedChain - represents a chain of inlined_subroutine DIEs, (possibly ending wit...