Skip to content

Commit 7d44d6e

Browse files
[dsymutil] Teach dsymutil about CAS and loading clang modules from CAS
Teach dsymutil how to use CAS and how to load clang modules from CAS when building dSYM when gmodule is used.
1 parent 957a8ab commit 7d44d6e

File tree

18 files changed

+426
-64
lines changed

18 files changed

+426
-64
lines changed

clang/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ if( NOT CLANG_BUILT_STANDALONE )
153153
llvm-config
154154
FileCheck count not
155155
CASPluginTest
156+
dsymutil
156157
llc
157158
llvm-ar
158159
llvm-as

clang/test/ClangScanDeps/gmodules.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@
3535
// RUN: %clang @%t/Right.rsp
3636
// RUN: %clang @%t/tu.rsp
3737

38+
// RUN: llvm-dwarfdump --debug-info %t/tu.o | FileCheck %s --check-prefix=OBJECT-DWARF
39+
// OBJECT-DWARF: DW_TAG_compile_unit
40+
// OBJECT-DWARF: DW_AT_name ("Left")
41+
// OBJECT-DWARF: DW_AT_dwo_name ("llvmcas://
42+
43+
/// Check debug info is correct.
44+
// RUN: %clang %t/tu.o -o %t/a.out
45+
// RUN: dsymutil -cas %t/cas %t/a.out -o %t/a.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
46+
// RUN: dsymutil %t/a.out -o %t/a2.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
47+
// WARN-NOT: warning:
48+
49+
// RUN: dsymutil -cas %t/cas-empty %t/a.out -o %t/a3.dSYM 2>&1 | FileCheck %s --check-prefix=WARN-CAS --check-prefix=WARN-FILE
50+
// WARN-CAS: warning: failed to load CAS object
51+
// RUN: echo "bad" > %t/.cas-config
52+
// RUN: dsymutil %t/a.out -o %t/a4.dSYM 2>&1 | FileCheck %s --check-prefix=WARN-FILE
53+
// WARN-FILE: warning:
54+
// WARN-FILE-SAME: No such file or directory
55+
56+
// RUN: llvm-dwarfdump --debug-info %t/a.dSYM | FileCheck %s --check-prefix=DWARF
57+
3858
/// Check module in a different directory and compare output.
3959
// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json \
4060
// RUN: -cas-path %t/cas -module-files-dir %t/outputs-2 \
@@ -59,6 +79,39 @@
5979
// RUN: diff %t/prefix.h.pch %t/prefix_2.pch
6080
// RUN: diff %t/tu.o %t/tu_2.o
6181

82+
// Check all the types are available
83+
// DWARF: DW_TAG_compile_unit
84+
// DWARF: DW_TAG_module
85+
// DWARF-NEXT: DW_AT_name ("Top")
86+
// DWARF: DW_TAG_structure_type
87+
// DWARF-NEXT: DW_AT_name ("Top")
88+
// DWARF: DW_TAG_compile_unit
89+
// DWARF: DW_TAG_module
90+
// DWARF-NEXT: DW_AT_name ("Left")
91+
// DWARF: DW_TAG_structure_type
92+
// DWARF-NEXT: DW_AT_name ("Left")
93+
// DWARF: DW_TAG_member
94+
// DWARF-NEXT: DW_AT_name ("top")
95+
// DWARF-NEXT: DW_AT_type
96+
// DWARF-SAME: "Top::Top"
97+
// DWARF: DW_TAG_compile_unit
98+
// DWARF: DW_TAG_module
99+
// DWARF-NEXT: DW_AT_name ("Right")
100+
// DWARF: DW_TAG_structure_type
101+
// DWARF-NEXT: DW_AT_name ("Right")
102+
// DWARF: DW_TAG_member
103+
// DWARF-NEXT: DW_AT_name ("top")
104+
// DWARF-NEXT: DW_AT_type
105+
// DWARF-SAME: "Top::Top"
106+
// DWARF: DW_TAG_compile_unit
107+
// DWARF: DW_TAG_module
108+
// DWARF: DW_TAG_structure_type
109+
// DWARF-NEXT: DW_AT_name ("Prefix")
110+
// DWARF: DW_TAG_member
111+
// DWARF-NEXT: DW_AT_name ("top")
112+
// DWARF-NEXT: DW_AT_type
113+
// DWARF-SAME: "Top::Top"
114+
62115

63116
// CHECK: {
64117
// CHECK-NEXT: "modules": [

llvm/docs/CommandGuide/dsymutil.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ OPTIONS
4040
'profile'. Setting the DYLD_IMAGE_SUFFIX environment variable will
4141
cause dyld to load the specified variant at runtime.
4242

43+
.. option:: --cas <path to CAS>
44+
45+
Specify the path to a content addressable storage that dsymutil may used to
46+
resolve CASID file paths in the debug info.
47+
48+
.. option:: --cas-plugin-path <path to dylib>
49+
50+
Specify the path to CAS plugin dylib if used.
51+
52+
.. option:: --cas-plugin-option <cas option>
53+
54+
Specify the options to pass to CAS plugin dylib if needed.
55+
4356
.. option:: --dump-debug-map
4457

4558
Dump the *executable*'s debug-map (the list of the object files containing the

llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ class LLVM_ABI DWARFLinker : public DWARFLinkerBase {
239239
/// \pre NoODR, Update options should be set before call to addObjectFile.
240240
void addObjectFile(
241241
DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
242-
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override;
242+
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {},
243+
CASLoaderTy CASLoader = nullptr) override;
243244

244245
/// Link debug info for added objFiles. Object files are linked all together.
245246
Error link() override;
@@ -487,15 +488,15 @@ class LLVM_ABI DWARFLinker : public DWARFLinkerBase {
487488
bool registerModuleReference(const DWARFDie &CUDie, LinkContext &Context,
488489
ObjFileLoaderTy Loader,
489490
CompileUnitHandlerTy OnCUDieLoaded,
490-
unsigned Indent = 0);
491+
CASLoaderTy CASLoader, unsigned Indent = 0);
491492

492493
/// Recursively add the debug info in this clang module .pcm
493494
/// file (and all the modules imported by it in a bottom-up fashion)
494495
/// to ModuleUnits.
495496
Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie,
496497
const std::string &PCMFile, LinkContext &Context,
497498
CompileUnitHandlerTy OnCUDieLoaded,
498-
unsigned Indent = 0);
499+
CASLoaderTy CASLoader, unsigned Indent = 0);
499500

500501
/// Clone specified Clang module unit \p Unit.
501502
Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,

llvm/include/llvm/DWARFLinker/DWARFLinkerBase.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class DWARFLinkerBase {
8484
using ObjectPrefixMapTy = std::map<std::string, std::string>;
8585
using CompileUnitHandlerTy = function_ref<void(const DWARFUnit &Unit)>;
8686
using SwiftInterfacesMapTy = std::map<std::string, std::string>;
87+
using CASLoaderTy =
88+
std::function<Expected<DWARFFile *>(StringRef CASID, StringRef Filename)>;
8789
/// Type of output file.
8890
enum class OutputFileType : uint8_t {
8991
Object,
@@ -99,12 +101,15 @@ class DWARFLinkerBase {
99101
/// \p OnCUDieLoaded for each compile unit die. If \p File has reference to
100102
/// a Clang module and UpdateIndexTablesOnly == false then the module is be
101103
/// pre-loaded by \p Loader.
104+
/// \p CASLoader for loading file from CAS when compilation caching is
105+
/// enabled.
102106
///
103107
/// \pre a call to setNoODR(true) and/or setUpdateIndexTablesOnly(bool Update)
104108
/// must be made when required.
105109
virtual void addObjectFile(
106110
DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
107-
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) = 0;
111+
CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {},
112+
CASLoaderTy CASLoader = nullptr) = 0;
108113
/// Link the debug info for all object files added through calls to
109114
/// addObjectFile.
110115
virtual Error link() = 0;

llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2729,6 +2729,7 @@ bool DWARFLinker::registerModuleReference(const DWARFDie &CUDie,
27292729
LinkContext &Context,
27302730
ObjFileLoaderTy Loader,
27312731
CompileUnitHandlerTy OnCUDieLoaded,
2732+
CASLoaderTy CASLoader,
27322733
unsigned Indent) {
27332734
std::string PCMFile = getPCMFile(CUDie, Options.ObjectPrefixMap);
27342735
std::pair<bool, bool> IsClangModuleRef =
@@ -2748,47 +2749,62 @@ bool DWARFLinker::registerModuleReference(const DWARFDie &CUDie,
27482749
ClangModules.insert({PCMFile, getDwoId(CUDie)});
27492750

27502751
if (Error E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2751-
Indent + 2)) {
2752+
CASLoader, Indent + 2)) {
27522753
consumeError(std::move(E));
27532754
return false;
27542755
}
27552756
return true;
27562757
}
27572758

2758-
Error DWARFLinker::loadClangModule(
2759-
ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile,
2760-
LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {
2759+
Error DWARFLinker::loadClangModule(ObjFileLoaderTy Loader,
2760+
const DWARFDie &CUDie,
2761+
const std::string &PCMFile,
2762+
LinkContext &Context,
2763+
CompileUnitHandlerTy OnCUDieLoaded,
2764+
CASLoaderTy CASLoader, unsigned Indent) {
27612765

27622766
uint64_t DwoId = getDwoId(CUDie);
27632767
std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
27642768

2765-
/// Using a SmallString<0> because loadClangModule() is recursive.
2766-
SmallString<0> Path(Options.PrependPath);
2767-
if (sys::path::is_relative(PCMFile))
2768-
resolveRelativeObjectPath(Path, CUDie);
2769-
sys::path::append(Path, PCMFile);
2770-
// Don't use the cached binary holder because we have no thread-safety
2771-
// guarantee and the lifetime is limited.
2772-
2773-
if (Loader == nullptr) {
2774-
reportError("Could not load clang module: loader is not specified.\n",
2775-
Context.File);
2776-
return Error::success();
2777-
}
2769+
DWARFFile *PCM = nullptr;
2770+
if (CASLoader) {
2771+
auto LoadPCM = CASLoader(PCMFile, Context.File.FileName);
2772+
if (!LoadPCM)
2773+
return LoadPCM.takeError();
2774+
PCM = *LoadPCM;
2775+
}
2776+
2777+
if (!PCM) {
2778+
/// Using a SmallString<0> because loadClangModule() is recursive.
2779+
SmallString<0> Path(Options.PrependPath);
2780+
if (sys::path::is_relative(PCMFile))
2781+
resolveRelativeObjectPath(Path, CUDie);
2782+
sys::path::append(Path, PCMFile);
2783+
// Don't use the cached binary holder because we have no thread-safety
2784+
// guarantee and the lifetime is limited.
2785+
2786+
if (Loader == nullptr) {
2787+
reportError("Could not load clang module: loader is not specified.\n",
2788+
Context.File);
2789+
return Error::success();
2790+
}
27782791

2779-
auto ErrOrObj = Loader(Context.File.FileName, Path);
2780-
if (!ErrOrObj)
2781-
return Error::success();
2792+
auto ErrOrObj = Loader(Context.File.FileName, Path);
2793+
if (!ErrOrObj)
2794+
return Error::success();
2795+
2796+
PCM = &*ErrOrObj;
2797+
}
27822798

27832799
std::unique_ptr<CompileUnit> Unit;
2784-
for (const auto &CU : ErrOrObj->Dwarf->compile_units()) {
2800+
for (const auto &CU : PCM->Dwarf->compile_units()) {
27852801
OnCUDieLoaded(*CU);
27862802
// Recursively get all modules imported by this one.
27872803
auto ChildCUDie = CU->getUnitDIE();
27882804
if (!ChildCUDie)
27892805
continue;
27902806
if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2791-
Indent)) {
2807+
CASLoader, Indent)) {
27922808
if (Unit) {
27932809
std::string Err =
27942810
(PCMFile +
@@ -2818,7 +2834,7 @@ Error DWARFLinker::loadClangModule(
28182834
}
28192835

28202836
if (Unit)
2821-
Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2837+
Context.ModuleUnits.emplace_back(RefModuleUnit{*PCM, std::move(Unit)});
28222838

28232839
return Error::success();
28242840
}
@@ -2925,7 +2941,8 @@ void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {
29252941
}
29262942

29272943
void DWARFLinker::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
2928-
CompileUnitHandlerTy OnCUDieLoaded) {
2944+
CompileUnitHandlerTy OnCUDieLoaded,
2945+
CASLoaderTy CASLoader) {
29292946
ObjectContexts.emplace_back(LinkContext(File));
29302947

29312948
if (ObjectContexts.back().File.Dwarf) {
@@ -2940,7 +2957,7 @@ void DWARFLinker::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
29402957

29412958
if (!LLVM_UNLIKELY(Options.Update))
29422959
registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2943-
OnCUDieLoaded);
2960+
OnCUDieLoaded, CASLoader);
29442961
}
29452962
}
29462963
}

0 commit comments

Comments
 (0)