Skip to content

Commit 609c782

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 609c782

File tree

7 files changed

+181
-7
lines changed

7 files changed

+181
-7
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/tools/dsymutil/BinaryHolder.cpp

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "BinaryHolder.h"
15+
#include "llvm/CAS/CASConfiguration.h"
1516
#include "llvm/Object/MachO.h"
1617
#include "llvm/Support/WithColor.h"
1718
#include "llvm/Support/raw_ostream.h"
@@ -42,8 +43,9 @@ getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
4243
}
4344

4445
BinaryHolder::BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
45-
BinaryHolder::Options Opts)
46-
: VFS(VFS), Opts(Opts) {}
46+
BinaryHolder::Options Opts,
47+
std::shared_ptr<cas::ObjectStore> CAS)
48+
: VFS(VFS), CAS(std::move(CAS)), Opts(Opts) {}
4749

4850
Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
4951
StringRef Filename,
@@ -144,6 +146,40 @@ Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
144146
return Error::success();
145147
}
146148

149+
bool BinaryHolder::ObjectEntry::load(cas::ObjectStore &CAS,
150+
StringRef PossibleID, Options Opts) {
151+
auto ID = CAS.parseID(PossibleID);
152+
if (!ID) {
153+
// This maybe not a CASID since we always try to load from CAS first. Ignore
154+
// any error happening when parsing the CASID.
155+
consumeError(ID.takeError());
156+
return false;
157+
}
158+
159+
if (Opts.Verbose)
160+
WithColor::note() << "resolving cas object " << PossibleID << "\n";
161+
162+
auto Ref = CAS.getProxy(*ID);
163+
if (!Ref) {
164+
WithColor::warning() << "failed to load CAS object: "
165+
<< toString(Ref.takeError()) << "\n";
166+
return false;
167+
}
168+
169+
// Only module files should be loaded here. Always not fat.
170+
auto ObjectBuf = Ref->getMemoryBuffer();
171+
auto ErrOrObjectFile =
172+
object::ObjectFile::createObjectFile(ObjectBuf->getMemBufferRef());
173+
if (!ErrOrObjectFile) {
174+
WithColor::warning() << "malformed object loaded via " << PossibleID
175+
<< "\n";
176+
return false;
177+
}
178+
179+
Objects.push_back(std::move(*ErrOrObjectFile));
180+
return true;
181+
}
182+
147183
std::vector<const object::ObjectFile *>
148184
BinaryHolder::ObjectEntry::getObjects() const {
149185
std::vector<const object::ObjectFile *> Result;
@@ -231,6 +267,21 @@ BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename,
231267
return *(MemberCache[Key] = std::move(OE));
232268
}
233269

270+
static Expected<std::shared_ptr<cas::ObjectStore>>
271+
searchAndCreateCAS(StringRef Path) {
272+
auto Config = cas::CASConfiguration::createFromSearchConfigFile(Path);
273+
if (!Config)
274+
return nullptr;
275+
276+
auto DB = Config->second.createDatabases();
277+
if (!DB)
278+
return DB.takeError();
279+
280+
WithColor::note() << "create CAS using configuration: " << Config->first
281+
<< "'\n";
282+
return DB->first;
283+
}
284+
234285
Expected<const BinaryHolder::ObjectEntry &>
235286
BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
236287
if (Opts.Verbose)
@@ -265,9 +316,18 @@ BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
265316
ObjectRefCounter[Filename]++;
266317
if (!ObjectCache.count(Filename)) {
267318
auto OE = std::make_unique<ObjectEntry>();
268-
auto Err = OE->load(VFS, Filename, Timestamp, Opts);
269-
if (Err)
270-
return std::move(Err);
319+
if (!CAS) {
320+
auto MaybeCAS = searchAndCreateCAS(Filename);
321+
if (!MaybeCAS)
322+
return MaybeCAS.takeError();
323+
CAS = std::move(*MaybeCAS);
324+
}
325+
326+
if (!(CAS && OE->load(*CAS, Filename, Opts))) {
327+
auto Err = OE->load(VFS, Filename, Timestamp, Opts);
328+
if (Err)
329+
return std::move(Err);
330+
}
271331
ObjectCache[Filename] = std::move(OE);
272332
}
273333

llvm/tools/dsymutil/BinaryHolder.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "llvm/ADT/DenseMap.h"
1717
#include "llvm/ADT/StringMap.h"
18+
#include "llvm/CAS/ObjectStore.h"
1819
#include "llvm/Object/Archive.h"
1920
#include "llvm/Object/Error.h"
2021
#include "llvm/Object/MachOUniversal.h"
@@ -46,7 +47,8 @@ class BinaryHolder {
4647
};
4748

4849
BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
49-
BinaryHolder::Options Opts = {});
50+
BinaryHolder::Options Opts = {},
51+
std::shared_ptr<cas::ObjectStore> CAS = nullptr);
5052

5153
// Forward declarations for friend declaration.
5254
class ObjectEntry;
@@ -67,6 +69,9 @@ class BinaryHolder {
6769
Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
6870
TimestampTy Timestamp, BinaryHolder::Options = {});
6971

72+
bool load(cas::ObjectStore &CAS, StringRef Filename,
73+
BinaryHolder::Options = {});
74+
7075
/// Access all owned ObjectFiles.
7176
std::vector<const object::ObjectFile *> getObjects() const;
7277

@@ -150,6 +155,8 @@ class BinaryHolder {
150155
/// Virtual File System instance.
151156
IntrusiveRefCntPtr<vfs::FileSystem> VFS;
152157

158+
std::shared_ptr<cas::ObjectStore> CAS;
159+
153160
Options Opts;
154161
};
155162

llvm/tools/dsymutil/Options.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,16 @@ def dsym_search_path: Separate<["-", "--"], "D">,
218218
MetaVarName<"<path>">,
219219
HelpText<"Specify a directory that contain dSYM files to search for.">,
220220
Group<grp_general>;
221+
222+
def cas : Separate<["-", "--"], "cas">,
223+
MetaVarName<"<path>">,
224+
HelpText<"Specify CAS directory to load CAS references from.">,
225+
Group<grp_general>;
226+
def cas_plugin_path : Separate<["-", "--"], "cas-plugin-path">,
227+
MetaVarName<"<path>">,
228+
HelpText<"Path to CAS plugin library if used">,
229+
Group<grp_general>;
230+
def cas_plugin_option : Separate<["-", "--"], "cas-plugin-option">,
231+
MetaVarName<"<Option>=<Value>">,
232+
HelpText<"Plugin CAS options">,
233+
Group<grp_general>;

llvm/tools/dsymutil/dsymutil.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include "llvm/ADT/SmallVector.h"
2424
#include "llvm/ADT/StringExtras.h"
2525
#include "llvm/ADT/StringRef.h"
26+
#include "llvm/CAS/ActionCache.h"
27+
#include "llvm/CAS/CASConfiguration.h"
28+
#include "llvm/CAS/ObjectStore.h"
2629
#include "llvm/DebugInfo/DIContext.h"
2730
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
2831
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
@@ -120,6 +123,7 @@ struct DsymutilOptions {
120123
DWARFVerify Verify = DWARFVerify::Default;
121124
ReproducerMode ReproMode = ReproducerMode::GenerateOnCrash;
122125
dsymutil::LinkOptions LinkOpts;
126+
cas::CASConfiguration CASOptions;
123127
};
124128

125129
/// Return a list of input files. This function has logic for dealing with the
@@ -397,6 +401,17 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
397401
for (auto *SearchPath : Args.filtered(OPT_dsym_search_path))
398402
Options.LinkOpts.DSYMSearchPaths.push_back(SearchPath->getValue());
399403

404+
if (opt::Arg *CASPath = Args.getLastArg(OPT_cas))
405+
Options.CASOptions.CASPath = CASPath->getValue();
406+
407+
if (opt::Arg *CASPluginPath = Args.getLastArg(OPT_cas_plugin_path))
408+
Options.CASOptions.PluginPath = CASPluginPath->getValue();
409+
410+
for (auto CASPluginOpt : Args.getAllArgValues(OPT_cas_plugin_option)) {
411+
auto [Name, Val] = StringRef(CASPluginOpt).split('=');
412+
Options.CASOptions.PluginOptions.emplace_back(Name, Val);
413+
}
414+
400415
if (Error E = verifyOptions(Options))
401416
return std::move(E);
402417
return Options;
@@ -666,12 +681,24 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
666681
return EXIT_FAILURE;
667682
}
668683

684+
// Create CAS. Only support unified database for now.
685+
std::shared_ptr<llvm::cas::ObjectStore> CAS;
686+
if (!Options.CASOptions.CASPath.empty()) {
687+
auto DB = Options.CASOptions.createDatabases();
688+
if (!DB) {
689+
WithColor::error() << "failed to open CAS: " << toString(DB.takeError())
690+
<< "\n";
691+
return EXIT_FAILURE;
692+
}
693+
CAS = std::move(DB->first);
694+
}
695+
669696
for (auto &InputFile : Options.InputFiles) {
670697
// Shared a single binary holder for all the link steps.
671698
BinaryHolder::Options BinOpts;
672699
BinOpts.Verbose = Options.LinkOpts.Verbose;
673700
BinOpts.Warn = !Options.NoObjectTimestamp;
674-
BinaryHolder BinHolder(Options.LinkOpts.VFS, BinOpts);
701+
BinaryHolder BinHolder(Options.LinkOpts.VFS, BinOpts, CAS);
675702

676703
// Dump the symbol table for each input file and requested arch
677704
if (Options.DumpStab) {

0 commit comments

Comments
 (0)