Debugger: Refactor non-interactive report handling.

- Add dedicated ReportDebugger application class for the case where we're
  asked to do nothing more than save a report. Also add a corresponding
  UserInterface subclass whose sole purpose is to take those necessary
  actions and then exit.
- When the debugger is invoked via the --save-report option, we now start
  via the aforementioned report/interface rather than piggybacking on the
  CLI.
- Clean up CommandLineUserInterface/CliContext to remove handling for the
  report saving option.

Should hopefully resolve #12155.
This commit is contained in:
Rene Gollent
2015-08-22 00:21:07 -04:00
parent 3667f6efdb
commit 2d9d01e2e8
8 changed files with 416 additions and 114 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014, Rene Gollent, [email protected].
* Copyright 2011-2015, Rene Gollent, [email protected].
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -93,13 +93,9 @@ private:
// #pragma mark - CommandLineUserInterface
CommandLineUserInterface::CommandLineUserInterface(bool saveReport,
const char* reportPath, thread_id reportTargetThread)
CommandLineUserInterface::CommandLineUserInterface()
:
fCommands(20, true),
fReportPath(reportPath),
fSaveReport(saveReport),
fReportTargetThread(reportTargetThread),
fShowSemaphore(-1),
fShown(false),
fTerminating(false)
@@ -128,8 +124,6 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
if (error != B_OK)
return error;
fContext.SetInteractive(!fSaveReport);
error = _RegisterCommands();
if (error != B_OK)
return error;
@@ -138,8 +132,6 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
if (fShowSemaphore < 0)
return fShowSemaphore;
team->AddListener(this);
return B_OK;
}
@@ -176,9 +168,7 @@ CommandLineUserInterface::Terminate()
bool
CommandLineUserInterface::IsInteractive() const
{
// if we were invoked solely for the purpose of saving a crash report,
// then we're not taking user input into account.
return !fSaveReport;
return true;
}
@@ -237,43 +227,12 @@ CommandLineUserInterface::Run()
if (error != B_OK)
return;
if (fSaveReport) {
ArgumentVector args;
char buffer[256];
const char* parseErrorLocation;
if (_ReportTargetThreadStopNeeded()) {
snprintf(buffer, sizeof(buffer), "stop %" B_PRId32,
fReportTargetThread);
args.Parse(buffer, &parseErrorLocation);
_ExecuteCommand(args.ArgumentCount(), args.Arguments());
} else
_SubmitSaveReport();
}
_InputLoop();
// Release the Show() semaphore to signal Terminate().
release_sem(fShowSemaphore);
}
void
CommandLineUserInterface::ThreadStateChanged(const Team::ThreadEvent& event)
{
if (fSaveReport) {
Thread* thread = event.GetThread();
// If we were asked to attach/report on a specific thread
// rather than a team, and said thread was still
// running, when we attached, we need to wait for its corresponding
// stop state before generating a report, else we might not get its
// stack trace.
if (thread->ID() == fReportTargetThread
&& thread->State() == THREAD_STATE_STOPPED) {
_SubmitSaveReport();
}
}
}
/*static*/ status_t
CommandLineUserInterface::_InputLoopEntry(void* data)
{
@@ -473,32 +432,3 @@ CommandLineUserInterface::_CompareCommandEntries(const CommandEntry* command1,
{
return ::Compare(command1->Name(), command2->Name());
}
bool
CommandLineUserInterface::_ReportTargetThreadStopNeeded() const
{
if (fReportTargetThread < 0)
return false;
Team* team = fContext.GetTeam();
AutoLocker<Team> teamLocker(team);
Thread* thread = team->ThreadByID(fReportTargetThread);
if (thread == NULL)
return false;
return thread->State() != THREAD_STATE_STOPPED;
}
void
CommandLineUserInterface::_SubmitSaveReport()
{
ArgumentVector args;
char buffer[256];
const char* parseErrorLocation;
snprintf(buffer, sizeof(buffer), "save-report %s",
fReportPath != NULL ? fReportPath : "");
args.Parse(buffer, &parseErrorLocation);
_ExecuteCommand(args.ArgumentCount(), args.Arguments());
}