Skip to content

Commit ccacb6c

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 1165168 commit ccacb6c

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
@@ -155,6 +155,7 @@ if( NOT CLANG_BUILT_STANDALONE )
155155
llvm-config
156156
FileCheck count not
157157
CASPluginTest
158+
dsymutil
158159
llc
159160
llvm-ar
160161
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
@@ -2611,6 +2611,7 @@ bool DWARFLinker::registerModuleReference(const DWARFDie &CUDie,
26112611
LinkContext &Context,
26122612
ObjFileLoaderTy Loader,
26132613
CompileUnitHandlerTy OnCUDieLoaded,
2614+
CASLoaderTy CASLoader,
26142615
unsigned Indent) {
26152616
std::string PCMFile = getPCMFile(CUDie, Options.ObjectPrefixMap);
26162617
std::pair<bool, bool> IsClangModuleRef =
@@ -2630,47 +2631,62 @@ bool DWARFLinker::registerModuleReference(const DWARFDie &CUDie,
26302631
ClangModules.insert({PCMFile, getDwoId(CUDie)});
26312632

26322633
if (Error E = loadClangModule(Loader, CUDie, PCMFile, Context, OnCUDieLoaded,
2633-
Indent + 2)) {
2634+
CASLoader, Indent + 2)) {
26342635
consumeError(std::move(E));
26352636
return false;
26362637
}
26372638
return true;
26382639
}
26392640

2640-
Error DWARFLinker::loadClangModule(
2641-
ObjFileLoaderTy Loader, const DWARFDie &CUDie, const std::string &PCMFile,
2642-
LinkContext &Context, CompileUnitHandlerTy OnCUDieLoaded, unsigned Indent) {
2641+
Error DWARFLinker::loadClangModule(ObjFileLoaderTy Loader,
2642+
const DWARFDie &CUDie,
2643+
const std::string &PCMFile,
2644+
LinkContext &Context,
2645+
CompileUnitHandlerTy OnCUDieLoaded,
2646+
CASLoaderTy CASLoader, unsigned Indent) {
26432647

26442648
uint64_t DwoId = getDwoId(CUDie);
26452649
std::string ModuleName = dwarf::toString(CUDie.find(dwarf::DW_AT_name), "");
26462650

2647-
/// Using a SmallString<0> because loadClangModule() is recursive.
2648-
SmallString<0> Path(Options.PrependPath);
2649-
if (sys::path::is_relative(PCMFile))
2650-
resolveRelativeObjectPath(Path, CUDie);
2651-
sys::path::append(Path, PCMFile);
2652-
// Don't use the cached binary holder because we have no thread-safety
2653-
// guarantee and the lifetime is limited.
2654-
2655-
if (Loader == nullptr) {
2656-
reportError("Could not load clang module: loader is not specified.\n",
2657-
Context.File);
2658-
return Error::success();
2659-
}
2651+
DWARFFile *PCM = nullptr;
2652+
if (CASLoader) {
2653+
auto LoadPCM = CASLoader(PCMFile, Context.File.FileName);
2654+
if (!LoadPCM)
2655+
return LoadPCM.takeError();
2656+
PCM = *LoadPCM;
2657+
}
2658+
2659+
if (!PCM) {
2660+
/// Using a SmallString<0> because loadClangModule() is recursive.
2661+
SmallString<0> Path(Options.PrependPath);
2662+
if (sys::path::is_relative(PCMFile))
2663+
resolveRelativeObjectPath(Path, CUDie);
2664+
sys::path::append(Path, PCMFile);
2665+
// Don't use the cached binary holder because we have no thread-safety
2666+
// guarantee and the lifetime is limited.
2667+
2668+
if (Loader == nullptr) {
2669+
reportError("Could not load clang module: loader is not specified.\n",
2670+
Context.File);
2671+
return Error::success();
2672+
}
26602673

2661-
auto ErrOrObj = Loader(Context.File.FileName, Path);
2662-
if (!ErrOrObj)
2663-
return Error::success();
2674+
auto ErrOrObj = Loader(Context.File.FileName, Path);
2675+
if (!ErrOrObj)
2676+
return Error::success();
2677+
2678+
PCM = &*ErrOrObj;
2679+
}
26642680

26652681
std::unique_ptr<CompileUnit> Unit;
2666-
for (const auto &CU : ErrOrObj->Dwarf->compile_units()) {
2682+
for (const auto &CU : PCM->Dwarf->compile_units()) {
26672683
OnCUDieLoaded(*CU);
26682684
// Recursively get all modules imported by this one.
26692685
auto ChildCUDie = CU->getUnitDIE();
26702686
if (!ChildCUDie)
26712687
continue;
26722688
if (!registerModuleReference(ChildCUDie, Context, Loader, OnCUDieLoaded,
2673-
Indent)) {
2689+
CASLoader, Indent)) {
26742690
if (Unit) {
26752691
std::string Err =
26762692
(PCMFile +
@@ -2700,7 +2716,7 @@ Error DWARFLinker::loadClangModule(
27002716
}
27012717

27022718
if (Unit)
2703-
Context.ModuleUnits.emplace_back(RefModuleUnit{*ErrOrObj, std::move(Unit)});
2719+
Context.ModuleUnits.emplace_back(RefModuleUnit{*PCM, std::move(Unit)});
27042720

27052721
return Error::success();
27062722
}
@@ -2807,7 +2823,8 @@ void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {
28072823
}
28082824

28092825
void DWARFLinker::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
2810-
CompileUnitHandlerTy OnCUDieLoaded) {
2826+
CompileUnitHandlerTy OnCUDieLoaded,
2827+
CASLoaderTy CASLoader) {
28112828
ObjectContexts.emplace_back(LinkContext(File));
28122829

28132830
if (ObjectContexts.back().File.Dwarf) {
@@ -2822,7 +2839,7 @@ void DWARFLinker::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
28222839

28232840
if (!LLVM_UNLIKELY(Options.Update))
28242841
registerModuleReference(CUDie, ObjectContexts.back(), Loader,
2825-
OnCUDieLoaded);
2842+
OnCUDieLoaded, CASLoader);
28262843
}
28272844
}
28282845
}

0 commit comments

Comments
 (0)