blob: f04ec7706cd8368bc4b0726e13d3624ea61a1027 [file] [log] [blame]
Eugene Zelenkoe94042c2017-02-27 23:43:14 +00001//===- DWARFAcceleratorTable.cpp ------------------------------------------===//
Frederic Riss7c41c642014-11-20 16:21:06 +00002//
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
Zachary Turner82af9432015-01-30 18:07:45 +000010#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000011
Chandler Carruth6bda14b2017-06-06 11:49:48 +000012#include "llvm/ADT/SmallVector.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000013#include "llvm/BinaryFormat/Dwarf.h"
George Rimarf8a96422017-04-21 09:12:18 +000014#include "llvm/DebugInfo/DWARF/DWARFContext.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000015#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000016#include "llvm/Support/Compiler.h"
Frederic Risse837ec22014-11-14 16:15:53 +000017#include "llvm/Support/Format.h"
18#include "llvm/Support/raw_ostream.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000019#include <cstddef>
20#include <cstdint>
21#include <utility>
Frederic Risse837ec22014-11-14 16:15:53 +000022
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000023using namespace llvm;
Frederic Risse837ec22014-11-14 16:15:53 +000024
25bool DWARFAcceleratorTable::extract() {
26 uint32_t Offset = 0;
27
28 // Check that we can at least read the header.
29 if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
30 return false;
31
32 Hdr.Magic = AccelSection.getU32(&Offset);
33 Hdr.Version = AccelSection.getU16(&Offset);
34 Hdr.HashFunction = AccelSection.getU16(&Offset);
35 Hdr.NumBuckets = AccelSection.getU32(&Offset);
36 Hdr.NumHashes = AccelSection.getU32(&Offset);
37 Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
38
39 // Check that we can read all the hashes and offsets from the
40 // section (see SourceLevelDebugging.rst for the structure of the index).
41 if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
42 Hdr.NumBuckets*4 + Hdr.NumHashes*8))
43 return false;
44
45 HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
46 uint32_t NumAtoms = AccelSection.getU32(&Offset);
47
48 for (unsigned i = 0; i < NumAtoms; ++i) {
49 uint16_t AtomType = AccelSection.getU16(&Offset);
Greg Clayton6c273762016-10-27 16:32:04 +000050 auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
Frederic Risse837ec22014-11-14 16:15:53 +000051 HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
52 }
53
Adrian Prantl99fdb9d2017-09-28 18:10:52 +000054 IsValid = true;
Frederic Risse837ec22014-11-14 16:15:53 +000055 return true;
56}
57
Spyridoula Gravanie41823b2017-06-14 00:17:55 +000058uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
59uint32_t DWARFAcceleratorTable::getNumHashes() { return Hdr.NumHashes; }
60uint32_t DWARFAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
61uint32_t DWARFAcceleratorTable::getHeaderDataLength() {
62 return Hdr.HeaderDataLength;
63}
64
Spyridoula Gravani837c1102017-06-29 20:13:05 +000065ArrayRef<std::pair<DWARFAcceleratorTable::HeaderData::AtomType,
66 DWARFAcceleratorTable::HeaderData::Form>>
67DWARFAcceleratorTable::getAtomsDesc() {
68 return HdrData.Atoms;
69}
70
71bool DWARFAcceleratorTable::validateForms() {
72 for (auto Atom : getAtomsDesc()) {
73 DWARFFormValue FormValue(Atom.second);
74 switch (Atom.first) {
75 case dwarf::DW_ATOM_die_offset:
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000076 case dwarf::DW_ATOM_die_tag:
77 case dwarf::DW_ATOM_type_flags:
Spyridoula Gravani837c1102017-06-29 20:13:05 +000078 if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
79 !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
80 FormValue.getForm() == dwarf::DW_FORM_sdata)
81 return false;
82 default:
83 break;
84 }
85 }
86 return true;
87}
88
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000089std::pair<uint32_t, dwarf::Tag>
90DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000091 uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000092 dwarf::Tag DieTag = dwarf::DW_TAG_null;
Paul Robinsone5400f82017-11-07 19:57:12 +000093 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Spyridoula Gravani837c1102017-06-29 20:13:05 +000094
95 for (auto Atom : getAtomsDesc()) {
96 DWARFFormValue FormValue(Atom.second);
Paul Robinsone5400f82017-11-07 19:57:12 +000097 FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
Spyridoula Gravani837c1102017-06-29 20:13:05 +000098 switch (Atom.first) {
99 case dwarf::DW_ATOM_die_offset:
100 DieOffset = *FormValue.getAsUnsignedConstant();
101 break;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000102 case dwarf::DW_ATOM_die_tag:
103 DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
104 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000105 default:
106 break;
107 }
108 }
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000109 return {DieOffset, DieTag};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000110}
111
Matthias Braun8c209aa2017-01-28 02:02:38 +0000112LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000113 if (!IsValid)
114 return;
115
Frederic Risse837ec22014-11-14 16:15:53 +0000116 // Dump the header.
117 OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
118 << "Version = " << format("0x%04x", Hdr.Version) << '\n'
119 << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
120 << "Bucket count = " << Hdr.NumBuckets << '\n'
121 << "Hashes count = " << Hdr.NumHashes << '\n'
122 << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
123 << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
124 << "Number of atoms = " << HdrData.Atoms.size() << '\n';
125
126 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000127 SmallVector<DWARFFormValue, 3> AtomForms;
Frederic Risse837ec22014-11-14 16:15:53 +0000128 for (const auto &Atom: HdrData.Atoms) {
129 OS << format("Atom[%d] Type: ", i++);
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000130 auto TypeString = dwarf::AtomTypeString(Atom.first);
131 if (!TypeString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000132 OS << TypeString;
133 else
134 OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
135 OS << " Form: ";
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000136 auto FormString = dwarf::FormEncodingString(Atom.second);
137 if (!FormString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000138 OS << FormString;
139 else
Frederic Riss77a07432014-11-20 16:21:11 +0000140 OS << format("DW_FORM_Unknown_0x%x", Atom.second);
Frederic Risse837ec22014-11-14 16:15:53 +0000141 OS << '\n';
Frederic Riss77a07432014-11-20 16:21:11 +0000142 AtomForms.push_back(DWARFFormValue(Atom.second));
Frederic Risse837ec22014-11-14 16:15:53 +0000143 }
144
145 // Now go through the actual tables and dump them.
146 uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
147 unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
148 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
Paul Robinsone5400f82017-11-07 19:57:12 +0000149 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Frederic Risse837ec22014-11-14 16:15:53 +0000150
151 for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
152 unsigned Index = AccelSection.getU32(&Offset);
153
154 OS << format("Bucket[%d]\n", Bucket);
155 if (Index == UINT32_MAX) {
156 OS << " EMPTY\n";
157 continue;
158 }
159
160 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
161 unsigned HashOffset = HashesBase + HashIdx*4;
162 unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
163 uint32_t Hash = AccelSection.getU32(&HashOffset);
164
165 if (Hash % Hdr.NumBuckets != Bucket)
166 break;
167
168 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
169 OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
170 if (!AccelSection.isValidOffset(DataOffset)) {
171 OS << " Invalid section offset\n";
172 continue;
173 }
Frederic Riss7c500472014-11-14 19:30:08 +0000174 while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
Paul Robinson17536b92017-06-29 16:52:08 +0000175 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
Frederic Riss7c500472014-11-14 19:30:08 +0000176 if (!StringOffset)
177 break;
Frederic Risse837ec22014-11-14 16:15:53 +0000178 OS << format(" Name: %08x \"%s\"\n", StringOffset,
179 StringSection.getCStr(&StringOffset));
180 unsigned NumData = AccelSection.getU32(&DataOffset);
181 for (unsigned Data = 0; Data < NumData; ++Data) {
182 OS << format(" Data[%d] => ", Data);
183 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000184 for (auto &Atom : AtomForms) {
Frederic Risse837ec22014-11-14 16:15:53 +0000185 OS << format("{Atom[%d]: ", i++);
Paul Robinsone5400f82017-11-07 19:57:12 +0000186 if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
Greg Claytoncddab272016-10-31 16:46:02 +0000187 Atom.dump(OS);
Frederic Risse837ec22014-11-14 16:15:53 +0000188 else
189 OS << "Error extracting the value";
190 OS << "} ";
191 }
192 OS << '\n';
193 }
194 }
195 }
196 }
197}
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000198
199DWARFAcceleratorTable::ValueIterator::ValueIterator(
200 const DWARFAcceleratorTable &AccelTable, unsigned Offset)
201 : AccelTable(&AccelTable), DataOffset(Offset) {
202 if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
203 return;
204
205 for (const auto &Atom : AccelTable.HdrData.Atoms)
206 AtomForms.push_back(DWARFFormValue(Atom.second));
207
208 // Read the first entry.
209 NumData = AccelTable.AccelSection.getU32(&DataOffset);
210 Next();
211}
212
213void DWARFAcceleratorTable::ValueIterator::Next() {
214 assert(NumData > 0 && "attempted to increment iterator past the end");
215 auto &AccelSection = AccelTable->AccelSection;
216 if (Data >= NumData ||
217 !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
218 NumData = 0;
219 return;
220 }
Paul Robinsone5400f82017-11-07 19:57:12 +0000221 DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
222 dwarf::DwarfFormat::DWARF32};
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000223 for (auto &Atom : AtomForms)
Paul Robinsone5400f82017-11-07 19:57:12 +0000224 Atom.extractValue(AccelSection, &DataOffset, FormParams);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000225 ++Data;
226}
227
228iterator_range<DWARFAcceleratorTable::ValueIterator>
229DWARFAcceleratorTable::equal_range(StringRef Key) const {
230 if (!IsValid)
231 return make_range(ValueIterator(), ValueIterator());
232
233 // Find the bucket.
234 unsigned HashValue = dwarf::djbHash(Key);
235 unsigned Bucket = HashValue % Hdr.NumBuckets;
236 unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
237 unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
238 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
239
240 unsigned BucketOffset = BucketBase + Bucket * 4;
241 unsigned Index = AccelSection.getU32(&BucketOffset);
242
243 // Search through all hashes in the bucket.
244 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
245 unsigned HashOffset = HashesBase + HashIdx * 4;
246 unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
247 uint32_t Hash = AccelSection.getU32(&HashOffset);
248
249 if (Hash % Hdr.NumBuckets != Bucket)
250 // We are already in the next bucket.
251 break;
252
253 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
254 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
255 if (!StringOffset)
256 break;
257
258 // Finally, compare the key.
259 if (Key == StringSection.getCStr(&StringOffset))
260 return make_range({*this, DataOffset}, ValueIterator());
261 }
262 return make_range(ValueIterator(), ValueIterator());
263}