aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/DebugInfo/Symbolize/Symbolize.h31
-rw-r--r--include/llvm/Object/COFF.h8
-rw-r--r--lib/DebugInfo/Symbolize/Symbolize.cpp154
-rw-r--r--lib/Object/COFFObjectFile.cpp11
-rw-r--r--test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exebin0 -> 32256 bytes
-rw-r--r--test/tools/llvm-symbolizer/pdb/missing_pdb.test17
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp14
-rw-r--r--tools/sancov/sancov.cc6
-rw-r--r--tools/sanstats/sanstats.cpp6
9 files changed, 161 insertions, 86 deletions
diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 1c487aafc57..9253adf7eed 100644
--- a/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -49,12 +49,12 @@ public:
flush();
}
- 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);
+ Expected<DILineInfo> symbolizeCode(const std::string &ModuleName,
+ uint64_t ModuleOffset);
+ Expected<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName,
+ uint64_t ModuleOffset);
+ Expected<DIGlobal> symbolizeData(const std::string &ModuleName,
+ uint64_t ModuleOffset);
void flush();
static std::string DemangleName(const std::string &Name,
const SymbolizableModule *ModInfo);
@@ -64,8 +64,13 @@ private:
// corresponding debug info. These objects can be the same.
typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair;
- ErrorOr<SymbolizableModule *>
+ /// Returns a SymbolizableModule or an error if loading debug info failed.
+ /// Only one attempt is made to load a module, and errors during loading are
+ /// only reported once. Subsequent calls to get module info for a module that
+ /// failed to load will return nullptr.
+ Expected<SymbolizableModule *>
getOrCreateModuleInfo(const std::string &ModuleName);
+
ObjectFile *lookUpDsymFile(const std::string &Path,
const MachOObjectFile *ExeObj,
const std::string &ArchName);
@@ -74,27 +79,27 @@ private:
const std::string &ArchName);
/// \brief Returns pair of pointers to object and debug object.
- ErrorOr<ObjectPair> getOrCreateObjectPair(const std::string &Path,
+ Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName);
/// \brief Return a pointer to object file at specified path, for a specified
/// architecture (e.g. if path refers to a Mach-O universal binary, only one
/// object file from it will be returned).
- ErrorOr<ObjectFile *> getOrCreateObject(const std::string &Path,
+ Expected<ObjectFile *> getOrCreateObject(const std::string &Path,
const std::string &ArchName);
- std::map<std::string, ErrorOr<std::unique_ptr<SymbolizableModule>>> Modules;
+ std::map<std::string, std::unique_ptr<SymbolizableModule>> Modules;
/// \brief Contains cached results of getOrCreateObjectPair().
- std::map<std::pair<std::string, std::string>, ErrorOr<ObjectPair>>
+ std::map<std::pair<std::string, std::string>, ObjectPair>
ObjectPairForPathArch;
/// \brief Contains parsed binary for each path, or parsing error.
- std::map<std::string, ErrorOr<OwningBinary<Binary>>> BinaryForPath;
+ std::map<std::string, OwningBinary<Binary>> BinaryForPath;
/// \brief Parsed object file for path/architecture pair, where "path" refers
/// to Mach-O universal binary.
- std::map<std::pair<std::string, std::string>, ErrorOr<std::unique_ptr<ObjectFile>>>
+ std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>>
ObjectForUBPathAndArch;
Options Opts;
diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h
index f859b7dea1a..4578ce10f1c 100644
--- a/include/llvm/Object/COFF.h
+++ b/include/llvm/Object/COFF.h
@@ -870,10 +870,18 @@ public:
std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
StringRef &Name) const;
+ /// Get PDB information out of a codeview debug directory entry.
std::error_code getDebugPDBInfo(const debug_directory *DebugDir,
const debug_pdb_info *&Info,
StringRef &PDBFileName) const;
+ /// Get PDB information from an executable. If the information is not present,
+ /// Info will be set to nullptr and PDBFileName will be empty. An error is
+ /// returned only on corrupt object files. Convenience accessor that can be
+ /// used if the debug directory is not already handy.
+ std::error_code getDebugPDBInfo(const debug_pdb_info *&Info,
+ StringRef &PDBFileName) const;
+
bool isRelocatableObject() const override;
bool is64() const { return PE32PlusHeader; }
diff --git a/lib/DebugInfo/Symbolize/Symbolize.cpp b/lib/DebugInfo/Symbolize/Symbolize.cpp
index 9c12169fb67..e2732bf819e 100644
--- a/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -50,12 +50,18 @@
namespace llvm {
namespace symbolize {
-ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
+Expected<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();
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DILineInfo();
// 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.
@@ -69,13 +75,19 @@ ErrorOr<DILineInfo> LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
return LineInfo;
}
-ErrorOr<DIInliningInfo>
+Expected<DIInliningInfo>
LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
- auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
- if (auto EC = InfoOrErr.getError())
- return EC;
- SymbolizableModule *Info = InfoOrErr.get();
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIInliningInfo();
// 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.
@@ -93,12 +105,18 @@ LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
return InlinedContext;
}
-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();
+Expected<DIGlobal> LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
+ uint64_t ModuleOffset) {
+ SymbolizableModule *Info;
+ if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
+ Info = InfoOrErr.get();
+ else
+ return InfoOrErr.takeError();
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIGlobal();
// 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,9 +250,14 @@ ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
}
for (const auto &Path : DsymPaths) {
auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
- if (!DbgObjOrErr)
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
continue;
+ }
ObjectFile *DbgObj = DbgObjOrErr.get();
+ if (!DbgObj)
+ continue;
const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
if (!MachDbgObj)
continue;
@@ -255,23 +278,27 @@ ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
return nullptr;
auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
- if (!DbgObjOrErr)
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
return nullptr;
+ }
return DbgObjOrErr.get();
}
-ErrorOr<LLVMSymbolizer::ObjectPair>
+Expected<LLVMSymbolizer::ObjectPair>
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName) {
const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
- if (I != ObjectPairForPathArch.end())
+ if (I != ObjectPairForPathArch.end()) {
return I->second;
+ }
auto ObjOrErr = getOrCreateObject(Path, ArchName);
- if (auto EC = ObjOrErr.getError()) {
- ObjectPairForPathArch.insert(
- std::make_pair(std::make_pair(Path, ArchName), EC));
- return EC;
+ if (!ObjOrErr) {
+ ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
+ ObjectPair(nullptr, nullptr)));
+ return ObjOrErr.takeError();
}
ObjectFile *Obj = ObjOrErr.get();
@@ -290,7 +317,7 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
return Res;
}
-ErrorOr<ObjectFile *>
+Expected<ObjectFile *>
LLVMSymbolizer::getOrCreateObject(const std::string &Path,
const std::string &ArchName) {
const auto &I = BinaryForPath.find(Path);
@@ -298,34 +325,29 @@ LLVMSymbolizer::getOrCreateObject(const std::string &Path,
if (I == BinaryForPath.end()) {
Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
if (!BinOrErr) {
- auto EC = errorToErrorCode(BinOrErr.takeError());
- BinaryForPath.insert(std::make_pair(Path, EC));
- return EC;
+ BinaryForPath.insert({Path, OwningBinary<Binary>()});
+ return BinOrErr.takeError();
}
Bin = BinOrErr->getBinary();
BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
- } else if (auto EC = I->second.getError()) {
- return EC;
} else {
- Bin = I->second->getBinary();
+ Bin = I->second.getBinary();
}
- assert(Bin != nullptr);
+ if (!Bin)
+ return static_cast<ObjectFile *>(nullptr);
- if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
+ if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
if (I != ObjectForUBPathAndArch.end()) {
- if (auto EC = I->second.getError())
- return EC;
- return I->second->get();
+ return I->second.get();
}
Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
UB->getObjectForArch(ArchName);
if (!ObjOrErr) {
- auto EC = errorToErrorCode(ObjOrErr.takeError());
- ObjectForUBPathAndArch.insert(
- std::make_pair(std::make_pair(Path, ArchName), EC));
- return EC;
+ ObjectForUBPathAndArch.insert(std::make_pair(
+ std::make_pair(Path, ArchName), std::unique_ptr<ObjectFile>()));
+ return ObjOrErr.takeError();
}
ObjectFile *Res = ObjOrErr->get();
ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
@@ -335,17 +357,14 @@ LLVMSymbolizer::getOrCreateObject(const std::string &Path,
if (Bin->isObject()) {
return cast<ObjectFile>(Bin);
}
- return object_error::arch_not_found;
+ return errorCodeToError(object_error::arch_not_found);
}
-ErrorOr<SymbolizableModule *>
+Expected<SymbolizableModule *>
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
const auto &I = Modules.find(ModuleName);
if (I != Modules.end()) {
- auto &InfoOrErr = I->second;
- if (auto EC = InfoOrErr.getError())
- return EC;
- return InfoOrErr->get();
+ return I->second.get();
}
std::string BinaryName = ModuleName;
std::string ArchName = Opts.DefaultArch;
@@ -359,27 +378,31 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
}
}
auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
- if (auto EC = ObjectsOrErr.getError()) {
+ if (!ObjectsOrErr) {
// Failed to find valid object file.
- Modules.insert(std::make_pair(ModuleName, EC));
- return EC;
+ Modules.insert(
+ std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
+ return ObjectsOrErr.takeError();
}
ObjectPair Objects = ObjectsOrErr.get();
std::unique_ptr<DIContext> Context;
+ // If this is a COFF object containing PDB info, use a PDBContext to
+ // symbolize. Otherwise, use DWARF.
if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
- using namespace pdb;
- // If this is a COFF object, assume it contains PDB debug information. If
- // we don't find any we will fall back to the DWARF case.
- std::unique_ptr<IPDBSession> Session;
- auto Error = loadDataForEXE(
- PDB_ReaderType::DIA, Objects.first->getFileName(), Session);
- if (!Error) {
+ const debug_pdb_info *PDBInfo;
+ StringRef PDBFileName;
+ auto EC = CoffObject->getDebugPDBInfo(PDBInfo, PDBFileName);
+ if (!EC && PDBInfo != nullptr) {
+ using namespace pdb;
+ std::unique_ptr<IPDBSession> Session;
+ if (auto Err = loadDataForEXE(PDB_ReaderType::DIA,
+ Objects.first->getFileName(), Session)) {
+ Modules.insert(
+ std::make_pair(ModuleName, std::unique_ptr<SymbolizableModule>()));
+ return std::move(Err);
+ }
Context.reset(new PDBContext(*CoffObject, std::move(Session)));
- } else {
- // Drop error
- handleAllErrors(std::move(Error),
- [](const ErrorInfoBase &) { return Error::success(); });
}
}
if (!Context)
@@ -387,12 +410,15 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
assert(Context);
auto InfoOrErr =
SymbolizableObjectFile::create(Objects.first, std::move(Context));
+ std::unique_ptr<SymbolizableModule> SymMod;
+ if (InfoOrErr)
+ SymMod = std::move(InfoOrErr.get());
auto InsertResult =
- Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr)));
+ Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
assert(InsertResult.second);
- if (auto EC = InsertResult.first->second.getError())
- return EC;
- return InsertResult.first->second->get();
+ if (auto EC = InfoOrErr.getError())
+ return errorCodeToError(EC);
+ return InsertResult.first->second.get();
}
namespace {
diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp
index 8390edda3bf..28627cd1d42 100644
--- a/lib/Object/COFFObjectFile.cpp
+++ b/lib/Object/COFFObjectFile.cpp
@@ -505,6 +505,17 @@ std::error_code COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
return std::error_code();
}
+std::error_code COFFObjectFile::getDebugPDBInfo(const debug_pdb_info *&PDBInfo,
+ StringRef &PDBFileName) const {
+ for (const debug_directory &D : debug_directories())
+ if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
+ return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
+ // If we get here, there is no PDB info to return.
+ PDBInfo = nullptr;
+ PDBFileName = StringRef();
+ return std::error_code();
+}
+
// Find the import table.
std::error_code COFFObjectFile::initImportTablePtr() {
// First, we get the RVA of the import table. If the file lacks a pointer to
diff --git a/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe b/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe
new file mode 100644
index 00000000000..320e1f30e58
--- /dev/null
+++ b/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe
Binary files differ
diff --git a/test/tools/llvm-symbolizer/pdb/missing_pdb.test b/test/tools/llvm-symbolizer/pdb/missing_pdb.test
new file mode 100644
index 00000000000..0478dfbc05e
--- /dev/null
+++ b/test/tools/llvm-symbolizer/pdb/missing_pdb.test
@@ -0,0 +1,17 @@
+RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
+RUN: | llvm-symbolizer -obj="%p/Inputs/missing_pdb.exe" 2>%t.err \
+RUN: | FileCheck %s
+RUN: FileCheck --check-prefix=ERROR %s < %t.err
+
+ADDR: 0x401000
+ADDR: 0x401001
+
+llvm-symbolizer should print one error and two unknown line info records.
+
+ERROR: LLVMSymbolizer: error reading file: PDB Error: Unable to load PDB. Make sure the file exists and is readable.
+ERROR-NOT: error reading file
+
+CHECK: ??
+CHECK: ??:0:0
+CHECK: ??
+CHECK: ??:0:0
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 950349377bf..4a3a7b3d2f3 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -86,10 +86,12 @@ static cl::opt<int> ClPrintSourceContextLines(
"print-source-context-lines", cl::init(0),
cl::desc("Print N number of source file context"));
-static bool error(std::error_code ec) {
- if (!ec)
+template<typename T>
+static bool error(Expected<T> &ResOrErr) {
+ if (ResOrErr)
return false;
- errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
+ logAllUnhandledErrors(ResOrErr.takeError(), errs(),
+ "LLVMSymbolizer: error reading file: ");
return true;
}
@@ -185,14 +187,14 @@ int main(int argc, char **argv) {
}
if (IsData) {
auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
- Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get());
+ Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
} else if (ClPrintInlining) {
auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
- Printer << (error(ResOrErr.getError()) ? DIInliningInfo()
+ Printer << (error(ResOrErr) ? DIInliningInfo()
: ResOrErr.get());
} else {
auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
- Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get());
+ Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
}
outs() << "\n";
outs().flush();
diff --git a/tools/sancov/sancov.cc b/tools/sancov/sancov.cc
index efeb46a1faa..e4e83b0bbc8 100644
--- a/tools/sancov/sancov.cc
+++ b/tools/sancov/sancov.cc
@@ -135,6 +135,12 @@ template <typename T> static void FailIfError(const ErrorOr<T> &E) {
FailIfError(E.getError());
}
+template <typename T> static void FailIfError(Expected<T> &E) {
+ if (E)
+ return;
+ logAllUnhandledErrors(E.takeError(), errs(), "Error: ");
+}
+
static void FailIfNotEmpty(const llvm::Twine &E) {
if (E.str().empty())
return;
diff --git a/tools/sanstats/sanstats.cpp b/tools/sanstats/sanstats.cpp
index 3a8cc9aea8c..b2216eab119 100644
--- a/tools/sanstats/sanstats.cpp
+++ b/tools/sanstats/sanstats.cpp
@@ -76,12 +76,12 @@ const char *ReadModule(char SizeofPtr, const char *Begin, const char *End) {
if (Begin == End)
return nullptr;
- ErrorOr<DILineInfo> LineInfo = Symbolizer.symbolizeCode(Filename, Addr);
- if (LineInfo) {
+ if (Expected<DILineInfo> LineInfo =
+ Symbolizer.symbolizeCode(Filename, Addr)) {
llvm::outs() << LineInfo->FileName << ':' << LineInfo->Line << ' '
<< LineInfo->FunctionName << ' ';
} else {
- llvm::outs() << "<error> ";
+ logAllUnhandledErrors(LineInfo.takeError(), llvm::outs(), "<error> ");
}
switch (KindFromData(Data, SizeofPtr)) {