LLVM symbolizer gsym support - attempt 2 (#139686)
Add support for gsym files to llvm-symbolizer.
co-author @sfc-gh-sgiesecke
Notes:
There was a PR that was
approved and merged: https://github.com/llvm/llvm-project/pull/134847
and reverted: https://github.com/llvm/llvm-project/pull/139660
Due to buildbot failures:
https://lab.llvm.org/buildbot/#/builders/66/builds/13851 - it looks like
related
https://lab.llvm.org/buildbot/#/builders/51/builds/16018 - it looks like
related
https://lab.llvm.org/buildbot/#/builders/146/builds/2905 - it looks like
it's not related to changes
Fix:
To fix missing GSYM symbols
```
+ diff -u expected.new undefined.new
+_ZN4llvm4gsym10GsymReader8openFileENS_9StringRefE U
+_ZN4llvm4gsym10GsymReaderC1EOS1_ U
+_ZN4llvm4gsym10GsymReaderD1Ev U
+_ZN4llvm4gsym13GsymDIContextC1ENSt20__InternalSymbolizer10unique_ptrINS0_10GsymReaderENS2_14default_deleteIS4_EEEE U
+ echo 'Failed: unexpected symbols'
```
for script
compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
LLVMDebugInfoGSYM was added.
Please check the commit:
ba55425db9
That's the only change compare to
https://github.com/llvm/llvm-project/pull/134847
This commit is contained in:
parent
99f0309669
commit
f4b80b9109
@ -145,7 +145,7 @@ if [[ ! -f ${LLVM_BUILD}/build.ninja ]]; then
|
|||||||
$LLVM_SRC
|
$LLVM_SRC
|
||||||
fi
|
fi
|
||||||
cd ${LLVM_BUILD}
|
cd ${LLVM_BUILD}
|
||||||
ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMSupport LLVMDebugInfoPDB LLVMDebuginfod LLVMMC LLVMDemangle LLVMTextAPI LLVMTargetParser LLVMCore
|
ninja LLVMSymbolize LLVMObject LLVMBinaryFormat LLVMDebugInfoDWARF LLVMDebugInfoGSYM LLVMSupport LLVMDebugInfoPDB LLVMDebuginfod LLVMMC LLVMDemangle LLVMTextAPI LLVMTargetParser LLVMCore
|
||||||
|
|
||||||
cd ${BUILD_DIR}
|
cd ${BUILD_DIR}
|
||||||
rm -rf ${SYMBOLIZER_BUILD}
|
rm -rf ${SYMBOLIZER_BUILD}
|
||||||
@ -174,6 +174,7 @@ $LINK $LIBCXX_ARCHIVE_DIR/libc++.a \
|
|||||||
$LLVM_BUILD/lib/libLLVMObject.a \
|
$LLVM_BUILD/lib/libLLVMObject.a \
|
||||||
$LLVM_BUILD/lib/libLLVMBinaryFormat.a \
|
$LLVM_BUILD/lib/libLLVMBinaryFormat.a \
|
||||||
$LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \
|
$LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \
|
||||||
|
$LLVM_BUILD/lib/libLLVMDebugInfoGSYM.a \
|
||||||
$LLVM_BUILD/lib/libLLVMSupport.a \
|
$LLVM_BUILD/lib/libLLVMSupport.a \
|
||||||
$LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \
|
$LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \
|
||||||
$LLVM_BUILD/lib/libLLVMDebugInfoMSF.a \
|
$LLVM_BUILD/lib/libLLVMDebugInfoMSF.a \
|
||||||
|
@ -238,7 +238,7 @@ struct DIDumpOptions {
|
|||||||
|
|
||||||
class DIContext {
|
class DIContext {
|
||||||
public:
|
public:
|
||||||
enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF };
|
enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF, CK_GSYM };
|
||||||
|
|
||||||
DIContext(DIContextKind K) : Kind(K) {}
|
DIContext(DIContextKind K) : Kind(K) {}
|
||||||
virtual ~DIContext() = default;
|
virtual ~DIContext() = default;
|
||||||
|
66
llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
Normal file
66
llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//===-- GsymDIContext.h --------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
|
||||||
|
#ifndef LLVM_DEBUGINFO_GSYM_GSYMDICONTEXT_H
|
||||||
|
#define LLVM_DEBUGINFO_GSYM_GSYMDICONTEXT_H
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/DIContext.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
namespace gsym {
|
||||||
|
|
||||||
|
class GsymReader;
|
||||||
|
|
||||||
|
/// GSYM DI Context
|
||||||
|
/// This data structure is the top level entity that deals with GSYM
|
||||||
|
/// symbolication.
|
||||||
|
/// This data structure exists only when there is a need for a transparent
|
||||||
|
/// interface to different symbolication formats (e.g. GSYM, PDB and DWARF).
|
||||||
|
/// More control and power over the debug information access can be had by using
|
||||||
|
/// the GSYM interfaces directly.
|
||||||
|
class GsymDIContext : public DIContext {
|
||||||
|
public:
|
||||||
|
GsymDIContext(std::unique_ptr<GsymReader> Reader);
|
||||||
|
|
||||||
|
GsymDIContext(GsymDIContext &) = delete;
|
||||||
|
GsymDIContext &operator=(GsymDIContext &) = delete;
|
||||||
|
|
||||||
|
static bool classof(const DIContext *DICtx) {
|
||||||
|
return DICtx->getKind() == CK_GSYM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(raw_ostream &OS, DIDumpOptions DIDumpOpts) override;
|
||||||
|
|
||||||
|
std::optional<DILineInfo> getLineInfoForAddress(
|
||||||
|
object::SectionedAddress Address,
|
||||||
|
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
|
||||||
|
std::optional<DILineInfo>
|
||||||
|
getLineInfoForDataAddress(object::SectionedAddress Address) override;
|
||||||
|
DILineInfoTable getLineInfoForAddressRange(
|
||||||
|
object::SectionedAddress Address, uint64_t Size,
|
||||||
|
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
|
||||||
|
DIInliningInfo getInliningInfoForAddress(
|
||||||
|
object::SectionedAddress Address,
|
||||||
|
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
|
||||||
|
|
||||||
|
std::vector<DILocal>
|
||||||
|
getLocalsForAddress(object::SectionedAddress Address) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::unique_ptr<GsymReader> Reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace gsym
|
||||||
|
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
|
#endif // LLVM_DEBUGINFO_PDB_PDBCONTEXT_H
|
@ -58,11 +58,13 @@ public:
|
|||||||
bool RelativeAddresses = false;
|
bool RelativeAddresses = false;
|
||||||
bool UntagAddresses = false;
|
bool UntagAddresses = false;
|
||||||
bool UseDIA = false;
|
bool UseDIA = false;
|
||||||
|
bool DisableGsym = false;
|
||||||
std::string DefaultArch;
|
std::string DefaultArch;
|
||||||
std::vector<std::string> DsymHints;
|
std::vector<std::string> DsymHints;
|
||||||
std::string FallbackDebugPath;
|
std::string FallbackDebugPath;
|
||||||
std::string DWPName;
|
std::string DWPName;
|
||||||
std::vector<std::string> DebugFileDirectory;
|
std::vector<std::string> DebugFileDirectory;
|
||||||
|
std::vector<std::string> GsymFileDirectory;
|
||||||
size_t MaxCacheSize =
|
size_t MaxCacheSize =
|
||||||
sizeof(size_t) == 4
|
sizeof(size_t) == 4
|
||||||
? 512 * 1024 * 1024 /* 512 MiB */
|
? 512 * 1024 * 1024 /* 512 MiB */
|
||||||
@ -177,6 +179,7 @@ private:
|
|||||||
ObjectFile *lookUpBuildIDObject(const std::string &Path,
|
ObjectFile *lookUpBuildIDObject(const std::string &Path,
|
||||||
const ELFObjectFileBase *Obj,
|
const ELFObjectFileBase *Obj,
|
||||||
const std::string &ArchName);
|
const std::string &ArchName);
|
||||||
|
std::string lookUpGsymFile(const std::string &Path);
|
||||||
|
|
||||||
bool findDebugBinary(const std::string &OrigPath,
|
bool findDebugBinary(const std::string &OrigPath,
|
||||||
const std::string &DebuglinkName, uint32_t CRCHash,
|
const std::string &DebuglinkName, uint32_t CRCHash,
|
||||||
|
@ -4,6 +4,7 @@ add_llvm_component_library(LLVMDebugInfoGSYM
|
|||||||
FileWriter.cpp
|
FileWriter.cpp
|
||||||
FunctionInfo.cpp
|
FunctionInfo.cpp
|
||||||
GsymCreator.cpp
|
GsymCreator.cpp
|
||||||
|
GsymDIContext.cpp
|
||||||
GsymReader.cpp
|
GsymReader.cpp
|
||||||
InlineInfo.cpp
|
InlineInfo.cpp
|
||||||
LineTable.cpp
|
LineTable.cpp
|
||||||
|
166
llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
Normal file
166
llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
//===-- GsymDIContext.cpp ------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/GSYM/GsymDIContext.h"
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/GSYM/GsymReader.h"
|
||||||
|
#include "llvm/Support/Path.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
using namespace llvm::gsym;
|
||||||
|
|
||||||
|
GsymDIContext::GsymDIContext(std::unique_ptr<GsymReader> Reader)
|
||||||
|
: DIContext(CK_GSYM), Reader(std::move(Reader)) {}
|
||||||
|
|
||||||
|
void GsymDIContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {}
|
||||||
|
|
||||||
|
static bool fillLineInfoFromLocation(const SourceLocation &Location,
|
||||||
|
DILineInfoSpecifier Specifier,
|
||||||
|
DILineInfo &LineInfo) {
|
||||||
|
// FIXME Demangle in case of DINameKind::ShortName
|
||||||
|
if (Specifier.FNKind != DINameKind::None) {
|
||||||
|
LineInfo.FunctionName = Location.Name.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Specifier.FLIKind) {
|
||||||
|
case DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath:
|
||||||
|
// We have no information to determine the relative path, so we fall back to
|
||||||
|
// returning the absolute path.
|
||||||
|
case DILineInfoSpecifier::FileLineInfoKind::RawValue:
|
||||||
|
case DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath:
|
||||||
|
if (Location.Dir.empty()) {
|
||||||
|
if (Location.Base.empty())
|
||||||
|
LineInfo.FileName = DILineInfo::BadString;
|
||||||
|
else
|
||||||
|
LineInfo.FileName = Location.Base.str();
|
||||||
|
} else {
|
||||||
|
SmallString<128> Path(Location.Dir);
|
||||||
|
sys::path::append(Path, Location.Base);
|
||||||
|
LineInfo.FileName = static_cast<std::string>(Path);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DILineInfoSpecifier::FileLineInfoKind::BaseNameOnly:
|
||||||
|
LineInfo.FileName = Location.Base.str();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LineInfo.Line = Location.Line;
|
||||||
|
|
||||||
|
// We don't have information in GSYM to fill any of the Source, Column,
|
||||||
|
// StartFileName or StartLine attributes.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<DILineInfo>
|
||||||
|
GsymDIContext::getLineInfoForAddress(object::SectionedAddress Address,
|
||||||
|
DILineInfoSpecifier Specifier) {
|
||||||
|
if (Address.SectionIndex != object::SectionedAddress::UndefSection)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto ResultOrErr = Reader->lookup(Address.Address);
|
||||||
|
|
||||||
|
if (!ResultOrErr) {
|
||||||
|
consumeError(ResultOrErr.takeError());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &Result = *ResultOrErr;
|
||||||
|
|
||||||
|
DILineInfo LineInfo;
|
||||||
|
|
||||||
|
if (Result.Locations.empty()) {
|
||||||
|
// No debug info for this, we just had a symbol from the symbol table.
|
||||||
|
|
||||||
|
// FIXME Demangle in case of DINameKind::ShortName
|
||||||
|
if (Specifier.FNKind != DINameKind::None)
|
||||||
|
LineInfo.FunctionName = Result.FuncName.str();
|
||||||
|
} else if (!fillLineInfoFromLocation(Result.Locations.front(), Specifier,
|
||||||
|
LineInfo))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
LineInfo.StartAddress = Result.FuncRange.start();
|
||||||
|
|
||||||
|
return LineInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<DILineInfo>
|
||||||
|
GsymDIContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
|
||||||
|
// We can't implement this, there's no such information in the GSYM file.
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
DILineInfoTable
|
||||||
|
GsymDIContext::getLineInfoForAddressRange(object::SectionedAddress Address,
|
||||||
|
uint64_t Size,
|
||||||
|
DILineInfoSpecifier Specifier) {
|
||||||
|
if (Size == 0)
|
||||||
|
return DILineInfoTable();
|
||||||
|
|
||||||
|
if (Address.SectionIndex != llvm::object::SectionedAddress::UndefSection)
|
||||||
|
return DILineInfoTable();
|
||||||
|
|
||||||
|
if (auto FuncInfoOrErr = Reader->getFunctionInfo(Address.Address)) {
|
||||||
|
DILineInfoTable Table;
|
||||||
|
if (FuncInfoOrErr->OptLineTable) {
|
||||||
|
const gsym::LineTable < = *FuncInfoOrErr->OptLineTable;
|
||||||
|
const uint64_t StartAddr = Address.Address;
|
||||||
|
const uint64_t EndAddr = Address.Address + Size;
|
||||||
|
for (const auto &LineEntry : LT) {
|
||||||
|
if (StartAddr <= LineEntry.Addr && LineEntry.Addr < EndAddr) {
|
||||||
|
// Use LineEntry.Addr, LineEntry.File (which is a file index into the
|
||||||
|
// files tables from the GsymReader), and LineEntry.Line (source line
|
||||||
|
// number) to add stuff to the DILineInfoTable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Table;
|
||||||
|
} else {
|
||||||
|
consumeError(FuncInfoOrErr.takeError());
|
||||||
|
return DILineInfoTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DIInliningInfo
|
||||||
|
GsymDIContext::getInliningInfoForAddress(object::SectionedAddress Address,
|
||||||
|
DILineInfoSpecifier Specifier) {
|
||||||
|
auto ResultOrErr = Reader->lookup(Address.Address);
|
||||||
|
|
||||||
|
if (!ResultOrErr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto &Result = *ResultOrErr;
|
||||||
|
|
||||||
|
DIInliningInfo InlineInfo;
|
||||||
|
|
||||||
|
for (const auto &Location : Result.Locations) {
|
||||||
|
DILineInfo LineInfo;
|
||||||
|
|
||||||
|
if (!fillLineInfoFromLocation(Location, Specifier, LineInfo))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Hm, that's probably something that should only be filled in the first or
|
||||||
|
// last frame?
|
||||||
|
LineInfo.StartAddress = Result.FuncRange.start();
|
||||||
|
|
||||||
|
InlineInfo.addFrame(LineInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InlineInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DILocal>
|
||||||
|
GsymDIContext::getLocalsForAddress(object::SectionedAddress Address) {
|
||||||
|
// We can't implement this, there's no such information in the GSYM file.
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
@ -10,6 +10,7 @@ add_llvm_component_library(LLVMSymbolize
|
|||||||
|
|
||||||
LINK_COMPONENTS
|
LINK_COMPONENTS
|
||||||
DebugInfoDWARF
|
DebugInfoDWARF
|
||||||
|
DebugInfoGSYM
|
||||||
DebugInfoPDB
|
DebugInfoPDB
|
||||||
DebugInfoBTF
|
DebugInfoBTF
|
||||||
Object
|
Object
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/DebugInfo/BTF/BTFContext.h"
|
#include "llvm/DebugInfo/BTF/BTFContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
|
#include "llvm/DebugInfo/GSYM/GsymDIContext.h"
|
||||||
|
#include "llvm/DebugInfo/GSYM/GsymReader.h"
|
||||||
#include "llvm/DebugInfo/PDB/PDB.h"
|
#include "llvm/DebugInfo/PDB/PDB.h"
|
||||||
#include "llvm/DebugInfo/PDB/PDBContext.h"
|
#include "llvm/DebugInfo/PDB/PDBContext.h"
|
||||||
#include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
|
#include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
|
||||||
@ -498,6 +500,34 @@ bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LLVMSymbolizer::lookUpGsymFile(const std::string &Path) {
|
||||||
|
if (Opts.DisableGsym)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto CheckGsymFile = [](const llvm::StringRef &GsymPath) {
|
||||||
|
sys::fs::file_status Status;
|
||||||
|
std::error_code EC = llvm::sys::fs::status(GsymPath, Status);
|
||||||
|
return !EC && !llvm::sys::fs::is_directory(Status);
|
||||||
|
};
|
||||||
|
|
||||||
|
// First, look beside the binary file
|
||||||
|
if (const auto GsymPath = Path + ".gsym"; CheckGsymFile(GsymPath))
|
||||||
|
return GsymPath;
|
||||||
|
|
||||||
|
// Then, look in the directories specified by GsymFileDirectory
|
||||||
|
|
||||||
|
for (const auto &Directory : Opts.GsymFileDirectory) {
|
||||||
|
SmallString<16> GsymPath = llvm::StringRef{Directory};
|
||||||
|
llvm::sys::path::append(GsymPath,
|
||||||
|
llvm::sys::path::filename(Path) + ".gsym");
|
||||||
|
|
||||||
|
if (CheckGsymFile(GsymPath))
|
||||||
|
return static_cast<std::string>(GsymPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Expected<LLVMSymbolizer::ObjectPair>
|
Expected<LLVMSymbolizer::ObjectPair>
|
||||||
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
|
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
|
||||||
const std::string &ArchName) {
|
const std::string &ArchName) {
|
||||||
@ -634,30 +664,48 @@ LLVMSymbolizer::getOrCreateModuleInfo(StringRef ModuleName) {
|
|||||||
std::unique_ptr<DIContext> Context;
|
std::unique_ptr<DIContext> Context;
|
||||||
// If this is a COFF object containing PDB info and not containing DWARF
|
// If this is a COFF object containing PDB info and not containing DWARF
|
||||||
// section, use a PDBContext to symbolize. Otherwise, use DWARF.
|
// section, use a PDBContext to symbolize. Otherwise, use DWARF.
|
||||||
if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
|
// Create a DIContext to symbolize as follows:
|
||||||
const codeview::DebugInfo *DebugInfo;
|
// - If there is a GSYM file, create a GsymDIContext.
|
||||||
StringRef PDBFileName;
|
// - Otherwise, if this is a COFF object containing PDB info, create a
|
||||||
auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
|
// PDBContext.
|
||||||
// Use DWARF if there're DWARF sections.
|
// - Otherwise, create a DWARFContext.
|
||||||
bool HasDwarf =
|
const auto GsymFile = lookUpGsymFile(BinaryName.str());
|
||||||
llvm::any_of(Objects.first->sections(), [](SectionRef Section) -> bool {
|
if (!GsymFile.empty()) {
|
||||||
if (Expected<StringRef> SectionName = Section.getName())
|
auto ReaderOrErr = gsym::GsymReader::openFile(GsymFile);
|
||||||
return SectionName.get() == ".debug_info";
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (!EC && !HasDwarf && DebugInfo != nullptr && !PDBFileName.empty()) {
|
|
||||||
using namespace pdb;
|
|
||||||
std::unique_ptr<IPDBSession> Session;
|
|
||||||
|
|
||||||
PDB_ReaderType ReaderType =
|
if (ReaderOrErr) {
|
||||||
Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
|
std::unique_ptr<gsym::GsymReader> Reader =
|
||||||
if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
|
std::make_unique<gsym::GsymReader>(std::move(*ReaderOrErr));
|
||||||
Session)) {
|
|
||||||
Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
|
Context = std::make_unique<gsym::GsymDIContext>(std::move(Reader));
|
||||||
// Return along the PDB filename to provide more context
|
}
|
||||||
return createFileError(PDBFileName, std::move(Err));
|
}
|
||||||
|
if (!Context) {
|
||||||
|
if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
|
||||||
|
const codeview::DebugInfo *DebugInfo;
|
||||||
|
StringRef PDBFileName;
|
||||||
|
auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
|
||||||
|
// Use DWARF if there're DWARF sections.
|
||||||
|
bool HasDwarf = llvm::any_of(
|
||||||
|
Objects.first->sections(), [](SectionRef Section) -> bool {
|
||||||
|
if (Expected<StringRef> SectionName = Section.getName())
|
||||||
|
return SectionName.get() == ".debug_info";
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
if (!EC && !HasDwarf && DebugInfo != nullptr && !PDBFileName.empty()) {
|
||||||
|
using namespace pdb;
|
||||||
|
std::unique_ptr<IPDBSession> Session;
|
||||||
|
|
||||||
|
PDB_ReaderType ReaderType =
|
||||||
|
Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
|
||||||
|
if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
|
||||||
|
Session)) {
|
||||||
|
Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
|
||||||
|
// Return along the PDB filename to provide more context
|
||||||
|
return createFileError(PDBFileName, std::move(Err));
|
||||||
|
}
|
||||||
|
Context.reset(new PDBContext(*CoffObject, std::move(Session)));
|
||||||
}
|
}
|
||||||
Context.reset(new PDBContext(*CoffObject, std::move(Session)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Context)
|
if (!Context)
|
||||||
|
BIN
llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe
Executable file
BIN
llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe
Executable file
Binary file not shown.
BIN
llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym
Normal file
BIN
llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym
Normal file
Binary file not shown.
93
llvm/test/tools/llvm-symbolizer/sym-gsymonly.test
Normal file
93
llvm/test/tools/llvm-symbolizer/sym-gsymonly.test
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# This test is a variant of sym.test. It uses a binary without DWARF debug
|
||||||
|
# info, but a corresponding .gsym file. The expectations are the same, except
|
||||||
|
# for the fact that GSYM doesn't provide us with column numbers.
|
||||||
|
#
|
||||||
|
# Source:
|
||||||
|
# #include <stdio.h>
|
||||||
|
# static inline int inctwo (int *a) {
|
||||||
|
# printf ("%d\n",(*a)++);
|
||||||
|
# return (*a)++;
|
||||||
|
# }
|
||||||
|
# static inline int inc (int *a) {
|
||||||
|
# printf ("%d\n",inctwo(a));
|
||||||
|
# return (*a)++;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# int main () {
|
||||||
|
# int x = 1;
|
||||||
|
# return inc(&x);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# Build as : clang -g -O2 addr.c
|
||||||
|
extrat gsym file as : llvm-gsymutil --convert=%p/Inputs/addr.exe --out-file=%p/Inputs/addr-gsymonly.exe.gsym
|
||||||
|
strip debug as : llvm-objcopy --strip-debug %p/Inputs/addr.exe %p/Inputs/addr-gsymonly.exe
|
||||||
|
|
||||||
|
|
||||||
|
RUN: llvm-symbolizer --print-address --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck %s
|
||||||
|
RUN: llvm-symbolizer --addresses --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck %s
|
||||||
|
RUN: llvm-symbolizer -a --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck %s
|
||||||
|
|
||||||
|
CHECK: ??:0:0
|
||||||
|
CHECK-EMPTY:
|
||||||
|
CHECK-NEXT: 0x40054d
|
||||||
|
CHECK-NEXT: inctwo
|
||||||
|
CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:3:0
|
||||||
|
CHECK-NEXT: inc
|
||||||
|
CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7:0
|
||||||
|
CHECK-NEXT: main
|
||||||
|
CHECK-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14:0
|
||||||
|
CHECK-EMPTY:
|
||||||
|
CHECK-NEXT: ??
|
||||||
|
CHECK-NEXT: ??:0:0
|
||||||
|
|
||||||
|
RUN: llvm-symbolizer --inlining --print-address --pretty-print --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
RUN: llvm-symbolizer --inlining --print-address -p --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
RUN: llvm-symbolizer --inlines --print-address --pretty-print --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
RUN: llvm-symbolizer --inlines --print-address -p --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
RUN: llvm-symbolizer -i --print-address --pretty-print --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
RUN: llvm-symbolizer -i --print-address -p --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
|
||||||
|
# Before 2020-08-04, asan_symbolize.py passed --inlining=true.
|
||||||
|
# Support this compatibility alias for a while.
|
||||||
|
RUN: llvm-symbolizer --inlining=true --print-address -p --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix="PRETTY" %s
|
||||||
|
|
||||||
|
PRETTY: ??:0:0
|
||||||
|
PRETTY: {{[0x]+}}40054d: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3:0
|
||||||
|
PRETTY: (inlined by) inc at {{[/\]+}}tmp{{[/\]+}}x.c:7:0
|
||||||
|
PRETTY: (inlined by) main at {{[/\]+}}tmp{{[/\]+}}x.c:14:0
|
||||||
|
PRETTY: ??:0:0
|
||||||
|
|
||||||
|
RUN: llvm-addr2line --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefix=A2L %s
|
||||||
|
RUN: llvm-addr2line -a --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_A %s
|
||||||
|
RUN: llvm-addr2line -f --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_F %s
|
||||||
|
RUN: llvm-addr2line -i --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_I %s
|
||||||
|
RUN: llvm-addr2line -fi --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2L,A2L_F,A2L_I,A2L_FI %s
|
||||||
|
|
||||||
|
RUN: llvm-addr2line -pa --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_A %s
|
||||||
|
RUN: llvm-addr2line -pf --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_F %s
|
||||||
|
RUN: llvm-addr2line -paf --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_AF %s
|
||||||
|
RUN: llvm-addr2line -pai --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_A,A2LP_I %s
|
||||||
|
RUN: llvm-addr2line -pfi --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_F,A2LP_FI %s
|
||||||
|
RUN: llvm-addr2line -pafi --obj=%p/Inputs/addr-gsymonly.exe < %p/Inputs/addr.inp | FileCheck -check-prefixes=A2LP,A2LP_AF,A2LP_FI %s
|
||||||
|
|
||||||
|
A2L: ??:0
|
||||||
|
A2L_A-NEXT: 0x40054d
|
||||||
|
A2L_F-NEXT: inctwo
|
||||||
|
A2L-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
|
||||||
|
A2L_FI-NEXT: inc{{$}}
|
||||||
|
A2L_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
|
||||||
|
A2L_FI-NEXT: main
|
||||||
|
A2L_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
|
||||||
|
A2L_F-NEXT: ??
|
||||||
|
A2L-NEXT: ??:0
|
||||||
|
|
||||||
|
A2LP: ??:0
|
||||||
|
A2LP_A-NEXT: 0x40054d: {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
|
||||||
|
A2LP_F-NEXT: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
|
||||||
|
A2LP_AF-NEXT: 0x40054d: inctwo at {{[/\]+}}tmp{{[/\]+}}x.c:3{{$}}
|
||||||
|
A2LP_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
|
||||||
|
A2LP_I-NEXT: {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
|
||||||
|
A2LP_FI-NEXT: (inlined by) inc at {{[/\]+}}tmp{{[/\]+}}x.c:7{{$}}
|
||||||
|
A2LP_FI-NEXT: (inlined by) main at {{[/\]+}}tmp{{[/\]+}}x.c:14{{$}}
|
||||||
|
A2LP-NEXT: ??:0
|
@ -16,6 +16,9 @@ class F<string name, string help>: Flag<["--"], name>, HelpText<help>;
|
|||||||
def grp_mach_o : OptionGroup<"kind">,
|
def grp_mach_o : OptionGroup<"kind">,
|
||||||
HelpText<"llvm-symbolizer Mach-O Specific Options">;
|
HelpText<"llvm-symbolizer Mach-O Specific Options">;
|
||||||
|
|
||||||
|
def grp_gsym : OptionGroup<"kind">,
|
||||||
|
HelpText<"llvm-symbolizer GSYM Related Options">;
|
||||||
|
|
||||||
def addresses : F<"addresses", "Show address before line information">;
|
def addresses : F<"addresses", "Show address before line information">;
|
||||||
defm adjust_vma
|
defm adjust_vma
|
||||||
: Eq<"adjust-vma", "Add specified offset to object file addresses">,
|
: Eq<"adjust-vma", "Add specified offset to object file addresses">,
|
||||||
@ -31,9 +34,11 @@ defm default_arch
|
|||||||
: Eq<"default-arch", "Default architecture (for multi-arch objects)">,
|
: Eq<"default-arch", "Default architecture (for multi-arch objects)">,
|
||||||
Group<grp_mach_o>;
|
Group<grp_mach_o>;
|
||||||
defm demangle : B<"demangle", "Demangle function names", "Don't demangle function names">;
|
defm demangle : B<"demangle", "Demangle function names", "Don't demangle function names">;
|
||||||
|
def disable_gsym : F<"disable-gsym", "Don't consider using GSYM files for symbolication">, Group<grp_gsym>;
|
||||||
def filter_markup : Flag<["--"], "filter-markup">, HelpText<"Filter symbolizer markup from stdin.">;
|
def filter_markup : Flag<["--"], "filter-markup">, HelpText<"Filter symbolizer markup from stdin.">;
|
||||||
def functions : F<"functions", "Print function name for a given address">;
|
def functions : F<"functions", "Print function name for a given address">;
|
||||||
def functions_EQ : Joined<["--"], "functions=">, HelpText<"Print function name for a given address">, Values<"none,short,linkage">;
|
def functions_EQ : Joined<["--"], "functions=">, HelpText<"Print function name for a given address">, Values<"none,short,linkage">;
|
||||||
|
defm gsym_file_directory : Eq<"gsym-file-directory", "Path to directory where to look for GSYM files">, MetaVarName<"<dir>">, Group<grp_gsym>;
|
||||||
def help : F<"help", "Display this help">;
|
def help : F<"help", "Display this help">;
|
||||||
defm dwp : Eq<"dwp", "Path to DWP file to be use for any split CUs">, MetaVarName<"<file>">;
|
defm dwp : Eq<"dwp", "Path to DWP file to be use for any split CUs">, MetaVarName<"<file>">;
|
||||||
defm dsym_hint
|
defm dsym_hint
|
||||||
|
@ -499,6 +499,8 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
|
|||||||
Opts.DWPName = Args.getLastArgValue(OPT_dwp_EQ).str();
|
Opts.DWPName = Args.getLastArgValue(OPT_dwp_EQ).str();
|
||||||
Opts.FallbackDebugPath =
|
Opts.FallbackDebugPath =
|
||||||
Args.getLastArgValue(OPT_fallback_debug_path_EQ).str();
|
Args.getLastArgValue(OPT_fallback_debug_path_EQ).str();
|
||||||
|
Opts.GsymFileDirectory = Args.getAllArgValues(OPT_gsym_file_directory_EQ);
|
||||||
|
Opts.DisableGsym = Args.hasArg(OPT_disable_gsym);
|
||||||
Opts.PrintFunctions = decideHowToPrintFunctions(Args, IsAddr2Line);
|
Opts.PrintFunctions = decideHowToPrintFunctions(Args, IsAddr2Line);
|
||||||
parseIntArg(Args, OPT_print_source_context_lines_EQ,
|
parseIntArg(Args, OPT_print_source_context_lines_EQ,
|
||||||
Config.SourceContextLines);
|
Config.SourceContextLines);
|
||||||
|
@ -12,6 +12,7 @@ static_library("GSYM") {
|
|||||||
"FileWriter.cpp",
|
"FileWriter.cpp",
|
||||||
"FunctionInfo.cpp",
|
"FunctionInfo.cpp",
|
||||||
"GsymCreator.cpp",
|
"GsymCreator.cpp",
|
||||||
|
"GsymDIContext.cpp",
|
||||||
"GsymReader.cpp",
|
"GsymReader.cpp",
|
||||||
"Header.cpp",
|
"Header.cpp",
|
||||||
"InlineInfo.cpp",
|
"InlineInfo.cpp",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user