xref: /llvm-project/bolt/lib/Core/GDBIndex.cpp (revision 33960ce5a8e26baf05521fd7f8be5c5abb6bb0ff)
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