12a6efe6aSSayhaan Siddiqui //===- bolt/Core/GDBIndex.cpp - GDB Index support ------------------------===// 22a6efe6aSSayhaan Siddiqui // 32a6efe6aSSayhaan Siddiqui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42a6efe6aSSayhaan Siddiqui // See https://llvm.org/LICENSE.txt for license information. 52a6efe6aSSayhaan Siddiqui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62a6efe6aSSayhaan Siddiqui // 72a6efe6aSSayhaan Siddiqui //===----------------------------------------------------------------------===// 82a6efe6aSSayhaan Siddiqui 92a6efe6aSSayhaan Siddiqui #include "bolt/Core/GDBIndex.h" 102a6efe6aSSayhaan Siddiqui 112a6efe6aSSayhaan Siddiqui using namespace llvm::bolt; 122a6efe6aSSayhaan Siddiqui using namespace llvm::support::endian; 132a6efe6aSSayhaan Siddiqui 142a6efe6aSSayhaan Siddiqui void GDBIndex::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) { 152a6efe6aSSayhaan Siddiqui std::lock_guard<std::mutex> Lock(GDBIndexMutex); 162a6efe6aSSayhaan Siddiqui if (!BC.getGdbIndexSection()) 172a6efe6aSSayhaan Siddiqui return; 182a6efe6aSSayhaan Siddiqui GDBIndexTUEntryVector.emplace_back(Entry); 192a6efe6aSSayhaan Siddiqui } 202a6efe6aSSayhaan Siddiqui 212a6efe6aSSayhaan Siddiqui void GDBIndex::updateGdbIndexSection( 222a6efe6aSSayhaan Siddiqui const CUOffsetMap &CUMap, const uint32_t NumCUs, 232a6efe6aSSayhaan Siddiqui DebugARangesSectionWriter &ARangesSectionWriter) { 242a6efe6aSSayhaan Siddiqui if (!BC.getGdbIndexSection()) 252a6efe6aSSayhaan Siddiqui return; 262a6efe6aSSayhaan Siddiqui // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html 272a6efe6aSSayhaan Siddiqui // for .gdb_index section format. 282a6efe6aSSayhaan Siddiqui 292a6efe6aSSayhaan Siddiqui StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents(); 302a6efe6aSSayhaan Siddiqui 312a6efe6aSSayhaan Siddiqui const char *Data = GdbIndexContents.data(); 322a6efe6aSSayhaan Siddiqui 332a6efe6aSSayhaan Siddiqui // Parse the header. 342a6efe6aSSayhaan Siddiqui const uint32_t Version = read32le(Data); 352a6efe6aSSayhaan Siddiqui if (Version != 7 && Version != 8) { 362a6efe6aSSayhaan Siddiqui errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n"; 372a6efe6aSSayhaan Siddiqui exit(1); 382a6efe6aSSayhaan Siddiqui } 392a6efe6aSSayhaan Siddiqui 402a6efe6aSSayhaan Siddiqui // Some .gdb_index generators use file offsets while others use section 412a6efe6aSSayhaan Siddiqui // offsets. Hence we can only rely on offsets relative to each other, 422a6efe6aSSayhaan Siddiqui // and ignore their absolute values. 432a6efe6aSSayhaan Siddiqui const uint32_t CUListOffset = read32le(Data + 4); 442a6efe6aSSayhaan Siddiqui const uint32_t CUTypesOffset = read32le(Data + 8); 452a6efe6aSSayhaan Siddiqui const uint32_t AddressTableOffset = read32le(Data + 12); 462a6efe6aSSayhaan Siddiqui const uint32_t SymbolTableOffset = read32le(Data + 16); 472a6efe6aSSayhaan Siddiqui const uint32_t ConstantPoolOffset = read32le(Data + 20); 482a6efe6aSSayhaan Siddiqui Data += 24; 492a6efe6aSSayhaan Siddiqui 502a6efe6aSSayhaan Siddiqui // Map CUs offsets to indices and verify existing index table. 512a6efe6aSSayhaan Siddiqui std::map<uint32_t, uint32_t> OffsetToIndexMap; 522a6efe6aSSayhaan Siddiqui const uint32_t CUListSize = CUTypesOffset - CUListOffset; 532a6efe6aSSayhaan Siddiqui const uint32_t TUListSize = AddressTableOffset - CUTypesOffset; 542a6efe6aSSayhaan Siddiqui const unsigned NUmCUsEncoded = CUListSize / 16; 552a6efe6aSSayhaan Siddiqui unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion(); 562a6efe6aSSayhaan Siddiqui unsigned NumDWARF5TUs = 572a6efe6aSSayhaan Siddiqui getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits(); 582a6efe6aSSayhaan Siddiqui bool SkipTypeUnits = false; 592a6efe6aSSayhaan Siddiqui // For DWARF5 Types are in .debug_info. 602a6efe6aSSayhaan Siddiqui // LLD doesn't generate Types CU List, and in CU list offset 612a6efe6aSSayhaan Siddiqui // only includes CUs. 622a6efe6aSSayhaan Siddiqui // GDB 11+ includes only CUs in CU list and generates Types 632a6efe6aSSayhaan Siddiqui // list. 642a6efe6aSSayhaan Siddiqui // GDB 9 includes CUs and TUs in CU list and generates TYpes 652a6efe6aSSayhaan Siddiqui // list. The NumCUs is CUs + TUs, so need to modify the check. 662a6efe6aSSayhaan Siddiqui // For split-dwarf 672a6efe6aSSayhaan Siddiqui // GDB-11, DWARF5: TU units from dwo are not included. 682a6efe6aSSayhaan Siddiqui // GDB-11, DWARF4: TU units from dwo are included. 692a6efe6aSSayhaan Siddiqui if (MaxDWARFVersion >= 5) 702a6efe6aSSayhaan Siddiqui SkipTypeUnits = !TUListSize ? true 712a6efe6aSSayhaan Siddiqui : ((NUmCUsEncoded + NumDWARF5TUs) == 722a6efe6aSSayhaan Siddiqui BC.DwCtx->getNumCompileUnits()); 732a6efe6aSSayhaan Siddiqui 742a6efe6aSSayhaan Siddiqui if (!((CUListSize == NumCUs * 16) || 752a6efe6aSSayhaan Siddiqui (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) { 762a6efe6aSSayhaan Siddiqui errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n"; 772a6efe6aSSayhaan Siddiqui exit(1); 782a6efe6aSSayhaan Siddiqui } 792a6efe6aSSayhaan Siddiqui DenseSet<uint64_t> OriginalOffsets; 802a6efe6aSSayhaan Siddiqui for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits(); 812a6efe6aSSayhaan Siddiqui Index < Units; ++Index) { 822a6efe6aSSayhaan Siddiqui const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index); 832a6efe6aSSayhaan Siddiqui if (SkipTypeUnits && CU->isTypeUnit()) 842a6efe6aSSayhaan Siddiqui continue; 852a6efe6aSSayhaan Siddiqui const uint64_t Offset = read64le(Data); 862a6efe6aSSayhaan Siddiqui Data += 16; 872a6efe6aSSayhaan Siddiqui if (CU->getOffset() != Offset) { 882a6efe6aSSayhaan Siddiqui errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n"; 892a6efe6aSSayhaan Siddiqui exit(1); 902a6efe6aSSayhaan Siddiqui } 912a6efe6aSSayhaan Siddiqui 922a6efe6aSSayhaan Siddiqui OriginalOffsets.insert(Offset); 932a6efe6aSSayhaan Siddiqui OffsetToIndexMap[Offset] = Index; 942a6efe6aSSayhaan Siddiqui } 952a6efe6aSSayhaan Siddiqui 962a6efe6aSSayhaan Siddiqui // Ignore old address table. 972a6efe6aSSayhaan Siddiqui const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset; 982a6efe6aSSayhaan Siddiqui // Move Data to the beginning of symbol table. 992a6efe6aSSayhaan Siddiqui Data += SymbolTableOffset - CUTypesOffset; 1002a6efe6aSSayhaan Siddiqui 1012a6efe6aSSayhaan Siddiqui // Calculate the size of the new address table. 1022a6efe6aSSayhaan Siddiqui uint32_t NewAddressTableSize = 0; 1032a6efe6aSSayhaan Siddiqui for (const auto &CURangesPair : ARangesSectionWriter.getCUAddressRanges()) { 1042a6efe6aSSayhaan Siddiqui const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second; 1052a6efe6aSSayhaan Siddiqui NewAddressTableSize += Ranges.size() * 20; 1062a6efe6aSSayhaan Siddiqui } 1072a6efe6aSSayhaan Siddiqui 1082a6efe6aSSayhaan Siddiqui // Difference between old and new table (and section) sizes. 1092a6efe6aSSayhaan Siddiqui // Could be negative. 1102a6efe6aSSayhaan Siddiqui int32_t Delta = NewAddressTableSize - OldAddressTableSize; 1112a6efe6aSSayhaan Siddiqui 1122a6efe6aSSayhaan Siddiqui size_t NewGdbIndexSize = GdbIndexContents.size() + Delta; 1132a6efe6aSSayhaan Siddiqui 1142a6efe6aSSayhaan Siddiqui // Free'd by ExecutableFileMemoryManager. 1152a6efe6aSSayhaan Siddiqui auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize]; 1162a6efe6aSSayhaan Siddiqui uint8_t *Buffer = NewGdbIndexContents; 1172a6efe6aSSayhaan Siddiqui 1182a6efe6aSSayhaan Siddiqui write32le(Buffer, Version); 1192a6efe6aSSayhaan Siddiqui write32le(Buffer + 4, CUListOffset); 1202a6efe6aSSayhaan Siddiqui write32le(Buffer + 8, CUTypesOffset); 1212a6efe6aSSayhaan Siddiqui write32le(Buffer + 12, AddressTableOffset); 1222a6efe6aSSayhaan Siddiqui write32le(Buffer + 16, SymbolTableOffset + Delta); 1232a6efe6aSSayhaan Siddiqui write32le(Buffer + 20, ConstantPoolOffset + Delta); 1242a6efe6aSSayhaan Siddiqui Buffer += 24; 1252a6efe6aSSayhaan Siddiqui 1262a6efe6aSSayhaan Siddiqui using MapEntry = std::pair<uint32_t, CUInfo>; 1272a6efe6aSSayhaan Siddiqui std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end()); 1282a6efe6aSSayhaan Siddiqui // Need to sort since we write out all of TUs in .debug_info before CUs. 1292a6efe6aSSayhaan Siddiqui std::sort(CUVector.begin(), CUVector.end(), 1302a6efe6aSSayhaan Siddiqui [](const MapEntry &E1, const MapEntry &E2) -> bool { 1312a6efe6aSSayhaan Siddiqui return E1.second.Offset < E2.second.Offset; 1322a6efe6aSSayhaan Siddiqui }); 1332a6efe6aSSayhaan Siddiqui // Writing out CU List <Offset, Size> 1342a6efe6aSSayhaan Siddiqui for (auto &CUInfo : CUVector) { 1352a6efe6aSSayhaan Siddiqui // Skipping TU for DWARF5 when they are not included in CU list. 1362a6efe6aSSayhaan Siddiqui if (!OriginalOffsets.count(CUInfo.first)) 1372a6efe6aSSayhaan Siddiqui continue; 1382a6efe6aSSayhaan Siddiqui write64le(Buffer, CUInfo.second.Offset); 1392a6efe6aSSayhaan Siddiqui // Length encoded in CU doesn't contain first 4 bytes that encode length. 1402a6efe6aSSayhaan Siddiqui write64le(Buffer + 8, CUInfo.second.Length + 4); 1412a6efe6aSSayhaan Siddiqui Buffer += 16; 1422a6efe6aSSayhaan Siddiqui } 143*33960ce5SSayhaan Siddiqui sortGDBIndexTUEntryVector(); 1442a6efe6aSSayhaan Siddiqui // Rewrite TU CU List, since abbrevs can be different. 1452a6efe6aSSayhaan Siddiqui // Entry example: 1462a6efe6aSSayhaan Siddiqui // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = 1472a6efe6aSSayhaan Siddiqui // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset, 1482a6efe6aSSayhaan Siddiqui // the second value is the type offset in the CU, and the third value is the 1492a6efe6aSSayhaan Siddiqui // type signature" Looking at what is being generated by gdb-add-index. The 1502a6efe6aSSayhaan Siddiqui // first entry is TU offset, second entry is offset from it, and third entry 1512a6efe6aSSayhaan Siddiqui // is the type signature. 1522a6efe6aSSayhaan Siddiqui if (TUListSize) 1532a6efe6aSSayhaan Siddiqui for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) { 1542a6efe6aSSayhaan Siddiqui write64le(Buffer, Entry.UnitOffset); 1552a6efe6aSSayhaan Siddiqui write64le(Buffer + 8, Entry.TypeDIERelativeOffset); 1562a6efe6aSSayhaan Siddiqui write64le(Buffer + 16, Entry.TypeHash); 1572a6efe6aSSayhaan Siddiqui Buffer += sizeof(GDBIndexTUEntry); 1582a6efe6aSSayhaan Siddiqui } 1592a6efe6aSSayhaan Siddiqui 1602a6efe6aSSayhaan Siddiqui // Generate new address table. 1612a6efe6aSSayhaan Siddiqui for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair : 1622a6efe6aSSayhaan Siddiqui ARangesSectionWriter.getCUAddressRanges()) { 1632a6efe6aSSayhaan Siddiqui const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first]; 1642a6efe6aSSayhaan Siddiqui const DebugAddressRangesVector &Ranges = CURangesPair.second; 1652a6efe6aSSayhaan Siddiqui for (const DebugAddressRange &Range : Ranges) { 1662a6efe6aSSayhaan Siddiqui write64le(Buffer, Range.LowPC); 1672a6efe6aSSayhaan Siddiqui write64le(Buffer + 8, Range.HighPC); 1682a6efe6aSSayhaan Siddiqui write32le(Buffer + 16, CUIndex); 1692a6efe6aSSayhaan Siddiqui Buffer += 20; 1702a6efe6aSSayhaan Siddiqui } 1712a6efe6aSSayhaan Siddiqui } 1722a6efe6aSSayhaan Siddiqui 1732a6efe6aSSayhaan Siddiqui const size_t TrailingSize = 1742a6efe6aSSayhaan Siddiqui GdbIndexContents.data() + GdbIndexContents.size() - Data; 1752a6efe6aSSayhaan Siddiqui assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize && 1762a6efe6aSSayhaan Siddiqui "size calculation error"); 1772a6efe6aSSayhaan Siddiqui 1782a6efe6aSSayhaan Siddiqui // Copy over the rest of the original data. 1792a6efe6aSSayhaan Siddiqui memcpy(Buffer, Data, TrailingSize); 1802a6efe6aSSayhaan Siddiqui 1812a6efe6aSSayhaan Siddiqui // Register the new section. 1822a6efe6aSSayhaan Siddiqui BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents, 1832a6efe6aSSayhaan Siddiqui NewGdbIndexSize); 1842a6efe6aSSayhaan Siddiqui } 185