Home | History | Annotate | Line # | Download | only in obj2yaml
      1 //===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
      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/BinaryFormat/Dwarf.h"
     10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
     11 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
     12 #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
     13 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
     14 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
     15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
     16 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
     17 #include "llvm/ObjectYAML/DWARFYAML.h"
     18 
     19 #include <algorithm>
     20 
     21 using namespace llvm;
     22 
     23 void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
     24   auto AbbrevSetPtr = DCtx.getDebugAbbrev();
     25   if (AbbrevSetPtr) {
     26     uint64_t AbbrevTableID = 0;
     27     for (auto AbbrvDeclSet : *AbbrevSetPtr) {
     28       Y.DebugAbbrev.emplace_back();
     29       Y.DebugAbbrev.back().ID = AbbrevTableID++;
     30       for (auto AbbrvDecl : AbbrvDeclSet.second) {
     31         DWARFYAML::Abbrev Abbrv;
     32         Abbrv.Code = AbbrvDecl.getCode();
     33         Abbrv.Tag = AbbrvDecl.getTag();
     34         Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
     35                                                  : dwarf::DW_CHILDREN_no;
     36         for (auto Attribute : AbbrvDecl.attributes()) {
     37           DWARFYAML::AttributeAbbrev AttAbrv;
     38           AttAbrv.Attribute = Attribute.Attr;
     39           AttAbrv.Form = Attribute.Form;
     40           if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
     41             AttAbrv.Value = Attribute.getImplicitConstValue();
     42           Abbrv.Attributes.push_back(AttAbrv);
     43         }
     44         Y.DebugAbbrev.back().Table.push_back(Abbrv);
     45       }
     46     }
     47   }
     48 }
     49 
     50 Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
     51   DWARFDebugAddrTable AddrTable;
     52   DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
     53                               DCtx.getDWARFObj().getAddrSection(),
     54                               DCtx.isLittleEndian(), /*AddrSize=*/0);
     55   std::vector<DWARFYAML::AddrTableEntry> AddrTables;
     56   uint64_t Offset = 0;
     57   while (AddrData.isValidOffset(Offset)) {
     58     // We ignore any errors that don't prevent parsing the section, since we can
     59     // still represent such sections.
     60     if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0,
     61                                         consumeError))
     62       return Err;
     63     AddrTables.emplace_back();
     64     for (uint64_t Addr : AddrTable.getAddressEntries()) {
     65       // Currently, the parser doesn't support parsing an address table with non
     66       // linear addresses (segment_selector_size != 0). The segment selectors
     67       // are specified to be zero.
     68       AddrTables.back().SegAddrPairs.push_back(
     69           {/*SegmentSelector=*/0, /*Address=*/Addr});
     70     }
     71 
     72     AddrTables.back().Format = AddrTable.getFormat();
     73     AddrTables.back().Length = AddrTable.getLength();
     74     AddrTables.back().Version = AddrTable.getVersion();
     75     AddrTables.back().AddrSize = AddrTable.getAddressSize();
     76     AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize();
     77   }
     78   Y.DebugAddr = std::move(AddrTables);
     79   return Error::success();
     80 }
     81 
     82 Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
     83   DataExtractor StrData = DCtx.getStringExtractor();
     84   uint64_t Offset = 0;
     85   std::vector<StringRef> DebugStr;
     86   Error Err = Error::success();
     87   while (StrData.isValidOffset(Offset)) {
     88     const char *CStr = StrData.getCStr(&Offset, &Err);
     89     if (Err)
     90       return Err;
     91     DebugStr.push_back(CStr);
     92   }
     93 
     94   Y.DebugStrings = DebugStr;
     95   return Err;
     96 }
     97 
     98 Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
     99   DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
    100                                  DCtx.isLittleEndian(), 0);
    101   uint64_t Offset = 0;
    102   DWARFDebugArangeSet Set;
    103   std::vector<DWARFYAML::ARange> DebugAranges;
    104 
    105   // We ignore any errors that don't prevent parsing the section, since we can
    106   // still represent such sections. These errors are recorded via the
    107   // WarningHandler parameter of Set.extract().
    108   auto DiscardError = [](Error Err) { consumeError(std::move(Err)); };
    109 
    110   while (ArangesData.isValidOffset(Offset)) {
    111     if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
    112       return E;
    113     DWARFYAML::ARange Range;
    114     Range.Format = Set.getHeader().Format;
    115     Range.Length = Set.getHeader().Length;
    116     Range.Version = Set.getHeader().Version;
    117     Range.CuOffset = Set.getHeader().CuOffset;
    118     Range.AddrSize = Set.getHeader().AddrSize;
    119     Range.SegSize = Set.getHeader().SegSize;
    120     for (auto Descriptor : Set.descriptors()) {
    121       DWARFYAML::ARangeDescriptor Desc;
    122       Desc.Address = Descriptor.Address;
    123       Desc.Length = Descriptor.Length;
    124       Range.Descriptors.push_back(Desc);
    125     }
    126     DebugAranges.push_back(Range);
    127   }
    128 
    129   Y.DebugAranges = DebugAranges;
    130   return ErrorSuccess();
    131 }
    132 
    133 Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
    134   // We are assuming all address byte sizes will be consistent across all
    135   // compile units.
    136   uint8_t AddrSize = 0;
    137   for (const auto &CU : DCtx.compile_units()) {
    138     const uint8_t CUAddrSize = CU->getAddressByteSize();
    139     if (AddrSize == 0)
    140       AddrSize = CUAddrSize;
    141     else if (CUAddrSize != AddrSize)
    142       return createStringError(std::errc::invalid_argument,
    143                                "address sizes vary in different compile units");
    144   }
    145 
    146   DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
    147                           DCtx.isLittleEndian(), AddrSize);
    148   uint64_t Offset = 0;
    149   DWARFDebugRangeList DwarfRanges;
    150   std::vector<DWARFYAML::Ranges> DebugRanges;
    151 
    152   while (Data.isValidOffset(Offset)) {
    153     DWARFYAML::Ranges YamlRanges;
    154     YamlRanges.Offset = Offset;
    155     YamlRanges.AddrSize = AddrSize;
    156     if (Error E = DwarfRanges.extract(Data, &Offset))
    157       return E;
    158     for (const auto &RLE : DwarfRanges.getEntries())
    159       YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
    160     DebugRanges.push_back(std::move(YamlRanges));
    161   }
    162 
    163   Y.DebugRanges = DebugRanges;
    164   return ErrorSuccess();
    165 }
    166 
    167 static Optional<DWARFYAML::PubSection>
    168 dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
    169                bool IsGNUStyle) {
    170   DWARFYAML::PubSection Y;
    171   DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
    172                                     DCtx.isLittleEndian(), 0);
    173   DWARFDebugPubTable Table;
    174   // We ignore any errors that don't prevent parsing the section, since we can
    175   // still represent such sections.
    176   Table.extract(PubSectionData, IsGNUStyle,
    177                 [](Error Err) { consumeError(std::move(Err)); });
    178   ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
    179   if (Sets.empty())
    180     return None;
    181 
    182   // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
    183   Y.Format = Sets[0].Format;
    184   Y.Length = Sets[0].Length;
    185   Y.Version = Sets[0].Version;
    186   Y.UnitOffset = Sets[0].Offset;
    187   Y.UnitSize = Sets[0].Size;
    188 
    189   for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries)
    190     Y.Entries.push_back(DWARFYAML::PubEntry{(uint32_t)E.SecOffset,
    191                                             E.Descriptor.toBits(), E.Name});
    192 
    193   return Y;
    194 }
    195 
    196 void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
    197   const DWARFObject &D = DCtx.getDWARFObj();
    198 
    199   Y.PubNames =
    200       dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
    201   Y.PubTypes =
    202       dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
    203   // TODO: Test dumping .debug_gnu_pubnames section.
    204   Y.GNUPubNames =
    205       dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
    206   // TODO: Test dumping .debug_gnu_pubtypes section.
    207   Y.GNUPubTypes =
    208       dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
    209 }
    210 
    211 void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
    212   for (const auto &CU : DCtx.compile_units()) {
    213     DWARFYAML::Unit NewUnit;
    214     NewUnit.Format = CU->getFormat();
    215     NewUnit.Length = CU->getLength();
    216     NewUnit.Version = CU->getVersion();
    217     if (NewUnit.Version >= 5)
    218       NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
    219     const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
    220     NewUnit.AbbrevTableID = std::distance(
    221         DebugAbbrev->begin(),
    222         llvm::find_if(
    223             *DebugAbbrev,
    224             [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
    225               return P.first == CU->getAbbreviations()->getOffset();
    226             }));
    227     NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
    228     NewUnit.AddrSize = CU->getAddressByteSize();
    229     for (auto DIE : CU->dies()) {
    230       DWARFYAML::Entry NewEntry;
    231       DataExtractor EntryData = CU->getDebugInfoExtractor();
    232       uint64_t offset = DIE.getOffset();
    233 
    234       assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
    235       if (!EntryData.isValidOffset(offset))
    236         continue;
    237 
    238       NewEntry.AbbrCode = EntryData.getULEB128(&offset);
    239 
    240       auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
    241       if (AbbrevDecl) {
    242         for (const auto &AttrSpec : AbbrevDecl->attributes()) {
    243           DWARFYAML::FormValue NewValue;
    244           NewValue.Value = 0xDEADBEEFDEADBEEF;
    245           DWARFDie DIEWrapper(CU.get(), &DIE);
    246           auto FormValue = DIEWrapper.find(AttrSpec.Attr);
    247           if (!FormValue)
    248             return;
    249           auto Form = FormValue.getValue().getForm();
    250           bool indirect = false;
    251           do {
    252             indirect = false;
    253             switch (Form) {
    254             case dwarf::DW_FORM_addr:
    255             case dwarf::DW_FORM_GNU_addr_index:
    256               if (auto Val = FormValue.getValue().getAsAddress())
    257                 NewValue.Value = Val.getValue();
    258               break;
    259             case dwarf::DW_FORM_ref_addr:
    260             case dwarf::DW_FORM_ref1:
    261             case dwarf::DW_FORM_ref2:
    262             case dwarf::DW_FORM_ref4:
    263             case dwarf::DW_FORM_ref8:
    264             case dwarf::DW_FORM_ref_udata:
    265             case dwarf::DW_FORM_ref_sig8:
    266               if (auto Val = FormValue.getValue().getAsReferenceUVal())
    267                 NewValue.Value = Val.getValue();
    268               break;
    269             case dwarf::DW_FORM_exprloc:
    270             case dwarf::DW_FORM_block:
    271             case dwarf::DW_FORM_block1:
    272             case dwarf::DW_FORM_block2:
    273             case dwarf::DW_FORM_block4:
    274               if (auto Val = FormValue.getValue().getAsBlock()) {
    275                 auto BlockData = Val.getValue();
    276                 std::copy(BlockData.begin(), BlockData.end(),
    277                           std::back_inserter(NewValue.BlockData));
    278               }
    279               NewValue.Value = NewValue.BlockData.size();
    280               break;
    281             case dwarf::DW_FORM_data1:
    282             case dwarf::DW_FORM_flag:
    283             case dwarf::DW_FORM_data2:
    284             case dwarf::DW_FORM_data4:
    285             case dwarf::DW_FORM_data8:
    286             case dwarf::DW_FORM_sdata:
    287             case dwarf::DW_FORM_udata:
    288             case dwarf::DW_FORM_ref_sup4:
    289             case dwarf::DW_FORM_ref_sup8:
    290               if (auto Val = FormValue.getValue().getAsUnsignedConstant())
    291                 NewValue.Value = Val.getValue();
    292               break;
    293             case dwarf::DW_FORM_string:
    294               if (auto Val = FormValue.getValue().getAsCString())
    295                 NewValue.CStr = Val.getValue();
    296               break;
    297             case dwarf::DW_FORM_indirect:
    298               indirect = true;
    299               if (auto Val = FormValue.getValue().getAsUnsignedConstant()) {
    300                 NewValue.Value = Val.getValue();
    301                 NewEntry.Values.push_back(NewValue);
    302                 Form = static_cast<dwarf::Form>(Val.getValue());
    303               }
    304               break;
    305             case dwarf::DW_FORM_strp:
    306             case dwarf::DW_FORM_sec_offset:
    307             case dwarf::DW_FORM_GNU_ref_alt:
    308             case dwarf::DW_FORM_GNU_strp_alt:
    309             case dwarf::DW_FORM_line_strp:
    310             case dwarf::DW_FORM_strp_sup:
    311             case dwarf::DW_FORM_GNU_str_index:
    312             case dwarf::DW_FORM_strx:
    313               if (auto Val = FormValue.getValue().getAsCStringOffset())
    314                 NewValue.Value = Val.getValue();
    315               break;
    316             case dwarf::DW_FORM_flag_present:
    317               NewValue.Value = 1;
    318               break;
    319             default:
    320               break;
    321             }
    322           } while (indirect);
    323           NewEntry.Values.push_back(NewValue);
    324         }
    325       }
    326 
    327       NewUnit.Entries.push_back(NewEntry);
    328     }
    329     Y.CompileUnits.push_back(NewUnit);
    330   }
    331 }
    332 
    333 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
    334                    DWARFYAML::File &File) {
    335   File.Name = Data.getCStr(&Offset);
    336   if (File.Name.empty())
    337     return false;
    338   File.DirIdx = Data.getULEB128(&Offset);
    339   File.ModTime = Data.getULEB128(&Offset);
    340   File.Length = Data.getULEB128(&Offset);
    341   return true;
    342 }
    343 
    344 void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
    345   for (const auto &CU : DCtx.compile_units()) {
    346     auto CUDIE = CU->getUnitDIE();
    347     if (!CUDIE)
    348       continue;
    349     if (auto StmtOffset =
    350             dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
    351       DWARFYAML::LineTable DebugLines;
    352       DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
    353                              DCtx.isLittleEndian(), CU->getAddressByteSize());
    354       uint64_t Offset = *StmtOffset;
    355       uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset);
    356       if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) {
    357         DebugLines.Format = dwarf::DWARF64;
    358         DebugLines.Length = LineData.getU64(&Offset);
    359       } else {
    360         DebugLines.Format = dwarf::DWARF32;
    361         DebugLines.Length = LengthOrDWARF64Prefix;
    362       }
    363       assert(DebugLines.Length);
    364       uint64_t LineTableLength = *DebugLines.Length;
    365       uint64_t SizeOfPrologueLength =
    366           DebugLines.Format == dwarf::DWARF64 ? 8 : 4;
    367       DebugLines.Version = LineData.getU16(&Offset);
    368       DebugLines.PrologueLength =
    369           LineData.getUnsigned(&Offset, SizeOfPrologueLength);
    370       assert(DebugLines.PrologueLength);
    371       const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset;
    372 
    373       DebugLines.MinInstLength = LineData.getU8(&Offset);
    374       if (DebugLines.Version >= 4)
    375         DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
    376       DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
    377       DebugLines.LineBase = LineData.getU8(&Offset);
    378       DebugLines.LineRange = LineData.getU8(&Offset);
    379       DebugLines.OpcodeBase = LineData.getU8(&Offset);
    380 
    381       DebugLines.StandardOpcodeLengths.emplace();
    382       for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
    383         DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
    384 
    385       while (Offset < EndPrologue) {
    386         StringRef Dir = LineData.getCStr(&Offset);
    387         if (!Dir.empty())
    388           DebugLines.IncludeDirs.push_back(Dir);
    389         else
    390           break;
    391       }
    392 
    393       while (Offset < EndPrologue) {
    394         DWARFYAML::File TmpFile;
    395         if (dumpFileEntry(LineData, Offset, TmpFile))
    396           DebugLines.Files.push_back(TmpFile);
    397         else
    398           break;
    399       }
    400 
    401       const uint64_t LineEnd =
    402           LineTableLength + *StmtOffset + SizeOfPrologueLength;
    403       while (Offset < LineEnd) {
    404         DWARFYAML::LineTableOpcode NewOp = {};
    405         NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
    406         if (NewOp.Opcode == 0) {
    407           auto StartExt = Offset;
    408           NewOp.ExtLen = LineData.getULEB128(&Offset);
    409           NewOp.SubOpcode =
    410               (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
    411           switch (NewOp.SubOpcode) {
    412           case dwarf::DW_LNE_set_address:
    413           case dwarf::DW_LNE_set_discriminator:
    414             NewOp.Data = LineData.getAddress(&Offset);
    415             break;
    416           case dwarf::DW_LNE_define_file:
    417             dumpFileEntry(LineData, Offset, NewOp.FileEntry);
    418             break;
    419           case dwarf::DW_LNE_end_sequence:
    420             break;
    421           default:
    422             while (Offset < StartExt + *NewOp.ExtLen)
    423               NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
    424           }
    425         } else if (NewOp.Opcode < *DebugLines.OpcodeBase) {
    426           switch (NewOp.Opcode) {
    427           case dwarf::DW_LNS_copy:
    428           case dwarf::DW_LNS_negate_stmt:
    429           case dwarf::DW_LNS_set_basic_block:
    430           case dwarf::DW_LNS_const_add_pc:
    431           case dwarf::DW_LNS_set_prologue_end:
    432           case dwarf::DW_LNS_set_epilogue_begin:
    433             break;
    434 
    435           case dwarf::DW_LNS_advance_pc:
    436           case dwarf::DW_LNS_set_file:
    437           case dwarf::DW_LNS_set_column:
    438           case dwarf::DW_LNS_set_isa:
    439             NewOp.Data = LineData.getULEB128(&Offset);
    440             break;
    441 
    442           case dwarf::DW_LNS_advance_line:
    443             NewOp.SData = LineData.getSLEB128(&Offset);
    444             break;
    445 
    446           case dwarf::DW_LNS_fixed_advance_pc:
    447             NewOp.Data = LineData.getU16(&Offset);
    448             break;
    449 
    450           default:
    451             for (uint8_t i = 0;
    452                  i <
    453                  DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
    454                  ++i)
    455               NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
    456           }
    457         }
    458         DebugLines.Opcodes.push_back(NewOp);
    459       }
    460       Y.DebugLines.push_back(DebugLines);
    461     }
    462   }
    463 }
    464