base: use proper Cpu_session when tracing threads

Up to now it was not possible to trace threads that use a different
Cpu_session rather than env()->cpu_session() (as done by VirtualBox).
This problem is now solved by setting the Cpu_session explicitly when
creating the event logger and attaching the trace control area when
creating the thread.

Fixes #1618.
This commit is contained in:
Josef Söntgen 2015-07-03 16:22:35 +02:00 committed by Norman Feske
parent eaf4150c7b
commit 7e40f5f587
4 changed files with 62 additions and 64 deletions

View File

@ -296,6 +296,11 @@ class Genode::Thread_base
*/
Genode::Cpu_session *_cpu_session;
/**
* Base pointer to Trace::Control area used by this thread
*/
Trace::Control *_trace_control;
/**
* Pointer to primary thread context
*/

View File

@ -33,6 +33,7 @@ struct Genode::Trace::Logger
private:
Thread_capability thread_cap;
Cpu_session *cpu;
Control *control;
bool enabled;
unsigned policy_version;
@ -54,7 +55,7 @@ struct Genode::Trace::Logger
void init_pending(bool val) { pending_init = val; }
void init(Thread_capability);
void init(Thread_capability, Cpu_session*, Control*);
/**
* Log binary data to trace buffer

View File

@ -175,12 +175,19 @@ Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type type, Cpu_session *cpu_session)
:
_cpu_session(cpu_session),
_trace_control(nullptr),
_context(type == REINITIALIZED_MAIN ?
_context : _alloc_context(stack_size, type == MAIN)),
_join_lock(Lock::LOCKED)
{
strncpy(_context->name, name, sizeof(_context->name));
_init_platform_thread(weight, type);
if (_cpu_session) {
Dataspace_capability ds = _cpu_session->trace_control();
if (ds.valid())
_trace_control = env()->rm_session()->attach(ds);
}
}
@ -193,4 +200,12 @@ Thread_base::~Thread_base()
{
_deinit_platform_thread();
_free_context(_context);
/*
* We have to detach the trace control dataspace last because
* we cannot invalidate the pointer used by the Trace::Logger
* from here and any following RPC call will stumple upon the
* detached trace control dataspace.
*/
env()->rm_session()->detach(_trace_control);
}

View File

@ -27,61 +27,6 @@ using namespace Genode;
namespace Genode { bool inhibit_tracing = true; /* cleared by '_main' */ }
/**
* Return trace-control structure for specified thread
*/
static Trace::Control *trace_control(Cpu_session *cpu, Rm_session *rm,
Thread_capability thread_cap)
{
struct Area
{
Cpu_session &cpu;
Rm_session &rm;
Dataspace_capability ds;
size_t const size;
Trace::Control * const base;
Area(Cpu_session &cpu, Rm_session &rm)
:
cpu(cpu), rm(rm),
ds(cpu.trace_control()),
size(ds.valid() ? Dataspace_client(ds).size() : 0),
base(ds.valid() ? (Trace::Control * const)rm.attach(ds) : 0)
{ }
Trace::Control *slot(Thread_capability thread)
{
if (!thread.valid() || base == 0)
return 0;
unsigned const index = cpu.trace_control_index(thread);
if ((index + 1)*sizeof(Trace::Control) > size) {
PERR("thread control index is out of range");
return 0;
}
return base + index;
}
};
/**
* We have to construct the Area object explicitly because otherwise
* the destructor may use a invalid capability. This is mainly the
* case by e.g. forked processes in noux.
*/
static char area_mem[sizeof (Area)];
static Area *area = 0;
if (!area) {
area = construct_at<Area>(area_mem, *cpu, *rm);
}
return area->slot(thread_cap);
}
/*******************
** Trace::Logger **
*******************/
@ -129,7 +74,7 @@ bool Trace::Logger::_evaluate_control()
Control::Inhibit_guard guard(*control);
/* obtain policy */
Dataspace_capability policy_ds = env()->cpu_session()->trace_policy(thread_cap);
Dataspace_capability policy_ds = cpu->trace_policy(thread_cap);
if (!policy_ds.valid()) {
PWRN("could not obtain trace policy");
@ -155,7 +100,7 @@ bool Trace::Logger::_evaluate_control()
/* obtain buffer */
buffer = 0;
Dataspace_capability buffer_ds = env()->cpu_session()->trace_buffer(thread_cap);
Dataspace_capability buffer_ds = cpu->trace_buffer(thread_cap);
if (!buffer_ds.valid()) {
PWRN("could not obtain trace buffer");
@ -185,17 +130,31 @@ void Trace::Logger::log(char const *msg, size_t len)
}
void Trace::Logger::init(Thread_capability thread)
void Trace::Logger::init(Thread_capability thread, Cpu_session *cpu_session,
Trace::Control *attached_control)
{
thread_cap = thread;
if (!attached_control)
return;
control = trace_control(env()->cpu_session(), env()->rm_session(), thread);
thread_cap = thread;
cpu = cpu_session;
unsigned const index = cpu->trace_control_index(thread);
Dataspace_capability ds = cpu->trace_control();
size_t size = Dataspace_client(ds).size();
if ((index + 1)*sizeof(Trace::Control) > size) {
PERR("thread control index is out of range");
return;
}
control = attached_control + index;
}
Trace::Logger::Logger()
:
control(0),
cpu(nullptr),
control(nullptr),
enabled(false),
policy_version(0),
policy_module(0),
@ -218,6 +177,9 @@ static Trace::Logger *main_trace_logger()
}
static Trace::Control *main_trace_control;
Trace::Logger *Thread_base::_logger()
{
if (inhibit_tracing)
@ -235,9 +197,24 @@ Trace::Logger *Thread_base::_logger()
/* lazily initialize trace object */
if (!logger->is_initialized()) {
logger->init_pending(true);
logger->init(myself ? myself->_thread_cap : env()->parent()->main_thread_cap());
Thread_capability thread_cap = myself ? myself->_thread_cap
: env()->parent()->main_thread_cap();
Genode::Cpu_session *cpu = myself ? myself->_cpu_session
: env()->cpu_session();
if (!cpu) cpu = env()->cpu_session();
if (!myself)
if (!main_trace_control) {
Dataspace_capability ds = env()->cpu_session()->trace_control();
if (ds.valid())
main_trace_control = env()->rm_session()->attach(ds);
}
logger->init(thread_cap, cpu,
myself ? myself->_trace_control : main_trace_control);
}
return logger;
}