Eugene Zelenko | e94042c | 2017-02-27 23:43:14 +0000 | [diff] [blame] | 1 | //===- DWARFAcceleratorTable.cpp ------------------------------------------===// |
Frederic Riss | 7c41c64 | 2014-11-20 16:21:06 +0000 | [diff] [blame] | 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 | |
Zachary Turner | 82af943 | 2015-01-30 18:07:45 +0000 | [diff] [blame] | 10 | #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" |
Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 +0000 | [diff] [blame] | 11 | |
Chandler Carruth | 6bda14b | 2017-06-06 11:49:48 +0000 | [diff] [blame] | 12 | #include "llvm/ADT/SmallVector.h" |
Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 +0000 | [diff] [blame] | 13 | #include "llvm/BinaryFormat/Dwarf.h" |
Eugene Zelenko | e94042c | 2017-02-27 23:43:14 +0000 | [diff] [blame] | 14 | #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" |
Eugene Zelenko | e94042c | 2017-02-27 23:43:14 +0000 | [diff] [blame] | 15 | #include "llvm/Support/Compiler.h" |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 16 | #include "llvm/Support/Format.h" |
| 17 | #include "llvm/Support/raw_ostream.h" |
Eugene Zelenko | e94042c | 2017-02-27 23:43:14 +0000 | [diff] [blame] | 18 | #include <cstddef> |
| 19 | #include <cstdint> |
| 20 | #include <utility> |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 21 | |
Eugene Zelenko | e94042c | 2017-02-27 23:43:14 +0000 | [diff] [blame] | 22 | using namespace llvm; |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 23 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 24 | llvm::Error AppleAcceleratorTable::extract() { |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 25 | uint32_t Offset = 0; |
| 26 | |
| 27 | // Check that we can at least read the header. |
| 28 | if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4)) |
Jonas Devlieghere | ba91589 | 2017-12-11 18:22:47 +0000 | [diff] [blame] | 29 | return make_error<StringError>("Section too small: cannot read header.", |
| 30 | inconvertibleErrorCode()); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 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). |
Jonas Devlieghere | ba91589 | 2017-12-11 18:22:47 +0000 | [diff] [blame] | 41 | // 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 Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 43 | if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + |
Jonas Devlieghere | ba91589 | 2017-12-11 18:22:47 +0000 | [diff] [blame] | 44 | Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1)) |
| 45 | return make_error<StringError>( |
| 46 | "Section too small: cannot read buckets and hashes.", |
| 47 | inconvertibleErrorCode()); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 48 | |
| 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 Clayton | 6c27376 | 2016-10-27 16:32:04 +0000 | [diff] [blame] | 54 | auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 55 | HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); |
| 56 | } |
| 57 | |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 58 | IsValid = true; |
Jonas Devlieghere | ba91589 | 2017-12-11 18:22:47 +0000 | [diff] [blame] | 59 | return Error::success(); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 60 | } |
| 61 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 62 | uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; } |
| 63 | uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.NumHashes; } |
| 64 | uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } |
| 65 | uint32_t AppleAcceleratorTable::getHeaderDataLength() { |
Spyridoula Gravani | e41823b | 2017-06-14 00:17:55 +0000 | [diff] [blame] | 66 | return Hdr.HeaderDataLength; |
| 67 | } |
| 68 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 69 | ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType, |
| 70 | AppleAcceleratorTable::HeaderData::Form>> |
| 71 | AppleAcceleratorTable::getAtomsDesc() { |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 72 | return HdrData.Atoms; |
| 73 | } |
| 74 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 75 | bool AppleAcceleratorTable::validateForms() { |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 76 | for (auto Atom : getAtomsDesc()) { |
| 77 | DWARFFormValue FormValue(Atom.second); |
| 78 | switch (Atom.first) { |
| 79 | case dwarf::DW_ATOM_die_offset: |
Spyridoula Gravani | 70d35e1 | 2017-07-31 18:01:16 +0000 | [diff] [blame] | 80 | case dwarf::DW_ATOM_die_tag: |
| 81 | case dwarf::DW_ATOM_type_flags: |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 82 | if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && |
| 83 | !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || |
| 84 | FormValue.getForm() == dwarf::DW_FORM_sdata) |
| 85 | return false; |
Adrian Prantl | 0e6694d | 2017-12-19 22:05:25 +0000 | [diff] [blame] | 86 | break; |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 87 | default: |
| 88 | break; |
| 89 | } |
| 90 | } |
| 91 | return true; |
| 92 | } |
| 93 | |
Spyridoula Gravani | 70d35e1 | 2017-07-31 18:01:16 +0000 | [diff] [blame] | 94 | std::pair<uint32_t, dwarf::Tag> |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 95 | AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 96 | uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; |
Spyridoula Gravani | 70d35e1 | 2017-07-31 18:01:16 +0000 | [diff] [blame] | 97 | dwarf::Tag DieTag = dwarf::DW_TAG_null; |
Paul Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 98 | DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 99 | |
| 100 | for (auto Atom : getAtomsDesc()) { |
| 101 | DWARFFormValue FormValue(Atom.second); |
Paul Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 102 | FormValue.extractValue(AccelSection, &HashDataOffset, FormParams); |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 103 | switch (Atom.first) { |
| 104 | case dwarf::DW_ATOM_die_offset: |
| 105 | DieOffset = *FormValue.getAsUnsignedConstant(); |
| 106 | break; |
Spyridoula Gravani | 70d35e1 | 2017-07-31 18:01:16 +0000 | [diff] [blame] | 107 | case dwarf::DW_ATOM_die_tag: |
| 108 | DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); |
| 109 | break; |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 110 | default: |
| 111 | break; |
| 112 | } |
| 113 | } |
Spyridoula Gravani | 70d35e1 | 2017-07-31 18:01:16 +0000 | [diff] [blame] | 114 | return {DieOffset, DieTag}; |
Spyridoula Gravani | 837c110 | 2017-06-29 20:13:05 +0000 | [diff] [blame] | 115 | } |
| 116 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 117 | LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 118 | if (!IsValid) |
| 119 | return; |
| 120 | |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 121 | // 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 Riss | 77a0743 | 2014-11-20 16:21:11 +0000 | [diff] [blame] | 132 | SmallVector<DWARFFormValue, 3> AtomForms; |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 133 | for (const auto &Atom: HdrData.Atoms) { |
| 134 | OS << format("Atom[%d] Type: ", i++); |
Mehdi Amini | 149f6ea | 2016-10-05 05:59:29 +0000 | [diff] [blame] | 135 | auto TypeString = dwarf::AtomTypeString(Atom.first); |
| 136 | if (!TypeString.empty()) |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 137 | OS << TypeString; |
| 138 | else |
| 139 | OS << format("DW_ATOM_Unknown_0x%x", Atom.first); |
| 140 | OS << " Form: "; |
Mehdi Amini | 149f6ea | 2016-10-05 05:59:29 +0000 | [diff] [blame] | 141 | auto FormString = dwarf::FormEncodingString(Atom.second); |
| 142 | if (!FormString.empty()) |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 143 | OS << FormString; |
| 144 | else |
Frederic Riss | 77a0743 | 2014-11-20 16:21:11 +0000 | [diff] [blame] | 145 | OS << format("DW_FORM_Unknown_0x%x", Atom.second); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 146 | OS << '\n'; |
Frederic Riss | 77a0743 | 2014-11-20 16:21:11 +0000 | [diff] [blame] | 147 | AtomForms.push_back(DWARFFormValue(Atom.second)); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 148 | } |
| 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 Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 154 | DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 155 | |
| 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 Riss | 7c50047 | 2014-11-14 19:30:08 +0000 | [diff] [blame] | 179 | while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { |
Paul Robinson | 17536b9 | 2017-06-29 16:52:08 +0000 | [diff] [blame] | 180 | unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); |
Frederic Riss | 7c50047 | 2014-11-14 19:30:08 +0000 | [diff] [blame] | 181 | if (!StringOffset) |
| 182 | break; |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 183 | 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 Riss | 77a0743 | 2014-11-20 16:21:11 +0000 | [diff] [blame] | 189 | for (auto &Atom : AtomForms) { |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 190 | OS << format("{Atom[%d]: ", i++); |
Paul Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 191 | if (Atom.extractValue(AccelSection, &DataOffset, FormParams)) |
Greg Clayton | cddab27 | 2016-10-31 16:46:02 +0000 | [diff] [blame] | 192 | Atom.dump(OS); |
Frederic Riss | e837ec2 | 2014-11-14 16:15:53 +0000 | [diff] [blame] | 193 | else |
| 194 | OS << "Error extracting the value"; |
| 195 | OS << "} "; |
| 196 | } |
| 197 | OS << '\n'; |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | } |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 203 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 204 | AppleAcceleratorTable::ValueIterator::ValueIterator( |
| 205 | const AppleAcceleratorTable &AccelTable, unsigned Offset) |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 206 | : 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 Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 218 | void AppleAcceleratorTable::ValueIterator::Next() { |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 219 | 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 Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 226 | DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0, |
| 227 | dwarf::DwarfFormat::DWARF32}; |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 228 | for (auto &Atom : AtomForms) |
Paul Robinson | e5400f8 | 2017-11-07 19:57:12 +0000 | [diff] [blame] | 229 | Atom.extractValue(AccelSection, &DataOffset, FormParams); |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 230 | ++Data; |
| 231 | } |
| 232 | |
Pavel Labath | 9b36fd2 | 2018-01-22 13:17:23 +0000 | [diff] [blame] | 233 | iterator_range<AppleAcceleratorTable::ValueIterator> |
| 234 | AppleAcceleratorTable::equal_range(StringRef Key) const { |
Adrian Prantl | 99fdb9d | 2017-09-28 18:10:52 +0000 | [diff] [blame] | 235 | 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 | } |