--- /dev/null
+/* This is the main file used to produce the basic* objects that are
+ used for the dsymutil tests.
+
+ These are compiled in a couple of different ways (always on a
+ Darwin system):
+ Basic compilation:
+ for FILE in basic1.c basic2.c basic3.c; do
+ clang -g -c $FILE -o ${FILE%.c}.macho.x86_64.o
+ done
+ clang basic1.macho.x86_64.o basic2.macho.x86_64.o basic3.macho.x86_64.o -o basic.macho.x86_64 -Wl,-dead_strip
+
+ LTO compilation:
+ for FILE in basic1.c basic2.c basic3.c; do
+ clang -g -c -flto $FILE -o ${FILE%.c}-lto.o
+ done
+ clang basic1-lto.o basic2-lto.o basic3-lto.o -o basic-lto.macho.x86_64 -Wl,-object_path_lto,$PWD/basic-lto.macho.x86_64.o -Wl,-dead_strip
+ rm basic1-lto.o basic2-lto.o basic3-lto.o
+
+*/
+
+int foo(int);
+
+int main(int argc, const char *argv[]) {
+ return foo(argc);
+}
--- /dev/null
+/* For compilation instructions see basic1.c. */
+
+static int baz = 42;
+static int private_int;
+extern volatile int val;
+int unused_data = 1;
+
+int bar(int);
+
+void unused1() {
+ bar(baz);
+}
+
+static int inc() {
+ return ++private_int;
+}
+
+__attribute__((noinline))
+int foo(int arg) {
+ return bar(arg+val) + inc() + baz++;
+}
+
--- /dev/null
+/* For compilation instructions see basic1.c. */
+
+volatile int val;
+
+extern int foo(int);
+
+int unused2() {
+ return foo(val);
+}
+
+static int inc() {
+ return ++val;
+}
+
+__attribute__((noinline))
+int bar(int arg) {
+ if (arg > 42)
+ return inc();
+ return foo(val + arg);
+}
--- /dev/null
+RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic.macho.x86_64 | FileCheck %s
+RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO
+RUN: llvm-dsymutil -v -parse-only %p/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=NOT-FOUND
+RUN: not llvm-dsymutil -v -parse-only %p/Inputs/inexistant 2>&1 | FileCheck %s --check-prefix=NO-EXECUTABLE
+Check that We can parse the debug map of the basic executable.
+
+CHECK-NOT: error
+CHECK: DEBUG MAP:
+CHECK: /Inputs/basic1.macho.x86_64.o:
+CHECK: 0000000000000000 => 0000000100000ea0 _main
+CHECK: /Inputs/basic2.macho.x86_64.o:
+CHECK: 0000000000000310 => 0000000100001000 _baz
+CHECK: 0000000000000020 => 0000000100000ed0 _foo
+CHECK: 0000000000000070 => 0000000100000f20 _inc
+CHECK: 0000000000000560 => 0000000100001008 _private_int
+CHECK: /Inputs/basic3.macho.x86_64.o:
+CHECK: 0000000000000020 => 0000000100000f40 _bar
+CHECK: 0000000000000070 => 0000000100000f90 _inc
+CHECK: 0000000000000004 => 0000000100001004 _val
+CHECK: END DEBUG MAP
+
+
+Check that we can parse the debug-map of the basic-lto executable
+
+CHECK-LTO-NOT: error
+CHECK-LTO: DEBUG MAP:
+CHECK-LTO: /Inputs/basic-lto.macho.x86_64.o:
+CHECK-LTO: 0000000000000050 => 0000000100000f90 _bar
+CHECK-LTO: 0000000000000658 => 0000000100001000 _baz
+CHECK-LTO: 0000000000000010 => 0000000100000f50 _foo
+CHECK-LTO: 0000000000000000 => 0000000100000f40 _main
+CHECK-LTO: 00000000000008e8 => 0000000100001008 _private_int
+CHECK-LTO: 00000000000008ec => 0000000100001004 _val
+CHECK-LTO: END DEBUG MAP
+
+Check that we warn about missing object files (this presumes that the files aren't
+present in the machine's /Inputs/ folder, which should be a pretty safe bet).
+
+NOT-FOUND: cannot open{{.*}}"/Inputs/basic1.macho.x86_64.o": No such file
+NOT-FOUND: cannot open{{.*}}"/Inputs/basic2.macho.x86_64.o": No such file
+NOT-FOUND: cannot open{{.*}}"/Inputs/basic3.macho.x86_64.o": No such file
+NOT-FOUND: DEBUG MAP:
+NOT-FOUND-NEXT: END DEBUG MAP
+
+Check that we correctly error out on invalid executatble.
+
+NO-EXECUTABLE: cannot parse{{.*}}/inexistant": No such file
+NO-EXECUTABLE-NOT: DEBUG MAP
add_llvm_tool_subdirectory(llvm-readobj)
add_llvm_tool_subdirectory(llvm-rtdyld)
add_llvm_tool_subdirectory(llvm-dwarfdump)
+add_llvm_tool_subdirectory(dsymutil)
add_llvm_tool_subdirectory(llvm-vtabledump)
if( LLVM_USE_INTEL_JITEVENTS )
add_llvm_tool_subdirectory(llvm-jitlistener)
;===------------------------------------------------------------------------===;
[common]
-subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder
+subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
[component_0]
type = Group
macho-dump llvm-objdump llvm-readobj llvm-rtdyld \
llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
- llvm-vtabledump verify-uselistorder
+ llvm-vtabledump verify-uselistorder dsymutil
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
--- /dev/null
+set(LLVM_LINK_COMPONENTS
+ Object
+ Support
+ )
+
+add_llvm_tool(llvm-dsymutil
+ dsymutil.cpp
+ DebugMap.cpp
+ DwarfLinker.cpp
+ MachODebugMapParser.cpp
+ )
+
--- /dev/null
+//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "DebugMap.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+namespace llvm {
+
+using namespace llvm::object;
+
+DebugMapObject::DebugMapObject(StringRef ObjectFilename)
+ : Filename(ObjectFilename) {}
+
+bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress,
+ uint64_t LinkedAddress) {
+ auto InsertResult = Symbols.insert(std::make_pair(Name,
+ SymbolMapping{ObjectAddress,
+ LinkedAddress}));
+ return InsertResult.second;
+}
+
+void DebugMapObject::print(raw_ostream& OS) const {
+ OS << getObjectFilename() << ":\n";
+ // Sort the symbols in alphabetical order, like llvm-nm (and to get
+ // deterministic output for testing).
+ typedef StringMapEntry<SymbolMapping> MapEntryTy;
+ std::vector<const MapEntryTy *> Entries;
+ Entries.reserve(Symbols.getNumItems());
+ for (auto SymIt = Symbols.begin(), End = Symbols.end(); SymIt != End; ++SymIt)
+ Entries.push_back(&*SymIt);
+ std::sort(Entries.begin(), Entries.end(),
+ [] (const MapEntryTy *LHS, const MapEntryTy *RHS) {
+ return LHS->getKey() < RHS->getKey();
+ });
+ for (const auto *Entry: Entries) {
+ const auto &Sym = Entry->getValue();
+ OS << format("\t%016" PRIx64 " => %016" PRIx64 "\t%s\n",
+ Sym.ObjectAddress, Sym.BinaryAddress, Entry->getKeyData());
+ }
+ OS << '\n';
+}
+
+#ifndef NDEBUG
+void DebugMapObject::dump() const {
+ print(errs());
+}
+#endif
+
+DebugMapObject& DebugMap::addDebugMapObject(StringRef ObjectFilePath) {
+ Objects.emplace_back(new DebugMapObject(ObjectFilePath));
+ return *Objects.back();
+}
+
+const DebugMapObject::SymbolMapping *
+DebugMapObject::lookupSymbol(StringRef SymbolName) const {
+ StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
+ if (Sym == Symbols.end())
+ return nullptr;
+ return &Sym->getValue();
+}
+
+void DebugMap::print(raw_ostream& OS) const {
+ OS << "DEBUG MAP: object addr => executable addr\tsymbol name\n";
+ for (const auto &Obj: objects())
+ Obj->print(OS);
+ OS << "END DEBUG MAP\n";
+}
+
+#ifndef NDEBUG
+void DebugMap::dump() const {
+ print(errs());
+}
+#endif
+}
--- /dev/null
+//===- tools/dsymutil/DebugMap.h - Generic debug map representation -------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This file contains the class declaration of the DebugMap
+/// entity. A DebugMap lists all the object files linked together to
+/// produce an executable along with the linked address of all the
+/// atoms used in these object files.
+/// The DebugMap is an input to the DwarfLinker class that will
+/// extract the Dwarf debug information from the referenced object
+/// files and link their usefull debug info together.
+///
+//===----------------------------------------------------------------------===//
+#ifndef DSYMUTIL_DEBUGMAP_H
+#define DSYMUTIL_DEBUGMAP_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/iterator_range.h"
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DebugMapObject;
+
+/// \brief The DebugMap object stores the list of object files to
+/// query for debug information along with the mapping between the
+/// symbols' addresses in the object file to their linked address in
+/// the linked binary.
+///
+/// A DebugMap producer could look like this:
+/// DebugMap *DM = new DebugMap();
+/// for (const auto &Obj: LinkedObjects) {
+/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath());
+/// for (const auto &Sym: Obj.getLinkedSymbols())
+/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(),
+/// Sym.getBinaryAddress());
+/// }
+///
+/// A DebugMap consumer can then use the map to link the debug
+/// information. For example something along the lines of:
+/// for (const auto &DMO: DM->objects()) {
+/// auto Obj = createBinary(DMO.getObjectFilename());
+/// for (auto &DIE: Obj.getDwarfDIEs()) {
+/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName()))
+/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress);
+/// else
+/// DIE.discardSubtree();
+/// }
+/// }
+class DebugMap
+{
+ typedef std::vector<std::unique_ptr<DebugMapObject>> ObjectContainer;
+ ObjectContainer Objects;
+
+public:
+ typedef ObjectContainer::const_iterator const_iterator;
+
+ iterator_range<const_iterator> objects() const {
+ return make_range(begin(), end());
+ }
+
+ const_iterator begin() const {
+ return Objects.begin();
+ }
+
+ const_iterator end() const {
+ return Objects.end();
+ }
+
+ /// This function adds an DebugMapObject to the list owned by this
+ /// debug map.
+ DebugMapObject& addDebugMapObject(StringRef ObjectFilePath);
+
+ void print(raw_ostream& OS) const;
+
+#ifndef NDEBUG
+ void dump() const;
+#endif
+};
+
+/// \brief The DebugMapObject represents one object file described by
+/// the DebugMap. It contains a list of mappings between addresses in
+/// the object file and in the linked binary for all the linked atoms
+/// in this object file.
+class DebugMapObject {
+public:
+ struct SymbolMapping {
+ uint64_t ObjectAddress;
+ uint64_t BinaryAddress;
+ };
+
+ /// \brief Adds a symbol mapping to this DebugMapObject.
+ /// \returns false if the symbol was already registered. The request
+ /// is discarded in this case.
+ bool addSymbol(llvm::StringRef SymName, uint64_t ObjectAddress,
+ uint64_t LinkedAddress);
+
+ /// \bried Lookup a symbol mapping.
+ /// \returns null if the symbol isn't found.
+ const SymbolMapping *lookupSymbol(StringRef SymbolName) const;
+
+ llvm::StringRef getObjectFilename() const { return Filename; }
+
+ void print(raw_ostream& OS) const;
+#ifndef NDEBUG
+ void dump() const;
+#endif
+private:
+ friend class DebugMap;
+ /// DebugMapObjects can only be constructed by the owning DebugMap.
+ DebugMapObject(StringRef ObjectFilename);
+
+ std::string Filename;
+ StringMap<SymbolMapping> Symbols;
+};
+
+}
+
+#endif // DSYMUTIL_DEBUGMAP_H
--- /dev/null
+//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "DwarfLinker.h"
+#include "DebugMap.h"
+
+namespace llvm {
+
+DwarfLinker::DwarfLinker(StringRef OutputFilename)
+ : OutputFilename(OutputFilename)
+{}
+
+bool DwarfLinker::link(const DebugMap &Map) {
+ return true;
+}
+
+}
--- /dev/null
+//===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker -------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This file contains the class declaration of the DwarfLinker
+/// object. A DwarfLinker takes a DebugMap as input and links the
+/// debug information of all the referenced object files together. It
+/// may drop and rewrite some parts of the debug info tree in the
+/// process.
+///
+//===----------------------------------------------------------------------===//
+#ifndef DSYMUTIL_DWARFLINKER_H
+#define DSYMUTIL_DWARFLINKER_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+class DebugMap;
+
+class DwarfLinker {
+ std::string OutputFilename;
+public:
+ DwarfLinker(StringRef OutputFilename);
+
+ /// \brief Link the passed debug map into the ouptut file.
+ /// \returns false if the link encountered a fatal error.
+ bool link(const DebugMap&);
+};
+
+}
+
+#endif
--- /dev/null
+;===- ./tools/dsymutil/LLVMBuild.txt ---------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = dsymutil
+parent = Tools
+required_libraries = Object Support
--- /dev/null
+//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachODebugMapParser.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::object;
+
+namespace llvm {
+
+static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; }
+
+static ErrorOr<OwningBinary<MachOObjectFile>> createMachOBinary(StringRef file) {
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
+ if (BinaryOrErr.getError())
+ return BinaryOrErr.getError();
+
+ std::unique_ptr<Binary> Bin;
+ std::unique_ptr<MemoryBuffer> Buf;
+ std::tie(Bin, Buf) = BinaryOrErr->takeBinary();
+ if (!isa<MachOObjectFile>(Bin.get()))
+ return make_error_code(object_error::invalid_file_type);
+
+ std::unique_ptr<MachOObjectFile> MachOFile(cast<MachOObjectFile>(Bin.release()));
+ return OwningBinary<MachOObjectFile>(std::move(MachOFile), std::move(Buf));
+}
+
+/// Reset the parser state coresponding to the current object
+/// file. This is to be called after an object file is finished
+/// processing.
+void MachODebugMapParser::resetParserState() {
+ CurrentObjectFile = OwningBinary<object::MachOObjectFile>();
+ CurrentObjectAddresses.clear();
+ CurrentDebugMapObject = nullptr;
+}
+
+/// Create a new DebugMapObject. This function resets the state of the
+/// parser that was referring to the last object file and sets
+/// everything up to add symbols to the new one.
+void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) {
+ resetParserState();
+
+ std::string Path = Filename;
+ if (!PathPrefix.empty())
+ Path = PathPrefix + sys::path::get_separator().data() + Path;
+
+ auto MachOOrError = createMachOBinary(Path);
+ if (auto Error = MachOOrError.getError()) {
+ Warning(Twine("cannot open debug object \"") + Path + "\": "
+ + Error.message() + "\n");
+ return;
+ }
+
+ CurrentObjectFile = std::move(*MachOOrError);
+ loadCurrentObjectFileSymbols();
+ CurrentDebugMapObject = &Result->addDebugMapObject(Path);
+}
+
+/// This main parsing routine tries to open the main binary and if
+/// successful iterates over the STAB entries. The real parsing is
+/// done in handleStabSymbolTableEntry.
+ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
+ auto MainBinaryOrError = createMachOBinary(BinaryPath);
+ if (MainBinaryOrError.getError())
+ return MainBinaryOrError.getError();
+
+ MainOwningBinary = std::move(*MainBinaryOrError);
+ Result = make_unique<DebugMap>();
+ const auto &MainBinary = *MainOwningBinary.getBinary();
+ for (const SymbolRef &Symbol : MainBinary.symbols()) {
+ const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
+ if (MainBinary.is64Bit())
+ handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
+ else
+ handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
+ }
+
+ resetParserState();
+ return std::move(Result);
+}
+
+/// Interpret the STAB entries to fill the DebugMap.
+void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
+ uint8_t Type,
+ uint8_t SectionIndex,
+ uint16_t Flags,
+ uint64_t Value) {
+ if (!(Type & MachO::N_STAB))
+ return;
+
+ const MachOObjectFile &MachOBinary = *MainOwningBinary.getBinary();
+ const char *Name = &MachOBinary.getStringTableData().data()[StringIndex];
+
+ // An N_OSO entry represents the start of a new object file description.
+ if (Type == MachO::N_OSO)
+ return switchToNewDebugMapObject(Name);
+
+ // If the last N_OSO object file wasn't found,
+ // CurrentDebugMapObject will be null. Do not update anything
+ // until we find the next valid N_OSO entry.
+ if (!CurrentDebugMapObject)
+ return;
+
+ switch (Type) {
+ case MachO::N_GSYM:
+ // This is a global variable. We need to query the main binary
+ // symbol table to find its address as it might not be in the
+ // debug map (for common symbols).
+ Value = getMainBinarySymbolAddress(Name);
+ if (Value == UnknownAddressOrSize)
+ return;
+ break;
+ case MachO::N_FUN:
+ // Functions are scopes in STABS. They have an end marker that we
+ // need to ignore.
+ if (Name[0] == '\0')
+ return;
+ break;
+ case MachO::N_STSYM:
+ break;
+ default:
+ return;
+ }
+
+ auto ObjectSymIt = CurrentObjectAddresses.find(Name);
+ if (ObjectSymIt == CurrentObjectAddresses.end())
+ return Warning("could not find object file symbol for symbol " +
+ Twine(Name));
+ if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value))
+ return Warning(Twine("failed to insert symbol '") + Name + "' in the debug map.");
+}
+
+/// Load the current object file symbols into CurrentObjectAddresses.
+void MachODebugMapParser::loadCurrentObjectFileSymbols() {
+ CurrentObjectAddresses.clear();
+ const auto &Binary = *CurrentObjectFile.getBinary();
+
+ for (auto Sym : Binary.symbols()) {
+ StringRef Name;
+ uint64_t Addr;
+ if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
+ Sym.getName(Name))
+ continue;
+ CurrentObjectAddresses[Name] = Addr;
+ }
+}
+
+/// Lookup a symbol address in the main binary symbol table. The
+/// parser only needs to query common symbols, thus not every symbol's
+/// address is available through this function.
+uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
+ if (MainBinarySymbolAddresses.empty())
+ loadMainBinarySymbols();
+
+ auto Sym = MainBinarySymbolAddresses.find(Name);
+ if (Sym == MainBinarySymbolAddresses.end())
+ return UnknownAddressOrSize;
+ return Sym->second;
+}
+
+/// Load the interesting main binary symbols' addresses into
+/// MainBinarySymbolAddresses.
+void MachODebugMapParser::loadMainBinarySymbols() {
+ const MachOObjectFile &Binary = *MainOwningBinary.getBinary();
+ section_iterator Section = Binary.section_end();
+ for (const auto &Sym : Binary.symbols()) {
+ SymbolRef::Type Type;
+ // Skip undefined and STAB entries.
+ if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) ||
+ (Type & SymbolRef::ST_Unknown))
+ continue;
+ StringRef Name;
+ uint64_t Addr;
+ // The only symbols of interest are the global variables. These
+ // are the only ones that need to be queried because the address
+ // of common data won't be described in the debug map. All other
+ // addresses should be fetched for the debug map.
+ if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
+ !(Sym.getFlags() & SymbolRef::SF_Global) ||
+ Sym.getSection(Section) || Section->isText() || Sym.getName(Name) ||
+ Name.size() == 0 || Name[0] == '\0')
+ continue;
+ MainBinarySymbolAddresses[Name] = Addr;
+ }
+}
+
+}
--- /dev/null
+//===- tools/dsymutil/MachODebugMapParser.h - Parse STABS debug maps ------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// This file contains the class declaration for the code that parses STABS
+/// debug maps that are embedded in the binaries symbol tables.
+///
+//===----------------------------------------------------------------------===//
+#ifndef DSYMUTIL_MACHODEBUGMAPPARSER_H
+#define DSYMUTIL_MACHODEBUGMAPPARSER_H
+
+#include "DebugMap.h"
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/Error.h"
+
+namespace llvm {
+
+class MachODebugMapParser {
+public:
+ MachODebugMapParser(StringRef BinaryPath)
+ : BinaryPath(BinaryPath) {}
+
+ /// \brief Add a prefix to every object file path before trying to
+ /// open it.
+ void setPreprendPath(StringRef Prefix) { PathPrefix = Prefix; }
+
+ /// \brief Parses and returns the DebugMap of the input binary.
+ /// \returns an error in case the provided BinaryPath doesn't exist
+ /// or isn't of a supported type.
+ ErrorOr<std::unique_ptr<DebugMap>> parse();
+
+private:
+ std::string BinaryPath;
+ std::string PathPrefix;
+
+ /// OwningBinary constructed from the BinaryPath.
+ object::OwningBinary<object::MachOObjectFile> MainOwningBinary;
+ /// Map of the binary symbol addresses.
+ StringMap<uint64_t> MainBinarySymbolAddresses;
+ /// The constructed DebugMap.
+ std::unique_ptr<DebugMap> Result;
+
+ /// Handle to the currently processed object file.
+ object::OwningBinary<object::MachOObjectFile> CurrentObjectFile;
+ /// Map of the currently processed object file symbol addresses.
+ StringMap<uint64_t> CurrentObjectAddresses;
+ /// Element of the debug map corresponfing to the current object file.
+ DebugMapObject *CurrentDebugMapObject;
+
+ void switchToNewDebugMapObject(StringRef Filename);
+ void resetParserState();
+ uint64_t getMainBinarySymbolAddress(StringRef Name);
+ void loadMainBinarySymbols();
+ void loadCurrentObjectFileSymbols();
+ void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
+ uint8_t SectionIndex, uint16_t Flags,
+ uint64_t Value);
+
+ template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
+ handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
+ STE.n_value);
+ }
+};
+
+}
+
+#endif // DSYMUTIL_MACHODEBUGMAPPARSER_H
--- /dev/null
+##===- tools/dsymutil/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+TOOLNAME := llvm-dsymutil
+LINK_COMPONENTS := Object Support
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
--- /dev/null
+//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that aims to be a dropin replacement for
+// Darwin's dsymutil.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DebugMap.h"
+#include "DwarfLinker.h"
+#include "MachODebugMapParser.h"
+
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Options.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+#include <string>
+
+static llvm::cl::opt<std::string> InputFile(llvm::cl::Positional,
+ llvm::cl::desc("<input file>"),
+ llvm::cl::init("-"));
+
+static llvm::cl::opt<std::string> OsoPrependPath("oso-prepend-path",
+ llvm::cl::desc("<path>"));
+
+static llvm::cl::opt<bool> Verbose("v", llvm::cl::desc("Verbosity level"),
+ llvm::cl::init(false));
+
+static llvm::cl::opt<bool> ParseOnly("parse-only",
+ llvm::cl::desc("Only parse the debug map, do "
+ "not actaully link the DWARF."),
+ llvm::cl::init(false));
+
+int main(int argc, char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
+ llvm::llvm_shutdown_obj Shutdown;
+
+ llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
+
+ llvm::MachODebugMapParser Parser(InputFile);
+ Parser.setPreprendPath(OsoPrependPath);
+ llvm::ErrorOr<std::unique_ptr<llvm::DebugMap>> DebugMap = Parser.parse();
+
+ if (auto EC = DebugMap.getError()) {
+ llvm::errs() << "error: cannot parse the debug map for \"" << InputFile <<
+ "\": " << EC.message() << '\n';
+ return 1;
+ }
+
+ if (Verbose)
+ (*DebugMap)->print(llvm::outs());
+
+ if (ParseOnly)
+ return 0;
+
+ llvm::DwarfLinker Linker(InputFile + ".dwarf");
+ return !Linker.link(*DebugMap.get());
+}