/* * \brief Event-tracing support * \author Norman Feske * \date 2013-08-09 */ /* * Copyright (C) 2013-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ #include #include #include #include #include #include /* local includes */ #include using namespace Genode; namespace Genode { bool inhibit_tracing = true; /* cleared by '_main' */ } static Env *_env_ptr; namespace Genode { void init_tracing(Env &env) { _env_ptr = &env; } } static Env &_env() { if (_env_ptr) return *_env_ptr; struct Missing_call_of_init_tracing { }; throw Missing_call_of_init_tracing(); } /******************* ** 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().detach(policy_module); policy_module = 0; } /* unmap trace buffer */ if (buffer) { _env().rm().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 = Cpu_thread_client(thread_cap).trace_policy(); if (!policy_ds.valid()) { warning("could not obtain trace policy"); control->error(); enabled = false; return false; } try { max_event_size = 0; policy_module = 0; enum { MAX_SIZE = 0, NO_OFFSET = 0, ANY_LOCAL_ADDR = false, EXECUTABLE = true }; policy_module = _env().rm().attach(policy_ds, MAX_SIZE, NO_OFFSET, ANY_LOCAL_ADDR, nullptr, EXECUTABLE); /* 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 = Cpu_thread_client(thread_cap).trace_buffer(); if (!buffer_ds.valid()) { warning("could not obtain trace buffer"); control->error(); enabled = false; return false; } try { buffer = _env().rm().attach(buffer_ds); buffer->init(Dataspace_client(buffer_ds).size()); } catch (...) { } policy_version = control->policy_version(); } return enabled && policy_module; } __attribute__((optimize("-fno-delete-null-pointer-checks"))) 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, Cpu_session *cpu_session, Trace::Control *attached_control) { if (!attached_control) return; thread_cap = thread; cpu = cpu_session; unsigned const index = Cpu_thread_client(thread).trace_control_index(); Dataspace_capability ds = cpu->trace_control(); size_t size = Dataspace_client(ds).size(); if ((index + 1)*sizeof(Trace::Control) > size) { error("thread control index is out of range"); return; } control = attached_control + index; } Trace::Logger::Logger() { } /************ ** Thread ** ************/ /** * return logger instance for the main thread ** */ static Trace::Logger &main_trace_logger() { static Trace::Logger logger; return logger; } static Trace::Control *main_trace_control; Trace::Logger *Thread::_logger() { if (inhibit_tracing) return nullptr; Thread * const myself = Thread::myself(); Trace::Logger &logger = myself ? myself->_trace_logger : main_trace_logger(); /* logger is already being initialized */ if (logger.init_pending()) return &logger; /* lazily initialize trace object */ if (!logger.initialized()) { logger.init_pending(true); Thread_capability thread_cap = myself ? myself->_thread_cap : _env().parent().main_thread_cap(); Cpu_session &cpu = myself ? *myself->_cpu_session : _env().cpu(); if (!myself) if (!main_trace_control) { Dataspace_capability ds = _env().cpu().trace_control(); if (ds.valid()) main_trace_control = _env().rm().attach(ds); } logger.init(thread_cap, &cpu, myself ? myself->_trace_control : main_trace_control); } return &logger; }