xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- LVBinaryReader.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the LVBinaryReader class, which is used to describe a
10 // binary reader.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H
15 #define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H
16 
17 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
18 #include "llvm/MC/MCAsmInfo.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
21 #include "llvm/MC/MCInstPrinter.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCObjectFileInfo.h"
24 #include "llvm/MC/MCRegisterInfo.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/MC/TargetRegistry.h"
27 #include "llvm/Object/COFF.h"
28 #include "llvm/Object/ObjectFile.h"
29 
30 namespace llvm {
31 namespace logicalview {
32 
33 constexpr bool UpdateHighAddress = false;
34 
35 // Logical scope, Section address, Section index, IsComdat.
36 struct LVSymbolTableEntry final {
37   LVScope *Scope = nullptr;
38   LVAddress Address = 0;
39   LVSectionIndex SectionIndex = 0;
40   bool IsComdat = false;
41   LVSymbolTableEntry() = default;
LVSymbolTableEntryfinal42   LVSymbolTableEntry(LVScope *Scope, LVAddress Address,
43                      LVSectionIndex SectionIndex, bool IsComdat)
44       : Scope(Scope), Address(Address), SectionIndex(SectionIndex),
45         IsComdat(IsComdat) {}
46 };
47 
48 // Function names extracted from the object symbol table.
49 class LVSymbolTable final {
50   using LVSymbolNames = std::map<std::string, LVSymbolTableEntry>;
51   LVSymbolNames SymbolNames;
52 
53 public:
54   LVSymbolTable() = default;
55 
56   void add(StringRef Name, LVScope *Function, LVSectionIndex SectionIndex = 0);
57   void add(StringRef Name, LVAddress Address, LVSectionIndex SectionIndex,
58            bool IsComdat);
59   LVSectionIndex update(LVScope *Function);
60 
61   const LVSymbolTableEntry &getEntry(StringRef Name);
62   LVAddress getAddress(StringRef Name);
63   LVSectionIndex getIndex(StringRef Name);
64   bool getIsComdat(StringRef Name);
65 
66   void print(raw_ostream &OS);
67 };
68 
69 class LVBinaryReader : public LVReader {
70   // Function names extracted from the object symbol table.
71   LVSymbolTable SymbolTable;
72 
73   // It contains the LVLineDebug elements representing the inlined logical
74   // lines for the current compile unit, created by parsing the CodeView
75   // S_INLINESITE symbol annotation data.
76   using LVInlineeLine = std::map<LVScope *, std::unique_ptr<LVLines>>;
77   LVInlineeLine CUInlineeLines;
78 
79   // Instruction lines for a logical scope. These instructions are fetched
80   // during its merge with the debug lines.
81   LVDoubleMap<LVSectionIndex, LVScope *, LVLines *> ScopeInstructions;
82 
83   // Links the scope with its first assembler address line.
84   LVDoubleMap<LVSectionIndex, LVAddress, LVScope *> AssemblerMappings;
85 
86   // Mapping from virtual address to section.
87   // The virtual address refers to the address where the section is loaded.
88   using LVSectionAddresses = std::map<LVSectionIndex, object::SectionRef>;
89   LVSectionAddresses SectionAddresses;
90 
addSectionAddress(const object::SectionRef & Section)91   void addSectionAddress(const object::SectionRef &Section) {
92     if (SectionAddresses.find(Section.getAddress()) == SectionAddresses.end())
93       SectionAddresses.emplace(Section.getAddress(), Section);
94   }
95 
96   // Scopes with ranges for current compile unit. It is used to find a line
97   // giving its exact or closest address. To support comdat functions, all
98   // addresses for the same section are recorded in the same map.
99   using LVSectionRanges = std::map<LVSectionIndex, std::unique_ptr<LVRange>>;
100   LVSectionRanges SectionRanges;
101 
102   // Image base and virtual address for Executable file.
103   uint64_t ImageBaseAddress = 0;
104   uint64_t VirtualAddress = 0;
105 
106   // Object sections with machine code.
107   using LVSections = std::map<LVSectionIndex, object::SectionRef>;
108   LVSections Sections;
109 
110   std::vector<std::unique_ptr<LVLines>> DiscoveredLines;
111 
112 protected:
113   // It contains the LVLineDebug elements representing the logical lines for
114   // the current compile unit, created by parsing the debug line section.
115   LVLines CULines;
116 
117   std::unique_ptr<const MCRegisterInfo> MRI;
118   std::unique_ptr<const MCAsmInfo> MAI;
119   std::unique_ptr<const MCSubtargetInfo> STI;
120   std::unique_ptr<const MCInstrInfo> MII;
121   std::unique_ptr<const MCDisassembler> MD;
122   std::unique_ptr<MCContext> MC;
123   std::unique_ptr<MCInstPrinter> MIP;
124 
125   // https://yurydelendik.github.io/webassembly-dwarf/
126   // 2. Consuming and Generating DWARF for WebAssembly Code
127   // Note: Some DWARF constructs don't map one-to-one onto WebAssembly
128   // constructs. We strive to enumerate and resolve any ambiguities here.
129   //
130   // 2.1. Code Addresses
131   // Note: DWARF associates various bits of debug info
132   // with particular locations in the program via its code address (instruction
133   // pointer or PC). However, WebAssembly's linear memory address space does not
134   // contain WebAssembly instructions.
135   //
136   // Wherever a code address (see 2.17 of [DWARF]) is used in DWARF for
137   // WebAssembly, it must be the offset of an instruction relative within the
138   // Code section of the WebAssembly file. The DWARF is considered malformed if
139   // a PC offset is between instruction boundaries within the Code section.
140   //
141   // Note: It is expected that a DWARF consumer does not know how to decode
142   // WebAssembly instructions. The instruction pointer is selected as the offset
143   // in the binary file of the first byte of the instruction, and it is
144   // consistent with the WebAssembly Web API conventions definition of the code
145   // location.
146   //
147   // EXAMPLE: .DEBUG_LINE INSTRUCTION POINTERS
148   // The .debug_line DWARF section maps instruction pointers to source
149   // locations. With WebAssembly, the .debug_line section maps Code
150   // section-relative instruction offsets to source locations.
151   //
152   // EXAMPLE: DW_AT_* ATTRIBUTES
153   // For entities with a single associated code address, DWARF uses
154   // the DW_AT_low_pc attribute to specify the associated code address value.
155   // For WebAssembly, the DW_AT_low_pc's value is a Code section-relative
156   // instruction offset.
157   //
158   // For entities with a single contiguous range of code, DWARF uses a
159   // pair of DW_AT_low_pc and DW_AT_high_pc attributes to specify the associated
160   // contiguous range of code address values. For WebAssembly, these attributes
161   // are Code section-relative instruction offsets.
162   //
163   // For entities with multiple ranges of code, DWARF uses the DW_AT_ranges
164   // attribute, which refers to the array located at the .debug_ranges section.
165   LVAddress WasmCodeSectionOffset = 0;
166 
167   // Loads all info for the architecture of the provided object file.
168   Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures);
169 
mapRangeAddress(const object::ObjectFile & Obj)170   virtual void mapRangeAddress(const object::ObjectFile &Obj) {}
mapRangeAddress(const object::ObjectFile & Obj,const object::SectionRef & Section,bool IsComdat)171   virtual void mapRangeAddress(const object::ObjectFile &Obj,
172                                const object::SectionRef &Section,
173                                bool IsComdat) {}
174 
175   // Create a mapping from virtual address to section.
176   void mapVirtualAddress(const object::ObjectFile &Obj);
177   void mapVirtualAddress(const object::COFFObjectFile &COFFObj);
178 
179   Expected<std::pair<LVSectionIndex, object::SectionRef>>
180   getSection(LVScope *Scope, LVAddress Address, LVSectionIndex SectionIndex);
181 
182   void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope);
183   void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,
184                        LVAddress LowerAddress, LVAddress UpperAddress);
185   LVRange *getSectionRanges(LVSectionIndex SectionIndex);
186 
187   void includeInlineeLines(LVSectionIndex SectionIndex, LVScope *Function);
188 
189   Error createInstructions();
190   Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex);
191   Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex,
192                            const LVNameInfo &NameInfo);
193 
194   void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex);
195   void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex,
196                     LVScope *Function);
197 
198 public:
199   LVBinaryReader() = delete;
LVBinaryReader(StringRef Filename,StringRef FileFormatName,ScopedPrinter & W,LVBinaryType BinaryType)200   LVBinaryReader(StringRef Filename, StringRef FileFormatName, ScopedPrinter &W,
201                  LVBinaryType BinaryType)
202       : LVReader(Filename, FileFormatName, W, BinaryType) {}
203   LVBinaryReader(const LVBinaryReader &) = delete;
204   LVBinaryReader &operator=(const LVBinaryReader &) = delete;
205   virtual ~LVBinaryReader() = default;
206 
addInlineeLines(LVScope * Scope,LVLines & Lines)207   void addInlineeLines(LVScope *Scope, LVLines &Lines) {
208     CUInlineeLines.emplace(Scope, std::make_unique<LVLines>(std::move(Lines)));
209   }
210 
211   // Convert Segment::Offset pair to absolute address.
212   LVAddress linearAddress(uint16_t Segment, uint32_t Offset,
213                           LVAddress Addendum = 0) {
214     return ImageBaseAddress + (Segment * VirtualAddress) + Offset + Addendum;
215   }
216 
217   void addToSymbolTable(StringRef Name, LVScope *Function,
218                         LVSectionIndex SectionIndex = 0);
219   void addToSymbolTable(StringRef Name, LVAddress Address,
220                         LVSectionIndex SectionIndex, bool IsComdat);
221   LVSectionIndex updateSymbolTable(LVScope *Function);
222 
223   const LVSymbolTableEntry &getSymbolTableEntry(StringRef Name);
224   LVAddress getSymbolTableAddress(StringRef Name);
225   LVSectionIndex getSymbolTableIndex(StringRef Name);
226   bool getSymbolTableIsComdat(StringRef Name);
227 
getSectionIndex(LVScope * Scope)228   LVSectionIndex getSectionIndex(LVScope *Scope) override {
229     return Scope ? getSymbolTableIndex(Scope->getLinkageName())
230                  : DotTextSectionIndex;
231   }
232 
233   void print(raw_ostream &OS) const;
234 
235 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump()236   void dump() const { print(dbgs()); }
237 #endif
238 };
239 
240 } // end namespace logicalview
241 } // end namespace llvm
242 
243 #endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H
244