blob: 8bb14876f15344786dc7f11640f236e8f41850cc [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"
Jonas Devlieghere92ac9d32018-01-28 11:05:10 +000016#include "llvm/Support/DJB.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
Pavel Labath9b36fd22018-01-22 13:17:23 +000025llvm::Error AppleAcceleratorTable::extract() {
Frederic Risse837ec22014-11-14 16:15:53 +000026 uint32_t Offset = 0;
27
28 // Check that we can at least read the header.
29 if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
Jonas Devlieghereba915892017-12-11 18:22:47 +000030 return make_error<StringError>("Section too small: cannot read header.",
31 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000032
33 Hdr.Magic = AccelSection.getU32(&Offset);
34 Hdr.Version = AccelSection.getU16(&Offset);
35 Hdr.HashFunction = AccelSection.getU16(&Offset);
36 Hdr.NumBuckets = AccelSection.getU32(&Offset);
37 Hdr.NumHashes = AccelSection.getU32(&Offset);
38 Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
39
40 // Check that we can read all the hashes and offsets from the
41 // section (see SourceLevelDebugging.rst for the structure of the index).
Jonas Devlieghereba915892017-12-11 18:22:47 +000042 // We need to substract one because we're checking for an *offset* which is
43 // equal to the size for an empty table and hence pointer after the section.
Frederic Risse837ec22014-11-14 16:15:53 +000044 if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
Jonas Devlieghereba915892017-12-11 18:22:47 +000045 Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1))
46 return make_error<StringError>(
47 "Section too small: cannot read buckets and hashes.",
48 inconvertibleErrorCode());
Frederic Risse837ec22014-11-14 16:15:53 +000049
50 HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
51 uint32_t NumAtoms = AccelSection.getU32(&Offset);
52
53 for (unsigned i = 0; i < NumAtoms; ++i) {
54 uint16_t AtomType = AccelSection.getU16(&Offset);
Greg Clayton6c273762016-10-27 16:32:04 +000055 auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
Frederic Risse837ec22014-11-14 16:15:53 +000056 HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
57 }
58
Adrian Prantl99fdb9d2017-09-28 18:10:52 +000059 IsValid = true;
Jonas Devlieghereba915892017-12-11 18:22:47 +000060 return Error::success();
Frederic Risse837ec22014-11-14 16:15:53 +000061}
62
Pavel Labath9b36fd22018-01-22 13:17:23 +000063uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
64uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.NumHashes; }
65uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
66uint32_t AppleAcceleratorTable::getHeaderDataLength() {
Spyridoula Gravanie41823b2017-06-14 00:17:55 +000067 return Hdr.HeaderDataLength;
68}
69
Pavel Labath9b36fd22018-01-22 13:17:23 +000070ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
71 AppleAcceleratorTable::HeaderData::Form>>
72AppleAcceleratorTable::getAtomsDesc() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000073 return HdrData.Atoms;
74}
75
Pavel Labath9b36fd22018-01-22 13:17:23 +000076bool AppleAcceleratorTable::validateForms() {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000077 for (auto Atom : getAtomsDesc()) {
78 DWARFFormValue FormValue(Atom.second);
79 switch (Atom.first) {
80 case dwarf::DW_ATOM_die_offset:
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000081 case dwarf::DW_ATOM_die_tag:
82 case dwarf::DW_ATOM_type_flags:
Spyridoula Gravani837c1102017-06-29 20:13:05 +000083 if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
84 !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
85 FormValue.getForm() == dwarf::DW_FORM_sdata)
86 return false;
Adrian Prantl0e6694d2017-12-19 22:05:25 +000087 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +000088 default:
89 break;
90 }
91 }
92 return true;
93}
94
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000095std::pair<uint32_t, dwarf::Tag>
Pavel Labath9b36fd22018-01-22 13:17:23 +000096AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +000097 uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +000098 dwarf::Tag DieTag = dwarf::DW_TAG_null;
Paul Robinsone5400f82017-11-07 19:57:12 +000099 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000100
101 for (auto Atom : getAtomsDesc()) {
102 DWARFFormValue FormValue(Atom.second);
Paul Robinsone5400f82017-11-07 19:57:12 +0000103 FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000104 switch (Atom.first) {
105 case dwarf::DW_ATOM_die_offset:
106 DieOffset = *FormValue.getAsUnsignedConstant();
107 break;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000108 case dwarf::DW_ATOM_die_tag:
109 DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
110 break;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000111 default:
112 break;
113 }
114 }
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000115 return {DieOffset, DieTag};
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000116}
117
Pavel Labath9b36fd22018-01-22 13:17:23 +0000118LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000119 if (!IsValid)
120 return;
121
Frederic Risse837ec22014-11-14 16:15:53 +0000122 // Dump the header.
123 OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
124 << "Version = " << format("0x%04x", Hdr.Version) << '\n'
125 << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
126 << "Bucket count = " << Hdr.NumBuckets << '\n'
127 << "Hashes count = " << Hdr.NumHashes << '\n'
128 << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
129 << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
130 << "Number of atoms = " << HdrData.Atoms.size() << '\n';
131
132 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000133 SmallVector<DWARFFormValue, 3> AtomForms;
Frederic Risse837ec22014-11-14 16:15:53 +0000134 for (const auto &Atom: HdrData.Atoms) {
135 OS << format("Atom[%d] Type: ", i++);
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000136 auto TypeString = dwarf::AtomTypeString(Atom.first);
137 if (!TypeString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000138 OS << TypeString;
139 else
140 OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
141 OS << " Form: ";
Mehdi Amini149f6ea2016-10-05 05:59:29 +0000142 auto FormString = dwarf::FormEncodingString(Atom.second);
143 if (!FormString.empty())
Frederic Risse837ec22014-11-14 16:15:53 +0000144 OS << FormString;
145 else
Frederic Riss77a07432014-11-20 16:21:11 +0000146 OS << format("DW_FORM_Unknown_0x%x", Atom.second);
Frederic Risse837ec22014-11-14 16:15:53 +0000147 OS << '\n';
Frederic Riss77a07432014-11-20 16:21:11 +0000148 AtomForms.push_back(DWARFFormValue(Atom.second));
Frederic Risse837ec22014-11-14 16:15:53 +0000149 }
150
151 // Now go through the actual tables and dump them.
152 uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
153 unsigned HashesBase = Offset + Hdr.NumBuckets * 4;
154 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
Paul Robinsone5400f82017-11-07 19:57:12 +0000155 DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
Frederic Risse837ec22014-11-14 16:15:53 +0000156
157 for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
158 unsigned Index = AccelSection.getU32(&Offset);
159
160 OS << format("Bucket[%d]\n", Bucket);
161 if (Index == UINT32_MAX) {
162 OS << " EMPTY\n";
163 continue;
164 }
165
166 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
167 unsigned HashOffset = HashesBase + HashIdx*4;
168 unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
169 uint32_t Hash = AccelSection.getU32(&HashOffset);
170
171 if (Hash % Hdr.NumBuckets != Bucket)
172 break;
173
174 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
175 OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
176 if (!AccelSection.isValidOffset(DataOffset)) {
177 OS << " Invalid section offset\n";
178 continue;
179 }
Frederic Riss7c500472014-11-14 19:30:08 +0000180 while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
Paul Robinson17536b92017-06-29 16:52:08 +0000181 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
Frederic Riss7c500472014-11-14 19:30:08 +0000182 if (!StringOffset)
183 break;
Frederic Risse837ec22014-11-14 16:15:53 +0000184 OS << format(" Name: %08x \"%s\"\n", StringOffset,
185 StringSection.getCStr(&StringOffset));
186 unsigned NumData = AccelSection.getU32(&DataOffset);
187 for (unsigned Data = 0; Data < NumData; ++Data) {
188 OS << format(" Data[%d] => ", Data);
189 unsigned i = 0;
Frederic Riss77a07432014-11-20 16:21:11 +0000190 for (auto &Atom : AtomForms) {
Frederic Risse837ec22014-11-14 16:15:53 +0000191 OS << format("{Atom[%d]: ", i++);
Paul Robinsone5400f82017-11-07 19:57:12 +0000192 if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
Greg Claytoncddab272016-10-31 16:46:02 +0000193 Atom.dump(OS);
Frederic Risse837ec22014-11-14 16:15:53 +0000194 else
195 OS << "Error extracting the value";
196 OS << "} ";
197 }
198 OS << '\n';
199 }
200 }
201 }
202 }
203}
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000204
Pavel Labath9b36fd22018-01-22 13:17:23 +0000205AppleAcceleratorTable::ValueIterator::ValueIterator(
206 const AppleAcceleratorTable &AccelTable, unsigned Offset)
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000207 : AccelTable(&AccelTable), DataOffset(Offset) {
208 if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
209 return;
210
211 for (const auto &Atom : AccelTable.HdrData.Atoms)
212 AtomForms.push_back(DWARFFormValue(Atom.second));
213
214 // Read the first entry.
215 NumData = AccelTable.AccelSection.getU32(&DataOffset);
216 Next();
217}
218
Pavel Labath9b36fd22018-01-22 13:17:23 +0000219void AppleAcceleratorTable::ValueIterator::Next() {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000220 assert(NumData > 0 && "attempted to increment iterator past the end");
221 auto &AccelSection = AccelTable->AccelSection;
222 if (Data >= NumData ||
223 !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
224 NumData = 0;
225 return;
226 }
Paul Robinsone5400f82017-11-07 19:57:12 +0000227 DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
228 dwarf::DwarfFormat::DWARF32};
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000229 for (auto &Atom : AtomForms)
Paul Robinsone5400f82017-11-07 19:57:12 +0000230 Atom.extractValue(AccelSection, &DataOffset, FormParams);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000231 ++Data;
232}
233
Pavel Labath9b36fd22018-01-22 13:17:23 +0000234iterator_range<AppleAcceleratorTable::ValueIterator>
235AppleAcceleratorTable::equal_range(StringRef Key) const {
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000236 if (!IsValid)
237 return make_range(ValueIterator(), ValueIterator());
238
239 // Find the bucket.
Jonas Devlieghere92ac9d32018-01-28 11:05:10 +0000240 unsigned HashValue = djbHash(Key);
Adrian Prantl99fdb9d2017-09-28 18:10:52 +0000241 unsigned Bucket = HashValue % Hdr.NumBuckets;
242 unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
243 unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
244 unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
245
246 unsigned BucketOffset = BucketBase + Bucket * 4;
247 unsigned Index = AccelSection.getU32(&BucketOffset);
248
249 // Search through all hashes in the bucket.
250 for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
251 unsigned HashOffset = HashesBase + HashIdx * 4;
252 unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
253 uint32_t Hash = AccelSection.getU32(&HashOffset);
254
255 if (Hash % Hdr.NumBuckets != Bucket)
256 // We are already in the next bucket.
257 break;
258
259 unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
260 unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
261 if (!StringOffset)
262 break;
263
264 // Finally, compare the key.
265 if (Key == StringSection.getCStr(&StringOffset))
266 return make_range({*this, DataOffset}, ValueIterator());
267 }
268 return make_range(ValueIterator(), ValueIterator());
269}