|
| 1 | +//===- bolt/Core/GDBIndex.cpp - GDB Index support ------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#include "bolt/Core/GDBIndex.h" |
| 10 | + |
| 11 | +using namespace llvm::bolt; |
| 12 | +using namespace llvm::support::endian; |
| 13 | + |
| 14 | +void GDBIndex::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) { |
| 15 | + std::lock_guard<std::mutex> Lock(GDBIndexMutex); |
| 16 | + if (!BC.getGdbIndexSection()) |
| 17 | + return; |
| 18 | + GDBIndexTUEntryVector.emplace_back(Entry); |
| 19 | +} |
| 20 | + |
| 21 | +void GDBIndex::updateGdbIndexSection( |
| 22 | + const CUOffsetMap &CUMap, const uint32_t NumCUs, |
| 23 | + DebugARangesSectionWriter &ARangesSectionWriter) { |
| 24 | + if (!BC.getGdbIndexSection()) |
| 25 | + return; |
| 26 | + |
| 27 | + // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html |
| 28 | + // for .gdb_index section format. |
| 29 | + |
| 30 | + StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents(); |
| 31 | + |
| 32 | + const char *Data = GdbIndexContents.data(); |
| 33 | + |
| 34 | + // Parse the header. |
| 35 | + const uint32_t Version = read32le(Data); |
| 36 | + if (Version != 7 && Version != 8) { |
| 37 | + errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n"; |
| 38 | + exit(1); |
| 39 | + } |
| 40 | + |
| 41 | + // Some .gdb_index generators use file offsets while others use section |
| 42 | + // offsets. Hence we can only rely on offsets relative to each other, |
| 43 | + // and ignore their absolute values. |
| 44 | + const uint32_t CUListOffset = read32le(Data + 4); |
| 45 | + const uint32_t CUTypesOffset = read32le(Data + 8); |
| 46 | + const uint32_t AddressTableOffset = read32le(Data + 12); |
| 47 | + const uint32_t SymbolTableOffset = read32le(Data + 16); |
| 48 | + const uint32_t ConstantPoolOffset = read32le(Data + 20); |
| 49 | + Data += 24; |
| 50 | + |
| 51 | + // Map CUs offsets to indices and verify existing index table. |
| 52 | + std::map<uint32_t, uint32_t> OffsetToIndexMap; |
| 53 | + const uint32_t CUListSize = CUTypesOffset - CUListOffset; |
| 54 | + const uint32_t TUListSize = AddressTableOffset - CUTypesOffset; |
| 55 | + const unsigned NUmCUsEncoded = CUListSize / 16; |
| 56 | + unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion(); |
| 57 | + unsigned NumDWARF5TUs = |
| 58 | + getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits(); |
| 59 | + bool SkipTypeUnits = false; |
| 60 | + // For DWARF5 Types are in .debug_info. |
| 61 | + // LLD doesn't generate Types CU List, and in CU list offset |
| 62 | + // only includes CUs. |
| 63 | + // GDB 11+ includes only CUs in CU list and generates Types |
| 64 | + // list. |
| 65 | + // GDB 9 includes CUs and TUs in CU list and generates TYpes |
| 66 | + // list. The NumCUs is CUs + TUs, so need to modify the check. |
| 67 | + // For split-dwarf |
| 68 | + // GDB-11, DWARF5: TU units from dwo are not included. |
| 69 | + // GDB-11, DWARF4: TU units from dwo are included. |
| 70 | + if (MaxDWARFVersion >= 5) |
| 71 | + SkipTypeUnits = !TUListSize ? true |
| 72 | + : ((NUmCUsEncoded + NumDWARF5TUs) == |
| 73 | + BC.DwCtx->getNumCompileUnits()); |
| 74 | + |
| 75 | + if (!((CUListSize == NumCUs * 16) || |
| 76 | + (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) { |
| 77 | + errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n"; |
| 78 | + exit(1); |
| 79 | + } |
| 80 | + DenseSet<uint64_t> OriginalOffsets; |
| 81 | + for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits(); |
| 82 | + Index < Units; ++Index) { |
| 83 | + const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index); |
| 84 | + if (SkipTypeUnits && CU->isTypeUnit()) |
| 85 | + continue; |
| 86 | + const uint64_t Offset = read64le(Data); |
| 87 | + Data += 16; |
| 88 | + if (CU->getOffset() != Offset) { |
| 89 | + errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n"; |
| 90 | + exit(1); |
| 91 | + } |
| 92 | + |
| 93 | + OriginalOffsets.insert(Offset); |
| 94 | + OffsetToIndexMap[Offset] = Index; |
| 95 | + } |
| 96 | + |
| 97 | + // Ignore old address table. |
| 98 | + const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset; |
| 99 | + // Move Data to the beginning of symbol table. |
| 100 | + Data += SymbolTableOffset - CUTypesOffset; |
| 101 | + |
| 102 | + // Calculate the size of the new address table. |
| 103 | + uint32_t NewAddressTableSize = 0; |
| 104 | + for (const auto &CURangesPair : ARangesSectionWriter.getCUAddressRanges()) { |
| 105 | + const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second; |
| 106 | + NewAddressTableSize += Ranges.size() * 20; |
| 107 | + } |
| 108 | + |
| 109 | + // Difference between old and new table (and section) sizes. |
| 110 | + // Could be negative. |
| 111 | + int32_t Delta = NewAddressTableSize - OldAddressTableSize; |
| 112 | + |
| 113 | + size_t NewGdbIndexSize = GdbIndexContents.size() + Delta; |
| 114 | + |
| 115 | + // Free'd by ExecutableFileMemoryManager. |
| 116 | + auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize]; |
| 117 | + uint8_t *Buffer = NewGdbIndexContents; |
| 118 | + |
| 119 | + write32le(Buffer, Version); |
| 120 | + write32le(Buffer + 4, CUListOffset); |
| 121 | + write32le(Buffer + 8, CUTypesOffset); |
| 122 | + write32le(Buffer + 12, AddressTableOffset); |
| 123 | + write32le(Buffer + 16, SymbolTableOffset + Delta); |
| 124 | + write32le(Buffer + 20, ConstantPoolOffset + Delta); |
| 125 | + Buffer += 24; |
| 126 | + |
| 127 | + using MapEntry = std::pair<uint32_t, CUInfo>; |
| 128 | + std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end()); |
| 129 | + // Need to sort since we write out all of TUs in .debug_info before CUs. |
| 130 | + std::sort(CUVector.begin(), CUVector.end(), |
| 131 | + [](const MapEntry &E1, const MapEntry &E2) -> bool { |
| 132 | + return E1.second.Offset < E2.second.Offset; |
| 133 | + }); |
| 134 | + // Writing out CU List <Offset, Size> |
| 135 | + for (auto &CUInfo : CUVector) { |
| 136 | + // Skipping TU for DWARF5 when they are not included in CU list. |
| 137 | + if (!OriginalOffsets.count(CUInfo.first)) |
| 138 | + continue; |
| 139 | + write64le(Buffer, CUInfo.second.Offset); |
| 140 | + // Length encoded in CU doesn't contain first 4 bytes that encode length. |
| 141 | + write64le(Buffer + 8, CUInfo.second.Length + 4); |
| 142 | + Buffer += 16; |
| 143 | + } |
| 144 | + |
| 145 | + // Rewrite TU CU List, since abbrevs can be different. |
| 146 | + // Entry example: |
| 147 | + // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = |
| 148 | + // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset, |
| 149 | + // the second value is the type offset in the CU, and the third value is the |
| 150 | + // type signature" Looking at what is being generated by gdb-add-index. The |
| 151 | + // first entry is TU offset, second entry is offset from it, and third entry |
| 152 | + // is the type signature. |
| 153 | + if (TUListSize) |
| 154 | + for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) { |
| 155 | + write64le(Buffer, Entry.UnitOffset); |
| 156 | + write64le(Buffer + 8, Entry.TypeDIERelativeOffset); |
| 157 | + write64le(Buffer + 16, Entry.TypeHash); |
| 158 | + Buffer += sizeof(GDBIndexTUEntry); |
| 159 | + } |
| 160 | + |
| 161 | + // Generate new address table. |
| 162 | + for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair : |
| 163 | + ARangesSectionWriter.getCUAddressRanges()) { |
| 164 | + const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first]; |
| 165 | + const DebugAddressRangesVector &Ranges = CURangesPair.second; |
| 166 | + for (const DebugAddressRange &Range : Ranges) { |
| 167 | + write64le(Buffer, Range.LowPC); |
| 168 | + write64le(Buffer + 8, Range.HighPC); |
| 169 | + write32le(Buffer + 16, CUIndex); |
| 170 | + Buffer += 20; |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + const size_t TrailingSize = |
| 175 | + GdbIndexContents.data() + GdbIndexContents.size() - Data; |
| 176 | + assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize && |
| 177 | + "size calculation error"); |
| 178 | + |
| 179 | + // Copy over the rest of the original data. |
| 180 | + memcpy(Buffer, Data, TrailingSize); |
| 181 | + |
| 182 | + // Register the new section. |
| 183 | + BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents, |
| 184 | + NewGdbIndexSize); |
| 185 | +} |
0 commit comments