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