@@ -116,6 +116,9 @@ static constexpr OptionEnumValues ReproducerSignalType() {
116116#define LLDB_OPTIONS_reproducer_xcrash
117117#include " CommandOptions.inc"
118118
119+ #define LLDB_OPTIONS_reproducer_verify
120+ #include " CommandOptions.inc"
121+
119122template <typename T>
120123llvm::Expected<T> static ReadFromYAML (StringRef filename) {
121124 auto error_or_file = MemoryBuffer::getFile (filename);
@@ -134,6 +137,38 @@ llvm::Expected<T> static ReadFromYAML(StringRef filename) {
134137 return t;
135138}
136139
140+ static void SetError (CommandReturnObject &result, Error err) {
141+ result.GetErrorStream ().Printf (" error: %s\n " ,
142+ toString (std::move (err)).c_str ());
143+ result.SetStatus (eReturnStatusFailed);
144+ }
145+
146+ // / Create a loader from the given path if specified. Otherwise use the current
147+ // / loader used for replay.
148+ static Loader *
149+ GetLoaderFromPathOrCurrent (llvm::Optional<Loader> &loader_storage,
150+ CommandReturnObject &result,
151+ FileSpec reproducer_path) {
152+ if (reproducer_path) {
153+ loader_storage.emplace (reproducer_path);
154+ Loader *loader = &(*loader_storage);
155+ if (Error err = loader->LoadIndex ()) {
156+ // This is a hard error and will set the result to eReturnStatusFailed.
157+ SetError (result, std::move (err));
158+ return nullptr ;
159+ }
160+ return loader;
161+ }
162+
163+ if (Loader *loader = Reproducer::Instance ().GetLoader ())
164+ return loader;
165+
166+ // This is a soft error because this is expected to fail during capture.
167+ result.SetError (" Not specifying a reproducer is only support during replay." );
168+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
169+ return nullptr ;
170+ }
171+
137172class CommandObjectReproducerGenerate : public CommandObjectParsed {
138173public:
139174 CommandObjectReproducerGenerate (CommandInterpreter &interpreter)
@@ -312,12 +347,6 @@ class CommandObjectReproducerStatus : public CommandObjectParsed {
312347 }
313348};
314349
315- static void SetError (CommandReturnObject &result, Error err) {
316- result.GetErrorStream ().Printf (" error: %s\n " ,
317- toString (std::move (err)).c_str ());
318- result.SetStatus (eReturnStatusFailed);
319- }
320-
321350class CommandObjectReproducerDump : public CommandObjectParsed {
322351public:
323352 CommandObjectReproducerDump (CommandInterpreter &interpreter)
@@ -382,29 +411,11 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
382411 return false ;
383412 }
384413
385- // If no reproducer path is specified, use the loader currently used for
386- // replay. Otherwise create a new loader just for dumping.
387414 llvm::Optional<Loader> loader_storage;
388- Loader *loader = nullptr ;
389- if (!m_options.file ) {
390- loader = Reproducer::Instance ().GetLoader ();
391- if (loader == nullptr ) {
392- result.SetError (
393- " Not specifying a reproducer is only support during replay." );
394- result.SetStatus (eReturnStatusSuccessFinishNoResult);
395- return false ;
396- }
397- } else {
398- loader_storage.emplace (m_options.file );
399- loader = &(*loader_storage);
400- if (Error err = loader->LoadIndex ()) {
401- SetError (result, std::move (err));
402- return false ;
403- }
404- }
405-
406- // If we get here we should have a valid loader.
407- assert (loader);
415+ Loader *loader =
416+ GetLoaderFromPathOrCurrent (loader_storage, result, m_options.file );
417+ if (!loader)
418+ return false ;
408419
409420 switch (m_options.provider ) {
410421 case eReproducerProviderFiles: {
@@ -583,6 +594,101 @@ class CommandObjectReproducerDump : public CommandObjectParsed {
583594 CommandOptions m_options;
584595};
585596
597+ class CommandObjectReproducerVerify : public CommandObjectParsed {
598+ public:
599+ CommandObjectReproducerVerify (CommandInterpreter &interpreter)
600+ : CommandObjectParsed(interpreter, " reproducer verify" ,
601+ " Verify the contents of a reproducer. "
602+ " If no reproducer is specified during replay, it "
603+ " verifies the content of the current reproducer." ,
604+ nullptr ) {}
605+
606+ ~CommandObjectReproducerVerify () override = default ;
607+
608+ Options *GetOptions () override { return &m_options; }
609+
610+ class CommandOptions : public Options {
611+ public:
612+ CommandOptions () : Options(), file() {}
613+
614+ ~CommandOptions () override = default ;
615+
616+ Status SetOptionValue (uint32_t option_idx, StringRef option_arg,
617+ ExecutionContext *execution_context) override {
618+ Status error;
619+ const int short_option = m_getopt_table[option_idx].val ;
620+
621+ switch (short_option) {
622+ case ' f' :
623+ file.SetFile (option_arg, FileSpec::Style::native);
624+ FileSystem::Instance ().Resolve (file);
625+ break ;
626+ default :
627+ llvm_unreachable (" Unimplemented option" );
628+ }
629+
630+ return error;
631+ }
632+
633+ void OptionParsingStarting (ExecutionContext *execution_context) override {
634+ file.Clear ();
635+ }
636+
637+ ArrayRef<OptionDefinition> GetDefinitions () override {
638+ return makeArrayRef (g_reproducer_verify_options);
639+ }
640+
641+ FileSpec file;
642+ };
643+
644+ protected:
645+ bool DoExecute (Args &command, CommandReturnObject &result) override {
646+ if (!command.empty ()) {
647+ result.AppendErrorWithFormat (" '%s' takes no arguments" ,
648+ m_cmd_name.c_str ());
649+ return false ;
650+ }
651+
652+ llvm::Optional<Loader> loader_storage;
653+ Loader *loader =
654+ GetLoaderFromPathOrCurrent (loader_storage, result, m_options.file );
655+ if (!loader)
656+ return false ;
657+
658+ bool errors = false ;
659+ auto error_callback = [&](llvm::StringRef error) {
660+ errors = true ;
661+ result.AppendError (error);
662+ };
663+
664+ bool warnings = false ;
665+ auto warning_callback = [&](llvm::StringRef warning) {
666+ warnings = true ;
667+ result.AppendWarning (warning);
668+ };
669+
670+ auto note_callback = [&](llvm::StringRef warning) {
671+ result.AppendMessage (warning);
672+ };
673+
674+ Verifier verifier (loader);
675+ verifier.Verify (error_callback, warning_callback, note_callback);
676+
677+ if (warnings || errors) {
678+ result.AppendMessage (" reproducer verification failed" );
679+ result.SetStatus (eReturnStatusFailed);
680+ } else {
681+ result.AppendMessage (" reproducer verification succeeded" );
682+ result.SetStatus (eReturnStatusSuccessFinishResult);
683+ }
684+
685+ return result.Succeeded ();
686+ }
687+
688+ private:
689+ CommandOptions m_options;
690+ };
691+
586692CommandObjectReproducer::CommandObjectReproducer (
587693 CommandInterpreter &interpreter)
588694 : CommandObjectMultiword(
@@ -605,6 +711,8 @@ CommandObjectReproducer::CommandObjectReproducer(
605711 new CommandObjectReproducerStatus (interpreter)));
606712 LoadSubCommand (" dump" ,
607713 CommandObjectSP (new CommandObjectReproducerDump (interpreter)));
714+ LoadSubCommand (" verify" , CommandObjectSP (
715+ new CommandObjectReproducerVerify (interpreter)));
608716 LoadSubCommand (" xcrash" , CommandObjectSP (
609717 new CommandObjectReproducerXCrash (interpreter)));
610718}
0 commit comments