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