Frederic Riss | 231f714 | 2014-12-12 17:31:24 +0000 | [diff] [blame] | 1 | //===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===// |
| 2 | // |
| 3 | // The LLVM Linker |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | #include "DebugMap.h" |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 10 | #include "BinaryHolder.h" |
| 11 | #include "DebugMap.h" |
Frederic Riss | 231f714 | 2014-12-12 17:31:24 +0000 | [diff] [blame] | 12 | #include "dsymutil.h" |
Zachary Turner | 82af943 | 2015-01-30 18:07:45 +0000 | [diff] [blame] | 13 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| 14 | #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 15 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 16 | #include "llvm/Object/MachO.h" |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 17 | #include <string> |
Frederic Riss | 231f714 | 2014-12-12 17:31:24 +0000 | [diff] [blame] | 18 | |
| 19 | namespace llvm { |
| 20 | namespace dsymutil { |
| 21 | |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 22 | namespace { |
| 23 | |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 24 | /// \brief Stores all information relating to a compile unit, be it in |
| 25 | /// its original instance in the object file to its brand new cloned |
| 26 | /// and linked DIE tree. |
| 27 | class CompileUnit { |
| 28 | public: |
| 29 | /// \brief Information gathered about a DIE in the object file. |
| 30 | struct DIEInfo { |
| 31 | uint32_t ParentIdx; |
| 32 | }; |
| 33 | |
| 34 | CompileUnit(DWARFUnit &OrigUnit) : OrigUnit(OrigUnit) { |
| 35 | Info.resize(OrigUnit.getNumDIEs()); |
| 36 | } |
| 37 | |
Frederic Riss | c3349d4 | 2015-02-13 23:18:27 +0000 | [diff] [blame] | 38 | DWARFUnit &getOrigUnit() const { return OrigUnit; } |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 39 | |
| 40 | DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } |
| 41 | const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } |
| 42 | |
| 43 | private: |
| 44 | DWARFUnit &OrigUnit; |
| 45 | std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. |
| 46 | }; |
| 47 | |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 48 | /// \brief The core of the Dwarf linking logic. |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 49 | /// |
| 50 | /// The link of the dwarf information from the object files will be |
| 51 | /// driven by the selection of 'root DIEs', which are DIEs that |
| 52 | /// describe variables or functions that are present in the linked |
| 53 | /// binary (and thus have entries in the debug map). All the debug |
| 54 | /// information that will be linked (the DIEs, but also the line |
| 55 | /// tables, ranges, ...) is derived from that set of root DIEs. |
| 56 | /// |
| 57 | /// The root DIEs are identified because they contain relocations that |
| 58 | /// correspond to a debug map entry at specific places (the low_pc for |
| 59 | /// a function, the location for a variable). These relocations are |
| 60 | /// called ValidRelocs in the DwarfLinker and are gathered as a very |
| 61 | /// first step when we start processing a DebugMapObject. |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 62 | class DwarfLinker { |
| 63 | public: |
| 64 | DwarfLinker(StringRef OutputFilename, bool Verbose) |
| 65 | : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {} |
| 66 | |
| 67 | /// \brief Link the contents of the DebugMap. |
| 68 | bool link(const DebugMap &); |
| 69 | |
| 70 | private: |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 71 | /// \brief Called at the start of a debug object link. |
| 72 | void startDebugObject(DWARFContext &); |
| 73 | |
| 74 | /// \brief Called at the end of a debug object link. |
| 75 | void endDebugObject(); |
| 76 | |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 77 | /// \defgroup FindValidRelocations Translate debug map into a list |
| 78 | /// of relevant relocations |
| 79 | /// |
| 80 | /// @{ |
| 81 | struct ValidReloc { |
| 82 | uint32_t Offset; |
| 83 | uint32_t Size; |
| 84 | uint64_t Addend; |
| 85 | const DebugMapObject::DebugMapEntry *Mapping; |
| 86 | |
| 87 | ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend, |
| 88 | const DebugMapObject::DebugMapEntry *Mapping) |
| 89 | : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} |
| 90 | |
| 91 | bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; } |
| 92 | }; |
| 93 | |
| 94 | /// \brief The valid relocations for the current DebugMapObject. |
| 95 | /// This vector is sorted by relocation offset. |
| 96 | std::vector<ValidReloc> ValidRelocs; |
| 97 | |
| 98 | /// \brief Index into ValidRelocs of the next relocation to |
| 99 | /// consider. As we walk the DIEs in acsending file offset and as |
| 100 | /// ValidRelocs is sorted by file offset, keeping this index |
| 101 | /// uptodate is all we have to do to have a cheap lookup during the |
| 102 | /// root DIE selection. |
| 103 | unsigned NextValidReloc; |
| 104 | |
| 105 | bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, |
| 106 | const DebugMapObject &DMO); |
| 107 | |
| 108 | bool findValidRelocs(const object::SectionRef &Section, |
| 109 | const object::ObjectFile &Obj, |
| 110 | const DebugMapObject &DMO); |
| 111 | |
| 112 | void findValidRelocsMachO(const object::SectionRef &Section, |
| 113 | const object::MachOObjectFile &Obj, |
| 114 | const DebugMapObject &DMO); |
| 115 | /// @} |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 116 | |
| 117 | /// \defgroup Helpers Various helper methods. |
| 118 | /// |
| 119 | /// @{ |
| 120 | const DWARFDebugInfoEntryMinimal * |
| 121 | resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit, |
| 122 | const DWARFDebugInfoEntryMinimal &DIE, |
| 123 | CompileUnit *&ReferencedCU); |
| 124 | |
| 125 | CompileUnit *getUnitForOffset(unsigned Offset); |
| 126 | |
| 127 | void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr, |
| 128 | const DWARFDebugInfoEntryMinimal *DIE = nullptr); |
| 129 | /// @} |
| 130 | |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 131 | private: |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 132 | std::string OutputFilename; |
| 133 | bool Verbose; |
| 134 | BinaryHolder BinHolder; |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 135 | |
| 136 | /// The units of the current debug map object. |
| 137 | std::vector<CompileUnit> Units; |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 138 | |
| 139 | /// The debug map object curently under consideration. |
| 140 | DebugMapObject *CurrentDebugObject; |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 141 | }; |
| 142 | |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 143 | /// \brief Similar to DWARFUnitSection::getUnitForOffset(), but |
| 144 | /// returning our CompileUnit object instead. |
| 145 | CompileUnit *DwarfLinker::getUnitForOffset(unsigned Offset) { |
| 146 | auto CU = |
| 147 | std::upper_bound(Units.begin(), Units.end(), Offset, |
| 148 | [](uint32_t LHS, const CompileUnit &RHS) { |
| 149 | return LHS < RHS.getOrigUnit().getNextUnitOffset(); |
| 150 | }); |
| 151 | return CU != Units.end() ? &*CU : nullptr; |
| 152 | } |
| 153 | |
| 154 | /// \brief Resolve the DIE attribute reference that has been |
| 155 | /// extracted in \p RefValue. The resulting DIE migh be in another |
| 156 | /// CompileUnit which is stored into \p ReferencedCU. |
| 157 | /// \returns null if resolving fails for any reason. |
| 158 | const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference( |
| 159 | DWARFFormValue &RefValue, const DWARFUnit &Unit, |
| 160 | const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) { |
| 161 | assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); |
| 162 | uint64_t RefOffset = *RefValue.getAsReference(&Unit); |
| 163 | |
| 164 | if ((RefCU = getUnitForOffset(RefOffset))) |
| 165 | if (const auto *RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) |
| 166 | return RefDie; |
| 167 | |
| 168 | reportWarning("could not find referenced DIE", &Unit, &DIE); |
| 169 | return nullptr; |
| 170 | } |
| 171 | |
| 172 | /// \brief Report a warning to the user, optionaly including |
| 173 | /// information about a specific \p DIE related to the warning. |
| 174 | void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit, |
| 175 | const DWARFDebugInfoEntryMinimal *DIE) { |
| 176 | if (CurrentDebugObject) |
| 177 | errs() << Twine("while processing ") + |
| 178 | CurrentDebugObject->getObjectFilename() + ":\n"; |
| 179 | errs() << Twine("warning: ") + Warning + "\n"; |
| 180 | |
| 181 | if (!Verbose || !DIE) |
| 182 | return; |
| 183 | |
| 184 | errs() << " in DIE:\n"; |
| 185 | DIE->dump(errs(), const_cast<DWARFUnit *>(Unit), 0 /* RecurseDepth */, |
| 186 | 6 /* Indent */); |
| 187 | } |
| 188 | |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 189 | /// \brief Recursive helper to gather the child->parent relationships in the |
| 190 | /// original compile unit. |
Frederic Riss | 9aa725b | 2015-02-13 23:18:31 +0000 | [diff] [blame^] | 191 | static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, |
| 192 | unsigned ParentIdx, CompileUnit &CU) { |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 193 | unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE); |
| 194 | CU.getInfo(MyIdx).ParentIdx = ParentIdx; |
| 195 | |
| 196 | if (DIE->hasChildren()) |
| 197 | for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL(); |
| 198 | Child = Child->getSibling()) |
Frederic Riss | 9aa725b | 2015-02-13 23:18:31 +0000 | [diff] [blame^] | 199 | gatherDIEParents(Child, MyIdx, CU); |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | void DwarfLinker::startDebugObject(DWARFContext &Dwarf) { |
| 203 | Units.reserve(Dwarf.getNumCompileUnits()); |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 204 | NextValidReloc = 0; |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 205 | } |
| 206 | |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 207 | void DwarfLinker::endDebugObject() { |
| 208 | Units.clear(); |
| 209 | ValidRelocs.clear(); |
| 210 | } |
| 211 | |
| 212 | /// \brief Iterate over the relocations of the given \p Section and |
| 213 | /// store the ones that correspond to debug map entries into the |
| 214 | /// ValidRelocs array. |
| 215 | void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, |
| 216 | const object::MachOObjectFile &Obj, |
| 217 | const DebugMapObject &DMO) { |
| 218 | StringRef Contents; |
| 219 | Section.getContents(Contents); |
| 220 | DataExtractor Data(Contents, Obj.isLittleEndian(), 0); |
| 221 | |
| 222 | for (const object::RelocationRef &Reloc : Section.relocations()) { |
| 223 | object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl(); |
| 224 | MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef); |
| 225 | unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); |
| 226 | uint64_t Offset64; |
| 227 | if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) { |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 228 | reportWarning(" unsupported relocation in debug_info section."); |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 229 | continue; |
| 230 | } |
| 231 | uint32_t Offset = Offset64; |
| 232 | // Mach-o uses REL relocations, the addend is at the relocation offset. |
| 233 | uint64_t Addend = Data.getUnsigned(&Offset, RelocSize); |
| 234 | |
| 235 | auto Sym = Reloc.getSymbol(); |
| 236 | if (Sym != Obj.symbol_end()) { |
| 237 | StringRef SymbolName; |
| 238 | if (Sym->getName(SymbolName)) { |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 239 | reportWarning("error getting relocation symbol name."); |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 240 | continue; |
| 241 | } |
| 242 | if (const auto *Mapping = DMO.lookupSymbol(SymbolName)) |
| 243 | ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping); |
| 244 | } else if (const auto *Mapping = DMO.lookupObjectAddress(Addend)) { |
| 245 | // Do not store the addend. The addend was the address of the |
| 246 | // symbol in the object file, the address in the binary that is |
| 247 | // stored in the debug map doesn't need to be offseted. |
| 248 | ValidRelocs.emplace_back(Offset64, RelocSize, 0, Mapping); |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | /// \brief Dispatch the valid relocation finding logic to the |
| 254 | /// appropriate handler depending on the object file format. |
| 255 | bool DwarfLinker::findValidRelocs(const object::SectionRef &Section, |
| 256 | const object::ObjectFile &Obj, |
| 257 | const DebugMapObject &DMO) { |
| 258 | // Dispatch to the right handler depending on the file type. |
| 259 | if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj)) |
| 260 | findValidRelocsMachO(Section, *MachOObj, DMO); |
| 261 | else |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 262 | reportWarning(Twine("unsupported object file type: ") + Obj.getFileName()); |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 263 | |
| 264 | if (ValidRelocs.empty()) |
| 265 | return false; |
| 266 | |
| 267 | // Sort the relocations by offset. We will walk the DIEs linearly in |
| 268 | // the file, this allows us to just keep an index in the relocation |
| 269 | // array that we advance during our walk, rather than resorting to |
| 270 | // some associative container. See DwarfLinker::NextValidReloc. |
| 271 | std::sort(ValidRelocs.begin(), ValidRelocs.end()); |
| 272 | return true; |
| 273 | } |
| 274 | |
| 275 | /// \brief Look for relocations in the debug_info section that match |
| 276 | /// entries in the debug map. These relocations will drive the Dwarf |
| 277 | /// link by indicating which DIEs refer to symbols present in the |
| 278 | /// linked binary. |
| 279 | /// \returns wether there are any valid relocations in the debug info. |
| 280 | bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj, |
| 281 | const DebugMapObject &DMO) { |
| 282 | // Find the debug_info section. |
| 283 | for (const object::SectionRef &Section : Obj.sections()) { |
| 284 | StringRef SectionName; |
| 285 | Section.getName(SectionName); |
| 286 | SectionName = SectionName.substr(SectionName.find_first_not_of("._")); |
| 287 | if (SectionName != "debug_info") |
| 288 | continue; |
| 289 | return findValidRelocs(Section, Obj, DMO); |
| 290 | } |
| 291 | return false; |
| 292 | } |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 293 | |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 294 | bool DwarfLinker::link(const DebugMap &Map) { |
| 295 | |
| 296 | if (Map.begin() == Map.end()) { |
| 297 | errs() << "Empty debug map.\n"; |
| 298 | return false; |
| 299 | } |
| 300 | |
| 301 | for (const auto &Obj : Map.objects()) { |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 302 | CurrentDebugObject = Obj.get(); |
| 303 | |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 304 | if (Verbose) |
| 305 | outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; |
| 306 | auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename()); |
| 307 | if (std::error_code EC = ErrOrObj.getError()) { |
Frederic Riss | 1b9da42 | 2015-02-13 23:18:29 +0000 | [diff] [blame] | 308 | reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message()); |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 309 | continue; |
| 310 | } |
| 311 | |
Frederic Riss | 1036e64 | 2015-02-13 23:18:22 +0000 | [diff] [blame] | 312 | // Look for relocations that correspond to debug map entries. |
| 313 | if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { |
| 314 | if (Verbose) |
| 315 | outs() << "No valid relocations found. Skipping.\n"; |
| 316 | continue; |
| 317 | } |
| 318 | |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 319 | // Setup access to the debug info. |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 320 | DWARFContextInMemory DwarfContext(*ErrOrObj); |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 321 | startDebugObject(DwarfContext); |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 322 | |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 323 | // In a first phase, just read in the debug info and store the DIE |
| 324 | // parent links that we will use during the next phase. |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 325 | for (const auto &CU : DwarfContext.compile_units()) { |
| 326 | auto *CUDie = CU->getCompileUnitDIE(false); |
| 327 | if (Verbose) { |
| 328 | outs() << "Input compilation unit:"; |
| 329 | CUDie->dump(outs(), CU.get(), 0); |
| 330 | } |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 331 | Units.emplace_back(*CU); |
Frederic Riss | 9aa725b | 2015-02-13 23:18:31 +0000 | [diff] [blame^] | 332 | gatherDIEParents(CUDie, 0, Units.back()); |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 333 | } |
Frederic Riss | 563cba6 | 2015-01-28 22:15:14 +0000 | [diff] [blame] | 334 | |
| 335 | // Clean-up before starting working on the next object. |
| 336 | endDebugObject(); |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 337 | } |
| 338 | |
Frederic Riss | 231f714 | 2014-12-12 17:31:24 +0000 | [diff] [blame] | 339 | return true; |
| 340 | } |
| 341 | } |
Frederic Riss | d345518 | 2015-01-28 18:27:01 +0000 | [diff] [blame] | 342 | |
| 343 | bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) { |
| 344 | DwarfLinker Linker(OutputFilename, Verbose); |
| 345 | return Linker.link(DM); |
| 346 | } |
| 347 | } |
Frederic Riss | 231f714 | 2014-12-12 17:31:24 +0000 | [diff] [blame] | 348 | } |