gdb_monitor: API transition

Issue #1987
This commit is contained in:
Christian Prochaska 2017-01-04 11:38:39 +01:00 committed by Norman Feske
parent 537dde1f40
commit 7a0bcbbccb
35 changed files with 735 additions and 891 deletions

View File

@ -0,0 +1 @@
LIBS += gdbserver_platform_foc

View File

@ -0,0 +1 @@
LIBS += gdbserver_platform_nova

View File

@ -1,3 +0,0 @@
SRC_CC = spec/nova_x86_32/low.cc native_cpu.cc
include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc

View File

@ -1,3 +0,0 @@
SRC_CC = spec/nova_x86_64/low.cc native_cpu.cc
include $(REP_DIR)/lib/mk/spec/x86_64/gdbserver_platform.inc

View File

@ -3,4 +3,4 @@ SRC_CC = spec/foc_x86_32/low.cc \
LIBS += syscall-foc
include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc
include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform_x86_32.inc

View File

@ -0,0 +1,3 @@
SRC_CC = spec/nova_x86_32/low.cc native_cpu.cc
include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform_x86_32.inc

View File

@ -0,0 +1,3 @@
SRC_CC = spec/nova_x86_64/low.cc native_cpu.cc
include $(REP_DIR)/lib/mk/spec/x86_64/gdbserver_platform_x86_64.inc

View File

@ -149,7 +149,30 @@ run_genode_until {.*\[init -> gdb_monitor\].*} 30
puts "GDB monitor is up, starting GDB in a new terminal"
exec [terminal] -e "[gdb] bin/nitpicker -ex \"target remote localhost:$local_port\"" &
source ${genode_dir}/repos/ports/run/gdb_monitor.inc
# GDB loads symbols from 'bin/ld.lib.so'
if { [have_spec nova] } {
exec ln -sf ld-nova.lib.so bin/ld.lib.so
}
if { [have_spec foc] } {
exec ln -sf ld-foc.lib.so bin/ld.lib.so
}
set gdb_target_binary "nitpicker"
# sequence of GDB commands to execute at startup
set gdb_cmds ""
append gdb_cmds "-ex \"target remote localhost:$local_port\" "
append gdb_cmds [gdb_initial_breakpoint_cmds $gdb_target_binary]
# ask the user for confirmations again
append gdb_cmds {-ex "set interactive-mode auto" }
puts "command: [gdb] bin/ld.lib.so $gdb_cmds"
exec [terminal] -e "[gdb] bin/ld.lib.so $gdb_cmds" &
interact -i [output_spawn_id]

View File

@ -4,14 +4,12 @@
# \date 2013-09-04
#
proc gdb_main_breakpoint_cmds { target_binary_name } {
proc gdb_initial_breakpoint_cmds { target_binary_name } {
#
# We set a break in the 'main()' function of a dynamically linked
# application by using the following gdb command sequence. It's important that
# the 'main()' breakpoint gets set before the 'sharedlibrary' command is
# executed. Otherwise the breakpoint would get set in ld.lib.so's main()
# function.
# We set a break in the 'binary_ready_hook_for_gdb()' function in the
# dynamic linker and load the symbols of the application by using the
# following gdb command sequence.
#
set gdb_cmds ""
@ -31,20 +29,11 @@ proc gdb_main_breakpoint_cmds { target_binary_name } {
# load the symbols of the test application
append gdb_cmds "-ex \"file bin/$target_binary_name\" "
# set a breakpoint in the application's 'main()' function
append gdb_cmds {-ex "b main" }
# set search path for "sharedlibrary" to bin
append gdb_cmds {-ex "set solib-search-path bin" }
# load the symbols of loaded shared libraries
append gdb_cmds {-ex "sharedlibrary" }
# continue execution until the breakpoint triggers
append gdb_cmds {-ex "c" }
# delete the 'main()' breakpoint
append gdb_cmds {-ex "delete 2" }
return $gdb_cmds
}

View File

@ -90,7 +90,7 @@ install_config $config
# generic modules
set boot_modules {
core init timer
ld.lib.so libc.lib.so libc_pipe.lib.so libc_terminal.lib.so
ld.lib.so libc.lib.so libm.lib.so libc_pipe.lib.so libc_terminal.lib.so
uart_drv
gdb_monitor test-gdb_monitor
}
@ -120,12 +120,20 @@ puts "GDB monitor is up, starting GDB"
source ${genode_dir}/repos/ports/run/gdb_monitor.inc
# GDB loads symbols from 'bin/ld.lib.so'
if { [have_spec nova] } {
exec ln -sf ld-nova.lib.so bin/ld.lib.so
}
if { [have_spec foc] } {
exec ln -sf ld-foc.lib.so bin/ld.lib.so
}
set gdb_target_binary "test-gdb_monitor"
# sequence of GDB commands to execute at startup
set gdb_cmds ""
append gdb_cmds {-ex "target remote localhost:$local_port" }
append gdb_cmds [gdb_main_breakpoint_cmds $gdb_target_binary]
append gdb_cmds [gdb_initial_breakpoint_cmds $gdb_target_binary]
# run GDB and redirect stderr to stdio to get the relevant output into the expect buffer
eval spawn [gdb] bin/ld.lib.so -n $gdb_cmds 2&>1
@ -137,11 +145,19 @@ puts ""
run_genode_until {\(gdb\)} 60 $gdb_id
send "b main\n"
run_genode_until {\(gdb\)} 20 $gdb_id
send "c\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Breakpoint 2, main ()} $output]} {
puts stderr "*** Error: Breakpoint in main() did not trigger"
exit -1
}
send "delete 2\n"
run_genode_until {\(gdb\)} 20 $gdb_id
puts "\n"
puts "----- test: breakpoint in shared library -----"
puts ""

View File

@ -77,7 +77,7 @@ install_config $config
# generic modules
set boot_modules {
core init timer
ld.lib.so libc.lib.so libc_pipe.lib.so libc_terminal.lib.so
ld.lib.so libc.lib.so libm.lib.so libc_pipe.lib.so libc_terminal.lib.so
uart_drv
gdb_monitor test-gdb_monitor
}
@ -106,18 +106,26 @@ puts "GDB monitor is up, starting GDB in a new terminal"
source ${genode_dir}/repos/ports/run/gdb_monitor.inc
# GDB loads symbols from 'bin/ld.lib.so'
if { [have_spec nova] } {
exec ln -sf ld-nova.lib.so bin/ld.lib.so
}
if { [have_spec foc] } {
exec ln -sf ld-foc.lib.so bin/ld.lib.so
}
set gdb_target_binary "test-gdb_monitor"
# sequence of GDB commands to execute at startup
set gdb_cmds ""
append gdb_cmds "-ex \"target remote localhost:$local_port\" "
append gdb_cmds [gdb_main_breakpoint_cmds $gdb_target_binary]
append gdb_cmds [gdb_initial_breakpoint_cmds $gdb_target_binary]
# ask the user for confirmations again
append gdb_cmds {-ex "set interactive-mode auto" }
puts "command: [gdb] bin/$gdb_target_binary $gdb_cmds"
puts "command: [gdb] bin/ld.lib.so $gdb_cmds"
exec [terminal] -e "[gdb] bin/ld.lib.so $gdb_cmds" &

View File

@ -53,10 +53,16 @@ set config {
<config>
<target name="test-gdb_monitor_target_config">
<config>
<libc stdout="/dev/log" stderr="/dev/log">
<vfs> <dir name="dev"> <log/> </dir> </vfs>
</libc>
<test_config_subnode/>
</config>
</target>
<preserve name="RAM" quantum="3M"/>
<libc stdout="/dev/log" stderr="/dev/log">
<vfs> <dir name="dev"> <log/> </dir> </vfs>
</libc>
</config>
</start>
</config>
@ -98,15 +104,29 @@ run_genode_until {.*Remote debugging using /dev/terminal.*} 30
puts "GDB monitor is up, starting GDB in a new terminal"
source ${genode_dir}/repos/ports/run/gdb_monitor.inc
# GDB loads symbols from 'bin/ld.lib.so'
if { [have_spec nova] } {
exec ln -sf ld-nova.lib.so bin/ld.lib.so
}
if { [have_spec foc] } {
exec ln -sf ld-foc.lib.so bin/ld.lib.so
}
set gdb_target_binary "test-gdb_monitor_target_config"
# sequence of GDB commands to execute at startup
set gdb_cmds ""
append gdb_cmds "-ex \"target remote localhost:$local_port\" "
append gdb_cmds [gdb_initial_breakpoint_cmds $gdb_target_binary]
# continue execution
append gdb_cmds {-ex "c" }
exec [terminal] -e "[gdb] bin/test-gdb_monitor_target_config $gdb_cmds" &
exec [terminal] -e "[gdb] bin/ld.lib.so $gdb_cmds" &
interact
interact -i [output_spawn_id]
# vi: set ft=tcl :

View File

@ -1,5 +1,5 @@
if {![have_spec foc] && ![have_spec nova]} {
puts "\nThe Noux GDB scenario is supported on NOVA and Fiasco.OC only\n"
if {!([have_spec nova] || ([have_spec foc] && [have_spec 32bit]))} {
puts "\nThe Noux GDB scenario is only supported for NOVA or 32-bit Fiasco.OC\n"
exit 0
}
@ -26,7 +26,10 @@ set build_components {
app/gdb_monitor
}
lappend_if [have_spec gpio] build_components drivers/gpio
lappend_if [have_spec gpio] build_components drivers/gpio
lappend_if [have_spec nova] build_components lib/ld/nova
lappend_if [have_spec foc] build_components lib/ld/foc
lappend build_components noux-pkg/[noux_gdb_pkg_name]
@ -39,11 +42,20 @@ append_platform_drv_build_components
build $build_components
# GDB loads symbols from 'bin/ld.lib.so'
if { [have_spec nova] } {
exec ln -sf ld-nova.lib.so bin/ld.lib.so
}
if { [have_spec foc] } {
exec ln -sf ld-foc.lib.so bin/ld.lib.so
}
# names of the binaries needed for the GDB monitor test
set gdb_target_binaries {
test-gdb_monitor
ld.lib.so
libc.lib.so
libm.lib.so
}
lappend gdb_target_binaries ${gdb_target_binary_name}

View File

@ -1,162 +0,0 @@
if {![have_spec foc] || ![have_spec 32bit]} {
puts "\nThe Noux GDB scenario is supported on 32-bit Fiasco.OC only\n"
exit 0
}
source ${genode_dir}/repos/ports/run/noux_gdb.inc
#
# Uncomment the following line when working on the GDB source code. Otherwise,
# the package may get recompiled, yet it does not get reinstalled into 'bin/'.
#
#exec rm -rf noux-pkg/[noux_gdb_pkg_name]/ bin/[noux_gdb_pkg_name]/
set build_components {
core init drivers/timer noux lib/libc_noux
drivers/uart
server/terminal_mux server/terminal_crosslink
server/terminal_log
app/cli_monitor
app/gdb_monitor
}
lappend build_components noux-pkg/[noux_gdb_pkg_name]
lappend build_components test/gdb_monitor
set gdb_target_binary_name test-gdb_monitor
build $build_components
# names of the binaries needed for the GDB monitor test
set gdb_target_binaries {
ld.lib.so
libc.lib.so
}
lappend gdb_target_binaries ${gdb_target_binary_name}
create_gdb_tar
create_binary_and_source_tars "gdb_target" ${gdb_target_binaries}
create_boot_directory
append config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="LOG"/>
<service name="RAM"/>
<service name="RM"/>
<service name="CPU"/>
<service name="PD"/>
<service name="IRQ"/>
<service name="IO_PORT"/>
<service name="IO_MEM"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
<route> <any-service> <parent/> </any-service> </route>
</start>
<start name="uart_drv">}
# use kernel debugger as UART on Fiasco.OC
append_if [have_spec foc] config {
<binary name="kdb_uart_drv"/>}
append config {
<resource name="RAM" quantum="1M"/>
<provides>
<service name="Uart"/>
<service name="Terminal"/>
</provides>
<config> }
# on Fiasco.OC the kdb_uart_drv is always UART 0
append_if [have_spec foc] config {
<policy label_prefix="terminal_mux" uart="0" detect_size="yes"/> }
# on all other kernels, direct terminal_mux to UART 1 (Qemu stdio, see below)
append_if [expr ![have_spec foc]] config {
<policy label_prefix="terminal_mux" uart="1" detect_size="yes"/> }
append config {
</config>
<route> <any-service> <parent/> <any-child/> </any-service> </route>
</start>
<start name="terminal_mux">
<resource name="RAM" quantum="3M"/>
<provides><service name="Terminal"/></provides>
<route>
<service name="Terminal"><child name="uart_drv"/></service>
<any-service> <parent/> <any-child/> </any-service>
</route>
<config>
<keyboard layout="de"/>
</config>
</start>
<start name="terminal_log">
<resource name="RAM" quantum="2M"/>
<provides>
<service name="LOG"/>
</provides>
<route>
<any-service><child name="terminal_mux"/> <any-child/> <parent/> </any-service>
</route>
</start>
<start name="cli_monitor">
<resource name="RAM" quantum="3G"/>
<config>
<subsystem name="gdb_test" help="GDB test application"> }
append config "
<binary name=\"${gdb_target_binary_name}\"/> "
append config {
<resource name="RAM" quantum="50M"/>
</subsystem>
</config>
<route>
<service name="LOG"><child name="terminal_log"/></service>
<service name="Terminal"><child name="terminal_mux"/></service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
</config>
}
install_config $config
#
# Boot modules
#
exec cp ${genode_dir}/repos/os/src/app/cli_monitor/gdb_command_config bin
# generic modules
set boot_modules {
core init timer ld.lib.so noux terminal_mux terminal_crosslink
libc.lib.so libm.lib.so libc_noux.lib.so ncurses.lib.so expat.lib.so
libc_pipe.lib.so libc_terminal.lib.so
cli_monitor gdb_monitor terminal_log gdb.tar
gdb_command_config
gdb_target.tar
gdb_target-src.tar
}
lappend boot_modules ${gdb_target_binary_name}
# platform-specific modules
lappend_if [expr ![have_spec foc]] boot_modules uart_drv
lappend_if [have_spec foc] boot_modules kdb_uart_drv
set fiasco_serial_esc_arg ""
build_boot_image $boot_modules
append qemu_args " -nographic "
run_genode_until forever
exec rm bin/gdb.tar

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2009-2016 Genode Labs GmbH
* Copyright (C) 2009-2017 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.
@ -14,9 +14,7 @@
#ifndef _APP_CHILD_H_
#define _APP_CHILD_H_
#include <stdio.h>
#include <sys/stat.h>
/* Genode includes */
#include <base/child.h>
#include <base/service.h>
@ -25,37 +23,43 @@
#include <util/arg_string.h>
/* GDB monitor includes */
#include "genode_child_resources.h"
#include "cpu_session_component.h"
#include "pd_session_component.h"
#include "rom.h"
namespace Gdb_monitor {
using namespace Genode;
namespace Gdb_monitor { class App_child; }
class App_child;
}
class Gdb_monitor::App_child : public Child_policy
{
public:
typedef Genode::Registered<Genode::Parent_service> Parent_service;
typedef Genode::Registry<Parent_service> Parent_services;
typedef Registered<Genode::Parent_service> Parent_service;
typedef Registry<Parent_service> Parent_services;
private:
enum { STACK_SIZE = 4*1024*sizeof(long) };
Genode::Env &_env;
Env &_env;
Genode::Ram_session_capability _ref_ram_cap { _env.ram_session_cap() };
Genode::Ram_session_client _ref_ram { _ref_ram_cap };
Allocator &_alloc;
Ram_session_capability _ref_ram_cap { _env.ram_session_cap() };
Ram_session_client _ref_ram { _ref_ram_cap };
const char *_unique_name;
Genode::Dataspace_capability _elf_ds;
Dataspace_capability _elf_ds;
Genode::Region_map &_rm;
Region_map &_rm;
Genode::size_t _ram_quota;
size_t _ram_quota;
Rpc_entrypoint _entrypoint;
@ -71,7 +75,7 @@ class Gdb_monitor::App_child : public Child_policy
Dataspace_pool _managed_ds_map;
Pd_session_component _pd {_unique_name, _entrypoint, _managed_ds_map};
Pd_session_component _pd { _entrypoint, _env, _alloc, _unique_name, _managed_ds_map };
Pd_service::Single_session_factory _pd_factory { _pd };
Pd_service _pd_service { _pd_factory };
@ -83,156 +87,16 @@ class Gdb_monitor::App_child : public Child_policy
Child *_child;
/* FIXME */
#if 0
/**
* Proxy for a service provided by the child
*/
class Child_service_root : public Genode::Rpc_object<Genode::Root>
{
private:
/**
* Root interface of the real service, provided by the child
*/
Genode::Root_client _child_root;
/**
* Child's RAM session used for quota transfers
*/
Genode::Ram_session_capability _child_ram;
struct Child_session;
typedef Genode::Object_pool<Child_session> Session_pool;
/**
* Per-session meta data
*
* For each session, we need to keep track of the quota
* attached to it - in order to revert the quota donation
* when the session gets closed.
*/
struct Child_session : public Session_pool::Entry
{
Genode::size_t ram_quota;
Child_session(Genode::Session_capability cap,
Genode::size_t ram_quota)
: Session_pool::Entry(cap), ram_quota(ram_quota) { }
};
/**
* Data base containing per-session meta data
*/
Session_pool _sessions;
public:
/**
* Constructor
*/
Child_service_root(Genode::Ram_session_capability child_ram,
Genode::Root_capability child_root)
: _child_root(child_root), _child_ram(child_ram)
{ }
/********************
** Root interface **
********************/
Session_capability session(Session_args const &args,
Affinity const &affinity)
{
using namespace Genode;
Genode::size_t ram_quota =
Arg_string::find_arg(args.string(),
"ram_quota").ulong_value(0);
/* forward session quota to child */
env()->ram_session()->transfer_quota(_child_ram, ram_quota);
Session_capability cap = _child_root.session(args, affinity);
/*
* Keep information about donated quota in '_sessions'
* data base.
*/
_sessions.insert(new (env()->heap())
Child_session(cap, ram_quota));
return cap;
}
void upgrade(Session_capability session_cap,
Upgrade_args const &args)
{
using namespace Genode;
auto lambda = [&] (Child_session *session) {
if (!session) {
error("attempt to upgrade unknown session");
return;
}
Genode::size_t ram_quota =
Arg_string::find_arg(args.string(),
"ram_quota").ulong_value(0);
/* forward session quota to child */
env()->ram_session()->transfer_quota(_child_ram, ram_quota);
session->ram_quota += ram_quota;
/* inform child about quota upgrade */
_child_root.upgrade(session_cap, args);
};
_sessions.apply(session_cap, lambda);
}
void close(Session_capability session_cap)
{
using namespace Genode;
Child_session *session;
auto lambda = [&] (Child_session *s) {
session = s;
if (!session) {
error("attempt to close unknown session");
return;
}
_sessions.remove(session);
};
_sessions.apply(session_cap, lambda);
Genode::size_t ram_quota = session->ram_quota;
destroy(env()->heap(), session);
_child_root.close(session_cap);
/*
* The child is expected to free enough quota to revert
* the quota donation.
*/
Ram_session_client child_ram(_child_ram);
child_ram.transfer_quota(env()->ram_session_cap(), ram_quota);
}
};
#endif
void _dispatch_unresolved_page_fault(unsigned)
{
_genode_child_resources.cpu_session_component()->handle_unresolved_page_fault();
_genode_child_resources.cpu_session_component().handle_unresolved_page_fault();
}
template <typename T>
static Genode::Service *_find_service(Genode::Registry<T> &services,
Genode::Service::Name const &name)
static Service *_find_service(Registry<T> &services,
Service::Name const &name)
{
Genode::Service *service = nullptr;
Service *service = nullptr;
services.for_each([&] (T &s) {
if (!service && (s.name() == name))
service = &s; });
@ -244,27 +108,27 @@ class Gdb_monitor::App_child : public Child_policy
/**
* Constructor
*/
App_child(Genode::Env &env,
const char *unique_name,
Genode::Pd_session &pd,
Genode::Region_map &rm,
Genode::size_t ram_quota,
Signal_receiver *signal_receiver,
Xml_node target_node)
App_child(Env &env,
Allocator &alloc,
char const *unique_name,
size_t ram_quota,
Signal_receiver &signal_receiver,
Xml_node target_node)
:
_env(env),
_alloc(alloc),
_unique_name(unique_name),
_rm(rm),
_rm(_env.rm()),
_ram_quota(ram_quota),
_entrypoint(&pd, STACK_SIZE, "GDB monitor entrypoint"),
_child_config(env.ram(), rm, target_node),
_entrypoint(&_env.pd(), STACK_SIZE, "GDB monitor entrypoint"),
_child_config(env.ram(), _rm, target_node),
_config_policy("config", _child_config.dataspace(), &_entrypoint),
_unresolved_page_fault_dispatcher(*signal_receiver,
_unresolved_page_fault_dispatcher(signal_receiver,
*this,
&App_child::_dispatch_unresolved_page_fault),
_cpu_factory(_env, _entrypoint, Genode::env()->heap(), _pd.core_pd_cap(),
_cpu_factory(_env, _entrypoint, _alloc, _pd.core_pd_cap(),
signal_receiver, &_genode_child_resources),
_rom_factory(env, _entrypoint)
_rom_factory(env, _entrypoint, _alloc)
{
_genode_child_resources.region_map_component(&_pd.region_map());
_pd.region_map().fault_handler(_unresolved_page_fault_dispatcher);
@ -272,7 +136,7 @@ class Gdb_monitor::App_child : public Child_policy
~App_child()
{
destroy(env()->heap(), _child);
destroy(_alloc, _child);
}
Genode_child_resources *genode_child_resources()
@ -282,7 +146,7 @@ class Gdb_monitor::App_child : public Child_policy
void start()
{
_child = new (env()->heap()) Child(_rm, _entrypoint, *this);
_child = new (_alloc) Child(_rm, _entrypoint, *this);
}
/****************************
@ -291,19 +155,19 @@ class Gdb_monitor::App_child : public Child_policy
Name name() const override { return _unique_name; }
Genode::Ram_session &ref_ram() override { return _ref_ram; }
Ram_session &ref_ram() override { return _ref_ram; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Genode::Ram_session &session,
Genode::Ram_session_capability cap) override
void init(Ram_session &session,
Ram_session_capability cap) override
{
session.ref_account(_ref_ram_cap);
_ref_ram.transfer_quota(cap, _ram_quota);
}
Service &resolve_session_request(Genode::Service::Name const &service_name,
Genode::Session_state::Args const &args) override
Service &resolve_session_request(Service::Name const &service_name,
Session_state::Args const &args) override
{
Service *service = nullptr;
@ -322,7 +186,7 @@ class Gdb_monitor::App_child : public Child_policy
service = _find_service(_parent_services, service_name);
if (!service)
service = new (env()->heap()) Parent_service(_parent_services, _env, service_name);
service = new (_alloc) Parent_service(_parent_services, _env, service_name);
if (!service)
throw Parent::Service_denied();
@ -334,15 +198,7 @@ class Gdb_monitor::App_child : public Child_policy
// to the child
void announce_service(Service::Name const &name) override
{
/* FIXME */
#if 0
/* create and announce proxy for the child's root interface */
Child_service_root *r = new (alloc)
Child_service_root(_ram_session, root);
Genode::env()->parent()->announce(name, _root_ep->manage(r));
#else
Genode::warning(__PRETTY_FUNCTION__, ": not implemented");
#endif
}
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -21,6 +21,9 @@
/* GDB monitor includes */
#include "cpu_thread_component.h"
/* libc includes */
#include <sys/signal.h>
/* genode-low.cc */
extern void genode_remove_thread(unsigned long lwpid);
@ -40,7 +43,7 @@ Rpc_entrypoint &Cpu_session_component::thread_ep()
}
Signal_receiver *Cpu_session_component::exception_signal_receiver()
Signal_receiver &Cpu_session_component::exception_signal_receiver()
{
return _exception_signal_receiver;
}
@ -299,11 +302,11 @@ Capability<Cpu_session::Native_cpu> Cpu_session_component::native_cpu()
}
Cpu_session_component::Cpu_session_component(Genode::Env &env,
Cpu_session_component::Cpu_session_component(Env &env,
Rpc_entrypoint &ep,
Allocator *md_alloc,
Allocator &md_alloc,
Pd_session_capability core_pd,
Signal_receiver *exception_signal_receiver,
Signal_receiver &exception_signal_receiver,
const char *args,
Affinity const &affinity)
: _env(env),
@ -335,7 +338,7 @@ Cpu_session_component::~Cpu_session_component()
int Cpu_session_component::ref_account(Cpu_session_capability) { return -1; }
int Cpu_session_component::transfer_quota(Cpu_session_capability, Genode::size_t) { return -1; }
int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; }
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2006-2016 Genode Labs GmbH
* Copyright (C) 2006-2017 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.
@ -31,13 +31,13 @@
namespace Gdb_monitor
{
using namespace Genode;
class Cpu_session_component;
class Cpu_thread_component;
class Local_cpu_factory;
typedef Genode::Local_service<Cpu_session_component> Cpu_service;
using namespace Genode;
typedef Local_service<Cpu_session_component> Cpu_service;
}
@ -46,29 +46,29 @@ class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
private:
Genode::Env &_env;
Env &_env;
Genode::Parent::Client _parent_client;
Parent::Client _parent_client;
Id_space<Parent::Client>::Element const _id_space_element
Id_space<Parent::Client>::Element const _id_space_element
{ _parent_client, _env.id_space() };
Rpc_entrypoint &_ep;
Allocator *_md_alloc;
Rpc_entrypoint &_ep;
Allocator &_md_alloc;
Pd_session_capability _core_pd;
Pd_session_capability _core_pd;
Cpu_session_client _parent_cpu_session;
Signal_receiver *_exception_signal_receiver;
Cpu_session_client _parent_cpu_session;
Signal_receiver &_exception_signal_receiver;
Append_list<Cpu_thread_component> _thread_list;
Append_list<Cpu_thread_component> _thread_list;
bool _stop_new_threads = true;
Lock _stop_new_threads_lock;
bool _stop_new_threads = true;
Lock _stop_new_threads_lock;
Capability<Cpu_session::Native_cpu> _native_cpu_cap;
Capability<Cpu_session::Native_cpu> _native_cpu_cap;
Capability<Cpu_session::Native_cpu> _setup_native_cpu();
Capability<Cpu_session::Native_cpu> _setup_native_cpu();
void _cleanup_native_cpu();
public:
@ -76,11 +76,11 @@ class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
/**
* Constructor
*/
Cpu_session_component(Genode::Env &env,
Cpu_session_component(Env &env,
Rpc_entrypoint &ep,
Allocator *md_alloc,
Allocator &md_alloc,
Pd_session_capability core_pd,
Signal_receiver *exception_signal_receiver,
Signal_receiver &exception_signal_receiver,
const char *args,
Affinity const &affinity);
@ -91,7 +91,7 @@ class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
Cpu_session &parent_cpu_session();
Rpc_entrypoint &thread_ep();
Signal_receiver *exception_signal_receiver();
Signal_receiver &exception_signal_receiver();
Thread_capability thread_cap(unsigned long lwpid);
unsigned long lwpid(Thread_capability thread_cap);
Cpu_thread_component *lookup_cpu_thread(unsigned long lwpid);
@ -122,7 +122,7 @@ class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
Affinity::Space affinity_space() const override;
Dataspace_capability trace_control() override;
int ref_account(Cpu_session_capability c) override;
int transfer_quota(Cpu_session_capability c, Genode::size_t q) override;
int transfer_quota(Cpu_session_capability c, size_t q) override;
Quota quota() override;
Capability<Native_cpu> native_cpu() override;
};
@ -132,21 +132,22 @@ class Gdb_monitor::Local_cpu_factory : public Cpu_service::Factory
{
private:
Genode::Env &_env;
Genode::Rpc_entrypoint &_ep;
Env &_env;
Rpc_entrypoint &_ep;
Allocator *_md_alloc;
Allocator &_md_alloc;
Pd_session_capability _core_pd;
Genode::Signal_receiver *_signal_receiver;
Signal_receiver &_signal_receiver;
Genode_child_resources *_genode_child_resources;
public:
Local_cpu_factory(Genode::Env &env, Genode::Rpc_entrypoint &ep,
Allocator *md_alloc,
Pd_session_capability core_pd,
Genode::Signal_receiver *signal_receiver,
Local_cpu_factory(Env &env,
Rpc_entrypoint &ep,
Allocator &md_alloc,
Pd_session_capability core_pd,
Signal_receiver &signal_receiver,
Genode_child_resources *genode_child_resources)
: _env(env), _ep(ep),
_md_alloc(md_alloc),
@ -178,7 +179,7 @@ class Gdb_monitor::Local_cpu_factory : public Cpu_service::Factory
void destroy(Cpu_session_component &session) override
{
Genode::destroy(env()->heap(), &session);
Genode::destroy(_md_alloc, &session);
}
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
* Copyright (C) 2016-2017 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.
@ -15,6 +15,9 @@
/* GDB monitor includes */
#include "cpu_thread_component.h"
/* libc includes */
#include <signal.h>
#include <unistd.h>
/* mem-break.c */
extern "C" int breakpoint_len;
@ -61,6 +64,150 @@ void Cpu_thread_component::_remove_breakpoint_at_first_instruction()
}
void Cpu_thread_component::_dispatch_exception(unsigned)
{
deliver_signal(SIGTRAP);
}
void Cpu_thread_component::_dispatch_sigstop(unsigned)
{
deliver_signal(SIGSTOP);
}
void Cpu_thread_component::_dispatch_sigint(unsigned)
{
deliver_signal(SIGINT);
}
Cpu_thread_component::Cpu_thread_component(Cpu_session_component &cpu_session_component,
Capability<Pd_session> pd,
Cpu_session::Name const &name,
Affinity::Location affinity,
Cpu_session::Weight weight,
addr_t utcb)
: _cpu_session_component(cpu_session_component),
_parent_cpu_thread(
_cpu_session_component.parent_cpu_session().create_thread(pd,
name,
affinity,
weight,
utcb)),
_exception_dispatcher(
_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_exception),
_sigstop_dispatcher(
_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_sigstop),
_sigint_dispatcher(
_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_sigint)
{
_cpu_session_component.thread_ep().manage(this);
if (pipe(_pipefd) != 0)
error("could not create pipe");
}
Cpu_thread_component::~Cpu_thread_component()
{
close(_pipefd[0]);
close(_pipefd[1]);
_cpu_session_component.thread_ep().dissolve(this);
}
int Cpu_thread_component::send_signal(int signo)
{
pause();
switch (signo) {
case SIGSTOP:
Signal_transmitter(sigstop_signal_context_cap()).submit();
return 1;
case SIGINT:
Signal_transmitter(sigint_signal_context_cap()).submit();
return 1;
default:
error("unexpected signal ", signo);
return 0;
}
}
int Cpu_thread_component::deliver_signal(int signo)
{
if ((signo == SIGTRAP) && _initial_sigtrap_pending) {
_initial_sigtrap_pending = false;
if (_verbose)
log("received initial SIGTRAP for lwpid ", _lwpid);
if (_lwpid == GENODE_MAIN_LWPID) {
_remove_breakpoint_at_first_instruction();
_initial_breakpoint_handled = true;
}
/*
* The lock guard prevents an interruption by
* 'genode_stop_all_threads()', which could cause
* the new thread to be resumed when it should be
* stopped.
*/
Lock::Guard stop_new_threads_lock_guard(
_cpu_session_component.stop_new_threads_lock());
if (!_cpu_session_component.stop_new_threads())
resume();
/*
* gdbserver expects SIGSTOP as first signal of a new thread,
* but we cannot write SIGSTOP here, because waitpid() would
* detect that the thread is in an exception state and wait
* for the SIGTRAP. So SIGINFO ist used for this purpose.
*/
signo = SIGINFO;
}
switch (signo) {
case SIGSTOP:
if (_verbose)
log("delivering SIGSTOP to thread ", _lwpid);
break;
case SIGTRAP:
if (_verbose)
log("delivering SIGTRAP to thread ", _lwpid);
break;
case SIGSEGV:
if (_verbose)
log("delivering SIGSEGV to thread ", _lwpid);
break;
case SIGINT:
if (_verbose)
log("delivering SIGINT to thread ", _lwpid);
break;
case SIGINFO:
if (_verbose)
log("delivering initial SIGSTOP to thread ", _lwpid);
break;
default:
error("unexpected signal ", signo);
}
write(_pipefd[1], &signo, sizeof(signo));
return 0;
}
Dataspace_capability Cpu_thread_component::utcb()
{
return _parent_cpu_thread.utcb();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
* Copyright (C) 2016-2017 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.
@ -19,10 +19,6 @@
#include <cpu_session/cpu_session.h>
#include <cpu_thread/client.h>
/* libc includes */
#include <signal.h>
#include <unistd.h>
#include "config.h"
#include "append_list.h"
#include "cpu_session_component.h"
@ -65,62 +61,20 @@ class Gdb_monitor::Cpu_thread_component : public Rpc_object<Cpu_thread>,
bool _set_breakpoint_at_first_instruction(addr_t ip);
void _remove_breakpoint_at_first_instruction();
void _dispatch_exception(unsigned)
{
deliver_signal(SIGTRAP);
}
void _dispatch_sigstop(unsigned)
{
deliver_signal(SIGSTOP);
}
void _dispatch_sigint(unsigned)
{
deliver_signal(SIGINT);
}
void _dispatch_exception(unsigned);
void _dispatch_sigstop(unsigned);
void _dispatch_sigint(unsigned);
public:
Cpu_thread_component(Cpu_session_component &cpu_session_component,
Capability<Pd_session> pd,
Cpu_thread_component(Cpu_session_component &cpu_session_component,
Capability<Pd_session> pd,
Cpu_session::Name const &name,
Affinity::Location affinity,
Cpu_session::Weight weight,
addr_t utcb)
: _cpu_session_component(cpu_session_component),
_parent_cpu_thread(
_cpu_session_component.parent_cpu_session().create_thread(pd,
name,
affinity,
weight,
utcb)),
_exception_dispatcher(
*_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_exception),
_sigstop_dispatcher(
*_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_sigstop),
_sigint_dispatcher(
*_cpu_session_component.exception_signal_receiver(),
*this,
&Cpu_thread_component::_dispatch_sigint)
{
_cpu_session_component.thread_ep().manage(this);
Affinity::Location affinity,
Cpu_session::Weight weight,
addr_t utcb);
if (pipe(_pipefd) != 0)
error("could not create pipe");
}
~Cpu_thread_component()
{
close(_pipefd[0]);
close(_pipefd[1]);
_cpu_session_component.thread_ep().dissolve(this);
}
~Cpu_thread_component();
Signal_context_capability exception_signal_context_cap()
{
@ -154,89 +108,9 @@ class Gdb_monitor::Cpu_thread_component : public Rpc_object<Cpu_thread>,
return 0;
}
int send_signal(int signo)
{
pause();
switch (signo) {
case SIGSTOP:
Signal_transmitter(sigstop_signal_context_cap()).submit();
return 1;
case SIGINT:
Signal_transmitter(sigint_signal_context_cap()).submit();
return 1;
default:
error("unexpected signal ", signo);
return 0;
}
}
int deliver_signal(int signo)
{
if ((signo == SIGTRAP) && _initial_sigtrap_pending) {
_initial_sigtrap_pending = false;
if (_verbose)
log("received initial SIGTRAP for lwpid ", _lwpid);
if (_lwpid == GENODE_MAIN_LWPID) {
_remove_breakpoint_at_first_instruction();
_initial_breakpoint_handled = true;
}
/*
* The lock guard prevents an interruption by
* 'genode_stop_all_threads()', which could cause
* the new thread to be resumed when it should be
* stopped.
*/
Lock::Guard stop_new_threads_lock_guard(
_cpu_session_component.stop_new_threads_lock());
if (!_cpu_session_component.stop_new_threads())
resume();
/*
* gdbserver expects SIGSTOP as first signal of a new thread,
* but we cannot write SIGSTOP here, because waitpid() would
* detect that the thread is in an exception state and wait
* for the SIGTRAP. So SIGINFO ist used for this purpose.
*/
signo = SIGINFO;
}
switch (signo) {
case SIGSTOP:
if (_verbose)
log("delivering SIGSTOP to thread ", _lwpid);
break;
case SIGTRAP:
if (_verbose)
log("delivering SIGTRAP to thread ", _lwpid);
break;
case SIGSEGV:
if (_verbose)
log("delivering SIGSEGV to thread ", _lwpid);
break;
case SIGINT:
if (_verbose)
log("delivering SIGINT to thread ", _lwpid);
break;
case SIGINFO:
if (_verbose)
log("delivering initial SIGSTOP to thread ", _lwpid);
break;
default:
error("unexpected signal ", signo);
}
write(_pipefd[1], &signo, sizeof(signo));
return 0;
}
int send_signal(int signo);
int deliver_signal(int signo);
/**************************
** CPU thread interface **

View File

@ -6,15 +6,26 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
*/
#include <signal.h>
#include <sys/wait.h>
/* Genode includes */
#include <base/env.h>
#include <os/config.h>
/* GDB monitor includes */
#include "app_child.h"
#include "cpu_thread_component.h"
#include "genode_child_resources.h"
#include "signal_handler_thread.h"
/* libc includes */
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern "C" {
@ -27,23 +38,6 @@ extern "C" {
int linux_detach_one_lwp (struct inferior_list_entry *entry, void *args);
}
#include <base/log.h>
#include <base/service.h>
#include <cap_session/connection.h>
#include <cpu_thread/client.h>
#include <dataspace/client.h>
#include <os/config.h>
#include <ram_session/connection.h>
#include <rom_session/connection.h>
#include <util/xml_node.h>
#include "app_child.h"
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
#include "genode_child_resources.h"
#include "rom.h"
#include "signal_handler_thread.h"
static bool verbose = false;
Genode::Env *genode_env;
@ -60,20 +54,185 @@ static unsigned long sigtrap_lwpid;
using namespace Genode;
using namespace Gdb_monitor;
static Genode_child_resources *_genode_child_resources = 0;
Genode_child_resources *genode_child_resources()
class Memory_model
{
return _genode_child_resources;
private:
Lock _lock;
Region_map_component &_address_space;
Region_map &_rm;
/**
* Representation of a currently mapped region
*/
struct Mapped_region
{
Region_map_component::Region *_region;
unsigned char *_local_base;
Mapped_region() : _region(0), _local_base(0) { }
bool valid() { return _region != 0; }
bool loaded(Region_map_component::Region const * region)
{
return _region == region;
}
void flush(Region_map &rm)
{
if (!valid()) return;
rm.detach(_local_base);
_local_base = 0;
_region = 0;
}
void load(Region_map_component::Region *region, Region_map &rm)
{
if (region == _region)
return;
if (!region || valid())
flush(rm);
if (!region)
return;
try {
_region = region;
_local_base = rm.attach(_region->ds_cap(),
0, _region->offset());
} catch (Region_map::Attach_failed) {
flush(rm);
error(__func__, ": RM attach failed");
}
}
unsigned char *local_base() { return _local_base; }
};
enum { NUM_MAPPED_REGIONS = 1 };
Mapped_region _mapped_region[NUM_MAPPED_REGIONS];
unsigned _evict_idx = 0;
/**
* Return local address of mapped region
*
* The function returns 0 if the mapping fails
*/
unsigned char *_update_curr_region(Region_map_component::Region *region)
{
for (unsigned i = 0; i < NUM_MAPPED_REGIONS; i++) {
if (_mapped_region[i].loaded(region))
return _mapped_region[i].local_base();
}
/* flush one currently mapped region */
_evict_idx++;
if (_evict_idx == NUM_MAPPED_REGIONS)
_evict_idx = 0;
_mapped_region[_evict_idx].load(region, _rm);
return _mapped_region[_evict_idx].local_base();
}
public:
Memory_model(Region_map_component &address_space,
Region_map &rm)
:
_address_space(address_space),
_rm(rm)
{ }
unsigned char read(void *addr)
{
Lock::Guard guard(_lock);
addr_t offset_in_region = 0;
Region_map_component::Region *region =
_address_space.find_region(addr, &offset_in_region);
unsigned char *local_base = _update_curr_region(region);
if (!local_base) {
warning(__func__, ": no memory at address ", addr);
throw No_memory_at_address();
}
unsigned char value =
local_base[offset_in_region];
if (verbose)
log(__func__, ": read addr=", addr, ", value=", Hex(value));
return value;
}
void write(void *addr, unsigned char value)
{
if (verbose)
log(__func__, ": write addr=", addr, ", value=", Hex(value));
Lock::Guard guard(_lock);
addr_t offset_in_region = 0;
Region_map_component::Region *region =
_address_space.find_region(addr, &offset_in_region);
unsigned char *local_base = _update_curr_region(region);
if (!local_base) {
warning(__func__, ": no memory at address=", addr);
warning("(attempted to write ", Hex(value), ")");
throw No_memory_at_address();
}
local_base[offset_in_region] = value;
}
};
static Genode_child_resources *_genode_child_resources = 0;
static Memory_model *_memory_model = 0;
Genode_child_resources &genode_child_resources()
{
if (!_genode_child_resources) {
Genode::error("_genode_child_resources is not set");
abort();
}
return *_genode_child_resources;
}
/**
* Return singleton instance of memory model
*/
Memory_model &memory_model()
{
if (!_memory_model) {
Genode::error("_memory_model is not set");
abort();
}
return *_memory_model;
}
static void genode_stop_thread(unsigned long lwpid)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
Cpu_thread_component *cpu_thread = csc.lookup_cpu_thread(lwpid);
if (!cpu_thread) {
error(__PRETTY_FUNCTION__, ": "
@ -91,7 +250,7 @@ extern "C" pid_t waitpid(pid_t pid, int *status, int flags)
fd_set readset;
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
while(1) {
@ -104,16 +263,16 @@ extern "C" pid_t waitpid(pid_t pid, int *status, int flags)
FD_SET(_new_thread_pipe[0], &readset);
Thread_capability thread_cap = csc->first();
Thread_capability thread_cap = csc.first();
while (thread_cap.valid()) {
FD_SET(csc->signal_pipe_read_fd(thread_cap), &readset);
thread_cap = csc->next(thread_cap);
FD_SET(csc.signal_pipe_read_fd(thread_cap), &readset);
thread_cap = csc.next(thread_cap);
}
} else {
FD_SET(csc->signal_pipe_read_fd(csc->thread_cap(pid)), &readset);
FD_SET(csc.signal_pipe_read_fd(csc.thread_cap(pid)), &readset);
}
struct timeval wnohang_timeout = {0, 0};
@ -157,21 +316,21 @@ extern "C" pid_t waitpid(pid_t pid, int *status, int flags)
/* received a signal */
Thread_capability thread_cap = csc->first();
Thread_capability thread_cap = csc.first();
while (thread_cap.valid()) {
if (FD_ISSET(csc->signal_pipe_read_fd(thread_cap), &readset))
if (FD_ISSET(csc.signal_pipe_read_fd(thread_cap), &readset))
break;
thread_cap = csc->next(thread_cap);
thread_cap = csc.next(thread_cap);
}
if (!thread_cap.valid())
continue;
int signal;
read(csc->signal_pipe_read_fd(thread_cap), &signal, sizeof(signal));
read(csc.signal_pipe_read_fd(thread_cap), &signal, sizeof(signal));
unsigned long lwpid = csc->lwpid(thread_cap);
unsigned long lwpid = csc.lwpid(thread_cap);
if (verbose)
log("thread ", lwpid, " received signal ", signal);
@ -191,13 +350,13 @@ extern "C" pid_t waitpid(pid_t pid, int *status, int flags)
* delivered first, otherwise gdbserver would single-step the thread again.
*/
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
Cpu_thread_component *cpu_thread = csc.lookup_cpu_thread(lwpid);
Thread_state thread_state = cpu_thread->state();
if (thread_state.exception) {
/* resend the SIGSTOP signal */
csc->send_signal(cpu_thread->cap(), SIGSTOP);
csc.send_signal(cpu_thread->cap(), SIGSTOP);
continue;
}
@ -308,26 +467,31 @@ extern "C" int fork()
return -1;
}
Number_of_bytes ram_quota = env()->ram_session()->avail() - preserved_ram_quota;
Number_of_bytes ram_quota = genode_env->ram().avail() - preserved_ram_quota;
/* start the application */
static Heap alloc(genode_env->ram(), genode_env->rm());
static Signal_receiver signal_receiver;
static Gdb_monitor::Signal_handler_thread
signal_handler_thread(&signal_receiver);
signal_handler_thread(*genode_env, signal_receiver);
signal_handler_thread.start();
App_child *child = new (env()->heap()) App_child(*genode_env,
filename,
genode_env->pd(),
genode_env->rm(),
ram_quota,
&signal_receiver,
target_node);
App_child *child = new (alloc) App_child(*genode_env,
alloc,
filename,
ram_quota,
signal_receiver,
target_node);
_genode_child_resources = child->genode_child_resources();
static Memory_model memory_model(genode_child_resources().region_map_component(), genode_env->rm());
_memory_model = &memory_model;
try {
child->start();
} catch (...) {
@ -341,9 +505,9 @@ extern "C" int fork()
extern "C" int kill(pid_t pid, int sig)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
Thread_capability thread_cap = csc->thread_cap(pid);
Thread_capability thread_cap = csc.thread_cap(pid);
if (!thread_cap.valid()) {
error(__PRETTY_FUNCTION__, ": "
@ -351,14 +515,14 @@ extern "C" int kill(pid_t pid, int sig)
return -1;
}
return csc->send_signal(thread_cap, sig);
return csc.send_signal(thread_cap, sig);
}
extern "C" int initial_breakpoint_handler(CORE_ADDR addr)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
return csc->handle_initial_breakpoint(sigtrap_lwpid);
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
return csc.handle_initial_breakpoint(sigtrap_lwpid);
}
@ -378,15 +542,15 @@ void genode_remove_thread(unsigned long lwpid)
extern "C" void genode_stop_all_threads()
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->pause_all_threads();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
csc.pause_all_threads();
}
void genode_resume_all_threads()
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->resume_all_threads();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
csc.resume_all_threads();
}
@ -409,9 +573,9 @@ int genode_kill(int pid)
void genode_continue_thread(unsigned long lwpid, int single_step)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources().cpu_session_component();
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
Cpu_thread_component *cpu_thread = csc.lookup_cpu_thread(lwpid);
if (!cpu_thread) {
error(__func__, ": " "could not find CPU thread object for lwpid ", lwpid);
@ -465,160 +629,9 @@ void genode_store_registers(struct regcache *regcache, int regno)
}
class Memory_model
{
private:
Lock _lock;
Region_map_component * const _address_space;
/**
* Representation of a currently mapped region
*/
struct Mapped_region
{
Region_map_component::Region *_region;
unsigned char *_local_base;
Mapped_region() : _region(0), _local_base(0) { }
bool valid() { return _region != 0; }
bool loaded(Region_map_component::Region const * region)
{
return _region == region;
}
void flush()
{
if (!valid()) return;
env()->rm_session()->detach(_local_base);
_local_base = 0;
_region = 0;
}
void load(Region_map_component::Region *region)
{
if (region == _region)
return;
if (!region || valid())
flush();
if (!region)
return;
try {
_region = region;
_local_base = env()->rm_session()->attach(_region->ds_cap(),
0, _region->offset());
} catch (Region_map::Attach_failed) {
flush();
error(__func__, ": RM attach failed");
}
}
unsigned char *local_base() { return _local_base; }
};
enum { NUM_MAPPED_REGIONS = 1 };
Mapped_region _mapped_region[NUM_MAPPED_REGIONS];
unsigned _evict_idx;
/**
* Return local address of mapped region
*
* The function returns 0 if the mapping fails
*/
unsigned char *_update_curr_region(Region_map_component::Region *region)
{
for (unsigned i = 0; i < NUM_MAPPED_REGIONS; i++) {
if (_mapped_region[i].loaded(region))
return _mapped_region[i].local_base();
}
/* flush one currently mapped region */
_evict_idx++;
if (_evict_idx == NUM_MAPPED_REGIONS)
_evict_idx = 0;
_mapped_region[_evict_idx].load(region);
return _mapped_region[_evict_idx].local_base();
}
public:
Memory_model(Region_map_component *address_space)
:
_address_space(address_space), _evict_idx(0)
{ }
unsigned char read(void *addr)
{
Lock::Guard guard(_lock);
addr_t offset_in_region = 0;
Region_map_component::Region *region =
_address_space->find_region(addr, &offset_in_region);
unsigned char *local_base = _update_curr_region(region);
if (!local_base) {
warning(__func__, ": no memory at address ", addr);
throw No_memory_at_address();
}
unsigned char value =
local_base[offset_in_region];
if (verbose)
log(__func__, ": read addr=", addr, ", value=", Hex(value));
return value;
}
void write(void *addr, unsigned char value)
{
if (verbose)
log(__func__, ": write addr=", addr, ", value=", Hex(value));
Lock::Guard guard(_lock);
addr_t offset_in_region = 0;
Region_map_component::Region *region =
_address_space->find_region(addr, &offset_in_region);
unsigned char *local_base = _update_curr_region(region);
if (!local_base) {
warning(__func__, ": no memory at address=", addr);
warning("(attempted to write ", Hex(value), ")");
throw No_memory_at_address();
}
local_base[offset_in_region] = value;
}
};
/**
* Return singleton instance of memory model
*/
static Memory_model *memory_model()
{
static Memory_model inst(genode_child_resources()->region_map_component());
return &inst;
}
unsigned char genode_read_memory_byte(void *addr)
{
return memory_model()->read(addr);
return memory_model().read(addr);
}
@ -641,7 +654,7 @@ int genode_read_memory(CORE_ADDR memaddr, unsigned char *myaddr, int len)
void genode_write_memory_byte(void *addr, unsigned char value)
{
memory_model()->write(addr, value);
memory_model().write(addr, value);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -16,6 +16,8 @@
#include "region_map_component.h"
extern "C" void abort();
namespace Gdb_monitor {
class Cpu_session_component;
class Genode_child_resources;
@ -23,7 +25,6 @@ namespace Gdb_monitor {
class Gdb_monitor::Genode_child_resources
{
private:
Cpu_session_component *_cpu_session_component = 0;
@ -41,8 +42,23 @@ class Gdb_monitor::Genode_child_resources
_region_map_component = region_map_component;
}
Cpu_session_component *cpu_session_component() { return _cpu_session_component; }
Region_map_component *region_map_component() { return _region_map_component; }
Cpu_session_component &cpu_session_component()
{
if (!_cpu_session_component) {
Genode::error("_cpu_session_component is not set");
abort();
}
return *_cpu_session_component;
}
Region_map_component &region_map_component()
{
if (!_region_map_component) {
Genode::error("_region_map_component is not set");
abort();
}
return *_region_map_component;
}
};
#endif /* _GENODE_CHILD_RESOURCES_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
* Copyright (C) 2016-2017 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.
@ -22,9 +22,10 @@
#include "region_map_component.h"
namespace Gdb_monitor {
class Pd_session_component;
typedef Genode::Local_service<Pd_session_component> Pd_service;
using namespace Genode;
class Pd_session_component;
typedef Local_service<Pd_session_component> Pd_service;
}
class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
@ -32,6 +33,7 @@ class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
private:
Rpc_entrypoint &_ep;
Allocator &_alloc;
Pd_connection _pd;
@ -44,13 +46,18 @@ class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
/**
* Constructor
*/
Pd_session_component(char const *binary_name, Rpc_entrypoint &ep,
Pd_session_component(Rpc_entrypoint &ep,
Env &env,
Allocator &alloc,
char const *binary_name,
Dataspace_pool &managed_ds_map)
:
_ep(ep), _pd(binary_name),
_address_space(_ep, managed_ds_map, _pd, _pd.address_space()),
_stack_area (_ep, managed_ds_map, _pd, _pd.stack_area()),
_linker_area (_ep, managed_ds_map, _pd, _pd.linker_area())
_ep(ep),
_alloc(alloc),
_pd(env, binary_name),
_address_space(_ep, _alloc, managed_ds_map, _pd, _pd.address_space()),
_stack_area (_ep, _alloc, managed_ds_map, _pd, _pd.stack_area()),
_linker_area (_ep, _alloc, managed_ds_map, _pd, _pd.linker_area())
{
_ep.manage(this);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -20,7 +20,7 @@
using namespace Genode;
using namespace Gdb_monitor;
Ram_session_component::Ram_session_component(Genode::Env &env, const char *args,
Ram_session_component::Ram_session_component(Env &env, const char *args,
Affinity const &affinity)
: _env(env),
_parent_ram_session(_env.session<Ram_session>(_id_space_element.id(), args, affinity))

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2006-2016 Genode Labs GmbH
* Copyright (C) 2006-2017 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.
@ -20,29 +20,30 @@
namespace Gdb_monitor
{
class Ram_session_component;
using namespace Genode;
class Ram_session_component;
}
class Gdb_monitor::Ram_session_component : public Rpc_object<Ram_session>
{
private:
Genode::Env &_env;
Env &_env;
Genode::Parent::Client _parent_client;
Parent::Client _parent_client;
Id_space<Parent::Client>::Element const _id_space_element
{ _parent_client, _env.id_space() };
Genode::Ram_session_client _parent_ram_session;
Ram_session_client _parent_ram_session;
public:
/**
* Constructor
*/
Ram_session_component(Genode::Env &env, const char *args,
Ram_session_component(Env &env, const char *args,
Affinity const &affinity);
/**
@ -55,12 +56,12 @@ class Gdb_monitor::Ram_session_component : public Rpc_object<Ram_session>
** RAM Session interface **
***************************/
Ram_dataspace_capability alloc(Genode::size_t, Cache_attribute);
Ram_dataspace_capability alloc(size_t, Cache_attribute);
void free(Ram_dataspace_capability);
int ref_account(Ram_session_capability);
int transfer_quota(Ram_session_capability, Genode::size_t);
Genode::size_t quota();
Genode::size_t used();
int transfer_quota(Ram_session_capability, size_t);
size_t quota();
size_t used();
};
#endif /* _RAM_SESSION_COMPONENT_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -75,7 +75,7 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
executable);
Lock::Guard lock_guard(_region_map_lock);
_region_map.insert(new (env()->heap()) Region(addr, (void*)((addr_t)addr + size - 1), ds_cap, offset));
_region_map.insert(new (_alloc) Region(addr, (void*)((addr_t)addr + size - 1), ds_cap, offset));
return addr;
}
@ -92,7 +92,7 @@ void Region_map_component::detach(Region_map::Local_addr local_addr)
return;
}
_region_map.remove(region);
destroy(env()->heap(), region);
destroy(_alloc, region);
}
@ -111,16 +111,18 @@ Region_map::State Region_map_component::state()
Dataspace_capability Region_map_component::dataspace()
{
Dataspace_capability ds_cap = _parent_region_map.dataspace();
_managed_ds_map.insert(new (env()->heap()) Dataspace_object(ds_cap, this));
_managed_ds_map.insert(new (_alloc) Dataspace_object(ds_cap, this));
return ds_cap;
}
Region_map_component::Region_map_component(Rpc_entrypoint &ep,
Allocator &alloc,
Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map)
:
_ep(ep),
_alloc(alloc),
_pd(pd),
_parent_region_map(parent_region_map),
_managed_ds_map(managed_ds_map)

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2006-2016 Genode Labs GmbH
* Copyright (C) 2006-2017 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.
@ -31,11 +31,13 @@ namespace Gdb_monitor {
{
private:
Rpc_entrypoint &_ep;
Rpc_entrypoint &_ep;
Pd_session_capability _pd;
Allocator &_alloc;
Genode::Region_map_client _parent_region_map;
Pd_session_capability _pd;
Region_map_client _parent_region_map;
public:
@ -44,7 +46,7 @@ namespace Gdb_monitor {
private:
void *_start;
void *_end;
Genode::off_t _offset;
off_t _offset;
Dataspace_capability _ds_cap;
public:
@ -63,7 +65,7 @@ namespace Gdb_monitor {
}
void *start() { return _start; }
Genode::off_t offset() { return _offset; }
off_t offset() { return _offset; }
Dataspace_capability ds_cap() { return _ds_cap; }
};
@ -78,9 +80,10 @@ namespace Gdb_monitor {
/**
* Constructor
*/
Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Region_map_component(Rpc_entrypoint &ep,
Allocator &alloc,
Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map);
~Region_map_component();
@ -98,8 +101,8 @@ namespace Gdb_monitor {
** Region manager session interface **
**************************************/
Local_addr attach (Dataspace_capability, Genode::size_t,
Genode::off_t, bool, Local_addr, bool) override;
Local_addr attach (Dataspace_capability, size_t,
off_t, bool, Local_addr, bool) override;
void detach (Local_addr) override;
void fault_handler (Signal_context_capability) override;
State state () override;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -24,38 +24,11 @@
namespace Gdb_monitor
{
using namespace Genode;
class Rom_session_component;
class Local_rom_factory;
typedef Genode::Local_service<Rom_session_component> Rom_service;
using namespace Genode;
}
/**
* Clone a ROM dataspace in RAM
*/
static Genode::Capability<Genode::Ram_dataspace>
clone_rom(Genode::Capability<Genode::Rom_dataspace> rom_cap)
{
using namespace Genode;
Genode::size_t rom_size = Dataspace_client(rom_cap).size();
Capability<Ram_dataspace> clone_cap = env()->ram_session()->alloc(rom_size);
if (!clone_cap.valid()) {
error(__func__, ": memory allocation for cloned dataspace failed");
return Capability<Ram_dataspace>();
}
void *rom = env()->rm_session()->attach(rom_cap);
void *clone = env()->rm_session()->attach(clone_cap);
Genode::memcpy(clone, rom, rom_size);
env()->rm_session()->detach(rom);
env()->rm_session()->detach(clone);
return clone_cap;
typedef Local_service<Rom_session_component> Rom_service;
}
@ -66,20 +39,51 @@ class Gdb_monitor::Rom_session_component : public Rpc_object<Rom_session>
{
private:
Genode::Rpc_entrypoint &_ep;
Env &_env;
Rpc_entrypoint &_ep;
Capability<Ram_dataspace> _clone_cap;
/**
* Clone a ROM dataspace in RAM
*/
Capability<Ram_dataspace> _clone_rom(Capability<Rom_dataspace> rom_cap)
{
using namespace Genode;
size_t rom_size = Dataspace_client(rom_cap).size();
Capability<Ram_dataspace> clone_cap = _env.ram().alloc(rom_size);
if (!clone_cap.valid()) {
error(__func__, ": memory allocation for cloned dataspace failed");
return Capability<Ram_dataspace>();
}
void *rom = _env.rm().attach(rom_cap);
void *clone = _env.rm().attach(clone_cap);
memcpy(clone, rom, rom_size);
_env.rm().detach(rom);
_env.rm().detach(clone);
return clone_cap;
}
Capability<Ram_dataspace> _clone_cap;
public:
Rom_session_component(Genode::Rpc_entrypoint &ep, char const *filename)
: _ep(ep),
_clone_cap(clone_rom(Rom_connection(filename).dataspace()))
Rom_session_component(Env &env,
Rpc_entrypoint &ep,
char const *filename)
: _env(env),
_ep(ep),
_clone_cap(_clone_rom(Rom_connection(env, filename).dataspace()))
{ _ep.manage(this); }
~Rom_session_component()
{
env()->ram_session()->free(_clone_cap);
_env.ram().free(_clone_cap);
_ep.dissolve(this);
}
@ -93,7 +97,7 @@ class Gdb_monitor::Rom_session_component : public Rpc_object<Rom_session>
static_cap_cast<Dataspace>(_clone_cap));
}
void sigh(Genode::Signal_context_capability) override { }
void sigh(Signal_context_capability) override { }
};
@ -101,13 +105,14 @@ class Gdb_monitor::Local_rom_factory : public Rom_service::Factory
{
private:
Genode::Env &_env;
Genode::Rpc_entrypoint &_ep;
Env &_env;
Rpc_entrypoint &_ep;
Allocator &_alloc;
public:
Local_rom_factory(Genode::Env &env, Genode::Rpc_entrypoint &ep)
: _env(env), _ep(ep) { }
Local_rom_factory(Env &env, Rpc_entrypoint &ep, Allocator &alloc)
: _env(env), _ep(ep), _alloc(alloc) { }
/***********************
** Factory interface **
@ -117,15 +122,17 @@ class Gdb_monitor::Local_rom_factory : public Rom_service::Factory
{
Session_label const label = label_from_args(args.string());
return *new (env()->heap())
Rom_session_component(_ep, label.last_element().string());
return *new (_alloc)
Rom_session_component(_env,
_ep,
label.last_element().string());
}
void upgrade(Rom_session_component &, Args const &) override { }
void destroy(Rom_session_component &session) override
{
Genode::destroy(env()->heap(), &session);
Genode::destroy(_alloc, &session);
}
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -16,16 +16,17 @@
using namespace Genode;
using namespace Gdb_monitor;
Signal_handler_thread::Signal_handler_thread(Signal_receiver *receiver)
Signal_handler_thread::Signal_handler_thread(Env &env,
Signal_receiver &receiver)
:
Thread_deprecated<SIGNAL_HANDLER_THREAD_STACK_SIZE>("sig_handler"),
Thread(env, "sig_handler", SIGNAL_HANDLER_THREAD_STACK_SIZE),
_signal_receiver(receiver) { }
void Signal_handler_thread::entry()
{
while(1) {
Signal s = _signal_receiver->wait_for_signal();
Signal s = _signal_receiver.wait_for_signal();
Signal_dispatcher_base *signal_dispatcher =
dynamic_cast<Signal_dispatcher_base*>(s.context());

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
@ -17,22 +17,21 @@
#include <base/signal.h>
#include <base/thread.h>
using namespace Genode;
namespace Gdb_monitor {
using namespace Genode;
enum { SIGNAL_HANDLER_THREAD_STACK_SIZE = 2*1024*sizeof(addr_t) };
class Signal_handler_thread
: public Thread_deprecated<SIGNAL_HANDLER_THREAD_STACK_SIZE>
class Signal_handler_thread : public Thread
{
private:
Signal_receiver *_signal_receiver;
Signal_receiver &_signal_receiver;
public:
Signal_handler_thread(Signal_receiver *receiver);
Signal_handler_thread(Env &env, Signal_receiver &receiver);
void entry();
};

View File

@ -5,12 +5,17 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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.
*/
#include <cpu_thread/client.h>
#include "cpu_session_component.h"
#include "genode_child_resources.h"
extern "C" {
#define private _private
#include "server.h"
@ -19,11 +24,6 @@ extern "C" {
#define _private private
}
#include <cpu_thread/client.h>
#include "cpu_session_component.h"
#include "genode_child_resources.h"
using namespace Genode;
using namespace Gdb_monitor;
@ -35,11 +35,11 @@ static constexpr bool verbose = false;
Thread_state get_current_thread_state()
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources()->cpu_session_component();
ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id;
Cpu_thread_client cpu_thread(csc->thread_cap(ptid.lwp));
Cpu_thread_client cpu_thread(csc.thread_cap(ptid.lwp));
return cpu_thread.state();
}
@ -47,11 +47,11 @@ Thread_state get_current_thread_state()
void set_current_thread_state(Thread_state thread_state)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_session_component &csc = genode_child_resources()->cpu_session_component();
ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id;
Cpu_thread_client cpu_thread(csc->thread_cap(ptid.lwp));
Cpu_thread_client cpu_thread(csc.thread_cap(ptid.lwp));
cpu_thread.state(thread_state);
}

View File

@ -5,25 +5,28 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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/log.h>
/* GDB monitor includes */
#include "cpu_session_component.h"
#include "reg-arm.h"
#include "gdbserver_platform_helper.h"
#include "genode_child_resources.h"
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/log.h>
#include "cpu_session_component.h"
#include "reg-arm.h"
#include "gdbserver_platform_helper.h"
#include "genode_child_resources.h"
using namespace Genode;
static bool in_syscall(Thread_state const &ts)

View File

@ -5,24 +5,27 @@
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
* Copyright (C) 2011-2017 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/log.h>
/* GDB monitor includes */
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "genode_child_resources.h"
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/log.h>
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "genode_child_resources.h"
using namespace Genode;
static bool in_syscall(Thread_state const &thread_state)