1 //===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "BinaryHolder.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/Object/MachO.h"
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.
29 /// \brief Information gathered about a DIE in the object file.
34 CompileUnit(DWARFUnit &OrigUnit) : OrigUnit(OrigUnit) {
35 Info.resize(OrigUnit.getNumDIEs());
38 DWARFUnit &getOrigUnit() const { return OrigUnit; }
40 DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
41 const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
45 std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
48 /// \brief The core of the Dwarf linking logic.
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.
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.
64 DwarfLinker(StringRef OutputFilename, bool Verbose)
65 : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {}
67 /// \brief Link the contents of the DebugMap.
68 bool link(const DebugMap &);
71 /// \brief Called at the start of a debug object link.
72 void startDebugObject(DWARFContext &);
74 /// \brief Called at the end of a debug object link.
75 void endDebugObject();
77 /// \defgroup FindValidRelocations Translate debug map into a list
78 /// of relevant relocations
85 const DebugMapObject::DebugMapEntry *Mapping;
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) {}
91 bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
94 /// \brief The valid relocations for the current DebugMapObject.
95 /// This vector is sorted by relocation offset.
96 std::vector<ValidReloc> ValidRelocs;
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;
105 bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
106 const DebugMapObject &DMO);
108 bool findValidRelocs(const object::SectionRef &Section,
109 const object::ObjectFile &Obj,
110 const DebugMapObject &DMO);
112 void findValidRelocsMachO(const object::SectionRef &Section,
113 const object::MachOObjectFile &Obj,
114 const DebugMapObject &DMO);
117 /// \defgroup Helpers Various helper methods.
120 const DWARFDebugInfoEntryMinimal *
121 resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit,
122 const DWARFDebugInfoEntryMinimal &DIE,
123 CompileUnit *&ReferencedCU);
125 CompileUnit *getUnitForOffset(unsigned Offset);
127 void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr,
128 const DWARFDebugInfoEntryMinimal *DIE = nullptr);
132 std::string OutputFilename;
134 BinaryHolder BinHolder;
136 /// The units of the current debug map object.
137 std::vector<CompileUnit> Units;
139 /// The debug map object curently under consideration.
140 DebugMapObject *CurrentDebugObject;
143 /// \brief Similar to DWARFUnitSection::getUnitForOffset(), but
144 /// returning our CompileUnit object instead.
145 CompileUnit *DwarfLinker::getUnitForOffset(unsigned Offset) {
147 std::upper_bound(Units.begin(), Units.end(), Offset,
148 [](uint32_t LHS, const CompileUnit &RHS) {
149 return LHS < RHS.getOrigUnit().getNextUnitOffset();
151 return CU != Units.end() ? &*CU : nullptr;
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);
164 if ((RefCU = getUnitForOffset(RefOffset)))
165 if (const auto *RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset))
168 reportWarning("could not find referenced DIE", &Unit, &DIE);
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";
181 if (!Verbose || !DIE)
184 errs() << " in DIE:\n";
185 DIE->dump(errs(), const_cast<DWARFUnit *>(Unit), 0 /* RecurseDepth */,
189 /// \brief Recursive helper to gather the child->parent relationships in the
190 /// original compile unit.
191 void GatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, unsigned ParentIdx,
193 unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
194 CU.getInfo(MyIdx).ParentIdx = ParentIdx;
196 if (DIE->hasChildren())
197 for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
198 Child = Child->getSibling())
199 GatherDIEParents(Child, MyIdx, CU);
202 void DwarfLinker::startDebugObject(DWARFContext &Dwarf) {
203 Units.reserve(Dwarf.getNumCompileUnits());
207 void DwarfLinker::endDebugObject() {
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) {
219 Section.getContents(Contents);
220 DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
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);
227 if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) {
228 reportWarning(" unsupported relocation in debug_info section.");
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);
235 auto Sym = Reloc.getSymbol();
236 if (Sym != Obj.symbol_end()) {
237 StringRef SymbolName;
238 if (Sym->getName(SymbolName)) {
239 reportWarning("error getting relocation symbol name.");
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);
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);
262 reportWarning(Twine("unsupported object file type: ") + Obj.getFileName());
264 if (ValidRelocs.empty())
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());
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
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")
289 return findValidRelocs(Section, Obj, DMO);
294 bool DwarfLinker::link(const DebugMap &Map) {
296 if (Map.begin() == Map.end()) {
297 errs() << "Empty debug map.\n";
301 for (const auto &Obj : Map.objects()) {
302 CurrentDebugObject = Obj.get();
305 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
306 auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename());
307 if (std::error_code EC = ErrOrObj.getError()) {
308 reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message());
312 // Look for relocations that correspond to debug map entries.
313 if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
315 outs() << "No valid relocations found. Skipping.\n";
319 // Setup access to the debug info.
320 DWARFContextInMemory DwarfContext(*ErrOrObj);
321 startDebugObject(DwarfContext);
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.
325 for (const auto &CU : DwarfContext.compile_units()) {
326 auto *CUDie = CU->getCompileUnitDIE(false);
328 outs() << "Input compilation unit:";
329 CUDie->dump(outs(), CU.get(), 0);
331 Units.emplace_back(*CU);
332 GatherDIEParents(CUDie, 0, Units.back());
335 // Clean-up before starting working on the next object.
343 bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) {
344 DwarfLinker Linker(OutputFilename, Verbose);
345 return Linker.link(DM);