blob: be6fb3addd4cbdbece1f0c95fb1d417d4da35df9 [file] [log] [blame]
Frederic Riss231f7142014-12-12 17:31:24 +00001//===- 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 Rissd3455182015-01-28 18:27:01 +000010#include "BinaryHolder.h"
11#include "DebugMap.h"
Frederic Riss231f7142014-12-12 17:31:24 +000012#include "dsymutil.h"
Zachary Turner82af9432015-01-30 18:07:45 +000013#include "llvm/DebugInfo/DWARF/DWARFContext.h"
14#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
Frederic Riss1036e642015-02-13 23:18:22 +000015#include "llvm/Object/MachO.h"
Frederic Rissd3455182015-01-28 18:27:01 +000016#include <string>
Frederic Riss231f7142014-12-12 17:31:24 +000017
18namespace llvm {
19namespace dsymutil {
20
Frederic Rissd3455182015-01-28 18:27:01 +000021namespace {
22
Frederic Riss563cba62015-01-28 22:15:14 +000023/// \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.
26class CompileUnit {
27public:
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 Rissc3349d42015-02-13 23:18:27 +000037 DWARFUnit &getOrigUnit() const { return OrigUnit; }
Frederic Riss563cba62015-01-28 22:15:14 +000038
39 DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
40 const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
41
42private:
43 DWARFUnit &OrigUnit;
44 std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
45};
46
Frederic Rissd3455182015-01-28 18:27:01 +000047/// \brief The core of the Dwarf linking logic.
Frederic Riss1036e642015-02-13 23:18:22 +000048///
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 Rissd3455182015-01-28 18:27:01 +000061class DwarfLinker {
62public:
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
69private:
Frederic Riss563cba62015-01-28 22:15:14 +000070 /// \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 Riss1036e642015-02-13 23:18:22 +000076 /// \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 Riss563cba62015-01-28 22:15:14 +0000115private:
Frederic Rissd3455182015-01-28 18:27:01 +0000116 std::string OutputFilename;
117 bool Verbose;
118 BinaryHolder BinHolder;
Frederic Riss563cba62015-01-28 22:15:14 +0000119
120 /// The units of the current debug map object.
121 std::vector<CompileUnit> Units;
Frederic Rissd3455182015-01-28 18:27:01 +0000122};
123
Frederic Riss563cba62015-01-28 22:15:14 +0000124/// \brief Recursive helper to gather the child->parent relationships in the
125/// original compile unit.
126void 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
137void DwarfLinker::startDebugObject(DWARFContext &Dwarf) {
138 Units.reserve(Dwarf.getNumCompileUnits());
Frederic Riss1036e642015-02-13 23:18:22 +0000139 NextValidReloc = 0;
Frederic Riss563cba62015-01-28 22:15:14 +0000140}
141
Frederic Riss1036e642015-02-13 23:18:22 +0000142void 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.
150void 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.
190bool 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.
216bool 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 Riss563cba62015-01-28 22:15:14 +0000229
Frederic Rissd3455182015-01-28 18:27:01 +0000230bool 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 Riss1036e642015-02-13 23:18:22 +0000246 // 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 Riss563cba62015-01-28 22:15:14 +0000253 // Setup access to the debug info.
Frederic Rissd3455182015-01-28 18:27:01 +0000254 DWARFContextInMemory DwarfContext(*ErrOrObj);
Frederic Riss563cba62015-01-28 22:15:14 +0000255 startDebugObject(DwarfContext);
Frederic Rissd3455182015-01-28 18:27:01 +0000256
Frederic Riss563cba62015-01-28 22:15:14 +0000257 // 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 Rissd3455182015-01-28 18:27:01 +0000259 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 Riss563cba62015-01-28 22:15:14 +0000265 Units.emplace_back(*CU);
266 GatherDIEParents(CUDie, 0, Units.back());
Frederic Rissd3455182015-01-28 18:27:01 +0000267 }
Frederic Riss563cba62015-01-28 22:15:14 +0000268
269 // Clean-up before starting working on the next object.
270 endDebugObject();
Frederic Rissd3455182015-01-28 18:27:01 +0000271 }
272
Frederic Riss231f7142014-12-12 17:31:24 +0000273 return true;
274}
275}
Frederic Rissd3455182015-01-28 18:27:01 +0000276
277bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) {
278 DwarfLinker Linker(OutputFilename, Verbose);
279 return Linker.link(DM);
280}
281}
Frederic Riss231f7142014-12-12 17:31:24 +0000282}