blob: ac30f74f346654ca408a1930cc7dce17d4bd9491 [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"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000014#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000015#include "llvm/Support/Compiler.h"
Frederic Risse837ec22014-11-14 16:15:53 +000016#include "llvm/Support/Format.h"
17#include "llvm/Support/raw_ostream.h"
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000018#include <cstddef>
19#include <cstdint>
20#include <utility>
Frederic Risse837ec22014-11-14 16:15:53 +000021
Eugene Zelenkoe94042c2017-02-27 23:43:14 +000022using namespace llvm;
Frederic Risse837ec22014-11-14 16:15:53 +000023
Pavel Labath9b36fd22018-01-22 13:17:23 +000024llvm::Error AppleAcceleratorTable::extract() {
Frederic Risse837ec22014-11-14 16:15:53 +000025 uint32_t Offset = 0;
26
27 // Check that we can at least read the header.
28 if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
Jonas Devlieghereba915892017-12-11 18:22:47 +000029 return make_error<StringError>("Section too small: cannot read header.",
30 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000031
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).
Jonas Devlieghereba915892017-12-11 18:22:47 +000041 // We need to substract one because we're checking for an *offset* which is
42 // equal to the size for an empty table and hence pointer after the section.
Frederic Risse837ec22014-11-14 16:15:53 +000043 if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
Jonas Devlieghereba915892017-12-11 18:22:47 +000044 Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1))
45 return make_error<StringError>(
46 "Section too small: cannot read buckets and hashes.",
47 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000048
49 HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
50 uint32_t NumAtoms = AccelSection.getU32(&Offset);
51
52 for (unsigned i = 0; i < NumAtoms; ++i) {
53 uint16_t AtomType = AccelSection.getU16(&Offset);
Greg Clayton6c273762016-10-27 16:32:04 +000054 auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
Frederic Risse837ec22014-11-14 16:15:53 +000055 HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
56 }
57
Adrian Prantl99fdb9d2017-09-28 18:10:52 +000058 IsValid = true;
Jonas Devlieghereba915892017-12-11 18:22:47 +000059 return Error::success();
Frederic Risse837ec22014-11-14 16:15:53 +000060}
61
Pavel Labath9b36fd22018-01-22 13:17:23 +000062uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
63uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.NumHashes; }
64uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
65uint32_t AppleAcceleratorTable::getHeaderDataLength() {
Spyridoula Gravanie41823b2017-06-14 00:17:55 +000066 return Hdr.HeaderDataLength;
67}
68
Pavel Labath9b36fd22018-01-22 13:17:23 +000069ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
70 AppleAcceleratorTable::HeaderData::Form>>
71AppleAcceleratorTable::getAtomsDesc() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000072 return HdrData.Atoms;
73}
74
Pavel Labath9b36fd22018-01-22 13:17:23 +000075bool AppleAcceleratorTable::validateForms() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000076 for (auto Atom : getAtomsDesc()) {
77 DWARFFormValue FormValue(Atom.second);
78 switch (Atom.first) {
79 case dwarf::DW_ATOM_die_offset:
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000080 case dwarf::DW_ATOM_die_tag:
81 case dwarf::DW_ATOM_type_flags:
Spyridoula Gravani837c1102017-06-29 20:13:05 +000082 if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
83 !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
84 FormValue.getForm() == dwarf::DW_FORM_sdata)
85 return false;
Adrian Prantl0e6694d2017-12-19 22:05:25 +000086 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +000087 default:
88 break;
89 }
90 }
91 return true;
92}
93
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000094std::pair<uint32_t, dwarf::Tag>
Pavel Labath9b36fd22018-01-22 13:17:23 +000095AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000096 uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000097 dwarf::Tag DieTag = dwarf::DW_TAG_null;
Paul Robinsone5400f82017-11-07 19:57:12 +000098 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Spyridoula Gravani837c1102017-06-29 20:13:05 +000099
100 for (auto Atom : getAtomsDesc()) {
101 DWARFFormValue FormValue(Atom.second);
Paul Robinsone5400f82017-11-07 19:57:12 +0000102 FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000103 switch (Atom.first) {
104 case dwarf::DW_ATOM_die_offset:
105 DieOffset = *FormValue.getAsUnsignedConstant();
106 break;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000107 case dwarf::DW_ATOM_die_tag:
108 DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
109 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000110 default:
111 break;
112 }
113 }
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000114 return {DieOffset, DieTag};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000115}
116
Pavel Labath9b36fd22018-01-22 13:17:23 +0000117LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000118 if (!IsValid)
119 return;
120
Frederic Risse837ec22014-11-14 16:15:53 +0000121 // Dump the header.
122 OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
123 << "Version = " << format("0x%04x", Hdr.Version) << '\n'
124 << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
125 << "Bucket count = " << Hdr.NumBuckets << '\n'
126 << "Hashes count = " << Hdr.NumHashes << '\n'
127 << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
128 << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
129 << "Number of atoms = " << HdrData.Atoms.size() << '\n';
130
131 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000132 SmallVector<DWARFFormValue, 3> AtomForms;
Frederic Risse837ec22014-11-14 16:15:53 +0000133 for (const auto &Atom: HdrData.Atoms) {
134 OS << format("Atom[%d] Type: ", i++);
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000135 auto TypeString = dwarf::AtomTypeString(Atom.first);
136 if (!TypeString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000137 OS << TypeString;
138 else
139 OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
140 OS << " Form: ";
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000141 auto FormString = dwarf::FormEncodingString(Atom.second);
142 if (!FormString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000143 OS << FormString;
144 else
Frederic Riss77a07432014-11-20 16:21:11 +0000145 OS << format("DW_FORM_Unknown_0x%x", Atom.second);
Frederic Risse837ec22014-11-14 16:15:53 +0000146 OS << '\n';
Frederic Riss77a07432014-11-20 16:21:11 +0000147 AtomForms.push_back(DWARFFormValue(Atom.second));
Frederic Risse837ec22014-11-14 16:15:53 +0000148 }
149
150 // Now go through the actual tables and dump them.
151 uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
152 unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
153 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
Paul Robinsone5400f82017-11-07 19:57:12 +0000154 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Frederic Risse837ec22014-11-14 16:15:53 +0000155
156 for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
157 unsigned Index = AccelSection.getU32(&Offset);
158
159 OS << format("Bucket[%d]\n", Bucket);
160 if (Index == UINT32_MAX) {
161 OS << " EMPTY\n";
162 continue;
163 }
164
165 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
166 unsigned HashOffset = HashesBase + HashIdx*4;
167 unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
168 uint32_t Hash = AccelSection.getU32(&HashOffset);
169
170 if (Hash % Hdr.NumBuckets != Bucket)
171 break;
172
173 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
174 OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
175 if (!AccelSection.isValidOffset(DataOffset)) {
176 OS << " Invalid section offset\n";
177 continue;
178 }
Frederic Riss7c500472014-11-14 19:30:08 +0000179 while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
Paul Robinson17536b92017-06-29 16:52:08 +0000180 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
Frederic Riss7c500472014-11-14 19:30:08 +0000181 if (!StringOffset)
182 break;
Frederic Risse837ec22014-11-14 16:15:53 +0000183 OS << format(" Name: %08x \"%s\"\n", StringOffset,
184 StringSection.getCStr(&StringOffset));
185 unsigned NumData = AccelSection.getU32(&DataOffset);
186 for (unsigned Data = 0; Data < NumData; ++Data) {
187 OS << format(" Data[%d] => ", Data);
188 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000189 for (auto &Atom : AtomForms) {
Frederic Risse837ec22014-11-14 16:15:53 +0000190 OS << format("{Atom[%d]: ", i++);
Paul Robinsone5400f82017-11-07 19:57:12 +0000191 if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
Greg Claytoncddab272016-10-31 16:46:02 +0000192 Atom.dump(OS);
Frederic Risse837ec22014-11-14 16:15:53 +0000193 else
194 OS << "Error extracting the value";
195 OS << "} ";
196 }
197 OS << '\n';
198 }
199 }
200 }
201 }
202}
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000203
Pavel Labath9b36fd22018-01-22 13:17:23 +0000204AppleAcceleratorTable::ValueIterator::ValueIterator(
205 const AppleAcceleratorTable &AccelTable, unsigned Offset)
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000206 : AccelTable(&AccelTable), DataOffset(Offset) {
207 if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
208 return;
209
210 for (const auto &Atom : AccelTable.HdrData.Atoms)
211 AtomForms.push_back(DWARFFormValue(Atom.second));
212
213 // Read the first entry.
214 NumData = AccelTable.AccelSection.getU32(&DataOffset);
215 Next();
216}
217
Pavel Labath9b36fd22018-01-22 13:17:23 +0000218void AppleAcceleratorTable::ValueIterator::Next() {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000219 assert(NumData > 0 && "attempted to increment iterator past the end");
220 auto &AccelSection = AccelTable->AccelSection;
221 if (Data >= NumData ||
222 !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
223 NumData = 0;
224 return;
225 }
Paul Robinsone5400f82017-11-07 19:57:12 +0000226 DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
227 dwarf::DwarfFormat::DWARF32};
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000228 for (auto &Atom : AtomForms)
Paul Robinsone5400f82017-11-07 19:57:12 +0000229 Atom.extractValue(AccelSection, &DataOffset, FormParams);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000230 ++Data;
231}
232
Pavel Labath9b36fd22018-01-22 13:17:23 +0000233iterator_range<AppleAcceleratorTable::ValueIterator>
234AppleAcceleratorTable::equal_range(StringRef Key) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000235 if (!IsValid)
236 return make_range(ValueIterator(), ValueIterator());
237
238 // Find the bucket.
239 unsigned HashValue = dwarf::djbHash(Key);
240 unsigned Bucket = HashValue % Hdr.NumBuckets;
241 unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
242 unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
243 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
244
245 unsigned BucketOffset = BucketBase + Bucket * 4;
246 unsigned Index = AccelSection.getU32(&BucketOffset);
247
248 // Search through all hashes in the bucket.
249 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
250 unsigned HashOffset = HashesBase + HashIdx * 4;
251 unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
252 uint32_t Hash = AccelSection.getU32(&HashOffset);
253
254 if (Hash % Hdr.NumBuckets != Bucket)
255 // We are already in the next bucket.
256 break;
257
258 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
259 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
260 if (!StringOffset)
261 break;
262
263 // Finally, compare the key.
264 if (Key == StringSection.getCStr(&StringOffset))
265 return make_range({*this, DataOffset}, ValueIterator());
266 }
267 return make_range(ValueIterator(), ValueIterator());
268}