88
99#include " CommandObjectReproducer.h"
1010
11+ #include " lldb/Host/OptionParser.h"
1112#include " lldb/Utility/Reproducer.h"
1213
1314#include " lldb/Interpreter/CommandInterpreter.h"
1617#include " lldb/Interpreter/OptionGroupBoolean.h"
1718
1819using namespace lldb ;
20+ using namespace llvm ;
1921using namespace lldb_private ;
22+ using namespace lldb_private ::repro;
23+
24+ enum ReproducerProvider {
25+ eReproducerProviderCommands,
26+ eReproducerProviderFiles,
27+ eReproducerProviderGDB,
28+ eReproducerProviderVersion,
29+ eReproducerProviderNone
30+ };
31+
32+ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
33+ {
34+ eReproducerProviderCommands,
35+ " commands" ,
36+ " Command Interpreter Commands" ,
37+ },
38+ {
39+ eReproducerProviderFiles,
40+ " files" ,
41+ " Files" ,
42+ },
43+ {
44+ eReproducerProviderGDB,
45+ " gdb" ,
46+ " GDB Remote Packets" ,
47+ },
48+ {
49+ eReproducerProviderVersion,
50+ " version" ,
51+ " Version" ,
52+ },
53+ {
54+ eReproducerProviderNone,
55+ " none" ,
56+ " None" ,
57+ },
58+ };
59+
60+ static constexpr OptionEnumValues ReproducerProviderType () {
61+ return OptionEnumValues (g_reproducer_provider_type);
62+ }
63+
64+ #define LLDB_OPTIONS_reproducer
65+ #include " CommandOptions.inc"
2066
2167class CommandObjectReproducerGenerate : public CommandObjectParsed {
2268public:
@@ -38,7 +84,7 @@ class CommandObjectReproducerGenerate : public CommandObjectParsed {
3884 return false ;
3985 }
4086
41- auto &r = repro:: Reproducer::Instance ();
87+ auto &r = Reproducer::Instance ();
4288 if (auto generator = r.GetGenerator ()) {
4389 generator->Keep ();
4490 } else if (r.GetLoader ()) {
@@ -84,7 +130,7 @@ class CommandObjectReproducerStatus : public CommandObjectParsed {
84130 return false ;
85131 }
86132
87- auto &r = repro:: Reproducer::Instance ();
133+ auto &r = Reproducer::Instance ();
88134 if (r.GetGenerator ()) {
89135 result.GetOutputStream () << " Reproducer is in capture mode.\n " ;
90136 } else if (r.GetLoader ()) {
@@ -98,6 +144,191 @@ class CommandObjectReproducerStatus : public CommandObjectParsed {
98144 }
99145};
100146
147+ static void SetError (CommandReturnObject &result, Error err) {
148+ result.GetErrorStream ().Printf (" error: %s\n " ,
149+ toString (std::move (err)).c_str ());
150+ result.SetStatus (eReturnStatusFailed);
151+ }
152+
153+ class CommandObjectReproducerDump : public CommandObjectParsed {
154+ public:
155+ CommandObjectReproducerDump (CommandInterpreter &interpreter)
156+ : CommandObjectParsed(interpreter, " reproducer dump" ,
157+ " Dump the information contained in a reproducer." ,
158+ nullptr ) {}
159+
160+ ~CommandObjectReproducerDump () override = default ;
161+
162+ Options *GetOptions () override { return &m_options; }
163+
164+ class CommandOptions : public Options {
165+ public:
166+ CommandOptions () : Options(), file() {}
167+
168+ ~CommandOptions () override = default ;
169+
170+ Status SetOptionValue (uint32_t option_idx, StringRef option_arg,
171+ ExecutionContext *execution_context) override {
172+ Status error;
173+ const int short_option = m_getopt_table[option_idx].val ;
174+
175+ switch (short_option) {
176+ case ' f' :
177+ file.SetFile (option_arg, FileSpec::Style::native);
178+ FileSystem::Instance ().Resolve (file);
179+ break ;
180+ case ' p' :
181+ provider = (ReproducerProvider)OptionArgParser::ToOptionEnum (
182+ option_arg, GetDefinitions ()[option_idx].enum_values , 0 , error);
183+ if (!error.Success ())
184+ error.SetErrorStringWithFormat (" unrecognized value for provider '%s'" ,
185+ option_arg.str ().c_str ());
186+ break ;
187+ default :
188+ llvm_unreachable (" Unimplemented option" );
189+ }
190+
191+ return error;
192+ }
193+
194+ void OptionParsingStarting (ExecutionContext *execution_context) override {
195+ file.Clear ();
196+ provider = eReproducerProviderNone;
197+ }
198+
199+ ArrayRef<OptionDefinition> GetDefinitions () override {
200+ return makeArrayRef (g_reproducer_options);
201+ }
202+
203+ FileSpec file;
204+ ReproducerProvider provider = eReproducerProviderNone;
205+ };
206+
207+ protected:
208+ bool DoExecute (Args &command, CommandReturnObject &result) override {
209+ if (!command.empty ()) {
210+ result.AppendErrorWithFormat (" '%s' takes no arguments" ,
211+ m_cmd_name.c_str ());
212+ return false ;
213+ }
214+
215+ // If no reproducer path is specified, use the loader currently used for
216+ // replay. Otherwise create a new loader just for dumping.
217+ llvm::Optional<Loader> loader_storage;
218+ Loader *loader = nullptr ;
219+ if (!m_options.file ) {
220+ loader = Reproducer::Instance ().GetLoader ();
221+ if (loader == nullptr ) {
222+ result.SetError (
223+ " Not specifying a reproducer is only support during replay." );
224+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
225+ return false ;
226+ }
227+ } else {
228+ loader_storage.emplace (m_options.file );
229+ loader = &(*loader_storage);
230+ if (Error err = loader->LoadIndex ()) {
231+ SetError (result, std::move (err));
232+ return false ;
233+ }
234+ }
235+
236+ // If we get here we should have a valid loader.
237+ assert (loader);
238+
239+ switch (m_options.provider ) {
240+ case eReproducerProviderFiles: {
241+ FileSpec vfs_mapping = loader->GetFile <FileProvider::Info>();
242+
243+ // Read the VFS mapping.
244+ ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
245+ vfs::getRealFileSystem ()->getBufferForFile (vfs_mapping.GetPath ());
246+ if (!buffer) {
247+ SetError (result, errorCodeToError (buffer.getError ()));
248+ return false ;
249+ }
250+
251+ // Initialize a VFS from the given mapping.
252+ IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML (
253+ std::move (buffer.get ()), nullptr , vfs_mapping.GetPath ());
254+
255+ // Dump the VFS to a buffer.
256+ std::string str;
257+ raw_string_ostream os (str);
258+ static_cast <vfs::RedirectingFileSystem &>(*vfs).dump (os);
259+ os.flush ();
260+
261+ // Return the string.
262+ result.AppendMessage (str);
263+ result.SetStatus (eReturnStatusSuccessFinishResult);
264+ return true ;
265+ }
266+ case eReproducerProviderVersion: {
267+ FileSpec version_file = loader->GetFile <VersionProvider::Info>();
268+
269+ // Load the version info into a buffer.
270+ ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
271+ vfs::getRealFileSystem ()->getBufferForFile (version_file.GetPath ());
272+ if (!buffer) {
273+ SetError (result, errorCodeToError (buffer.getError ()));
274+ return false ;
275+ }
276+
277+ // Return the version string.
278+ StringRef version = (*buffer)->getBuffer ();
279+ result.AppendMessage (version.str ());
280+ result.SetStatus (eReturnStatusSuccessFinishResult);
281+ return true ;
282+ }
283+ case eReproducerProviderCommands: {
284+ // Create a new command loader.
285+ std::unique_ptr<repro::CommandLoader> command_loader =
286+ repro::CommandLoader::Create (loader);
287+ if (!command_loader) {
288+ SetError (result,
289+ make_error<StringError>(llvm::inconvertibleErrorCode (),
290+ " Unable to create command loader." ));
291+ return false ;
292+ }
293+
294+ // Iterate over the command files and dump them.
295+ while (true ) {
296+ llvm::Optional<std::string> command_file =
297+ command_loader->GetNextFile ();
298+ if (!command_file)
299+ break ;
300+
301+ auto command_buffer = llvm::MemoryBuffer::getFile (*command_file);
302+ if (auto err = command_buffer.getError ()) {
303+ SetError (result, errorCodeToError (err));
304+ return false ;
305+ }
306+ result.AppendMessage ((*command_buffer)->getBuffer ());
307+ }
308+
309+ result.SetStatus (eReturnStatusSuccessFinishResult);
310+ return true ;
311+ }
312+ case eReproducerProviderGDB: {
313+ // FIXME: Dumping the GDB remote packets means moving the
314+ // (de)serialization code out of the GDB-remote plugin.
315+ result.AppendMessage (" Dumping GDB remote packets isn't implemented yet." );
316+ result.SetStatus (eReturnStatusSuccessFinishResult);
317+ return true ;
318+ }
319+ case eReproducerProviderNone:
320+ result.SetError (" No valid provider specified." );
321+ return false ;
322+ }
323+
324+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
325+ return result.Succeeded ();
326+ }
327+
328+ private:
329+ CommandOptions m_options;
330+ };
331+
101332CommandObjectReproducer::CommandObjectReproducer (
102333 CommandInterpreter &interpreter)
103334 : CommandObjectMultiword(
@@ -109,6 +340,8 @@ CommandObjectReproducer::CommandObjectReproducer(
109340 CommandObjectSP (new CommandObjectReproducerGenerate (interpreter)));
110341 LoadSubCommand (" status" , CommandObjectSP (
111342 new CommandObjectReproducerStatus (interpreter)));
343+ LoadSubCommand (" dump" ,
344+ CommandObjectSP (new CommandObjectReproducerDump (interpreter)));
112345}
113346
114347CommandObjectReproducer::~CommandObjectReproducer () = default ;
0 commit comments