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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user