287 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "bolt/Core/GDBIndex.h"10 11using namespace llvm::bolt;12using namespace llvm::support::endian;13 14void 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 21void GDBIndex::updateGdbIndexSection(22 const CUOffsetMap &CUMap, const uint32_t NumCUs,23 DebugARangesSectionWriter &ARangesSectionWriter) {24 if (!BC.getGdbIndexSection())25 return;26 // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html27 // for .gdb_index section format.28 29 StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents();30 31 const char *Data = GdbIndexContents.data();32 33 // Parse the header.34 const uint32_t Version = read32le(Data);35 if (Version != 7 && Version != 8) {36 errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n";37 exit(1);38 }39 40 // Some .gdb_index generators use file offsets while others use section41 // offsets. Hence we can only rely on offsets relative to each other,42 // and ignore their absolute values.43 const uint32_t CUListOffset = read32le(Data + 4);44 const uint32_t CUTypesOffset = read32le(Data + 8);45 const uint32_t AddressTableOffset = read32le(Data + 12);46 const uint32_t SymbolTableOffset = read32le(Data + 16);47 const uint32_t ConstantPoolOffset = read32le(Data + 20);48 Data += 24;49 50 // Map CUs offsets to indices and verify existing index table.51 std::map<uint32_t, uint32_t> OffsetToIndexMap;52 const uint32_t CUListSize = CUTypesOffset - CUListOffset;53 const uint32_t TUListSize = AddressTableOffset - CUTypesOffset;54 const unsigned NUmCUsEncoded = CUListSize / 16;55 unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion();56 unsigned NumDWARF5TUs =57 getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits();58 bool SkipTypeUnits = false;59 // For DWARF5 Types are in .debug_info.60 // LLD doesn't generate Types CU List, and in CU list offset61 // only includes CUs.62 // GDB 11+ includes only CUs in CU list and generates Types63 // list.64 // GDB 9 includes CUs and TUs in CU list and generates TYpes65 // list. The NumCUs is CUs + TUs, so need to modify the check.66 // For split-dwarf67 // GDB-11, DWARF5: TU units from dwo are not included.68 // GDB-11, DWARF4: TU units from dwo are included.69 if (MaxDWARFVersion >= 5)70 SkipTypeUnits = !TUListSize ? true71 : ((NUmCUsEncoded + NumDWARF5TUs) ==72 BC.DwCtx->getNumCompileUnits());73 74 if (!((CUListSize == NumCUs * 16) ||75 (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) {76 errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n";77 exit(1);78 }79 DenseSet<uint64_t> OriginalOffsets;80 for (unsigned Index = 0, PresentUnitsIndex = 0,81 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] = PresentUnitsIndex++;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 const auto IsValidAddressRange = [](const DebugAddressRange &Range) {104 return Range.HighPC > Range.LowPC;105 };106 107 uint32_t NewAddressTableSize = 0;108 for (const auto &CURangesPair : ARangesSectionWriter.getCUAddressRanges()) {109 const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second;110 NewAddressTableSize +=111 llvm::count_if(Ranges,112 [&IsValidAddressRange](const DebugAddressRange &Range) {113 return IsValidAddressRange(Range);114 }) *115 20;116 }117 118 // Difference between old and new table (and section) sizes.119 // Could be negative.120 int32_t Delta = NewAddressTableSize - OldAddressTableSize;121 122 size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;123 124 // Free'd by ExecutableFileMemoryManager.125 auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize];126 uint8_t *Buffer = NewGdbIndexContents;127 128 write32le(Buffer, Version);129 write32le(Buffer + 4, CUListOffset);130 write32le(Buffer + 8, CUTypesOffset);131 write32le(Buffer + 12, AddressTableOffset);132 write32le(Buffer + 16, SymbolTableOffset + Delta);133 write32le(Buffer + 20, ConstantPoolOffset + Delta);134 Buffer += 24;135 136 using MapEntry = std::pair<uint32_t, CUInfo>;137 std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end());138 // Remove the CUs we won't emit anyway.139 CUVector.erase(std::remove_if(CUVector.begin(), CUVector.end(),140 [&OriginalOffsets](const MapEntry &It) {141 // Skipping TU for DWARF5 when they are not142 // included in CU list.143 return OriginalOffsets.count(It.first) == 0;144 }),145 CUVector.end());146 // Need to sort since we write out all of TUs in .debug_info before CUs.147 std::sort(CUVector.begin(), CUVector.end(),148 [](const MapEntry &E1, const MapEntry &E2) -> bool {149 return E1.second.Offset < E2.second.Offset;150 });151 // Create the original CU index -> updated CU index mapping,152 // as the sort above could've changed the order and we have to update153 // indices correspondingly in address map and constant pool.154 std::unordered_map<uint32_t, uint32_t> OriginalCUIndexToUpdatedCUIndexMap;155 OriginalCUIndexToUpdatedCUIndexMap.reserve(CUVector.size());156 for (uint32_t I = 0; I < CUVector.size(); ++I) {157 OriginalCUIndexToUpdatedCUIndexMap[OffsetToIndexMap.at(CUVector[I].first)] =158 I;159 }160 const auto RemapCUIndex = [&OriginalCUIndexToUpdatedCUIndexMap,161 CUVectorSize = CUVector.size(),162 TUVectorSize = getGDBIndexTUEntryVector().size()](163 uint32_t OriginalIndex) {164 if (OriginalIndex >= CUVectorSize) {165 if (OriginalIndex >= CUVectorSize + TUVectorSize) {166 errs() << "BOLT-ERROR: .gdb_index unknown CU index\n";167 exit(1);168 }169 // The index is into TU CU List, which we don't reorder, so return as is.170 return OriginalIndex;171 }172 173 const auto It = OriginalCUIndexToUpdatedCUIndexMap.find(OriginalIndex);174 if (It == OriginalCUIndexToUpdatedCUIndexMap.end()) {175 errs() << "BOLT-ERROR: .gdb_index unknown CU index\n";176 exit(1);177 }178 179 return It->second;180 };181 182 // Writing out CU List <Offset, Size>183 for (auto &CUInfo : CUVector) {184 write64le(Buffer, CUInfo.second.Offset);185 // Length encoded in CU doesn't contain first 4 bytes that encode length.186 write64le(Buffer + 8, CUInfo.second.Length + 4);187 Buffer += 16;188 }189 sortGDBIndexTUEntryVector();190 // Rewrite TU CU List, since abbrevs can be different.191 // Entry example:192 // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature =193 // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset,194 // the second value is the type offset in the CU, and the third value is the195 // type signature" Looking at what is being generated by gdb-add-index. The196 // first entry is TU offset, second entry is offset from it, and third entry197 // is the type signature.198 if (TUListSize)199 for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) {200 write64le(Buffer, Entry.UnitOffset);201 write64le(Buffer + 8, Entry.TypeDIERelativeOffset);202 write64le(Buffer + 16, Entry.TypeHash);203 Buffer += sizeof(GDBIndexTUEntry);204 }205 206 // Generate new address table.207 for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair :208 ARangesSectionWriter.getCUAddressRanges()) {209 const uint32_t OriginalCUIndex = OffsetToIndexMap[CURangesPair.first];210 const uint32_t UpdatedCUIndex = RemapCUIndex(OriginalCUIndex);211 const DebugAddressRangesVector &Ranges = CURangesPair.second;212 for (const DebugAddressRange &Range : Ranges) {213 // Don't emit ranges that break gdb,214 // https://sourceware.org/bugzilla/show_bug.cgi?id=33247.215 // We've seen [0, 0) ranges here, for instance.216 if (IsValidAddressRange(Range)) {217 write64le(Buffer, Range.LowPC);218 write64le(Buffer + 8, Range.HighPC);219 write32le(Buffer + 16, UpdatedCUIndex);220 Buffer += 20;221 }222 }223 }224 225 const size_t TrailingSize =226 GdbIndexContents.data() + GdbIndexContents.size() - Data;227 assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize &&228 "size calculation error");229 230 // Copy over the rest of the original data.231 memcpy(Buffer, Data, TrailingSize);232 233 // Fixup CU-indices in constant pool.234 const char *const OriginalConstantPoolData =235 GdbIndexContents.data() + ConstantPoolOffset;236 uint8_t *const UpdatedConstantPoolData =237 NewGdbIndexContents + ConstantPoolOffset + Delta;238 239 const char *OriginalSymbolTableData =240 GdbIndexContents.data() + SymbolTableOffset;241 std::set<uint32_t> CUVectorOffsets;242 // Parse the symbol map and extract constant pool CU offsets from it.243 while (OriginalSymbolTableData < OriginalConstantPoolData) {244 const uint32_t NameOffset = read32le(OriginalSymbolTableData);245 const uint32_t CUVectorOffset = read32le(OriginalSymbolTableData + 4);246 OriginalSymbolTableData += 8;247 248 // Iff both are zero, then the slot is considered empty in the hash-map.249 if (NameOffset || CUVectorOffset) {250 CUVectorOffsets.insert(CUVectorOffset);251 }252 }253 254 // Update the CU-indicies in the constant pool255 for (const auto CUVectorOffset : CUVectorOffsets) {256 const char *CurrentOriginalConstantPoolData =257 OriginalConstantPoolData + CUVectorOffset;258 uint8_t *CurrentUpdatedConstantPoolData =259 UpdatedConstantPoolData + CUVectorOffset;260 261 const uint32_t Num = read32le(CurrentOriginalConstantPoolData);262 CurrentOriginalConstantPoolData += 4;263 CurrentUpdatedConstantPoolData += 4;264 265 for (uint32_t J = 0; J < Num; ++J) {266 const uint32_t OriginalCUIndexAndAttributes =267 read32le(CurrentOriginalConstantPoolData);268 CurrentOriginalConstantPoolData += 4;269 270 // We only care for the index, which is the lowest 24 bits, other bits are271 // left as is.272 const uint32_t OriginalCUIndex =273 OriginalCUIndexAndAttributes & ((1 << 24) - 1);274 const uint32_t Attributes = OriginalCUIndexAndAttributes >> 24;275 const uint32_t UpdatedCUIndexAndAttributes =276 RemapCUIndex(OriginalCUIndex) | (Attributes << 24);277 278 write32le(CurrentUpdatedConstantPoolData, UpdatedCUIndexAndAttributes);279 CurrentUpdatedConstantPoolData += 4;280 }281 }282 283 // Register the new section.284 BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents,285 NewGdbIndexSize);286}287