base: User-level tracing support
This commit is contained in:
parent
a2b15349fd
commit
fe4a6d7d81
|
@ -20,12 +20,13 @@ SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
|
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
|
||||||
SRC_CC += env/utcb.cc
|
SRC_CC += env/utcb.cc
|
||||||
SRC_CC += lock/cmpxchg.cc
|
SRC_CC += lock/cmpxchg.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
||||||
|
|
||||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
|
|
|
@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc
|
SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
|
|
|
@ -20,9 +20,11 @@ SRC_CC += lock/lock.cc
|
||||||
SRC_CC += env/spin_lock.cc env/cap_map.cc
|
SRC_CC += env/spin_lock.cc env/cap_map.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
|
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
vpath %.cc $(BASE_DIR)/src/base
|
vpath %.cc $(BASE_DIR)/src/base
|
||||||
|
|
|
@ -182,7 +182,8 @@ void Thread_base::name(char *dst, size_t dst_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread_base *Thread_base::myself() {
|
Thread_base *Thread_base::myself()
|
||||||
|
{
|
||||||
using namespace Fiasco;
|
using namespace Fiasco;
|
||||||
|
|
||||||
return reinterpret_cast<Thread_base*>(l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ]);
|
return reinterpret_cast<Thread_base*>(l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ]);
|
||||||
|
|
|
@ -18,9 +18,11 @@ SRC_CC += console/console.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread_bootstrap.cc
|
SRC_CC += thread/thread_bootstrap.cc thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
vpath %.cc $(BASE_DIR)/src/base
|
vpath %.cc $(BASE_DIR)/src/base
|
||||||
|
|
|
@ -19,11 +19,13 @@ SRC_CC += lock/lock.cc
|
||||||
SRC_CC += env/rm_session_mmap.cc env/debug.cc
|
SRC_CC += env/rm_session_mmap.cc env/debug.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
|
SRC_CC += thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
|
||||||
INC_DIR += $(REP_DIR)/src/base/ipc
|
INC_DIR += $(REP_DIR)/src/base/ipc
|
||||||
INC_DIR += $(REP_DIR)/src/base/env
|
INC_DIR += $(REP_DIR)/src/base/env
|
||||||
INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
|
INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
vpath %.cc $(BASE_DIR)/src/base
|
vpath %.cc $(BASE_DIR)/src/base
|
||||||
|
|
|
@ -28,7 +28,7 @@ INC_DIR += $(REP_DIR)/src/core/include \
|
||||||
$(REP_DIR)/src/platform \
|
$(REP_DIR)/src/platform \
|
||||||
$(REP_DIR)/src/base/ipc \
|
$(REP_DIR)/src/base/ipc \
|
||||||
$(REP_DIR)/src/base/env \
|
$(REP_DIR)/src/base/env \
|
||||||
$(REP_DIR)/src/base/console
|
$(REP_DIR)/src/base/console \
|
||||||
|
|
||||||
HOST_INC_DIR += /usr/include
|
HOST_INC_DIR += /usr/include
|
||||||
|
|
||||||
|
@ -50,4 +50,5 @@ vpath signal_session_component.cc $(GEN_CORE_DIR)
|
||||||
vpath signal_source_component.cc $(GEN_CORE_DIR)
|
vpath signal_source_component.cc $(GEN_CORE_DIR)
|
||||||
vpath core_printf.cc $(BASE_DIR)/src/base/console
|
vpath core_printf.cc $(BASE_DIR)/src/base/console
|
||||||
vpath thread.cc $(BASE_DIR)/src/base/thread
|
vpath thread.cc $(BASE_DIR)/src/base/thread
|
||||||
|
vpath trace.cc $(BASE_DIR)/src/base/thread
|
||||||
vpath %.cc $(PRG_DIR)
|
vpath %.cc $(PRG_DIR)
|
||||||
|
|
|
@ -18,9 +18,11 @@ SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc
|
SRC_CC += server/server.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_context.cc
|
SRC_CC += thread/thread.cc thread/thread_context.cc thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
vpath %.cc $(BASE_DIR)/src/base
|
vpath %.cc $(BASE_DIR)/src/base
|
||||||
|
|
|
@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
|
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
|
|
|
@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc
|
||||||
SRC_CC += lock/lock.cc
|
SRC_CC += lock/lock.cc
|
||||||
SRC_CC += signal/signal.cc signal/common.cc
|
SRC_CC += signal/signal.cc signal/common.cc
|
||||||
SRC_CC += server/server.cc server/common.cc
|
SRC_CC += server/server.cc server/common.cc
|
||||||
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
|
SRC_CC += thread/thread.cc thread/trace.cc thread/thread_bootstrap.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/base/lock
|
INC_DIR += $(REP_DIR)/src/base/lock
|
||||||
|
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||||
|
|
||||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||||
vpath %.cc $(REP_DIR)/src/base
|
vpath %.cc $(REP_DIR)/src/base
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include <base/exception.h>
|
#include <base/exception.h>
|
||||||
#include <base/lock.h>
|
#include <base/lock.h>
|
||||||
#include <base/native_types.h>
|
#include <base/native_types.h>
|
||||||
|
#include <base/trace/logger.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
|
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
|
||||||
#include <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
|
#include <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
|
||||||
|
@ -259,6 +260,17 @@ namespace Genode {
|
||||||
*/
|
*/
|
||||||
Genode::Lock _join_lock;
|
Genode::Lock _join_lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Trace::Logger _trace_logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return 'Trace::Logger' instance of calling thread
|
||||||
|
*
|
||||||
|
* This function is used by the tracing framework internally.
|
||||||
|
*/
|
||||||
|
static Trace::Logger *_logger();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -355,6 +367,22 @@ namespace Genode {
|
||||||
* undefined behaviour.
|
* undefined behaviour.
|
||||||
*/
|
*/
|
||||||
void join();
|
void join();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log null-terminated string as trace event
|
||||||
|
*/
|
||||||
|
static void trace(char const *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log binary data as trace event
|
||||||
|
*/
|
||||||
|
static void trace(char const *, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log trace event as defined in base/trace.h
|
||||||
|
*/
|
||||||
|
template <typename EVENT>
|
||||||
|
static void trace(EVENT const *event) { _logger()->log(event); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* \brief Event tracing infrastructure
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__TRACE__BUFFER_H_
|
||||||
|
#define _INCLUDE__BASE__TRACE__BUFFER_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
#include <base/thread.h>
|
||||||
|
#include <cpu_session/cpu_session.h>
|
||||||
|
|
||||||
|
namespace Genode { namespace Trace { class Buffer; } }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer shared between CPU client thread and TRACE client
|
||||||
|
*/
|
||||||
|
class Genode::Trace::Buffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned volatile _head_offset; /* in bytes, relative to 'entries' */
|
||||||
|
unsigned volatile _size; /* in bytes */
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry _entries[0];
|
||||||
|
|
||||||
|
Entry *_head_entry() { return (Entry *)((addr_t)_entries + _head_offset); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'entries' member marks the beginning of the trace buffer
|
||||||
|
* entries. No other member variables must follow.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
** Functions called from the CPU client **
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
void init(size_t size)
|
||||||
|
{
|
||||||
|
_head_offset = 0;
|
||||||
|
|
||||||
|
/* compute number of bytes available for tracing data */
|
||||||
|
size_t const header_size = (addr_t)&_entries - (addr_t)this;
|
||||||
|
|
||||||
|
_size = size - header_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *reserve(size_t len)
|
||||||
|
{
|
||||||
|
if (_head_offset + sizeof(Entry) + len <= _size)
|
||||||
|
return _head_entry()->data;
|
||||||
|
|
||||||
|
/* mark last entry with len 0 and wrap */
|
||||||
|
_head_entry()->len = 0;
|
||||||
|
_head_offset = 0;
|
||||||
|
|
||||||
|
return _head_entry()->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit(size_t len)
|
||||||
|
{
|
||||||
|
_head_entry()->len = len;
|
||||||
|
|
||||||
|
/* advance head offset, wrap when reaching buffer boundary */
|
||||||
|
_head_offset += sizeof(Entry) + len;
|
||||||
|
if (_head_offset == _size)
|
||||||
|
_head_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
** Functions called from the TRACE client **
|
||||||
|
********************************************/
|
||||||
|
|
||||||
|
addr_t entries() const { return (addr_t)_entries; }
|
||||||
|
addr_t head_offset() const { return (addr_t)_head_offset; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__TRACE__BUFFER_H_ */
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* \brief Trace-event definitions
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__TRACE__EVENTS_H_
|
||||||
|
#define _INCLUDE__BASE__TRACE__EVENTS_H_
|
||||||
|
|
||||||
|
#include <base/thread.h>
|
||||||
|
#include <base/trace/policy.h>
|
||||||
|
|
||||||
|
namespace Genode { namespace Trace {
|
||||||
|
struct Rpc_call;
|
||||||
|
struct Rpc_returned;
|
||||||
|
struct Rpc_dispatch;
|
||||||
|
struct Rpc_reply;
|
||||||
|
struct Signal_submit;
|
||||||
|
struct Signal_received;
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Rpc_call
|
||||||
|
{
|
||||||
|
char const *rpc_name;
|
||||||
|
Msgbuf_base const &msg;
|
||||||
|
|
||||||
|
Rpc_call(char const *rpc_name, Msgbuf_base const &msg)
|
||||||
|
: rpc_name(rpc_name), msg(msg)
|
||||||
|
{
|
||||||
|
Thread_base::trace(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.rpc_call(dst, rpc_name, msg); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Rpc_returned
|
||||||
|
{
|
||||||
|
char const *rpc_name;
|
||||||
|
Msgbuf_base const &msg;
|
||||||
|
|
||||||
|
Rpc_returned(char const *rpc_name, Msgbuf_base const &msg)
|
||||||
|
: rpc_name(rpc_name), msg(msg)
|
||||||
|
{
|
||||||
|
Thread_base::trace(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.rpc_returned(dst, rpc_name, msg); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Rpc_dispatch
|
||||||
|
{
|
||||||
|
char const *rpc_name;
|
||||||
|
Rpc_object_base const &obj;
|
||||||
|
Msgbuf_base const &msg;
|
||||||
|
|
||||||
|
Rpc_dispatch(char const *rpc_name, Rpc_object_base const &obj,
|
||||||
|
Msgbuf_base const &msg)
|
||||||
|
:
|
||||||
|
rpc_name(rpc_name), obj(obj), msg(msg)
|
||||||
|
{
|
||||||
|
Thread_base::trace(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.rpc_dispatch(dst, rpc_name, obj, msg); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Rpc_reply
|
||||||
|
{
|
||||||
|
char const *rpc_name;
|
||||||
|
Rpc_object_base const &obj;
|
||||||
|
Msgbuf_base const &msg;
|
||||||
|
|
||||||
|
Rpc_reply(char const *rpc_name, Rpc_object_base const &obj,
|
||||||
|
Msgbuf_base const &msg)
|
||||||
|
:
|
||||||
|
rpc_name(rpc_name), obj(obj), msg(msg)
|
||||||
|
{
|
||||||
|
Thread_base::trace(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.rpc_reply(dst, rpc_name, obj, msg); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Signal_submit
|
||||||
|
{
|
||||||
|
unsigned const num;
|
||||||
|
|
||||||
|
Signal_submit(unsigned const num) : num(num)
|
||||||
|
{ Thread_base::trace(this); }
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.signal_submit(dst, num); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Trace::Signal_received
|
||||||
|
{
|
||||||
|
Signal const &signal;;
|
||||||
|
|
||||||
|
Signal_received(Signal const &signal) : signal(signal)
|
||||||
|
{ Thread_base::trace(this); }
|
||||||
|
|
||||||
|
size_t generate(Policy_module &policy, char *dst) const {
|
||||||
|
return policy.signal_received(dst, signal); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__TRACE__EVENTS_H_ */
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* \brief Event tracing infrastructure
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__TRACE__LOGGER_H_
|
||||||
|
#define _INCLUDE__BASE__TRACE__LOGGER_H_
|
||||||
|
|
||||||
|
#include <base/trace/buffer.h>
|
||||||
|
#include <cpu_session/cpu_session.h>
|
||||||
|
|
||||||
|
namespace Genode { namespace Trace {
|
||||||
|
|
||||||
|
class Control;
|
||||||
|
class Policy_module;
|
||||||
|
class Logger;
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Facility for logging events to a thread-specific buffer
|
||||||
|
*/
|
||||||
|
struct Genode::Trace::Logger
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Thread_capability thread_cap;
|
||||||
|
Control *control;
|
||||||
|
bool enabled;
|
||||||
|
unsigned policy_version;
|
||||||
|
Policy_module *policy_module;
|
||||||
|
Buffer *buffer;
|
||||||
|
size_t max_event_size;
|
||||||
|
|
||||||
|
bool pending_init;
|
||||||
|
|
||||||
|
bool _evaluate_control();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Logger();
|
||||||
|
|
||||||
|
bool is_initialized() { return control != 0; }
|
||||||
|
|
||||||
|
bool is_init_pending() { return pending_init; }
|
||||||
|
|
||||||
|
void init_pending(bool val) { pending_init = val; }
|
||||||
|
|
||||||
|
void init(Thread_capability);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log binary data to trace buffer
|
||||||
|
*/
|
||||||
|
void log(char const *, size_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log event to trace buffer
|
||||||
|
*/
|
||||||
|
template <typename EVENT>
|
||||||
|
void log(EVENT const *event)
|
||||||
|
{
|
||||||
|
if (!this || !_evaluate_control()) return;
|
||||||
|
|
||||||
|
buffer->commit(event->generate(*policy_module, buffer->reserve(max_event_size)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__TRACE__LOGGER_H_ */
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* \brief Event tracing infrastructure
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__TRACE__POLICY_H_
|
||||||
|
#define _INCLUDE__BASE__TRACE__POLICY_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
class Msgbuf_base;
|
||||||
|
class Signal;
|
||||||
|
class Rpc_object_base;
|
||||||
|
|
||||||
|
namespace Trace { class Policy_module; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header of tracing policy
|
||||||
|
*/
|
||||||
|
struct Genode::Trace::Policy_module
|
||||||
|
{
|
||||||
|
size_t (*max_event_size) ();
|
||||||
|
size_t (*rpc_call) (char *, char const *, Msgbuf_base const &);
|
||||||
|
size_t (*rpc_returned) (char *, char const *, Msgbuf_base const &);
|
||||||
|
size_t (*rpc_dispatch) (char *, char const *);
|
||||||
|
size_t (*rpc_reply) (char *, char const *);
|
||||||
|
size_t (*signal_submit) (char *, unsigned const);
|
||||||
|
size_t (*signal_received) (char *, Signal const &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__TRACE__POLICY_H_ */
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* \brief Event-tracing support
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/env.h>
|
||||||
|
#include <base/thread.h>
|
||||||
|
#include <base/trace/policy.h>
|
||||||
|
#include <dataspace/client.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include <trace/control.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Area area(*cpu, *rm);
|
||||||
|
return area.slot(thread_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
** Trace::Logger **
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
bool Trace::Logger::_evaluate_control()
|
||||||
|
{
|
||||||
|
/* check process-global and thread-specific tracing condition */
|
||||||
|
if (inhibit_tracing || !control || control->tracing_inhibited())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (control->state_changed()) {
|
||||||
|
|
||||||
|
/* suppress tracing during initialization */
|
||||||
|
Control::Inhibit_guard guard(*control);
|
||||||
|
|
||||||
|
if (control->to_be_disabled()) {
|
||||||
|
|
||||||
|
/* unload policy */
|
||||||
|
if (policy_module) {
|
||||||
|
env()->rm_session()->detach(policy_module);
|
||||||
|
policy_module = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unmap trace buffer */
|
||||||
|
if (buffer) {
|
||||||
|
env()->rm_session()->detach(buffer);
|
||||||
|
buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inhibit generation of trace events */
|
||||||
|
enabled = false;
|
||||||
|
control->acknowledge_disabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (control->to_be_enabled()) {
|
||||||
|
|
||||||
|
control->acknowledge_enabled();
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled && (policy_version != control->policy_version())) {
|
||||||
|
|
||||||
|
/* suppress tracing during policy change */
|
||||||
|
Control::Inhibit_guard guard(*control);
|
||||||
|
|
||||||
|
/* obtain policy */
|
||||||
|
Dataspace_capability policy_ds = env()->cpu_session()->trace_policy(thread_cap);
|
||||||
|
|
||||||
|
if (!policy_ds.valid()) {
|
||||||
|
PWRN("could not obtain trace policy");
|
||||||
|
control->error();
|
||||||
|
enabled = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
max_event_size = 0;
|
||||||
|
policy_module = 0;
|
||||||
|
|
||||||
|
policy_module = env()->rm_session()->attach(policy_ds);
|
||||||
|
|
||||||
|
/* relocate function pointers of policy callback table */
|
||||||
|
for (unsigned i = 0; i < sizeof(Trace::Policy_module)/sizeof(void *); i++) {
|
||||||
|
((addr_t *)policy_module)[i] += (addr_t)(policy_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
max_event_size = policy_module->max_event_size();
|
||||||
|
|
||||||
|
} catch (...) { }
|
||||||
|
|
||||||
|
/* obtain buffer */
|
||||||
|
buffer = 0;
|
||||||
|
Dataspace_capability buffer_ds = env()->cpu_session()->trace_buffer(thread_cap);
|
||||||
|
|
||||||
|
if (!buffer_ds.valid()) {
|
||||||
|
PWRN("could not obtain trace buffer");
|
||||||
|
control->error();
|
||||||
|
enabled = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer = env()->rm_session()->attach(buffer_ds);
|
||||||
|
buffer->init(Dataspace_client(buffer_ds).size());
|
||||||
|
} catch (...) { }
|
||||||
|
|
||||||
|
policy_version = control->policy_version();
|
||||||
|
}
|
||||||
|
|
||||||
|
return enabled && policy_module;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Trace::Logger::log(char const *msg, size_t len)
|
||||||
|
{
|
||||||
|
if (!this || !_evaluate_control()) return;
|
||||||
|
|
||||||
|
memcpy(buffer->reserve(len), msg, len);
|
||||||
|
buffer->commit(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Trace::Logger::init(Thread_capability thread)
|
||||||
|
{
|
||||||
|
thread_cap = thread;
|
||||||
|
|
||||||
|
control = trace_control(env()->cpu_session(), env()->rm_session(), thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Trace::Logger::Logger()
|
||||||
|
:
|
||||||
|
thread_cap(thread_cap),
|
||||||
|
control(0),
|
||||||
|
enabled(false),
|
||||||
|
policy_version(0),
|
||||||
|
policy_module(0),
|
||||||
|
max_event_size(0),
|
||||||
|
pending_init(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
** Thread_base **
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return logger instance for the main thread **
|
||||||
|
*/
|
||||||
|
static Trace::Logger *main_trace_logger()
|
||||||
|
{
|
||||||
|
static Trace::Logger logger;
|
||||||
|
return &logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Trace::Logger *Thread_base::_logger()
|
||||||
|
{
|
||||||
|
if (inhibit_tracing)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Thread_base * const myself = Thread_base::myself();
|
||||||
|
|
||||||
|
Trace::Logger * const logger = myself ? &myself->_trace_logger
|
||||||
|
: main_trace_logger();
|
||||||
|
|
||||||
|
/* logger is already being initialized */
|
||||||
|
if (logger->is_init_pending())
|
||||||
|
return logger;
|
||||||
|
|
||||||
|
/* lazily initialize trace object */
|
||||||
|
if (!logger->is_initialized()) {
|
||||||
|
logger->init_pending(true);
|
||||||
|
logger->init(myself ? myself->_thread_cap : env()->parent()->main_thread_cap());
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* \brief Event tracing control interface between CPU client and CPU server
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-08-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TRACE_CONTROL_H_
|
||||||
|
#define _TRACE_CONTROL_H_
|
||||||
|
|
||||||
|
namespace Genode { namespace Trace { class Control; } }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure shared between core and CPU session client
|
||||||
|
*
|
||||||
|
* The 'Trace_control' structure allows core to propagate control
|
||||||
|
* information to the threads of a process in an asynchronous way,
|
||||||
|
* for example to enable/disable tracing or setting the tracing
|
||||||
|
* policy.
|
||||||
|
*/
|
||||||
|
class Genode::Trace::Control
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum State { FREE, DISABLED, ENABLED, ERROR };
|
||||||
|
|
||||||
|
unsigned volatile _policy_version;
|
||||||
|
|
||||||
|
State volatile _designated_state;
|
||||||
|
State volatile _acknowledged_state;
|
||||||
|
|
||||||
|
bool volatile _inhibit;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/*************************************************
|
||||||
|
** Interface used by by the CPU session client **
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Facility to temporarily inhibit tracing
|
||||||
|
*
|
||||||
|
* This utility is used by a thread during the initialization of its
|
||||||
|
* 'Trace::Logger' to prevent recursion. During initialiation, the
|
||||||
|
* logger performs a few RPCs (e.g., to obtain the trace-control
|
||||||
|
* index). Because an RPC is a trace point, this would result in the
|
||||||
|
* re-entering the logger initialization.
|
||||||
|
*/
|
||||||
|
struct Inhibit_guard
|
||||||
|
{
|
||||||
|
Control &_control;
|
||||||
|
Inhibit_guard(Control &control) : _control(control)
|
||||||
|
{
|
||||||
|
_control._inhibit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Inhibit_guard() { _control._inhibit = false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request current policy version
|
||||||
|
*
|
||||||
|
* To be compared to the version currently installed at the
|
||||||
|
* client.
|
||||||
|
*/
|
||||||
|
unsigned policy_version() const { return _policy_version; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after having updated the policy
|
||||||
|
*/
|
||||||
|
void acknowledge_policy_version(unsigned version) { _policy_version = version; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect state change
|
||||||
|
*/
|
||||||
|
bool state_changed() const { return _designated_state != _acknowledged_state; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU client thread should stop tracing
|
||||||
|
*/
|
||||||
|
bool to_be_disabled() const
|
||||||
|
{
|
||||||
|
return state_changed() && (_designated_state == DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU client thread should start tracing
|
||||||
|
*/
|
||||||
|
bool to_be_enabled() const
|
||||||
|
{
|
||||||
|
return state_changed() && (_designated_state == ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm that the CPU client has enabled the tracing
|
||||||
|
*/
|
||||||
|
void acknowledge_enabled() { _acknowledged_state = ENABLED; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm that the CPU client has disabled the tracing
|
||||||
|
*
|
||||||
|
* After acknowledging that we disabled the policy, core is
|
||||||
|
* safe to free the policy dataspace.
|
||||||
|
*/
|
||||||
|
void acknowledge_disabled() { _acknowledged_state = DISABLED; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State set when trace buffer or policy could not be successfully
|
||||||
|
* obtained.
|
||||||
|
*/
|
||||||
|
void error() { _acknowledged_state = ERROR; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the corresponding thread should suppress trace events
|
||||||
|
*/
|
||||||
|
bool tracing_inhibited() const { return _inhibit; }
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************
|
||||||
|
** Accessors called by the CPU service **
|
||||||
|
*****************************************/
|
||||||
|
|
||||||
|
bool is_free() const { return _designated_state == FREE; }
|
||||||
|
|
||||||
|
void alloc()
|
||||||
|
{
|
||||||
|
_policy_version = 0;
|
||||||
|
_designated_state = DISABLED;
|
||||||
|
_acknowledged_state = DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
_policy_version = 0;
|
||||||
|
_designated_state = FREE;
|
||||||
|
_acknowledged_state = FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace()
|
||||||
|
{
|
||||||
|
_policy_version++;
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable()
|
||||||
|
{
|
||||||
|
_designated_state = ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable()
|
||||||
|
{
|
||||||
|
_designated_state = DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_error() const { return _acknowledged_state == ERROR; }
|
||||||
|
|
||||||
|
bool is_enabled() const { return _acknowledged_state == ENABLED; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _TRACE_CONTROL_H_ */
|
|
@ -171,8 +171,15 @@ class Core_child : public Child_policy
|
||||||
** Core main **
|
** Core main **
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
|
namespace Genode { extern bool inhibit_tracing; }
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Disable tracing within core because it is currently not fully implemented.
|
||||||
|
*/
|
||||||
|
inhibit_tracing = true;
|
||||||
|
|
||||||
PDBG("--- create local services ---");
|
PDBG("--- create local services ---");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -220,6 +220,9 @@ int genode_argc = 1;
|
||||||
char **genode_envp = 0;
|
char **genode_envp = 0;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Genode { extern bool inhibit_tracing; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C entry function called by the crt0 startup code
|
* C entry function called by the crt0 startup code
|
||||||
*/
|
*/
|
||||||
|
@ -227,6 +230,9 @@ extern "C" int _main()
|
||||||
{
|
{
|
||||||
main_thread_bootstrap();
|
main_thread_bootstrap();
|
||||||
|
|
||||||
|
/* call env() explicitly to setup the environment */
|
||||||
|
(void*)env();
|
||||||
|
|
||||||
/* initialize exception handling */
|
/* initialize exception handling */
|
||||||
init_exception_handling();
|
init_exception_handling();
|
||||||
|
|
||||||
|
@ -258,6 +264,9 @@ extern "C" int _main()
|
||||||
/* create the thread context area RM session */
|
/* create the thread context area RM session */
|
||||||
env_context_area_rm_session();
|
env_context_area_rm_session();
|
||||||
|
|
||||||
|
/* enable tracing support */
|
||||||
|
inhibit_tracing = false;
|
||||||
|
|
||||||
/* call real main function */
|
/* call real main function */
|
||||||
int ret = main(genode_argc, genode_argv, genode_envp);
|
int ret = main(genode_argc, genode_argv, genode_envp);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue