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/ADT/StringSwitch.h" 12 #include "llvm/DWARFLinker/DWARFLinker.h" 13 #include "llvm/DWARFLinker/DWARFStreamer.h" 14 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 15 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 16 #include "llvm/Object/ObjectFile.h" 17 #include "llvm/Support/Endian.h" 18 #include <memory> 19 #include <vector> 20 21 namespace llvm { 22 namespace dwarfutil { 23 24 // ObjFileAddressMap allows to check whether specified DIE referencing 25 // dead addresses. It uses tombstone values to determine dead addresses. 26 // The concrete values of tombstone constants were discussed in 27 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825. 28 // So we use following values as indicators of dead addresses: 29 // 30 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less)) 31 // or ([LowPC, HighPC] is not inside address ranges of .text sections). 32 // 33 // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less)) 34 // That value is assumed to be compatible with 35 // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1 36 // 37 // exec: [LowPC, HighPC] is not inside address ranges of .text sections 38 // 39 // universal: maxpc and bfd 40 class ObjFileAddressMap : public AddressesMap { 41 public: 42 ObjFileAddressMap(DWARFContext &Context, const Options &Options, 43 object::ObjectFile &ObjFile) 44 : Opts(Options) { 45 // Remember addresses of existing text sections. 46 for (const object::SectionRef &Sect : ObjFile.sections()) { 47 if (!Sect.isText()) 48 continue; 49 const uint64_t Size = Sect.getSize(); 50 if (Size == 0) 51 continue; 52 const uint64_t StartAddr = Sect.getAddress(); 53 TextAddressRanges.insert({StartAddr, StartAddr + Size}); 54 } 55 56 // Check CU address ranges for tombstone value. 57 for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) { 58 Expected<llvm::DWARFAddressRangesVector> ARanges = 59 CU->getUnitDIE().getAddressRanges(); 60 if (ARanges) { 61 for (auto &Range : *ARanges) { 62 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(), 63 Options.Tombstone, CU->getAddressByteSize())) 64 DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0); 65 } 66 } 67 } 68 } 69 70 // should be renamed into has valid address ranges 71 bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); } 72 73 std::optional<int64_t> 74 getSubprogramRelocAdjustment(const DWARFDie &DIE) override { 75 assert((DIE.getTag() == dwarf::DW_TAG_subprogram || 76 DIE.getTag() == dwarf::DW_TAG_label) && 77 "Wrong type of input die"); 78 79 if (std::optional<uint64_t> LowPC = 80 dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) { 81 if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(), 82 Opts.Tombstone, 83 DIE.getDwarfUnit()->getAddressByteSize())) 84 // Relocation value for the linked binary is 0. 85 return 0; 86 } 87 88 return std::nullopt; 89 } 90 91 std::optional<int64_t> getExprOpAddressRelocAdjustment( 92 DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, 93 uint64_t EndOffset) override { 94 switch (Op.getCode()) { 95 default: { 96 assert(false && "Specified operation does not have address operand"); 97 } break; 98 case dwarf::DW_OP_const4u: 99 case dwarf::DW_OP_const8u: 100 case dwarf::DW_OP_const4s: 101 case dwarf::DW_OP_const8s: 102 case dwarf::DW_OP_addr: { 103 if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone, 104 U.getAddressByteSize())) 105 // Relocation value for the linked binary is 0. 106 return 0; 107 } break; 108 case dwarf::DW_OP_constx: 109 case dwarf::DW_OP_addrx: { 110 if (std::optional<object::SectionedAddress> Address = 111 U.getAddrOffsetSectionItem(Op.getRawOperand(0))) { 112 if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone, 113 U.getAddressByteSize())) 114 // Relocation value for the linked binary is 0. 115 return 0; 116 } 117 } break; 118 } 119 120 return std::nullopt; 121 } 122 123 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override { 124 // no need to apply relocations to the linked binary. 125 return false; 126 } 127 128 RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; }; 129 130 void clear() override { DWARFAddressRanges.clear(); } 131 132 protected: 133 // returns true if specified address range is inside address ranges 134 // of executable sections. 135 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC, 136 std::optional<uint64_t> HighPC) { 137 std::optional<AddressRange> Range = 138 TextAddressRanges.getRangeThatContains(LowPC); 139 140 if (HighPC) 141 return Range.has_value() && Range->end() >= *HighPC; 142 143 return Range.has_value(); 144 } 145 146 uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC, 147 uint16_t Version) { 148 if (LowPC == 0) 149 return true; 150 151 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1)) 152 return true; 153 154 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 155 } 156 157 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, 158 std::optional<uint64_t> HighPC, 159 uint16_t Version, uint8_t AddressByteSize) { 160 if (Version <= 4 && HighPC) { 161 if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1)) 162 return true; 163 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize)) 164 return true; 165 166 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC)) 167 warning("Address referencing invalid text section is not marked with " 168 "tombstone value"); 169 170 return false; 171 } 172 173 bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC, 174 uint16_t Version, TombstoneKind Tombstone, 175 uint8_t AddressByteSize) { 176 switch (Tombstone) { 177 case TombstoneKind::BFD: 178 return isBFDDeadAddressRange(LowPC, HighPC, Version); 179 case TombstoneKind::MaxPC: 180 return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 181 case TombstoneKind::Universal: 182 return isBFDDeadAddressRange(LowPC, HighPC, Version) || 183 isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 184 case TombstoneKind::Exec: 185 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 186 } 187 188 llvm_unreachable("Unknown tombstone value"); 189 } 190 191 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone, 192 uint8_t AddressByteSize) { 193 return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone, 194 AddressByteSize); 195 } 196 197 private: 198 RangesTy DWARFAddressRanges; 199 AddressRanges TextAddressRanges; 200 const Options &Opts; 201 }; 202 203 static bool knownByDWARFUtil(StringRef SecName) { 204 return llvm::StringSwitch<bool>(SecName) 205 .Case(".debug_info", true) 206 .Case(".debug_types", true) 207 .Case(".debug_abbrev", true) 208 .Case(".debug_loc", true) 209 .Case(".debug_loclists", true) 210 .Case(".debug_frame", true) 211 .Case(".debug_aranges", true) 212 .Case(".debug_ranges", true) 213 .Case(".debug_rnglists", true) 214 .Case(".debug_line", true) 215 .Case(".debug_line_str", true) 216 .Case(".debug_addr", true) 217 .Case(".debug_macro", true) 218 .Case(".debug_macinfo", true) 219 .Case(".debug_str", true) 220 .Case(".debug_str_offsets", true) 221 .Case(".debug_pubnames", true) 222 .Case(".debug_pubtypes", true) 223 .Case(".debug_names", true) 224 .Default(false); 225 } 226 227 static std::optional<DwarfLinkerAccelTableKind> 228 getAcceleratorTableKind(StringRef SecName) { 229 return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName) 230 .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub) 231 .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub) 232 .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames) 233 .Default(std::nullopt); 234 } 235 236 static std::string getMessageForReplacedAcceleratorTables( 237 SmallVector<StringRef> &AccelTableNamesToReplace, 238 DwarfUtilAccelKind TargetTable) { 239 std::string Message; 240 241 Message += "'"; 242 for (StringRef Name : AccelTableNamesToReplace) { 243 if (Message.size() > 1) 244 Message += ", "; 245 Message += Name; 246 } 247 248 Message += "' will be replaced with requested "; 249 250 switch (TargetTable) { 251 case DwarfUtilAccelKind::DWARF: 252 Message += ".debug_names table"; 253 break; 254 255 default: 256 assert(false); 257 } 258 259 return Message; 260 } 261 262 static std::string getMessageForDeletedAcceleratorTables( 263 SmallVector<StringRef> &AccelTableNamesToReplace) { 264 std::string Message; 265 266 Message += "'"; 267 for (StringRef Name : AccelTableNamesToReplace) { 268 if (Message.size() > 1) 269 Message += ", "; 270 Message += Name; 271 } 272 273 Message += "' will be deleted as no accelerator tables are requested"; 274 275 return Message; 276 } 277 278 Error linkDebugInfo(object::ObjectFile &File, const Options &Options, 279 raw_pwrite_stream &OutStream) { 280 281 auto ReportWarn = [&](const Twine &Message, StringRef Context, 282 const DWARFDie *Die) { 283 warning(Message, Context); 284 285 if (!Options.Verbose || !Die) 286 return; 287 288 DIDumpOptions DumpOpts; 289 DumpOpts.ChildRecurseDepth = 0; 290 DumpOpts.Verbose = Options.Verbose; 291 292 WithColor::note() << " in DIE:\n"; 293 Die->dump(errs(), /*Indent=*/6, DumpOpts); 294 }; 295 auto ReportErr = [&](const Twine &Message, StringRef Context, 296 const DWARFDie *) { 297 WithColor::error(errs(), Context) << Message << '\n'; 298 }; 299 300 // Create output streamer. 301 DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr, 302 ReportWarn, ReportWarn); 303 Triple TargetTriple = File.makeTriple(); 304 if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}", 305 TargetTriple.getTriple()) 306 .str())) 307 return createStringError(std::errc::invalid_argument, ""); 308 309 std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); 310 311 // Create DWARF linker. 312 DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); 313 314 DebugInfoLinker.setEstimatedObjfilesAmount(1); 315 DebugInfoLinker.setErrorHandler(ReportErr); 316 DebugInfoLinker.setWarningHandler(ReportWarn); 317 DebugInfoLinker.setNumThreads(Options.NumThreads); 318 DebugInfoLinker.setNoODR(!Options.DoODRDeduplication); 319 DebugInfoLinker.setVerbosity(Options.Verbose); 320 DebugInfoLinker.setUpdate(!Options.DoGarbageCollection); 321 322 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1); 323 std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1); 324 std::vector<std::string> EmptyWarnings; 325 326 // Add object files to the DWARFLinker. 327 AddresssMapForLinking[0] = 328 std::make_unique<ObjFileAddressMap>(*Context, Options, File); 329 330 ObjectsForLinking[0] = std::make_unique<DWARFFile>( 331 File.getFileName(), &*Context, AddresssMapForLinking[0].get(), 332 EmptyWarnings); 333 334 uint16_t MaxDWARFVersion = 0; 335 std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded = 336 [&MaxDWARFVersion](const DWARFUnit &Unit) { 337 MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion); 338 }; 339 340 for (size_t I = 0; I < ObjectsForLinking.size(); I++) 341 DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr, 342 OnCUDieLoaded); 343 344 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway. 345 if (MaxDWARFVersion == 0) 346 MaxDWARFVersion = 3; 347 348 if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion)) 349 return Err; 350 351 SmallVector<DwarfLinkerAccelTableKind> AccelTables; 352 353 switch (Options.AccelTableKind) { 354 case DwarfUtilAccelKind::None: 355 // Nothing to do. 356 break; 357 case DwarfUtilAccelKind::DWARF: 358 // use .debug_names for all DWARF versions. 359 AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames); 360 break; 361 } 362 363 // Add accelerator tables to DWARFLinker. 364 for (DwarfLinkerAccelTableKind Table : AccelTables) 365 DebugInfoLinker.addAccelTableKind(Table); 366 367 SmallVector<StringRef> AccelTableNamesToReplace; 368 SmallVector<StringRef> AccelTableNamesToDelete; 369 370 // Unknown debug sections or non-requested accelerator sections would be 371 // removed. Display warning for such sections. 372 for (SectionName Sec : Context->getDWARFObj().getSectionNames()) { 373 if (isDebugSection(Sec.Name)) { 374 std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind = 375 getAcceleratorTableKind(Sec.Name); 376 377 if (SrcAccelTableKind) { 378 assert(knownByDWARFUtil(Sec.Name)); 379 380 if (Options.AccelTableKind == DwarfUtilAccelKind::None) 381 AccelTableNamesToDelete.push_back(Sec.Name); 382 else if (std::find(AccelTables.begin(), AccelTables.end(), 383 *SrcAccelTableKind) == AccelTables.end()) 384 AccelTableNamesToReplace.push_back(Sec.Name); 385 } else if (!knownByDWARFUtil(Sec.Name)) { 386 assert(!SrcAccelTableKind); 387 warning( 388 formatv("'{0}' is not currently supported: section will be skipped", 389 Sec.Name), 390 Options.InputFileName); 391 } 392 } 393 } 394 395 // Display message for the replaced accelerator tables. 396 if (!AccelTableNamesToReplace.empty()) 397 warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, 398 Options.AccelTableKind), 399 Options.InputFileName); 400 401 // Display message for the removed accelerator tables. 402 if (!AccelTableNamesToDelete.empty()) 403 warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), 404 Options.InputFileName); 405 406 // Link debug info. 407 if (Error Err = DebugInfoLinker.link()) 408 return Err; 409 410 OutStreamer.finish(); 411 return Error::success(); 412 } 413 414 } // end of namespace dwarfutil 415 } // end of namespace llvm 416