Skip to content

Commit 64ed801

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 d0a3e68 commit 64ed801

File tree

6 files changed

+150
-7
lines changed

6 files changed

+150
-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: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
// RUN: %clang @%t/Right.rsp
3636
// RUN: %clang @%t/tu.rsp
3737

38+
/// Check debug info is correct.
39+
// RUN: %clang %t/tu.o -o %t/a.out
40+
// RUN: dsymutil -cas %t/cas %t/a.out -o %t/a.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
41+
// RUN: dsymutil %t/a.out -o %t/a2.dSYM 2>&1 | FileCheck %s --check-prefix=WARN --allow-empty
42+
// WARN-NOT: warning:
43+
44+
// RUN: llvm-dwarfdump --debug-info %t/a.dSYM | FileCheck %s --check-prefix=DWARF
45+
3846
/// Check module in a different directory and compare output.
3947
// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json \
4048
// RUN: -cas-path %t/cas -module-files-dir %t/outputs-2 \
@@ -59,6 +67,39 @@
5967
// RUN: diff %t/prefix.h.pch %t/prefix_2.pch
6068
// RUN: diff %t/tu.o %t/tu_2.o
6169

70+
// Check all the types are available
71+
// DWARF: DW_TAG_compile_unit
72+
// DWARF: DW_TAG_module
73+
// DWARF-NEXT: DW_AT_name ("Top")
74+
// DWARF: DW_TAG_structure_type
75+
// DWARF-NEXT: DW_AT_name ("Top")
76+
// DWARF: DW_TAG_compile_unit
77+
// DWARF: DW_TAG_module
78+
// DWARF-NEXT: DW_AT_name ("Left")
79+
// DWARF: DW_TAG_structure_type
80+
// DWARF-NEXT: DW_AT_name ("Left")
81+
// DWARF: DW_TAG_member
82+
// DWARF-NEXT: DW_AT_name ("top")
83+
// DWARF-NEXT: DW_AT_type
84+
// DWARF-SAME: "Top::Top"
85+
// DWARF: DW_TAG_compile_unit
86+
// DWARF: DW_TAG_module
87+
// DWARF-NEXT: DW_AT_name ("Right")
88+
// DWARF: DW_TAG_structure_type
89+
// DWARF-NEXT: DW_AT_name ("Right")
90+
// DWARF: DW_TAG_member
91+
// DWARF-NEXT: DW_AT_name ("top")
92+
// DWARF-NEXT: DW_AT_type
93+
// DWARF-SAME: "Top::Top"
94+
// DWARF: DW_TAG_compile_unit
95+
// DWARF: DW_TAG_module
96+
// DWARF: DW_TAG_structure_type
97+
// DWARF-NEXT: DW_AT_name ("Prefix")
98+
// DWARF: DW_TAG_member
99+
// DWARF-NEXT: DW_AT_name ("top")
100+
// DWARF-NEXT: DW_AT_type
101+
// DWARF-SAME: "Top::Top"
102+
62103

63104
// CHECK: {
64105
// CHECK-NEXT: "modules": [

llvm/tools/dsymutil/BinaryHolder.cpp

Lines changed: 59 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,37 @@ 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+
consumeError(ID.takeError());
154+
return false;
155+
}
156+
157+
if (Opts.Verbose)
158+
WithColor::note() << "try load cas object " << PossibleID << "\n";
159+
160+
auto Ref = CAS.getProxy(*ID);
161+
if (!Ref) {
162+
WithColor::warning() << "failed to load CAS object " << PossibleID << "\n";
163+
return false;
164+
}
165+
166+
// Only module files should be loaded here. Always not fat.
167+
auto ObjectBuf = Ref->getMemoryBuffer();
168+
auto ErrOrObjectFile =
169+
object::ObjectFile::createObjectFile(ObjectBuf->getMemBufferRef());
170+
if (!ErrOrObjectFile) {
171+
WithColor::warning() << "malformed object loaded via " << PossibleID
172+
<< "\n";
173+
return false;
174+
}
175+
176+
Objects.push_back(std::move(*ErrOrObjectFile));
177+
return true;
178+
}
179+
147180
std::vector<const object::ObjectFile *>
148181
BinaryHolder::ObjectEntry::getObjects() const {
149182
std::vector<const object::ObjectFile *> Result;
@@ -231,6 +264,22 @@ BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename,
231264
return *(MemberCache[Key] = std::move(OE));
232265
}
233266

267+
static std::shared_ptr<cas::ObjectStore> searchAndCreateCAS(StringRef Path) {
268+
auto Config = cas::CASConfiguration::createFromSearchConfigFile(Path);
269+
if (!Config)
270+
return nullptr;
271+
272+
auto DB = Config->second.createDatabases();
273+
if (!DB) {
274+
consumeError(DB.takeError());
275+
return nullptr;
276+
}
277+
278+
WithColor::note() << "create CAS using configuration: " << Config->first
279+
<< "'\n";
280+
return DB->first;
281+
}
282+
234283
Expected<const BinaryHolder::ObjectEntry &>
235284
BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
236285
if (Opts.Verbose)
@@ -265,9 +314,14 @@ BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
265314
ObjectRefCounter[Filename]++;
266315
if (!ObjectCache.count(Filename)) {
267316
auto OE = std::make_unique<ObjectEntry>();
268-
auto Err = OE->load(VFS, Filename, Timestamp, Opts);
269-
if (Err)
270-
return std::move(Err);
317+
if (!CAS)
318+
CAS = searchAndCreateCAS(Filename);
319+
320+
if (!(CAS && OE->load(*CAS, Filename, Opts))) {
321+
auto Err = OE->load(VFS, Filename, Timestamp, Opts);
322+
if (Err)
323+
return std::move(Err);
324+
}
271325
ObjectCache[Filename] = std::move(OE);
272326
}
273327

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)