//===- LineTable.h ----------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_DEBUGINFO_GSYM_LINETABLE_H #define LLVM_DEBUGINFO_GSYM_LINETABLE_H #include "llvm/DebugInfo/GSYM/LineEntry.h" #include "llvm/Support/Error.h" #include <cstdint> #include <vector> namespace llvm { namespace gsym { struct FunctionInfo; class FileWriter; /// LineTable class contains deserialized versions of line tables for each /// function's address ranges. /// /// When saved to disk, the line table is encoded using a modified version of /// the DWARF line tables that only tracks address to source file and line. /// /// ENCODING /// /// The line table starts with a small prolog that contains the following /// values: /// /// ENCODING NAME DESCRIPTION /// ======== =========== ==================================================== /// SLEB MinDelta The min line delta for special opcodes that advance /// the address and line number. /// SLEB MaxDelta The max line delta for single byte opcodes that /// advance the address and line number. /// ULEB FirstLine The value of the first source line number to /// initialize the LineEntry with. /// /// Once these prolog items are read, we initialize a LineEntry struct with /// the start address of the function from the FunctionInfo's address range, /// a default file index of 1, and the line number set to "FirstLine" from /// the prolog above: /// /// LineEntry Row(BaseAddr, 1, FirstLine); /// /// The line table state machine is now initialized and ready to be parsed. /// The stream that follows this encodes the line entries in a compact /// form. Some opcodes cause "Row" to be modified and some opcodes may also /// push "Row" onto the end of the "LineTable.Lines" vector. The end result /// is a vector of LineEntry structs that is sorted in ascending address /// order. /// /// NORMAL OPCODES /// /// The opcodes 0 through 3 are normal in opcodes. Their encoding and /// descriptions are listed below: /// /// ENCODING ENUMERATION VALUE DESCRIPTION /// ======== ================ ===== ======================================== /// LTOC_EndSequence 0x00 Parsing is done. /// ULEB LTOC_SetFile 0x01 Row.File = ULEB /// ULEB LTOC_AdvancePC 0x02 Row.Addr += ULEB, push "Row". /// SLEB LTOC_AdvanceLine 0x03 Row.Line += SLEB /// LTOC_FirstSpecial 0x04 First special opcode (see SPECIAL /// OPCODES below). /// /// SPECIAL OPCODES /// /// Opcodes LTOC_FirstSpecial through 255 are special opcodes that always /// increment both the Row.Addr and Row.Line and push "Row" onto the /// LineEntry.Lines array. They do this by using some of the bits to /// increment/decrement the source line number, and some of the bits to /// increment the address. Line numbers can go up or down when making line /// tables, where addresses always only increase since line tables are sorted /// by address. /// /// In order to calculate the amount to increment the line and address for /// these special opcodes, we calculate the number of values reserved for the /// line increment/decrement using the "MinDelta" and "MaxDelta" from the /// prolog: /// /// const int64_t LineRange = MaxDelta - MinDelta + 1; /// /// Then we can adjust the opcode to not include any of the normal opcodes: /// /// const uint8_t AdjustedOp = Opcode - LTOC_FirstSpecial; /// /// And we can calculate the line offset, and address offset: /// /// const int64_t LineDelta = MinDelta + (AdjustedOp % LineRange); /// const uint64_t AddrDelta = (AdjustedOp / LineRange); /// /// And use these to modify our "Row": /// /// Row.Line += LineDelta; /// Row.Addr += AddrDelta; /// /// And push a row onto the line table: /// /// Lines.push_back(Row); /// /// This is verify similar to the way that DWARF encodes its line tables. The /// only difference is the DWARF line tables have more normal opcodes and the /// "Row" contains more members, like source column number, bools for end of /// prologue, beginnging of epilogue, is statement and many others. There are /// also more complex rules that happen for the extra normal opcodes. By /// leaving these extra opcodes out, we leave more bits for the special /// opcodes that allows us to encode line tables in fewer bytes than standard /// DWARF encodings. /// /// Opcodes that will push "Row" onto the LineEntry.Lines include the /// LTOC_AdvancePC opcode and all special opcodes. All other opcodes /// only modify the current "Row", or cause the line table to end. class LineTable { … }; raw_ostream &operator<<(raw_ostream &OS, const gsym::LineTable <); } // namespace gsym } // namespace llvm #endif // LLVM_DEBUGINFO_GSYM_LINETABLE_H