forked from OSchip/llvm-project
[LLVMSymbolize] Properly propagate object parsing errors from the library.
llvm-svn: 252021
This commit is contained in:
parent
b0742319fc
commit
884adda0fb
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
|
||||
#include "llvm/Object/MachOUniversal.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
@ -51,11 +52,12 @@ public:
|
|||
flush();
|
||||
}
|
||||
|
||||
DILineInfo symbolizeCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset);
|
||||
DIInliningInfo symbolizeInlinedCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset);
|
||||
DIGlobal symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
|
||||
ErrorOr<DILineInfo> symbolizeCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset);
|
||||
ErrorOr<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset);
|
||||
ErrorOr<DIGlobal> symbolizeData(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset);
|
||||
void flush();
|
||||
static std::string DemangleName(const std::string &Name,
|
||||
const SymbolizableModule *ModInfo);
|
||||
|
@ -63,17 +65,19 @@ public:
|
|||
private:
|
||||
typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair;
|
||||
|
||||
SymbolizableModule *getOrCreateModuleInfo(const std::string &ModuleName);
|
||||
ErrorOr<SymbolizableModule *>
|
||||
getOrCreateModuleInfo(const std::string &ModuleName);
|
||||
ObjectFile *lookUpDsymFile(const std::string &Path,
|
||||
const MachOObjectFile *ExeObj,
|
||||
const std::string &ArchName);
|
||||
|
||||
/// \brief Returns pair of pointers to object and debug object.
|
||||
ObjectPair getOrCreateObjects(const std::string &Path,
|
||||
const std::string &ArchName);
|
||||
ErrorOr<ObjectPair> getOrCreateObjects(const std::string &Path,
|
||||
const std::string &ArchName);
|
||||
/// \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);
|
||||
ErrorOr<ObjectFile *> getObjectFileFromBinary(Binary *Bin,
|
||||
const std::string &ArchName);
|
||||
|
||||
// Owns all the parsed binaries and object files.
|
||||
SmallVector<std::unique_ptr<Binary>, 4> ParsedBinariesAndObjects;
|
||||
|
@ -86,10 +90,10 @@ private:
|
|||
MemoryBuffers.push_back(std::move(MemBuf));
|
||||
}
|
||||
|
||||
std::map<std::string, std::unique_ptr<SymbolizableModule>> Modules;
|
||||
std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
|
||||
ObjectFileForArch;
|
||||
std::map<std::pair<std::string, std::string>, ObjectPair>
|
||||
std::map<std::string, ErrorOr<std::unique_ptr<SymbolizableModule>>> Modules;
|
||||
std::map<std::pair<MachOUniversalBinary *, std::string>,
|
||||
ErrorOr<ObjectFile *>> ObjectFileForArch;
|
||||
std::map<std::pair<std::string, std::string>, ErrorOr<ObjectPair>>
|
||||
ObjectPairForPathArch;
|
||||
|
||||
Options Opts;
|
||||
|
|
|
@ -46,19 +46,12 @@
|
|||
namespace llvm {
|
||||
namespace symbolize {
|
||||
|
||||
// FIXME: Move this to llvm-symbolizer tool.
|
||||
static bool error(std::error_code ec) {
|
||||
if (!ec)
|
||||
return false;
|
||||
errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
DILineInfo LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset) {
|
||||
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
|
||||
if (!Info)
|
||||
return DILineInfo();
|
||||
ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset) {
|
||||
auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
|
||||
if (auto EC = InfoOrErr.getError())
|
||||
return EC;
|
||||
SymbolizableModule *Info = InfoOrErr.get();
|
||||
|
||||
// If the user is giving us relative addresses, add the preferred base of the
|
||||
// object to the offset before we do the query. It's what DIContext expects.
|
||||
|
@ -72,12 +65,13 @@ DILineInfo LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
|
|||
return LineInfo;
|
||||
}
|
||||
|
||||
DIInliningInfo
|
||||
ErrorOr<DIInliningInfo>
|
||||
LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset) {
|
||||
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
|
||||
if (!Info)
|
||||
return DIInliningInfo();
|
||||
auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
|
||||
if (auto EC = InfoOrErr.getError())
|
||||
return EC;
|
||||
SymbolizableModule *Info = InfoOrErr.get();
|
||||
|
||||
// If the user is giving us relative addresses, add the preferred base of the
|
||||
// object to the offset before we do the query. It's what DIContext expects.
|
||||
|
@ -95,13 +89,12 @@ LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
|
|||
return InlinedContext;
|
||||
}
|
||||
|
||||
DIGlobal LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset) {
|
||||
if (!Opts.UseSymbolTable)
|
||||
return DIGlobal();
|
||||
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
|
||||
if (!Info)
|
||||
return DIGlobal();
|
||||
ErrorOr<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
|
||||
uint64_t ModuleOffset) {
|
||||
auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
|
||||
if (auto EC = InfoOrErr.getError())
|
||||
return EC;
|
||||
SymbolizableModule *Info = InfoOrErr.get();
|
||||
|
||||
// If the user is giving us relative addresses, add the preferred base of
|
||||
// the object to the offset before we do the query. It's what DIContext
|
||||
|
@ -232,72 +225,87 @@ ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
|
|||
}
|
||||
for (const auto &path : DsymPaths) {
|
||||
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path);
|
||||
std::error_code EC = BinaryOrErr.getError();
|
||||
if (EC != errc::no_such_file_or_directory && !error(EC)) {
|
||||
OwningBinary<Binary> B = std::move(BinaryOrErr.get());
|
||||
ObjectFile *DbgObj =
|
||||
getObjectFileFromBinary(B.getBinary(), ArchName);
|
||||
const MachOObjectFile *MachDbgObj =
|
||||
dyn_cast<const MachOObjectFile>(DbgObj);
|
||||
if (!MachDbgObj) continue;
|
||||
if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) {
|
||||
addOwningBinary(std::move(B));
|
||||
return DbgObj;
|
||||
}
|
||||
if (!BinaryOrErr)
|
||||
continue;
|
||||
OwningBinary<Binary> &B = BinaryOrErr.get();
|
||||
auto DbgObjOrErr = getObjectFileFromBinary(B.getBinary(), ArchName);
|
||||
if (!DbgObjOrErr)
|
||||
continue;
|
||||
ObjectFile *DbgObj = DbgObjOrErr.get();
|
||||
const MachOObjectFile *MachDbgObj =
|
||||
dyn_cast<const MachOObjectFile>(DbgObj);
|
||||
if (!MachDbgObj)
|
||||
continue;
|
||||
if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) {
|
||||
addOwningBinary(std::move(B));
|
||||
return DbgObj;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMSymbolizer::ObjectPair
|
||||
ErrorOr<LLVMSymbolizer::ObjectPair>
|
||||
LLVMSymbolizer::getOrCreateObjects(const std::string &Path,
|
||||
const std::string &ArchName) {
|
||||
const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
|
||||
if (I != ObjectPairForPathArch.end())
|
||||
return I->second;
|
||||
ObjectFile *Obj = nullptr;
|
||||
ObjectFile *DbgObj = nullptr;
|
||||
|
||||
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path);
|
||||
if (!error(BinaryOrErr.getError())) {
|
||||
OwningBinary<Binary> &B = BinaryOrErr.get();
|
||||
Obj = getObjectFileFromBinary(B.getBinary(), ArchName);
|
||||
if (!Obj) {
|
||||
ObjectPair Res = std::make_pair(nullptr, nullptr);
|
||||
ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
|
||||
return Res;
|
||||
}
|
||||
addOwningBinary(std::move(B));
|
||||
if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
|
||||
DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
|
||||
// Try to locate the debug binary using .gnu_debuglink section.
|
||||
if (!DbgObj) {
|
||||
std::string DebuglinkName;
|
||||
uint32_t CRCHash;
|
||||
std::string DebugBinaryPath;
|
||||
if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) &&
|
||||
findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) {
|
||||
BinaryOrErr = createBinary(DebugBinaryPath);
|
||||
if (!error(BinaryOrErr.getError())) {
|
||||
OwningBinary<Binary> B = std::move(BinaryOrErr.get());
|
||||
DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName);
|
||||
addOwningBinary(std::move(B));
|
||||
if (auto EC = BinaryOrErr.getError()) {
|
||||
ObjectPairForPathArch.insert(
|
||||
std::make_pair(std::make_pair(Path, ArchName), EC));
|
||||
return EC;
|
||||
}
|
||||
OwningBinary<Binary> &B = BinaryOrErr.get();
|
||||
|
||||
auto ObjOrErr = getObjectFileFromBinary(B.getBinary(), ArchName);
|
||||
if (auto EC = ObjOrErr.getError()) {
|
||||
ObjectPairForPathArch.insert(
|
||||
std::make_pair(std::make_pair(Path, ArchName), EC));
|
||||
return EC;
|
||||
}
|
||||
addOwningBinary(std::move(B));
|
||||
|
||||
ObjectFile *Obj = ObjOrErr.get();
|
||||
assert(Obj != nullptr);
|
||||
ObjectFile *DbgObj = nullptr;
|
||||
|
||||
if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
|
||||
DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
|
||||
// Try to locate the debug binary using .gnu_debuglink section.
|
||||
if (!DbgObj) {
|
||||
std::string DebuglinkName;
|
||||
uint32_t CRCHash;
|
||||
std::string DebugBinaryPath;
|
||||
if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) &&
|
||||
findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) {
|
||||
ErrorOr<OwningBinary<Binary>> DebugBinaryOrErr =
|
||||
createBinary(DebugBinaryPath);
|
||||
if (DebugBinaryOrErr) {
|
||||
OwningBinary<Binary> &DB = DebugBinaryOrErr.get();
|
||||
auto DbgObjOrErr = getObjectFileFromBinary(DB.getBinary(), ArchName);
|
||||
if (DbgObjOrErr) {
|
||||
DbgObj = DbgObjOrErr.get();
|
||||
assert(DbgObj != nullptr);
|
||||
addOwningBinary(std::move(DB));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DbgObj)
|
||||
DbgObj = Obj;
|
||||
ObjectPair Res = std::make_pair(Obj, DbgObj);
|
||||
ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
|
||||
ObjectPairForPathArch.insert(
|
||||
std::make_pair(std::make_pair(Path, ArchName), Res));
|
||||
return Res;
|
||||
}
|
||||
|
||||
ObjectFile *
|
||||
ErrorOr<ObjectFile *>
|
||||
LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin,
|
||||
const std::string &ArchName) {
|
||||
if (!Bin)
|
||||
return nullptr;
|
||||
ObjectFile *Res = nullptr;
|
||||
assert(Bin != nullptr);
|
||||
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
|
||||
const auto &I = ObjectFileForArch.find(
|
||||
std::make_pair(UB, ArchName));
|
||||
|
@ -305,22 +313,31 @@ LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin,
|
|||
return I->second;
|
||||
ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj =
|
||||
UB->getObjectForArch(ArchName);
|
||||
if (ParsedObj) {
|
||||
Res = ParsedObj.get().get();
|
||||
ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get()));
|
||||
if (auto EC = ParsedObj.getError()) {
|
||||
ObjectFileForArch.insert(
|
||||
std::make_pair(std::make_pair(UB, ArchName), EC));
|
||||
return EC;
|
||||
}
|
||||
ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
|
||||
} else if (Bin->isObject()) {
|
||||
Res = cast<ObjectFile>(Bin);
|
||||
ObjectFile *Res = ParsedObj.get().get();
|
||||
ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get()));
|
||||
ObjectFileForArch.insert(std::make_pair(std::make_pair(UB, ArchName), Res));
|
||||
return Res;
|
||||
}
|
||||
return Res;
|
||||
if (Bin->isObject()) {
|
||||
return cast<ObjectFile>(Bin);
|
||||
}
|
||||
return object_error::arch_not_found;
|
||||
}
|
||||
|
||||
SymbolizableModule *
|
||||
ErrorOr<SymbolizableModule *>
|
||||
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
||||
const auto &I = Modules.find(ModuleName);
|
||||
if (I != Modules.end())
|
||||
return I->second.get();
|
||||
if (I != Modules.end()) {
|
||||
auto &InfoOrErr = I->second;
|
||||
if (auto EC = InfoOrErr.getError())
|
||||
return EC;
|
||||
return InfoOrErr->get();
|
||||
}
|
||||
std::string BinaryName = ModuleName;
|
||||
std::string ArchName = Opts.DefaultArch;
|
||||
size_t ColonPos = ModuleName.find_last_of(':');
|
||||
|
@ -332,13 +349,14 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
|||
ArchName = ArchStr;
|
||||
}
|
||||
}
|
||||
ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName);
|
||||
|
||||
if (!Objects.first) {
|
||||
auto ObjectsOrErr = getOrCreateObjects(BinaryName, ArchName);
|
||||
if (auto EC = ObjectsOrErr.getError()) {
|
||||
// Failed to find valid object file.
|
||||
Modules.insert(std::make_pair(ModuleName, nullptr));
|
||||
return nullptr;
|
||||
Modules.insert(std::make_pair(ModuleName, EC));
|
||||
return EC;
|
||||
}
|
||||
ObjectPair Objects = ObjectsOrErr.get();
|
||||
|
||||
std::unique_ptr<DIContext> Context;
|
||||
if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
|
||||
// If this is a COFF object, assume it contains PDB debug information. If
|
||||
|
@ -353,15 +371,14 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
|
|||
if (!Context)
|
||||
Context.reset(new DWARFContextInMemory(*Objects.second));
|
||||
assert(Context);
|
||||
auto ErrOrInfo =
|
||||
auto InfoOrErr =
|
||||
SymbolizableObjectFile::create(Objects.first, std::move(Context));
|
||||
if (error(ErrOrInfo.getError())) {
|
||||
Modules.insert(std::make_pair(ModuleName, nullptr));
|
||||
return nullptr;
|
||||
}
|
||||
SymbolizableModule *Res = ErrOrInfo.get().get();
|
||||
Modules.insert(std::make_pair(ModuleName, std::move(ErrOrInfo.get())));
|
||||
return Res;
|
||||
auto InsertResult =
|
||||
Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr)));
|
||||
assert(InsertResult.second);
|
||||
if (auto EC = InsertResult.first->second.getError())
|
||||
return EC;
|
||||
return InsertResult.first->second->get();
|
||||
}
|
||||
|
||||
// Undo these various manglings for Win32 extern "C" functions:
|
||||
|
|
|
@ -78,6 +78,13 @@ static cl::opt<bool>
|
|||
ClPrintAddress("print-address", cl::init(false),
|
||||
cl::desc("Show address before line information"));
|
||||
|
||||
static bool error(std::error_code ec) {
|
||||
if (!ec)
|
||||
return false;
|
||||
errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseCommand(bool &IsData, std::string &ModuleName,
|
||||
uint64_t &ModuleOffset) {
|
||||
const char *kDataCmd = "DATA ";
|
||||
|
@ -158,11 +165,15 @@ int main(int argc, char **argv) {
|
|||
outs() << "\n";
|
||||
}
|
||||
if (IsData) {
|
||||
Printer << Symbolizer.symbolizeData(ModuleName, ModuleOffset);
|
||||
auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
|
||||
Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get());
|
||||
} else if (ClPrintInlining) {
|
||||
Printer << Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
|
||||
auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
|
||||
Printer << (error(ResOrErr.getError()) ? DIInliningInfo()
|
||||
: ResOrErr.get());
|
||||
} else {
|
||||
Printer << Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
|
||||
auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
|
||||
Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get());
|
||||
}
|
||||
outs() << "\n";
|
||||
outs().flush();
|
||||
|
|
Loading…
Reference in New Issue