[llvm] r229178 - [dsymutil] Find relocations that correspond to debug map entries.
Frederic Riss
friss at apple.com
Fri Feb 13 15:18:22 PST 2015
Author: friss
Date: Fri Feb 13 17:18:22 2015
New Revision: 229178
URL: http://llvm.org/viewvc/llvm-project?rev=229178&view=rev
Log:
[dsymutil] Find relocations that correspond to debug map entries.
These 'valid relocations' in the debug_info section will be how
dsymutil identifies the DIEs it needs to keep in the linked debug
information.
Modified:
llvm/trunk/tools/dsymutil/DwarfLinker.cpp
Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=229178&r1=229177&r2=229178&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Fri Feb 13 17:18:22 2015
@@ -12,6 +12,7 @@
#include "dsymutil.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/Object/MachO.h"
#include <string>
namespace llvm {
@@ -44,6 +45,19 @@ private:
};
/// \brief The core of the Dwarf linking logic.
+///
+/// The link of the dwarf information from the object files will be
+/// driven by the selection of 'root DIEs', which are DIEs that
+/// describe variables or functions that are present in the linked
+/// binary (and thus have entries in the debug map). All the debug
+/// information that will be linked (the DIEs, but also the line
+/// tables, ranges, ...) is derived from that set of root DIEs.
+///
+/// The root DIEs are identified because they contain relocations that
+/// correspond to a debug map entry at specific places (the low_pc for
+/// a function, the location for a variable). These relocations are
+/// called ValidRelocs in the DwarfLinker and are gathered as a very
+/// first step when we start processing a DebugMapObject.
class DwarfLinker {
public:
DwarfLinker(StringRef OutputFilename, bool Verbose)
@@ -59,6 +73,45 @@ private:
/// \brief Called at the end of a debug object link.
void endDebugObject();
+ /// \defgroup FindValidRelocations Translate debug map into a list
+ /// of relevant relocations
+ ///
+ /// @{
+ struct ValidReloc {
+ uint32_t Offset;
+ uint32_t Size;
+ uint64_t Addend;
+ const DebugMapObject::DebugMapEntry *Mapping;
+
+ ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
+ const DebugMapObject::DebugMapEntry *Mapping)
+ : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
+
+ bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
+ };
+
+ /// \brief The valid relocations for the current DebugMapObject.
+ /// This vector is sorted by relocation offset.
+ std::vector<ValidReloc> ValidRelocs;
+
+ /// \brief Index into ValidRelocs of the next relocation to
+ /// consider. As we walk the DIEs in acsending file offset and as
+ /// ValidRelocs is sorted by file offset, keeping this index
+ /// uptodate is all we have to do to have a cheap lookup during the
+ /// root DIE selection.
+ unsigned NextValidReloc;
+
+ bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ bool findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ void findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO);
+ /// @}
private:
std::string OutputFilename;
bool Verbose;
@@ -83,9 +136,96 @@ void GatherDIEParents(const DWARFDebugIn
void DwarfLinker::startDebugObject(DWARFContext &Dwarf) {
Units.reserve(Dwarf.getNumCompileUnits());
+ NextValidReloc = 0;
+}
+
+void DwarfLinker::endDebugObject() {
+ Units.clear();
+ ValidRelocs.clear();
+}
+
+/// \brief Iterate over the relocations of the given \p Section and
+/// store the ones that correspond to debug map entries into the
+/// ValidRelocs array.
+void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ StringRef Contents;
+ Section.getContents(Contents);
+ DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
+
+ for (const object::RelocationRef &Reloc : Section.relocations()) {
+ object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
+ MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
+ unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
+ uint64_t Offset64;
+ if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) {
+ errs() << "warning: unsupported relocation in debug_info section.\n";
+ continue;
+ }
+ uint32_t Offset = Offset64;
+ // Mach-o uses REL relocations, the addend is at the relocation offset.
+ uint64_t Addend = Data.getUnsigned(&Offset, RelocSize);
+
+ auto Sym = Reloc.getSymbol();
+ if (Sym != Obj.symbol_end()) {
+ StringRef SymbolName;
+ if (Sym->getName(SymbolName)) {
+ errs() << "warning: error getting relocation symbol name.\n";
+ continue;
+ }
+ if (const auto *Mapping = DMO.lookupSymbol(SymbolName))
+ ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
+ } else if (const auto *Mapping = DMO.lookupObjectAddress(Addend)) {
+ // Do not store the addend. The addend was the address of the
+ // symbol in the object file, the address in the binary that is
+ // stored in the debug map doesn't need to be offseted.
+ ValidRelocs.emplace_back(Offset64, RelocSize, 0, Mapping);
+ }
+ }
}
-void DwarfLinker::endDebugObject() { Units.clear(); }
+/// \brief Dispatch the valid relocation finding logic to the
+/// appropriate handler depending on the object file format.
+bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ // Dispatch to the right handler depending on the file type.
+ if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
+ findValidRelocsMachO(Section, *MachOObj, DMO);
+ else
+ errs() << "warning: unsupported object file type: " << Obj.getFileName()
+ << '\n';
+
+ if (ValidRelocs.empty())
+ return false;
+
+ // Sort the relocations by offset. We will walk the DIEs linearly in
+ // the file, this allows us to just keep an index in the relocation
+ // array that we advance during our walk, rather than resorting to
+ // some associative container. See DwarfLinker::NextValidReloc.
+ std::sort(ValidRelocs.begin(), ValidRelocs.end());
+ return true;
+}
+
+/// \brief Look for relocations in the debug_info section that match
+/// entries in the debug map. These relocations will drive the Dwarf
+/// link by indicating which DIEs refer to symbols present in the
+/// linked binary.
+/// \returns wether there are any valid relocations in the debug info.
+bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ // Find the debug_info section.
+ for (const object::SectionRef &Section : Obj.sections()) {
+ StringRef SectionName;
+ Section.getName(SectionName);
+ SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+ if (SectionName != "debug_info")
+ continue;
+ return findValidRelocs(Section, Obj, DMO);
+ }
+ return false;
+}
bool DwarfLinker::link(const DebugMap &Map) {
@@ -103,6 +243,13 @@ bool DwarfLinker::link(const DebugMap &M
continue;
}
+ // Look for relocations that correspond to debug map entries.
+ if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
+ if (Verbose)
+ outs() << "No valid relocations found. Skipping.\n";
+ continue;
+ }
+
// Setup access to the debug info.
DWARFContextInMemory DwarfContext(*ErrOrObj);
startDebugObject(DwarfContext);
More information about the llvm-commits
mailing list