Skip to content

Commit

Permalink
[kernel][exceptions] Add process debugger exception port.
Browse files Browse the repository at this point in the history
To specify setting the debugger exception port of a process,
pass MX_EXCEPTION_PORT_DEBUGGER as an option to
mx_object_bind_exception_port.

Change-Id: I47a2959b9ce24c5713dd873a9c8672eb9d36146a
  • Loading branch information
xdje42 committed Sep 22, 2016
1 parent c709d97 commit c9b120b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 18 deletions.
12 changes: 12 additions & 0 deletions kernel/lib/magenta/exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ static status_t try_exception_handler(mxtl::RefPtr<ExceptionPort> eport, UserThr
return status;
}

static status_t try_debugger_exception_handler(UserThread* thread,
const mx_exception_report_t* report,
const arch_exception_context_t* arch_context,
bool* processed) {
LTRACE_ENTRY;
return try_exception_handler(thread->process()->debugger_exception_port(), thread, report, arch_context, processed);
}

static status_t try_thread_exception_handler(UserThread* thread,
const mx_exception_report_t* report,
const arch_exception_context_t* arch_context,
Expand Down Expand Up @@ -118,6 +126,10 @@ status_t magenta_exception_handler(uint exception_type,
mx_exception_report_t report;
build_exception_report(&report, thread, exception_type, context, ip);

status = try_debugger_exception_handler(thread, &report, context, &processed);
if (status == NO_ERROR)
return NO_ERROR;

status = try_thread_exception_handler(thread, &report, context, &processed);
if (status == NO_ERROR)
return NO_ERROR;
Expand Down
6 changes: 4 additions & 2 deletions kernel/lib/magenta/include/magenta/process_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ class ProcessDispatcher : public Dispatcher
status_t CreateUserThread(mxtl::StringPiece name, uint32_t flags, mxtl::RefPtr<UserThread>* user_thread);

// exception handling support
status_t SetExceptionPort(mxtl::RefPtr<ExceptionPort> eport);
void ResetExceptionPort();
status_t SetExceptionPort(mxtl::RefPtr<ExceptionPort> eport, bool debugger);
void ResetExceptionPort(bool debugger);
mxtl::RefPtr<ExceptionPort> exception_port();
mxtl::RefPtr<ExceptionPort> debugger_exception_port();

// The following two methods can be slow and innacurrate and should only be
// called from diagnostics code.
Expand Down Expand Up @@ -218,6 +219,7 @@ class ProcessDispatcher : public Dispatcher
int retcode_ = 0;

mxtl::RefPtr<ExceptionPort> exception_port_;
mxtl::RefPtr<ExceptionPort> debugger_exception_port_;
Mutex exception_lock_;

uint32_t bad_handle_policy_ = MX_POLICY_BAD_HANDLE_IGNORE;
Expand Down
27 changes: 21 additions & 6 deletions kernel/lib/magenta/process_dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,29 +387,44 @@ status_t ProcessDispatcher::CreateUserThread(mxtl::StringPiece name, uint32_t fl
return NO_ERROR;
}

status_t ProcessDispatcher::SetExceptionPort(mxtl::RefPtr<ExceptionPort> eport) {
status_t ProcessDispatcher::SetExceptionPort(mxtl::RefPtr<ExceptionPort> eport, bool debugger) {
// Lock both |state_lock_| and |exception_lock_| to ensure the process
// doesn't transition to dead while we're setting the exception handler.
AutoLock state_lock(&state_lock_);
AutoLock excp_lock(&exception_lock_);
if (state_ == State::DEAD)
return ERR_NOT_FOUND; // TODO(dje): ?
if (exception_port_)
return ERR_BAD_STATE; // TODO(dje): ?
exception_port_ = eport;
if (debugger) {
if (debugger_exception_port_)
return ERR_BAD_STATE; // TODO(dje): ?
debugger_exception_port_ = eport;
} else {
if (exception_port_)
return ERR_BAD_STATE; // TODO(dje): ?
exception_port_ = eport;
}
return NO_ERROR;
}

void ProcessDispatcher::ResetExceptionPort() {
void ProcessDispatcher::ResetExceptionPort(bool debugger) {
AutoLock lock(&exception_lock_);
exception_port_.reset();
if (debugger) {
debugger_exception_port_.reset();
} else {
exception_port_.reset();
}
}

mxtl::RefPtr<ExceptionPort> ProcessDispatcher::exception_port() {
AutoLock lock(&exception_lock_);
return exception_port_;
}

mxtl::RefPtr<ExceptionPort> ProcessDispatcher::debugger_exception_port() {
AutoLock lock(&exception_lock_);
return debugger_exception_port_;
}

void ProcessDispatcher::AddProcess(ProcessDispatcher* process) {
// Don't call any method of |process|, it is not yet fully constructed.
AutoLock lock(&global_process_list_mutex_);
Expand Down
23 changes: 16 additions & 7 deletions kernel/lib/syscalls/syscalls_exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@

#define LOCAL_TRACE 0

static mx_status_t object_unbind_exception_port(mx_handle_t obj_handle) {
static mx_status_t object_unbind_exception_port(mx_handle_t obj_handle, bool debugger) {
//TODO: check rights once appropriate right is determined

if (obj_handle == MX_HANDLE_INVALID) {
//TODO: handle for system exception
if (debugger)
return ERR_INVALID_ARGS;
ResetSystemExceptionPort();
return NO_ERROR;
}
Expand All @@ -49,20 +51,22 @@ static mx_status_t object_unbind_exception_port(mx_handle_t obj_handle) {

auto process = dispatcher->get_specific<ProcessDispatcher>();
if (process) {
process->ResetExceptionPort();
process->ResetExceptionPort(debugger);
return NO_ERROR;
}

auto thread = dispatcher->get_specific<ThreadDispatcher>();
if (thread) {
if (debugger)
return ERR_INVALID_ARGS;
thread->ResetExceptionPort();
return NO_ERROR;
}

return ERR_WRONG_TYPE;
}

static mx_status_t object_bind_exception_port(mx_handle_t obj_handle, mx_handle_t eport_handle, uint64_t key) {
static mx_status_t object_bind_exception_port(mx_handle_t obj_handle, mx_handle_t eport_handle, uint64_t key, bool debugger) {
//TODO: check rights once appropriate right is determined
auto up = ProcessDispatcher::GetCurrent();

Expand All @@ -78,6 +82,8 @@ static mx_status_t object_bind_exception_port(mx_handle_t obj_handle, mx_handle_

if (obj_handle == MX_HANDLE_INVALID) {
//TODO: handle for system exception
if (debugger)
return ERR_INVALID_ARGS;
return SetSystemExceptionPort(mxtl::move(eport));
}

Expand All @@ -88,11 +94,13 @@ static mx_status_t object_bind_exception_port(mx_handle_t obj_handle, mx_handle_

auto process = dispatcher->get_specific<ProcessDispatcher>();
if (process) {
return process->SetExceptionPort(mxtl::move(eport));
return process->SetExceptionPort(mxtl::move(eport), debugger);
}

auto thread = dispatcher->get_specific<ThreadDispatcher>();
if (thread) {
if (debugger)
return ERR_INVALID_ARGS;
return thread->SetExceptionPort(mxtl::move(eport));
}

Expand All @@ -103,13 +111,14 @@ mx_status_t sys_object_bind_exception_port(mx_handle_t obj_handle, mx_handle_t e
uint64_t key, uint32_t options) {
LTRACE_ENTRY;

if (options != 0)
if (options & ~MX_EXCEPTION_PORT_DEBUGGER)
return ERR_INVALID_ARGS;
bool debugger = (options & MX_EXCEPTION_PORT_DEBUGGER) != 0;

if (eport_handle == MX_HANDLE_INVALID) {
return object_unbind_exception_port(obj_handle);
return object_unbind_exception_port(obj_handle, debugger);
} else {
return object_bind_exception_port(obj_handle, eport_handle, key);
return object_bind_exception_port(obj_handle, eport_handle, key, debugger);
}
}

Expand Down
5 changes: 5 additions & 0 deletions system/public/magenta/syscalls-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ typedef enum {
// let any additional exception handlers (eg, system after process) take a shot
// at it, and if there are no additional handlers, the thread will terminate

// Flags for mx_object_bind_exception_port.
#define MX_EXCEPTION_PORT_DEBUGGER (1)
// When binding an exception port to a process, set the process's debugger
// exception port.

// Valid topics for mx_object_get_info.
typedef enum {
MX_INFO_HANDLE_VALID = 1,
Expand Down
7 changes: 4 additions & 3 deletions system/utest/debugger/debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,9 @@ static bool debugger_test(void)
inferior = mx_handle_duplicate(inferior, MX_RIGHT_SAME_RIGHTS);
ASSERT_GT(inferior, 0, "mx_handle_duplicate failed");

// TODO(dje): Set the debug exception port when available.
mx_handle_t eport = tu_io_port_create(0);
status = mx_object_bind_exception_port(inferior, eport, 0, 0);
status = mx_object_bind_exception_port(inferior, eport, 0,
MX_EXCEPTION_PORT_DEBUGGER);
EXPECT_EQ(status, NO_ERROR, "error setting exception port");
unittest_printf("Attached to inferior\n");

Expand Down Expand Up @@ -486,7 +486,8 @@ static bool debugger_test(void)
unittest_printf("wait-inf thread done\n");

// TODO(dje): detach-on-close
status = mx_object_bind_exception_port(inferior, MX_HANDLE_INVALID, 0, 0);
status = mx_object_bind_exception_port(inferior, MX_HANDLE_INVALID, 0,
MX_EXCEPTION_PORT_DEBUGGER);
EXPECT_EQ(status, NO_ERROR, "error resetting exception port");
tu_handle_close(eport);
tu_handle_close(inferior);
Expand Down
14 changes: 14 additions & 0 deletions system/utest/exception/exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,20 @@ static bool thread_handler_test(void)
END_TEST;
}

static bool debugger_handler_test(void)
{
BEGIN_TEST;
unittest_printf("debugger exception handler basic test\n");

mx_handle_t child, our_pipe;
start_test_child(&child, &our_pipe);
mx_handle_t eport = tu_io_port_create(0);
tu_set_exception_port(child, eport, 0, MX_EXCEPTION_PORT_DEBUGGER);

finish_basic_test("debugger", child, eport, our_pipe, MSG_CRASH);
END_TEST;
}

static bool process_gone_notification_test(void)
{
BEGIN_TEST;
Expand Down

0 comments on commit c9b120b

Please sign in to comment.