* Moved all handling of threads from TeamDebugger into new class ThreadHandler.
* Added new job to get the initial state of a thread. * Now we also get the states of new threads correctly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31221 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -25,6 +25,7 @@ Application Debugger :
|
|||||||
# ElfFile.cpp
|
# ElfFile.cpp
|
||||||
Jobs.cpp
|
Jobs.cpp
|
||||||
TeamDebugger.cpp
|
TeamDebugger.cpp
|
||||||
|
ThreadHandler.cpp
|
||||||
Worker.cpp
|
Worker.cpp
|
||||||
|
|
||||||
# arch
|
# arch
|
||||||
|
|||||||
@@ -22,6 +22,56 @@
|
|||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - GetThreadStateJob
|
||||||
|
|
||||||
|
|
||||||
|
GetThreadStateJob::GetThreadStateJob(DebuggerInterface* debuggerInterface,
|
||||||
|
Thread* thread)
|
||||||
|
:
|
||||||
|
fDebuggerInterface(debuggerInterface),
|
||||||
|
fThread(thread)
|
||||||
|
{
|
||||||
|
fThread->AddReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GetThreadStateJob::~GetThreadStateJob()
|
||||||
|
{
|
||||||
|
fThread->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JobKey
|
||||||
|
GetThreadStateJob::Key() const
|
||||||
|
{
|
||||||
|
return JobKey(fThread, JOB_TYPE_GET_THREAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
GetThreadStateJob::Do()
|
||||||
|
{
|
||||||
|
CpuState* state = NULL;
|
||||||
|
status_t error = fDebuggerInterface->GetCpuState(fThread->ID(), state);
|
||||||
|
Reference<CpuState> reference(state, true);
|
||||||
|
|
||||||
|
AutoLocker<Team> locker(fThread->GetTeam());
|
||||||
|
|
||||||
|
if (fThread->State() != THREAD_STATE_UNKNOWN)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
if (error == B_OK) {
|
||||||
|
fThread->SetState(THREAD_STATE_STOPPED);
|
||||||
|
fThread->SetCpuState(state);
|
||||||
|
} else if (error == B_BAD_THREAD_STATE) {
|
||||||
|
fThread->SetState(THREAD_STATE_RUNNING);
|
||||||
|
} else
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - GetCpuStateJob
|
// #pragma mark - GetCpuStateJob
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class Thread;
|
|||||||
|
|
||||||
// job types
|
// job types
|
||||||
enum {
|
enum {
|
||||||
|
JOB_TYPE_GET_THREAD_STATE,
|
||||||
JOB_TYPE_GET_CPU_STATE,
|
JOB_TYPE_GET_CPU_STATE,
|
||||||
JOB_TYPE_GET_STACK_TRACE,
|
JOB_TYPE_GET_STACK_TRACE,
|
||||||
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO,
|
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO,
|
||||||
@@ -27,6 +28,22 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class GetThreadStateJob : public Job {
|
||||||
|
public:
|
||||||
|
GetThreadStateJob(
|
||||||
|
DebuggerInterface* debuggerInterface,
|
||||||
|
Thread* thread);
|
||||||
|
virtual ~GetThreadStateJob();
|
||||||
|
|
||||||
|
virtual JobKey Key() const;
|
||||||
|
virtual status_t Do();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DebuggerInterface* fDebuggerInterface;
|
||||||
|
Thread* fThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class GetCpuStateJob : public Job {
|
class GetCpuStateJob : public Job {
|
||||||
public:
|
public:
|
||||||
GetCpuStateJob(
|
GetCpuStateJob(
|
||||||
|
|||||||
@@ -59,6 +59,13 @@ TeamDebugger::~TeamDebugger()
|
|||||||
if (fDebugEventListener >= 0)
|
if (fDebugEventListener >= 0)
|
||||||
wait_for_thread(fDebugEventListener, NULL);
|
wait_for_thread(fDebugEventListener, NULL);
|
||||||
|
|
||||||
|
ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
|
||||||
|
while (threadHandler != NULL) {
|
||||||
|
ThreadHandler* next = threadHandler->fNext;
|
||||||
|
threadHandler->RemoveReference();
|
||||||
|
threadHandler = next;
|
||||||
|
}
|
||||||
|
|
||||||
delete fDebuggerInterface;
|
delete fDebuggerInterface;
|
||||||
delete fWorker;
|
delete fWorker;
|
||||||
delete fDebugModel;
|
delete fDebugModel;
|
||||||
@@ -92,6 +99,11 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
|
|
||||||
fTeam->AddListener(this);
|
fTeam->AddListener(this);
|
||||||
|
|
||||||
|
// init thread handler table
|
||||||
|
error = fThreadHandlers.Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
// create our worker
|
// create our worker
|
||||||
fWorker = new(std::nothrow) Worker;
|
fWorker = new(std::nothrow) Worker;
|
||||||
if (fWorker == NULL)
|
if (fWorker == NULL)
|
||||||
@@ -136,7 +148,14 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
_UpdateThreadState(thread);
|
ThreadHandler* handler = new(std::nothrow) ThreadHandler(
|
||||||
|
fDebugModel, thread, fWorker, fDebuggerInterface);
|
||||||
|
if (handler == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fThreadHandlers.Insert(handler);
|
||||||
|
|
||||||
|
handler->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +223,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
if (message->FindInt32("thread", &threadID) != B_OK)
|
if (message->FindInt32("thread", &threadID) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_HandleThreadAction(threadID, message->what);
|
if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
|
||||||
|
handler->HandleThreadAction(message->what);
|
||||||
|
handler->RemoveReference();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +254,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
if (message->FindInt32("thread", &threadID) != B_OK)
|
if (message->FindInt32("thread", &threadID) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_HandleThreadStateChanged(threadID);
|
if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
|
||||||
|
handler->HandleThreadStateChanged();
|
||||||
|
handler->RemoveReference();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_THREAD_CPU_STATE_CHANGED:
|
case MSG_THREAD_CPU_STATE_CHANGED:
|
||||||
@@ -241,7 +266,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
if (message->FindInt32("thread", &threadID) != B_OK)
|
if (message->FindInt32("thread", &threadID) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_HandleCpuStateChanged(threadID);
|
if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
|
||||||
|
handler->HandleCpuStateChanged();
|
||||||
|
handler->RemoveReference();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_THREAD_STACK_TRACE_CHANGED:
|
case MSG_THREAD_STACK_TRACE_CHANGED:
|
||||||
@@ -250,7 +278,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
if (message->FindInt32("thread", &threadID) != B_OK)
|
if (message->FindInt32("thread", &threadID) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
_HandleStackTraceChanged(threadID);
|
if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
|
||||||
|
handler->HandleStackTraceChanged();
|
||||||
|
handler->RemoveReference();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,35 +479,51 @@ TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
|
|||||||
printf("TeamDebugger::_HandleDebuggerMessage(): %d\n", event->EventType());
|
printf("TeamDebugger::_HandleDebuggerMessage(): %d\n", event->EventType());
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
|
|
||||||
|
ThreadHandler* handler = _GetThreadHandler(event->Thread());
|
||||||
|
Reference<ThreadHandler> handlerReference(handler);
|
||||||
|
|
||||||
switch (event->EventType()) {
|
switch (event->EventType()) {
|
||||||
case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
|
case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
|
||||||
printf("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleThreadDebugged(
|
if (handler != NULL) {
|
||||||
dynamic_cast<ThreadDebuggedEvent*>(event));
|
handled = handler->HandleThreadDebugged(
|
||||||
|
dynamic_cast<ThreadDebuggedEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
|
case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
|
||||||
printf("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleDebuggerCall(
|
if (handler != NULL) {
|
||||||
dynamic_cast<DebuggerCallEvent*>(event));
|
handled = handler->HandleDebuggerCall(
|
||||||
|
dynamic_cast<DebuggerCallEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
|
case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
|
||||||
printf("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleBreakpointHit(
|
if (handler != NULL) {
|
||||||
dynamic_cast<BreakpointHitEvent*>(event));
|
handled = handler->HandleBreakpointHit(
|
||||||
|
dynamic_cast<BreakpointHitEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
|
case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
|
||||||
printf("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleWatchpointHit(
|
if (handler != NULL) {
|
||||||
dynamic_cast<WatchpointHitEvent*>(event));
|
handled = handler->HandleWatchpointHit(
|
||||||
|
dynamic_cast<WatchpointHitEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_SINGLE_STEP:
|
case B_DEBUGGER_MESSAGE_SINGLE_STEP:
|
||||||
printf("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleSingleStep(dynamic_cast<SingleStepEvent*>(event));
|
if (handler != NULL) {
|
||||||
|
handled = handler->HandleSingleStep(
|
||||||
|
dynamic_cast<SingleStepEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
|
case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
|
||||||
printf("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %ld\n", event->Thread());
|
printf("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %ld\n", event->Thread());
|
||||||
handled = _HandleExceptionOccurred(
|
if (handler != NULL) {
|
||||||
dynamic_cast<ExceptionOccurredEvent*>(event));
|
handled = handler->HandleExceptionOccurred(
|
||||||
|
dynamic_cast<ExceptionOccurredEvent*>(event));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// case B_DEBUGGER_MESSAGE_TEAM_CREATED:
|
// case B_DEBUGGER_MESSAGE_TEAM_CREATED:
|
||||||
//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
|
//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
|
||||||
@@ -523,63 +570,6 @@ printf("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %ld\n", event->Team());
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleThreadStopped(thread_id threadID, CpuState* cpuState)
|
|
||||||
{
|
|
||||||
// get the thread
|
|
||||||
AutoLocker< ::Team> locker(fTeam);
|
|
||||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
|
||||||
if (thread == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_SetThreadState(thread, THREAD_STATE_STOPPED, cpuState);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleThreadDebugged(ThreadDebuggedEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleDebuggerCall(DebuggerCallEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleBreakpointHit(BreakpointHitEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), event->GetCpuState());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleWatchpointHit(WatchpointHitEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), event->GetCpuState());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleSingleStep(SingleStepEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), event->GetCpuState());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
TeamDebugger::_HandleExceptionOccurred(ExceptionOccurredEvent* event)
|
|
||||||
{
|
|
||||||
return _HandleThreadStopped(event->Thread(), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
|
TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
|
||||||
{
|
{
|
||||||
@@ -588,8 +578,17 @@ TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
|
|||||||
ThreadInfo info;
|
ThreadInfo info;
|
||||||
status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
|
status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
|
||||||
info);
|
info);
|
||||||
if (error == B_OK)
|
if (error == B_OK) {
|
||||||
fTeam->AddThread(info);
|
::Thread* thread;
|
||||||
|
fTeam->AddThread(info, &thread);
|
||||||
|
|
||||||
|
ThreadHandler* handler = new(std::nothrow) ThreadHandler(
|
||||||
|
fDebugModel, thread, fWorker, fDebuggerInterface);
|
||||||
|
if (handler != NULL) {
|
||||||
|
fThreadHandlers.Insert(handler);
|
||||||
|
handler->Init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -599,6 +598,10 @@ bool
|
|||||||
TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
|
TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
|
||||||
{
|
{
|
||||||
AutoLocker< ::Team> locker(fTeam);
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
|
if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
|
||||||
|
fThreadHandlers.Remove(handler);
|
||||||
|
handler->RemoveReference();
|
||||||
|
}
|
||||||
fTeam->RemoveThread(event->Thread());
|
fTeam->RemoveThread(event->Thread());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -622,32 +625,6 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::_UpdateThreadState(::Thread* thread)
|
|
||||||
{
|
|
||||||
CpuState* cpuState = NULL;
|
|
||||||
status_t error = fDebuggerInterface->GetCpuState(thread->ID(), cpuState);
|
|
||||||
|
|
||||||
uint32 newState = THREAD_STATE_UNKNOWN;
|
|
||||||
if (error == B_OK) {
|
|
||||||
newState = THREAD_STATE_STOPPED;
|
|
||||||
cpuState->RemoveReference();
|
|
||||||
} else if (error == B_BAD_THREAD_STATE)
|
|
||||||
newState = THREAD_STATE_RUNNING;
|
|
||||||
|
|
||||||
_SetThreadState(thread, newState, cpuState);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::_SetThreadState(::Thread* thread, uint32 state,
|
|
||||||
CpuState* cpuState)
|
|
||||||
{
|
|
||||||
thread->SetState(state);
|
|
||||||
thread->SetCpuState(cpuState);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TeamDebugger::_SetUserBreakpoint(target_addr_t address, bool enabled)
|
TeamDebugger::_SetUserBreakpoint(target_addr_t address, bool enabled)
|
||||||
{
|
{
|
||||||
@@ -715,56 +692,6 @@ printf("-> breakpoint %sinstalled successfully!\n", install ? "" : "un");
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::_HandleThreadAction(thread_id threadID, uint32 action)
|
|
||||||
{
|
|
||||||
AutoLocker< ::Team> locker(fTeam);
|
|
||||||
|
|
||||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
|
||||||
if (thread == NULL || thread->State() == THREAD_STATE_UNKNOWN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// When stop is requested, thread must be running, otherwise stopped.
|
|
||||||
if (action == MSG_THREAD_STOP
|
|
||||||
? thread->State() != THREAD_STATE_RUNNING
|
|
||||||
: thread->State() != THREAD_STATE_STOPPED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When continuing the thread update thread state before actually issuing
|
|
||||||
// the command, since we need to unlock.
|
|
||||||
if (action != MSG_THREAD_STOP)
|
|
||||||
_SetThreadState(thread, THREAD_STATE_RUNNING, NULL);
|
|
||||||
|
|
||||||
locker.Unlock();
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
case MSG_THREAD_RUN:
|
|
||||||
printf("MSG_THREAD_RUN\n");
|
|
||||||
fDebuggerInterface->ContinueThread(threadID);
|
|
||||||
break;
|
|
||||||
case MSG_THREAD_STOP:
|
|
||||||
printf("MSG_THREAD_STOP\n");
|
|
||||||
fDebuggerInterface->StopThread(threadID);
|
|
||||||
break;
|
|
||||||
case MSG_THREAD_STEP_OVER:
|
|
||||||
printf("MSG_THREAD_STEP_OVER\n");
|
|
||||||
fDebuggerInterface->SingleStepThread(threadID);
|
|
||||||
break;
|
|
||||||
case MSG_THREAD_STEP_INTO:
|
|
||||||
printf("MSG_THREAD_STEP_INTO\n");
|
|
||||||
fDebuggerInterface->SingleStepThread(threadID);
|
|
||||||
break;
|
|
||||||
case MSG_THREAD_STEP_OUT:
|
|
||||||
printf("MSG_THREAD_STEP_OUT\n");
|
|
||||||
fDebuggerInterface->SingleStepThread(threadID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: Handle stepping correctly!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
||||||
{
|
{
|
||||||
@@ -806,55 +733,15 @@ printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
ThreadHandler*
|
||||||
TeamDebugger::_HandleThreadStateChanged(thread_id threadID)
|
TeamDebugger::_GetThreadHandler(thread_id threadID)
|
||||||
{
|
{
|
||||||
AutoLocker< ::Team> teamLocker(fTeam);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
|
||||||
if (thread == NULL)
|
if (handler != NULL)
|
||||||
return;
|
handler->AddReference();
|
||||||
|
return handler;
|
||||||
// cancel jobs for this thread
|
|
||||||
fWorker->AbortJob(JobKey(thread, JOB_TYPE_GET_CPU_STATE));
|
|
||||||
fWorker->AbortJob(JobKey(thread, JOB_TYPE_GET_STACK_TRACE));
|
|
||||||
|
|
||||||
// If the thread is stopped and has no CPU state yet, schedule a job.
|
|
||||||
if (thread->State() == THREAD_STATE_STOPPED
|
|
||||||
&& thread->GetCpuState() == NULL) {
|
|
||||||
fWorker->ScheduleJob(
|
|
||||||
new(std::nothrow) GetCpuStateJob(fDebuggerInterface, thread),
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::_HandleCpuStateChanged(thread_id threadID)
|
|
||||||
{
|
|
||||||
AutoLocker< ::Team> teamLocker(fTeam);
|
|
||||||
|
|
||||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
|
||||||
if (thread == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// cancel stack trace job for this thread
|
|
||||||
fWorker->AbortJob(JobKey(thread, JOB_TYPE_GET_STACK_TRACE));
|
|
||||||
|
|
||||||
// If the thread has a CPU state, but no stack trace yet, schedule a job.
|
|
||||||
if (thread->GetCpuState() != NULL && thread->GetStackTrace() == NULL) {
|
|
||||||
fWorker->ScheduleJob(
|
|
||||||
new(std::nothrow) GetStackTraceJob(fDebuggerInterface,
|
|
||||||
fDebuggerInterface->GetArchitecture(), thread),
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::_HandleStackTraceChanged(thread_id threadID)
|
|
||||||
{
|
|
||||||
printf("TeamDebugger::_HandleStackTraceChanged()\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "DebugEvent.h"
|
#include "DebugEvent.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "TeamWindow.h"
|
#include "TeamWindow.h"
|
||||||
|
#include "ThreadHandler.h"
|
||||||
#include "Worker.h"
|
#include "Worker.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -66,21 +67,6 @@ private:
|
|||||||
|
|
||||||
void _HandleDebuggerMessage(DebugEvent* event);
|
void _HandleDebuggerMessage(DebugEvent* event);
|
||||||
|
|
||||||
bool _HandleThreadStopped(thread_id threadID,
|
|
||||||
CpuState* cpuState);
|
|
||||||
|
|
||||||
bool _HandleThreadDebugged(
|
|
||||||
ThreadDebuggedEvent* event);
|
|
||||||
bool _HandleDebuggerCall(
|
|
||||||
DebuggerCallEvent* event);
|
|
||||||
bool _HandleBreakpointHit(
|
|
||||||
BreakpointHitEvent* event);
|
|
||||||
bool _HandleWatchpointHit(
|
|
||||||
WatchpointHitEvent* event);
|
|
||||||
bool _HandleSingleStep(
|
|
||||||
SingleStepEvent* event);
|
|
||||||
bool _HandleExceptionOccurred(
|
|
||||||
ExceptionOccurredEvent* event);
|
|
||||||
bool _HandleThreadCreated(
|
bool _HandleThreadCreated(
|
||||||
ThreadCreatedEvent* event);
|
ThreadCreatedEvent* event);
|
||||||
bool _HandleThreadDeleted(
|
bool _HandleThreadDeleted(
|
||||||
@@ -90,23 +76,17 @@ private:
|
|||||||
bool _HandleImageDeleted(
|
bool _HandleImageDeleted(
|
||||||
ImageDeletedEvent* event);
|
ImageDeletedEvent* event);
|
||||||
|
|
||||||
void _UpdateThreadState(::Thread* thread);
|
|
||||||
void _SetThreadState(::Thread* thread, uint32 state,
|
|
||||||
CpuState* cpuState);
|
|
||||||
|
|
||||||
status_t _SetUserBreakpoint(target_addr_t address,
|
status_t _SetUserBreakpoint(target_addr_t address,
|
||||||
bool enabled);
|
bool enabled);
|
||||||
|
|
||||||
void _HandleThreadAction(thread_id threadID,
|
|
||||||
uint32 action);
|
|
||||||
void _HandleSetUserBreakpoint(target_addr_t address,
|
void _HandleSetUserBreakpoint(target_addr_t address,
|
||||||
bool enabled);
|
bool enabled);
|
||||||
void _HandleClearUserBreakpoint(
|
void _HandleClearUserBreakpoint(
|
||||||
target_addr_t address);
|
target_addr_t address);
|
||||||
|
|
||||||
void _HandleThreadStateChanged(thread_id threadID);
|
|
||||||
void _HandleCpuStateChanged(thread_id threadID);
|
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
||||||
void _HandleStackTraceChanged(thread_id threadID);
|
|
||||||
|
|
||||||
void _NotifyUser(const char* title,
|
void _NotifyUser(const char* title,
|
||||||
const char* text,...);
|
const char* text,...);
|
||||||
@@ -116,7 +96,8 @@ private:
|
|||||||
::Team* fTeam;
|
::Team* fTeam;
|
||||||
TeamDebugModel* fDebugModel;
|
TeamDebugModel* fDebugModel;
|
||||||
team_id fTeamID;
|
team_id fTeamID;
|
||||||
port_id fNubPort;
|
ThreadHandlerTable fThreadHandlers;
|
||||||
|
// protected by the team lock
|
||||||
DebuggerInterface* fDebuggerInterface;
|
DebuggerInterface* fDebuggerInterface;
|
||||||
Worker* fWorker;
|
Worker* fWorker;
|
||||||
thread_id fDebugEventListener;
|
thread_id fDebugEventListener;
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ThreadHandler.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#include "CpuState.h"
|
||||||
|
#include "DebuggerInterface.h"
|
||||||
|
#include "Jobs.h"
|
||||||
|
#include "MessageCodes.h"
|
||||||
|
#include "Team.h"
|
||||||
|
#include "TeamDebugModel.h"
|
||||||
|
#include "Worker.h"
|
||||||
|
|
||||||
|
|
||||||
|
ThreadHandler::ThreadHandler(TeamDebugModel* debugModel, Thread* thread,
|
||||||
|
Worker* worker, DebuggerInterface* debuggerInterface)
|
||||||
|
:
|
||||||
|
fDebugModel(debugModel),
|
||||||
|
fThread(thread),
|
||||||
|
fWorker(worker),
|
||||||
|
fDebuggerInterface(debuggerInterface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ThreadHandler::~ThreadHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::Init()
|
||||||
|
{
|
||||||
|
fWorker->ScheduleJob(new(std::nothrow) GetThreadStateJob(fDebuggerInterface,
|
||||||
|
fThread));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleThreadDebugged(ThreadDebuggedEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleDebuggerCall(DebuggerCallEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(event->GetCpuState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleWatchpointHit(WatchpointHitEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(event->GetCpuState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleSingleStep(SingleStepEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(event->GetCpuState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event)
|
||||||
|
{
|
||||||
|
return _HandleThreadStopped(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::HandleThreadAction(uint32 action)
|
||||||
|
{
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
if (fThread->State() == THREAD_STATE_UNKNOWN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// When stop is requested, thread must be running, otherwise stopped.
|
||||||
|
if (action == MSG_THREAD_STOP
|
||||||
|
? fThread->State() != THREAD_STATE_RUNNING
|
||||||
|
: fThread->State() != THREAD_STATE_STOPPED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When continuing the thread update thread state before actually issuing
|
||||||
|
// the command, since we need to unlock.
|
||||||
|
if (action != MSG_THREAD_STOP)
|
||||||
|
_SetThreadState(THREAD_STATE_RUNNING, NULL);
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case MSG_THREAD_RUN:
|
||||||
|
printf("MSG_THREAD_RUN\n");
|
||||||
|
fDebuggerInterface->ContinueThread(ThreadID());
|
||||||
|
break;
|
||||||
|
case MSG_THREAD_STOP:
|
||||||
|
printf("MSG_THREAD_STOP\n");
|
||||||
|
fDebuggerInterface->StopThread(ThreadID());
|
||||||
|
break;
|
||||||
|
case MSG_THREAD_STEP_OVER:
|
||||||
|
printf("MSG_THREAD_STEP_OVER\n");
|
||||||
|
fDebuggerInterface->SingleStepThread(ThreadID());
|
||||||
|
break;
|
||||||
|
case MSG_THREAD_STEP_INTO:
|
||||||
|
printf("MSG_THREAD_STEP_INTO\n");
|
||||||
|
fDebuggerInterface->SingleStepThread(ThreadID());
|
||||||
|
break;
|
||||||
|
case MSG_THREAD_STEP_OUT:
|
||||||
|
printf("MSG_THREAD_STEP_OUT\n");
|
||||||
|
fDebuggerInterface->SingleStepThread(ThreadID());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO: Handle stepping correctly!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::HandleThreadStateChanged()
|
||||||
|
{
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
// cancel jobs for this thread
|
||||||
|
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_CPU_STATE));
|
||||||
|
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
|
||||||
|
|
||||||
|
// If the thread is stopped and has no CPU state yet, schedule a job.
|
||||||
|
if (fThread->State() == THREAD_STATE_STOPPED
|
||||||
|
&& fThread->GetCpuState() == NULL) {
|
||||||
|
fWorker->ScheduleJob(
|
||||||
|
new(std::nothrow) GetCpuStateJob(fDebuggerInterface, fThread));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::HandleCpuStateChanged()
|
||||||
|
{
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
// cancel stack trace job for this thread
|
||||||
|
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
|
||||||
|
|
||||||
|
// If the thread has a CPU state, but no stack trace yet, schedule a job.
|
||||||
|
if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) {
|
||||||
|
fWorker->ScheduleJob(
|
||||||
|
new(std::nothrow) GetStackTraceJob(fDebuggerInterface,
|
||||||
|
fDebuggerInterface->GetArchitecture(), fThread));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::HandleStackTraceChanged()
|
||||||
|
{
|
||||||
|
printf("ThreadHandler::_HandleStackTraceChanged()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ThreadHandler::_HandleThreadStopped(CpuState* cpuState)
|
||||||
|
{
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
_SetThreadState(THREAD_STATE_STOPPED, cpuState);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ThreadHandler::_SetThreadState(uint32 state, CpuState* cpuState)
|
||||||
|
{
|
||||||
|
fThread->SetState(state);
|
||||||
|
fThread->SetCpuState(cpuState);
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef THREAD_HANDLER_H
|
||||||
|
#define THREAD_HANDLER_H
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
#include "DebugEvent.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
|
||||||
|
|
||||||
|
class DebuggerInterface;
|
||||||
|
class TeamDebugModel;
|
||||||
|
class Worker;
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadHandler : public Referenceable,
|
||||||
|
public HashTableLink<ThreadHandler> {
|
||||||
|
public:
|
||||||
|
ThreadHandler(TeamDebugModel* debugModel,
|
||||||
|
Thread* thread, Worker* worker,
|
||||||
|
DebuggerInterface* debuggerInterface);
|
||||||
|
~ThreadHandler();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
thread_id ThreadID() const { return fThread->ID(); }
|
||||||
|
Thread* GetThread() const { return fThread; }
|
||||||
|
|
||||||
|
bool HandleThreadDebugged(
|
||||||
|
ThreadDebuggedEvent* event);
|
||||||
|
bool HandleDebuggerCall(
|
||||||
|
DebuggerCallEvent* event);
|
||||||
|
bool HandleBreakpointHit(
|
||||||
|
BreakpointHitEvent* event);
|
||||||
|
bool HandleWatchpointHit(
|
||||||
|
WatchpointHitEvent* event);
|
||||||
|
bool HandleSingleStep(
|
||||||
|
SingleStepEvent* event);
|
||||||
|
bool HandleExceptionOccurred(
|
||||||
|
ExceptionOccurredEvent* event);
|
||||||
|
|
||||||
|
void HandleThreadAction(uint32 action);
|
||||||
|
|
||||||
|
void HandleThreadStateChanged();
|
||||||
|
void HandleCpuStateChanged();
|
||||||
|
void HandleStackTraceChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _HandleThreadStopped(CpuState* cpuState);
|
||||||
|
|
||||||
|
void _SetThreadState(uint32 state,
|
||||||
|
CpuState* cpuState);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TeamDebugModel* fDebugModel;
|
||||||
|
Thread* fThread;
|
||||||
|
Worker* fWorker;
|
||||||
|
DebuggerInterface* fDebuggerInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ThreadHandlerHashDefinition {
|
||||||
|
typedef thread_id KeyType;
|
||||||
|
typedef ThreadHandler ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(thread_id key) const
|
||||||
|
{
|
||||||
|
return (size_t)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const ThreadHandler* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->ThreadID());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(thread_id key, ThreadHandler* value) const
|
||||||
|
{
|
||||||
|
return value->ThreadID() == key;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<ThreadHandler>* GetLink(ThreadHandler* value) const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef OpenHashTable<ThreadHandlerHashDefinition> ThreadHandlerTable;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // THREAD_HANDLER_H
|
||||||
Reference in New Issue
Block a user