diff options
Diffstat (limited to 'llvm/lib/DebugInfo/Symbolize/Symbolize.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/Symbolize/Symbolize.cpp | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index be79d9e637c1..35e3ead6317b 100644 --- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -284,6 +284,79 @@ bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); } +template <typename ELFT> +Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> *Obj) { + if (!Obj) + return {}; + auto PhdrsOrErr = Obj->program_headers(); + if (!PhdrsOrErr) { + consumeError(PhdrsOrErr.takeError()); + return {}; + } + for (const auto &P : *PhdrsOrErr) { + if (P.p_type != ELF::PT_NOTE) + continue; + Error Err = Error::success(); + for (auto N : Obj->notes(P, Err)) + if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU) + return N.getDesc(); + } + return {}; +} + +Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) { + Optional<ArrayRef<uint8_t>> BuildID; + if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else + llvm_unreachable("unsupported file format"); + return BuildID; +} + +bool findDebugBinary(const std::vector<std::string> &DebugFileDirectory, + const ArrayRef<uint8_t> BuildID, + std::string &Result) { + auto getDebugPath = [&](StringRef Directory) { + SmallString<128> Path{Directory}; + sys::path::append(Path, ".build-id", + llvm::toHex(BuildID[0], /*LowerCase=*/true), + llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); + Path += ".debug"; + return Path; + }; + if (DebugFileDirectory.empty()) { + SmallString<128> Path = getDebugPath( +#if defined(__NetBSD__) + // Try /usr/libdata/debug/.build-id/../... + "/usr/libdata/debug" +#else + // Try /usr/lib/debug/.build-id/../... + "/usr/lib/debug" +#endif + ); + if (llvm::sys::fs::exists(Path)) { + Result = Path.str(); + return true; + } + } else { + for (const auto &Directory : DebugFileDirectory) { + // Try <debug-file-directory>/.build-id/../... + SmallString<128> Path = getDebugPath(Directory); + if (llvm::sys::fs::exists(Path)) { + Result = Path.str(); + return true; + } + } + } + return false; +} + } // end anonymous namespace ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, @@ -335,6 +408,25 @@ ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, return DbgObjOrErr.get(); } +ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path, + const ELFObjectFileBase *Obj, + const std::string &ArchName) { + auto BuildID = getBuildID(Obj); + if (!BuildID) + return nullptr; + if (BuildID->size() < 2) + return nullptr; + std::string DebugBinaryPath; + if (!findDebugBinary(Opts.DebugFileDirectory, *BuildID, DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) { + consumeError(DbgObjOrErr.takeError()); + return nullptr; + } + return DbgObjOrErr.get(); +} + Expected<LLVMSymbolizer::ObjectPair> LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, const std::string &ArchName) { @@ -355,6 +447,8 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) DbgObj = lookUpDsymFile(Path, MachObj, ArchName); + else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj)) + DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName); if (!DbgObj) DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); if (!DbgObj) |