From f208695cc18a91def34ea8118ce608f5b344a2d9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 18 Jun 2009 17:57:37 +0000 Subject: [PATCH] Moved all interaction with the kernel/debugger interface into new class DebuggerInterface. This will simplify adding support for remote debugging eventually. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31100 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/CpuState.cpp | 11 + src/apps/debugger/CpuState.h | 19 ++ src/apps/debugger/Image.cpp | 2 +- src/apps/debugger/Image.h | 14 +- src/apps/debugger/ImageInfo.cpp | 41 +++ src/apps/debugger/ImageInfo.h | 33 ++ src/apps/debugger/Jamfile | 11 +- src/apps/debugger/Team.cpp | 20 +- src/apps/debugger/Team.h | 8 +- src/apps/debugger/TeamDebugger.cpp | 193 ++++++------ src/apps/debugger/TeamDebugger.h | 16 +- src/apps/debugger/ThreadInfo.cpp | 42 +++ src/apps/debugger/ThreadInfo.h | 33 ++ .../debugger_interface/DebugEvent.cpp | 201 ++++++++++++ .../debugger/debugger_interface/DebugEvent.h | 174 +++++++++++ .../debugger_interface/DebuggerInterface.cpp | 295 ++++++++++++++++++ .../debugger_interface/DebuggerInterface.h | 55 ++++ 17 files changed, 1033 insertions(+), 135 deletions(-) create mode 100644 src/apps/debugger/CpuState.cpp create mode 100644 src/apps/debugger/CpuState.h create mode 100644 src/apps/debugger/ImageInfo.cpp create mode 100644 src/apps/debugger/ImageInfo.h create mode 100644 src/apps/debugger/ThreadInfo.cpp create mode 100644 src/apps/debugger/ThreadInfo.h create mode 100644 src/apps/debugger/debugger_interface/DebugEvent.cpp create mode 100644 src/apps/debugger/debugger_interface/DebugEvent.h create mode 100644 src/apps/debugger/debugger_interface/DebuggerInterface.cpp create mode 100644 src/apps/debugger/debugger_interface/DebuggerInterface.h diff --git a/src/apps/debugger/CpuState.cpp b/src/apps/debugger/CpuState.cpp new file mode 100644 index 0000000000..457cc6db88 --- /dev/null +++ b/src/apps/debugger/CpuState.cpp @@ -0,0 +1,11 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "CpuState.h" + + +CpuState::~CpuState() +{ +} diff --git a/src/apps/debugger/CpuState.h b/src/apps/debugger/CpuState.h new file mode 100644 index 0000000000..6b109f2944 --- /dev/null +++ b/src/apps/debugger/CpuState.h @@ -0,0 +1,19 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CPU_STATE_H +#define CPU_STATE_H + +#include + +#include + + +class CpuState : public Referenceable { +public: + virtual ~CpuState(); +}; + + +#endif // CPU_STATE_H diff --git a/src/apps/debugger/Image.cpp b/src/apps/debugger/Image.cpp index 525360b91d..e8c4af4b4d 100644 --- a/src/apps/debugger/Image.cpp +++ b/src/apps/debugger/Image.cpp @@ -6,7 +6,7 @@ #include "Image.h" -Image::Image(Team* team,const image_info& imageInfo) +Image::Image(Team* team,const ImageInfo& imageInfo) : fTeam(team), fInfo(imageInfo) diff --git a/src/apps/debugger/Image.h b/src/apps/debugger/Image.h index 19c39c2dbc..2e3581cd87 100644 --- a/src/apps/debugger/Image.h +++ b/src/apps/debugger/Image.h @@ -10,26 +10,28 @@ #include #include +#include "ImageInfo.h" + class Team; class Image : public Referenceable, public DoublyLinkedListLinkImpl { public: - Image(Team* team, const image_info& imageInfo); + Image(Team* team, const ImageInfo& imageInfo); ~Image(); status_t Init(); - + Team* GetTeam() const { return fTeam; } - image_id ID() const { return fInfo.id; } - const char* Name() const { return fInfo.name; } - const image_info& Info() const { return fInfo; } + image_id ID() const { return fInfo.ImageID(); } + const char* Name() const { return fInfo.Name(); } + const ImageInfo& Info() const { return fInfo; } private: Team* fTeam; - image_info fInfo; + ImageInfo fInfo; }; diff --git a/src/apps/debugger/ImageInfo.cpp b/src/apps/debugger/ImageInfo.cpp new file mode 100644 index 0000000000..3733124c19 --- /dev/null +++ b/src/apps/debugger/ImageInfo.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "ImageInfo.h" + + +ImageInfo::ImageInfo() + : + fTeam(-1), + fImage(-1), + fName() +{ +} + +ImageInfo::ImageInfo(const ImageInfo& other) + : + fTeam(other.fTeam), + fImage(other.fImage), + fName(other.fName) +{ +} + + +ImageInfo::ImageInfo(team_id team, image_id image, const BString& name) + : + fTeam(team), + fImage(image), + fName(name) +{ +} + + +void +ImageInfo::SetTo(team_id team, image_id image, const BString& name) +{ + fTeam = team; + fImage = image; + fName = name; +} diff --git a/src/apps/debugger/ImageInfo.h b/src/apps/debugger/ImageInfo.h new file mode 100644 index 0000000000..c34fb6f14b --- /dev/null +++ b/src/apps/debugger/ImageInfo.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef IMAGE_INFO_H +#define IMAGE_INFO_H + +#include +#include + + +class ImageInfo { +public: + ImageInfo(); + ImageInfo(const ImageInfo& other); + ImageInfo(team_id team, image_id image, + const BString& name); + + void SetTo(team_id team, image_id image, + const BString& name); + + team_id TeamID() const { return fTeam; } + image_id ImageID() const { return fImage; } + const char* Name() const { return fName.String(); } + +private: + thread_id fTeam; + image_id fImage; + BString fName; +}; + + +#endif // IMAGE_INFO_H diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 325f634948..3d73271148 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -6,6 +6,7 @@ C++FLAGS += -Werror ; UsePrivateHeaders debug interface kernel shared ; UsePrivateSystemHeaders ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ; local debugAnalyzerSources @@ -16,14 +17,16 @@ SubDirHdrs [ FDirName $(debugAnalyzerSources) gui ] ; SubDirHdrs [ FDirName $(debugAnalyzerSources) util ] ; Application Debugger : + CpuState.cpp Debugger.cpp - ElfFile.cpp - +# ElfFile.cpp Image.cpp + ImageInfo.cpp Team.cpp TeamDebugger.cpp TeamDebugModel.cpp Thread.cpp + ThreadInfo.cpp # DebugAnalyzer:util Variant.cpp @@ -33,6 +36,10 @@ Application Debugger : TeamWindow.cpp ThreadListView.cpp + # debugger_interface + DebugEvent.cpp + DebuggerInterface.cpp + # DWARF # attribute_classes.cpp # AttributeValue.cpp diff --git a/src/apps/debugger/Team.cpp b/src/apps/debugger/Team.cpp index 60f8605160..bbb73bcf6b 100644 --- a/src/apps/debugger/Team.cpp +++ b/src/apps/debugger/Team.cpp @@ -50,12 +50,13 @@ Team::AddThread(Thread* thread) fThreads.Add(thread); _NotifyThreadAdded(thread); } - + + status_t -Team::AddThread(const thread_info& threadInfo, Thread** _thread) +Team::AddThread(const ThreadInfo& threadInfo, Thread** _thread) { - Thread* thread = new(std::nothrow) Thread(this, threadInfo.thread); + Thread* thread = new(std::nothrow) Thread(this, threadInfo.ThreadID()); if (thread == NULL) return B_NO_MEMORY; @@ -65,7 +66,7 @@ Team::AddThread(const thread_info& threadInfo, Thread** _thread) return error; } - thread->SetName(threadInfo.name); + thread->SetName(threadInfo.Name()); AddThread(thread); if (_thread != NULL) @@ -75,15 +76,6 @@ Team::AddThread(const thread_info& threadInfo, Thread** _thread) } -status_t -Team::AddThread(thread_id threadID, Thread** _thread) -{ - thread_info threadInfo; - status_t error = get_thread_info(threadID, &threadInfo); - return error == B_OK ? AddThread(threadInfo, _thread) : error; -} - - void Team::RemoveThread(Thread* thread) { @@ -134,7 +126,7 @@ Team::AddImage(Image* image) status_t -Team::AddImage(const image_info& imageInfo, Image** _image) +Team::AddImage(const ImageInfo& imageInfo, Image** _image) { Image* image = new(std::nothrow) Image(this, imageInfo); if (image == NULL) diff --git a/src/apps/debugger/Team.h b/src/apps/debugger/Team.h index 0b74998d61..568177ecba 100644 --- a/src/apps/debugger/Team.h +++ b/src/apps/debugger/Team.h @@ -8,7 +8,9 @@ #include #include "Image.h" +#include "ImageInfo.h" #include "Thread.h" +#include "ThreadInfo.h" // team event types @@ -39,9 +41,7 @@ public: void SetName(const BString& name); void AddThread(Thread* thread); - status_t AddThread(const thread_info& threadInfo, - Thread** _thread = NULL); - status_t AddThread(thread_id threadID, + status_t AddThread(const ThreadInfo& threadInfo, Thread** _thread = NULL); void RemoveThread(Thread* thread); bool RemoveThread(thread_id threadID); @@ -49,7 +49,7 @@ public: const ThreadList& Threads() const; void AddImage(Image* image); - status_t AddImage(const image_info& imageInfo, + status_t AddImage(const ImageInfo& imageInfo, Image** _image = NULL); void RemoveImage(Image* image); bool RemoveImage(image_id imageID); diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 8f33a76cb9..8bcb4b7ce6 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -15,6 +15,8 @@ #include "debug_utils.h" +#include "CpuState.h" +#include "DebuggerInterface.h" #include "Team.h" #include "TeamDebugModel.h" @@ -25,13 +27,11 @@ TeamDebugger::TeamDebugger() fTeam(NULL), fDebugModel(NULL), fTeamID(-1), - fDebuggerPort(-1), - fNubPort(-1), + fDebuggerInterface(NULL), fDebugEventListener(-1), fTeamWindow(NULL), fTerminating(false) { - fDebugContext.reply_port = -1; } @@ -41,18 +41,16 @@ TeamDebugger::~TeamDebugger() fTerminating = true; - if (fDebuggerPort >= 0) - delete_port(fDebuggerPort); + fDebuggerInterface->Close(); locker.Unlock(); if (fDebugEventListener >= 0) wait_for_thread(fDebugEventListener, NULL); - destroy_debug_context(&fDebugContext); - delete fDebugModel; delete fTeam; + delete fDebuggerInterface; } @@ -87,54 +85,52 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) if (error != B_OK) return error; - // create debugger port - char buffer[128]; - snprintf(buffer, sizeof(buffer), "team %ld debugger", fTeamID); - fDebuggerPort = create_port(100, buffer); - if (fDebuggerPort < 0) - return fDebuggerPort; + // create debugger interface + fDebuggerInterface = new(std::nothrow) DebuggerInterface(fTeamID); + if (fDebuggerInterface == NULL) + return B_NO_MEMORY; - // install as team debugger - fNubPort = install_team_debugger(fTeamID, fDebuggerPort); - if (fNubPort < 0) - return fNubPort; - - // init debug context - error = init_debug_context(&fDebugContext, fTeamID, fNubPort); + error = fDebuggerInterface->Init(); if (error != B_OK) return error; // set team debugging flags - set_team_debugging_flags(fNubPort, + fDebuggerInterface->SetTeamDebuggingFlags( B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES); // get the initial state of the team AutoLocker< ::Team> teamLocker(fTeam); - thread_info threadInfo; - int32 cookie = 0; - while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) { - ::Thread* thread; - error = fTeam->AddThread(threadInfo, &thread); - if (error != B_OK) - return error; + { + BObjectList threadInfos(20, true); + status_t error = fDebuggerInterface->GetThreadInfos(threadInfos); + for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) { + ::Thread* thread; + error = fTeam->AddThread(*info, &thread); + if (error != B_OK) + return error; - _UpdateThreadState(thread); + _UpdateThreadState(thread); + } } - image_info imageInfo; - cookie = 0; - while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) { - error = fTeam->AddImage(imageInfo); - if (error != B_OK) - return error; + { + BObjectList imageInfos(20, true); + status_t error = fDebuggerInterface->GetImageInfos(imageInfos); + for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) { + error = fTeam->AddImage(*info); + if (error != B_OK) + return error; + } } // create the debug event listener + char buffer[128]; snprintf(buffer, sizeof(buffer), "team %ld debug listener", fTeamID); fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer, B_NORMAL_PRIORITY, this); - if (fDebugEventListener < 0) +// if (fDebugEventListener < 0) + if (fDebugEventListener < NULL) return fDebugEventListener; resume_thread(fDebugEventListener); @@ -191,31 +187,27 @@ status_t TeamDebugger::_DebugEventListener() { while (!fTerminating) { - // read the next message - debug_debugger_message_data message; - int32 messageCode; - ssize_t size = read_port(fDebuggerPort, &messageCode, &message, - sizeof(message)); - if (size < 0) { - if (size == B_INTERRUPTED) - continue; -// TODO: Error handling! + // get the next event + DebugEvent* event; + status_t error = fDebuggerInterface->GetNextDebugEvent(event); + if (error != B_OK) break; - } + // TODO: Error handling! - if (message.origin.team != fTeamID) { -printf("TeamDebugger for team %ld: received message from team %ld!\n", fTeamID, -message.origin.team); + + if (event->Team() != fTeamID) { +printf("TeamDebugger for team %ld: received event from team %ld!\n", fTeamID, +event->Team()); continue; } - _HandleDebuggerMessage(messageCode, message); + _HandleDebuggerMessage(event); - if (messageCode == B_DEBUGGER_MESSAGE_TEAM_DELETED - || messageCode == B_DEBUGGER_MESSAGE_TEAM_EXEC) { - // TODO:... - break; - } +// if (event->EventType() == B_DEBUGGER_MESSAGE_TEAM_DELETED +// || event->EventType() == B_DEBUGGER_MESSAGE_TEAM_EXEC) { +// // TODO:... +// break; +// } } return B_OK; @@ -223,51 +215,54 @@ message.origin.team); void -TeamDebugger::_HandleDebuggerMessage(int32 messageCode, - const debug_debugger_message_data& message) +TeamDebugger::_HandleDebuggerMessage(DebugEvent* event) { -printf("TeamDebugger::_HandleDebuggerMessage(): %ld\n", messageCode); +printf("TeamDebugger::_HandleDebuggerMessage(): %d\n", event->EventType()); bool handled = false; - switch (messageCode) { + switch (event->EventType()) { case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: -printf("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %ld\n", message.origin.thread); +printf("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %ld\n", event->Thread()); break; case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: -printf("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %ld\n", message.origin.thread); +printf("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %ld\n", event->Thread()); break; case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: -printf("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %ld\n", message.origin.thread); +printf("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %ld\n", event->Thread()); break; case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: -printf("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %ld\n", message.origin.thread); +printf("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %ld\n", event->Thread()); break; case B_DEBUGGER_MESSAGE_SINGLE_STEP: -printf("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %ld\n", message.origin.thread); +printf("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %ld\n", event->Thread()); break; case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: -printf("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %ld\n", message.origin.thread); - break; - case B_DEBUGGER_MESSAGE_TEAM_CREATED: -printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team); +printf("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %ld\n", event->Thread()); break; +// case B_DEBUGGER_MESSAGE_TEAM_CREATED: +//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team); +// break; case B_DEBUGGER_MESSAGE_TEAM_DELETED: -printf("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %ld\n", message.origin.team); +printf("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %ld\n", event->Team()); break; case B_DEBUGGER_MESSAGE_TEAM_EXEC: -printf("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %ld\n", message.origin.team); +printf("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %ld\n", event->Team()); break; case B_DEBUGGER_MESSAGE_THREAD_CREATED: - handled = _HandleThreadCreated(message.thread_created); + handled = _HandleThreadCreated( + dynamic_cast(event)); break; case B_DEBUGGER_MESSAGE_THREAD_DELETED: - handled = _HandleThreadDeleted(message.thread_deleted); + handled = _HandleThreadDeleted( + dynamic_cast(event)); break; case B_DEBUGGER_MESSAGE_IMAGE_CREATED: - handled = _HandleImageCreated(message.image_created); + handled = _HandleImageCreated( + dynamic_cast(event)); break; case B_DEBUGGER_MESSAGE_IMAGE_DELETED: - handled = _HandleImageDeleted(message.image_deleted); + handled = _HandleImageDeleted( + dynamic_cast(event)); break; case B_DEBUGGER_MESSAGE_PRE_SYSCALL: case B_DEBUGGER_MESSAGE_POST_SYSCALL: @@ -277,48 +272,54 @@ printf("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %ld\n", message.origin.team); // not interested break; default: - printf("TeamDebugger for team %ld: unknown message from kernel: " - "%ld\n", fTeamID, messageCode); + printf("TeamDebugger for team %ld: unknown event type: " + "%d\n", fTeamID, event->EventType()); break; } - if (!handled && message.origin.thread >= 0 && message.origin.nub_port >= 0) - continue_thread(message.origin.nub_port, message.origin.thread); + if (!handled && event->ThreadStopped()) + fDebuggerInterface->ContinueThread(event->Thread()); } bool -TeamDebugger::_HandleThreadCreated(const debug_thread_created& message) +TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event) { AutoLocker< ::Team> locker(fTeam); - fTeam->AddThread(message.new_thread); + + ThreadInfo info; + status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(), + info); + if (error == B_OK) + fTeam->AddThread(info); + return false; } bool -TeamDebugger::_HandleThreadDeleted(const debug_thread_deleted& message) +TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event) { AutoLocker< ::Team> locker(fTeam); - fTeam->RemoveThread(message.origin.thread); + fTeam->RemoveThread(event->Thread()); return false; } bool -TeamDebugger::_HandleImageCreated(const debug_image_created& message) +TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event) { AutoLocker< ::Team> locker(fTeam); - fTeam->AddImage(message.info); + fTeam->AddImage(event->GetImageInfo()); return false; } bool -TeamDebugger::_HandleImageDeleted(const debug_image_deleted& message) +TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) { AutoLocker< ::Team> locker(fTeam); - fTeam->RemoveImage(message.info.id); + fTeam->RemoveImage(event->GetImageInfo().ImageID()); return false; } @@ -326,23 +327,15 @@ TeamDebugger::_HandleImageDeleted(const debug_image_deleted& message) void TeamDebugger::_UpdateThreadState(::Thread* thread) { - debug_nub_get_cpu_state message; - message.reply_port = fDebugContext.reply_port; - message.thread = thread->ID(); - - debug_nub_get_cpu_state_reply reply; - - status_t error = send_debug_message(&fDebugContext, - B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply, - sizeof(reply)); + CpuState* state = NULL; + status_t error = fDebuggerInterface->GetCpuState(thread->ID(), state); uint32 newState = THREAD_STATE_UNKNOWN; if (error == B_OK) { - if (reply.error == B_OK) - newState = THREAD_STATE_STOPPED; - else if (reply.error == B_BAD_THREAD_STATE) - newState = THREAD_STATE_RUNNING; - } + newState = THREAD_STATE_STOPPED; + state->RemoveReference(); + } else if (error == B_BAD_THREAD_STATE) + newState = THREAD_STATE_RUNNING; thread->SetState(newState); } diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index 3abe214c61..c824f73c57 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -11,9 +11,11 @@ #include #include +#include "DebugEvent.h" #include "TeamWindow.h" +class DebuggerInterface; class Team; class TeamDebugModel; @@ -36,17 +38,16 @@ private: static status_t _DebugEventListenerEntry(void* data); status_t _DebugEventListener(); - void _HandleDebuggerMessage(int32 messageCode, - const debug_debugger_message_data& message); + void _HandleDebuggerMessage(DebugEvent* event); bool _HandleThreadCreated( - const debug_thread_created& message); + ThreadCreatedEvent* event); bool _HandleThreadDeleted( - const debug_thread_deleted& message); + ThreadDeletedEvent* event); bool _HandleImageCreated( - const debug_image_created& message); + ImageCreatedEvent* event); bool _HandleImageDeleted( - const debug_image_deleted& message); + ImageDeletedEvent* event); void _UpdateThreadState(::Thread* thread); @@ -54,9 +55,8 @@ private: ::Team* fTeam; TeamDebugModel* fDebugModel; team_id fTeamID; - port_id fDebuggerPort; port_id fNubPort; - debug_context fDebugContext; + DebuggerInterface* fDebuggerInterface; thread_id fDebugEventListener; TeamWindow* fTeamWindow; volatile bool fTerminating; diff --git a/src/apps/debugger/ThreadInfo.cpp b/src/apps/debugger/ThreadInfo.cpp new file mode 100644 index 0000000000..c2fcfbb473 --- /dev/null +++ b/src/apps/debugger/ThreadInfo.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "ThreadInfo.h" + + +ThreadInfo::ThreadInfo() + : + fTeam(-1), + fThread(-1), + fName() +{ +} + + +ThreadInfo::ThreadInfo(const ThreadInfo& other) + : + fTeam(other.fTeam), + fThread(other.fThread), + fName(other.fName) +{ +} + + +ThreadInfo::ThreadInfo(team_id team, thread_id thread, const BString& name) + : + fTeam(team), + fThread(thread), + fName(name) +{ +} + + +void +ThreadInfo::SetTo(team_id team, thread_id thread, const BString& name) +{ + fTeam = team; + fThread = thread; + fName = name; +} diff --git a/src/apps/debugger/ThreadInfo.h b/src/apps/debugger/ThreadInfo.h new file mode 100644 index 0000000000..d88dabc33c --- /dev/null +++ b/src/apps/debugger/ThreadInfo.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef THREAD_INFO_H +#define THREAD_INFO_H + +#include +#include + + +class ThreadInfo { +public: + ThreadInfo(); + ThreadInfo(const ThreadInfo& other); + ThreadInfo(team_id team, thread_id thread, + const BString& name); + + void SetTo(team_id team, thread_id thread, + const BString& name); + + team_id TeamID() const { return fTeam; } + thread_id ThreadID() const { return fThread; } + const char* Name() const { return fName.String(); } + +private: + team_id fTeam; + thread_id fThread; + BString fName; +}; + + +#endif // THREAD_INFO_H diff --git a/src/apps/debugger/debugger_interface/DebugEvent.cpp b/src/apps/debugger/debugger_interface/DebugEvent.cpp new file mode 100644 index 0000000000..5538550813 --- /dev/null +++ b/src/apps/debugger/debugger_interface/DebugEvent.cpp @@ -0,0 +1,201 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "DebugEvent.h" + +#include "CpuState.h" + + +// #pragma mark - DebugEvent + + +DebugEvent::DebugEvent(debug_debugger_message eventType, team_id team, + thread_id thread) + : + fEventType(eventType), + fTeam(team), + fThread(thread), + fThreadStopped(false) +{ +} + + +DebugEvent::~DebugEvent() +{ +} + + +void +DebugEvent::SetThreadStopped(bool stopped) +{ + fThreadStopped = stopped; +} + + +// #pragma mark - CpuStateEvent + + +CpuStateEvent::CpuStateEvent(debug_debugger_message eventType, team_id team, + thread_id thread, CpuState* state) + : + DebugEvent(eventType, team, thread), + fCpuState(state) +{ + if (fCpuState != NULL) + fCpuState->AddReference(); +} + + +CpuStateEvent::~CpuStateEvent() +{ + if (fCpuState != NULL) + fCpuState->RemoveReference(); +} + + +// #pragma mark - ThreadDebuggedEvent + + +ThreadDebuggedEvent::ThreadDebuggedEvent(team_id team, thread_id thread) + : + DebugEvent(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, team, thread) +{ +} + + +// #pragma mark - DebuggerCallEvent + + +DebuggerCallEvent::DebuggerCallEvent(team_id team, thread_id thread, + target_addr_t message) + : + DebugEvent(B_DEBUGGER_MESSAGE_DEBUGGER_CALL, team, thread), + fMessage(message) +{ +} + + +// #pragma mark - BreakpointHitEvent + + +BreakpointHitEvent::BreakpointHitEvent(team_id team, thread_id thread, + CpuState* state) + : + CpuStateEvent(B_DEBUGGER_MESSAGE_BREAKPOINT_HIT, team, thread, state) +{ +} + + +// #pragma mark - WatchpointHitEvent + + +WatchpointHitEvent::WatchpointHitEvent(team_id team, thread_id thread, + CpuState* state) + : + CpuStateEvent(B_DEBUGGER_MESSAGE_WATCHPOINT_HIT, team, thread, state) +{ +} + + + +// #pragma mark - SingleStepEvent + + +SingleStepEvent::SingleStepEvent(team_id team, thread_id thread, + CpuState* state) + : + CpuStateEvent(B_DEBUGGER_MESSAGE_SINGLE_STEP, team, thread, state) +{ +} + + +// #pragma mark - ExceptionOccurredEvent + + +ExceptionOccurredEvent::ExceptionOccurredEvent(team_id team, thread_id thread, + uint32 exception) + : + DebugEvent(B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED, team, thread), + fException(exception) +{ +} + + +// #pragma mark - TeamDeletedEvent + + +TeamDeletedEvent::TeamDeletedEvent(team_id team, thread_id thread) + : + DebugEvent(B_DEBUGGER_MESSAGE_TEAM_DELETED, team, thread) +{ +} + + +// #pragma mark - TeamExecEvent + + +TeamExecEvent::TeamExecEvent(team_id team, thread_id thread) + : + DebugEvent(B_DEBUGGER_MESSAGE_TEAM_EXEC, team, thread) +{ +} + + +// #pragma mark - ThreadCreatedEvent + + +ThreadCreatedEvent::ThreadCreatedEvent(team_id team, thread_id thread, + thread_id newThread) + : + DebugEvent(B_DEBUGGER_MESSAGE_THREAD_CREATED, team, thread), + fNewThread(newThread) +{ +} + + +// #pragma mark - ThreadDeletedEvent + + +ThreadDeletedEvent::ThreadDeletedEvent(team_id team, thread_id thread) + : + DebugEvent(B_DEBUGGER_MESSAGE_THREAD_DELETED, team, thread) +{ +} + + +// #pragma mark - ImageCreatedEvent + + +ImageCreatedEvent::ImageCreatedEvent(team_id team, thread_id thread, + const ImageInfo& info) + : + DebugEvent(B_DEBUGGER_MESSAGE_IMAGE_CREATED, team, thread), + fInfo(info) +{ +} + + +// #pragma mark - ImageDeletedEvent + + +ImageDeletedEvent::ImageDeletedEvent(team_id team, thread_id thread, + const ImageInfo& info) + : + DebugEvent(B_DEBUGGER_MESSAGE_IMAGE_DELETED, team, thread), + fInfo(info) +{ +} + + +// #pragma mark - HandedOverEvent + + +HandedOverEvent::HandedOverEvent(team_id team, thread_id thread, + thread_id causingThread) + : + DebugEvent(B_DEBUGGER_MESSAGE_HANDED_OVER, team, thread), + fCausingThread(causingThread) +{ +} diff --git a/src/apps/debugger/debugger_interface/DebugEvent.h b/src/apps/debugger/debugger_interface/DebugEvent.h new file mode 100644 index 0000000000..0cbcb2eef8 --- /dev/null +++ b/src/apps/debugger/debugger_interface/DebugEvent.h @@ -0,0 +1,174 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEBUG_EVENT_H +#define DEBUG_EVENT_H + +#include + +#include "ImageInfo.h" + + +typedef uint64 target_addr_t; + // TODO: Define elsewhere! + +class CpuState; + + +class DebugEvent { +public: + DebugEvent(debug_debugger_message eventType, + team_id team, thread_id thread); + virtual ~DebugEvent(); + + debug_debugger_message EventType() const { return fEventType; } + team_id Team() const { return fTeam; } + thread_id Thread() const { return fThread; } + + bool ThreadStopped() const { return fThreadStopped; } + void SetThreadStopped(bool stopped); + +private: + debug_debugger_message fEventType; + team_id fTeam; + thread_id fThread; + bool fThreadStopped; +}; + + +class CpuStateEvent : public DebugEvent { +public: + CpuStateEvent(debug_debugger_message eventType, + team_id team, thread_id thread, + CpuState* state); + virtual ~CpuStateEvent(); + + CpuState* GetCpuState() const { return fCpuState; } + +private: + CpuState* fCpuState; +}; + + +class ThreadDebuggedEvent : public DebugEvent { +public: + ThreadDebuggedEvent(team_id team, + thread_id thread); +}; + + +class DebuggerCallEvent : public DebugEvent { +public: + DebuggerCallEvent(team_id team, + thread_id thread, target_addr_t message); + + target_addr_t Message() const { return fMessage; } + +private: + target_addr_t fMessage; +}; + + +class BreakpointHitEvent : public CpuStateEvent { +public: + BreakpointHitEvent(team_id team, + thread_id thread, CpuState* state); +}; + + +class WatchpointHitEvent : public CpuStateEvent { +public: + WatchpointHitEvent(team_id team, + thread_id thread, CpuState* state); +}; + + +class SingleStepEvent : public CpuStateEvent { +public: + SingleStepEvent(team_id team, + thread_id thread, CpuState* state); +}; + + +class ExceptionOccurredEvent : public DebugEvent { +public: + ExceptionOccurredEvent(team_id team, + thread_id thread, uint32 exception); + + uint32 Exception() const { return fException; } + +private: + uint32 fException; +}; + + +class TeamDeletedEvent : public DebugEvent { +public: + TeamDeletedEvent(team_id team, + thread_id thread); +}; + + +class TeamExecEvent : public DebugEvent { +public: + TeamExecEvent(team_id team, thread_id thread); +}; + + +class ThreadCreatedEvent : public DebugEvent { +public: + ThreadCreatedEvent(team_id team, + thread_id thread, thread_id newThread); + + thread_id NewThread() const { return fNewThread; } + +private: + thread_id fNewThread; +}; + + +class ThreadDeletedEvent : public DebugEvent { +public: + ThreadDeletedEvent(team_id team, + thread_id thread); +}; + + +class ImageCreatedEvent : public DebugEvent { +public: + ImageCreatedEvent(team_id team, + thread_id thread, const ImageInfo& info); + + const ImageInfo& GetImageInfo() const { return fInfo; } + +private: + ImageInfo fInfo; +}; + + +class ImageDeletedEvent : public DebugEvent { +public: + ImageDeletedEvent(team_id team, + thread_id thread, const ImageInfo& info); + + const ImageInfo& GetImageInfo() const { return fInfo; } + +private: + ImageInfo fInfo; +}; + + +class HandedOverEvent : public DebugEvent { +public: + HandedOverEvent(team_id team, + thread_id thread, thread_id causingThread); + + thread_id CausingThread() const { return fCausingThread; } + +private: + thread_id fCausingThread; +}; + + +#endif // DEBUG_EVENT_H diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp new file mode 100644 index 0000000000..d44fe7a3fd --- /dev/null +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp @@ -0,0 +1,295 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "DebuggerInterface.h" + +#include + +#include + +#include "debug_utils.h" + +#include "CpuState.h" +#include "DebugEvent.h" +#include "ImageInfo.h" +#include "ThreadInfo.h" + + +DebuggerInterface::DebuggerInterface(team_id teamID) + : + fTeamID(teamID), + fDebuggerPort(-1), + fNubPort(-1) +{ + fDebugContext.reply_port = -1; +} + + +DebuggerInterface::~DebuggerInterface() +{ + destroy_debug_context(&fDebugContext); + + Close(); +} + + +status_t +DebuggerInterface::Init() +{ + // create debugger port + char buffer[128]; + snprintf(buffer, sizeof(buffer), "team %ld debugger", fTeamID); + fDebuggerPort = create_port(100, buffer); + if (fDebuggerPort < 0) + return fDebuggerPort; + + // install as team debugger + fNubPort = install_team_debugger(fTeamID, fDebuggerPort); + if (fNubPort < 0) + return fNubPort; + + // init debug context + status_t error = init_debug_context(&fDebugContext, fTeamID, fNubPort); + if (error != B_OK) + return error; + + return B_OK; +} + + +void +DebuggerInterface::Close() +{ + if (fDebuggerPort >= 0) + delete_port(fDebuggerPort); +} + + +status_t +DebuggerInterface::GetNextDebugEvent(DebugEvent*& _event) +{ + while (true) { + debug_debugger_message_data message; + int32 messageCode; + ssize_t size = read_port(fDebuggerPort, &messageCode, &message, + sizeof(message)); + if (size < 0) { + if (size == B_INTERRUPTED) + continue; + return size; + } + + if (message.origin.team != fTeamID) + continue; + + bool ignore = false; + status_t error = _CreateDebugEvent(messageCode, message, ignore, + _event); + if (error != B_OK) + return error; + + if (ignore) { + if (message.origin.thread >= 0 && message.origin.nub_port >= 0) + continue_thread(message.origin.nub_port, message.origin.thread); + continue; + } + + return B_OK; + } +} + + +status_t +DebuggerInterface::SetTeamDebuggingFlags(uint32 flags) +{ + set_team_debugging_flags(fNubPort, flags); + return B_OK; +} + + +status_t +DebuggerInterface::ContinueThread(thread_id thread) +{ + continue_thread(fNubPort, thread); + return B_OK; +} + + +status_t +DebuggerInterface::GetThreadInfos(BObjectList& infos) +{ + thread_info threadInfo; + int32 cookie = 0; + while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) { + ThreadInfo* info = new(std::nothrow) ThreadInfo(threadInfo.team, + threadInfo.thread, threadInfo.name); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +DebuggerInterface::GetImageInfos(BObjectList& infos) +{ + image_info imageInfo; + int32 cookie = 0; + while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) { + ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id, + imageInfo.name); + if (info == NULL || !infos.AddItem(info)) { + delete info; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +DebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info) +{ + thread_info threadInfo; + status_t error = get_thread_info(thread, &threadInfo); + if (error != B_OK) + return error; + + info.SetTo(threadInfo.team, threadInfo.thread, threadInfo.name); + return B_OK; +} + + +status_t +DebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state) +{ + debug_nub_get_cpu_state message; + message.reply_port = fDebugContext.reply_port; + message.thread = thread; + + debug_nub_get_cpu_state_reply reply; + + status_t error = send_debug_message(&fDebugContext, + B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply, + sizeof(reply)); + if (error != B_OK) + return error; + if (reply.error != B_OK) + return reply.error; + + // TODO: Correctly create the state... + CpuState* state = new(std::nothrow) CpuState; + if (state == NULL) + return B_NO_MEMORY; + + _state = state; + return B_OK; +} + + +status_t +DebuggerInterface::_CreateDebugEvent(int32 messageCode, + const debug_debugger_message_data& message, bool& _ignore, + DebugEvent*& _event) +{ + DebugEvent* event = NULL; + + switch (messageCode) { + case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: + event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: + event = new(std::nothrow) DebuggerCallEvent(message.origin.team, + message.origin.thread, + (target_addr_t)message.debugger_call.message); + break; + case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: + event = new(std::nothrow) BreakpointHitEvent(message.origin.team, + message.origin.thread, NULL); + // TODO: CpuState! + break; + case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: + event = new(std::nothrow) WatchpointHitEvent(message.origin.team, + message.origin.thread, NULL); + // TODO: CpuState! + break; + case B_DEBUGGER_MESSAGE_SINGLE_STEP: + event = new(std::nothrow) SingleStepEvent(message.origin.team, + message.origin.thread, NULL); + // TODO: CpuState! + break; + case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: + event = new(std::nothrow) ExceptionOccurredEvent( + message.origin.team, message.origin.thread, + message.exception_occurred.exception); + break; + case B_DEBUGGER_MESSAGE_TEAM_DELETED: + if (message.origin.team != fTeamID) { + _ignore = true; + return B_OK; + } + event = new(std::nothrow) TeamDeletedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_TEAM_EXEC: + if (message.origin.team != fTeamID) { + _ignore = true; + return B_OK; + } + event = new(std::nothrow) TeamExecEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_THREAD_CREATED: + event = new(std::nothrow) ThreadCreatedEvent(message.origin.team, + message.origin.thread, message.thread_created.new_thread); + break; + case B_DEBUGGER_MESSAGE_THREAD_DELETED: + event = new(std::nothrow) ThreadDeletedEvent(message.origin.team, + message.origin.thread); + break; + case B_DEBUGGER_MESSAGE_IMAGE_CREATED: + { + const image_info& info = message.image_created.info; + event = new(std::nothrow) ImageCreatedEvent(message.origin.team, + message.origin.thread, ImageInfo(fTeamID, info.id, info.name)); + break; + } + case B_DEBUGGER_MESSAGE_IMAGE_DELETED: + { + const image_info& info = message.image_deleted.info; + event = new(std::nothrow) ImageDeletedEvent(message.origin.team, + message.origin.thread, ImageInfo(fTeamID, info.id, info.name)); + break; + } + default: + printf("DebuggerInterface for team %ld: unknown message from " + "kernel: %ld\n", fTeamID, messageCode); + // fall through... + case B_DEBUGGER_MESSAGE_TEAM_CREATED: + case B_DEBUGGER_MESSAGE_PRE_SYSCALL: + case B_DEBUGGER_MESSAGE_POST_SYSCALL: + case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: + case B_DEBUGGER_MESSAGE_PROFILER_UPDATE: + case B_DEBUGGER_MESSAGE_HANDED_OVER: + _ignore = true; + return B_OK; + } + + if (event == NULL) + return B_NO_MEMORY; + + if (message.origin.thread >= 0 && message.origin.nub_port >= 0) + event->SetThreadStopped(true); + + _ignore = false; + _event = event; + + return B_OK; +} diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.h b/src/apps/debugger/debugger_interface/DebuggerInterface.h new file mode 100644 index 0000000000..7a5f3600e0 --- /dev/null +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEBUGGER_INTERFACE_H +#define DEBUGGER_INTERFACE_H + +#include + +#include +#include + + +class CpuState; +class DebugEvent; +class ImageInfo; +class ThreadInfo; + + +class DebuggerInterface { +public: + DebuggerInterface(team_id teamID); + ~DebuggerInterface(); + + status_t Init(); + void Close(); + + virtual status_t GetNextDebugEvent(DebugEvent*& _event); + + virtual status_t SetTeamDebuggingFlags(uint32 flags); + + virtual status_t ContinueThread(thread_id thread); + + virtual status_t GetThreadInfos(BObjectList& infos); + virtual status_t GetImageInfos(BObjectList& infos); + + virtual status_t GetThreadInfo(thread_id thread, + ThreadInfo& info); + virtual status_t GetCpuState(thread_id thread, + CpuState*& _state); + // returns a reference to the caller + +private: + status_t _CreateDebugEvent(int32 messageCode, + const debug_debugger_message_data& message, + bool& _ignore, DebugEvent*& _event); + +private: + team_id fTeamID; + port_id fDebuggerPort; + port_id fNubPort; + debug_context fDebugContext; +}; + +#endif // DEBUGGER_INTERFACE_H