brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.3 KiB · 4c34f5e Raw
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