Debugger: Implement remainder of #12729.

UserInterfaceListener:
- Add request hook for writing a core file. Implement in TeamDebugger.

Jobs/WriteCoreFileJob:
- Add new job to actually dispatch the core file request via the debugger
  interface.

Team{::Listener}
- Add listener event + hook for notifications when a core file gets written.
  Implement in CLI.

CliContext:
- Add event flag for core file changed.

CommandLineUserInterface:
- Add 'write-core' command. This optionally takes a path to write the core to,
  otherwise one is automatically generated by, similarly to debug reports. As
  such, one can now generate cores for things like app_server and registrar
  crashes if desired, in addition to reports.
This commit is contained in:
Rene Gollent
2016-04-26 22:36:26 -04:00
parent 5c8966c740
commit e2d845a47f
16 changed files with 284 additions and 8 deletions
+2
View File
@@ -171,6 +171,7 @@ local sources =
LoadSourceCodeJob.cpp
ResolveValueNodeJob.cpp
RetrieveMemoryBlockJob.cpp
WriteCoreFileJob.cpp
WriteMemoryJob.cpp
WriteValueNodeJob.cpp
@@ -278,6 +279,7 @@ local sources =
CliThreadCommand.cpp
CliThreadsCommand.cpp
CliVariablesCommand.cpp
CliWriteCoreFileCommand.cpp
# user_interface/gui
GraphicalUserInterface.cpp
+1
View File
@@ -97,6 +97,7 @@ enum {
MSG_SHOW_CONTAINER_RANGE_PROMPT = 'scrp',
MSG_SET_CONTAINER_RANGE = 'chcr',
MSG_GENERATE_DEBUG_REPORT = 'gdrp',
MSG_WRITE_CORE_FILE = 'wrcf',
MSG_WRITE_VARIABLE_VALUE = 'wrvv',
MSG_DEBUG_INFO_NEEDS_USER_INPUT = 'dnui',
@@ -846,6 +846,16 @@ TeamDebugger::MessageReceived(BMessage* message)
break;
}
case MSG_WRITE_CORE_FILE:
{
entry_ref ref;
if (message->FindRef("target", &ref) != B_OK)
break;
_HandleWriteCoreFile(ref);
break;
}
case MSG_THREAD_STATE_CHANGED:
{
int32 threadID;
@@ -1304,6 +1314,15 @@ TeamDebugger::DebugReportRequested(entry_ref* targetPath)
}
void
TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
{
BMessage message(MSG_WRITE_CORE_FILE);
message.AddRef("target", targetPath);
PostMessage(&message);
}
void
TeamDebugger::TeamRestartRequested()
{
@@ -2305,6 +2324,19 @@ TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
}
void
TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
{
status_t result = fWorker->ScheduleJob(
new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
targetPath));
if (result != B_OK) {
_NotifyUser("Write Core File", "Failed to write core file: %s",
strerror(result));
}
}
status_t
TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
{
@@ -131,6 +131,8 @@ private:
virtual void DebugReportRequested(entry_ref* targetPath);
virtual void WriteCoreFileRequested(entry_ref* targetPath);
virtual void TeamRestartRequested();
virtual bool UserInterfaceQuitRequested(
@@ -220,6 +222,8 @@ private:
StackFrame* frame,
::Thread* thread);
void _HandleWriteCoreFile(const entry_ref& ref);
status_t _HandleSetArguments(int argc,
const char* const* argv);
+22 -2
View File
@@ -1,11 +1,12 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2011-2015, Rene Gollent, rene@gollent.com.
* Copyright 2011-2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef JOBS_H
#define JOBS_H
#include <Entry.h>
#include <String.h>
#include "ImageDebugInfoLoadingState.h"
@@ -54,7 +55,8 @@ enum {
JOB_TYPE_WRITE_VALUE_NODE_VALUE,
JOB_TYPE_GET_MEMORY_BLOCK,
JOB_TYPE_WRITE_MEMORY,
JOB_TYPE_EVALUATE_EXPRESSION
JOB_TYPE_EVALUATE_EXPRESSION,
JOB_TYPE_WRITE_CORE_FILE
};
@@ -303,4 +305,22 @@ private:
};
class WriteCoreFileJob : public Job {
public:
WriteCoreFileJob(Team* team,
DebuggerInterface* debuggerInterface,
const entry_ref& targetPath);
virtual ~WriteCoreFileJob();
virtual const JobKey& Key() const;
virtual status_t Do();
private:
SimpleJobKey fKey;
Team* fTeam;
DebuggerInterface* fDebuggerInterface;
entry_ref fTargetPath;
};
#endif // JOBS_H
@@ -0,0 +1,58 @@
/*
* Copyright 2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "Jobs.h"
#include <Path.h>
#include <AutoLocker.h>
#include "DebuggerInterface.h"
#include "Team.h"
WriteCoreFileJob::WriteCoreFileJob(Team* team,
DebuggerInterface* interface, const entry_ref& path)
:
fKey(&path, JOB_TYPE_WRITE_CORE_FILE),
fTeam(team),
fDebuggerInterface(interface),
fTargetPath(path)
{
fDebuggerInterface->AcquireReference();
}
WriteCoreFileJob::~WriteCoreFileJob()
{
fDebuggerInterface->AcquireReference();
}
const JobKey&
WriteCoreFileJob::Key() const
{
return fKey;
}
status_t
WriteCoreFileJob::Do()
{
BPath path(&fTargetPath);
status_t error = path.InitCheck();
if (error != B_OK)
return error;
error = fDebuggerInterface->WriteCoreFile(path.Path());
if (error != B_OK)
return error;
AutoLocker< ::Team> teamLocker(fTeam);
fTeam->NotifyCoreFileChanged(path.Path());
return B_OK;
}
+29
View File
@@ -852,6 +852,17 @@ Team::NotifyDebugReportChanged(const char* reportPath)
}
void
Team::NotifyCoreFileChanged(const char* targetPath)
{
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->CoreFileChanged(CoreFileChangedEvent(
TEAM_EVENT_CORE_FILE_CHANGED, this, targetPath));
}
}
void
Team::NotifyMemoryChanged(target_addr_t address, target_size_t size)
{
@@ -1033,6 +1044,18 @@ Team::DebugReportEvent::DebugReportEvent(uint32 type, Team* team,
}
// #pragma mark - CoreFileChangedEvent
Team::CoreFileChangedEvent::CoreFileChangedEvent(uint32 type, Team* team,
const char* targetPath)
:
Event(type, team),
fTargetPath(targetPath)
{
}
// #pragma mark - MemoryChangedEvent
@@ -1221,6 +1244,12 @@ Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
}
void
Team::Listener::CoreFileChanged(const Team::CoreFileChangedEvent& event)
{
}
void
Team::Listener::MemoryChanged(const Team::MemoryChangedEvent& event)
{
+19
View File
@@ -57,6 +57,8 @@ enum {
TEAM_EVENT_DEBUG_REPORT_CHANGED,
TEAM_EVENT_CORE_FILE_CHANGED,
TEAM_EVENT_MEMORY_CHANGED
};
@@ -96,6 +98,7 @@ public:
class ThreadEvent;
class UserBreakpointEvent;
class WatchpointEvent;
class CoreFileChangedEvent;
class Listener;
public:
@@ -263,6 +266,10 @@ public:
void NotifyDebugReportChanged(
const char* reportPath);
// core file related service methods
void NotifyCoreFileChanged(
const char* targetPath);
// memory write related service methods
void NotifyMemoryChanged(target_addr_t address,
target_size_t size);
@@ -433,6 +440,15 @@ protected:
const char* fReportPath;
};
class Team::CoreFileChangedEvent : public Event {
public:
CoreFileChangedEvent(uint32 type, Team* team,
const char* targetPath);
const char* GetTargetPath() const { return fTargetPath; }
protected:
const char* fTargetPath;
};
class Team::MemoryChangedEvent : public Event {
public:
@@ -533,6 +549,9 @@ public:
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
virtual void CoreFileChanged(
const Team::CoreFileChangedEvent& event);
virtual void MemoryChanged(
const Team::MemoryChangedEvent& event);
};
@@ -173,6 +173,8 @@ public:
virtual void DebugReportRequested(entry_ref* path) = 0;
virtual void WriteCoreFileRequested(entry_ref* path) = 0;
virtual void TeamRestartRequested() = 0;
virtual bool UserInterfaceQuitRequested(
@@ -516,6 +516,17 @@ CliContext::DebugReportChanged(const Team::DebugReportEvent& event)
}
void
CliContext::CoreFileChanged(const Team::CoreFileChangedEvent& event)
{
printf("Successfully saved core file to %s\n",
event.GetTargetPath());
_QueueEvent(new(std::nothrow) Event(EVENT_CORE_FILE_CHANGED));
_SignalInputLoop(EVENT_CORE_FILE_CHANGED);
}
void
CliContext::MemoryBlockRetrieved(TeamMemoryBlock* block)
{
@@ -1,6 +1,6 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2014-2015, Rene Gollent, rene@gollent.com.
* Copyright 2014-2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_CONTEXT_H
@@ -42,7 +42,8 @@ public:
EVENT_VALUE_NODE_CHANGED = 0x40,
EVENT_TEAM_MEMORY_BLOCK_RETRIEVED = 0x80,
EVENT_EXPRESSION_EVALUATED = 0x100,
EVENT_DEBUG_REPORT_CHANGED = 0x200
EVENT_DEBUG_REPORT_CHANGED = 0x200,
EVENT_CORE_FILE_CHANGED = 0x400
};
public:
@@ -112,6 +113,9 @@ private:
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
virtual void CoreFileChanged(
const Team::CoreFileChangedEvent& event);
// TeamMemoryBlock::Listener
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015, Rene Gollent, rene@gollent.com.
* Copyright 2011-2016, Rene Gollent, rene@gollent.com.
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@@ -28,6 +28,7 @@
#include "CliThreadCommand.h"
#include "CliThreadsCommand.h"
#include "CliVariablesCommand.h"
#include "CliWriteCoreFileCommand.h"
static const char* kDebuggerPrompt = "debugger> ";
@@ -311,7 +312,9 @@ CommandLineUserInterface::_RegisterCommands()
&& _RegisterCommand("thread", new(std::nothrow) CliThreadCommand)
&& _RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)
&& _RegisterCommand("variables",
new(std::nothrow) CliVariablesCommand)) {
new(std::nothrow) CliVariablesCommand)
&& _RegisterCommand("write-core",
new(std::nothrow) CliWriteCoreFileCommand)) {
fCommands.SortItems(&_CompareCommandEntries);
return B_OK;
}
@@ -0,0 +1,51 @@
/*
* Copyright 2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "CliWriteCoreFileCommand.h"
#include <Entry.h>
#include <FindDirectory.h>
#include <Path.h>
#include <String.h>
#include "CliContext.h"
#include "UiUtils.h"
#include "UserInterface.h"
CliWriteCoreFileCommand::CliWriteCoreFileCommand()
:
CliCommand("write core file",
"%s\n"
"Writes a core dump file for the current team.")
{
}
void
CliWriteCoreFileCommand::Execute(int argc, const char* const* argv, CliContext& context)
{
BPath path;
if (argc > 1) {
path.SetTo(argv[1]);
if (path.InitCheck() != B_OK) {
printf("Invalid core file path %s given.\n", argv[1]);
return;
}
} else {
char buffer[B_FILE_NAME_LENGTH];
UiUtils::CoreFileNameForTeam(context.GetTeam(), buffer,
sizeof(buffer));
find_directory(B_DESKTOP_DIRECTORY, &path);
path.Append(buffer);
}
entry_ref ref;
if (get_ref_for_path(path.Path(), &ref) == B_OK) {
printf("Writing core file to %s...\n", path.Path());
context.GetUserInterfaceListener()->WriteCoreFileRequested(&ref);
}
}
@@ -0,0 +1,20 @@
/*
* Copyright 2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_WRITE_CORE_FILE_COMMAND_H
#define CLI_WRITE_CORE_FILE_COMMAND_H
#include "CliCommand.h"
class CliWriteCoreFileCommand : public CliCommand {
public:
CliWriteCoreFileCommand();
virtual void Execute(int argc, const char* const* argv,
CliContext& context);
};
#endif // CLI_WRITE_CORE_FILE_COMMAND_H
@@ -1,6 +1,6 @@
/*
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2012-2015, Rene Gollent, rene@gollent.com.
* Copyright 2012-2016, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
@@ -257,6 +257,23 @@ UiUtils::ReportNameForTeam(::Team* team, char* buffer, size_t bufferSize)
currentTime.Time().Minute(), currentTime.Time().Second());
return buffer;
}
/*static*/ const char*
UiUtils::CoreFileNameForTeam(::Team* team, char* buffer, size_t bufferSize)
{
BPath teamPath(team->Name());
BDateTime currentTime;
currentTime.SetTime_t(time(NULL));
snprintf(buffer, bufferSize, "%s-%" B_PRId32 "-debug-%02" B_PRId32 "-%02"
B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02" B_PRId32 "-%02"
B_PRId32 ".core", teamPath.Leaf(), team->ID(),
currentTime.Date().Day(), currentTime.Date().Month(),
currentTime.Date().Year(), currentTime.Time().Hour(),
currentTime.Time().Minute(), currentTime.Time().Second());
return buffer;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2015, Rene Gollent, rene@gollent.com.
* Copyright 2014-2016, Rene Gollent, rene@gollent.com.
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@@ -51,6 +51,9 @@ public:
static const char* ReportNameForTeam(::Team* team,
char* buffer, size_t bufferSize);
static const char* CoreFileNameForTeam(::Team* team,
char* buffer, size_t bufferSize);
// this function assumes the value nodes have already been resolved
// (if possible).
static void PrintValueNodeGraph(BString& _output,