[llvm] [DRAFT] LLVM symbolizer gsym support (PR #134847)

Mariusz Kwiczala via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 17 00:39:47 PDT 2025


https://github.com/sfc-gh-mkwiczala updated https://github.com/llvm/llvm-project/pull/134847

>From f04cbe9337ea322e911c30dcee135cee361f2677 Mon Sep 17 00:00:00 2001
From: Mariusz Kwiczala <mariusz.kwiczala at snowflake.com>
Date: Tue, 8 Apr 2025 12:01:45 +0000
Subject: [PATCH 1/5] llvm-symbolizer add gsym support

---
 llvm/include/llvm/DebugInfo/DIContext.h       |   2 +-
 .../llvm/DebugInfo/GSYM/GsymDIContext.h       |  66 +++++++
 .../llvm/DebugInfo/Symbolize/Symbolize.h      |   3 +
 llvm/lib/DebugInfo/GSYM/CMakeLists.txt        |   1 +
 llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp     | 170 ++++++++++++++++++
 llvm/lib/DebugInfo/Symbolize/CMakeLists.txt   |   1 +
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp    |  98 +++++++---
 .../tools/llvm-symbolizer/sym-gsymonly.test   |  93 ++++++++++
 llvm/tools/llvm-symbolizer/Opts.td            |   5 +
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |   2 +
 .../llvm/lib/DebugInfo/GSYM/BUILD.gn          |   1 +
 11 files changed, 418 insertions(+), 24 deletions(-)
 create mode 100644 llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
 create mode 100644 llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
 create mode 100644 llvm/test/tools/llvm-symbolizer/sym-gsymonly.test

diff --git a/llvm/include/llvm/DebugInfo/DIContext.h b/llvm/include/llvm/DebugInfo/DIContext.h
index c90b99987f1db..0347f90c236d1 100644
--- a/llvm/include/llvm/DebugInfo/DIContext.h
+++ b/llvm/include/llvm/DebugInfo/DIContext.h
@@ -238,7 +238,7 @@ struct DIDumpOptions {
 
 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 0000000000000..a45db18fe8de6
--- /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;
+
+  DILineInfo getLineInfoForAddress(
+      object::SectionedAddress Address,
+      DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
+  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 5747ad99d0f13..7c6beaa2189b7 100644
--- a/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
+++ b/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h
@@ -58,11 +58,13 @@ class LLVMSymbolizer {
     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 @@ class LLVMSymbolizer {
   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 c27d648db62f6..724b5b213d643 100644
--- a/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
@@ -4,6 +4,7 @@ add_llvm_component_library(LLVMDebugInfoGSYM
   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 0000000000000..99d25216082c3
--- /dev/null
+++ b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
@@ -0,0 +1,170 @@
+//===-- 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;
+}
+
+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;
+}
+
+DILineInfo
+GsymDIContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
+  // TODO:
+  // We can't implement this, there's no such information in the GSYM file.
+
+  return DILineInfo();
+}
+
+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 &LT = *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 std::vector<DILocal>();
+}
diff --git a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
index 29f62bf6156fc..7aef3b0d79a3a 100644
--- a/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/Symbolize/CMakeLists.txt
@@ -10,6 +10,7 @@ add_llvm_component_library(LLVMSymbolize
 
   LINK_COMPONENTS
   DebugInfoDWARF
+  DebugInfoGSYM
   DebugInfoPDB
   DebugInfoBTF
   Object
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index b96f97a159243..29b38aa1288f2 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,38 @@ bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
   return false;
 }
 
+std::string LLVMSymbolizer::lookUpGsymFile(const std::string &Path) {
+  if (Opts.DisableGsym)
+    return {};
+
+  auto CheckGsymFile = [](const llvm::StringRef &GsymPath) {
+    // TODO Also check if GSYM file is up-to-date?
+    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
+  {
+    const auto GsymPath = Path + ".gsym";
+    if (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 +668,48 @@ LLVMSymbolizer::getOrCreateModuleInfo(StringRef ModuleName) {
   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;
-
-      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));
+  // 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);
+  if (!GsymFile.empty()) {
+    auto ReaderOrErr = gsym::GsymReader::openFile(GsymFile);
+
+    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/sym-gsymonly.test b/llvm/test/tools/llvm-symbolizer/sym-gsymonly.test
new file mode 100644
index 0000000000000..0d00c002a2bdb
--- /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 d0b227af9db46..10f1e6dbbddf7 100644
--- a/llvm/tools/llvm-symbolizer/Opts.td
+++ b/llvm/tools/llvm-symbolizer/Opts.td
@@ -16,6 +16,9 @@ class F<string name, string help>: Flag<["--"], name>, HelpText<help>;
 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 @@ defm default_arch
     : 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 3ba7f59d5b847..b80f79200ba42 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -499,6 +499,8 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
   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 cadd34ddd908a..157fa6e885afc 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 @@ static_library("GSYM") {
     "FileWriter.cpp",
     "FunctionInfo.cpp",
     "GsymCreator.cpp",
+    "GsymDIContext.cpp",
     "GsymReader.cpp",
     "Header.cpp",
     "InlineInfo.cpp",

>From 978438d546ef2b7c700e011d59beb8eb43ca913d Mon Sep 17 00:00:00 2001
From: Mariusz Kwiczala <mariusz.kwiczala at snowflake.com>
Date: Tue, 8 Apr 2025 12:09:14 +0000
Subject: [PATCH 2/5] add addr-gsymonly.exe addr-gsymonly.exe.gsym

---
 .../llvm-symbolizer/Inputs/addr-gsymonly.exe     | Bin 0 -> 8528 bytes
 .../Inputs/addr-gsymonly.exe.gsym                | Bin 0 -> 536 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100755 llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe
 create mode 100644 llvm/test/tools/llvm-symbolizer/Inputs/addr-gsymonly.exe.gsym

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 0000000000000000000000000000000000000000..f6f013b2458229262a6f5ccdca2c5773398ba144
GIT binary patch
literal 8528
zcmeHNU2GKB6~4QRvH7XJID{Cm;%T+C5b$7QV>v}BV~ow1F5sA at QY+|q?Op7x*1KqT
zHo+}PExEL;fYeg^fU5pPmD2Lis(olA!~>W*3aa`-`jSdbs}&8Bp`bb?MOGxT{mz|x
zc4x;+(?0a2@{wlFJ>NawJ?Gx}yZ7#XvoGB5_xS{iUwlE3)waTrkaHGdW}`F})-6^E
zL$ruyu at XoP4nx+Ec1o-lRnx5NlwSaP1&(gN19bZhSzz7lz=+ at oXGogjmBmm+N3W=L
zOx8kZ5+EMsI{ztYLJ!LVYtF+^`7n=6;)#0c4n6D?lrE^mSabiVZ*)XddlA0 at i)@3G
z*e}mzO}-?9ckCFIH5rt&L2ya$kd_dvnfD at iilRLJz2ZEFRJ<pROOwi<wd$_enM{my
zb?!{YT9b)X?sV(v?ylCZPCc8}cgcPS5uSVx96lx!;c;w$MLDm>LH7XFH@@=o0e^GL
zjW;e_%^qxt?6|i5%=>(QkR~q2MX^E%=cA(H6O2u$Z>-|;=_lY6L#yI1ENg5cowBla
zG-F$qz_5(cD0GQanMBGyiF$%m{X{g85(mNq`+BWi`YwGpHRxCU^9dR=I!JPx604}L
z!!bpnVOW;v8q=7RBseUKblX#oEOjniT|!x9PT#MaA4SoeeyeUyh~n;hYcx^Zav$f0
z76T=+$I16 at p$OS>n`~<O?k$+ at 4+iq@eAUd~HmBcT7>o?uoIO=z2=nHRDXDH6Q1dt8
z_~Fb9#WK&=Orinv?5yoC-jYFQ+;Zh}Nc5Q5szI64i}hyy&ddH2b5|$<B7Jz`I#m at 5
z4J}iIT_KD8Z!8AjZ{~k%-nh5d^xZPwS<Hcal^o5pe*oFczwPjEEB at 3A+mMdPtvd$h
z{HsXx#M?C+0QnxyQUA^97YcQ7u%9iZu>RQfMZ7KGU%YkV?l(YbXc2d_(CEnE^=3Sw
z*Jym&XXmedTr4^OjX8i{0=Pog>nn3kuOH5xB+(mMz6BI%=98g6hV!vd!MxaNA#(WQ
zmO)a$=finBv=Gjp2`!rW;~|XR{qFF#J3aZw1NlehjmLq3{JZnp5y3qBz;15;6XhSy
ze-zF?+MoY>PjUTw=JcG;eEx5ld*=D$AzX at NC>TB;3pIsN(!%HM(AMzzGodzIm2OH;
zUN7giz`f)bTVkt)Z*yP|y=&;1Ej&gjXboLI2R#V=I`lBK94(aTxhC;_eMtCD2Ys8@
z*4E8nbV9)BT|R?0+Q^|k*k9jtuwl*1byH&RrajMfgg!$s^8+3};gXN;K1Yr{_3}|6
z+{SSkxcfe*co%TI4m=MnUc6BA?Uh!&(LY`LUH at x=i`1cISssDq5m+99<q=pOf&cRn
z2x4AFvarI@(!h!5j6CmLt11=(j-OgCiM1;oo0oySZrZH;c|Ae%YLW%DzT)*8*Yjuh
zlHVXV at z0NoY0|TP1LyME&QS4rO;hk2s1;(hJPWZ`=`~6>DgCt4taz?G-!Lp8o+HRP
z2oRoc)GER=O3$kJj9*qZ_k-iDQvPgXx*_{>PWfYMByFGaTTu3ts#oy;Uh%rs6KR9G
zA3p23FWBusZ|~=|t;a at kDLbci>fL&K>#m%%+FxyN)7v`r_H7O>Mw8LhnD$aUlTD;k
zT8G}Hw`p7L=va2=P+z#O=V+hR(bcx|WFi$!ZWEq%JN1s%PN&`7PK!W<&=aYIZACMg
z=%moWOmNwbpSFcQmd0r`JuwkaIhKAZi9#lxj5;Nv3w<P;6?$wkm9;ZMkB?g?Gtr5-
zH6DZYwNaeLQaN3vZNbE{EuJ~0ngOlC!D(o6!b!)e8johjg`P^=alL2XKr6aj4x?}i
zF_KGQxtxf}CZZFGQK4tYk&_)AL5cO`gtRm1Sk#WfmCm0a0X)Useq)JO0CV_ARXiZ<
zs`v_VsVZJmdOqDj0 at xWTRQ0bF{QOq>*NJNPeE_>j{Jd29uNM5=RpM*JY?bFHAl3?g
zZ&mu^Emr0J4q#J<_qi(l8%poHN<1i<)O)ZJUsu|nsl*$_U{(L8O8ZZh{_9Kc%}V at f
zK`T(N1jL5&ew3>+Af74h7r0>T8#D=i4_4wEMG(tsuLQ&<LCbBg1O&hJ%Qdtf^kY1a
zd&W757oSfo&Hs1Gf6C+kdxihngCAA6_xtsMY`>f*Oeq at 9KD^!eJLI6)Z$g3c<nJNl
z#Pf-z*X68iA3H_02D?f<De<NK>XHdOwIuGF(tqjoO32oh#{G%(UwXa%3japrPrEK8
z{5?bRLX$}4=?5 at 1vGn?W3I0LxLD74CAHcs+EWQ8#4F78TWwi5A4ZnnTf>q+4fWL-1
zuRH{>&c9JKdG5CZ at Lz|P__^cx!yE9YaiDD{61m2Q-Uol`*H%wEKSmw-d!P3+z^jeJ
zUz9)XXOYM~2k19(XgIv`J<1dLd&jdGxaM_+{VN=e)!tW@`aH#Q6BCnG`TJ+#8<&~H
zc491TjV03~(WDi#)0wOl&7HQ&pGM{8eBxvq)hR$-ZOh$DK=@KRJC$NInoPQOHmMPO
ziBzT9(;Us_WFx{l_>wggA4_EM;p|ODv)Oo7#Nru+SoVZ9noOqv%Kc9loARcnvuSHQ
znu;ak!WxJivdY}Zp<ZG}q9a_#tyb2!I}=aE(999!8cU?CTs96fF2AFmy;{pU*gIr}
z2aZOtaqAd;hxf~J|4`4NK8r2H;_`v;k$pX3>qvk9(Y}Zk>Dd?V19$(I5BD4z=tU!*
z&0fQB at Af)d!j%}NFQ<}mJ08=!p6}RI<xctUpd8$B%az^>JTKtiH+VkIt&*=>egUHv
z2ftT%{=mOuXl`ee`FUjcEfm~*o at dyq!4Nwt?dAUrIQ_oE at p(RS$-`f%_&guyc76){
z5$4#;pY<C+Xni47>Gvcr->DVi`zX+wg82o%0ZU+>Bb69-l<Xso9mj7{_!psR&B1&l
zV8|LnEkt<TB0-$I<NqCCv}R!bl;Te*KF8zy*^l)}@M#UgHqWchDZYk!61qn2{3VFf
zD>!H at na}gD%Zkta<oKKq<6R#9tjd2@@p;`vd|F$2`35k`i`(b<+=Als&v0;&!q=Vc
zJt(;OrFoxn<oN8*>t5EhzIF5Yd(o!&?@^^on8(l$QE>Bl-Mm(Hh}Vnk at 6G=s#pm(o
z?_QJQ^LRapPxB;-&wOpAAzd}a-yyB?$s7MFs@!~@zYZ$?Z^~3z^5#Qax<=}9mFBtp
z`=Zz1Ytuc^;NtWAZGkEvUVpD0g%9Px at p<07_#g7$1(&+Y{POR;03iix974|z3CHLA
zpaqyaKL2i4piV*9-?7Rz<E^N0^Lf5LulQS;s5J9f`$2Z|d0rn>338s?4D;CTM}aWz
zKhI}0MfCc6 at 1GF36u%9JTbNJp7q^fv3F`vN9Gh^KA8~wkR23dm`~x`O`^+VMd7Wd;
dt3MAs3v)XT?hn7e?g6V7e}*@PJdJzf{|ntnJZk^|

literal 0
HcmV?d00001

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 0000000000000000000000000000000000000000..a46f78b9d880c13b2ae125aafddc735145aac0a9
GIT binary patch
literal 536
zcmZvYF-yZh6o6mS#8wm)brP|TQpNTk*i94!Q5QjYrb!wDxm?Iyv4sj598?^fopg|{
z&JKeA#lf+oqwlV at hTtP#-uvF=a>qM3J>E6ITn1=@iW%aD7!ZqBgFSP#`tfrACibf*
zTko6w&ta)yomrXnY7MOgyJ;tOX3tImGz|I!aY&pK36T*G#1rvFd=nKDfSyUvR(&Qg
zCyb#kSpwZ{7s6O0FFCkQ6k))4j6yo81kX?XAQaM1Q8IKR9{U3RX(4(XgNV1B2tCPD
zflj9j?bKmDdL71kfEa}>7hTc8b{K~+e*bl;DPeppYSH(8p4@&^JQjSV;I)G96#S^*
z7dcmZX>6JbWvg5=p<mZCT-W`Yq1M$G8^*lKa|W!zlB&w8KMFN-`74xfiMyOnQ+=KD
EA4J?)ivR!s

literal 0
HcmV?d00001


>From 9df4bc16dcdf9dbf74517e23468e51b7d7410856 Mon Sep 17 00:00:00 2001
From: Mariusz Kwiczala <mariusz.kwiczala at snowflake.com>
Date: Tue, 8 Apr 2025 14:12:58 +0000
Subject: [PATCH 3/5] Add optional

---
 llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h | 4 ++--
 llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp        | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h b/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
index a45db18fe8de6..396c08c608d25 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymDIContext.h
@@ -40,10 +40,10 @@ class GsymDIContext : public DIContext {
 
   void dump(raw_ostream &OS, DIDumpOptions DIDumpOpts) override;
 
-  DILineInfo getLineInfoForAddress(
+  std::optional<DILineInfo> getLineInfoForAddress(
       object::SectionedAddress Address,
       DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
-  DILineInfo
+  std::optional<DILineInfo>
   getLineInfoForDataAddress(object::SectionedAddress Address) override;
   DILineInfoTable getLineInfoForAddressRange(
       object::SectionedAddress Address, uint64_t Size,
diff --git a/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
index 99d25216082c3..1fdecdc583993 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
@@ -60,7 +60,7 @@ static bool fillLineInfoFromLocation(const SourceLocation &Location,
   return true;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 GsymDIContext::getLineInfoForAddress(object::SectionedAddress Address,
                                      DILineInfoSpecifier Specifier) {
   if (Address.SectionIndex != object::SectionedAddress::UndefSection)
@@ -95,12 +95,12 @@ GsymDIContext::getLineInfoForAddress(object::SectionedAddress Address,
   return LineInfo;
 }
 
-DILineInfo
+std::optional<DILineInfo>
 GsymDIContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
   // TODO:
   // We can't implement this, there's no such information in the GSYM file.
 
-  return DILineInfo();
+  return {};
 }
 
 DILineInfoTable

>From 4c3db2c375fbfcea90ce5cb7d6f6ff3ee75de3a8 Mon Sep 17 00:00:00 2001
From: Mariusz Kwiczala <mariusz.kwiczala at snowflake.com>
Date: Tue, 8 Apr 2025 15:49:17 +0000
Subject: [PATCH 4/5] Fix compilation

---
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 29b38aa1288f2..11f35856a33cc 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -673,7 +673,7 @@ LLVMSymbolizer::getOrCreateModuleInfo(StringRef ModuleName) {
   // - Otherwise, if this is a COFF object containing PDB info, create a
   // PDBContext.
   // - Otherwise, create a DWARFContext.
-  const auto GsymFile = lookUpGsymFile(BinaryName);
+  const auto GsymFile = lookUpGsymFile(BinaryName.str());
   if (!GsymFile.empty()) {
     auto ReaderOrErr = gsym::GsymReader::openFile(GsymFile);
 

>From 632b9695de0416f3ec20079f338629fd935e5b3c Mon Sep 17 00:00:00 2001
From: Mariusz Kwiczala <70530507+sfc-gh-mkwiczala at users.noreply.github.com>
Date: Thu, 17 Apr 2025 09:39:37 +0200
Subject: [PATCH 5/5] Remove TODO

---
 llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp  | 1 -
 llvm/lib/DebugInfo/Symbolize/Symbolize.cpp | 1 -
 2 files changed, 2 deletions(-)

diff --git a/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
index 1fdecdc583993..d494e521851a2 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymDIContext.cpp
@@ -97,7 +97,6 @@ GsymDIContext::getLineInfoForAddress(object::SectionedAddress Address,
 
 std::optional<DILineInfo>
 GsymDIContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
-  // TODO:
   // We can't implement this, there's no such information in the GSYM file.
 
   return {};
diff --git a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
index 11f35856a33cc..16ac664506f49 100644
--- a/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
+++ b/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -505,7 +505,6 @@ std::string LLVMSymbolizer::lookUpGsymFile(const std::string &Path) {
     return {};
 
   auto CheckGsymFile = [](const llvm::StringRef &GsymPath) {
-    // TODO Also check if GSYM file is up-to-date?
     sys::fs::file_status Status;
     std::error_code EC = llvm::sys::fs::status(GsymPath, Status);
     return !EC && !llvm::sys::fs::is_directory(Status);



More information about the llvm-commits mailing list