Home | History | Annotate | Line # | Download | only in DWARF
      1 //===- DWARFGdbIndex.cpp --------------------------------------------------===//
      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 "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
     10 #include "llvm/ADT/SmallVector.h"
     11 #include "llvm/ADT/StringRef.h"
     12 #include "llvm/Support/Format.h"
     13 #include "llvm/Support/FormatVariadic.h"
     14 #include "llvm/Support/raw_ostream.h"
     15 #include <algorithm>
     16 #include <cassert>
     17 #include <cinttypes>
     18 #include <cstdint>
     19 #include <utility>
     20 
     21 using namespace llvm;
     22 
     23 // .gdb_index section format reference:
     24 // https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
     25 
     26 void DWARFGdbIndex::dumpCUList(raw_ostream &OS) const {
     27   OS << format("\n  CU list offset = 0x%x, has %" PRId64 " entries:",
     28                CuListOffset, (uint64_t)CuList.size())
     29      << '\n';
     30   uint32_t I = 0;
     31   for (const CompUnitEntry &CU : CuList)
     32     OS << format("    %d: Offset = 0x%llx, Length = 0x%llx\n", I++, CU.Offset,
     33                  CU.Length);
     34 }
     35 
     36 void DWARFGdbIndex::dumpTUList(raw_ostream &OS) const {
     37   OS << formatv("\n  Types CU list offset = {0:x}, has {1} entries:\n",
     38                 TuListOffset, TuList.size());
     39   uint32_t I = 0;
     40   for (const TypeUnitEntry &TU : TuList)
     41     OS << formatv("    {0}: offset = {1:x8}, type_offset = {2:x8}, "
     42                   "type_signature = {3:x16}\n",
     43                   I++, TU.Offset, TU.TypeOffset, TU.TypeSignature);
     44 }
     45 
     46 void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const {
     47   OS << format("\n  Address area offset = 0x%x, has %" PRId64 " entries:",
     48                AddressAreaOffset, (uint64_t)AddressArea.size())
     49      << '\n';
     50   for (const AddressEntry &Addr : AddressArea)
     51     OS << format(
     52         "    Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n",
     53         Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress,
     54         Addr.CuIndex);
     55 }
     56 
     57 void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const {
     58   OS << format("\n  Symbol table offset = 0x%x, size = %" PRId64
     59                ", filled slots:",
     60                SymbolTableOffset, (uint64_t)SymbolTable.size())
     61      << '\n';
     62   uint32_t I = -1;
     63   for (const SymTableEntry &E : SymbolTable) {
     64     ++I;
     65     if (!E.NameOffset && !E.VecOffset)
     66       continue;
     67 
     68     OS << format("    %d: Name offset = 0x%x, CU vector offset = 0x%x\n", I,
     69                  E.NameOffset, E.VecOffset);
     70 
     71     StringRef Name = ConstantPoolStrings.substr(
     72         ConstantPoolOffset - StringPoolOffset + E.NameOffset);
     73 
     74     auto CuVector = llvm::find_if(
     75         ConstantPoolVectors,
     76         [&](const std::pair<uint32_t, SmallVector<uint32_t, 0>> &V) {
     77           return V.first == E.VecOffset;
     78         });
     79     assert(CuVector != ConstantPoolVectors.end() && "Invalid symbol table");
     80     uint32_t CuVectorId = CuVector - ConstantPoolVectors.begin();
     81     OS << format("      String name: %s, CU vector index: %d\n", Name.data(),
     82                  CuVectorId);
     83   }
     84 }
     85 
     86 void DWARFGdbIndex::dumpConstantPool(raw_ostream &OS) const {
     87   OS << format("\n  Constant pool offset = 0x%x, has %" PRId64 " CU vectors:",
     88                ConstantPoolOffset, (uint64_t)ConstantPoolVectors.size());
     89   uint32_t I = 0;
     90   for (const auto &V : ConstantPoolVectors) {
     91     OS << format("\n    %d(0x%x): ", I++, V.first);
     92     for (uint32_t Val : V.second)
     93       OS << format("0x%x ", Val);
     94   }
     95   OS << '\n';
     96 }
     97 
     98 void DWARFGdbIndex::dump(raw_ostream &OS) {
     99   if (HasError) {
    100     OS << "\n<error parsing>\n";
    101     return;
    102   }
    103 
    104   if (HasContent) {
    105     OS << "  Version = " << Version << '\n';
    106     dumpCUList(OS);
    107     dumpTUList(OS);
    108     dumpAddressArea(OS);
    109     dumpSymbolTable(OS);
    110     dumpConstantPool(OS);
    111   }
    112 }
    113 
    114 bool DWARFGdbIndex::parseImpl(DataExtractor Data) {
    115   uint64_t Offset = 0;
    116 
    117   // Only version 7 is supported at this moment.
    118   Version = Data.getU32(&Offset);
    119   if (Version != 7)
    120     return false;
    121 
    122   CuListOffset = Data.getU32(&Offset);
    123   TuListOffset = Data.getU32(&Offset);
    124   AddressAreaOffset = Data.getU32(&Offset);
    125   SymbolTableOffset = Data.getU32(&Offset);
    126   ConstantPoolOffset = Data.getU32(&Offset);
    127 
    128   if (Offset != CuListOffset)
    129     return false;
    130 
    131   uint32_t CuListSize = (TuListOffset - CuListOffset) / 16;
    132   CuList.reserve(CuListSize);
    133   for (uint32_t i = 0; i < CuListSize; ++i) {
    134     uint64_t CuOffset = Data.getU64(&Offset);
    135     uint64_t CuLength = Data.getU64(&Offset);
    136     CuList.push_back({CuOffset, CuLength});
    137   }
    138 
    139   // CU Types are no longer needed as DWARF skeleton type units never made it
    140   // into the standard.
    141   uint32_t TuListSize = (AddressAreaOffset - TuListOffset) / 24;
    142   TuList.resize(TuListSize);
    143   for (uint32_t I = 0; I < TuListSize; ++I) {
    144     uint64_t CuOffset = Data.getU64(&Offset);
    145     uint64_t TypeOffset = Data.getU64(&Offset);
    146     uint64_t Signature = Data.getU64(&Offset);
    147     TuList[I] = {CuOffset, TypeOffset, Signature};
    148   }
    149 
    150   uint32_t AddressAreaSize = (SymbolTableOffset - AddressAreaOffset) / 20;
    151   AddressArea.reserve(AddressAreaSize);
    152   for (uint32_t i = 0; i < AddressAreaSize; ++i) {
    153     uint64_t LowAddress = Data.getU64(&Offset);
    154     uint64_t HighAddress = Data.getU64(&Offset);
    155     uint32_t CuIndex = Data.getU32(&Offset);
    156     AddressArea.push_back({LowAddress, HighAddress, CuIndex});
    157   }
    158 
    159   // The symbol table. This is an open addressed hash table. The size of the
    160   // hash table is always a power of 2.
    161   // Each slot in the hash table consists of a pair of offset_type values. The
    162   // first value is the offset of the symbol's name in the constant pool. The
    163   // second value is the offset of the CU vector in the constant pool.
    164   // If both values are 0, then this slot in the hash table is empty. This is ok
    165   // because while 0 is a valid constant pool index, it cannot be a valid index
    166   // for both a string and a CU vector.
    167   uint32_t SymTableSize = (ConstantPoolOffset - SymbolTableOffset) / 8;
    168   SymbolTable.reserve(SymTableSize);
    169   uint32_t CuVectorsTotal = 0;
    170   for (uint32_t i = 0; i < SymTableSize; ++i) {
    171     uint32_t NameOffset = Data.getU32(&Offset);
    172     uint32_t CuVecOffset = Data.getU32(&Offset);
    173     SymbolTable.push_back({NameOffset, CuVecOffset});
    174     if (NameOffset || CuVecOffset)
    175       ++CuVectorsTotal;
    176   }
    177 
    178   // The constant pool. CU vectors are stored first, followed by strings.
    179   // The first value is the number of CU indices in the vector. Each subsequent
    180   // value is the index and symbol attributes of a CU in the CU list.
    181   for (uint32_t i = 0; i < CuVectorsTotal; ++i) {
    182     ConstantPoolVectors.emplace_back(0, SmallVector<uint32_t, 0>());
    183     auto &Vec = ConstantPoolVectors.back();
    184     Vec.first = Offset - ConstantPoolOffset;
    185 
    186     uint32_t Num = Data.getU32(&Offset);
    187     for (uint32_t j = 0; j < Num; ++j)
    188       Vec.second.push_back(Data.getU32(&Offset));
    189   }
    190 
    191   ConstantPoolStrings = Data.getData().drop_front(Offset);
    192   StringPoolOffset = Offset;
    193   return true;
    194 }
    195 
    196 void DWARFGdbIndex::parse(DataExtractor Data) {
    197   HasContent = !Data.getData().empty();
    198   HasError = HasContent && !parseImpl(Data);
    199 }
    200