* Correctly set debug_origin::nub_port in all concerned functions.
* Now a debugged thread and the debug nub thread are not longer blocking on ports when they receive a SIGKILL[THR] (we couldn't kill a debugged team before). * Small fixes. More correct cleanup when the debug nub thread terminates. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11491 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <debugger.h>
|
#include <debugger.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <ksignal.h>
|
||||||
#include <ksyscalls.h>
|
#include <ksyscalls.h>
|
||||||
#include <sem.h>
|
#include <sem.h>
|
||||||
#include <team.h>
|
#include <team.h>
|
||||||
@@ -33,6 +34,24 @@ static port_id sDefaultDebuggerPort = -1;
|
|||||||
static status_t ensure_debugger_installed(team_id teamID, port_id *port = NULL);
|
static status_t ensure_debugger_installed(team_id teamID, port_id *port = NULL);
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
kill_interruptable_read_port(port_id port, int32 *code, void *buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return read_port_etc(port, code, buffer, bufferSize,
|
||||||
|
B_KILL_CAN_INTERRUPT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
kill_interruptable_write_port(port_id port, int32 code, const void *buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return write_port_etc(port, code, buffer, bufferSize,
|
||||||
|
B_KILL_CAN_INTERRUPT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The team lock must be held.
|
* The team lock must be held.
|
||||||
*/
|
*/
|
||||||
@@ -133,8 +152,8 @@ prepare_thread_stopped_message(debug_thread_stopped &message,
|
|||||||
|
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = nubPort;
|
||||||
message.why = whyStopped;
|
message.why = whyStopped;
|
||||||
message.nub_port = nubPort;
|
|
||||||
message.data = data;
|
message.data = data;
|
||||||
arch_get_debug_cpu_state(&message.cpu_state);
|
arch_get_debug_cpu_state(&message.cpu_state);
|
||||||
}
|
}
|
||||||
@@ -239,8 +258,8 @@ thread_hit_debug_event(uint32 event, const void *message, int32 size,
|
|||||||
// read a command from the debug port
|
// read a command from the debug port
|
||||||
int32 command;
|
int32 command;
|
||||||
debugged_thread_message_data commandMessage;
|
debugged_thread_message_data commandMessage;
|
||||||
ssize_t commandMessageSize = read_port(port, &command,
|
ssize_t commandMessageSize = kill_interruptable_read_port(port,
|
||||||
&commandMessage, sizeof(commandMessage));
|
&command, &commandMessage, sizeof(commandMessage));
|
||||||
if (commandMessageSize < 0) {
|
if (commandMessageSize < 0) {
|
||||||
error = commandMessageSize;
|
error = commandMessageSize;
|
||||||
TRACE(("thread_hit_debug_event(): thread: %ld, failed to "
|
TRACE(("thread_hit_debug_event(): thread: %ld, failed to "
|
||||||
@@ -275,10 +294,8 @@ thread_hit_debug_event(uint32 event, const void *message, int32 size,
|
|||||||
teamDebugInfo.nub_port, additionalData);
|
teamDebugInfo.nub_port, additionalData);
|
||||||
|
|
||||||
// send it
|
// send it
|
||||||
do {
|
error = kill_interruptable_write_port(debuggerPort, event,
|
||||||
error = write_port(debuggerPort, event, &stoppedMessage,
|
&stoppedMessage, sizeof(stoppedMessage));
|
||||||
sizeof(stoppedMessage));
|
|
||||||
} while (error == B_INTERRUPTED);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -322,6 +339,7 @@ user_debug_pre_syscall(uint32 syscall, void *args)
|
|||||||
debug_pre_syscall message;
|
debug_pre_syscall message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
message.syscall = syscall;
|
message.syscall = syscall;
|
||||||
|
|
||||||
// copy the syscall args
|
// copy the syscall args
|
||||||
@@ -356,6 +374,7 @@ user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
|
|||||||
debug_post_syscall message;
|
debug_post_syscall message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
message.start_time = startTime;
|
message.start_time = startTime;
|
||||||
message.end_time = system_time();
|
message.end_time = system_time();
|
||||||
message.return_value = returnValue;
|
message.return_value = returnValue;
|
||||||
@@ -387,7 +406,7 @@ stop_thread(debug_why_stopped whyStopped, void *additionalData)
|
|||||||
|
|
||||||
// prepare the message
|
// prepare the message
|
||||||
debug_thread_stopped message;
|
debug_thread_stopped message;
|
||||||
prepare_thread_stopped_message(message, B_THREAD_NOT_RUNNING, nubPort,
|
prepare_thread_stopped_message(message, whyStopped, nubPort,
|
||||||
additionalData);
|
additionalData);
|
||||||
|
|
||||||
return thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_STOPPED, &message,
|
return thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_STOPPED, &message,
|
||||||
@@ -426,6 +445,7 @@ user_debug_handle_signal(int signal, struct sigaction *handler, bool deadly)
|
|||||||
debug_signal_received message;
|
debug_signal_received message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
message.signal = signal;
|
message.signal = signal;
|
||||||
message.handler = *handler;
|
message.handler = *handler;
|
||||||
message.deadly = deadly;
|
message.deadly = deadly;
|
||||||
@@ -459,6 +479,7 @@ user_debug_team_created(team_id teamID)
|
|||||||
debug_team_created message;
|
debug_team_created message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
message.new_team = teamID;
|
message.new_team = teamID;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_CREATED, &message,
|
||||||
@@ -473,6 +494,7 @@ user_debug_team_deleted(team_id teamID, port_id debuggerPort)
|
|||||||
debug_team_deleted message;
|
debug_team_deleted message;
|
||||||
message.origin.thread = -1;
|
message.origin.thread = -1;
|
||||||
message.origin.team = teamID;
|
message.origin.team = teamID;
|
||||||
|
message.origin.nub_port = -1;
|
||||||
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message,
|
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message,
|
||||||
sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
||||||
// TODO: Would it be OK to wait here?
|
// TODO: Would it be OK to wait here?
|
||||||
@@ -495,6 +517,7 @@ user_debug_thread_created(thread_id threadID)
|
|||||||
debug_thread_created message;
|
debug_thread_created message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
message.new_thread = threadID;
|
message.new_thread = threadID;
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_CREATED, &message,
|
||||||
@@ -532,6 +555,7 @@ user_debug_thread_deleted(team_id teamID, thread_id threadID)
|
|||||||
debug_thread_deleted message;
|
debug_thread_deleted message;
|
||||||
message.origin.thread = threadID;
|
message.origin.thread = threadID;
|
||||||
message.origin.team = teamID;
|
message.origin.team = teamID;
|
||||||
|
message.origin.nub_port = -1;
|
||||||
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED,
|
write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED,
|
||||||
&message, sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
&message, sizeof(message), B_RELATIVE_TIMEOUT, 0);
|
||||||
// TODO: Would it be OK to wait here?
|
// TODO: Would it be OK to wait here?
|
||||||
@@ -554,6 +578,7 @@ user_debug_image_created(const image_info *imageInfo)
|
|||||||
debug_image_created message;
|
debug_image_created message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
memcpy(&message.info, imageInfo, sizeof(image_info));
|
memcpy(&message.info, imageInfo, sizeof(image_info));
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
||||||
@@ -576,6 +601,7 @@ user_debug_image_deleted(const image_info *imageInfo)
|
|||||||
debug_image_deleted message;
|
debug_image_deleted message;
|
||||||
message.origin.thread = thread->id;
|
message.origin.thread = thread->id;
|
||||||
message.origin.team = thread->team->id;
|
message.origin.team = thread->team->id;
|
||||||
|
message.origin.nub_port = thread->team->debug_info.nub_port;
|
||||||
memcpy(&message.info, imageInfo, sizeof(image_info));
|
memcpy(&message.info, imageInfo, sizeof(image_info));
|
||||||
|
|
||||||
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
|
||||||
@@ -583,6 +609,31 @@ user_debug_image_deleted(const image_info *imageInfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
nub_thread_cleanup(struct thread *nubThread)
|
||||||
|
{
|
||||||
|
team_debug_info teamDebugInfo;
|
||||||
|
bool destroyDebugInfo = false;
|
||||||
|
|
||||||
|
cpu_status state = disable_interrupts();
|
||||||
|
GRAB_TEAM_LOCK();
|
||||||
|
|
||||||
|
team_debug_info &info = nubThread->team->debug_info;
|
||||||
|
if (info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED
|
||||||
|
&& info.nub_thread == nubThread->id) {
|
||||||
|
teamDebugInfo = info;
|
||||||
|
clear_team_debug_info(&info);
|
||||||
|
destroyDebugInfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RELEASE_TEAM_LOCK();
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
if (destroyDebugInfo)
|
||||||
|
destroy_team_debug_info(&teamDebugInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
debug_nub_thread(void *)
|
debug_nub_thread(void *)
|
||||||
{
|
{
|
||||||
@@ -606,22 +657,14 @@ debug_nub_thread(void *)
|
|||||||
while (true) {
|
while (true) {
|
||||||
int32 command;
|
int32 command;
|
||||||
debug_nub_message_data message;
|
debug_nub_message_data message;
|
||||||
ssize_t messageSize = read_port(port, &command, &message,
|
ssize_t messageSize = kill_interruptable_read_port(port, &command,
|
||||||
sizeof(message));
|
&message, sizeof(message));
|
||||||
|
|
||||||
if (messageSize < 0) {
|
if (messageSize < 0) {
|
||||||
// The port is not longer valid: If we are still listed in the
|
// The port is not longer valid or we were interrupted by a kill
|
||||||
// team's debug info as nub thread, we need to update that.
|
// signal: If we are still listed in the team's debug info as nub
|
||||||
cpu_status state = disable_interrupts();
|
// thread, we need to update that.
|
||||||
GRAB_TEAM_LOCK();
|
nub_thread_cleanup(nubThread);
|
||||||
|
|
||||||
team_debug_info &info = nubThread->team->debug_info;
|
|
||||||
if (info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED
|
|
||||||
&& info.nub_thread == nubThread->id) {
|
|
||||||
clear_team_debug_info(&info);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASE_TEAM_LOCK();
|
|
||||||
restore_interrupts(state);
|
|
||||||
|
|
||||||
TRACE(("nub thread %ld: terminating: %lx\n", nubThread->id,
|
TRACE(("nub thread %ld: terminating: %lx\n", nubThread->id,
|
||||||
messageSize));
|
messageSize));
|
||||||
@@ -824,8 +867,17 @@ debug_nub_thread(void *)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send the reply, if necessary
|
// send the reply, if necessary
|
||||||
if (sendReply)
|
if (sendReply) {
|
||||||
write_port(replyPort, command, &reply, replySize);
|
status_t error = kill_interruptable_write_port(replyPort, command,
|
||||||
|
&reply, replySize);
|
||||||
|
|
||||||
|
if (error != B_OK) {
|
||||||
|
// The debugger port is either not longer existing or we got
|
||||||
|
// interrupted by a kill signal. In either case we terminate.
|
||||||
|
nub_thread_cleanup(nubThread);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,6 +906,9 @@ TRACE(("install_team_debugger(team: %ld, port: %ld, default: %d, "
|
|||||||
: team_get_team_struct_locked(teamID));
|
: team_get_team_struct_locked(teamID));
|
||||||
|
|
||||||
if (team) {
|
if (team) {
|
||||||
|
// get a real team ID
|
||||||
|
teamID = team->id;
|
||||||
|
|
||||||
if (team == team_get_kernel_team()) {
|
if (team == team_get_kernel_team()) {
|
||||||
// don't allow to debug the kernel
|
// don't allow to debug the kernel
|
||||||
error = B_NOT_ALLOWED;
|
error = B_NOT_ALLOWED;
|
||||||
|
|||||||
Reference in New Issue
Block a user