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:
https://github.com/llvm/llvm-project/pull/139686/commits/ba55425db9fd8fd1ebb06a4c8d8c95eef213444f
That's the only change compare to
https://github.com/llvm/llvm-project/pull/134847
diff --git a/compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh b/compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
index a7b78f8..fe49d94 100755
--- a/compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
+++ b/compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
@@ -145,7 +145,7 @@
$LLVM_SRC
fi
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}
rm -rf ${SYMBOLIZER_BUILD}
@@ -174,6 +174,7 @@
$LLVM_BUILD/lib/libLLVMObject.a \
$LLVM_BUILD/lib/libLLVMBinaryFormat.a \
$LLVM_BUILD/lib/libLLVMDebugInfoDWARF.a \
+ $LLVM_BUILD/lib/libLLVMDebugInfoGSYM.a \
$LLVM_BUILD/lib/libLLVMSupport.a \
$LLVM_BUILD/lib/libLLVMDebugInfoPDB.a \
$LLVM_BUILD/lib/libLLVMDebugInfoMSF.a \
diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index c90b999..0347f90 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -238,7 +238,7 @@
class DIContext {
public:
- enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF };
+ enum DIContextKind { CK_DWARF, CK_PDB, CK_BTF, CK_GSYM };
DIContext(DIContextKind K) : Kind(K) {}
virtual ~DIContext() = default;
diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h b/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
new file mode 100644
index 0000000..396c08c
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
@@ -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
diff --git a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
index 5747ad9..7c6beaa 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -58,11 +58,13 @@
bool RelativeAddresses = false;
bool UntagAddresses = false;
bool UseDIA = false;
+ bool DisableGsym = false;
std::string DefaultArch;
std::vector<std::string> DsymHints;
std::string FallbackDebugPath;
std::string DWPName;
std::vector<std::string> DebugFileDirectory;
+ std::vector<std::string> GsymFileDirectory;
size_t MaxCacheSize =
sizeof(size_t) == 4
? 512 * 1024 * 1024 /* 512 MiB */
@@ -177,6 +179,7 @@
ObjectFile *lookUpBuildIDObject(const std::string &Path,
const ELFObjectFileBase *Obj,
const std::string &ArchName);
+ std::string lookUpGsymFile(const std::string &Path);
bool findDebugBinary(const std::string &OrigPath,
const std::string &DebuglinkName, uint32_t CRCHash,
diff --git a/llvm/lib/DebugInfo/GSYM/CMakeLists.txt b/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
index c27d648..724b5b2 100644
--- a/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
@@ -4,6 +4,7 @@
FileWriter.cpp
FunctionInfo.cpp
GsymCreator.cpp
+ GsymDIContext.cpp
GsymReader.cpp
InlineInfo.cpp
LineTable.cpp
diff --git a/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
new file mode 100644
index 0000000..68024a9
--- /dev/null
+++ b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
@@ -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 {};
+}
diff --git a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
index 29f62bf..7aef3b0 100644
--- a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
@@ -10,6 +10,7 @@
LINK_COMPONENTS
DebugInfoDWARF
+ DebugInfoGSYM
DebugInfoPDB
DebugInfoBTF
Object
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 1d8217a..78a1421 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -15,6 +15,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/BTF/BTFContext.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/PDBContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
@@ -498,6 +500,34 @@
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>
LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName) {
@@ -634,30 +664,48 @@
std::unique_ptr<DIContext> Context;
// If this is a COFF object containing PDB info and not containing DWARF
// section, use a PDBContext to symbolize. Otherwise, use DWARF.
- 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;
+ // Create a DIContext to symbolize as follows:
+ // - If there is a GSYM file, create a GsymDIContext.
+ // - Otherwise, if this is a COFF object containing PDB info, create a
+ // PDBContext.
+ // - Otherwise, create a DWARFContext.
+ const auto GsymFile = lookUpGsymFile(BinaryName.str());
+ if (!GsymFile.empty()) {
+ auto ReaderOrErr = gsym::GsymReader::openFile(GsymFile);
- 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));
+ if (ReaderOrErr) {
+ std::unique_ptr<gsym::GsymReader> Reader =
+ std::make_unique<gsym::GsymReader>(std::move(*ReaderOrErr));
+
+ Context = std::make_unique<gsym::GsymDIContext>(std::move(Reader));
+ }
+ }
+ 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)
diff --git a/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe b/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe
new file mode 100755
index 0000000..f6f013b
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe
Binary files differ
diff --git a/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym b/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym
new file mode 100644
index 0000000..a46f78b
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym
Binary files differ
diff --git a/llvm/test/tools/llvm-symbolizer/sym-gsymonly.test b/llvm/test/tools/llvm-symbolizer/sym-gsymonly.test
new file mode 100644
index 0000000..0d00c00
--- /dev/null
+++ b/llvm/test/tools/llvm-symbolizer/sym-gsymonly.test
@@ -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
diff --git a/llvm/tools/llvm-symbolizer/Opts.td b/llvm/tools/llvm-symbolizer/Opts.td
index d0b227a..10f1e6d 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -16,6 +16,9 @@
def grp_mach_o : OptionGroup<"kind">,
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">;
defm adjust_vma
: Eq<"adjust-vma", "Add specified offset to object file addresses">,
@@ -31,9 +34,11 @@
: Eq<"default-arch", "Default architecture (for multi-arch objects)">,
Group<grp_mach_o>;
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 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">;
+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">;
defm dwp : Eq<"dwp", "Path to DWP file to be use for any split CUs">, MetaVarName<"<file>">;
defm dsym_hint
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 3ba7f59..b80f792 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -499,6 +499,8 @@
Opts.DWPName = Args.getLastArgValue(OPT_dwp_EQ).str();
Opts.FallbackDebugPath =
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);
parseIntArg(Args, OPT_print_source_context_lines_EQ,
Config.SourceContextLines);
diff --git a/llvm/utils/gn/secondary/llvm/lib/DebugInfo/GSYM/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/DebugInfo/GSYM/BUILD.gn
index cadd34d..157fa6e 100644
--- a/llvm/utils/gn/secondary/llvm/lib/DebugInfo/GSYM/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/DebugInfo/GSYM/BUILD.gn
@@ -12,6 +12,7 @@
"FileWriter.cpp",
"FunctionInfo.cpp",
"GsymCreator.cpp",
+ "GsymDIContext.cpp",
"GsymReader.cpp",
"Header.cpp",
"InlineInfo.cpp",