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/Object/MachO.h"
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.
28 /// \brief Information gathered about a DIE in the object file.
33 CompileUnit(DWARFUnit &OrigUnit) : OrigUnit(OrigUnit) {
34 Info.resize(OrigUnit.getNumDIEs());
37 DWARFUnit &getOrigUnit() { return OrigUnit; }
39 DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
40 const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
44 std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
47 /// \brief The core of the Dwarf linking logic.
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.
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.
63 DwarfLinker(StringRef OutputFilename, bool Verbose)
64 : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {}
66 /// \brief Link the contents of the DebugMap.
67 bool link(const DebugMap &);
70 /// \brief Called at the start of a debug object link.
71 void startDebugObject(DWARFContext &);
73 /// \brief Called at the end of a debug object link.
74 void endDebugObject();
76 /// \defgroup FindValidRelocations Translate debug map into a list
77 /// of relevant relocations
84 const DebugMapObject::DebugMapEntry *Mapping;
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) {}
90 bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
93 /// \brief The valid relocations for the current DebugMapObject.
94 /// This vector is sorted by relocation offset.
95 std::vector<ValidReloc> ValidRelocs;
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;
104 bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
105 const DebugMapObject &DMO);
107 bool findValidRelocs(const object::SectionRef &Section,
108 const object::ObjectFile &Obj,
109 const DebugMapObject &DMO);
111 void findValidRelocsMachO(const object::SectionRef &Section,
112 const object::MachOObjectFile &Obj,
113 const DebugMapObject &DMO);
116 std::string OutputFilename;
118 BinaryHolder BinHolder;
120 /// The units of the current debug map object.
121 std::vector<CompileUnit> Units;
124 /// \brief Recursive helper to gather the child->parent relationships in the
125 /// original compile unit.
126 void GatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, unsigned ParentIdx,
128 unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
129 CU.getInfo(MyIdx).ParentIdx = ParentIdx;
131 if (DIE->hasChildren())
132 for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
133 Child = Child->getSibling())
134 GatherDIEParents(Child, MyIdx, CU);
137 void DwarfLinker::startDebugObject(DWARFContext &Dwarf) {
138 Units.reserve(Dwarf.getNumCompileUnits());
142 void DwarfLinker::endDebugObject() {
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) {
154 Section.getContents(Contents);
155 DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
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);
162 if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) {
163 errs() << "warning: unsupported relocation in debug_info section.\n";
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);
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";
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);
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);
197 errs() << "warning: unsupported object file type: " << Obj.getFileName()
200 if (ValidRelocs.empty())
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());
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
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")
225 return findValidRelocs(Section, Obj, DMO);
230 bool DwarfLinker::link(const DebugMap &Map) {
232 if (Map.begin() == Map.end()) {
233 errs() << "Empty debug map.\n";
237 for (const auto &Obj : Map.objects()) {
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";
246 // Look for relocations that correspond to debug map entries.
247 if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
249 outs() << "No valid relocations found. Skipping.\n";
253 // Setup access to the debug info.
254 DWARFContextInMemory DwarfContext(*ErrOrObj);
255 startDebugObject(DwarfContext);
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.
259 for (const auto &CU : DwarfContext.compile_units()) {
260 auto *CUDie = CU->getCompileUnitDIE(false);
262 outs() << "Input compilation unit:";
263 CUDie->dump(outs(), CU.get(), 0);
265 Units.emplace_back(*CU);
266 GatherDIEParents(CUDie, 0, Units.back());
269 // Clean-up before starting working on the next object.
277 bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) {
278 DwarfLinker Linker(OutputFilename, Verbose);
279 return Linker.link(DM);