brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · 03c0566 Raw
433 lines · c
1//===- DebugLineSectionEmitter.h --------------------------------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H10#define LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H11 12#include "DWARFEmitterImpl.h"13#include "llvm/DWARFLinker/AddressesMap.h"14#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"15#include "llvm/DebugInfo/DWARF/DWARFObject.h"16#include "llvm/MC/MCTargetOptionsCommandFlags.h"17#include "llvm/MC/TargetRegistry.h"18 19namespace llvm {20namespace dwarf_linker {21namespace parallel {22 23/// This class emits specified line table into the .debug_line section.24class DebugLineSectionEmitter {25public:26  DebugLineSectionEmitter(const Triple &TheTriple, DwarfUnit &U)27      : TheTriple(TheTriple), U(U) {}28 29  Error emit(const DWARFDebugLine::LineTable &LineTable) {30    // FIXME: remove dependence on MCDwarfLineAddr::encode.31    // As we reuse MCDwarfLineAddr::encode, we need to create/initialize32    // some MC* classes.33    if (Error Err = init(TheTriple))34      return Err;35 36    // Get descriptor for output .debug_line section.37    SectionDescriptor &OutSection =38        U.getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);39 40    // unit_length.41    OutSection.emitUnitLength(0xBADDEF);42    uint64_t OffsetAfterUnitLength = OutSection.OS.tell();43 44    // Emit prologue.45    emitLineTablePrologue(LineTable.Prologue, OutSection);46 47    // Emit rows.48    emitLineTableRows(LineTable, OutSection);49    uint64_t OffsetAfterEnd = OutSection.OS.tell();50 51    // Update unit length field with actual length value.52    assert(OffsetAfterUnitLength -53               OutSection.getFormParams().getDwarfOffsetByteSize() <54           OffsetAfterUnitLength);55    OutSection.apply(OffsetAfterUnitLength -56                         OutSection.getFormParams().getDwarfOffsetByteSize(),57                     dwarf::DW_FORM_sec_offset,58                     OffsetAfterEnd - OffsetAfterUnitLength);59 60    return Error::success();61  }62 63private:64  Error init(Triple TheTriple) {65    std::string ErrorStr;66    std::string TripleName;67 68    // Get the target.69    const Target *TheTarget =70        TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);71    if (!TheTarget)72      return createStringError(std::errc::invalid_argument, ErrorStr.c_str());73    TripleName = TheTriple.getTriple();74 75    // Create all the MC Objects.76    MRI.reset(TheTarget->createMCRegInfo(TheTriple));77    if (!MRI)78      return createStringError(std::errc::invalid_argument,79                               "no register info for target %s",80                               TripleName.c_str());81 82    MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();83    MAI.reset(TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));84    if (!MAI)85      return createStringError(std::errc::invalid_argument,86                               "no asm info for target %s", TripleName.c_str());87 88    MSTI.reset(TheTarget->createMCSubtargetInfo(TheTriple, "", ""));89    if (!MSTI)90      return createStringError(std::errc::invalid_argument,91                               "no subtarget info for target %s",92                               TripleName.c_str());93 94    MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,95                           nullptr, true, "__DWARF"));96 97    return Error::success();98  }99 100  void emitLineTablePrologue(const DWARFDebugLine::Prologue &P,101                             SectionDescriptor &Section) {102    // version (uhalf).103    Section.emitIntVal(P.getVersion(), 2);104    if (P.getVersion() == 5) {105      // address_size (ubyte).106      Section.emitIntVal(P.getAddressSize(), 1);107 108      // segment_selector_size (ubyte).109      Section.emitIntVal(P.SegSelectorSize, 1);110    }111 112    // header_length.113    Section.emitOffset(0xBADDEF);114 115    uint64_t OffsetAfterPrologueLength = Section.OS.tell();116    emitLineTableProloguePayload(P, Section);117    uint64_t OffsetAfterPrologueEnd = Section.OS.tell();118 119    // Update prologue length field with actual length value.120    Section.apply(OffsetAfterPrologueLength -121                      Section.getFormParams().getDwarfOffsetByteSize(),122                  dwarf::DW_FORM_sec_offset,123                  OffsetAfterPrologueEnd - OffsetAfterPrologueLength);124  }125 126  void127  emitLineTablePrologueV2IncludeAndFileTable(const DWARFDebugLine::Prologue &P,128                                             SectionDescriptor &Section) {129    // include_directories (sequence of path names).130    for (const DWARFFormValue &Include : P.IncludeDirectories) {131      std::optional<const char *> IncludeStr = dwarf::toString(Include);132      if (!IncludeStr) {133        U.warn("cann't read string from line table.");134        return;135      }136 137      Section.emitString(Include.getForm(), *IncludeStr);138    }139    // The last entry is followed by a single null byte.140    Section.emitIntVal(0, 1);141 142    // file_names (sequence of file entries).143    for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) {144      std::optional<const char *> FileNameStr = dwarf::toString(File.Name);145      if (!FileNameStr) {146        U.warn("cann't read string from line table.");147        return;148      }149 150      // A null-terminated string containing the full or relative path name of a151      // source file.152      Section.emitString(File.Name.getForm(), *FileNameStr);153 154      // An unsigned LEB128 number representing the directory index of a155      // directory in the include_directories section.156      encodeULEB128(File.DirIdx, Section.OS);157      // An unsigned LEB128 number representing the (implementation-defined)158      // time of last modification for the file, or 0 if not available.159      encodeULEB128(File.ModTime, Section.OS);160      // An unsigned LEB128 number representing the length in bytes of the file,161      // or 0 if not available.162      encodeULEB128(File.Length, Section.OS);163    }164    // The last entry is followed by a single null byte.165    Section.emitIntVal(0, 1);166  }167 168  void169  emitLineTablePrologueV5IncludeAndFileTable(const DWARFDebugLine::Prologue &P,170                                             SectionDescriptor &Section) {171    if (P.IncludeDirectories.empty()) {172      // directory_entry_format_count(ubyte).173      Section.emitIntVal(0, 1);174    } else {175      // directory_entry_format_count(ubyte).176      Section.emitIntVal(1, 1);177 178      // directory_entry_format (sequence of ULEB128 pairs).179      encodeULEB128(dwarf::DW_LNCT_path, Section.OS);180      encodeULEB128(P.IncludeDirectories[0].getForm(), Section.OS);181    }182 183    // directories_count (ULEB128).184    encodeULEB128(P.IncludeDirectories.size(), Section.OS);185    // directories (sequence of directory names).186    for (auto Include : P.IncludeDirectories) {187      std::optional<const char *> IncludeStr = dwarf::toString(Include);188      if (!IncludeStr) {189        U.warn("cann't read string from line table.");190        return;191      }192 193      Section.emitString(Include.getForm(), *IncludeStr);194    }195 196    bool HasChecksums = P.ContentTypes.HasMD5;197    bool HasInlineSources = P.ContentTypes.HasSource;198 199    dwarf::Form FileNameForm = dwarf::DW_FORM_string;200    dwarf::Form LLVMSourceForm = dwarf::DW_FORM_string;201 202    if (P.FileNames.empty()) {203      // file_name_entry_format_count (ubyte).204      Section.emitIntVal(0, 1);205    } else {206      FileNameForm = P.FileNames[0].Name.getForm();207      LLVMSourceForm = P.FileNames[0].Source.getForm();208 209      // file_name_entry_format_count (ubyte).210      Section.emitIntVal(211          2 + (HasChecksums ? 1 : 0) + (HasInlineSources ? 1 : 0), 1);212 213      // file_name_entry_format (sequence of ULEB128 pairs).214      encodeULEB128(dwarf::DW_LNCT_path, Section.OS);215      encodeULEB128(FileNameForm, Section.OS);216 217      encodeULEB128(dwarf::DW_LNCT_directory_index, Section.OS);218      encodeULEB128(dwarf::DW_FORM_udata, Section.OS);219 220      if (HasChecksums) {221        encodeULEB128(dwarf::DW_LNCT_MD5, Section.OS);222        encodeULEB128(dwarf::DW_FORM_data16, Section.OS);223      }224 225      if (HasInlineSources) {226        encodeULEB128(dwarf::DW_LNCT_LLVM_source, Section.OS);227        encodeULEB128(LLVMSourceForm, Section.OS);228      }229    }230 231    // file_names_count (ULEB128).232    encodeULEB128(P.FileNames.size(), Section.OS);233 234    // file_names (sequence of file name entries).235    for (auto File : P.FileNames) {236      std::optional<const char *> FileNameStr = dwarf::toString(File.Name);237      if (!FileNameStr) {238        U.warn("cann't read string from line table.");239        return;240      }241 242      // A null-terminated string containing the full or relative path name of a243      // source file.244      Section.emitString(FileNameForm, *FileNameStr);245      encodeULEB128(File.DirIdx, Section.OS);246 247      if (HasChecksums) {248        assert((File.Checksum.size() == 16) &&249               "checksum size is not equal to 16 bytes.");250        Section.emitBinaryData(251            StringRef(reinterpret_cast<const char *>(File.Checksum.data()),252                      File.Checksum.size()));253      }254 255      if (HasInlineSources) {256        std::optional<const char *> FileSourceStr =257            dwarf::toString(File.Source);258        if (!FileSourceStr) {259          U.warn("cann't read string from line table.");260          return;261        }262 263        Section.emitString(LLVMSourceForm, *FileSourceStr);264      }265    }266  }267 268  void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,269                                    SectionDescriptor &Section) {270    // minimum_instruction_length (ubyte).271    Section.emitIntVal(P.MinInstLength, 1);272    if (P.FormParams.Version >= 4) {273      // maximum_operations_per_instruction (ubyte).274      Section.emitIntVal(P.MaxOpsPerInst, 1);275    }276    // default_is_stmt (ubyte).277    Section.emitIntVal(P.DefaultIsStmt, 1);278    // line_base (sbyte).279    Section.emitIntVal(P.LineBase, 1);280    // line_range (ubyte).281    Section.emitIntVal(P.LineRange, 1);282    // opcode_base (ubyte).283    Section.emitIntVal(P.OpcodeBase, 1);284 285    // standard_opcode_lengths (array of ubyte).286    for (auto Length : P.StandardOpcodeLengths)287      Section.emitIntVal(Length, 1);288 289    if (P.FormParams.Version < 5)290      emitLineTablePrologueV2IncludeAndFileTable(P, Section);291    else292      emitLineTablePrologueV5IncludeAndFileTable(P, Section);293  }294 295  void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,296                         SectionDescriptor &Section) {297 298    MCDwarfLineTableParams Params;299    Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;300    Params.DWARF2LineBase = LineTable.Prologue.LineBase;301    Params.DWARF2LineRange = LineTable.Prologue.LineRange;302 303    SmallString<128> EncodingBuffer;304 305    if (LineTable.Rows.empty()) {306      // We only have the dummy entry, dsymutil emits an entry with a 0307      // address in that case.308      MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),309                              0, EncodingBuffer);310      Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());311      return;312    }313 314    // Line table state machine fields315    unsigned FileNum = 1;316    unsigned LastLine = 1;317    unsigned Column = 0;318    unsigned Discriminator = 0;319    unsigned IsStatement = 1;320    unsigned Isa = 0;321    uint64_t Address = -1ULL;322 323    unsigned RowsSinceLastSequence = 0;324 325    for (const DWARFDebugLine::Row &Row : LineTable.Rows) {326      int64_t AddressDelta;327      if (Address == -1ULL) {328        Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);329        encodeULEB128(Section.getFormParams().AddrSize + 1, Section.OS);330        Section.emitIntVal(dwarf::DW_LNE_set_address, 1);331        Section.emitIntVal(Row.Address.Address,332                           Section.getFormParams().AddrSize);333        AddressDelta = 0;334      } else {335        AddressDelta =336            (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;337      }338 339      // FIXME: code copied and transformed from340      // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share this341      // code, but the current compatibility requirement with classic dsymutil342      // makes it hard. Revisit that once this requirement is dropped.343 344      if (FileNum != Row.File) {345        FileNum = Row.File;346        Section.emitIntVal(dwarf::DW_LNS_set_file, 1);347        encodeULEB128(FileNum, Section.OS);348      }349      if (Column != Row.Column) {350        Column = Row.Column;351        Section.emitIntVal(dwarf::DW_LNS_set_column, 1);352        encodeULEB128(Column, Section.OS);353      }354      if (Discriminator != Row.Discriminator && MC->getDwarfVersion() >= 4) {355        Discriminator = Row.Discriminator;356        unsigned Size = getULEB128Size(Discriminator);357        Section.emitIntVal(dwarf::DW_LNS_extended_op, 1);358        encodeULEB128(Size + 1, Section.OS);359        Section.emitIntVal(dwarf::DW_LNE_set_discriminator, 1);360        encodeULEB128(Discriminator, Section.OS);361      }362      Discriminator = 0;363 364      if (Isa != Row.Isa) {365        Isa = Row.Isa;366        Section.emitIntVal(dwarf::DW_LNS_set_isa, 1);367        encodeULEB128(Isa, Section.OS);368      }369      if (IsStatement != Row.IsStmt) {370        IsStatement = Row.IsStmt;371        Section.emitIntVal(dwarf::DW_LNS_negate_stmt, 1);372      }373      if (Row.BasicBlock)374        Section.emitIntVal(dwarf::DW_LNS_set_basic_block, 1);375 376      if (Row.PrologueEnd)377        Section.emitIntVal(dwarf::DW_LNS_set_prologue_end, 1);378 379      if (Row.EpilogueBegin)380        Section.emitIntVal(dwarf::DW_LNS_set_epilogue_begin, 1);381 382      int64_t LineDelta = int64_t(Row.Line) - LastLine;383      if (!Row.EndSequence) {384        MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,385                                EncodingBuffer);386        Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());387        EncodingBuffer.resize(0);388        Address = Row.Address.Address;389        LastLine = Row.Line;390        RowsSinceLastSequence++;391      } else {392        if (LineDelta) {393          Section.emitIntVal(dwarf::DW_LNS_advance_line, 1);394          encodeSLEB128(LineDelta, Section.OS);395        }396        if (AddressDelta) {397          Section.emitIntVal(dwarf::DW_LNS_advance_pc, 1);398          encodeULEB128(AddressDelta, Section.OS);399        }400        MCDwarfLineAddr::encode(*MC, Params,401                                std::numeric_limits<int64_t>::max(), 0,402                                EncodingBuffer);403        Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());404        EncodingBuffer.resize(0);405        Address = -1ULL;406        LastLine = FileNum = IsStatement = 1;407        RowsSinceLastSequence = Column = Discriminator = Isa = 0;408      }409    }410 411    if (RowsSinceLastSequence) {412      MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(),413                              0, EncodingBuffer);414      Section.OS.write(EncodingBuffer.c_str(), EncodingBuffer.size());415      EncodingBuffer.resize(0);416    }417  }418 419  Triple TheTriple;420  DwarfUnit &U;421 422  std::unique_ptr<MCRegisterInfo> MRI;423  std::unique_ptr<MCAsmInfo> MAI;424  std::unique_ptr<MCContext> MC;425  std::unique_ptr<MCSubtargetInfo> MSTI;426};427 428} // end of namespace parallel429} // end of namespace dwarf_linker430} // end of namespace llvm431 432#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEBUGLINESECTIONEMITTER_H433