blob: 8693949cc77574ceb74a1db666fecb0eaeb43273 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <err.h>
#include <platform.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <trace.h>
#include <magenta/port_dispatcher.h>
#include <magenta/magenta.h>
#include <magenta/job_dispatcher.h>
#include <magenta/process_dispatcher.h>
#include <magenta/thread_dispatcher.h>
#include "syscalls_priv.h"
#define LOCAL_TRACE 0
static mx_status_t object_unbind_exception_port(mx_handle_t obj_handle, bool debugger, bool quietly) {
// TODO(MG-968): check rights once appropriate right is determined
if (obj_handle == MX_HANDLE_INVALID) {
// TODO(MG-987): handle for system exception
if (debugger || quietly)
return MX_ERR_INVALID_ARGS;
return ResetSystemExceptionPort()
? MX_OK
: MX_ERR_BAD_STATE; // No port was bound.
}
auto up = ProcessDispatcher::GetCurrent();
mxtl::RefPtr<Dispatcher> dispatcher;
auto status = up->GetDispatcher(obj_handle, &dispatcher);
if (status != MX_OK)
return status;
auto job = DownCastDispatcher<JobDispatcher>(&dispatcher);
if (job) {
if (debugger)
return MX_ERR_INVALID_ARGS;
return job->ResetExceptionPort(quietly)
? MX_OK
: MX_ERR_BAD_STATE; // No port was bound.
}
auto process = DownCastDispatcher<ProcessDispatcher>(&dispatcher);
if (process) {
return process->ResetExceptionPort(debugger, quietly)
? MX_OK
: MX_ERR_BAD_STATE; // No port was bound.
}
auto thread = DownCastDispatcher<ThreadDispatcher>(&dispatcher);
if (thread) {
if (debugger)
return MX_ERR_INVALID_ARGS;
return thread->ResetExceptionPort(quietly)
? MX_OK
: MX_ERR_BAD_STATE; // No port was bound.
}
return MX_ERR_WRONG_TYPE;
}
static mx_status_t task_bind_exception_port(mx_handle_t obj_handle, mx_handle_t eport_handle, uint64_t key, bool debugger) {
// TODO(MG-968): check rights once appropriate right is determined
auto up = ProcessDispatcher::GetCurrent();
mxtl::RefPtr<PortDispatcher> port;
mx_status_t status = up->GetDispatcher(eport_handle, &port);
if (status != MX_OK)
return status;
mxtl::RefPtr<ExceptionPort> eport;
if (obj_handle == MX_HANDLE_INVALID) {
// TODO(MG-987): handle for system exception
if (debugger)
return MX_ERR_INVALID_ARGS;
status = ExceptionPort::Create(ExceptionPort::Type::SYSTEM,
mxtl::move(port), key, &eport);
if (status != MX_OK)
return status;
status = SetSystemExceptionPort(eport);
if (status != MX_OK)
return status;
eport->SetSystemTarget();
return MX_OK;
}
mxtl::RefPtr<Dispatcher> dispatcher;
status = up->GetDispatcher(obj_handle, &dispatcher);
if (status != MX_OK)
return status;
auto job = DownCastDispatcher<JobDispatcher>(&dispatcher);
if (job) {
if (debugger)
return MX_ERR_INVALID_ARGS;
status = ExceptionPort::Create(ExceptionPort::Type::JOB,
mxtl::move(port), key, &eport);
if (status != MX_OK)
return status;
status = job->SetExceptionPort(eport);
if (status != MX_OK)
return status;
eport->SetTarget(job);
return MX_OK;
}
auto process = DownCastDispatcher<ProcessDispatcher>(&dispatcher);
if (process) {
ExceptionPort::Type type;
if (debugger)
type = ExceptionPort::Type::DEBUGGER;
else
type = ExceptionPort::Type::PROCESS;
status = ExceptionPort::Create(type, mxtl::move(port), key, &eport);
if (status != MX_OK)
return status;
status = process->SetExceptionPort(eport);
if (status != MX_OK)
return status;
eport->SetTarget(process);
return MX_OK;
}
auto thread = DownCastDispatcher<ThreadDispatcher>(&dispatcher);
if (thread) {
if (debugger)
return MX_ERR_INVALID_ARGS;
status = ExceptionPort::Create(ExceptionPort::Type::THREAD,
mxtl::move(port), key, &eport);
if (status != MX_OK)
return status;
status = thread->SetExceptionPort(eport);
if (status != MX_OK)
return status;
eport->SetTarget(thread);
return MX_OK;
}
return MX_ERR_WRONG_TYPE;
}
mx_status_t sys_task_bind_exception_port(mx_handle_t obj_handle, mx_handle_t eport_handle,
uint64_t key, uint32_t options) {
LTRACE_ENTRY;
if (eport_handle == MX_HANDLE_INVALID) {
if (options & ~(MX_EXCEPTION_PORT_DEBUGGER + MX_EXCEPTION_PORT_UNBIND_QUIETLY))
return MX_ERR_INVALID_ARGS;
} else {
if (options & ~MX_EXCEPTION_PORT_DEBUGGER)
return MX_ERR_INVALID_ARGS;
}
bool debugger = (options & MX_EXCEPTION_PORT_DEBUGGER) != 0;
if (eport_handle == MX_HANDLE_INVALID) {
bool quietly = (options & MX_EXCEPTION_PORT_UNBIND_QUIETLY) != 0;
return object_unbind_exception_port(obj_handle, debugger, quietly);
} else {
return task_bind_exception_port(obj_handle, eport_handle, key, debugger);
}
}
mx_status_t sys_task_resume(mx_handle_t handle, uint32_t options) {
LTRACE_ENTRY;
if (options & ~(MX_RESUME_EXCEPTION | MX_RESUME_TRY_NEXT))
return MX_ERR_INVALID_ARGS;
if (!(options & MX_RESUME_EXCEPTION)) {
// These options are only valid with MX_RESUME_EXCEPTION.
if (options & MX_RESUME_TRY_NEXT)
return MX_ERR_INVALID_ARGS;
}
auto up = ProcessDispatcher::GetCurrent();
// TODO(MG-968): Rights checking here
mxtl::RefPtr<Dispatcher> dispatcher;
auto status = up->GetDispatcher(handle, &dispatcher);
if (status != MX_OK)
return status;
auto thread = DownCastDispatcher<ThreadDispatcher>(&dispatcher);
if (!thread)
return MX_ERR_WRONG_TYPE;
if (options & MX_RESUME_EXCEPTION) {
ThreadDispatcher::ExceptionStatus estatus;
if (options & MX_RESUME_TRY_NEXT) {
estatus = ThreadDispatcher::ExceptionStatus::TRY_NEXT;
} else {
estatus = ThreadDispatcher::ExceptionStatus::RESUME;
}
return thread->MarkExceptionHandled(estatus);
} else {
if (options != 0) {
return MX_ERR_INVALID_ARGS;
}
return thread->Resume();
}
}