Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:41

0001 //===- DWARFDebugLine.h -----------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGLINE_H
0010 #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLINE_H
0011 
0012 #include "llvm/ADT/StringRef.h"
0013 #include "llvm/BinaryFormat/Dwarf.h"
0014 #include "llvm/DebugInfo/DIContext.h"
0015 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
0016 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
0017 #include "llvm/Support/MD5.h"
0018 #include "llvm/Support/Path.h"
0019 #include <cstdint>
0020 #include <map>
0021 #include <string>
0022 #include <vector>
0023 
0024 namespace llvm {
0025 
0026 class raw_ostream;
0027 
0028 class DWARFDebugLine {
0029 public:
0030   struct FileNameEntry {
0031     FileNameEntry() = default;
0032 
0033     DWARFFormValue Name;
0034     uint64_t DirIdx = 0;
0035     uint64_t ModTime = 0;
0036     uint64_t Length = 0;
0037     MD5::MD5Result Checksum;
0038     DWARFFormValue Source;
0039   };
0040 
0041   /// Tracks which optional content types are present in a DWARF file name
0042   /// entry format.
0043   struct ContentTypeTracker {
0044     ContentTypeTracker() = default;
0045 
0046     /// Whether filename entries provide a modification timestamp.
0047     bool HasModTime = false;
0048     /// Whether filename entries provide a file size.
0049     bool HasLength = false;
0050     /// For v5, whether filename entries provide an MD5 checksum.
0051     bool HasMD5 = false;
0052     /// For v5, whether filename entries provide source text.
0053     bool HasSource = false;
0054 
0055     /// Update tracked content types with \p ContentType.
0056     void trackContentType(dwarf::LineNumberEntryFormat ContentType);
0057   };
0058 
0059   struct Prologue {
0060     Prologue();
0061 
0062     /// The size in bytes of the statement information for this compilation unit
0063     /// (not including the total_length field itself).
0064     uint64_t TotalLength;
0065     /// Version, address size (starting in v5), and DWARF32/64 format; these
0066     /// parameters affect interpretation of forms (used in the directory and
0067     /// file tables starting with v5).
0068     dwarf::FormParams FormParams;
0069     /// The number of bytes following the prologue_length field to the beginning
0070     /// of the first byte of the statement program itself.
0071     uint64_t PrologueLength;
0072     /// In v5, size in bytes of a segment selector.
0073     uint8_t SegSelectorSize;
0074     /// The size in bytes of the smallest target machine instruction. Statement
0075     /// program opcodes that alter the address register first multiply their
0076     /// operands by this value.
0077     uint8_t MinInstLength;
0078     /// The maximum number of individual operations that may be encoded in an
0079     /// instruction.
0080     uint8_t MaxOpsPerInst;
0081     /// The initial value of theis_stmtregister.
0082     uint8_t DefaultIsStmt;
0083     /// This parameter affects the meaning of the special opcodes. See below.
0084     int8_t LineBase;
0085     /// This parameter affects the meaning of the special opcodes. See below.
0086     uint8_t LineRange;
0087     /// The number assigned to the first special opcode.
0088     uint8_t OpcodeBase;
0089     /// This tracks which optional file format content types are present.
0090     ContentTypeTracker ContentTypes;
0091     std::vector<uint8_t> StandardOpcodeLengths;
0092     std::vector<DWARFFormValue> IncludeDirectories;
0093     std::vector<FileNameEntry> FileNames;
0094 
0095     const dwarf::FormParams getFormParams() const { return FormParams; }
0096     uint16_t getVersion() const { return FormParams.Version; }
0097     uint8_t getAddressSize() const { return FormParams.AddrSize; }
0098     bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; }
0099 
0100     uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; }
0101 
0102     uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; }
0103 
0104     bool totalLengthIsValid() const;
0105 
0106     /// Length of the prologue in bytes.
0107     uint64_t getLength() const;
0108 
0109     /// Get DWARF-version aware access to the file name entry at the provided
0110     /// index.
0111     const llvm::DWARFDebugLine::FileNameEntry &
0112     getFileNameEntry(uint64_t Index) const;
0113 
0114     bool hasFileAtIndex(uint64_t FileIndex) const;
0115 
0116     std::optional<uint64_t> getLastValidFileIndex() const;
0117 
0118     bool
0119     getFileNameByIndex(uint64_t FileIndex, StringRef CompDir,
0120                        DILineInfoSpecifier::FileLineInfoKind Kind,
0121                        std::string &Result,
0122                        sys::path::Style Style = sys::path::Style::native) const;
0123 
0124     void clear();
0125     void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
0126     Error parse(DWARFDataExtractor Data, uint64_t *OffsetPtr,
0127                 function_ref<void(Error)> RecoverableErrorHandler,
0128                 const DWARFContext &Ctx, const DWARFUnit *U = nullptr);
0129   };
0130 
0131   /// Standard .debug_line state machine structure.
0132   struct Row {
0133     explicit Row(bool DefaultIsStmt = false);
0134 
0135     /// Called after a row is appended to the matrix.
0136     void postAppend();
0137     void reset(bool DefaultIsStmt);
0138     void dump(raw_ostream &OS) const;
0139 
0140     static void dumpTableHeader(raw_ostream &OS, unsigned Indent);
0141 
0142     static bool orderByAddress(const Row &LHS, const Row &RHS) {
0143       return std::tie(LHS.Address.SectionIndex, LHS.Address.Address) <
0144              std::tie(RHS.Address.SectionIndex, RHS.Address.Address);
0145     }
0146 
0147     /// The program-counter value corresponding to a machine instruction
0148     /// generated by the compiler and section index pointing to the section
0149     /// containg this PC. If relocation information is present then section
0150     /// index is the index of the section which contains above address.
0151     /// Otherwise this is object::SectionedAddress::Undef value.
0152     object::SectionedAddress Address;
0153     /// An unsigned integer indicating a source line number. Lines are numbered
0154     /// beginning at 1. The compiler may emit the value 0 in cases where an
0155     /// instruction cannot be attributed to any source line.
0156     uint32_t Line;
0157     /// An unsigned integer indicating a column number within a source line.
0158     /// Columns are numbered beginning at 1. The value 0 is reserved to indicate
0159     /// that a statement begins at the 'left edge' of the line.
0160     uint16_t Column;
0161     /// An unsigned integer indicating the identity of the source file
0162     /// corresponding to a machine instruction.
0163     uint16_t File;
0164     /// An unsigned integer representing the DWARF path discriminator value
0165     /// for this location.
0166     uint32_t Discriminator;
0167     /// An unsigned integer whose value encodes the applicable instruction set
0168     /// architecture for the current instruction.
0169     uint8_t Isa;
0170     /// An unsigned integer representing the index of an operation within a
0171     /// VLIW instruction. The index of the first operation is 0.
0172     /// For non-VLIW architectures, this register will always be 0.
0173     uint8_t OpIndex;
0174     /// A boolean indicating that the current instruction is the beginning of a
0175     /// statement.
0176     uint8_t IsStmt : 1,
0177         /// A boolean indicating that the current instruction is the
0178         /// beginning of a basic block.
0179         BasicBlock : 1,
0180         /// A boolean indicating that the current address is that of the
0181         /// first byte after the end of a sequence of target machine
0182         /// instructions.
0183         EndSequence : 1,
0184         /// A boolean indicating that the current address is one (of possibly
0185         /// many) where execution should be suspended for an entry breakpoint
0186         /// of a function.
0187         PrologueEnd : 1,
0188         /// A boolean indicating that the current address is one (of possibly
0189         /// many) where execution should be suspended for an exit breakpoint
0190         /// of a function.
0191         EpilogueBegin : 1;
0192   };
0193 
0194   /// Represents a series of contiguous machine instructions. Line table for
0195   /// each compilation unit may consist of multiple sequences, which are not
0196   /// guaranteed to be in the order of ascending instruction address.
0197   struct Sequence {
0198     Sequence();
0199 
0200     /// Sequence describes instructions at address range [LowPC, HighPC)
0201     /// and is described by line table rows [FirstRowIndex, LastRowIndex).
0202     uint64_t LowPC;
0203     uint64_t HighPC;
0204     /// If relocation information is present then this is the index of the
0205     /// section which contains above addresses. Otherwise this is
0206     /// object::SectionedAddress::Undef value.
0207     uint64_t SectionIndex;
0208     unsigned FirstRowIndex;
0209     unsigned LastRowIndex;
0210     bool Empty;
0211 
0212     void reset();
0213 
0214     static bool orderByHighPC(const Sequence &LHS, const Sequence &RHS) {
0215       return std::tie(LHS.SectionIndex, LHS.HighPC) <
0216              std::tie(RHS.SectionIndex, RHS.HighPC);
0217     }
0218 
0219     bool isValid() const {
0220       return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex);
0221     }
0222 
0223     bool containsPC(object::SectionedAddress PC) const {
0224       return SectionIndex == PC.SectionIndex &&
0225              (LowPC <= PC.Address && PC.Address < HighPC);
0226     }
0227   };
0228 
0229   struct LineTable {
0230     LineTable();
0231 
0232     /// Represents an invalid row
0233     const uint32_t UnknownRowIndex = UINT32_MAX;
0234 
0235     void appendRow(const DWARFDebugLine::Row &R) { Rows.push_back(R); }
0236 
0237     void appendSequence(const DWARFDebugLine::Sequence &S) {
0238       Sequences.push_back(S);
0239     }
0240 
0241     /// Returns the index of the row with file/line info for a given address,
0242     /// or UnknownRowIndex if there is no such row.
0243     uint32_t lookupAddress(object::SectionedAddress Address,
0244                            bool *IsApproximateLine = nullptr) const;
0245 
0246     bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size,
0247                             std::vector<uint32_t> &Result) const;
0248 
0249     bool hasFileAtIndex(uint64_t FileIndex) const {
0250       return Prologue.hasFileAtIndex(FileIndex);
0251     }
0252 
0253     std::optional<uint64_t> getLastValidFileIndex() const {
0254       return Prologue.getLastValidFileIndex();
0255     }
0256 
0257     /// Extracts filename by its index in filename table in prologue.
0258     /// In Dwarf 4, the files are 1-indexed and the current compilation file
0259     /// name is not represented in the list. In DWARF v5, the files are
0260     /// 0-indexed and the primary source file has the index 0.
0261     /// Returns true on success.
0262     bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir,
0263                             DILineInfoSpecifier::FileLineInfoKind Kind,
0264                             std::string &Result) const {
0265       return Prologue.getFileNameByIndex(FileIndex, CompDir, Kind, Result);
0266     }
0267 
0268     /// Fills the Result argument with the file and line information
0269     /// corresponding to Address. Returns true on success.
0270     bool getFileLineInfoForAddress(object::SectionedAddress Address,
0271                                    bool Approximate, const char *CompDir,
0272                                    DILineInfoSpecifier::FileLineInfoKind Kind,
0273                                    DILineInfo &Result) const;
0274 
0275     /// Extracts directory name by its Entry in include directories table
0276     /// in prologue. Returns true on success.
0277     bool getDirectoryForEntry(const FileNameEntry &Entry,
0278                               std::string &Directory) const;
0279 
0280     void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
0281     void clear();
0282 
0283     /// Parse prologue and all rows.
0284     Error parse(DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
0285                 const DWARFContext &Ctx, const DWARFUnit *U,
0286                 function_ref<void(Error)> RecoverableErrorHandler,
0287                 raw_ostream *OS = nullptr, bool Verbose = false);
0288 
0289     using RowVector = std::vector<Row>;
0290     using RowIter = RowVector::const_iterator;
0291     using SequenceVector = std::vector<Sequence>;
0292     using SequenceIter = SequenceVector::const_iterator;
0293 
0294     struct Prologue Prologue;
0295     RowVector Rows;
0296     SequenceVector Sequences;
0297 
0298   private:
0299     uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq,
0300                           object::SectionedAddress Address) const;
0301     std::optional<StringRef>
0302     getSourceByIndex(uint64_t FileIndex,
0303                      DILineInfoSpecifier::FileLineInfoKind Kind) const;
0304 
0305     uint32_t lookupAddressImpl(object::SectionedAddress Address,
0306                                bool *IsApproximateLine = nullptr) const;
0307 
0308     bool lookupAddressRangeImpl(object::SectionedAddress Address, uint64_t Size,
0309                                 std::vector<uint32_t> &Result) const;
0310   };
0311 
0312   const LineTable *getLineTable(uint64_t Offset) const;
0313   Expected<const LineTable *>
0314   getOrParseLineTable(DWARFDataExtractor &DebugLineData, uint64_t Offset,
0315                       const DWARFContext &Ctx, const DWARFUnit *U,
0316                       function_ref<void(Error)> RecoverableErrorHandler);
0317   void clearLineTable(uint64_t Offset);
0318 
0319   /// Helper to allow for parsing of an entire .debug_line section in sequence.
0320   class SectionParser {
0321   public:
0322     using LineToUnitMap = std::map<uint64_t, DWARFUnit *>;
0323 
0324     SectionParser(DWARFDataExtractor &Data, const DWARFContext &C,
0325                   DWARFUnitVector::iterator_range Units);
0326 
0327     /// Get the next line table from the section. Report any issues via the
0328     /// handlers.
0329     ///
0330     /// \param RecoverableErrorHandler - any issues that don't prevent further
0331     /// parsing of the table will be reported through this handler.
0332     /// \param UnrecoverableErrorHandler - any issues that prevent further
0333     /// parsing of the table will be reported through this handler.
0334     /// \param OS - if not null, the parser will print information about the
0335     /// table as it parses it.
0336     /// \param Verbose - if true, the parser will print verbose information when
0337     /// printing to the output.
0338     LineTable parseNext(function_ref<void(Error)> RecoverableErrorHandler,
0339                         function_ref<void(Error)> UnrecoverableErrorHandler,
0340                         raw_ostream *OS = nullptr, bool Verbose = false);
0341 
0342     /// Skip the current line table and go to the following line table (if
0343     /// present) immediately.
0344     ///
0345     /// \param RecoverableErrorHandler - report any recoverable prologue
0346     /// parsing issues via this handler.
0347     /// \param UnrecoverableErrorHandler - report any unrecoverable prologue
0348     /// parsing issues via this handler.
0349     void skip(function_ref<void(Error)> RecoverableErrorHandler,
0350               function_ref<void(Error)> UnrecoverableErrorHandler);
0351 
0352     /// Indicates if the parser has parsed as much as possible.
0353     ///
0354     /// \note Certain problems with the line table structure might mean that
0355     /// parsing stops before the end of the section is reached.
0356     bool done() const { return Done; }
0357 
0358     /// Get the offset the parser has reached.
0359     uint64_t getOffset() const { return Offset; }
0360 
0361   private:
0362     DWARFUnit *prepareToParse(uint64_t Offset);
0363     void moveToNextTable(uint64_t OldOffset, const Prologue &P);
0364     bool hasValidVersion(uint64_t Offset);
0365 
0366     LineToUnitMap LineToUnit;
0367 
0368     DWARFDataExtractor &DebugLineData;
0369     const DWARFContext &Context;
0370     uint64_t Offset = 0;
0371     bool Done = false;
0372   };
0373 
0374 private:
0375   struct ParsingState {
0376     ParsingState(struct LineTable *LT, uint64_t TableOffset,
0377                  function_ref<void(Error)> ErrorHandler);
0378 
0379     void resetRowAndSequence();
0380     void appendRowToMatrix();
0381 
0382     struct AddrOpIndexDelta {
0383       uint64_t AddrOffset;
0384       int16_t OpIndexDelta;
0385     };
0386 
0387     /// Advance the address and op-index by the \p OperationAdvance value.
0388     /// \returns the amount advanced by.
0389     AddrOpIndexDelta advanceAddrOpIndex(uint64_t OperationAdvance,
0390                                         uint8_t Opcode, uint64_t OpcodeOffset);
0391 
0392     struct OpcodeAdvanceResults {
0393       uint64_t AddrDelta;
0394       int16_t OpIndexDelta;
0395       uint8_t AdjustedOpcode;
0396     };
0397 
0398     /// Advance the address and op-index as required by the specified \p Opcode.
0399     /// \returns the amount advanced by and the calculated adjusted opcode.
0400     OpcodeAdvanceResults advanceForOpcode(uint8_t Opcode,
0401                                           uint64_t OpcodeOffset);
0402 
0403     struct SpecialOpcodeDelta {
0404       uint64_t Address;
0405       int32_t Line;
0406       int16_t OpIndex;
0407     };
0408 
0409     /// Advance the line, address and op-index as required by the specified
0410     /// special \p Opcode. \returns the address, op-index and line delta.
0411     SpecialOpcodeDelta handleSpecialOpcode(uint8_t Opcode,
0412                                            uint64_t OpcodeOffset);
0413 
0414     /// Line table we're currently parsing.
0415     struct LineTable *LineTable;
0416     struct Row Row;
0417     struct Sequence Sequence;
0418 
0419   private:
0420     uint64_t LineTableOffset;
0421 
0422     bool ReportAdvanceAddrProblem = true;
0423     bool ReportBadLineRange = true;
0424     function_ref<void(Error)> ErrorHandler;
0425   };
0426 
0427   using LineTableMapTy = std::map<uint64_t, LineTable>;
0428   using LineTableIter = LineTableMapTy::iterator;
0429   using LineTableConstIter = LineTableMapTy::const_iterator;
0430 
0431   LineTableMapTy LineTableMap;
0432 };
0433 
0434 } // end namespace llvm
0435 
0436 #endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGLINE_H