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[{StartAddr}] = {StartAddr + Size, 0}; 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[{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 auto Range = TextAddressRanges.lower_bound(LowPC); 150 if ((Range == TextAddressRanges.end() || Range->first != LowPC) && 151 Range != TextAddressRanges.begin()) 152 --Range; 153 154 if (Range != TextAddressRanges.end() && Range->first <= LowPC && 155 (HighPC ? Range->second.HighPC >= HighPC 156 : Range->second.HighPC >= LowPC)) 157 return true; 158 159 return false; 160 } 161 162 uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 163 uint16_t Version) { 164 if (LowPC == 0) 165 return true; 166 167 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1)) 168 return true; 169 170 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 171 } 172 173 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 174 uint16_t Version, uint8_t AddressByteSize) { 175 if (Version <= 4 && HighPC) { 176 if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1)) 177 return true; 178 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize)) 179 return true; 180 181 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC)) 182 warning("Address referencing invalid text section is not marked with " 183 "tombstone value"); 184 185 return false; 186 } 187 188 bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, 189 uint16_t Version, TombstoneKind Tombstone, 190 uint8_t AddressByteSize) { 191 switch (Tombstone) { 192 case TombstoneKind::BFD: 193 return isBFDDeadAddressRange(LowPC, HighPC, Version); 194 case TombstoneKind::MaxPC: 195 return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 196 case TombstoneKind::Universal: 197 return isBFDDeadAddressRange(LowPC, HighPC, Version) || 198 isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize); 199 case TombstoneKind::Exec: 200 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); 201 } 202 203 llvm_unreachable("Unknown tombstone value"); 204 } 205 206 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone, 207 uint8_t AddressByteSize) { 208 return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize); 209 } 210 211 private: 212 RangesTy DWARFAddressRanges; 213 RangesTy TextAddressRanges; 214 const Options &Opts; 215 }; 216 217 bool linkDebugInfo(object::ObjectFile &File, const Options &Options, 218 raw_pwrite_stream &OutStream) { 219 220 auto ReportWarn = [&](const Twine &Message, StringRef Context, 221 const DWARFDie *Die) { 222 warning(Message, Context); 223 224 if (!Options.Verbose || !Die) 225 return; 226 227 DIDumpOptions DumpOpts; 228 DumpOpts.ChildRecurseDepth = 0; 229 DumpOpts.Verbose = Options.Verbose; 230 231 WithColor::note() << " in DIE:\n"; 232 Die->dump(errs(), /*Indent=*/6, DumpOpts); 233 }; 234 auto ReportErr = [&](const Twine &Message, StringRef Context, 235 const DWARFDie *) { 236 WithColor::error(errs(), Context) << Message << '\n'; 237 }; 238 239 // Create output streamer. 240 DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr, 241 ReportWarn, ReportWarn); 242 if (!OutStreamer.init(File.makeTriple(), "")) 243 return false; 244 245 // Create DWARF linker. 246 DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); 247 248 DebugInfoLinker.setEstimatedObjfilesAmount(1); 249 DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None); 250 DebugInfoLinker.setErrorHandler(ReportErr); 251 DebugInfoLinker.setWarningHandler(ReportWarn); 252 DebugInfoLinker.setNumThreads(Options.NumThreads); 253 DebugInfoLinker.setNoODR(!Options.DoODRDeduplication); 254 DebugInfoLinker.setVerbosity(Options.Verbose); 255 DebugInfoLinker.setUpdate(!Options.DoGarbageCollection); 256 257 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1); 258 std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1); 259 std::vector<std::string> EmptyWarnings; 260 261 std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); 262 263 // Add object files to the DWARFLinker. 264 AddresssMapForLinking[0] = 265 std::make_unique<ObjFileAddressMap>(*Context, Options, File); 266 267 ObjectsForLinking[0] = std::make_unique<DWARFFile>( 268 File.getFileName(), &*Context, AddresssMapForLinking[0].get(), 269 EmptyWarnings); 270 271 for (size_t I = 0; I < ObjectsForLinking.size(); I++) 272 DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]); 273 274 // Link debug info. 275 DebugInfoLinker.link(); 276 OutStreamer.finish(); 277 return true; 278 } 279 280 } // end of namespace dwarfutil 281 } // end of namespace llvm 282