mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-27 13:30:05 +00:00
llvm-symbolizer: add support for Mach-O universal binaries
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185137 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
363720e06c
commit
8175bc3d3b
@ -22,6 +22,8 @@ EXAMPLE
|
|||||||
a.out 0x4004f4
|
a.out 0x4004f4
|
||||||
/tmp/b.out 0x400528
|
/tmp/b.out 0x400528
|
||||||
/tmp/c.so 0x710
|
/tmp/c.so 0x710
|
||||||
|
/tmp/mach_universal_binary:i386 0x1f84
|
||||||
|
/tmp/mach_universal_binary:x86_64 0x100000f24
|
||||||
$ llvm-symbolizer < addr.txt
|
$ llvm-symbolizer < addr.txt
|
||||||
main
|
main
|
||||||
/tmp/a.cc:4
|
/tmp/a.cc:4
|
||||||
@ -38,6 +40,12 @@ EXAMPLE
|
|||||||
main
|
main
|
||||||
/tmp/source.cc:8
|
/tmp/source.cc:8
|
||||||
|
|
||||||
|
_main
|
||||||
|
/tmp/source_i386.cc:8
|
||||||
|
|
||||||
|
_main
|
||||||
|
/tmp/source_x86_64.cc:8
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@ -59,6 +67,14 @@ OPTIONS
|
|||||||
If a source code location is in an inlined function, prints all the
|
If a source code location is in an inlined function, prints all the
|
||||||
inlnied frames. Defaults to true.
|
inlnied frames. Defaults to true.
|
||||||
|
|
||||||
|
.. option:: -default-arch
|
||||||
|
|
||||||
|
If a binary contains object files for multiple architectures (e.g. it is a
|
||||||
|
Mach-O universal binary), symbolize the object file for a given architecture.
|
||||||
|
You can also specify architecture by writing ``binary_name:arch_name`` in the
|
||||||
|
input (see example above). If architecture is not specified in either way,
|
||||||
|
address will not be symbolized. Defaults to empty string.
|
||||||
|
|
||||||
EXIT STATUS
|
EXIT STATUS
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
BIN
test/DebugInfo/Inputs/macho-universal
Executable file
BIN
test/DebugInfo/Inputs/macho-universal
Executable file
Binary file not shown.
10
test/DebugInfo/Inputs/macho-universal.cc
Normal file
10
test/DebugInfo/Inputs/macho-universal.cc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Built with Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
|
||||||
|
// clang++ -arch x86_64 -arch i386 macho-universal.cc
|
||||||
|
|
||||||
|
int inc(int x) {
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return inc(argc);
|
||||||
|
}
|
@ -3,9 +3,12 @@ RUN: echo "%p/Inputs/dwarfdump-test.elf-x86-64 0x400436" >> %t.input
|
|||||||
RUN: echo "%p/Inputs/dwarfdump-test4.elf-x86-64 0x62c" >> %t.input
|
RUN: echo "%p/Inputs/dwarfdump-test4.elf-x86-64 0x62c" >> %t.input
|
||||||
RUN: echo "%p/Inputs/dwarfdump-inl-test.elf-x86-64 0x710" >> %t.input
|
RUN: echo "%p/Inputs/dwarfdump-inl-test.elf-x86-64 0x710" >> %t.input
|
||||||
RUN: echo "\"%p/Inputs/dwarfdump-test3.elf-x86-64 space\" 0x633" >> %t.input
|
RUN: echo "\"%p/Inputs/dwarfdump-test3.elf-x86-64 space\" 0x633" >> %t.input
|
||||||
|
RUN: echo "%p/Inputs/macho-universal 0x1f84" >> %t.input
|
||||||
|
RUN: echo "%p/Inputs/macho-universal:i386 0x1f67" >> %t.input
|
||||||
|
RUN: echo "%p/Inputs/macho-universal:x86_64 0x100000f05" >> %t.input
|
||||||
|
|
||||||
RUN: llvm-symbolizer --functions --inlining --demangle=false < %t.input \
|
RUN: llvm-symbolizer --functions --inlining --demangle=false \
|
||||||
RUN: | FileCheck %s
|
RUN: --default-arch=i386 < %t.input | FileCheck %s
|
||||||
|
|
||||||
REQUIRES: shell
|
REQUIRES: shell
|
||||||
|
|
||||||
@ -29,5 +32,16 @@ CHECK-NEXT: dwarfdump-inl-test.cc:
|
|||||||
CHECK: _Z3do1v
|
CHECK: _Z3do1v
|
||||||
CHECK-NEXT: dwarfdump-test3-decl.h:7
|
CHECK-NEXT: dwarfdump-test3-decl.h:7
|
||||||
|
|
||||||
|
CHECK: _main
|
||||||
|
CHECK: __Z3inci
|
||||||
|
CHECK: __Z3inci
|
||||||
|
|
||||||
RUN: echo "unexisting-file 0x1234" > %t.input2
|
RUN: echo "unexisting-file 0x1234" > %t.input2
|
||||||
RUN: llvm-symbolizer < %t.input2
|
RUN: llvm-symbolizer < %t.input2
|
||||||
|
|
||||||
|
RUN: echo "%p/Inputs/macho-universal 0x1f84" > %t.input3
|
||||||
|
RUN: llvm-symbolizer < %t.input3 | FileCheck %s --check-prefix=UNKNOWN-ARCH
|
||||||
|
|
||||||
|
UNKNOWN-ARCH-NOT: main
|
||||||
|
UNKNOWN-ARCH: ??
|
||||||
|
UNKNOWN-ARCH-NOT: main
|
||||||
|
@ -198,23 +198,10 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
|
|||||||
|
|
||||||
void LLVMSymbolizer::flush() {
|
void LLVMSymbolizer::flush() {
|
||||||
DeleteContainerSeconds(Modules);
|
DeleteContainerSeconds(Modules);
|
||||||
|
DeleteContainerPointers(ParsedBinariesAndObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the object endianness is known.
|
static std::string getDarwinDWARFResourceForPath(const std::string &Path) {
|
||||||
static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
|
|
||||||
// FIXME: Implement this when libLLVMObject allows to do it easily.
|
|
||||||
IsLittleEndian = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ObjectFile *getObjectFile(const std::string &Path) {
|
|
||||||
OwningPtr<MemoryBuffer> Buff;
|
|
||||||
if (error(MemoryBuffer::getFile(Path, Buff)))
|
|
||||||
return 0;
|
|
||||||
return ObjectFile::createObjectFile(Buff.take());
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
|
|
||||||
StringRef Basename = sys::path::filename(Path);
|
StringRef Basename = sys::path::filename(Path);
|
||||||
const std::string &DSymDirectory = Path + ".dSYM";
|
const std::string &DSymDirectory = Path + ".dSYM";
|
||||||
SmallString<16> ResourceName = StringRef(DSymDirectory);
|
SmallString<16> ResourceName = StringRef(DSymDirectory);
|
||||||
@ -223,39 +210,85 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
|
|||||||
return ResourceName.str();
|
return ResourceName.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLVMSymbolizer::BinaryPair
|
||||||
|
LLVMSymbolizer::getOrCreateBinary(const std::string &Path) {
|
||||||
|
BinaryMapTy::iterator I = BinaryForPath.find(Path);
|
||||||
|
if (I != BinaryForPath.end())
|
||||||
|
return I->second;
|
||||||
|
Binary *Bin = 0;
|
||||||
|
Binary *DbgBin = 0;
|
||||||
|
OwningPtr<Binary> ParsedBinary;
|
||||||
|
OwningPtr<Binary> ParsedDbgBinary;
|
||||||
|
if (!error(createBinary(Path, ParsedBinary))) {
|
||||||
|
// Check if it's a universal binary.
|
||||||
|
Bin = ParsedBinary.take();
|
||||||
|
ParsedBinariesAndObjects.push_back(Bin);
|
||||||
|
if (Bin->isMachO() || Bin->isMachOUniversalBinary()) {
|
||||||
|
// On Darwin we may find DWARF in separate object file in
|
||||||
|
// resource directory.
|
||||||
|
const std::string &ResourcePath =
|
||||||
|
getDarwinDWARFResourceForPath(Path);
|
||||||
|
bool ResourceFileExists = false;
|
||||||
|
if (!sys::fs::exists(ResourcePath, ResourceFileExists) &&
|
||||||
|
ResourceFileExists &&
|
||||||
|
!error(createBinary(ResourcePath, ParsedDbgBinary))) {
|
||||||
|
DbgBin = ParsedDbgBinary.take();
|
||||||
|
ParsedBinariesAndObjects.push_back(DbgBin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DbgBin == 0)
|
||||||
|
DbgBin = Bin;
|
||||||
|
BinaryPair Res = std::make_pair(Bin, DbgBin);
|
||||||
|
BinaryForPath[Path] = Res;
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectFile *
|
||||||
|
LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) {
|
||||||
|
if (Bin == 0)
|
||||||
|
return 0;
|
||||||
|
ObjectFile *Res = 0;
|
||||||
|
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
|
||||||
|
ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find(
|
||||||
|
std::make_pair(UB, ArchName));
|
||||||
|
if (I != ObjectFileForArch.end())
|
||||||
|
return I->second;
|
||||||
|
OwningPtr<ObjectFile> ParsedObj;
|
||||||
|
if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) {
|
||||||
|
Res = ParsedObj.take();
|
||||||
|
ParsedBinariesAndObjects.push_back(Res);
|
||||||
|
}
|
||||||
|
ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
|
||||||
|
} else if (Bin->isObject()) {
|
||||||
|
Res = cast<ObjectFile>(Bin);
|
||||||
|
}
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
ModuleInfo *
|
ModuleInfo *
|
||||||
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
||||||
ModuleMapTy::iterator I = Modules.find(ModuleName);
|
ModuleMapTy::iterator I = Modules.find(ModuleName);
|
||||||
if (I != Modules.end())
|
if (I != Modules.end())
|
||||||
return I->second;
|
return I->second;
|
||||||
|
std::string BinaryName = ModuleName;
|
||||||
|
std::string ArchName = Opts.DefaultArch;
|
||||||
|
size_t ColonPos = ModuleName.find(':');
|
||||||
|
if (ColonPos != std::string::npos) {
|
||||||
|
BinaryName = ModuleName.substr(0, ColonPos);
|
||||||
|
ArchName = ModuleName.substr(ColonPos + 1);
|
||||||
|
}
|
||||||
|
BinaryPair Binaries = getOrCreateBinary(BinaryName);
|
||||||
|
ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName);
|
||||||
|
ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName);
|
||||||
|
|
||||||
ObjectFile *Obj = getObjectFile(ModuleName);
|
|
||||||
if (Obj == 0) {
|
if (Obj == 0) {
|
||||||
// Module name doesn't point to a valid object file.
|
// Failed to find valid object file.
|
||||||
Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
|
Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
DIContext *Context = DIContext::getDWARFContext(DbgObj);
|
||||||
DIContext *Context = 0;
|
assert(Context);
|
||||||
bool IsLittleEndian;
|
|
||||||
if (getObjectEndianness(Obj, IsLittleEndian)) {
|
|
||||||
// On Darwin we may find DWARF in separate object file in
|
|
||||||
// resource directory.
|
|
||||||
ObjectFile *DbgObj = Obj;
|
|
||||||
if (isa<MachOObjectFile>(Obj)) {
|
|
||||||
const std::string &ResourceName =
|
|
||||||
getDarwinDWARFResourceForModule(ModuleName);
|
|
||||||
bool ResourceFileExists = false;
|
|
||||||
if (!sys::fs::exists(ResourceName, ResourceFileExists) &&
|
|
||||||
ResourceFileExists) {
|
|
||||||
if (ObjectFile *ResourceObj = getObjectFile(ResourceName))
|
|
||||||
DbgObj = ResourceObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Context = DIContext::getDWARFContext(DbgObj);
|
|
||||||
assert(Context);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModuleInfo *Info = new ModuleInfo(Obj, Context);
|
ModuleInfo *Info = new ModuleInfo(Obj, Context);
|
||||||
Modules.insert(make_pair(ModuleName, Info));
|
Modules.insert(make_pair(ModuleName, Info));
|
||||||
return Info;
|
return Info;
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
#define LLVM_SYMBOLIZE_H
|
#define LLVM_SYMBOLIZE_H
|
||||||
|
|
||||||
#include "llvm/ADT/OwningPtr.h"
|
#include "llvm/ADT/OwningPtr.h"
|
||||||
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/DebugInfo/DIContext.h"
|
#include "llvm/DebugInfo/DIContext.h"
|
||||||
|
#include "llvm/Object/MachOUniversal.h"
|
||||||
#include "llvm/Object/ObjectFile.h"
|
#include "llvm/Object/ObjectFile.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -35,10 +37,13 @@ public:
|
|||||||
bool PrintFunctions : 1;
|
bool PrintFunctions : 1;
|
||||||
bool PrintInlining : 1;
|
bool PrintInlining : 1;
|
||||||
bool Demangle : 1;
|
bool Demangle : 1;
|
||||||
|
std::string DefaultArch;
|
||||||
Options(bool UseSymbolTable = true, bool PrintFunctions = true,
|
Options(bool UseSymbolTable = true, bool PrintFunctions = true,
|
||||||
bool PrintInlining = true, bool Demangle = true)
|
bool PrintInlining = true, bool Demangle = true,
|
||||||
|
std::string DefaultArch = "")
|
||||||
: UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions),
|
: UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions),
|
||||||
PrintInlining(PrintInlining), Demangle(Demangle) {
|
PrintInlining(PrintInlining), Demangle(Demangle),
|
||||||
|
DefaultArch(DefaultArch) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,12 +57,29 @@ public:
|
|||||||
symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
|
symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
|
||||||
void flush();
|
void flush();
|
||||||
private:
|
private:
|
||||||
|
typedef std::pair<Binary*, Binary*> BinaryPair;
|
||||||
|
|
||||||
ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName);
|
ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName);
|
||||||
|
/// \brief Returns pair of pointers to binary and debug binary.
|
||||||
|
BinaryPair getOrCreateBinary(const std::string &Path);
|
||||||
|
/// \brief Returns a parsed object file for a given architecture in a
|
||||||
|
/// universal binary (or the binary itself if it is an object file).
|
||||||
|
ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName);
|
||||||
|
|
||||||
std::string printDILineInfo(DILineInfo LineInfo) const;
|
std::string printDILineInfo(DILineInfo LineInfo) const;
|
||||||
void DemangleName(std::string &Name) const;
|
void DemangleName(std::string &Name) const;
|
||||||
|
|
||||||
|
// Owns all the parsed binaries and object files.
|
||||||
|
SmallVector<Binary*, 4> ParsedBinariesAndObjects;
|
||||||
|
// Owns module info objects.
|
||||||
typedef std::map<std::string, ModuleInfo *> ModuleMapTy;
|
typedef std::map<std::string, ModuleInfo *> ModuleMapTy;
|
||||||
ModuleMapTy Modules;
|
ModuleMapTy Modules;
|
||||||
|
typedef std::map<std::string, BinaryPair> BinaryMapTy;
|
||||||
|
BinaryMapTy BinaryForPath;
|
||||||
|
typedef std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
|
||||||
|
ObjectFileForArchMapTy;
|
||||||
|
ObjectFileForArchMapTy ObjectFileForArch;
|
||||||
|
|
||||||
Options Opts;
|
Options Opts;
|
||||||
static const char kBadString[];
|
static const char kBadString[];
|
||||||
};
|
};
|
||||||
@ -77,7 +99,7 @@ private:
|
|||||||
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
|
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
|
||||||
std::string &Name, uint64_t &Addr,
|
std::string &Name, uint64_t &Addr,
|
||||||
uint64_t &Size) const;
|
uint64_t &Size) const;
|
||||||
OwningPtr<ObjectFile> Module;
|
ObjectFile *Module;
|
||||||
OwningPtr<DIContext> DebugInfoContext;
|
OwningPtr<DIContext> DebugInfoContext;
|
||||||
|
|
||||||
struct SymbolDesc {
|
struct SymbolDesc {
|
||||||
|
@ -47,6 +47,10 @@ ClPrintInlining("inlining", cl::init(true),
|
|||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
|
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
|
||||||
|
|
||||||
|
static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
|
||||||
|
cl::desc("Default architecture "
|
||||||
|
"(for multi-arch objects)"));
|
||||||
|
|
||||||
static bool parseCommand(bool &IsData, std::string &ModuleName,
|
static bool parseCommand(bool &IsData, std::string &ModuleName,
|
||||||
uint64_t &ModuleOffset) {
|
uint64_t &ModuleOffset) {
|
||||||
const char *kDataCmd = "DATA ";
|
const char *kDataCmd = "DATA ";
|
||||||
@ -102,7 +106,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
|
cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
|
||||||
LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
|
LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
|
||||||
ClPrintInlining, ClDemangle);
|
ClPrintInlining, ClDemangle, ClDefaultArch);
|
||||||
LLVMSymbolizer Symbolizer(Opts);
|
LLVMSymbolizer Symbolizer(Opts);
|
||||||
|
|
||||||
bool IsData = false;
|
bool IsData = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user