Home | History | Annotate | Download | only in DWARF
      1 //===- DWARFDebugLine.h -----------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H
     11 #define LLVM_DEBUGINFO_DWARFDEBUGLINE_H
     12 
     13 #include "llvm/ADT/Optional.h"
     14 #include "llvm/ADT/StringRef.h"
     15 #include "llvm/DebugInfo/DIContext.h"
     16 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
     17 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
     18 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
     19 #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
     20 #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
     21 #include "llvm/Support/MD5.h"
     22 #include <cstdint>
     23 #include <map>
     24 #include <string>
     25 #include <vector>
     26 
     27 namespace llvm {
     28 
     29 class DWARFUnit;
     30 class raw_ostream;
     31 
     32 class DWARFDebugLine {
     33 public:
     34   struct FileNameEntry {
     35     FileNameEntry() = default;
     36 
     37     DWARFFormValue Name;
     38     uint64_t DirIdx = 0;
     39     uint64_t ModTime = 0;
     40     uint64_t Length = 0;
     41     MD5::MD5Result Checksum;
     42     DWARFFormValue Source;
     43   };
     44 
     45   /// Tracks which optional content types are present in a DWARF file name
     46   /// entry format.
     47   struct ContentTypeTracker {
     48     ContentTypeTracker() = default;
     49 
     50     /// Whether filename entries provide a modification timestamp.
     51     bool HasModTime = false;
     52     /// Whether filename entries provide a file size.
     53     bool HasLength = false;
     54     /// For v5, whether filename entries provide an MD5 checksum.
     55     bool HasMD5 = false;
     56     /// For v5, whether filename entries provide source text.
     57     bool HasSource = false;
     58 
     59     /// Update tracked content types with \p ContentType.
     60     void trackContentType(dwarf::LineNumberEntryFormat ContentType);
     61   };
     62 
     63   struct Prologue {
     64     Prologue();
     65 
     66     /// The size in bytes of the statement information for this compilation unit
     67     /// (not including the total_length field itself).
     68     uint64_t TotalLength;
     69     /// Version, address size (starting in v5), and DWARF32/64 format; these
     70     /// parameters affect interpretation of forms (used in the directory and
     71     /// file tables starting with v5).
     72     dwarf::FormParams FormParams;
     73     /// The number of bytes following the prologue_length field to the beginning
     74     /// of the first byte of the statement program itself.
     75     uint64_t PrologueLength;
     76     /// In v5, size in bytes of a segment selector.
     77     uint8_t SegSelectorSize;
     78     /// The size in bytes of the smallest target machine instruction. Statement
     79     /// program opcodes that alter the address register first multiply their
     80     /// operands by this value.
     81     uint8_t MinInstLength;
     82     /// The maximum number of individual operations that may be encoded in an
     83     /// instruction.
     84     uint8_t MaxOpsPerInst;
     85     /// The initial value of theis_stmtregister.
     86     uint8_t DefaultIsStmt;
     87     /// This parameter affects the meaning of the special opcodes. See below.
     88     int8_t LineBase;
     89     /// This parameter affects the meaning of the special opcodes. See below.
     90     uint8_t LineRange;
     91     /// The number assigned to the first special opcode.
     92     uint8_t OpcodeBase;
     93     /// This tracks which optional file format content types are present.
     94     ContentTypeTracker ContentTypes;
     95     std::vector<uint8_t> StandardOpcodeLengths;
     96     std::vector<DWARFFormValue> IncludeDirectories;
     97     std::vector<FileNameEntry> FileNames;
     98 
     99     const dwarf::FormParams getFormParams() const { return FormParams; }
    100     uint16_t getVersion() const { return FormParams.Version; }
    101     uint8_t getAddressSize() const { return FormParams.AddrSize; }
    102     bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; }
    103 
    104     uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; }
    105 
    106     uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; }
    107 
    108     bool totalLengthIsValid() const;
    109 
    110     /// Length of the prologue in bytes.
    111     uint32_t getLength() const {
    112       return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) +
    113              sizeofPrologueLength();
    114     }
    115 
    116     /// Length of the line table data in bytes (not including the prologue).
    117     uint32_t getStatementTableLength() const {
    118       return TotalLength + sizeofTotalLength() - getLength();
    119     }
    120 
    121     int32_t getMaxLineIncrementForSpecialOpcode() const {
    122       return LineBase + (int8_t)LineRange - 1;
    123     }
    124 
    125     void clear();
    126     void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
    127     Error parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
    128                 const DWARFContext &Ctx, const DWARFUnit *U = nullptr);
    129   };
    130 
    131   /// Standard .debug_line state machine structure.
    132   struct Row {
    133     explicit Row(bool DefaultIsStmt = false);
    134 
    135     /// Called after a row is appended to the matrix.
    136     void postAppend();
    137     void reset(bool DefaultIsStmt);
    138     void dump(raw_ostream &OS) const;
    139 
    140     static void dumpTableHeader(raw_ostream &OS);
    141 
    142     static bool orderByAddress(const Row &LHS, const Row &RHS) {
    143       return LHS.Address < RHS.Address;
    144     }
    145 
    146     /// The program-counter value corresponding to a machine instruction
    147     /// generated by the compiler.
    148     uint64_t Address;
    149     /// An unsigned integer indicating a source line number. Lines are numbered
    150     /// beginning at 1. The compiler may emit the value 0 in cases where an
    151     /// instruction cannot be attributed to any source line.
    152     uint32_t Line;
    153     /// An unsigned integer indicating a column number within a source line.
    154     /// Columns are numbered beginning at 1. The value 0 is reserved to indicate
    155     /// that a statement begins at the 'left edge' of the line.
    156     uint16_t Column;
    157     /// An unsigned integer indicating the identity of the source file
    158     /// corresponding to a machine instruction.
    159     uint16_t File;
    160     /// An unsigned integer representing the DWARF path discriminator value
    161     /// for this location.
    162     uint32_t Discriminator;
    163     /// An unsigned integer whose value encodes the applicable instruction set
    164     /// architecture for the current instruction.
    165     uint8_t Isa;
    166     /// A boolean indicating that the current instruction is the beginning of a
    167     /// statement.
    168     uint8_t IsStmt : 1,
    169         /// A boolean indicating that the current instruction is the
    170         /// beginning of a basic block.
    171         BasicBlock : 1,
    172         /// A boolean indicating that the current address is that of the
    173         /// first byte after the end of a sequence of target machine
    174         /// instructions.
    175         EndSequence : 1,
    176         /// A boolean indicating that the current address is one (of possibly
    177         /// many) where execution should be suspended for an entry breakpoint
    178         /// of a function.
    179         PrologueEnd : 1,
    180         /// A boolean indicating that the current address is one (of possibly
    181         /// many) where execution should be suspended for an exit breakpoint
    182         /// of a function.
    183         EpilogueBegin : 1;
    184   };
    185 
    186   /// Represents a series of contiguous machine instructions. Line table for
    187   /// each compilation unit may consist of multiple sequences, which are not
    188   /// guaranteed to be in the order of ascending instruction address.
    189   struct Sequence {
    190     Sequence();
    191 
    192     /// Sequence describes instructions at address range [LowPC, HighPC)
    193     /// and is described by line table rows [FirstRowIndex, LastRowIndex).
    194     uint64_t LowPC;
    195     uint64_t HighPC;
    196     unsigned FirstRowIndex;
    197     unsigned LastRowIndex;
    198     bool Empty;
    199 
    200     void reset();
    201 
    202     static bool orderByLowPC(const Sequence &LHS, const Sequence &RHS) {
    203       return LHS.LowPC < RHS.LowPC;
    204     }
    205 
    206     bool isValid() const {
    207       return !Empty && (LowPC < HighPC) && (FirstRowIndex < LastRowIndex);
    208     }
    209 
    210     bool containsPC(uint64_t PC) const { return (LowPC <= PC && PC < HighPC); }
    211   };
    212 
    213   struct LineTable {
    214     LineTable();
    215 
    216     /// Represents an invalid row
    217     const uint32_t UnknownRowIndex = UINT32_MAX;
    218 
    219     void appendRow(const DWARFDebugLine::Row &R) { Rows.push_back(R); }
    220 
    221     void appendSequence(const DWARFDebugLine::Sequence &S) {
    222       Sequences.push_back(S);
    223     }
    224 
    225     /// Returns the index of the row with file/line info for a given address,
    226     /// or UnknownRowIndex if there is no such row.
    227     uint32_t lookupAddress(uint64_t Address) const;
    228 
    229     bool lookupAddressRange(uint64_t Address, uint64_t Size,
    230                             std::vector<uint32_t> &Result) const;
    231 
    232     bool hasFileAtIndex(uint64_t FileIndex) const;
    233 
    234     /// Extracts filename by its index in filename table in prologue.
    235     /// Returns true on success.
    236     bool getFileNameByIndex(uint64_t FileIndex, const char *CompDir,
    237                             DILineInfoSpecifier::FileLineInfoKind Kind,
    238                             std::string &Result) const;
    239 
    240     /// Fills the Result argument with the file and line information
    241     /// corresponding to Address. Returns true on success.
    242     bool getFileLineInfoForAddress(uint64_t Address, const char *CompDir,
    243                                    DILineInfoSpecifier::FileLineInfoKind Kind,
    244                                    DILineInfo &Result) const;
    245 
    246     void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
    247     void clear();
    248 
    249     /// Parse prologue and all rows.
    250     Error parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
    251                 const DWARFContext &Ctx, const DWARFUnit *U,
    252                 std::function<void(Error)> RecoverableErrorCallback = warn,
    253                 raw_ostream *OS = nullptr);
    254 
    255     using RowVector = std::vector<Row>;
    256     using RowIter = RowVector::const_iterator;
    257     using SequenceVector = std::vector<Sequence>;
    258     using SequenceIter = SequenceVector::const_iterator;
    259 
    260     struct Prologue Prologue;
    261     RowVector Rows;
    262     SequenceVector Sequences;
    263 
    264   private:
    265     uint32_t findRowInSeq(const DWARFDebugLine::Sequence &Seq,
    266                           uint64_t Address) const;
    267     Optional<StringRef>
    268     getSourceByIndex(uint64_t FileIndex,
    269                      DILineInfoSpecifier::FileLineInfoKind Kind) const;
    270   };
    271 
    272   const LineTable *getLineTable(uint32_t Offset) const;
    273   Expected<const LineTable *> getOrParseLineTable(
    274       DWARFDataExtractor &DebugLineData, uint32_t Offset,
    275       const DWARFContext &Ctx, const DWARFUnit *U,
    276       std::function<void(Error)> RecoverableErrorCallback = warn);
    277 
    278   /// Helper to allow for parsing of an entire .debug_line section in sequence.
    279   class SectionParser {
    280   public:
    281     using cu_range = DWARFUnitSection<DWARFCompileUnit>::iterator_range;
    282     using tu_range =
    283         iterator_range<std::deque<DWARFUnitSection<DWARFTypeUnit>>::iterator>;
    284     using LineToUnitMap = std::map<uint64_t, DWARFUnit *>;
    285 
    286     SectionParser(DWARFDataExtractor &Data, const DWARFContext &C, cu_range CUs,
    287                   tu_range TUs);
    288 
    289     /// Get the next line table from the section. Report any issues via the
    290     /// callbacks.
    291     ///
    292     /// \param RecoverableErrorCallback - any issues that don't prevent further
    293     /// parsing of the table will be reported through this callback.
    294     /// \param UnrecoverableErrorCallback - any issues that prevent further
    295     /// parsing of the table will be reported through this callback.
    296     /// \param OS - if not null, the parser will print information about the
    297     /// table as it parses it.
    298     LineTable
    299     parseNext(function_ref<void(Error)> RecoverableErrorCallback = warn,
    300               function_ref<void(Error)> UnrecoverableErrorCallback = warn,
    301               raw_ostream *OS = nullptr);
    302 
    303     /// Skip the current line table and go to the following line table (if
    304     /// present) immediately.
    305     ///
    306     /// \param ErrorCallback - report any prologue parsing issues via this
    307     /// callback.
    308     void skip(function_ref<void(Error)> ErrorCallback = warn);
    309 
    310     /// Indicates if the parser has parsed as much as possible.
    311     ///
    312     /// \note Certain problems with the line table structure might mean that
    313     /// parsing stops before the end of the section is reached.
    314     bool done() const { return Done; }
    315 
    316     /// Get the offset the parser has reached.
    317     uint32_t getOffset() const { return Offset; }
    318 
    319   private:
    320     DWARFUnit *prepareToParse(uint32_t Offset);
    321     void moveToNextTable(uint32_t OldOffset, const Prologue &P);
    322 
    323     LineToUnitMap LineToUnit;
    324 
    325     DWARFDataExtractor &DebugLineData;
    326     const DWARFContext &Context;
    327     uint32_t Offset = 0;
    328     bool Done = false;
    329   };
    330 
    331   /// Helper function for DWARFDebugLine parse functions, to report issues
    332   /// identified during parsing.
    333   ///
    334   /// \param Err The Error to report.
    335   static void warn(Error Err);
    336 
    337 private:
    338   struct ParsingState {
    339     ParsingState(struct LineTable *LT);
    340 
    341     void resetRowAndSequence();
    342     void appendRowToMatrix(uint32_t Offset);
    343 
    344     /// Line table we're currently parsing.
    345     struct LineTable *LineTable;
    346     /// The row number that starts at zero for the prologue, and increases for
    347     /// each row added to the matrix.
    348     unsigned RowNumber = 0;
    349     struct Row Row;
    350     struct Sequence Sequence;
    351   };
    352 
    353   using LineTableMapTy = std::map<uint32_t, LineTable>;
    354   using LineTableIter = LineTableMapTy::iterator;
    355   using LineTableConstIter = LineTableMapTy::const_iterator;
    356 
    357   LineTableMapTy LineTableMap;
    358 };
    359 
    360 } // end namespace llvm
    361 
    362 #endif // LLVM_DEBUGINFO_DWARFDEBUGLINE_H
    363