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