GDB monitor: stability improvements

Fixes #1969
This commit is contained in:
Christian Prochaska 2016-05-17 16:13:23 +02:00 committed by Christian Helmuth
parent 2cde1d36c1
commit 5842b2065e
61 changed files with 3064 additions and 2360 deletions

View File

@ -256,7 +256,7 @@ via 'make run/gdb_monitor_interactive'. It will execute the scenario on Qemu and
use the UART to communicate with GDB. Qemu is instructed to redirect the second
serial interface to a local socket (using the port 5555):
! -serial chardev:uart
! -chardev socket,id=uart,port=5555,host=localhost,server,nowait
! -chardev socket,id=uart,port=5555,host=localhost,server,nowait,ipv4
The used TCP port is then specified to the GDB as remote target:
! target remote localhost:5555

View File

@ -1,7 +1 @@
INC_DIR += $(REP_DIR)/src/lib/gdbserver_libc_support
SRC_C += gdbserver_libc_support.c
LIBS += libc
vpath %.c $(REP_DIR)/src/lib/gdbserver_libc_support

View File

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

View File

@ -1,4 +1,6 @@
SRC_CC = spec/foc_arm/low.cc
SRC_CC = spec/foc_arm/low.cc \
spec/foc/native_cpu.cc
SRC_C = reg-arm.c \
linux-arm-low.c

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +1 @@
ca63e9871478fe3c800d7be3a26a5c4093d38f69
408b65147b4253d1ffa3d9ebd7b197df2a666261

View File

@ -11,6 +11,7 @@ DIR(gdb) := src/noux-pkg/gdb
GENODE_DIR := $(REP_DIR)/../..
PATCHES_DIR := $(GENODE_DIR)/tool/patches/gdb-$(VERSION)
PATCHES := $(addprefix $(PATCHES_DIR)/,$(shell cat $(PATCHES_DIR)/series)) \
$(REP_DIR)/src/app/gdb_monitor/siginfo.patch \
$(REP_DIR)/src/app/gdb_monitor/gdbserver_genode.patch \
$(REP_DIR)/src/noux-pkg/gdb/build.patch
PATCH_OPT := -p1 -d ${DIR(gdb)}

View File

@ -143,14 +143,14 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 "
run_genode_until {.*Remote debugging using /dev/terminal.*} 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\"" &
interact
interact -i [output_spawn_id]
# vi: set ft=tcl :

View File

@ -19,20 +19,17 @@ proc gdb_main_breakpoint_cmds { target_binary_name } {
# don't ask for y/n when loading a new symbol file
append gdb_cmds {-ex "set interactive-mode off" }
# load the symbols of ld.lib.so
append gdb_cmds {-ex "symbol-file bin/ld.lib.so" }
# set a breakpoint in the 'Linker::Binary::call_entry_point' function
append gdb_cmds {-ex "b Linker::Binary::call_entry_point" }
# set a breakpoint in the 'binary_ready_hook_for_gdb' function
append gdb_cmds {-ex "b binary_ready_hook_for_gdb" }
# continue execution until the breakpoint triggers
append gdb_cmds {-ex "c" }
# delete the 'call_program_main()' breakpoint
# delete the 'binary_ready_hook_for_gdb' breakpoint
append gdb_cmds {-ex "delete 1" }
# load the symbols of the test application
append gdb_cmds "-ex \"symbol-file bin/$target_binary_name\" "
append gdb_cmds "-ex \"file bin/$target_binary_name\" "
# set a breakpoint in the application's 'main()' function
append gdb_cmds {-ex "b main" }

View File

@ -6,8 +6,8 @@
#
#
# Only Genode/Fiasco.OC and Genode/NOVA supports all the tested features
# at this time
# Only the 32-bit NOVA and Fiasco.OC base platforms support most of the tested features
# at this time.
#
if {![have_include "power_on/qemu"] || (![have_spec foc] && ![have_spec nova])} {
@ -50,11 +50,11 @@ set config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="uart_drv">
<resource name="RAM" quantum="1M"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Terminal"/> </provides>
<config>
<policy label="gdb_monitor" uart="1"/>
@ -109,9 +109,9 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 "
run_genode_until {.*Remote debugging using /dev/terminal.*} 30
run_genode_until {.*\[init -> gdb_monitor\].*} 30
set genode_id [output_spawn_id]
puts "GDB monitor is up, starting GDB"
@ -123,128 +123,164 @@ 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]
#
# Test commands
#
# 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
set gdb_id [list $spawn_id $genode_id]
# test: breakpoint in shared library
append gdb_cmds {-ex "b puts" }
append gdb_cmds {-ex "c" }
puts ""
puts "----- test: breakpoint in 'main()' -----"
puts ""
# test: stack trace when not in syscall
append gdb_cmds {-ex "bt" }
run_genode_until {\(gdb\)} 60 $gdb_id
# test: modify variable
append gdb_cmds {-ex "print test_var" }
append gdb_cmds {-ex "set var test_var=2" }
append gdb_cmds {-ex "print test_var" }
# test: 'call' command
if {![have_spec nova]} {
append gdb_cmds {-ex "call test_var_func()" }
}
# test: thread info
append gdb_cmds {-ex "b Test_thread::entry()" }
append gdb_cmds {-ex "c" }
append gdb_cmds {-ex "info threads" }
# test: single stepping
append gdb_cmds {-ex "step" }
# test: catch segmentation fault
append gdb_cmds {-ex "c" }
# test: stack trace when in syscall
append gdb_cmds {-ex "thread 1" }
append gdb_cmds {-ex "bt" }
# quit
append gdb_cmds {-ex "q" }
# run GDB and redirect stderr to stdio to get the relevant output into the expect buffer
eval spawn [gdb] bin/$gdb_target_binary -n -batch $gdb_cmds 2&>1
set gdb_id $spawn_id
set timeout 120
expect {
-i [list $genode_id $gdb_id]
timeout { puts stderr "Error: Test execution timed out"; exit -2 }
}
set gdb_output $expect_out(buffer)
#
# Evaluate the test results
#
if {![regexp {Breakpoint 2, main ()} $gdb_output]} {
puts stderr "Error: Breakpoint in main() did not trigger"
if {![regexp {Breakpoint 2, main ()} $output]} {
puts stderr "*** Error: Breakpoint in main() did not trigger"
exit -1
}
if {![regexp {Breakpoint 3, puts (.*)} $gdb_output]} {
puts "Error: Breakpoint in shared library did not trigger"
puts "\n"
puts "----- test: breakpoint in shared library -----"
puts ""
send "b puts\n"
run_genode_until {\(gdb\)} 20 $gdb_id
send "c\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Breakpoint 3, puts ()} $output]} {
puts "*** Error: Breakpoint in shared library did not trigger"
exit -1
}
if {![regexp {#0 puts} $gdb_output] ||
![regexp {in func2()} $gdb_output] ||
![regexp {in func1()} $gdb_output] ||
![regexp {in main ()} $gdb_output]} {
puts "\n"
puts "----- test: stack trace when not in syscall -----"
puts ""
puts stderr "Error: Stack trace when not in syscall is not as expected"
send "bt\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {#0 puts} $output] ||
![regexp {in func2()} $output] ||
![regexp {in func1()} $output] ||
![regexp {in main ()} $output]} {
puts stderr "*** Error: Stack trace when not in syscall is not as expected"
exit -1
}
if {![regexp {\$1 = 1} $gdb_output]} {
puts stderr "Error: first 'print test_var' command didn't result in the expected output"
puts "\n"
puts "----- test: modification of a variable value -----"
puts ""
send "print test_var\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {\$1 = 1} $output]} {
puts stderr "*** Error: first 'print test_var' command didn't result in the expected output"
exit -1
}
if {![regexp {\$2 = 2} $gdb_output]} {
puts stderr "Error: second 'print test_var' command didn't result in the expected output"
send "set var test_var=2\n"
run_genode_until {\(gdb\)} 20 $gdb_id
send "print test_var\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {\$2 = 2} $output]} {
puts stderr "*** Error: second 'print test_var' command didn't result in the expected output"
exit -1
}
if {![have_spec nova]} {
if {![regexp {\$3 = 3} $gdb_output]} {
puts stderr "Error: 'call' command didn't result in the expected output"
exit -1
}
}
puts "\n"
puts "----- test: 'call' command -----"
puts ""
if {![regexp {Breakpoint 4, Test_thread::entry()} $gdb_output]} {
puts stderr "Error: Breakpoint in test thread did not trigger"
send "call test_var_func()\n"
run_genode_until {\(gdb\)} 60 $gdb_id
if {![regexp {\$3 = 3} $output]} {
puts stderr "*** Error: 'call' command didn't result in the expected output"
exit -1
}
if {![regexp {\* 2 Thread 2 Test_thread::entry} $gdb_output] ||
![regexp { 1 Thread 1} $gdb_output]} {
puts stderr "Error: Thread info is not as expected"
puts "\n"
puts "----- test: thread info -----"
puts ""
send "b Test_thread::entry()\n"
run_genode_until {\(gdb\)} 20 $gdb_id
send "c\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Breakpoint 4, Test_thread::entry()} $output]} {
puts stderr "*** Error: Breakpoint in test thread did not trigger"
exit -1
}
if {![regexp {38 static Timer::Connection timer} $gdb_output]} {
puts stderr "Error: Single stepping didn't result in the expected output"
send "info threads\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp { 4 Thread 3} $output] ||
![regexp {\* 3 Thread 4 Test_thread::entry} $output] ||
![regexp { 2 Thread 2} $output] ||
![regexp { 1 Thread 1} $output]} {
puts stderr "*** Error: Thread info is not as expected"
exit -1
}
if {![regexp {Program received signal SIGSEGV, Segmentation fault.} $gdb_output]} {
puts stderr "Error: Segmentation fault exception was not catched"
puts "\n"
puts "----- test: step into function -----"
puts ""
send "step\n"
run_genode_until {\(gdb\)} 30 $gdb_id
send "thread 2\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Test_thread::step_func} $output]} {
puts stderr "*** Error: Step into function didn't result in the expected output"
exit -1
}
if {![regexp {Genode::Cancelable_lock::lock\(\)} $gdb_output] ||
![regexp {Genode::Thread::join\(\)} $gdb_output] ||
![regexp {in main \(\)} $gdb_output]} {
puts "\n"
puts "----- test: catching a segmentation fault -----"
puts ""
puts stderr "Error: Stack trace when in syscall is not as expected"
send "c\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Program received signal SIGSEGV, Segmentation fault.} $output]} {
puts stderr "*** Error: Segmentation fault exception was not caught"
exit -1
}
# does not work well on ARM yet
if {![have_spec arm]} {
puts "\n"
puts "----- test: stack trace when in syscall -----"
puts ""
send "thread 2\n"
run_genode_until {\(gdb\)} 20 $gdb_id
send "bt\n"
run_genode_until {\(gdb\)} 20 $gdb_id
if {![regexp {Genode::Cancelable_lock::lock\(\)} $output] ||
![regexp {Genode::Thread::join\(\)} $output] ||
![regexp {in main \(\)} $output]} {
puts stderr "*** Error: Stack trace when in syscall is not as expected"
exit -1
}
}
puts ""
# vi: set ft=tcl :

View File

@ -39,11 +39,11 @@ set config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="uart_drv">
<resource name="RAM" quantum="1M"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Terminal"/> </provides>
<config>
<policy label="gdb_monitor" uart="1"/>
@ -98,7 +98,7 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 "
run_genode_until {.*Remote debugging using /dev/terminal.*} 30
@ -119,7 +119,7 @@ append gdb_cmds {-ex "set interactive-mode auto" }
puts "command: [gdb] bin/$gdb_target_binary $gdb_cmds"
exec [terminal] -e "[gdb] bin/test-gdb_monitor $gdb_cmds" &
exec [terminal] -e "[gdb] bin/ld.lib.so $gdb_cmds" &
interact -i [output_spawn_id]

View File

@ -92,7 +92,7 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait "
append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 "
run_genode_until {.*Remote debugging using /dev/terminal.*} 30

View File

@ -1,5 +1,5 @@
if {![have_spec foc] || ![have_spec 32bit]} {
puts "\nThe Noux GDB scenario is supported on 32-bit Fiasco.OC only\n"
if {![have_spec foc] && ![have_spec nova]} {
puts "\nThe Noux GDB scenario is supported on NOVA and Fiasco.OC only\n"
exit 0
}
@ -126,7 +126,7 @@ append config {
<provides> <service name="Terminal"/> </provides>
</start>
<start name="gdb_monitor">
<resource name="RAM" quantum="10M"/>
<resource name="RAM" quantum="16M"/>
<route>
<service name="Terminal"><child name="terminal_gdb"/></service>
<any-service><parent/><any-child/></any-service>
@ -171,19 +171,18 @@ append config {
</fstab> }
append config "
<start name=\"/bin/${tool_prefix}gdb\">
<arg value=\"/gdb/${gdb_target_binary_name}\"/> "
<arg value=\"/gdb/ld.lib.so\"/> "
append config {
<arg value="-ex" /><arg value="set interactive-mode off" />
<arg value="-ex" /><arg value="directory /gdb/src" />
<arg value="-ex" /><arg value="target remote /dev/gdb" />
<arg value="-ex" /><arg value="symbol-file /gdb/ld.lib.so" />
<arg value="-ex" /><arg value="b call_program_main" />
<arg value="-ex" /><arg value="b binary_ready_hook_for_gdb" />
<arg value="-ex" /><arg value="c" />
<arg value="-ex" /><arg value="delete 1" /> }
append config "
<arg value=\"-ex\" /><arg value=\"symbol-file /gdb/${gdb_target_binary_name}\" /> "
<arg value=\"-ex\" /><arg value=\"file /gdb/${gdb_target_binary_name}\" /> "
append config {
<arg value="-ex" /><arg value="b main()" />
<arg value="-ex" /><arg value="b main" />
<arg value="-ex" /><arg value="set solib-search-path /gdb" />
<arg value="-ex" /><arg value="sharedlibrary" />
<arg value="-ex" /><arg value="c" />

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
* Copyright (C) 2009-2016 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.
@ -26,292 +26,333 @@
#include <util/arg_string.h>
#include "cpu_root.h"
#include "gdb_stub_thread.h"
#include "ram_root.h"
#include "genode_child_resources.h"
#include "pd_session_component.h"
#include "ram_root.h"
#include "rom.h"
namespace Gdb_monitor {
namespace Gdb_monitor { class App_child; }
class App_child : public Child_policy, public Init::Child_policy_enforce_labeling
{
private:
class Gdb_monitor::App_child : public Child_policy,
public Init::Child_policy_enforce_labeling
{
private:
enum { STACK_SIZE = 4*1024*sizeof(long) };
enum { STACK_SIZE = 4*1024*sizeof(long) };
const char *_unique_name;
const char *_unique_name;
Rpc_entrypoint _entrypoint;
Genode::Dataspace_capability _elf_ds;
Genode::Dataspace_capability _ldso_ds;
Service_registry *_parent_services;
Service_registry _local_services;
Rpc_entrypoint _entrypoint;
Init::Child_config _child_config;
Service_registry *_parent_services;
Service_registry _local_services;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_provide_rom_file _config_policy;
Genode::Rpc_entrypoint *_root_ep;
Gdb_stub_thread _gdb_stub_thread;
Dataspace_pool _managed_ds_map;
Init::Child_config _child_config;
Cpu_root _cpu_root;
Cpu_session_client _cpu_session;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_provide_rom_file _config_policy;
Ram_session_client _ram_session;
Genode_child_resources _genode_child_resources;
Pd_session_component _pd { _unique_name, _entrypoint,
_managed_ds_map };
Signal_dispatcher<App_child> _unresolved_page_fault_dispatcher;
Region_map_client _address_space { _pd.address_space() };
Dataspace_pool _managed_ds_map;
Child::Initial_thread _initial_thread;
Pd_session_component _pd {_unique_name, _entrypoint, _managed_ds_map};
Child _child;
Cpu_root _cpu_root;
Cpu_session_client _cpu_session;
Genode::Rpc_entrypoint *_root_ep;
Ram_session_client _ram_session;
Rom_service _rom_service;
Region_map_client _address_space { _pd.address_space() };
Cpu_session_capability _get_cpu_session_cap()
{
_entrypoint.manage(&_cpu_root);
char args[64];
Genode::snprintf(args, sizeof(args), "ram_quota=32K, label=\"%s\"", _unique_name);
return static_cap_cast<Cpu_session>(_cpu_root.session(args, Affinity()));
}
Child::Initial_thread _initial_thread;
/**
* Proxy for a service provided by the child
*/
class Child_service_root : public Genode::Rpc_object<Genode::Root>
{
private:
Parent_service _parent_pd_service { "" };
Parent_service _parent_ram_service { "" };
Parent_service _parent_cpu_service { "" };
/**
* Root interface of the real service, provided by the child
Child *_child;
Rom_service _rom_service;
Cpu_session_capability _get_cpu_session_cap()
{
_entrypoint.manage(&_cpu_root);
char args[64];
Genode::snprintf(args, sizeof(args), "ram_quota=64K, label=\"%s\"", _unique_name);
return static_cap_cast<Cpu_session>(_cpu_root.session(args, Affinity()));
}
/**
* 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.
*/
Genode::Root_client _child_root;
_sessions.insert(new (env()->heap())
Child_session(cap, ram_quota));
return cap;
}
/**
* Child's RAM session used for quota transfers
*/
Genode::Ram_session_capability _child_ram;
void upgrade(Session_capability session_cap,
Upgrade_args const &args)
{
using namespace Genode;
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;
auto lambda = [&] (Child_session *session) {
if (!session) {
PERR("attempt to upgrade unknown session");
return;
}
Genode::size_t ram_quota =
Arg_string::find_arg(args.string(),
"ram_quota").ulong_value(0);
"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);
session->ram_quota += ram_quota;
/*
* Keep information about donated quota in '_sessions'
* data base.
*/
_sessions.insert(new (env()->heap())
Child_session(cap, ram_quota));
return cap;
}
/* inform child about quota upgrade */
_child_root.upgrade(session_cap, args);
};
void upgrade(Session_capability session_cap,
Upgrade_args const &args)
{
using namespace Genode;
auto lambda = [&] (Child_session *session) {
if (!session) {
PERR("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) {
PERR("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);
}
};
public:
/**
* Constructor
*
* \param root_ep entrypoint serving the root interfaces of the
* services provided by the child and announced
* towards the parent of GDB monitor
*/
App_child(const char *unique_name,
Genode::Dataspace_capability elf_ds,
Genode::Dataspace_capability ldso_ds,
Genode::Ram_session_capability ram_session,
Genode::Cap_session *cap_session,
Service_registry *parent_services,
Genode::Rpc_entrypoint *root_ep,
Xml_node target_node)
: Init::Child_policy_enforce_labeling(unique_name),
_unique_name(unique_name),
_entrypoint(cap_session, STACK_SIZE, "GDB monitor entrypoint name"),
_parent_services(parent_services),
_child_config(ram_session, target_node),
_binary_policy("binary", elf_ds, &_entrypoint),
_config_policy("config", _child_config.dataspace(), &_entrypoint),
_gdb_stub_thread(),
_cpu_root(&_entrypoint, env()->heap() /* should be _child.heap() */, &_gdb_stub_thread),
_cpu_session(_get_cpu_session_cap()),
_ram_session(ram_session),
_initial_thread(_cpu_session, _pd.cap(), unique_name),
_child(elf_ds, ldso_ds, _pd.cap(), _pd,
_ram_session, _ram_session, _cpu_session, _initial_thread,
*Genode::env()->rm_session(), _address_space, _entrypoint, *this),
_root_ep(root_ep),
_rom_service(&_entrypoint, _child.heap())
{
_gdb_stub_thread.set_region_map_component(&_pd.region_map());
_local_services.insert(&_rom_service);
_gdb_stub_thread.start();
}
~App_child()
{
}
/****************************
** Child-policy interface **
****************************/
const char *name() const { return _unique_name; }
void filter_session_args(const char *, char *args, Genode::size_t args_len)
{
Init::Child_policy_enforce_labeling::filter_session_args(0, args, args_len);
}
Service *resolve_session_request(const char *service_name,
const char *args)
{
Service *service = 0;
/* check for binary file request */
if ((service = _binary_policy.resolve_session_request(service_name, args)))
return service;
/* check for config file request */
if ((service = _config_policy.resolve_session_request(service_name, args)))
return service;
service = _local_services.find(service_name);
if (service)
return service;
service = _parent_services->find(service_name);
if (!service) {
service = new (env()->heap()) Parent_service(service_name);
_parent_services->insert(service);
_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) {
PERR("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);
}
};
void _dispatch_unresolved_page_fault(unsigned)
{
_genode_child_resources.cpu_session_component()->handle_unresolved_page_fault();
}
public:
/**
* Constructor
*
* \param root_ep entrypoint serving the root interfaces of the
* services provided by the child and announced
* towards the parent of GDB monitor
*/
App_child(const char *unique_name,
Genode::Dataspace_capability elf_ds,
Genode::Dataspace_capability ldso_ds,
Genode::Ram_session_capability ram_session,
Genode::Cap_session *cap_session,
Service_registry *parent_services,
Genode::Rpc_entrypoint *root_ep,
Signal_receiver *signal_receiver,
Xml_node target_node)
: Init::Child_policy_enforce_labeling(unique_name),
_unique_name(unique_name),
_elf_ds(elf_ds),
_ldso_ds(ldso_ds),
_entrypoint(cap_session, STACK_SIZE, "GDB monitor entrypoint name"),
_parent_services(parent_services),
_root_ep(root_ep),
_child_config(ram_session, target_node),
_binary_policy("binary", elf_ds, &_entrypoint),
_config_policy("config", _child_config.dataspace(), &_entrypoint),
_unresolved_page_fault_dispatcher(*signal_receiver,
*this,
&App_child::_dispatch_unresolved_page_fault),
_cpu_root(&_entrypoint, &_entrypoint, env()->heap(), _pd.core_pd_cap(),
signal_receiver, &_genode_child_resources),
_cpu_session(_get_cpu_session_cap()),
_ram_session(ram_session),
_initial_thread(_cpu_session, _pd.cap(), unique_name),
_rom_service(&_entrypoint, env()->heap())
{
_genode_child_resources.region_map_component(&_pd.region_map());
_pd.region_map().fault_handler(_unresolved_page_fault_dispatcher);
_local_services.insert(&_rom_service);
}
~App_child()
{
destroy(env()->heap(), _child);
}
Genode_child_resources *genode_child_resources()
{
return &_genode_child_resources;
}
void start()
{
_child = new (env()->heap()) Child(_elf_ds,
_ldso_ds,
_pd.cap(),
_pd,
_ram_session,
_ram_session,
_cpu_session,
_initial_thread,
*Genode::env()->rm_session(),
_address_space,
_entrypoint,
*this);
}
/****************************
** Child-policy interface **
****************************/
const char *name() const { return _unique_name; }
void filter_session_args(const char *, char *args, Genode::size_t args_len)
{
Init::Child_policy_enforce_labeling::filter_session_args(0, args, args_len);
}
Service *resolve_session_request(const char *service_name,
const char *args)
{
Service *service = 0;
/* check for binary file request */
if ((service = _binary_policy.resolve_session_request(service_name, args)))
return service;
/* check for config file request */
if ((service = _config_policy.resolve_session_request(service_name, args)))
return service;
service = _local_services.find(service_name);
if (service)
return service;
service = _parent_services->find(service_name);
if (!service) {
service = new (env()->heap()) Parent_service(service_name);
_parent_services->insert(service);
}
bool announce_service(const char *name,
Root_capability root,
Allocator *alloc,
Server *server)
{
/* create and announce proxy for the child's root interface */
Child_service_root *r = new (alloc)
Child_service_root(_ram_session, root);
return service;
}
Genode::env()->parent()->announce(name, _root_ep->manage(r));
return true;
}
};
}
bool announce_service(const char *name,
Root_capability root,
Allocator *alloc,
Server *server)
{
/* 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));
return true;
}
};
#endif /* _APP_CHILD_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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,43 +21,58 @@
#include <cpu_session_component.h>
/* GDB monitor includes */
#include "gdb_stub_thread.h"
#include "genode_child_resources.h"
namespace Gdb_monitor {
namespace Gdb_monitor { class Cpu_root; }
class Cpu_root : public Root_component<Cpu_session_component>
{
private:
Gdb_stub_thread *_gdb_stub_thread;
class Gdb_monitor::Cpu_root : public Root_component<Cpu_session_component>
{
private:
protected:
Rpc_entrypoint *_thread_ep;
Allocator *_md_alloc;
Pd_session_capability _core_pd;
Genode::Signal_receiver *_signal_receiver;
Genode_child_resources *_genode_child_resources;
Cpu_session_component *_create_session(const char *args)
{
Cpu_session_component *cpu_session_component =
new (md_alloc())
Cpu_session_component(_gdb_stub_thread->exception_signal_receiver(), args);
_gdb_stub_thread->set_cpu_session_component(cpu_session_component);
return cpu_session_component;
}
protected:
public:
Cpu_session_component *_create_session(const char *args)
{
Cpu_session_component *cpu_session_component =
new (md_alloc())
Cpu_session_component(_thread_ep,
_md_alloc,
_core_pd,
_signal_receiver,
args);
_genode_child_resources->cpu_session_component(cpu_session_component);
return cpu_session_component;
}
/**
* Constructor
*
* \param session_ep entry point for managing cpu session objects
* \param thread_ep entry point for managing threads
* \param md_alloc meta data allocator to be used by root component
*/
Cpu_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc,
Gdb_stub_thread *gdb_stub_thread)
:
Root_component<Cpu_session_component>(session_ep, md_alloc),
_gdb_stub_thread(gdb_stub_thread)
{ }
};
}
public:
/**
* Constructor
*
* \param session_ep entry point for managing cpu session objects
* \param thread_ep entry point for managing threads
* \param md_alloc meta data allocator to be used by root component
*/
Cpu_root(Rpc_entrypoint *session_ep,
Rpc_entrypoint *thread_ep,
Allocator *md_alloc,
Pd_session_capability core_pd,
Genode::Signal_receiver *signal_receiver,
Genode_child_resources *genode_child_resources)
:
Root_component<Cpu_session_component>(session_ep, md_alloc),
_thread_ep(thread_ep),
_md_alloc(md_alloc),
_core_pd(core_pd),
_signal_receiver(signal_receiver),
_genode_child_resources(genode_child_resources)
{ }
};
#endif /* _CPU_ROOT_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,31 +14,69 @@
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <cpu_session_component.h>
#include <util/list.h>
/* GDB monitor includes */
#include "config.h"
#include "cpu_thread_component.h"
extern void genode_add_thread(unsigned long lwpid);
/* genode-low.cc */
extern void genode_remove_thread(unsigned long lwpid);
using namespace Genode;
using namespace Gdb_monitor;
/* FIXME: use an allocator */
static unsigned long new_lwpid = GENODE_LWP_BASE;
Thread_info *Cpu_session_component::_thread_info(Thread_capability thread_cap)
Cpu_session &Cpu_session_component::parent_cpu_session()
{
Thread_info *thread_info = _thread_list.first();
while (thread_info) {
if (thread_info->thread_cap().local_name() == thread_cap.local_name()) {
return thread_info;
break;
}
thread_info = thread_info->next();
return _parent_cpu_session;
}
Rpc_entrypoint &Cpu_session_component::thread_ep()
{
return *_thread_ep;
}
Signal_receiver *Cpu_session_component::exception_signal_receiver()
{
return _exception_signal_receiver;
}
Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid)
{
Cpu_thread_component *cpu_thread = _thread_list.first();
while (cpu_thread) {
if (cpu_thread->lwpid() == lwpid)
return cpu_thread->thread_cap();
cpu_thread = cpu_thread->next();
}
return Thread_capability();
}
Cpu_thread_component *Cpu_session_component::lookup_cpu_thread(unsigned long lwpid)
{
Cpu_thread_component *cpu_thread = _thread_list.first();
while (cpu_thread) {
if (cpu_thread->lwpid() == lwpid)
return cpu_thread;
cpu_thread = cpu_thread->next();
}
return nullptr;
}
Cpu_thread_component *Cpu_session_component::lookup_cpu_thread(Thread_capability thread_cap)
{
Cpu_thread_component *cpu_thread = _thread_list.first();
while (cpu_thread) {
if (cpu_thread->thread_cap().local_name() == thread_cap.local_name())
return cpu_thread;
cpu_thread = cpu_thread->next();
}
return 0;
}
@ -46,68 +84,150 @@ Thread_info *Cpu_session_component::_thread_info(Thread_capability thread_cap)
unsigned long Cpu_session_component::lwpid(Thread_capability thread_cap)
{
return _thread_info(thread_cap)->lwpid();
return lookup_cpu_thread(thread_cap)->lwpid();
}
Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid)
int Cpu_session_component::signal_pipe_read_fd(Thread_capability thread_cap)
{
Thread_info *thread_info = _thread_list.first();
while (thread_info) {
if (thread_info->lwpid() == lwpid) {
return thread_info->thread_cap();
return lookup_cpu_thread(thread_cap)->signal_pipe_read_fd();
}
int Cpu_session_component::send_signal(Thread_capability thread_cap,
int signo)
{
Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap);
cpu_thread->pause();
switch (signo) {
case SIGSTOP:
Signal_transmitter(cpu_thread->sigstop_signal_context_cap()).submit();
return 1;
case SIGINT:
Signal_transmitter(cpu_thread->sigint_signal_context_cap()).submit();
return 1;
default:
PERR("unexpected signal %d", signo);
return 0;
}
}
/*
* This function delivers a SIGSEGV to the first thread with an unresolved
* page fault that it finds. Multiple page-faulted threads are currently
* not supported.
*/
void Cpu_session_component::handle_unresolved_page_fault()
{
/*
* It can happen that the thread state of the thread which caused the
* page fault is not accessible yet. In that case, we'll retry until
* it is accessible.
*/
while (1) {
Thread_capability thread_cap = first();
while (thread_cap.valid()) {
try {
Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap);
Thread_state thread_state = cpu_thread->state();
if (thread_state.unresolved_page_fault) {
/*
* On base-foc it is necessary to pause the thread before
* IP and SP are available in the thread state.
*/
cpu_thread->pause();
cpu_thread->deliver_signal(SIGSEGV);
return;
}
} catch (Cpu_thread::State_access_failed) { }
thread_cap = next(thread_cap);
}
thread_info = thread_info->next();
}
return Thread_capability();
}
Thread_capability
Cpu_session_component::create_thread(Capability<Pd_session> pd,
Name const &name,
Affinity::Location location,
Weight weight,
addr_t utcb)
void Cpu_session_component::stop_new_threads(bool stop)
{
Thread_capability thread_cap =
_parent_cpu_session.create_thread(pd, name, location, weight, utcb);
if (thread_cap.valid()) {
Thread_info *thread_info = new (env()->heap()) Thread_info(thread_cap, new_lwpid++);
_thread_list.append(thread_info);
}
return thread_cap;
_stop_new_threads = stop;
}
//Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread)
//{
// return _parent_cpu_session.utcb(thread);
//}
void Cpu_session_component::kill_thread(Thread_capability thread_cap)
bool Cpu_session_component::stop_new_threads()
{
Thread_info *thread_info = _thread_info(thread_cap);
return _stop_new_threads;
}
if (thread_info) {
_exception_signal_receiver->dissolve(thread_info);
genode_remove_thread(thread_info->lwpid());
_thread_list.remove(thread_info);
destroy(env()->heap(), thread_info);
Lock &Cpu_session_component::stop_new_threads_lock()
{
return _stop_new_threads_lock;
}
int Cpu_session_component::handle_initial_breakpoint(unsigned long lwpid)
{
Cpu_thread_component *cpu_thread = _thread_list.first();
while (cpu_thread) {
if (cpu_thread->lwpid() == lwpid)
return cpu_thread->handle_initial_breakpoint();
cpu_thread = cpu_thread->next();
}
return 0;
}
_parent_cpu_session.kill_thread(thread_cap);
void Cpu_session_component::pause_all_threads()
{
Lock::Guard stop_new_threads_lock_guard(stop_new_threads_lock());
stop_new_threads(true);
for (Cpu_thread_component *cpu_thread = _thread_list.first();
cpu_thread;
cpu_thread = cpu_thread->next()) {
cpu_thread->pause();
}
}
void Cpu_session_component::resume_all_threads()
{
Lock::Guard stop_new_threads_guard(stop_new_threads_lock());
stop_new_threads(false);
for (Cpu_thread_component *cpu_thread = _thread_list.first();
cpu_thread;
cpu_thread = cpu_thread->next()) {
cpu_thread->single_step(false);
cpu_thread->resume();
}
}
Thread_capability Cpu_session_component::first()
{
Thread_info *thread_info = _thread_list.first();
if (thread_info)
return thread_info->thread_cap();
Cpu_thread_component *cpu_thread = _thread_list.first();
if (cpu_thread)
return cpu_thread->thread_cap();
else
return Thread_capability();
}
@ -115,77 +235,50 @@ Thread_capability Cpu_session_component::first()
Thread_capability Cpu_session_component::next(Thread_capability thread_cap)
{
Thread_info *next_thread_info = _thread_info(thread_cap)->next();
if (next_thread_info)
return next_thread_info->thread_cap();
Cpu_thread_component *next_cpu_thread = lookup_cpu_thread(thread_cap)->next();
if (next_cpu_thread)
return next_cpu_thread->thread_cap();
else
return Thread_capability();
}
//int Cpu_session_component::start(Thread_capability thread_cap,
// addr_t ip, addr_t sp)
//{
// Thread_info *thread_info = _thread_info(thread_cap);
//
// if (thread_info)
// exception_handler(thread_cap, _exception_signal_receiver->manage(thread_info));
//
// int result = _parent_cpu_session.start(thread_cap, ip, sp);
//
// if (thread_info) {
// /* pause the first thread */
// if (thread_info->lwpid() == GENODE_LWP_BASE)
// pause(thread_cap);
//
// genode_add_thread(thread_info->lwpid());
// }
//
// return result;
//}
//void Cpu_session_component::pause(Thread_capability thread_cap)
//{
// _parent_cpu_session.pause(thread_cap);
//}
//void Cpu_session_component::resume(Thread_capability thread_cap)
//{
// _parent_cpu_session.resume(thread_cap);
//}
//void Cpu_session_component::cancel_blocking(Thread_capability thread_cap)
//{
// _parent_cpu_session.cancel_blocking(thread_cap);
//}
//void Cpu_session_component::state(Thread_capability thread_cap,
// Thread_state const &state)
//{
// _parent_cpu_session.state(thread_cap, state);
//}
//Thread_state Cpu_session_component::state(Thread_capability thread_cap)
//{
// return _parent_cpu_session.state(thread_cap);
//}
void Cpu_session_component::exception_sigh(Signal_context_capability sigh_cap)
Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd,
Cpu_session::Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb)
{
_parent_cpu_session.exception_sigh(sigh_cap);
Cpu_thread_component *cpu_thread =
new (_md_alloc) Cpu_thread_component(*this, _core_pd, name,
affinity, weight, utcb);
_thread_list.append(cpu_thread);
return cpu_thread->cap();
}
//void Cpu_session_component::single_step(Thread_capability thread_cap, bool enable)
//{
// _parent_cpu_session.single_step(thread_cap, enable);
//}
void Cpu_session_component::kill_thread(Thread_capability thread_cap)
{
Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap);
if (cpu_thread) {
genode_remove_thread(cpu_thread->lwpid());
_thread_list.remove(cpu_thread);
destroy(_md_alloc, cpu_thread);
} else
PERR("%s: could not find thread info for the given thread capability",
__PRETTY_FUNCTION__);
_parent_cpu_session.kill_thread(thread_cap);
}
void Cpu_session_component::exception_sigh(Signal_context_capability handler)
{
_parent_cpu_session.exception_sigh(handler);
}
Affinity::Space Cpu_session_component::affinity_space() const
@ -194,56 +287,49 @@ Affinity::Space Cpu_session_component::affinity_space() const
}
//void Cpu_session_component::affinity(Thread_capability thread_cap,
// Affinity::Location location)
//{
// _parent_cpu_session.affinity(thread_cap, location);
//}
Dataspace_capability Cpu_session_component::trace_control()
{
return _parent_cpu_session.trace_control();
}
//unsigned Cpu_session_component::trace_control_index(Thread_capability thread)
//{
// return _parent_cpu_session.trace_control_index(thread);
//}
//Dataspace_capability Cpu_session_component::trace_buffer(Thread_capability thread)
//{
// return _parent_cpu_session.trace_buffer(thread);
//}
//Dataspace_capability Cpu_session_component::trace_policy(Thread_capability thread)
//{
// return _parent_cpu_session.trace_policy(thread);
//}
Capability<Cpu_session::Native_cpu> Cpu_session_component::native_cpu()
{
return _parent_cpu_session.native_cpu();
return _native_cpu_cap;
}
Cpu_session_component::Cpu_session_component(Signal_receiver *exception_signal_receiver, const char *args)
: _parent_cpu_session(env()->parent()->session<Cpu_session>(args)),
_exception_signal_receiver(exception_signal_receiver)
Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep,
Allocator *md_alloc,
Pd_session_capability core_pd,
Signal_receiver *exception_signal_receiver,
const char *args)
: _thread_ep(thread_ep),
_md_alloc(md_alloc),
_core_pd(core_pd),
_parent_cpu_session(env()->parent()->session<Cpu_session>(args)),
_exception_signal_receiver(exception_signal_receiver),
_native_cpu_cap(_setup_native_cpu())
{
}
Cpu_session_component::~Cpu_session_component()
{
for (Cpu_thread_component *cpu_thread = _thread_list.first();
cpu_thread; cpu_thread = _thread_list.first()) {
_thread_list.remove(cpu_thread);
destroy(_md_alloc, cpu_thread);
}
_cleanup_native_cpu();
}
int Cpu_session_component::ref_account(Cpu_session_capability) { 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-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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,40 +15,77 @@
#define _CPU_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <base/thread.h>
#include <cpu_session/client.h>
#include <pd_session/capability.h>
/* GDB monitor includes */
#include "thread_info.h"
#include "append_list.h"
using namespace Genode;
using namespace Gdb_monitor;
class Cpu_session_component : public Rpc_object<Cpu_session>
namespace Gdb_monitor
{
class Cpu_session_component;
class Cpu_thread_component;
using namespace Genode;
}
class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
{
private:
Rpc_entrypoint *_thread_ep;
Allocator *_md_alloc;
Pd_session_capability _core_pd;
Cpu_session_client _parent_cpu_session;
Signal_receiver *_exception_signal_receiver;
Append_list<Thread_info> _thread_list;
Append_list<Cpu_thread_component> _thread_list;
Thread_info *_thread_info(Thread_capability thread_cap);
bool _stop_new_threads = true;
Lock _stop_new_threads_lock;
Capability<Cpu_session::Native_cpu> _native_cpu_cap;
Capability<Cpu_session::Native_cpu> _setup_native_cpu();
void _cleanup_native_cpu();
public:
/**
* Constructor
*/
Cpu_session_component(Signal_receiver *exception_signal_receiver, const char *args);
Cpu_session_component(Rpc_entrypoint *thread_ep,
Allocator *md_alloc,
Pd_session_capability core_pd,
Signal_receiver *exception_signal_receiver,
const char *args);
/**
* Destructor
*/
~Cpu_session_component();
unsigned long lwpid(Thread_capability thread_cap);
Cpu_session &parent_cpu_session();
Rpc_entrypoint &thread_ep();
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);
Cpu_thread_component *lookup_cpu_thread(Thread_capability thread_cap);
int signal_pipe_read_fd(Thread_capability thread_cap);
int send_signal(Thread_capability thread_cap, int signo);
void handle_unresolved_page_fault();
void stop_new_threads(bool stop);
bool stop_new_threads();
Lock &stop_new_threads_lock();
int handle_initial_breakpoint(unsigned long lwpid);
void pause_all_threads();
void resume_all_threads();
Thread_capability first();
Thread_capability next(Thread_capability);
@ -56,8 +93,11 @@ class Cpu_session_component : public Rpc_object<Cpu_session>
** CPU session interface **
***************************/
Thread_capability create_thread(Capability<Pd_session>, Name const &,
Affinity::Location, Weight, addr_t) override;
Thread_capability create_thread(Capability<Pd_session>,
Name const &,
Affinity::Location,
Weight,
addr_t) override;
void kill_thread(Thread_capability) override;
void exception_sigh(Signal_context_capability handler) override;
Affinity::Space affinity_space() const override;

View File

@ -0,0 +1,151 @@
/*
* \brief Cpu_thread_component class for GDB monitor
* \author Christian Prochaska
* \date 2016-05-12
*/
/*
* Copyright (C) 2016 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.
*/
/* GDB monitor includes */
#include "cpu_thread_component.h"
/* mem-break.c */
extern "C" int breakpoint_len;
extern "C" const unsigned char *breakpoint_data;
extern "C" int set_gdb_breakpoint_at(long long where);
/* genode-low.cc */
extern "C" int genode_read_memory(long long memaddr, unsigned char *myaddr, int len);
extern "C" int genode_write_memory (long long memaddr, const unsigned char *myaddr, int len);
extern void genode_set_initial_breakpoint_at(long long addr);
static unsigned long new_lwpid = GENODE_MAIN_LWPID;
using namespace Gdb_monitor;
bool Cpu_thread_component::_set_breakpoint_at_first_instruction(addr_t ip)
{
_breakpoint_ip = ip;
if (genode_read_memory(_breakpoint_ip, _original_instructions,
breakpoint_len) != 0) {
PWRN("%s: could not read memory at thread start address", __PRETTY_FUNCTION__);
return false;
}
if (genode_write_memory(_breakpoint_ip, breakpoint_data,
breakpoint_len) != 0) {
PWRN("%s: could not set breakpoint at thread start address", __PRETTY_FUNCTION__);
return false;
}
return true;
}
void Cpu_thread_component::_remove_breakpoint_at_first_instruction()
{
if (genode_write_memory(_breakpoint_ip, _original_instructions,
breakpoint_len) != 0)
PWRN("%s: could not remove breakpoint at thread start address", __PRETTY_FUNCTION__);
}
Dataspace_capability Cpu_thread_component::utcb()
{
return _parent_cpu_thread.utcb();
}
void Cpu_thread_component::start(addr_t ip, addr_t sp)
{
_lwpid = new_lwpid++;
_initial_ip = ip;
/* register the exception handler */
exception_sigh(exception_signal_context_cap());
/* set breakpoint at first instruction */
if (lwpid() == GENODE_MAIN_LWPID)
_set_breakpoint_at_first_instruction(ip);
else
genode_set_initial_breakpoint_at(ip);
_parent_cpu_thread.start(ip, sp);
}
void Cpu_thread_component::pause()
{
_parent_cpu_thread.pause();
}
void Cpu_thread_component::resume()
{
_parent_cpu_thread.resume();
}
void Cpu_thread_component::single_step(bool enable)
{
_parent_cpu_thread.single_step(enable);
}
void Cpu_thread_component::cancel_blocking()
{
_parent_cpu_thread.cancel_blocking();
}
void Cpu_thread_component::state(Thread_state const &state)
{
_parent_cpu_thread.state(state);
}
Thread_state Cpu_thread_component::state()
{
return _parent_cpu_thread.state();
}
void Cpu_thread_component::exception_sigh(Signal_context_capability handler)
{
_parent_cpu_thread.exception_sigh(handler);
}
void Cpu_thread_component::affinity(Affinity::Location location)
{
_parent_cpu_thread.affinity(location);
}
unsigned Cpu_thread_component::trace_control_index()
{
return _parent_cpu_thread.trace_control_index();
}
Dataspace_capability Cpu_thread_component::trace_buffer()
{
return _parent_cpu_thread.trace_buffer();
}
Dataspace_capability Cpu_thread_component::trace_policy()
{
return _parent_cpu_thread.trace_policy();
}

View File

@ -0,0 +1,260 @@
/*
* \brief Cpu_thread_component class for GDB monitor
* \author Christian Prochaska
* \date 2016-05-12
*/
/*
* Copyright (C) 2016 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 _CPU_THREAD_COMPONENT_H_
#define _CPU_THREAD_COMPONENT_H_
/* Genode includes */
#include <base/thread.h>
#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"
extern "C" int delete_gdb_breakpoint_at(long long where);
namespace Gdb_monitor { class Cpu_thread_component; }
class Gdb_monitor::Cpu_thread_component : public Rpc_object<Cpu_thread>,
public Append_list<Cpu_thread_component>::Element
{
private:
static constexpr bool _verbose = false;
Cpu_session_component &_cpu_session_component;
Cpu_thread_client _parent_cpu_thread;
unsigned long _lwpid;
addr_t _initial_ip;
/*
* SIGTRAP, SIGSTOP and SIGINT must get delivered to the gdbserver code
* in the same order that they were generated. Since these signals are
* generated by different threads, the exception signal receiver is
* used as synchronization point.
*/
Signal_dispatcher<Cpu_thread_component> _exception_dispatcher;
Signal_dispatcher<Cpu_thread_component> _sigstop_dispatcher;
Signal_dispatcher<Cpu_thread_component> _sigint_dispatcher;
int _pipefd[2];
bool _initial_sigtrap_pending = true;
bool _initial_breakpoint_handled = false;
/* data for breakpoint at first instruction */
enum { MAX_BREAKPOINT_LEN = 8 }; /* value from mem-break.c */
unsigned char _original_instructions[MAX_BREAKPOINT_LEN];
addr_t _breakpoint_ip;
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);
}
public:
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)
PERR("could not create pipe");
}
~Cpu_thread_component()
{
close(_pipefd[0]);
close(_pipefd[1]);
_cpu_session_component.thread_ep().dissolve(this);
}
Signal_context_capability exception_signal_context_cap()
{
return _exception_dispatcher;
}
Signal_context_capability sigstop_signal_context_cap()
{
return _sigstop_dispatcher;
}
Signal_context_capability sigint_signal_context_cap()
{
return _sigint_dispatcher;
}
Thread_capability thread_cap() { return cap(); }
unsigned long lwpid() { return _lwpid; }
Thread_capability parent_thread_cap() { return _parent_cpu_thread; }
int signal_pipe_read_fd() { return _pipefd[0]; }
int handle_initial_breakpoint()
{
if (!_initial_breakpoint_handled) {
_initial_breakpoint_handled = true;
return 1;
}
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:
PERR("unexpected signal %d", signo);
return 0;
}
}
int deliver_signal(int signo)
{
if ((signo == SIGTRAP) && _initial_sigtrap_pending) {
_initial_sigtrap_pending = false;
if (_verbose)
PDBG("received initial SIGTRAP for lwpid %lu", _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)
PDBG("delivering SIGSTOP to thread %lu", _lwpid);
break;
case SIGTRAP:
if (_verbose)
PDBG("delivering SIGTRAP to thread %lu", _lwpid);
break;
case SIGSEGV:
if (_verbose)
PDBG("delivering SIGSEGV to thread %lu", _lwpid);
break;
case SIGINT:
if (_verbose)
PDBG("delivering SIGINT to thread %lu", _lwpid);
break;
case SIGINFO:
if (_verbose)
PDBG("delivering initial SIGSTOP to thread %lu", _lwpid);
break;
default:
PERR("unexpected signal %d", signo);
}
write(_pipefd[1], &signo, sizeof(signo));
return 0;
}
/**************************
** CPU thread interface **
*************************/
Dataspace_capability utcb() override;
void start(addr_t, addr_t) override;
void pause() override;
void resume() override;
void single_step(bool) override;
void cancel_blocking() override;
Thread_state state() override;
void state(Thread_state const &) override;
void exception_sigh(Signal_context_capability) override;
void affinity(Affinity::Location) override;
unsigned trace_control_index() override;
Dataspace_capability trace_buffer() override;
Dataspace_capability trace_policy() override;
};
#endif /* _CPU_THREAD_COMPONENT_H_ */

View File

@ -41,6 +41,7 @@ namespace Gdb_monitor {
Region_map_component *region_map_component() { return _region_map_component; }
};
}
#endif /* _DATASPACE_OBJECT_H_ */

View File

@ -1,40 +0,0 @@
/*
* \brief GDB stub thread implementation
* \author Christian Prochaska
* \date 2011-03-10
*/
/*
* Copyright (C) 2011-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.
*/
#include <base/sleep.h>
#include "gdb_stub_thread.h"
using namespace Genode;
using namespace Gdb_monitor;
Gdb_stub_thread::Gdb_stub_thread()
:
Thread_deprecated<GDB_STUB_STACK_SIZE>("GDB server thread"),
_cpu_session_component(0),
_region_map_component(0),
_signal_handler_thread(&_exception_signal_receiver)
{
_signal_handler_thread.start();
}
extern "C" int gdbserver_main(const char *port, void *gdb_stub_thread);
void Gdb_stub_thread::entry()
{
gdbserver_main("/dev/terminal", this);
sleep_forever();
};

View File

@ -1,61 +0,0 @@
/*
* \brief GDB stub thread
* \author Christian Prochaska
* \date 2011-03-10
*/
/*
* Copyright (C) 2011-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 _GDB_STUB_THREAD_H_
#define _GDB_STUB_THREAD_H_
#include <base/thread.h>
#include "cpu_session_component.h"
#include "dataspace_object.h"
#include "region_map_component.h"
#include "signal_handler_thread.h"
namespace Gdb_monitor {
using namespace Genode;
enum { GDB_STUB_STACK_SIZE = 4*4096 };
class Gdb_stub_thread : public Thread_deprecated<GDB_STUB_STACK_SIZE>
{
private:
Cpu_session_component *_cpu_session_component;
Region_map_component *_region_map_component;
Signal_receiver _exception_signal_receiver;
Gdb_monitor::Signal_handler_thread _signal_handler_thread;
public:
Gdb_stub_thread();
void entry();
void set_cpu_session_component(Cpu_session_component *cpu_session_component)
{
_cpu_session_component = cpu_session_component;
}
void set_region_map_component(Region_map_component *region_map_component)
{
_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; }
Signal_receiver *exception_signal_receiver() { return &_exception_signal_receiver; }
int signal_fd() { return _signal_handler_thread.pipe_read_fd(); }
};
}
#endif /* _GDB_STUB_THREAD_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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.
@ -28,4 +28,4 @@
#define __GENODE__
/* first process id */
#define GENODE_LWP_BASE 1
#define GENODE_MAIN_LWPID 1

View File

@ -6,137 +6,423 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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>
#include <sys/ptrace.h>
#include <unistd.h>
extern "C" {
#define private _private
#include "genode-low.h"
#include "server.h"
#include "linux-low.h"
#define _private private
int linux_detach_one_lwp (struct inferior_list_entry *entry, void *args);
}
#include <base/env.h>
#include <base/printf.h>
#include <dataspace/client.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 "gdb_stub_thread.h"
#include "cpu_thread_component.h"
#include "genode_child_resources.h"
#include "rom.h"
#include "signal_handler_thread.h"
static bool verbose = false;
static int _new_thread_pipe[2];
/*
* When 'waitpid()' reports a SIGTRAP, this variable stores the lwpid of the
* corresponding thread. This information is used in the initial breakpoint
* handler to let the correct thread handle the event.
*/
static unsigned long sigtrap_lwpid;
using namespace Genode;
using namespace Gdb_monitor;
static Genode_child_resources *_genode_child_resources = 0;
static Lock &main_thread_ready_lock()
Genode_child_resources *genode_child_resources()
{
static Lock _main_thread_ready_lock(Lock::LOCKED);
return _main_thread_ready_lock;
return _genode_child_resources;
}
static Lock &gdbserver_ready_lock()
static void genode_stop_thread(unsigned long lwpid)
{
static Lock _gdbserver_ready_lock(Lock::LOCKED);
return _gdbserver_ready_lock;
}
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
Gdb_stub_thread *gdb_stub_thread()
{
return (Gdb_stub_thread*)(current_process()->_private->gdb_stub_thread);
}
extern "C" int genode_signal_fd()
{
return gdb_stub_thread()->signal_fd();
}
void genode_add_thread(unsigned long lwpid)
{
if (lwpid == GENODE_LWP_BASE) {
main_thread_ready_lock().unlock();
} else {
if (lwpid == GENODE_LWP_BASE + 1) {
/* make sure gdbserver is ready to attach new threads */
gdbserver_ready_lock().lock();
}
linux_attach_lwp(lwpid);
if (!cpu_thread) {
PERR("%s: could not find CPU thread object for lwpid %lu",
__PRETTY_FUNCTION__, lwpid);
return;
}
cpu_thread->pause();
}
extern "C" pid_t waitpid(pid_t pid, int *status, int flags)
{
extern int remote_desc;
fd_set readset;
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
while(1) {
FD_ZERO (&readset);
if (remote_desc != -1)
FD_SET (remote_desc, &readset);
if (pid == -1) {
FD_SET(_new_thread_pipe[0], &readset);
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);
}
} else {
FD_SET(csc->signal_pipe_read_fd(csc->thread_cap(pid)), &readset);
}
struct timeval wnohang_timeout = {0, 0};
struct timeval *timeout = (flags & WNOHANG) ? &wnohang_timeout : NULL;
/* TODO: determine the highest fd in the set for optimization */
int res = select(FD_SETSIZE, &readset, 0, 0, timeout);
if (res > 0) {
if ((remote_desc != -1) && FD_ISSET(remote_desc, &readset)) {
/* received input from GDB */
int cc;
char c = 0;
cc = read (remote_desc, &c, 1);
if (cc == 1 && c == '\003' && current_inferior != NULL) {
/* this causes a SIGINT to be delivered to one of the threads */
(*the_target->request_interrupt)();
continue;
} else {
if (verbose)
PDBG("input_interrupt, count = %d c = %d ('%c')", cc, c, c);
}
} else if (FD_ISSET(_new_thread_pipe[0], &readset)) {
unsigned long lwpid = GENODE_MAIN_LWPID;
genode_stop_thread(lwpid);
*status = W_STOPCODE(SIGTRAP) | (PTRACE_EVENT_CLONE << 16);
return lwpid;
} else {
/* received a signal */
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
if (FD_ISSET(csc->signal_pipe_read_fd(thread_cap), &readset))
break;
thread_cap = csc->next(thread_cap);
}
if (!thread_cap.valid())
continue;
int signal;
read(csc->signal_pipe_read_fd(thread_cap), &signal, sizeof(signal));
unsigned long lwpid = csc->lwpid(thread_cap);
if (verbose)
PDBG("thread %lu received signal %d", lwpid, signal);
if (signal == SIGTRAP) {
sigtrap_lwpid = lwpid;
} else if (signal == SIGSTOP) {
/*
* Check if a SIGTRAP is pending
*
* This can happen if a single-stepped thread gets paused while gdbserver
* handles a signal of a different thread and the exception signal after
* the single step has not arrived yet. In this case, the SIGTRAP must be
* delivered first, otherwise gdbserver would single-step the thread again.
*/
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);
continue;
}
} else if (signal == SIGINFO) {
if (verbose)
PDBG("received SIGINFO for new lwpid %lu", lwpid);
if (lwpid != GENODE_MAIN_LWPID)
write(_new_thread_pipe[1], &lwpid, sizeof(lwpid));
/*
* First signal of a new thread. On Genode originally a
* SIGTRAP, but gdbserver expects SIGSTOP.
*/
signal = SIGSTOP;
}
*status = W_STOPCODE(signal);
return lwpid;
}
} else {
return res;
}
}
}
extern "C" long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data)
{
const char *request_str = 0;
switch (request) {
case PTRACE_TRACEME: request_str = "PTRACE_TRACEME"; break;
case PTRACE_PEEKTEXT: request_str = "PTRACE_PEEKTEXT"; break;
case PTRACE_PEEKUSER: request_str = "PTRACE_PEEKUSER"; break;
case PTRACE_POKETEXT: request_str = "PTRACE_POKETEXT"; break;
case PTRACE_POKEUSER: request_str = "PTRACE_POKEUSER"; break;
case PTRACE_CONT: request_str = "PTRACE_CONT"; break;
case PTRACE_KILL: request_str = "PTRACE_KILL"; break;
case PTRACE_SINGLESTEP: request_str = "PTRACE_SINGLESTEP"; break;
case PTRACE_GETREGS: request_str = "PTRACE_GETREGS"; break;
case PTRACE_SETREGS: request_str = "PTRACE_SETREGS"; break;
case PTRACE_ATTACH: request_str = "PTRACE_ATTACH"; break;
case PTRACE_DETACH: request_str = "PTRACE_DETACH"; break;
case PTRACE_GETEVENTMSG:
/*
* Only PTRACE_EVENT_CLONE is currently supported.
*
* Read the lwpid of the new thread from the pipe.
*/
read(_new_thread_pipe[0], data, sizeof(unsigned long));
return 0;
case PTRACE_GETREGSET: request_str = "PTRACE_GETREGSET"; break;
}
PWRN("ptrace(%s (0x%x)) called - not implemented!", request_str, request);
errno = EINVAL;
return -1;
}
extern "C" int fork()
{
/* create the thread announcement pipe */
if (pipe(_new_thread_pipe) != 0) {
PERR("could not create the 'new thread' pipe");
return -1;
}
/* look for dynamic linker */
Dataspace_capability ldso_cap;
try {
Rom_connection ldso_rom("ld.lib.so");
ldso_cap = clone_rom(ldso_rom.dataspace());
} catch (...) {
PDBG("ld.lib.so not found");
}
/* extract target filename from config file */
static char filename[32] = "";
try {
config()->xml_node().sub_node("target").attribute("name").value(filename, sizeof(filename));
} catch (Xml_node::Nonexistent_sub_node) {
PERR("Error: Missing '<target>' sub node.");
return -1;
} catch (Xml_node::Nonexistent_attribute) {
PERR("Error: Missing 'name' attribute of '<target>' sub node.");
return -1;
}
/* extract target node from config file */
Xml_node target_node = config()->xml_node().sub_node("target");
/*
* preserve the configured amount of memory for gdb_monitor and give the
* remainder to the child
*/
Number_of_bytes preserved_ram_quota = 0;
try {
Xml_node preserve_node = config()->xml_node().sub_node("preserve");
if (preserve_node.attribute("name").has_value("RAM"))
preserve_node.attribute("quantum").value(&preserved_ram_quota);
else
throw Xml_node::Exception();
} catch (...) {
PERR("Error: could not find a valid <preserve> config node");
return -1;
}
Number_of_bytes ram_quota = env()->ram_session()->avail() - preserved_ram_quota;
/* start the application */
char *unique_name = filename;
Capability<Rom_dataspace> file_cap;
try {
static Rom_connection rom(filename, unique_name);
file_cap = rom.dataspace();
} catch (Rom_connection::Rom_connection_failed) {
Genode::printf("Error: Could not access file \"%s\" from ROM service.\n", filename);
return -1;
}
/* copy ELF image to writable dataspace */
Genode::size_t elf_size = Dataspace_client(file_cap).size();
Dataspace_capability elf_cap = clone_rom(file_cap);
/* create ram session for child with some of our own quota */
static Ram_connection ram;
ram.ref_account(env()->ram_session_cap());
env()->ram_session()->transfer_quota(ram.cap(), (Genode::size_t)ram_quota - elf_size);
/* cap session for allocating capabilities for parent interfaces */
static Cap_connection cap_session;
static Service_registry parent_services;
enum { CHILD_ROOT_EP_STACK = 1024*sizeof(addr_t) };
static Rpc_entrypoint child_root_ep(&cap_session, CHILD_ROOT_EP_STACK,
"child_root_ep");
static Signal_receiver signal_receiver;
static Gdb_monitor::Signal_handler_thread
signal_handler_thread(&signal_receiver);
signal_handler_thread.start();
App_child *child = new (env()->heap()) App_child(unique_name,
elf_cap,
ldso_cap,
ram.cap(),
&cap_session,
&parent_services,
&child_root_ep,
&signal_receiver,
target_node);
_genode_child_resources = child->genode_child_resources();
child->start();
return GENODE_MAIN_LWPID;
}
extern "C" int kill(pid_t pid, int sig)
{
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Thread_capability thread_cap = csc->thread_cap(pid);
if (!thread_cap.valid()) {
PERR("%s: could not find thread capability for lwpid %d",
__PRETTY_FUNCTION__, pid);
return -1;
}
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);
}
void genode_set_initial_breakpoint_at(CORE_ADDR addr)
{
set_breakpoint_at(addr, initial_breakpoint_handler);
}
void genode_remove_thread(unsigned long lwpid)
{
int pid = GENODE_LWP_BASE;
int pid = GENODE_MAIN_LWPID;
linux_detach_one_lwp((struct inferior_list_entry *)
find_thread_ptid(ptid_build(GENODE_LWP_BASE, lwpid, 0)), &pid);
}
void genode_wait_for_target_main_thread()
{
/* gdbserver is now ready to attach new threads */
gdbserver_ready_lock().unlock();
/* wait until the target's main thread has been created */
main_thread_ready_lock().lock();
}
extern "C" void genode_detect_all_threads()
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Thread_capability thread_cap = csc->next(csc->first()); /* second thread */
while (thread_cap.valid()) {
linux_attach_lwp(csc->lwpid(thread_cap));
thread_cap = csc->next(thread_cap);
}
find_thread_ptid(ptid_build(GENODE_MAIN_LWPID, lwpid, 0)), &pid);
}
extern "C" void genode_stop_all_threads()
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
Cpu_thread_client(thread_cap).pause();
thread_cap = csc->next(thread_cap);
}
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->pause_all_threads();
}
extern "C" void genode_resume_all_threads()
void genode_resume_all_threads()
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
Cpu_thread_client(thread_cap).resume();
thread_cap = csc->next(thread_cap);
}
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->resume_all_threads();
}
int genode_detach(int pid)
{
find_inferior (&all_threads, linux_detach_one_lwp, &pid);
genode_resume_all_threads();
return 0;
@ -146,86 +432,67 @@ int genode_detach(int pid)
int genode_kill(int pid)
{
/* TODO */
if (verbose) PDBG("genode_kill() called - not implemented\n");
if (verbose) PDBG("not implemented, just detaching instead...");
return genode_detach(pid);
}
void genode_interrupt_thread(unsigned long lwpid)
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Thread_capability thread_cap = csc->thread_cap(lwpid);
if (!thread_cap.valid()) {
PERR("could not find thread capability for lwpid %lu", lwpid);
return;
}
Cpu_thread_client(thread_cap).pause();
}
void genode_continue_thread(unsigned long lwpid, int single_step)
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
Thread_capability thread_cap = csc->thread_cap(lwpid);
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
if (!thread_cap.valid()) {
PERR("could not find thread capability for lwpid %lu", lwpid);
if (!cpu_thread) {
PERR("%s: could not find CPU thread object for lwpid %lu",
__PRETTY_FUNCTION__, lwpid);
return;
}
Cpu_thread_client cpu_thread(thread_cap);
cpu_thread.single_step(single_step);
cpu_thread.resume();
cpu_thread->single_step(single_step);
cpu_thread->resume();
}
/*
* This function returns the first thread with a page fault that it finds.
* Multiple page-faulted threads are currently not supported.
*/
unsigned long genode_find_segfault_lwpid()
void genode_fetch_registers(struct regcache *regcache, int regno)
{
unsigned long reg_content = 0;
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
/*
* It can happen that the thread state of the thread which caused the
* page fault is not accessible yet. In that case, we'll retry until
* it is accessible.
*/
while (1) {
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
try {
Thread_state thread_state = Cpu_thread_client(thread_cap).state();
if (thread_state.unresolved_page_fault) {
/*
* On base-foc it is necessary to pause the thread before
* IP and SP are available in the thread state.
*/
Cpu_thread_client(thread_cap).pause();
return csc->lwpid(thread_cap);
}
} catch (Cpu_thread::State_access_failed) { }
thread_cap = csc->next(thread_cap);
if (regno == -1) {
for (regno = 0; regno < the_low_target.num_regs; regno++) {
if (genode_fetch_register(regno, &reg_content) == 0)
supply_register(regcache, regno, &reg_content);
else
supply_register(regcache, regno, 0);
}
} else {
if (genode_fetch_register(regno, &reg_content) == 0)
supply_register(regcache, regno, &reg_content);
else
supply_register(regcache, regno, 0);
}
}
void genode_store_registers(struct regcache *regcache, int regno)
{
if (verbose) PDBG("genode_store_registers(): regno = %d", regno);
unsigned long reg_content = 0;
if (regno == -1) {
for (regno = 0; regno < the_low_target.num_regs; regno++) {
if ((size_t)register_size(regno) <= sizeof(reg_content)) {
collect_register(regcache, regno, &reg_content);
genode_store_register(regno, reg_content);
}
}
} else {
if ((size_t)register_size(regno) <= sizeof(reg_content)) {
collect_register(regcache, regno, &reg_content);
genode_store_register(regno, reg_content);
}
}
}
@ -335,7 +602,7 @@ class Memory_model
if (!local_base) {
PWRN("Memory model: no memory at address %p", addr);
return 0;
throw No_memory_at_address();
}
unsigned char value =
@ -350,7 +617,7 @@ class Memory_model
void write(void *addr, unsigned char value)
{
if (verbose)
Genode::printf("write addr=%p, value=%x\n", addr, value);
Genode::printf("write addr=%p, value=%x\n", addr, value);
Lock::Guard guard(_lock);
@ -363,7 +630,7 @@ class Memory_model
if (!local_base) {
PWRN("Memory model: no memory at address %p", addr);
PWRN("(attempted to write %x)", (int)value);
return;
throw No_memory_at_address();
}
local_base[offset_in_region] = value;
@ -376,7 +643,7 @@ class Memory_model
*/
static Memory_model *memory_model()
{
static Memory_model inst(gdb_stub_thread()->region_map_component());
static Memory_model inst(genode_child_resources()->region_map_component());
return &inst;
}
@ -387,7 +654,55 @@ unsigned char genode_read_memory_byte(void *addr)
}
int genode_read_memory(CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
if (verbose)
PDBG("genode_read_memory(%llx, %p, %d)", memaddr, myaddr, len);
if (myaddr)
try {
for (int i = 0; i < len; i++)
myaddr[i] = genode_read_memory_byte((void*)((unsigned long)memaddr + i));
} catch (No_memory_at_address) {
return EFAULT;
}
return 0;
}
void genode_write_memory_byte(void *addr, unsigned char value)
{
return memory_model()->write(addr, value);
memory_model()->write(addr, value);
}
int genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
{
if (verbose)
PDBG("genode_write_memory(%llx, %p, %d)", memaddr, myaddr, len);
if (myaddr && (len > 0)) {
if (debug_threads) {
/* Dump up to four bytes. */
unsigned int val = * (unsigned int *) myaddr;
if (len == 1)
val = val & 0xff;
else if (len == 2)
val = val & 0xffff;
else if (len == 3)
val = val & 0xffffff;
fprintf(stderr, "Writing %0*x to 0x%08lx", 2 * ((len < 4) ? len : 4),
val, (long)memaddr);
}
for (int i = 0; i < len; i++)
try {
genode_write_memory_byte((void*)((unsigned long)memaddr + i), myaddr[i]);
} catch (No_memory_at_address) {
return EFAULT;
}
}
return 0;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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.
@ -18,27 +18,29 @@
#ifndef GENODE_LOW_H
#define GENODE_LOW_H
#include <sys/types.h>
#include "server.h"
int genode_signal_fd();
/* exception type */
struct No_memory_at_address { };
void genode_wait_for_target_main_thread();
void genode_detect_all_threads();
/* interface for linux-low.c */
void genode_stop_all_threads();
void genode_resume_all_threads();
ptid_t genode_wait_for_signal_or_gdb_interrupt(struct target_waitstatus *status);
void genode_continue_thread(unsigned long lwpid, int single_step);
unsigned long genode_find_segfault_lwpid();
int genode_kill(int pid);
int genode_detach(int pid);
void genode_fetch_registers(struct regcache *regcache, int regno);
void genode_store_registers(struct regcache *regcache, int regno);
int genode_read_memory(CORE_ADDR memaddr, unsigned char *myaddr, int len);
int genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len);
/* interface for genode-low.cc and low.cc */
int genode_fetch_register(int regno, unsigned long *reg_content);
void genode_store_register(int regno, unsigned long reg_content);
unsigned char genode_read_memory_byte(void *addr);
void genode_write_memory_byte(void *addr, unsigned char value);
int genode_detach(int pid);
int genode_kill(int pid);
#endif /* GENODE_LOW_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
/*
* \brief Genode child resources provided to GDB monitor
* \author Christian Prochaska
* \date 2011-03-10
*/
/*
* Copyright (C) 2011-2016 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 _GENODE_CHILD_RESOURCES_H_
#define _GENODE_CHILD_RESOURCES_H_
#include "cpu_session_component.h"
#include "region_map_component.h"
namespace Gdb_monitor { class Genode_child_resources; }
class Gdb_monitor::Genode_child_resources
{
private:
Cpu_session_component *_cpu_session_component = 0;
Region_map_component *_region_map_component = 0;
public:
void cpu_session_component(Cpu_session_component *cpu_session_component)
{
_cpu_session_component = cpu_session_component;
}
void region_map_component(Region_map_component *region_map_component)
{
_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; }
};
#endif /* _GENODE_CHILD_RESOURCES_H_ */

View File

@ -5,29 +5,12 @@
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2016 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 <base/printf.h>
#include <base/service.h>
#include <base/sleep.h>
#include <os/config.h>
#include <util/xml_node.h>
#include <rom_session/connection.h>
#include <ram_session/connection.h>
#include <cap_session/connection.h>
#include "app_child.h"
#include "rom.h"
using namespace Genode;
using namespace Gdb_monitor;
/*
* Suppress messages of libc dummy functions
@ -36,92 +19,21 @@ extern "C" int _sigaction() { return -1; }
extern "C" int getpid() { return -1; }
extern "C" int sigprocmask() { return -1; }
extern "C" int _sigprocmask() { return -1; }
extern "C" int sigsuspend() { return -1; }
/*
* version.c
*/
extern "C" const char version[] = "7.3.1";
extern "C" const char host_name[] = "";
extern "C" int gdbserver_main(int argc, const char *argv[]);
int main()
{
/* look for dynamic linker */
Dataspace_capability ldso_ds;
try {
Rom_connection ldso_rom("ld.lib.so");
ldso_ds = clone_rom(ldso_rom.dataspace());
} catch (...) {
PDBG("ld.lib.so not found");
}
int argc = 3;
const char *argv[] = { "gdbserver", "/dev/terminal", "target", 0 };
/* extract target filename from config file */
static char filename[32] = "";
try {
config()->xml_node().sub_node("target").attribute("name").value(filename, sizeof(filename));
} catch (Xml_node::Nonexistent_sub_node) {
PERR("Error: Missing '<target>' sub node.");
return -1;
} catch (Xml_node::Nonexistent_attribute) {
PERR("Error: Missing 'name' attribute of '<target>' sub node.");
return -1;
}
/* extract target node from config file */
Xml_node target_node = config()->xml_node().sub_node("target");
/*
* preserve the configured amount of memory for gdb_monitor and give the
* remainder to the child
*/
Number_of_bytes preserved_ram_quota = 0;
try {
Xml_node preserve_node = config()->xml_node().sub_node("preserve");
if (preserve_node.attribute("name").has_value("RAM"))
preserve_node.attribute("quantum").value(&preserved_ram_quota);
else
throw Xml_node::Exception();
} catch (...) {
PERR("Error: could not find a valid <preserve> config node");
return -1;
}
Number_of_bytes ram_quota = env()->ram_session()->avail() - preserved_ram_quota;
/* start the application */
char *unique_name = filename;
Capability<Rom_dataspace> file_cap;
try {
static Rom_connection rom(filename, unique_name);
file_cap = rom.dataspace();
} catch (Rom_connection::Rom_connection_failed) {
Genode::printf("Error: Could not access file \"%s\" from ROM service.\n", filename);
return 0;
}
/* copy ELF image to writable dataspace */
Genode::size_t elf_size = Dataspace_client(file_cap).size();
Capability<Dataspace> elf_cap = clone_rom(file_cap);
/* create ram session for child with some of our own quota */
static Ram_connection ram;
ram.ref_account(env()->ram_session_cap());
env()->ram_session()->transfer_quota(ram.cap(), (Genode::size_t)ram_quota - elf_size);
/* cap session for allocating capabilities for parent interfaces */
static Cap_connection cap_session;
static Service_registry parent_services;
enum { CHILD_ROOT_EP_STACK = 4096 };
static Rpc_entrypoint child_root_ep(&cap_session, CHILD_ROOT_EP_STACK,
"child_root_ep");
new (env()->heap()) App_child(unique_name,
elf_cap,
ldso_ds,
ram.cap(),
&cap_session,
&parent_services,
&child_root_ep,
target_node);
sleep_forever();
return 0;
return gdbserver_main(argc, argv);
}

View File

@ -18,9 +18,15 @@
#include <base/rpc_server.h>
#include <pd_session/connection.h>
using namespace Genode;
/* GDB monitor includes */
#include "region_map_component.h"
class Pd_session_component : public Rpc_object<Pd_session>
namespace Gdb_monitor {
class Pd_session_component;
using namespace Genode;
}
class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
{
private:
@ -41,9 +47,9 @@ class Pd_session_component : public Rpc_object<Pd_session>
Dataspace_pool &managed_ds_map)
:
_ep(ep), _pd(binary_name),
_address_space(_ep, managed_ds_map, _pd.address_space()),
_stack_area (_ep, managed_ds_map, _pd.stack_area()),
_linker_area (_ep, managed_ds_map, _pd.linker_area())
_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.manage(this);
}
@ -54,11 +60,12 @@ class Pd_session_component : public Rpc_object<Pd_session>
}
/**
* Accessor used to let the GDB stub thread access the PD's address
* Accessor used to let the GDB monitor access the PD's address
* space
*/
Region_map_component &region_map() { return _address_space; }
Pd_session_capability core_pd_cap() { return _pd.cap(); }
/**************************
** Pd_session interface **

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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.
@ -18,31 +18,30 @@
#include "ram_session_component.h"
namespace Genode {
namespace Gdb_monitor { class Ram_root; }
class Ram_root : public Root_component<Ram_session_component>
{
protected:
class Gdb_monitor::Ram_root : public Root_component<Ram_session_component>
{
protected:
Ram_session_component *_create_session(const char *args)
{
return new (md_alloc())
Ram_session_component(args);
}
Ram_session_component *_create_session(const char *args)
{
return new (md_alloc())
Ram_session_component(args);
}
public:
public:
/**
* Constructor
*
* \param session_ep entry point for managing ram session objects
* \param md_alloc meta-data allocator to be used by root component
*/
Ram_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc)
: Root_component<Ram_session_component>(session_ep, md_alloc)
{ }
};
}
/**
* Constructor
*
* \param session_ep entry point for managing ram session objects
* \param md_alloc meta-data allocator to be used by root component
*/
Ram_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc)
: Root_component<Ram_session_component>(session_ep, md_alloc)
{ }
};
#endif /* _RAM_ROOT_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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.
@ -18,7 +18,7 @@
#include "ram_session_component.h"
using namespace Genode;
using namespace Gdb_monitor;
Ram_session_component::Ram_session_component(const char *args)
: _parent_ram_session(env()->parent()->session<Ram_session>(args))

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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.
@ -18,9 +18,13 @@
#include <base/rpc_server.h>
#include <ram_session/client.h>
using namespace Genode;
namespace Gdb_monitor
{
class Ram_session_component;
using namespace Genode;
}
class Ram_session_component : public Rpc_object<Ram_session>
class Gdb_monitor::Ram_session_component : public Rpc_object<Ram_session>
{
private:

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,19 +15,19 @@
#include <base/env.h>
#include <base/printf.h>
#include <dataspace/client.h>
#include <util/retry.h>
/* local includes */
#include "region_map_component.h"
static bool const verbose = false;
using namespace Gdb_monitor;
using namespace Genode;
/**************************
/**************************************
** Region map component **
**************************/
**************************************/
using namespace Gdb_monitor;
Region_map_component::Region *Region_map_component::find_region(void *local_addr, addr_t *offset_in_region)
{
@ -140,13 +140,16 @@ Dataspace_capability Region_map_component::dataspace()
Region_map_component::Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map)
:
_ep(ep),
_pd(pd),
_parent_region_map(parent_region_map),
_managed_ds_map(managed_ds_map)
{
_ep.manage(this);
if (verbose)
PDBG("Region_map_component()");
}

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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,8 +16,9 @@
#define _REGION_MAP_COMPONENT_H_
/* Genode includes */
#include <region_map/client.h>
#include <base/rpc_server.h>
#include <pd_session/capability.h>
#include <region_map/client.h>
/* GDB monitor includes */
#include "dataspace_object.h"
@ -32,6 +33,8 @@ namespace Gdb_monitor {
Rpc_entrypoint &_ep;
Pd_session_capability _pd;
Genode::Region_map_client _parent_region_map;
public:
@ -75,8 +78,9 @@ namespace Gdb_monitor {
/**
* Constructor
*/
Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map,
Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map);
~Region_map_component();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,111 +16,118 @@
/* Genode includes */
#include <base/service.h>
#include <dataspace/client.h>
#include <root/component.h>
#include <rom_session/client.h>
#include <rom_session/connection.h>
#include <util/arg_string.h>
namespace Gdb_monitor {
namespace Gdb_monitor
{
class Rom_session_component;
class Rom_root;
class Rom_service;
using namespace Genode;
/**
* Clone a ROM dataspace in RAM
*/
Capability<Ram_dataspace> clone_rom(Capability<Rom_dataspace> rom_cap)
{
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()) {
PERR("%s: memory allocation for cloned dataspace failed", __func__);
return Capability<Ram_dataspace>();
}
void *rom = env()->rm_session()->attach(rom_cap);
void *clone = env()->rm_session()->attach(clone_cap);
memcpy(clone, rom, rom_size);
env()->rm_session()->detach(rom);
env()->rm_session()->detach(clone);
return clone_cap;
}
/**
* ROM session backed by RAM dataspace copy of original ROM
*/
class Rom_session_component : public Rpc_object<Rom_session>
{
private:
Capability<Ram_dataspace> _clone_cap;
public:
Rom_session_component(char const *filename)
: _clone_cap(clone_rom(Rom_connection(filename).dataspace()))
{ }
~Rom_session_component() { env()->ram_session()->free(_clone_cap); }
Capability<Rom_dataspace> dataspace()
{
return static_cap_cast<Rom_dataspace>(
static_cap_cast<Dataspace>(_clone_cap));
}
void release() { }
void sigh(Genode::Signal_context_capability) { }
};
class Rom_root : public Root_component<Rom_session_component>
{
protected:
Rom_session_component *_create_session(char const *args)
{
enum { FILENAME_MAX_LEN = 128 };
char filename[FILENAME_MAX_LEN];
Arg_string::find_arg(args, "filename").string(filename, sizeof(filename), "");
return new (md_alloc()) Rom_session_component(filename);
}
public:
Rom_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc)
: Root_component<Rom_session_component>(session_ep, md_alloc)
{ }
};
class Rom_service : public Service
{
private:
Rom_root _root;
public:
Rom_service(Rpc_entrypoint *entrypoint,
Allocator *md_alloc)
: Service("ROM"), _root(entrypoint, md_alloc)
{ }
Capability<Session> session(char const *args, Affinity const &affinity) {
return _root.session(args, affinity); }
void upgrade(Capability<Session>, char const *) { }
void close(Capability<Session> cap) { _root.close(cap); }
};
}
/**
* 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()) {
PERR("%s: memory allocation for cloned dataspace failed", __func__);
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;
}
/**
* ROM session backed by RAM dataspace copy of original ROM
*/
class Gdb_monitor::Rom_session_component : public Rpc_object<Rom_session>
{
private:
Capability<Ram_dataspace> _clone_cap;
public:
Rom_session_component(char const *filename)
: _clone_cap(clone_rom(Rom_connection(filename).dataspace()))
{ }
~Rom_session_component() { env()->ram_session()->free(_clone_cap); }
Capability<Rom_dataspace> dataspace()
{
return static_cap_cast<Rom_dataspace>(
static_cap_cast<Dataspace>(_clone_cap));
}
void release() { }
void sigh(Genode::Signal_context_capability) { }
};
class Gdb_monitor::Rom_root : public Root_component<Rom_session_component>
{
protected:
Rom_session_component *_create_session(char const *args)
{
enum { FILENAME_MAX_LEN = 128 };
char filename[FILENAME_MAX_LEN];
Arg_string::find_arg(args, "filename").string(filename, sizeof(filename), "");
return new (md_alloc()) Rom_session_component(filename);
}
public:
Rom_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc)
: Root_component<Rom_session_component>(session_ep, md_alloc)
{ }
};
class Gdb_monitor::Rom_service : public Service
{
private:
Rom_root _root;
public:
Rom_service(Rpc_entrypoint *entrypoint,
Allocator *md_alloc)
: Service("ROM"), _root(entrypoint, md_alloc)
{ }
Capability<Session> session(char const *args, Affinity const &affinity) {
return _root.session(args, affinity); }
void upgrade(Capability<Session>, char const *) { }
void close(Capability<Session> cap) { _root.close(cap); }
};
#endif /* _ROM_H_ */

View File

@ -0,0 +1,279 @@
From 0bcbef9314d6679d1fbbb0114683d06de0196623 Mon Sep 17 00:00:00 2001
From: Christian Prochaska <christian.prochaska@genode-labs.com>
Message-Id: <0bcbef9314d6679d1fbbb0114683d06de0196623.1341578007.git.chris@arachsys.com>
From: Chris Webb <chris@arachsys.com>
Date: Fri, 6 Jul 2012 13:18:58 +0100
Subject: [PATCH] Replace struct siginfo with siginfo_t
Glibc 2.16.0 removes the undocumented definition of 'struct siginfo' from
<bits/siginfo.h>. This struct is also available as the POSIX-defined
siginfo_t, so replace all uses of struct siginfo with siginfo_t.
Signed-off-by: Chris Webb <chris@arachsys.com>
---
gdb/amd64-linux-nat.c | 4 ++--
gdb/arm-linux-nat.c | 2 +-
gdb/gdbserver/linux-low.c | 10 +++++-----
gdb/gdbserver/linux-low.h | 5 ++---
gdb/gdbserver/linux-x86-low.c | 4 ++--
gdb/ia64-linux-nat.c | 2 +-
gdb/linux-nat.c | 16 ++++++++--------
gdb/linux-nat.h | 6 +++---
gdb/ppc-linux-nat.c | 2 +-
gdb/procfs.c | 2 +-
10 files changed, 26 insertions(+), 27 deletions(-)
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index a869f85..7bae36d 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -684,13 +684,13 @@ siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
INF. */
static int
-amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf, int direction)
+amd64_linux_siginfo_fixup (siginfo_t *native, gdb_byte *inf, int direction)
{
/* Is the inferior 32-bit? If so, then do fixup the siginfo
object. */
if (gdbarch_addr_bit (get_frame_arch (get_current_frame ())) == 32)
{
- gdb_assert (sizeof (struct siginfo) == sizeof (compat_siginfo_t));
+ gdb_assert (sizeof (siginfo_t) == sizeof (compat_siginfo_t));
if (direction == 0)
compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, native);
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index 43f4fde..3ec2bfc 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -1203,7 +1203,7 @@ arm_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
static int
arm_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
- struct siginfo *siginfo_p = linux_nat_get_siginfo (inferior_ptid);
+ siginfo_t *siginfo_p = linux_nat_get_siginfo (inferior_ptid);
int slot = siginfo_p->si_errno;
/* This must be a hardware breakpoint. */
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 81b8540..e597e2f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -4693,7 +4693,7 @@ linux_qxfer_osdata (const char *annex,
layout of the inferiors' architecture. */
static void
-siginfo_fixup (struct siginfo *siginfo, void *inf_siginfo, int direction)
+siginfo_fixup (siginfo_t *siginfo, void *inf_siginfo, int direction)
{
int done = 0;
@@ -4705,9 +4705,9 @@ siginfo_fixup (struct siginfo *siginfo, void *inf_siginfo, int direction)
if (!done)
{
if (direction == 1)
- memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+ memcpy (siginfo, inf_siginfo, sizeof (siginfo_t));
else
- memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+ memcpy (inf_siginfo, siginfo, sizeof (siginfo_t));
}
}
@@ -4716,8 +4716,8 @@ linux_xfer_siginfo (const char *annex, unsigned char *readbuf,
unsigned const char *writebuf, CORE_ADDR offset, int len)
{
int pid;
- struct siginfo siginfo;
- char inf_siginfo[sizeof (struct siginfo)];
+ siginfo_t siginfo;
+ char inf_siginfo[sizeof (siginfo_t)];
if (current_inferior == NULL)
return -1;
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 6635bc6..d449e1b 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -21,6 +21,7 @@
#include <thread_db.h>
#endif
+#include <signal.h>
#include "gdb_proc_service.h"
#ifdef HAVE_LINUX_REGSETS
@@ -46,8 +47,6 @@ struct regset_info
extern struct regset_info target_regsets[];
#endif
-struct siginfo;
-
struct process_info_private
{
/* Arch-specific additions. */
@@ -100,7 +99,7 @@ struct linux_target_ops
Returns true if any conversion was done; false otherwise.
If DIRECTION is 1, then copy from INF to NATIVE.
If DIRECTION is 0, copy from NATIVE to INF. */
- int (*siginfo_fixup) (struct siginfo *native, void *inf, int direction);
+ int (*siginfo_fixup) (siginfo_t *native, void *inf, int direction);
/* Hook to call when a new process is created or attached to.
If extra per-process architecture-specific data is needed,
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 69c6b57..82dcf83 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -906,13 +906,13 @@ siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
INF. */
static int
-x86_siginfo_fixup (struct siginfo *native, void *inf, int direction)
+x86_siginfo_fixup (siginfo_t *native, void *inf, int direction)
{
#ifdef __x86_64__
/* Is the inferior 32-bit? If so, then fixup the siginfo object. */
if (register_size (0) == 4)
{
- if (sizeof (struct siginfo) != sizeof (compat_siginfo_t))
+ if (sizeof (siginfo_t) != sizeof (compat_siginfo_t))
fatal ("unexpected difference in siginfo");
if (direction == 0)
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index 0f88e14..02482b2 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -640,7 +640,7 @@ static int
ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
{
CORE_ADDR psr;
- struct siginfo *siginfo_p;
+ siginfo_t *siginfo_p;
struct regcache *regcache = get_current_regcache ();
siginfo_p = linux_nat_get_siginfo (inferior_ptid);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 44a2a21..791d7b2 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -214,7 +214,7 @@ static void (*linux_nat_new_thread) (ptid_t);
/* The method to call, if any, when the siginfo object needs to be
converted between the layout returned by ptrace, and the layout in
the architecture of the inferior. */
-static int (*linux_nat_siginfo_fixup) (struct siginfo *,
+static int (*linux_nat_siginfo_fixup) (siginfo_t *,
gdb_byte *,
int);
@@ -3945,7 +3945,7 @@ linux_nat_mourn_inferior (struct target_ops *ops)
layout of the inferiors' architecture. */
static void
-siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
{
int done = 0;
@@ -3957,9 +3957,9 @@ siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
if (!done)
{
if (direction == 1)
- memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+ memcpy (siginfo, inf_siginfo, sizeof (siginfo_t));
else
- memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+ memcpy (inf_siginfo, siginfo, sizeof (siginfo_t));
}
}
@@ -3969,8 +3969,8 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
int pid;
- struct siginfo siginfo;
- gdb_byte inf_siginfo[sizeof (struct siginfo)];
+ siginfo_t siginfo;
+ gdb_byte inf_siginfo[sizeof (siginfo_t)];
gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
gdb_assert (readbuf || writebuf);
@@ -5784,7 +5784,7 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
inferior. */
void
linux_nat_set_siginfo_fixup (struct target_ops *t,
- int (*siginfo_fixup) (struct siginfo *,
+ int (*siginfo_fixup) (siginfo_t *,
gdb_byte *,
int))
{
@@ -5793,7 +5793,7 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
}
/* Return the saved siginfo associated with PTID. */
-struct siginfo *
+siginfo_t *
linux_nat_get_siginfo (ptid_t ptid)
{
struct lwp_info *lp = find_lwp_pid (ptid);
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 42cb2fc..422db28 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -60,7 +60,7 @@ struct lwp_info
/* Non-zero si_signo if this LWP stopped with a trap. si_addr may
be the address of a hardware watchpoint. */
- struct siginfo siginfo;
+ siginfo_t siginfo;
/* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
watchpoint trap. */
@@ -160,7 +160,7 @@ void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
that ptrace returns, and the layout in the architecture of the
inferior. */
void linux_nat_set_siginfo_fixup (struct target_ops *,
- int (*) (struct siginfo *,
+ int (*) (siginfo_t *,
gdb_byte *,
int));
@@ -169,7 +169,7 @@ void linux_nat_set_siginfo_fixup (struct target_ops *,
void linux_nat_switch_fork (ptid_t new_ptid);
/* Return the saved siginfo associated with PTID. */
-struct siginfo *linux_nat_get_siginfo (ptid_t ptid);
+siginfo_t *linux_nat_get_siginfo (ptid_t ptid);
/* Compute and return the processor core of a given thread. */
int linux_nat_core_of_thread_1 (ptid_t ptid);
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 6f11715..3a3de07 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -2161,7 +2161,7 @@ ppc_linux_thread_exit (struct thread_info *tp, int silent)
static int
ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
- struct siginfo *siginfo_p;
+ siginfo_t *siginfo_p;
siginfo_p = linux_nat_get_siginfo (inferior_ptid);
diff --git a/gdb/procfs.c b/gdb/procfs.c
index 5d7cb23..ea52d97 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -263,7 +263,7 @@ typedef struct sigaction gdb_sigaction_t;
#ifdef HAVE_PR_SIGINFO64_T
typedef pr_siginfo64_t gdb_siginfo_t;
#else
-typedef struct siginfo gdb_siginfo_t;
+typedef siginfo_t gdb_siginfo_t;
#endif
/* On mips-irix, praddset and prdelset are defined in such a way that

View File

@ -5,36 +5,21 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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/sleep.h>
/* libc includes */
#include <unistd.h>
/* GDB monitor includes */
#include "thread_info.h"
#include "signal_handler_thread.h"
using namespace Genode;
using namespace Gdb_monitor;
static bool const verbose = false;
Signal_handler_thread::Signal_handler_thread(Signal_receiver *receiver)
:
Thread_deprecated<2*4096>("sig_handler"),
_signal_receiver(receiver)
{
if (pipe(_pipefd))
PERR("could not create pipe");
}
Thread_deprecated<SIGNAL_HANDLER_THREAD_STACK_SIZE>("sig_handler"),
_signal_receiver(receiver) { }
void Signal_handler_thread::entry()
@ -42,18 +27,9 @@ void Signal_handler_thread::entry()
while(1) {
Signal s = _signal_receiver->wait_for_signal();
if (verbose)
PDBG("received exception signal");
Signal_dispatcher_base *signal_dispatcher =
dynamic_cast<Signal_dispatcher_base*>(s.context());
/* default is segmentation fault */
unsigned long sig = 0;
if (Thread_info *thread_info = dynamic_cast<Thread_info*>(s.context()))
/* thread trapped */
sig = thread_info->lwpid();
write(_pipefd[1], &sig, sizeof(sig));
signal_dispatcher->dispatch(s.num());
}
sleep_forever();
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,18 +21,19 @@ using namespace Genode;
namespace Gdb_monitor {
class Signal_handler_thread : public Thread_deprecated<2*4096>
enum { SIGNAL_HANDLER_THREAD_STACK_SIZE = 2*1024*sizeof(addr_t) };
class Signal_handler_thread
: public Thread_deprecated<SIGNAL_HANDLER_THREAD_STACK_SIZE>
{
private:
int _pipefd[2];
Signal_receiver *_signal_receiver;
public:
Signal_handler_thread(Signal_receiver *receiver);
void entry();
int pipe_read_fd() { return _pipefd[0]; }
};
}

View File

@ -28,13 +28,13 @@ SRC_C = event-loop.c \
SRC_C += linux-low.c
CC_OPT += -DGDBSERVER
CC_OPT += -DGDBSERVER -DPKGVERSION="\"7.3.1\"" -DREPORT_BUGS_TO="\"\""
CC_OPT_linux-low += -Wno-unused-function
SRC_CC = genode-low.cc \
gdb_stub_thread.cc \
cpu_session_component.cc \
cpu_thread_component.cc \
ram_session_component.cc \
region_map_component.cc \
signal_handler_thread.cc \

View File

@ -1,43 +0,0 @@
/*
* \brief Thread info class for GDB monitor
* \author Christian Prochaska
* \date 2011-09-09
*/
/*
* Copyright (C) 2011-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 _THREAD_INFO_H_
#define _THREAD_INFO_H_
#include <base/thread.h>
#include "append_list.h"
namespace Gdb_monitor {
using namespace Genode;
class Thread_info : public Signal_context, public Append_list<Thread_info>::Element
{
private:
Thread_capability _thread_cap;
unsigned long _lwpid;
public:
Thread_info(Thread_capability thread_cap, unsigned long lwpid)
: _thread_cap(thread_cap),
_lwpid(lwpid) { }
Thread_capability thread_cap() { return _thread_cap; }
unsigned long lwpid() { return _lwpid; }
};
}
#endif /* _THREAD_INFO_H_ */

View File

@ -1,43 +0,0 @@
/*
* \brief Dummy implementations of Linux-specific libc functions
* needed to build gdbserver
* \author Christian Prochaska
* \date 2011-09-01
*/
/*
* Copyright (C) 2011-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.
*/
#include <errno.h>
#include <stdio.h>
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, ...)
{
char *request_str = 0;
switch (request) {
case PTRACE_TRACEME: request_str = "PTRACE_TRACEME"; break;
case PTRACE_ATTACH: request_str = "PTRACE_ATTACH"; break;
case PTRACE_KILL: request_str = "PTRACE_KILL"; break;
case PTRACE_DETACH: request_str = "PTRACE_DETACH"; break;
case PTRACE_SINGLESTEP: request_str = "PTRACE_SINGLESTEP"; break;
case PTRACE_CONT: request_str = "PTRACE_CONT"; break;
case PTRACE_PEEKTEXT: request_str = "PTRACE_PEEKTEXT"; break;
case PTRACE_POKETEXT: request_str = "PTRACE_POKETEXT"; break;
case PTRACE_PEEKUSER: request_str = "PTRACE_PEEKUSER"; break;
case PTRACE_POKEUSER: request_str = "PTRACE_POKEUSER"; break;
case PTRACE_GETREGS: request_str = "PTRACE_GETREGS"; break;
case PTRACE_SETREGS: request_str = "PTRACE_SETREGS"; break;
}
printf("ptrace(%s) called - not implemented!\n", request_str);
errno = EINVAL;
return -1;
}

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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.
@ -29,8 +29,4 @@ struct user {
unsigned long int u_debugreg [8];
};
/* Missing in libc's sys/wait.h */
#define __WCLONE 0
#endif /* GDBSERVER_LIBC_DUMMIES_H */

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,18 +20,23 @@
#include <gdbserver_libc_support.h>
enum __ptrace_request {
PTRACE_TRACEME,
PTRACE_ATTACH,
PTRACE_KILL,
PTRACE_DETACH,
PTRACE_SINGLESTEP,
PTRACE_CONT,
PTRACE_PEEKTEXT,
PTRACE_POKETEXT,
PTRACE_PEEKUSER,
PTRACE_POKEUSER,
PTRACE_GETREGS,
PTRACE_SETREGS,
PTRACE_TRACEME = 0,
PTRACE_PEEKTEXT = 1,
PTRACE_PEEKUSER = 3,
PTRACE_POKETEXT = 4,
PTRACE_POKEUSER = 6,
PTRACE_CONT = 7,
PTRACE_KILL = 8,
PTRACE_SINGLESTEP = 9,
PTRACE_GETREGS = 12,
PTRACE_SETREGS = 13,
PTRACE_ATTACH = 16,
PTRACE_DETACH = 17,
PTRACE_EVENT_CLONE = 3,
PTRACE_GETEVENTMSG = 0x4201,
PTRACE_GETREGSET = 0x4204,
};
extern long ptrace(enum __ptrace_request request, ...);

View File

@ -0,0 +1,37 @@
/*
* \brief Linux-specific types for gdbserver
* \author Christian Prochaska
* \date 2016-03-16
*/
/*
* Copyright (C) 2016 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 SYS_WAIT_H
#define SYS_WAIT_H
#define WNOHANG 1
#define __WCLONE 0x80000000
#define WIFEXITED(status) (status == 0)
#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
#define WIFSIGNALED(status) (!WIFEXITED(status) && !WIFSTOPPED(status))
#define WEXITSTATUS(status) ((status >> 8) & 0xff)
#define WSTOPSIG(status) ((status >> 8) & 0xff)
#define WTERMSIG(status) (status & 0x7f)
#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
__BEGIN_DECLS
pid_t waitpid(pid_t pid, int *status, int flags);
__END_DECLS
#endif /* SYS_WAIT_H */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,16 +22,20 @@ extern "C" {
#include <cpu_thread/client.h>
#include "cpu_session_component.h"
#include "gdb_stub_thread.h"
#include "genode_child_resources.h"
using namespace Genode;
using namespace Gdb_monitor;
extern Gdb_stub_thread *gdb_stub_thread();
extern Genode_child_resources *genode_child_resources();
static constexpr bool verbose = false;
Thread_state get_current_thread_state()
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id;
@ -40,9 +44,10 @@ Thread_state get_current_thread_state()
return cpu_thread.state();
}
void set_current_thread_state(Thread_state thread_state)
{
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component();
Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id;
@ -51,3 +56,43 @@ void set_current_thread_state(Thread_state thread_state)
cpu_thread.state(thread_state);
}
void fetch_register(const char *reg_name,
addr_t thread_state_reg,
unsigned long &value)
{
value = thread_state_reg;
if (verbose)
PDBG("%s = %8lx", reg_name, value);
}
void cannot_fetch_register(const char *reg_name)
{
if (verbose)
PDBG("cannot fetch register %s", reg_name);
}
bool store_register(const char *reg_name,
addr_t &thread_state_reg,
unsigned long value)
{
if (verbose)
PDBG("%s = %8lx", reg_name, value);
if (thread_state_reg == value)
return false;
thread_state_reg = value;
return true;
}
void cannot_store_register(const char *reg_name, unsigned long value)
{
if (verbose)
PDBG("cannot set contents of register %s (%8lx)", reg_name, value);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,4 +21,16 @@ Genode::Thread_state get_current_thread_state();
void set_current_thread_state(Genode::Thread_state thread_state);
void fetch_register(const char *reg_name,
Genode::addr_t thread_state_reg,
unsigned long &value);
void cannot_fetch_register(const char *reg_name);
bool store_register(const char *reg_name,
Genode::addr_t &thread_state_reg,
unsigned long value);
void cannot_store_register(const char *reg_name, unsigned long value);
#endif /* GDBSERVER_PLATFORM_HELPER_H */

View File

@ -1,82 +0,0 @@
/*
* \brief Fiasco(x86)-specific helper functions for GDB server
* \author Christian Prochaska
* \date 2011-05-06
*/
/*
* Copyright (C) 2011-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.
*/
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/printf.h>
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
using namespace Genode;
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
{
Thread_state thread_state;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
switch((enum reg_index)regno)
{
/* TODO: implement the backend function that tells gdbserver that these registers cannot be fetched */
case EAX: PDBG("cannot determine contents of register EAX"); return -1;
case ECX: PDBG("cannot determine contents of register ECX"); return -1;
case EDX: PDBG("cannot determine contents of register EDX"); return -1;
case EBX: PDBG("cannot determine contents of register EBX"); return -1;
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case EBP:
/*
* When in a syscall, the user EBP has been pushed onto the stack at address ESP+0
*
* looking for syscall pattern:
* EIP-2: cd 30 int $30
*/
if ((genode_read_memory_byte((void*)(thread_state.ip - 1)) == 0x30) &&
(genode_read_memory_byte((void*)(thread_state.ip - 2)) == 0xcd)) {
*reg_content = genode_read_memory_byte((void*)(thread_state.sp + 0)) +
(genode_read_memory_byte((void*)(thread_state.sp + 1)) << 8) +
(genode_read_memory_byte((void*)(thread_state.sp + 2)) << 16) +
(genode_read_memory_byte((void*)(thread_state.sp + 3)) << 24);
PDBG("ESP = %8lx", *reg_content);
return 0;
} else {
PDBG("cannot determine contents of register EBP"); return -1;
}
case ESI: PDBG("cannot determine contents of register ESI"); return -1;
case EDI: PDBG("cannot determine contents of register EDI"); return -1;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1;
case GS: PDBG("cannot determine contents of register GS"); return -1;
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
{
PDBG("not implemented yet for this platform");
}

View File

@ -0,0 +1,90 @@
/*
* \brief Fiasco.OC-specific 'Native_cpu' setup
* \author Christian Prochaska
* \date 2016-05-13
*/
/*
* Copyright (C) 2016 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 <foc_native_cpu/client.h>
/* GDB monitor includes */
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
namespace Gdb_monitor {
class Native_cpu_component;
}
using namespace Genode;
class Gdb_monitor::Native_cpu_component : public Rpc_object<Foc_native_cpu,
Native_cpu_component>
{
private:
Cpu_session_component &_cpu_session_component;
Foc_native_cpu_client _foc_native_cpu;
public:
Native_cpu_component(Cpu_session_component &cpu_session_component)
: _cpu_session_component(cpu_session_component),
_foc_native_cpu(_cpu_session_component.parent_cpu_session().native_cpu())
{
_cpu_session_component.thread_ep().manage(this);
}
~Native_cpu_component()
{
_cpu_session_component.thread_ep().dissolve(this);
}
void enable_vcpu(Thread_capability thread_cap, addr_t vcpu_state) override
{
Cpu_thread_component *cpu_thread = _cpu_session_component.lookup_cpu_thread(thread_cap);
_foc_native_cpu.enable_vcpu(cpu_thread->parent_thread_cap(), vcpu_state);
}
Native_capability native_cap(Thread_capability thread_cap) override
{
Cpu_thread_component *cpu_thread = _cpu_session_component.lookup_cpu_thread(thread_cap);
return _foc_native_cpu.native_cap(cpu_thread->parent_thread_cap());
}
Native_capability alloc_irq() override
{
return _foc_native_cpu.alloc_irq();
}
};
Capability<Cpu_session::Native_cpu>
Gdb_monitor::Cpu_session_component::_setup_native_cpu()
{
Native_cpu_component *native_cpu_component =
new (_md_alloc) Native_cpu_component(*this);
return native_cpu_component->cap();
}
void Gdb_monitor::Cpu_session_component::_cleanup_native_cpu()
{
Native_cpu_component *native_cpu_component = nullptr;
_thread_ep->apply(_native_cpu_cap, [&] (Native_cpu_component *c) { native_cpu_component = c; });
if (!native_cpu_component) return;
destroy(_md_alloc, native_cpu_component);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,107 +22,124 @@ extern "C" {
#include "reg-arm.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
#undef PDBG
#define PDBG(...)
#include "genode_child_resources.h"
using namespace Genode;
static bool in_syscall(Thread_state const &thread_state)
static bool in_syscall(Thread_state const &ts)
{
/* looking for syscall pattern:
* (PC-8: e1a0e00f mov lr, pc)
* PC-4: e3e0f00b mvn pc, #11
* (PC: e1a02004 mov r2, r4)
*/
if ((genode_read_memory_byte((void*)(thread_state.ip - 1)) == 0xe3) &&
(genode_read_memory_byte((void*)(thread_state.ip - 2)) == 0xe0) &&
(genode_read_memory_byte((void*)(thread_state.ip - 3)) == 0xf0) &&
(genode_read_memory_byte((void*)(thread_state.ip - 4)) == 0x0b))
return true;
try {
/* looking for syscall pattern:
* (PC-8: e1a0e00f mov lr, pc)
* PC-4: e3e0f00b mvn pc, #11
* (PC: e1a02004 mov r2, r4)
*/
if ((genode_read_memory_byte((void*)(ts.ip - 1)) == 0xe3) &&
(genode_read_memory_byte((void*)(ts.ip - 2)) == 0xe0) &&
(genode_read_memory_byte((void*)(ts.ip - 3)) == 0xf0) &&
(genode_read_memory_byte((void*)(ts.ip - 4)) == 0x0b))
return true;
} catch (No_memory_at_address) {
return false;
}
return false;
}
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
extern "C" int genode_fetch_register(int regno, unsigned long *value)
{
Thread_state thread_state;
Thread_state ts;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return -1;
}
if (in_syscall(ts) || ts.unresolved_page_fault) {
if (in_syscall(thread_state) || thread_state.unresolved_page_fault) {
switch((enum reg_index)regno)
{
case R0: PDBG("cannot determine contents of register R0"); return -1;
case R1: PDBG("cannot determine contents of register R1"); return -1;
case R2: PDBG("cannot determine contents of register R2"); return -1;
case R3: PDBG("cannot determine contents of register R3"); return -1;
case R4: PDBG("cannot determine contents of register R4"); return -1;
case R5: PDBG("cannot determine contents of register R5"); return -1;
case R6: PDBG("cannot determine contents of register R6"); return -1;
case R7: PDBG("cannot determine contents of register R7"); return -1;
case R8: PDBG("cannot determine contents of register R8"); return -1;
case R9: PDBG("cannot determine contents of register R9"); return -1;
case R10: PDBG("cannot determine contents of register R10"); return -1;
case R0: cannot_fetch_register("R0"); return -1;
case R1: cannot_fetch_register("R1"); return -1;
case R2: cannot_fetch_register("R2"); return -1;
case R3: cannot_fetch_register("R3"); return -1;
case R4: cannot_fetch_register("R4"); return -1;
case R5: cannot_fetch_register("R5"); return -1;
case R6: cannot_fetch_register("R6"); return -1;
case R7: cannot_fetch_register("R7"); return -1;
case R8: cannot_fetch_register("R8"); return -1;
case R9: cannot_fetch_register("R9"); return -1;
case R10: cannot_fetch_register("R10"); return -1;
case R11:
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
/* R11 can be calculated from SP. The offset can be found in
* the disassembled 'Fiasco::l4_ipc()' function:
* add r11, sp, #8 -> r11 = sp + 8
* sub sp, sp, #20 -> r11 = (sp + 20) + 8
*/
*reg_content = (thread_state.sp + 20) + 8;
PDBG("FP = %8lx", *reg_content);
*value = (ts.sp + 20) + 8;
/* for the debug output, if enabled */
fetch_register("R11", *value, *value);
return 0;
} else {
PDBG("cannot determine contents of register R11"); return -1;
cannot_fetch_register("R11");
return -1;
}
case R12: PDBG("cannot determine contents of register R12"); return -1;
case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0;
case LR: PDBG("cannot determine contents of register LR"); return -1;
case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0;
case F0: PDBG("cannot determine contents of register F0"); return -1;
case F1: PDBG("cannot determine contents of register F1"); return -1;
case F2: PDBG("cannot determine contents of register F2"); return -1;
case F3: PDBG("cannot determine contents of register F3"); return -1;
case F4: PDBG("cannot determine contents of register F4"); return -1;
case F5: PDBG("cannot determine contents of register F5"); return -1;
case F6: PDBG("cannot determine contents of register F6"); return -1;
case F7: PDBG("cannot determine contents of register F7"); return -1;
case FPS: PDBG("cannot determine contents of register FPS"); return -1;
case CPSR: PDBG("cannot determine contents of register CPSR"); return -1;
case R12: cannot_fetch_register("R12"); return -1;
case SP: fetch_register("SP ", ts.sp, *value); return 0;
case LR: cannot_fetch_register("LR"); return -1;
case PC: fetch_register("PC ", ts.ip, *value); return 0;
case F0: cannot_fetch_register("F0"); return -1;
case F1: cannot_fetch_register("F1"); return -1;
case F2: cannot_fetch_register("F2"); return -1;
case F3: cannot_fetch_register("F3"); return -1;
case F4: cannot_fetch_register("F4"); return -1;
case F5: cannot_fetch_register("F5"); return -1;
case F6: cannot_fetch_register("F6"); return -1;
case F7: cannot_fetch_register("F7"); return -1;
case FPS: cannot_fetch_register("FPS"); return -1;
case CPSR: cannot_fetch_register("CPSR"); return -1;
default: PERR("unhandled register %d", regno); return -1;
}
} else {
switch((enum reg_index)regno)
{
case R0: *reg_content = thread_state.r0; PDBG("R0 = %8lx", *reg_content); return 0;
case R1: *reg_content = thread_state.r1; PDBG("R1 = %8lx", *reg_content); return 0;
case R2: *reg_content = thread_state.r2; PDBG("R2 = %8lx", *reg_content); return 0;
case R3: *reg_content = thread_state.r3; PDBG("R3 = %8lx", *reg_content); return 0;
case R4: *reg_content = thread_state.r4; PDBG("R4 = %8lx", *reg_content); return 0;
case R5: *reg_content = thread_state.r5; PDBG("R5 = %8lx", *reg_content); return 0;
case R6: *reg_content = thread_state.r6; PDBG("R6 = %8lx", *reg_content); return 0;
case R7: *reg_content = thread_state.r7; PDBG("R7 = %8lx", *reg_content); return 0;
case R8: *reg_content = thread_state.r8; PDBG("R8 = %8lx", *reg_content); return 0;
case R9: *reg_content = thread_state.r9; PDBG("R9 = %8lx", *reg_content); return 0;
case R10: *reg_content = thread_state.r10; PDBG("R10 = %8lx", *reg_content); return 0;
case R11: *reg_content = thread_state.r11; PDBG("FP = %8lx", *reg_content); return 0;
case R12: *reg_content = thread_state.r12; PDBG("R12 = %8lx", *reg_content); return 0;
case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0;
case LR: *reg_content = thread_state.lr; PDBG("LR = %8lx", *reg_content); return 0;
case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0;
case F0: PDBG("cannot determine contents of register F0"); return -1;
case F1: PDBG("cannot determine contents of register F1"); return -1;
case F2: PDBG("cannot determine contents of register F2"); return -1;
case F3: PDBG("cannot determine contents of register F3"); return -1;
case F4: PDBG("cannot determine contents of register F4"); return -1;
case F5: PDBG("cannot determine contents of register F5"); return -1;
case F6: PDBG("cannot determine contents of register F6"); return -1;
case F7: PDBG("cannot determine contents of register F7"); return -1;
case FPS: PDBG("cannot determine contents of register FPS"); return -1;
case CPSR: *reg_content = thread_state.cpsr; PDBG("CPSR = %8lx", *reg_content); return 0;
case R0: fetch_register("R0 ", ts.r0, *value); return 0;
case R1: fetch_register("R1 ", ts.r1, *value); return 0;
case R2: fetch_register("R2 ", ts.r2, *value); return 0;
case R3: fetch_register("R3 ", ts.r3, *value); return 0;
case R4: fetch_register("R4 ", ts.r4, *value); return 0;
case R5: fetch_register("R5 ", ts.r5, *value); return 0;
case R6: fetch_register("R6 ", ts.r6, *value); return 0;
case R7: fetch_register("R7 ", ts.r7, *value); return 0;
case R8: fetch_register("R8 ", ts.r8, *value); return 0;
case R9: fetch_register("R9 ", ts.r9, *value); return 0;
case R10: fetch_register("R10 ", ts.r10, *value); return 0;
case R11: fetch_register("R11 ", ts.r11, *value); return 0;
case R12: fetch_register("R12 ", ts.r12, *value); return 0;
case SP: fetch_register("SP ", ts.sp, *value); return 0;
case LR: fetch_register("LR ", ts.lr, *value); return 0;
case PC: fetch_register("PC ", ts.ip, *value); return 0;
case F0: cannot_fetch_register("F0"); return -1;
case F1: cannot_fetch_register("F1"); return -1;
case F2: cannot_fetch_register("F2"); return -1;
case F3: cannot_fetch_register("F3"); return -1;
case F4: cannot_fetch_register("F4"); return -1;
case F5: cannot_fetch_register("F5"); return -1;
case F6: cannot_fetch_register("F6"); return -1;
case F7: cannot_fetch_register("F7"); return -1;
case FPS: cannot_fetch_register("FPS"); return -1;
case CPSR: fetch_register("CPSR", ts.cpsr, *value); return 0;
default: PERR("unhandled register %d", regno); return -1;
}
}
@ -130,48 +147,51 @@ extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
extern "C" void genode_store_register(int regno, unsigned long value)
{
Thread_state thread_state;
Thread_state ts;
try { thread_state = get_current_thread_state(); }
catch (...) { return; }
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return;
}
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
PDBG("cannot set registers while thread is in syscall");
return;
}
switch((enum reg_index)regno)
{
case R0: thread_state.r0 = reg_content; PDBG("R0 = %8lx", reg_content); break;
case R1: thread_state.r1 = reg_content; PDBG("R1 = %8lx", reg_content); break;
case R2: thread_state.r2 = reg_content; PDBG("R2 = %8lx", reg_content); break;
case R3: thread_state.r3 = reg_content; PDBG("R3 = %8lx", reg_content); break;
case R4: thread_state.r4 = reg_content; PDBG("R4 = %8lx", reg_content); break;
case R5: thread_state.r5 = reg_content; PDBG("R5 = %8lx", reg_content); break;
case R6: thread_state.r6 = reg_content; PDBG("R6 = %8lx", reg_content); break;
case R7: thread_state.r7 = reg_content; PDBG("R7 = %8lx", reg_content); break;
case R8: thread_state.r8 = reg_content; PDBG("R8 = %8lx", reg_content); break;
case R9: thread_state.r9 = reg_content; PDBG("R9 = %8lx", reg_content); break;
case R10: thread_state.r10 = reg_content; PDBG("R10 = %8lx", reg_content); break;
case R11: thread_state.r11 = reg_content; PDBG("FP = %8lx", reg_content); break;
case R12: thread_state.r12 = reg_content; PDBG("R12 = %8lx", reg_content); break;
case SP: thread_state.sp = reg_content; PDBG("SP = %8lx", reg_content); break;
case LR: thread_state.lr = reg_content; PDBG("LR = %8lx", reg_content); break;
case PC: thread_state.ip = reg_content; PDBG("PC = %8lx", reg_content); break;
case F0: PDBG("cannot set contents of register F0"); break;
case F1: PDBG("cannot set contents of register F1"); break;
case F2: PDBG("cannot set contents of register F2"); break;
case F3: PDBG("cannot set contents of register F3"); break;
case F4: PDBG("cannot set contents of register F4"); break;
case F5: PDBG("cannot set contents of register F5"); break;
case F6: PDBG("cannot set contents of register F6"); break;
case F7: PDBG("cannot set contents of register F7"); break;
case FPS: PDBG("cannot set contents of register FPS"); break;
case CPSR: thread_state.cpsr = reg_content; PDBG("CPSR = %8lx", reg_content); break;
case R0: if (!store_register("R0 ", ts.r0, value)) return; break;
case R1: if (!store_register("R1 ", ts.r1, value)) return; break;
case R2: if (!store_register("R2 ", ts.r2, value)) return; break;
case R3: if (!store_register("R3 ", ts.r3, value)) return; break;
case R4: if (!store_register("R4 ", ts.r4, value)) return; break;
case R5: if (!store_register("R5 ", ts.r5, value)) return; break;
case R6: if (!store_register("R6 ", ts.r6, value)) return; break;
case R7: if (!store_register("R7 ", ts.r7, value)) return; break;
case R8: if (!store_register("R8 ", ts.r8, value)) return; break;
case R9: if (!store_register("R9 ", ts.r9, value)) return; break;
case R10: if (!store_register("R10 ", ts.r10, value)) return; break;
case R11: if (!store_register("R11 ", ts.r11, value)) return; break;
case R12: if (!store_register("R12 ", ts.r12, value)) return; break;
case SP: if (!store_register("SP ", ts.sp, value)) return; break;
case LR: if (!store_register("LR ", ts.lr, value)) return; break;
case PC: if (!store_register("PC ", ts.ip, value)) return; break;
case F0: cannot_store_register("F0 ", value); return;
case F1: cannot_store_register("F1 ", value); return;
case F2: cannot_store_register("F2 ", value); return;
case F3: cannot_store_register("F3 ", value); return;
case F4: cannot_store_register("F4 ", value); return;
case F5: cannot_store_register("F5 ", value); return;
case F6: cannot_store_register("F6 ", value); return;
case F7: cannot_store_register("F7 ", value); return;
case FPS: cannot_store_register("FPS", value); return;
case CPSR: if (!store_register("CPSR", ts.cpsr, value)) return; break;
}
set_current_thread_state(thread_state);
set_current_thread_state(ts);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2016 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,10 +21,7 @@ extern "C" {
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
#undef PDBG
#define PDBG(...)
#include "genode_child_resources.h"
using namespace Genode;
@ -44,113 +41,146 @@ static bool in_syscall(Thread_state const &thread_state)
return false;
}
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
extern "C" int genode_fetch_register(int regno, unsigned long *value)
{
Thread_state thread_state;
Thread_state ts;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return -1;
}
if (in_syscall(ts) || ts.unresolved_page_fault) {
if (in_syscall(thread_state) || thread_state.unresolved_page_fault) {
switch((enum reg_index)regno)
{
case EAX: PDBG("cannot determine contents of register EAX"); return -1;
case ECX: PDBG("cannot determine contents of register ECX"); return -1;
case EDX: PDBG("cannot determine contents of register EDX"); return -1;
case EAX: cannot_fetch_register("EAX"); return -1;
case ECX: cannot_fetch_register("ECX"); return -1;
case EDX: cannot_fetch_register("EDX"); return -1;
case EBX:
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
/* When in a syscall, the user EBX has been pushed onto the stack at address ESP+4 */
*reg_content = genode_read_memory_byte((void*)(thread_state.sp + 4)) +
(genode_read_memory_byte((void*)(thread_state.sp + 5)) << 8) +
(genode_read_memory_byte((void*)(thread_state.sp + 6)) << 16) +
(genode_read_memory_byte((void*)(thread_state.sp + 7)) << 24);
PDBG("EBX = %8lx", *reg_content);
*value = genode_read_memory_byte((void*)(ts.sp + 4))
+ (genode_read_memory_byte((void*)(ts.sp + 5)) << 8)
+ (genode_read_memory_byte((void*)(ts.sp + 6)) << 16)
+ (genode_read_memory_byte((void*)(ts.sp + 7)) << 24);
/* for the debug output, if enabled */
fetch_register("EBX", *value, *value);
return 0;
} else {
PDBG("cannot determine contents of register EBX"); return -1;
cannot_fetch_register("EBX");
return -1;
}
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case UESP: fetch_register("ESP", ts.sp, *value); return 0;
case EBP:
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
/* When in a syscall, the user EBP has been pushed onto the stack at address ESP+0 */
*reg_content = genode_read_memory_byte((void*)(thread_state.sp + 0)) +
(genode_read_memory_byte((void*)(thread_state.sp + 1)) << 8) +
(genode_read_memory_byte((void*)(thread_state.sp + 2)) << 16) +
(genode_read_memory_byte((void*)(thread_state.sp + 3)) << 24);
PDBG("EBP = %8lx", *reg_content);
*value = genode_read_memory_byte((void*)(ts.sp + 0))
+ (genode_read_memory_byte((void*)(ts.sp + 1)) << 8)
+ (genode_read_memory_byte((void*)(ts.sp + 2)) << 16)
+ (genode_read_memory_byte((void*)(ts.sp + 3)) << 24);
/* for the debug output, if enabled */
fetch_register("EBP", *value, *value);
return 0;
} else {
PDBG("cannot determine contents of register EBP"); return -1;
cannot_fetch_register("EBP");
return -1;
}
case ESI: PDBG("cannot determine contents of register ESI"); return -1;
case EDI: PDBG("cannot determine contents of register EDI"); return -1;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1;
case GS: PDBG("cannot determine contents of register GS"); return -1;
case ESI: cannot_fetch_register("ESI"); return -1;
case EDI: cannot_fetch_register("EDI"); return -1;
case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case EFL: cannot_fetch_register("EFL"); return -1;
case CS: cannot_fetch_register("CS"); return -1;
case SS: cannot_fetch_register("SS"); return -1;
case DS: cannot_fetch_register("DS"); return -1;
case ES: cannot_fetch_register("ES"); return -1;
case FS: cannot_fetch_register("FS"); return -1;
case GS: cannot_fetch_register("GS"); return -1;
default: PERR("unhandled register %d", regno); return -1;
}
} else {
switch((enum reg_index)regno)
{
case EAX: *reg_content = thread_state.eax; PDBG("EAX = %8lx", *reg_content); return 0;
case ECX: *reg_content = thread_state.ecx; PDBG("ECX = %8lx", *reg_content); return 0;
case EDX: *reg_content = thread_state.edx; PDBG("EDX = %8lx", *reg_content); return 0;
case EBX: *reg_content = thread_state.ebx; PDBG("EBX = %8lx", *reg_content); return 0;
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case EBP: *reg_content = thread_state.ebp; PDBG("EBP = %8lx", *reg_content); return 0;
case ESI: *reg_content = thread_state.esi; PDBG("ESI = %8lx", *reg_content); return 0;
case EDI: *reg_content = thread_state.edi; PDBG("EDI = %8lx", *reg_content); return 0;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: *reg_content = thread_state.eflags; PDBG("EFLAGS = %8lx", *reg_content); return 0;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: *reg_content = thread_state.fs; PDBG("FS = %8lx", *reg_content); return 0;
case GS: *reg_content = thread_state.gs; PDBG("GS = %8lx", *reg_content); return 0;
case EAX: fetch_register("EAX", ts.eax, *value); return 0;
case ECX: fetch_register("ECX", ts.ecx, *value); return 0;
case EDX: fetch_register("EDX", ts.edx, *value); return 0;
case EBX: fetch_register("EBX", ts.ebx, *value); return 0;
case UESP: fetch_register("ESP", ts.sp, *value); return 0;
case EBP: fetch_register("EBP", ts.ebp, *value); return 0;
case ESI: fetch_register("ESI", ts.esi, *value); return 0;
case EDI: fetch_register("EDI", ts.edi, *value); return 0;
case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case EFL: fetch_register("EFL", ts.eflags, *value); return 0;
case CS: cannot_fetch_register("CS"); return -1;
case SS: cannot_fetch_register("SS"); return -1;
case DS: cannot_fetch_register("DS"); return -1;
case ES: cannot_fetch_register("ES"); return -1;
case FS: fetch_register("FS", ts.fs, *value); return 0;
case GS: fetch_register("GS", ts.gs, *value); return 0;
default: PERR("unhandled register %d", regno); return -1;
}
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
extern "C" void genode_store_register(int regno, unsigned long value)
{
Thread_state thread_state;
Thread_state ts;
try { thread_state = get_current_thread_state(); }
catch (...) { return; }
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return;
}
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
PDBG("cannot set registers while thread is in syscall");
return;
}
switch((enum reg_index)regno)
{
case EAX: thread_state.eax = reg_content; PDBG("EAX = %8lx", reg_content); break;
case ECX: thread_state.ecx = reg_content; PDBG("ECX = %8lx", reg_content); break;
case EDX: thread_state.edx = reg_content; PDBG("EDX = %8lx", reg_content); break;
case EBX: thread_state.ebx = reg_content; PDBG("EBX = %8lx", reg_content); break;
case UESP: thread_state.sp = reg_content; PDBG("ESP = %8lx", reg_content); break;
case EBP: thread_state.ebp = reg_content; PDBG("EBP = %8lx", reg_content); break;
case ESI: thread_state.esi = reg_content; PDBG("ESI = %8lx", reg_content); break;
case EDI: thread_state.edi = reg_content; PDBG("EDI = %8lx", reg_content); break;
case EIP: thread_state.ip = reg_content; PDBG("EIP = %8lx", reg_content); break;
case EFL: thread_state.eflags = reg_content; PDBG("EFL = %8lx", reg_content); break;
case CS: PDBG("cannot set contents of register CS"); PDBG(" CS = %8lx", reg_content); break;
case SS: PDBG("cannot set contents of register SS"); PDBG(" SS = %8lx", reg_content); break;
case DS: PDBG("cannot set contents of register DS"); PDBG(" DS = %8lx", reg_content); break;
case ES: PDBG("cannot set contents of register ES"); PDBG(" ES = %8lx", reg_content); break;
case FS: thread_state.fs = reg_content; PDBG(" FS = %8lx", reg_content); break;
case GS: thread_state.gs = reg_content; PDBG(" GS = %8lx", reg_content); break;
case EAX: if (!store_register("EAX", ts.eax, value)) return; break;
case ECX: if (!store_register("ECX", ts.ecx, value)) return; break;
case EDX: if (!store_register("EDX", ts.edx, value)) return; break;
case EBX: if (!store_register("EBX", ts.ebx, value)) return; break;
case UESP: if (!store_register("ESP", ts.sp, value)) return; break;
case EBP: if (!store_register("EBP", ts.ebp, value)) return; break;
case ESI: if (!store_register("ESI", ts.esi, value)) return; break;
case EDI: if (!store_register("EDI", ts.edi, value)) return; break;
case EIP: if (!store_register("EIP", ts.ip, value)) return; break;
case EFL: if (!store_register("EFL", ts.eflags, value)) return; break;
case CS: cannot_store_register("CS", value); return;
case SS: cannot_store_register("SS", value); return;
case DS: cannot_store_register("DS", value); return;
case ES: cannot_store_register("ES", value); return;
case FS: if (!store_register("FS ", ts.fs, value)) return; break;
case GS: if (!store_register("GS ", ts.gs, value)) return; break;
default: PERR("unhandled register %d", regno); return;
}
set_current_thread_state(thread_state);
set_current_thread_state(ts);
}

View File

@ -1,63 +0,0 @@
/*
* \brief Linux(x86_32)-specific helper functions for GDB server
* \author Christian Prochaska
* \date 2011-05-06
*/
/*
* Copyright (C) 2011-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.
*/
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/printf.h>
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
using namespace Genode;
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
{
Thread_state thread_state;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
switch((enum reg_index)regno)
{
case EAX: PDBG("cannot determine contents of register EAX"); return -1;
case ECX: PDBG("cannot determine contents of register ECX"); return -1;
case EDX: PDBG("cannot determine contents of register EDX"); return -1;
case EBX: PDBG("cannot determine contents of register EBX"); return -1;
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case EBP: PDBG("cannot determine contents of register EBP"); return -1;
case ESI: PDBG("cannot determine contents of register ESI"); return -1;
case EDI: PDBG("cannot determine contents of register EDI"); return -1;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1;
case GS: PDBG("cannot determine contents of register GS"); return -1;
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
{
PDBG("not implemented yet for this platform");
}

View File

@ -0,0 +1,79 @@
/*
* \brief NOVA-specific 'Native_cpu' setup
* \author Christian Prochaska
* \date 2016-05-13
*/
/*
* Copyright (C) 2016 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 <nova_native_cpu/client.h>
/* GDB monitor includes */
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
namespace Gdb_monitor {
class Native_cpu_component;
}
using namespace Genode;
class Gdb_monitor::Native_cpu_component : public Rpc_object<Nova_native_cpu,
Native_cpu_component>
{
private:
Cpu_session_component &_cpu_session_component;
Nova_native_cpu_client _nova_native_cpu;
public:
Native_cpu_component(Cpu_session_component &cpu_session_component)
: _cpu_session_component(cpu_session_component),
_nova_native_cpu(_cpu_session_component.parent_cpu_session().native_cpu())
{
_cpu_session_component.thread_ep().manage(this);
}
~Native_cpu_component()
{
_cpu_session_component.thread_ep().dissolve(this);
}
Native_capability pager_cap(Thread_capability thread_cap) override
{
Cpu_thread_component *cpu_thread = _cpu_session_component.lookup_cpu_thread(thread_cap);
return _nova_native_cpu.pager_cap(cpu_thread->parent_thread_cap());
}
};
Capability<Cpu_session::Native_cpu>
Gdb_monitor::Cpu_session_component::_setup_native_cpu()
{
Native_cpu_component *native_cpu_component =
new (_md_alloc) Native_cpu_component(*this);
return native_cpu_component->cap();
}
void Gdb_monitor::Cpu_session_component::_cleanup_native_cpu()
{
Native_cpu_component *native_cpu_component = nullptr;
_thread_ep->apply(_native_cpu_cap, [&] (Native_cpu_component *c) { native_cpu_component = c; });
if (!native_cpu_component) return;
destroy(_md_alloc, native_cpu_component);
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2016 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,43 +14,75 @@
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
#include "genode_child_resources.h"
using namespace Genode;
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
extern "C" int genode_fetch_register(int regno, unsigned long *value)
{
Thread_state thread_state;
Thread_state ts;
try { thread_state = get_current_thread_state(); }
catch (...) { return -1; }
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return -1;
}
switch((enum reg_index)regno)
{
case EAX: *reg_content = thread_state.eax; return 0;
case ECX: *reg_content = thread_state.ecx; return 0;
case EDX: *reg_content = thread_state.edx; return 0;
case EBX: *reg_content = thread_state.ebx; return 0;
case UESP: *reg_content = thread_state.sp; return 0;
case EBP: *reg_content = thread_state.ebp; return 0;
case ESI: *reg_content = thread_state.esi; return 0;
case EDI: *reg_content = thread_state.edi; return 0;
case EIP: *reg_content = thread_state.ip; return 0;
case EFL: *reg_content = thread_state.eflags; return 0;
case CS: return -1;
case SS: return -1;
case DS: return -1;
case ES: return -1;
case FS: *reg_content = thread_state.fs; return 0;
case GS: *reg_content = thread_state.gs; return 0;
case EAX: fetch_register("EAX", ts.eax, *value); return 0;
case ECX: fetch_register("ECX", ts.ecx, *value); return 0;
case EDX: fetch_register("EDX", ts.edx, *value); return 0;
case EBX: fetch_register("EBX", ts.ebx, *value); return 0;
case UESP: fetch_register("ESP", ts.sp, *value); return 0;
case EBP: fetch_register("EBP", ts.ebp, *value); return 0;
case ESI: fetch_register("ESI", ts.esi, *value); return 0;
case EDI: fetch_register("EDI", ts.edi, *value); return 0;
case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case EFL: fetch_register("EFL", ts.eflags, *value); return 0;
case CS: cannot_fetch_register("CS"); return -1;
case SS: cannot_fetch_register("SS"); return -1;
case DS: cannot_fetch_register("DS"); return -1;
case ES: cannot_fetch_register("ES"); return -1;
case FS: cannot_fetch_register("FS"); return -1;
case GS: cannot_fetch_register("GS"); return -1;
default: PERR("unhandled register %d", regno); return -1;
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
extern "C" void genode_store_register(int regno, unsigned long value)
{
PDBG("not implemented yet for this platform");
}
Thread_state ts;
try { ts = get_current_thread_state(); }
catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return;
}
switch ((enum reg_index)regno)
{
case EAX: if (!store_register("EAX", ts.eax, value)) return; break;
case ECX: if (!store_register("ECX", ts.ecx, value)) return; break;
case EDX: if (!store_register("EDX", ts.edx, value)) return; break;
case EBX: if (!store_register("EBX", ts.ebx, value)) return; break;
case UESP: if (!store_register("ESP", ts.sp, value)) return; break;
case EBP: if (!store_register("EBP", ts.ebp, value)) return; break;
case ESI: if (!store_register("ESI", ts.esi, value)) return; break;
case EDI: if (!store_register("EDI", ts.edi, value)) return; break;
case EIP: if (!store_register("EIP", ts.ip, value)) return; break;
case EFL: if (!store_register("EFL", ts.eflags, value)) return; break;
case CS: cannot_store_register("CS", value); return;
case SS: cannot_store_register("SS", value); return;
case DS: cannot_store_register("DS", value); return;
case ES: cannot_store_register("ES", value); return;
case FS: cannot_store_register("FS", value); return;
case GS: cannot_store_register("GS", value); return;
default: PERR("unhandled register %d", regno); return;
}
set_current_thread_state(ts);
}

View File

@ -1,82 +0,0 @@
/*
* \brief OKL4(x86)-specific helper functions for GDB server
* \author Christian Prochaska
* \date 2011-05-06
*/
/*
* Copyright (C) 2011-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.
*/
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/printf.h>
#include "i386.h"
#include "cpu_session_component.h"
#include "gdb_stub_thread.h"
#include "gdbserver_platform_helper.h"
using namespace Genode;
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
{
Thread_state thread_state;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
switch((enum reg_index)regno)
{
case EAX: *reg_content = thread_state.eax; PDBG("EAX = %8lx", *reg_content); return 0;
case ECX: *reg_content = thread_state.ecx; PDBG("ECX = %8lx", *reg_content); return 0;
case EDX: *reg_content = thread_state.edx; PDBG("EDX = %8lx", *reg_content); return 0;
case EBX: *reg_content = thread_state.ebx; PDBG("EBX = %8lx", *reg_content); return 0;
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case EBP:
/*
* When in a syscall, the user EBP has been pushed onto the stack at address ESP+4
*
* looking for syscall pattern:
* EIP-2: 0f 34 sysenter
*/
if ((genode_read_memory_byte((void*)(thread_state.ip - 1)) == 0x34) &&
(genode_read_memory_byte((void*)(thread_state.ip - 2)) == 0x0f)) {
*reg_content = genode_read_memory_byte((void*)(thread_state.sp + 4)) +
(genode_read_memory_byte((void*)(thread_state.sp + 5)) << 8) +
(genode_read_memory_byte((void*)(thread_state.sp + 6)) << 16) +
(genode_read_memory_byte((void*)(thread_state.sp + 7)) << 24);
PDBG("EBP = %8lx", *reg_content);
return 0;
} else {
*reg_content = thread_state.ebp;
PDBG("EBP = %8lx", *reg_content);
return 0;
}
case ESI: *reg_content = thread_state.esi; PDBG("ESI = %8lx", *reg_content); return 0;
case EDI: *reg_content = thread_state.edi; PDBG("EDI = %8lx", *reg_content); return 0;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: *reg_content = thread_state.eflags; PDBG("EFLAGS = %8lx", *reg_content); return 0;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1;
case GS: PDBG("cannot determine contents of register GS"); return -1;
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
{
PDBG("not implemented yet for this platform");
}

View File

@ -1,84 +0,0 @@
/*
* \brief Pistachio(x86)-specific helper functions for GDB server
// * \author Christian Prochaska
* \date 2011-05-06
*/
/*
* Copyright (C) 2011-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.
*/
extern "C" {
#define private _private
#include "genode-low.h"
#define _private private
}
#include <base/printf.h>
#include "i386.h"
#include "cpu_session_component.h"
#include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h"
using namespace Genode;
extern "C" int genode_fetch_register(int regno, unsigned long *reg_content)
{
Thread_state thread_state;
try { thread_state = get_current_thread_state(); }
catch (...) { return 0; }
switch((enum reg_index)regno)
{
case EAX: PDBG("cannot determine contents of register EAX"); return -1;
case ECX: PDBG("cannot determine contents of register ECX"); return -1;
case EDX: PDBG("cannot determine contents of register EDX"); return -1;
case EBX: PDBG("cannot determine contents of register EBX"); return -1;
case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0;
case EBP:
/*
* When in a syscall, the user EBP has been pushed onto the stack at address ESP+0
*
* looking for syscall pattern:
* EIP-6: 55 push %ebp
* EIP-5: e8 .. call ...
* EIP: 89 e9 mov %ebp, %ecx
*/
if ((genode_read_memory_byte((void*)(thread_state.ip + 1)) == 0xe9) &&
(genode_read_memory_byte((void*)(thread_state.ip)) == 0x89) &&
(genode_read_memory_byte((void*)(thread_state.ip - 5)) == 0xe8) &&
(genode_read_memory_byte((void*)(thread_state.ip - 6)) == 0x55)) {
*reg_content = genode_read_memory_byte((void*)(thread_state.sp + 0)) +
(genode_read_memory_byte((void*)(thread_state.sp + 1)) << 8) +
(genode_read_memory_byte((void*)(thread_state.sp + 2)) << 16) +
(genode_read_memory_byte((void*)(thread_state.sp + 3)) << 24);
PDBG("ESP = %8lx", *reg_content);
return 0;
} else {
PDBG("cannot determine contents of register EBP"); return -1;
}
case ESI: PDBG("cannot determine contents of register ESI"); return -1;
case EDI: PDBG("cannot determine contents of register EDI"); return -1;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0;
case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1;
case CS: PDBG("cannot determine contents of register CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1;
case GS: PDBG("cannot determine contents of register GS"); return -1;
}
return -1;
}
extern "C" void genode_store_register(int regno, unsigned long reg_content)
{
PDBG("not implemented yet for this platform");
}

View File

@ -29,7 +29,12 @@ class Test_thread : public Genode::Thread_deprecated<2*4096>
Test_thread() : Thread_deprecated("test") { }
void func()
void step_func()
{
/* nothing */
}
void sigsegv_func()
{
/*
* make sure that the main thread is sleeping in
@ -43,7 +48,9 @@ class Test_thread : public Genode::Thread_deprecated<2*4096>
void entry() /* set a breakpoint here to test the 'info threads' command */
{
func();
step_func();
sigsegv_func();
Genode::sleep_forever();
}

View File

@ -1,3 +1,5 @@
TARGET = test-gdb_monitor
SRC_CC = main.cc
LIBS = libc
CC_OLEVEL = -O0