1 //=== DebugInfoLinker.cpp -------------------------------------------------===// 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 #include "DebugInfoLinker.h" 10 #include "Error.h" 11 #include "llvm/DWARFLinker/DWARFLinker.h" 12 #include "llvm/DWARFLinker/DWARFStreamer.h" 13 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 15 #include "llvm/Object/ObjectFile.h" 16 #include <memory> 17 #include <vector> 18 19 namespace llvm { 20 namespace dwarfutil { 21 22 // ObjFileAddressMap allows to check whether specified DIE referencing 23 // dead addresses. It uses tombstone values to determine dead addresses. 24 // The concrete values of tombstone constants were discussed in 25 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825. 26 // So we use following values as indicators of dead addresses: 27 // 28 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less)) 29 // or ([LowPC, HighPC] is not inside address ranges of .text sections). 30 // 31 // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less)) 32 // That value is assumed to be compatible with 33 // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1 34 // 35 // exec: [LowPC, HighPC] is not inside address ranges of .text sections 36 // 37 // universal: maxpc and bfd 38 class ObjFileAddressMap : public AddressesMap { 39 public: 40 ObjFileAddressMap(DWARFContext &Context, const Options &Options, 41 object::ObjectFile &ObjFile) 42 : Opts(Options) { 43 // Remember addresses of existing text sections. 44 for (const object::SectionRef &Sect : ObjFile.sections()) { 45 if (!Sect.isText()) 46 continue; 47 const uint64_t Size = Sect.getSize(); 48 if (Size == 0) 49 continue; 50 const uint64_t StartAddr = Sect.getAddress(); 51 TextAddressRanges.insert({StartAddr, StartAddr + Size}); 52 } 53 54 // Check CU address ranges for tombstone value. 55 for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) { 56 Expected<llvm::DWARFAddressRangesVector> ARanges = 57 CU->getUnitDIE().getAddressRanges(); 58 if (ARanges) { 59 for (auto &Range : *ARanges) { 60 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(), 61 Options.Tombstone, CU->getAddressByteSize())) 62 DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0); 63 } 64 } 65 } 66 } 67 68 // should be renamed into has valid address ranges 69 bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); } 70 71 bool isLiveSubprogram(const DWARFDie &DIE, 72 CompileUnit::DIEInfo &Info) override { 73 assert((DIE.getTag() == dwarf::DW_TAG_subprogram || 74 DIE.getTag() == dwarf::DW_TAG_label) && 75 "Wrong type of input die"); 76 77 if (Optional<uint64_t> LowPC = 78 dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) { 79 if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(), 80 Opts.Tombstone, 81 DIE.getDwarfUnit()->getAddressByteSize())) { 82 Info.AddrAdjust = 0; 83 Info.InDebugMap = true; 84 return true; 85 } 86 } 87 88 return false; 89 } 90 91 bool isLiveVariable(const DWARFDie &DIE, 92 CompileUnit::DIEInfo &Info) override { 93 assert((DIE.getTag() == dwarf::DW_TAG_variable || 94 DIE.getTag() == dwarf::DW_TAG_constant) && 95 "Wrong type of input die"); 96 97 if (Expected<DWARFLocationExpressionsVector> Loc = 98 DIE.getLocations(dwarf::DW_AT_location)) { 99 DWARFUnit *U = DIE.getDwarfUnit(); 100 for (const auto &Entry : *Loc) { 101 DataExtractor Data(toStringRef(Entry.Expr), 102 U->getContext().isLittleEndian(), 0); 103 DWARFExpression Expression(Data, U->getAddressByteSize(), 104 U->getFormParams().Format); 105 bool HasLiveAddresses = 106 any_of(Expression, [&](const DWARFExpression::Operation &Op) { 107 // TODO: add handling of dwarf::DW_OP_addrx 108 return !Op.isError() && 109 (Op.getCode() == dwarf::DW_OP_addr && 110 !isDeadAddress(Op.getRawOperand(0), U->getVersion(), 111 Opts.Tombstone, 112 DIE.getDwarfUnit()->getAddressByteSize())); 113 }); 114 115 if (HasLiveAddresses) { 116 Info.AddrAdjust = 0; 117 Info.InDebugMap = true; 118 return true; 119 } 120 } 121 } else { 122 // FIXME: missing DW_AT_location is OK here, but other errors should be 123 // reported to the user. 124 consumeError(Loc.takeError()); 125 } 126 127 return false; 128 } 129 130 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override { 131 // no need to apply relocations to the linked binary. 132 return false; 133 } 134 135 RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; }; 136 137 void clear() override { DWARFAddressRanges.clear(); } 138 139 llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t, uint64_t) override { 140 // should not be called. 141 return object::createError("no relocations in linked binary"); 142 } 143 144 protected: 145 // returns true if specified address range is inside address ranges 146 // of executable sections. 147 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC, 148 Optional<uint64_t> HighPC) { 149 Optional<AddressRange> Range = 150 TextAddressRanges.getRangeThatContains(LowPC); 151 152 if (HighPC) 153 return Range.has_value() && Range->end() >= *HighPC; 154 155 return Range.has_value(); 156 } 157 158 uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 159 uint16_t Version) { 160 if (LowPC == 0) 161 return true; 162 163 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1)) 164 return true; 165 166 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 167 } 168 169 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 170 uint16_t Version, uint8_t AddressByteSize) { 171 if (Version <= 4 && HighPC) { 172 if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1)) 173 return true; 174 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize)) 175 return true; 176 177 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC)) 178 warning("Address referencing invalid text section is not marked with " 179 "tombstone value"); 180 181 return false; 182 } 183 184 bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 185 uint16_t Version, TombstoneKind Tombstone, 186 uint8_t AddressByteSize) { 187 switch (Tombstone) { 188 case TombstoneKind::BFD: 189 return isBFDDeadAddressRange(LowPC, HighPC, Version); 190 case TombstoneKind::MaxPC: 191 return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 192 case TombstoneKind::Universal: 193 return isBFDDeadAddressRange(LowPC, HighPC, Version) || 194 isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 195 case TombstoneKind::Exec: 196 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 197 } 198 199 llvm_unreachable("Unknown tombstone value"); 200 } 201 202 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone, 203 uint8_t AddressByteSize) { 204 return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize); 205 } 206 207 private: 208 RangesTy DWARFAddressRanges; 209 AddressRanges TextAddressRanges; 210 const Options &Opts; 211 }; 212 213 bool linkDebugInfo(object::ObjectFile &File, const Options &Options, 214 raw_pwrite_stream &OutStream) { 215 216 auto ReportWarn = [&](const Twine &Message, StringRef Context, 217 const DWARFDie *Die) { 218 warning(Message, Context); 219 220 if (!Options.Verbose || !Die) 221 return; 222 223 DIDumpOptions DumpOpts; 224 DumpOpts.ChildRecurseDepth = 0; 225 DumpOpts.Verbose = Options.Verbose; 226 227 WithColor::note() << " in DIE:\n"; 228 Die->dump(errs(), /*Indent=*/6, DumpOpts); 229 }; 230 auto ReportErr = [&](const Twine &Message, StringRef Context, 231 const DWARFDie *) { 232 WithColor::error(errs(), Context) << Message << '\n'; 233 }; 234 235 // Create output streamer. 236 DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr, 237 ReportWarn, ReportWarn); 238 if (!OutStreamer.init(File.makeTriple(), "")) 239 return false; 240 241 // Create DWARF linker. 242 DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); 243 244 DebugInfoLinker.setEstimatedObjfilesAmount(1); 245 DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None); 246 DebugInfoLinker.setErrorHandler(ReportErr); 247 DebugInfoLinker.setWarningHandler(ReportWarn); 248 DebugInfoLinker.setNumThreads(Options.NumThreads); 249 DebugInfoLinker.setNoODR(!Options.DoODRDeduplication); 250 DebugInfoLinker.setVerbosity(Options.Verbose); 251 DebugInfoLinker.setUpdate(!Options.DoGarbageCollection); 252 253 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1); 254 std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1); 255 std::vector<std::string> EmptyWarnings; 256 257 std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); 258 259 // Add object files to the DWARFLinker. 260 AddresssMapForLinking[0] = 261 std::make_unique<ObjFileAddressMap>(*Context, Options, File); 262 263 ObjectsForLinking[0] = std::make_unique<DWARFFile>( 264 File.getFileName(), &*Context, AddresssMapForLinking[0].get(), 265 EmptyWarnings); 266 267 for (size_t I = 0; I < ObjectsForLinking.size(); I++) 268 DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]); 269 270 // Link debug info. 271 DebugInfoLinker.link(); 272 OutStreamer.finish(); 273 return true; 274 } 275 276 } // end of namespace dwarfutil 277 } // end of namespace llvm 278