[LLVMSymbolize] Properly propagate object parsing errors from the library.

llvm-svn: 252021
This commit is contained in:
Alexey Samsonov 2015-11-04 00:30:24 +00:00
parent b0742319fc
commit 884adda0fb
3 changed files with 138 additions and 106 deletions

View File

@ -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;

View File

@ -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:

View File

@ -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();