1 //===- bolt/Rewrite/DWARFRewriter.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 #ifndef BOLT_REWRITE_DWARF_REWRITER_H 10 #define BOLT_REWRITE_DWARF_REWRITER_H 11 12 #include "bolt/Core/DebugData.h" 13 #include "llvm/MC/MCAsmLayout.h" 14 #include <cstdint> 15 #include <memory> 16 #include <mutex> 17 #include <set> 18 #include <unordered_map> 19 #include <unordered_set> 20 #include <vector> 21 22 namespace llvm { 23 24 namespace bolt { 25 26 class BinaryContext; 27 28 class DWARFRewriter { 29 public: 30 DWARFRewriter() = delete; 31 using DebugTypesSignaturesPerCUMap = 32 std::unordered_map<uint64_t, std::unordered_set<uint64_t>>; 33 34 private: 35 BinaryContext &BC; 36 37 std::mutex DebugInfoPatcherMutex; 38 39 /// Stores and serializes information that will be put into the 40 /// .debug_ranges DWARF section. 41 std::unique_ptr<DebugRangesSectionWriter> LegacyRangesSectionWriter; 42 43 /// Stores and serializes information that will be put into the 44 /// .debug_rnglists DWARF section. 45 std::unique_ptr<DebugRangeListsSectionWriter> RangeListsSectionWriter; 46 47 /// Stores and serializes information that will be put into the 48 /// .debug_aranges DWARF section. 49 std::unique_ptr<DebugARangesSectionWriter> ARangesSectionWriter; 50 51 /// Stores and serializes information that will be put into the 52 /// .debug_addr DWARF section. 53 std::unique_ptr<DebugAddrWriter> AddrWriter; 54 55 /// Stores and serializes information that will be put in to the 56 /// .debug_addr DWARF section. 57 /// Does not do de-duplication. 58 std::unique_ptr<DebugStrWriter> StrWriter; 59 60 /// Stores and serializes information that will be put in to the 61 /// .debug_str_offsets DWARF section. 62 std::unique_ptr<DebugStrOffsetsWriter> StrOffstsWriter; 63 64 /// .debug_abbrev section writer for the main binary. 65 std::unique_ptr<DebugAbbrevWriter> AbbrevWriter; 66 67 using LocWriters = std::map<uint64_t, std::unique_ptr<DebugLocWriter>>; 68 /// Use a separate location list writer for each compilation unit 69 LocWriters LocListWritersByCU; 70 71 using RangeListsDWOWriers = 72 std::unordered_map<uint64_t, 73 std::unique_ptr<DebugRangeListsSectionWriter>>; 74 /// Store Rangelists writer for each DWO CU. 75 RangeListsDWOWriers RangeListsWritersByCU; 76 77 using DebugAbbrevDWOWriters = 78 std::unordered_map<uint64_t, std::unique_ptr<DebugAbbrevWriter>>; 79 /// Abbrev section writers for DWOs. 80 DebugAbbrevDWOWriters BinaryDWOAbbrevWriters; 81 82 using DebugInfoDWOPatchers = 83 std::unordered_map<uint64_t, std::unique_ptr<SimpleBinaryPatcher>>; 84 /// Binary patchers for DWO debug_info sections. 85 DebugInfoDWOPatchers BinaryDWODebugInfoPatchers; 86 87 /// Stores all the Type Signatures for DWO CU. 88 DebugTypesSignaturesPerCUMap TypeSignaturesPerCU; 89 90 std::mutex LocListDebugInfoPatchesMutex; 91 92 /// DWARFLegacy is all DWARF versions before DWARF 5. 93 enum class DWARFVersion { DWARFLegacy, DWARF5 }; 94 95 /// Update debug info for all DIEs in \p Unit. 96 void updateUnitDebugInfo(DWARFUnit &Unit, 97 DebugInfoBinaryPatcher &DebugInfoPatcher, 98 DebugAbbrevWriter &AbbrevWriter, 99 DebugLocWriter &DebugLocWriter, 100 DebugRangesSectionWriter &RangesWriter, 101 Optional<uint64_t> RangesBase = None); 102 103 /// Patches the binary for an object's address ranges to be updated. 104 /// The object can be anything that has associated address ranges via either 105 /// DW_AT_low/high_pc or DW_AT_ranges (i.e. functions, lexical blocks, etc). 106 /// \p DebugRangesOffset is the offset in .debug_ranges of the object's 107 /// new address ranges in the output binary. 108 /// \p Unit Compile unit the object belongs to. 109 /// \p DIE is the object's DIE in the input binary. 110 /// \p RangesBase if present, update \p DIE to use DW_AT_GNU_ranges_base 111 /// attribute. 112 void updateDWARFObjectAddressRanges(const DWARFDie DIE, 113 uint64_t DebugRangesOffset, 114 SimpleBinaryPatcher &DebugInfoPatcher, 115 DebugAbbrevWriter &AbbrevWriter, 116 Optional<uint64_t> RangesBase = None); 117 118 std::unique_ptr<DebugBufferVector> 119 makeFinalLocListsSection(DebugInfoBinaryPatcher &DebugInfoPatcher, 120 DWARFVersion Version); 121 122 /// Finalize debug sections in the main binary. 123 CUOffsetMap finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher); 124 125 /// Patches the binary for DWARF address ranges (e.g. in functions and lexical 126 /// blocks) to be updated. 127 void updateDebugAddressRanges(); 128 129 /// Rewrite .gdb_index section if present. 130 void updateGdbIndexSection(CUOffsetMap &CUMap); 131 132 /// Output .dwo files. 133 void writeDWOFiles(std::unordered_map<uint64_t, std::string> &DWOIdToName); 134 135 /// Output .dwp files. 136 void writeDWP(std::unordered_map<uint64_t, std::string> &DWOIdToName); 137 138 /// DWARFDie contains a pointer to a DIE and hence gets invalidated once the 139 /// embedded DIE is destroyed. This wrapper class stores a DIE internally and 140 /// could be cast to a DWARFDie that is valid even after the initial DIE is 141 /// destroyed. 142 struct DWARFDieWrapper { 143 DWARFUnit *Unit; 144 DWARFDebugInfoEntry DIE; 145 DWARFDieWrapperDWARFDieWrapper146 DWARFDieWrapper(DWARFUnit *Unit, DWARFDebugInfoEntry DIE) 147 : Unit(Unit), DIE(DIE) {} 148 DWARFDieWrapperDWARFDieWrapper149 DWARFDieWrapper(DWARFDie &Die) 150 : Unit(Die.getDwarfUnit()), DIE(*Die.getDebugInfoEntry()) {} 151 DWARFDieDWARFDieWrapper152 operator DWARFDie() { return DWARFDie(Unit, &DIE); } 153 }; 154 155 /// DIEs with abbrevs that were not converted to DW_AT_ranges. 156 /// We only update those when all DIEs have been processed to guarantee that 157 /// the abbrev (which is shared) is intact. 158 using PendingRangesType = std::unordered_map< 159 const DWARFAbbreviationDeclaration *, 160 std::vector<std::pair<DWARFDieWrapper, DebugAddressRange>>>; 161 162 /// Convert \p Abbrev from using a simple DW_AT_(low|high)_pc range to 163 /// DW_AT_ranges with optional \p RangesBase. 164 void convertToRangesPatchAbbrev(const DWARFUnit &Unit, 165 const DWARFAbbreviationDeclaration *Abbrev, 166 DebugAbbrevWriter &AbbrevWriter, 167 Optional<uint64_t> RangesBase = None); 168 169 /// Update \p DIE that was using DW_AT_(low|high)_pc with DW_AT_ranges offset. 170 /// Updates to the DIE should be synced with abbreviation updates using the 171 /// function above. 172 void convertToRangesPatchDebugInfo(DWARFDie DIE, uint64_t RangesSectionOffset, 173 SimpleBinaryPatcher &DebugInfoPatcher, 174 Optional<uint64_t> RangesBase = None); 175 176 /// Helper function for creating and returning per-DWO patchers/writers. 177 template <class T, class Patcher> getBinaryDWOPatcherHelper(T & BinaryPatchers,uint64_t DwoId)178 Patcher *getBinaryDWOPatcherHelper(T &BinaryPatchers, uint64_t DwoId) { 179 std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex); 180 auto Iter = BinaryPatchers.find(DwoId); 181 if (Iter == BinaryPatchers.end()) { 182 // Using make_pair instead of {} to work around bug in older version of 183 // the library. https://timsong-cpp.github.io/lwg-issues/2354 184 Iter = BinaryPatchers 185 .insert(std::make_pair(DwoId, std::make_unique<Patcher>())) 186 .first; 187 } 188 189 return static_cast<Patcher *>(Iter->second.get()); 190 } 191 192 /// Adds a \p Str to .debug_str section. 193 /// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using 194 /// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets 195 /// for this contribution of \p Unit. 196 void addStringHelper(DebugInfoBinaryPatcher &DebugInfoPatcher, 197 const DWARFUnit &Unit, const AttrInfo &AttrInfoVal, 198 StringRef Str); 199 200 public: DWARFRewriter(BinaryContext & BC)201 DWARFRewriter(BinaryContext &BC) : BC(BC) {} 202 203 /// Main function for updating the DWARF debug info. 204 void updateDebugInfo(); 205 206 /// Update stmt_list for CUs based on the new .debug_line \p Layout. 207 void updateLineTableOffsets(const MCAsmLayout &Layout); 208 209 /// Returns a DWO Debug Info Patcher for DWO ID. 210 /// Creates a new instance if it does not already exist. getBinaryDWODebugInfoPatcher(uint64_t DwoId)211 SimpleBinaryPatcher *getBinaryDWODebugInfoPatcher(uint64_t DwoId) { 212 return getBinaryDWOPatcherHelper<DebugInfoDWOPatchers, 213 DebugInfoBinaryPatcher>( 214 BinaryDWODebugInfoPatchers, DwoId); 215 } 216 217 /// Creates abbrev writer for DWO unit with \p DWOId. createBinaryDWOAbbrevWriter(DWARFContext & Context,uint64_t DWOId)218 DebugAbbrevWriter *createBinaryDWOAbbrevWriter(DWARFContext &Context, 219 uint64_t DWOId) { 220 std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex); 221 auto &Entry = BinaryDWOAbbrevWriters[DWOId]; 222 Entry = std::make_unique<DebugAbbrevWriter>(Context, DWOId); 223 return Entry.get(); 224 } 225 226 /// Returns DWO abbrev writer for \p DWOId. The writer must exist. getBinaryDWOAbbrevWriter(uint64_t DWOId)227 DebugAbbrevWriter *getBinaryDWOAbbrevWriter(uint64_t DWOId) { 228 auto Iter = BinaryDWOAbbrevWriters.find(DWOId); 229 assert(Iter != BinaryDWOAbbrevWriters.end() && "writer does not exist"); 230 return Iter->second.get(); 231 } 232 233 /// Given a \p DWOId, return its DebugLocWriter if it exists. getDebugLocWriter(uint64_t DWOId)234 DebugLocWriter *getDebugLocWriter(uint64_t DWOId) { 235 auto Iter = LocListWritersByCU.find(DWOId); 236 return Iter == LocListWritersByCU.end() ? nullptr 237 : LocListWritersByCU[DWOId].get(); 238 } 239 }; 240 241 } // namespace bolt 242 } // namespace llvm 243 244 #endif 245