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 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 interface to a local socket (using the port 5555):
! -serial chardev:uart ! -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: The used TCP port is then specified to the GDB as remote target:
! target remote localhost:5555 ! target remote localhost:5555

View File

@ -1,7 +1 @@
INC_DIR += $(REP_DIR)/src/lib/gdbserver_libc_support 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 \ SRC_C = reg-arm.c \
linux-arm-low.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 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 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)/../.. GENODE_DIR := $(REP_DIR)/../..
PATCHES_DIR := $(GENODE_DIR)/tool/patches/gdb-$(VERSION) PATCHES_DIR := $(GENODE_DIR)/tool/patches/gdb-$(VERSION)
PATCHES := $(addprefix $(PATCHES_DIR)/,$(shell cat $(PATCHES_DIR)/series)) \ 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/app/gdb_monitor/gdbserver_genode.patch \
$(REP_DIR)/src/noux-pkg/gdb/build.patch $(REP_DIR)/src/noux-pkg/gdb/build.patch
PATCH_OPT := -p1 -d ${DIR(gdb)} 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 # connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart " 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" puts "GDB monitor is up, starting GDB in a new terminal"
exec [terminal] -e "[gdb] bin/nitpicker -ex \"target remote localhost:$local_port\"" & exec [terminal] -e "[gdb] bin/nitpicker -ex \"target remote localhost:$local_port\"" &
interact interact -i [output_spawn_id]
# vi: set ft=tcl : # 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 # don't ask for y/n when loading a new symbol file
append gdb_cmds {-ex "set interactive-mode off" } append gdb_cmds {-ex "set interactive-mode off" }
# load the symbols of ld.lib.so # set a breakpoint in the 'binary_ready_hook_for_gdb' function
append gdb_cmds {-ex "symbol-file bin/ld.lib.so" } append gdb_cmds {-ex "b binary_ready_hook_for_gdb" }
# set a breakpoint in the 'Linker::Binary::call_entry_point' function
append gdb_cmds {-ex "b Linker::Binary::call_entry_point" }
# continue execution until the breakpoint triggers # continue execution until the breakpoint triggers
append gdb_cmds {-ex "c" } 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" } append gdb_cmds {-ex "delete 1" }
# load the symbols of the test application # 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 # set a breakpoint in the application's 'main()' function
append gdb_cmds {-ex "b main" } append gdb_cmds {-ex "b main" }

View File

@ -6,8 +6,8 @@
# #
# #
# Only Genode/Fiasco.OC and Genode/NOVA supports all the tested features # Only the 32-bit NOVA and Fiasco.OC base platforms support most of the tested features
# at this time # at this time.
# #
if {![have_include "power_on/qemu"] || (![have_spec foc] && ![have_spec nova])} { 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> <any-service> <parent/> <any-child/> </any-service>
</default-route> </default-route>
<start name="timer"> <start name="timer">
<resource name="RAM" quantum="1M"/> <resource name="RAM" quantum="2M"/>
<provides> <service name="Timer"/> </provides> <provides> <service name="Timer"/> </provides>
</start> </start>
<start name="uart_drv"> <start name="uart_drv">
<resource name="RAM" quantum="1M"/> <resource name="RAM" quantum="2M"/>
<provides> <service name="Terminal"/> </provides> <provides> <service name="Terminal"/> </provides>
<config> <config>
<policy label="gdb_monitor" uart="1"/> <policy label="gdb_monitor" uart="1"/>
@ -109,9 +109,9 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port # connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart " 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] set genode_id [output_spawn_id]
puts "GDB monitor is up, starting GDB" 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 # sequence of GDB commands to execute at startup
set gdb_cmds "" set gdb_cmds ""
append gdb_cmds {-ex "target remote localhost:$local_port" } append gdb_cmds {-ex "target remote localhost:$local_port" }
append gdb_cmds [gdb_main_breakpoint_cmds $gdb_target_binary] append gdb_cmds [gdb_main_breakpoint_cmds $gdb_target_binary]
# # run GDB and redirect stderr to stdio to get the relevant output into the expect buffer
# Test commands 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 puts ""
append gdb_cmds {-ex "b puts" } puts "----- test: breakpoint in 'main()' -----"
append gdb_cmds {-ex "c" } puts ""
# test: stack trace when not in syscall run_genode_until {\(gdb\)} 60 $gdb_id
append gdb_cmds {-ex "bt" }
# test: modify variable if {![regexp {Breakpoint 2, main ()} $output]} {
append gdb_cmds {-ex "print test_var" } puts stderr "*** Error: Breakpoint in main() did not trigger"
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"
exit -1 exit -1
} }
if {![regexp {Breakpoint 3, puts (.*)} $gdb_output]} { puts "\n"
puts "Error: Breakpoint in shared library did not trigger" 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 exit -1
} }
if {![regexp {#0 puts} $gdb_output] || puts "\n"
![regexp {in func2()} $gdb_output] || puts "----- test: stack trace when not in syscall -----"
![regexp {in func1()} $gdb_output] || puts ""
![regexp {in main ()} $gdb_output]} {
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 exit -1
} }
if {![regexp {\$1 = 1} $gdb_output]} { puts "\n"
puts stderr "Error: first 'print test_var' command didn't result in the expected output" 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 exit -1
} }
if {![regexp {\$2 = 2} $gdb_output]} { send "set var test_var=2\n"
puts stderr "Error: second 'print test_var' command didn't result in the expected output" 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 exit -1
} }
if {![have_spec nova]} { puts "\n"
if {![regexp {\$3 = 3} $gdb_output]} { puts "----- test: 'call' command -----"
puts stderr "Error: 'call' command didn't result in the expected output" puts ""
exit -1
}
}
if {![regexp {Breakpoint 4, Test_thread::entry()} $gdb_output]} { send "call test_var_func()\n"
puts stderr "Error: Breakpoint in test thread did not trigger" 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 exit -1
} }
if {![regexp {\* 2 Thread 2 Test_thread::entry} $gdb_output] || puts "\n"
![regexp { 1 Thread 1} $gdb_output]} { puts "----- test: thread info -----"
puts stderr "Error: Thread info is not as expected" 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 exit -1
} }
if {![regexp {38 static Timer::Connection timer} $gdb_output]} { send "info threads\n"
puts stderr "Error: Single stepping didn't result in the expected output" 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 exit -1
} }
if {![regexp {Program received signal SIGSEGV, Segmentation fault.} $gdb_output]} { puts "\n"
puts stderr "Error: Segmentation fault exception was not catched" 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 exit -1
} }
if {![regexp {Genode::Cancelable_lock::lock\(\)} $gdb_output] || puts "\n"
![regexp {Genode::Thread::join\(\)} $gdb_output] || puts "----- test: catching a segmentation fault -----"
![regexp {in main \(\)} $gdb_output]} { 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 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 : # vi: set ft=tcl :

View File

@ -39,11 +39,11 @@ set config {
<any-service> <parent/> <any-child/> </any-service> <any-service> <parent/> <any-child/> </any-service>
</default-route> </default-route>
<start name="timer"> <start name="timer">
<resource name="RAM" quantum="1M"/> <resource name="RAM" quantum="2M"/>
<provides> <service name="Timer"/> </provides> <provides> <service name="Timer"/> </provides>
</start> </start>
<start name="uart_drv"> <start name="uart_drv">
<resource name="RAM" quantum="1M"/> <resource name="RAM" quantum="2M"/>
<provides> <service name="Terminal"/> </provides> <provides> <service name="Terminal"/> </provides>
<config> <config>
<policy label="gdb_monitor" uart="1"/> <policy label="gdb_monitor" uart="1"/>
@ -98,7 +98,7 @@ append qemu_args " -serial mon:stdio "
# connect comport 1 with TCP port $local_port # connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart " 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 {.*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" 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] 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 # connect comport 1 with TCP port $local_port
append qemu_args " -serial chardev:uart " 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 {.*Remote debugging using /dev/terminal.*} 30

View File

@ -1,5 +1,5 @@
if {![have_spec foc] || ![have_spec 32bit]} { if {![have_spec foc] && ![have_spec nova]} {
puts "\nThe Noux GDB scenario is supported on 32-bit Fiasco.OC only\n" puts "\nThe Noux GDB scenario is supported on NOVA and Fiasco.OC only\n"
exit 0 exit 0
} }
@ -126,7 +126,7 @@ append config {
<provides> <service name="Terminal"/> </provides> <provides> <service name="Terminal"/> </provides>
</start> </start>
<start name="gdb_monitor"> <start name="gdb_monitor">
<resource name="RAM" quantum="10M"/> <resource name="RAM" quantum="16M"/>
<route> <route>
<service name="Terminal"><child name="terminal_gdb"/></service> <service name="Terminal"><child name="terminal_gdb"/></service>
<any-service><parent/><any-child/></any-service> <any-service><parent/><any-child/></any-service>
@ -171,19 +171,18 @@ append config {
</fstab> } </fstab> }
append config " append config "
<start name=\"/bin/${tool_prefix}gdb\"> <start name=\"/bin/${tool_prefix}gdb\">
<arg value=\"/gdb/${gdb_target_binary_name}\"/> " <arg value=\"/gdb/ld.lib.so\"/> "
append config { append config {
<arg value="-ex" /><arg value="set interactive-mode off" /> <arg value="-ex" /><arg value="set interactive-mode off" />
<arg value="-ex" /><arg value="directory /gdb/src" /> <arg value="-ex" /><arg value="directory /gdb/src" />
<arg value="-ex" /><arg value="target remote /dev/gdb" /> <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 binary_ready_hook_for_gdb" />
<arg value="-ex" /><arg value="b call_program_main" />
<arg value="-ex" /><arg value="c" /> <arg value="-ex" /><arg value="c" />
<arg value="-ex" /><arg value="delete 1" /> } <arg value="-ex" /><arg value="delete 1" /> }
append config " 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 { 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="set solib-search-path /gdb" />
<arg value="-ex" /><arg value="sharedlibrary" /> <arg value="-ex" /><arg value="sharedlibrary" />
<arg value="-ex" /><arg value="c" /> <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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -26,292 +26,333 @@
#include <util/arg_string.h> #include <util/arg_string.h>
#include "cpu_root.h" #include "cpu_root.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
#include "ram_root.h"
#include "pd_session_component.h" #include "pd_session_component.h"
#include "ram_root.h"
#include "rom.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 class Gdb_monitor::App_child : public Child_policy,
{ public Init::Child_policy_enforce_labeling
private: {
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; Rpc_entrypoint _entrypoint;
Service_registry _local_services;
Init::Child_config _child_config; Service_registry *_parent_services;
Service_registry _local_services;
Init::Child_policy_provide_rom_file _binary_policy; Genode::Rpc_entrypoint *_root_ep;
Init::Child_policy_provide_rom_file _config_policy;
Gdb_stub_thread _gdb_stub_thread; Init::Child_config _child_config;
Dataspace_pool _managed_ds_map;
Cpu_root _cpu_root; Init::Child_policy_provide_rom_file _binary_policy;
Cpu_session_client _cpu_session; 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, Signal_dispatcher<App_child> _unresolved_page_fault_dispatcher;
_managed_ds_map };
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() Child::Initial_thread _initial_thread;
{
_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()));
}
/** Parent_service _parent_pd_service { "" };
* Proxy for a service provided by the child Parent_service _parent_ram_service { "" };
*/ Parent_service _parent_cpu_service { "" };
class Child_service_root : public Genode::Rpc_object<Genode::Root>
{
private:
/** Child *_child;
* Root interface of the real service, provided by the 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;
}
/** void upgrade(Session_capability session_cap,
* Child's RAM session used for quota transfers Upgrade_args const &args)
*/ {
Genode::Ram_session_capability _child_ram; using namespace Genode;
struct Child_session; auto lambda = [&] (Child_session *session) {
typedef Genode::Object_pool<Child_session> Session_pool; if (!session) {
PERR("attempt to upgrade unknown session");
/** return;
* 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 = Genode::size_t ram_quota =
Arg_string::find_arg(args.string(), Arg_string::find_arg(args.string(),
"ram_quota").ulong_value(0); "ram_quota").ulong_value(0);
/* forward session quota to child */ /* forward session quota to child */
env()->ram_session()->transfer_quota(_child_ram, ram_quota); env()->ram_session()->transfer_quota(_child_ram, ram_quota);
Session_capability cap = _child_root.session(args, affinity); session->ram_quota += ram_quota;
/* /* inform child about quota upgrade */
* Keep information about donated quota in '_sessions' _child_root.upgrade(session_cap, args);
* data base. };
*/
_sessions.insert(new (env()->heap())
Child_session(cap, ram_quota));
return cap;
}
void upgrade(Session_capability session_cap, _sessions.apply(session_cap, lambda);
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);
} }
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; 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, return service;
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)); bool announce_service(const char *name,
return true; 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_ */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -21,43 +21,58 @@
#include <cpu_session_component.h> #include <cpu_session_component.h>
/* GDB monitor includes */ /* 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> class Gdb_monitor::Cpu_root : public Root_component<Cpu_session_component>
{ {
private: private:
Gdb_stub_thread *_gdb_stub_thread;
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) protected:
{
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;
}
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;
}
/** public:
* Constructor
* /**
* \param session_ep entry point for managing cpu session objects * Constructor
* \param thread_ep entry point for managing threads *
* \param md_alloc meta data allocator to be used by root component * \param session_ep entry point for managing cpu session objects
*/ * \param thread_ep entry point for managing threads
Cpu_root(Rpc_entrypoint *session_ep, * \param md_alloc meta data allocator to be used by root component
Allocator *md_alloc, */
Gdb_stub_thread *gdb_stub_thread) Cpu_root(Rpc_entrypoint *session_ep,
: Rpc_entrypoint *thread_ep,
Root_component<Cpu_session_component>(session_ep, md_alloc), Allocator *md_alloc,
_gdb_stub_thread(gdb_stub_thread) 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_ */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -14,31 +14,69 @@
/* Genode includes */ /* Genode includes */
#include <base/env.h> #include <base/env.h>
#include <base/printf.h> #include <base/printf.h>
#include <base/sleep.h>
#include <cpu_session_component.h> #include <cpu_session_component.h>
#include <util/list.h> #include <util/list.h>
/* GDB monitor includes */ /* 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); extern void genode_remove_thread(unsigned long lwpid);
using namespace Genode; using namespace Genode;
using namespace Gdb_monitor; using namespace Gdb_monitor;
/* FIXME: use an allocator */
static unsigned long new_lwpid = GENODE_LWP_BASE;
Cpu_session &Cpu_session_component::parent_cpu_session()
Thread_info *Cpu_session_component::_thread_info(Thread_capability thread_cap)
{ {
Thread_info *thread_info = _thread_list.first(); return _parent_cpu_session;
while (thread_info) { }
if (thread_info->thread_cap().local_name() == thread_cap.local_name()) {
return thread_info;
break; Rpc_entrypoint &Cpu_session_component::thread_ep()
} {
thread_info = thread_info->next(); 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; 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) 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(); return lookup_cpu_thread(thread_cap)->signal_pipe_read_fd();
while (thread_info) { }
if (thread_info->lwpid() == lwpid) {
return thread_info->thread_cap();
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 void Cpu_session_component::stop_new_threads(bool stop)
Cpu_session_component::create_thread(Capability<Pd_session> pd,
Name const &name,
Affinity::Location location,
Weight weight,
addr_t utcb)
{ {
Thread_capability thread_cap = _stop_new_threads = stop;
_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;
} }
//Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread) bool Cpu_session_component::stop_new_threads()
//{
// return _parent_cpu_session.utcb(thread);
//}
void Cpu_session_component::kill_thread(Thread_capability thread_cap)
{ {
Thread_info *thread_info = _thread_info(thread_cap); return _stop_new_threads;
}
if (thread_info) {
_exception_signal_receiver->dissolve(thread_info); Lock &Cpu_session_component::stop_new_threads_lock()
genode_remove_thread(thread_info->lwpid()); {
_thread_list.remove(thread_info); return _stop_new_threads_lock;
destroy(env()->heap(), thread_info); }
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_capability Cpu_session_component::first()
{ {
Thread_info *thread_info = _thread_list.first(); Cpu_thread_component *cpu_thread = _thread_list.first();
if (thread_info) if (cpu_thread)
return thread_info->thread_cap(); return cpu_thread->thread_cap();
else else
return Thread_capability(); return Thread_capability();
} }
@ -115,77 +235,50 @@ Thread_capability Cpu_session_component::first()
Thread_capability Cpu_session_component::next(Thread_capability thread_cap) Thread_capability Cpu_session_component::next(Thread_capability thread_cap)
{ {
Thread_info *next_thread_info = _thread_info(thread_cap)->next(); Cpu_thread_component *next_cpu_thread = lookup_cpu_thread(thread_cap)->next();
if (next_thread_info) if (next_cpu_thread)
return next_thread_info->thread_cap(); return next_cpu_thread->thread_cap();
else else
return Thread_capability(); return Thread_capability();
} }
//int Cpu_session_component::start(Thread_capability thread_cap, Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd,
// addr_t ip, addr_t sp) Cpu_session::Name const &name,
//{ Affinity::Location affinity,
// Thread_info *thread_info = _thread_info(thread_cap); Weight weight,
// addr_t utcb)
// 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)
{ {
_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) void Cpu_session_component::kill_thread(Thread_capability thread_cap)
//{ {
// _parent_cpu_session.single_step(thread_cap, enable); 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 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() Dataspace_capability Cpu_session_component::trace_control()
{ {
return _parent_cpu_session.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() 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) Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep,
: _parent_cpu_session(env()->parent()->session<Cpu_session>(args)), Allocator *md_alloc,
_exception_signal_receiver(exception_signal_receiver) 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() 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::ref_account(Cpu_session_capability) { return -1; }
int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; } int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; }
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); } 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -15,40 +15,77 @@
#define _CPU_SESSION_COMPONENT_H_ #define _CPU_SESSION_COMPONENT_H_
/* Genode includes */ /* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <base/thread.h>
#include <cpu_session/client.h> #include <cpu_session/client.h>
#include <pd_session/capability.h>
/* GDB monitor includes */ /* GDB monitor includes */
#include "thread_info.h" #include "append_list.h"
using namespace Genode; namespace Gdb_monitor
using namespace Gdb_monitor;
class Cpu_session_component : public Rpc_object<Cpu_session>
{ {
class Cpu_session_component;
class Cpu_thread_component;
using namespace Genode;
}
class Gdb_monitor::Cpu_session_component : public Rpc_object<Cpu_session>
{
private: private:
Rpc_entrypoint *_thread_ep;
Allocator *_md_alloc;
Pd_session_capability _core_pd;
Cpu_session_client _parent_cpu_session; Cpu_session_client _parent_cpu_session;
Signal_receiver *_exception_signal_receiver; 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: public:
/** /**
* Constructor * 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 * Destructor
*/ */
~Cpu_session_component(); ~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); 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 first();
Thread_capability next(Thread_capability); Thread_capability next(Thread_capability);
@ -56,8 +93,11 @@ class Cpu_session_component : public Rpc_object<Cpu_session>
** CPU session interface ** ** CPU session interface **
***************************/ ***************************/
Thread_capability create_thread(Capability<Pd_session>, Name const &, Thread_capability create_thread(Capability<Pd_session>,
Affinity::Location, Weight, addr_t) override; Name const &,
Affinity::Location,
Weight,
addr_t) override;
void kill_thread(Thread_capability) override; void kill_thread(Thread_capability) override;
void exception_sigh(Signal_context_capability handler) override; void exception_sigh(Signal_context_capability handler) override;
Affinity::Space affinity_space() const 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; } Region_map_component *region_map_component() { return _region_map_component; }
}; };
} }
#endif /* _DATASPACE_OBJECT_H_ */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -28,4 +28,4 @@
#define __GENODE__ #define __GENODE__
/* first process id */ /* 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * 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" { extern "C" {
#define private _private #define private _private
#include "genode-low.h" #include "genode-low.h"
#include "server.h"
#include "linux-low.h" #include "linux-low.h"
#define _private private #define _private private
int linux_detach_one_lwp (struct inferior_list_entry *entry, void *args); int linux_detach_one_lwp (struct inferior_list_entry *entry, void *args);
} }
#include <base/env.h>
#include <base/printf.h> #include <base/printf.h>
#include <dataspace/client.h> #include <base/service.h>
#include <cap_session/connection.h>
#include <cpu_thread/client.h> #include <cpu_thread/client.h>
#include <dataspace/client.h>
#include <os/config.h>
#include <ram_session/connection.h>
#include <rom_session/connection.h>
#include <util/xml_node.h>
#include "app_child.h"
#include "cpu_session_component.h" #include "cpu_session_component.h"
#include "cpu_thread_component.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
#include "rom.h"
#include "signal_handler_thread.h"
static bool verbose = false; 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 Genode;
using namespace Gdb_monitor; 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 _genode_child_resources;
return _main_thread_ready_lock;
} }
static Lock &gdbserver_ready_lock() static void genode_stop_thread(unsigned long lwpid)
{ {
static Lock _gdbserver_ready_lock(Lock::LOCKED); Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
return _gdbserver_ready_lock;
}
Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid);
Gdb_stub_thread *gdb_stub_thread() if (!cpu_thread) {
{ PERR("%s: could not find CPU thread object for lwpid %lu",
return (Gdb_stub_thread*)(current_process()->_private->gdb_stub_thread); __PRETTY_FUNCTION__, lwpid);
} return;
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);
} }
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) 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 *) linux_detach_one_lwp((struct inferior_list_entry *)
find_thread_ptid(ptid_build(GENODE_LWP_BASE, lwpid, 0)), &pid); find_thread_ptid(ptid_build(GENODE_MAIN_LWPID, 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);
}
} }
extern "C" void genode_stop_all_threads() extern "C" void genode_stop_all_threads()
{ {
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->pause_all_threads();
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
Cpu_thread_client(thread_cap).pause();
thread_cap = csc->next(thread_cap);
}
} }
extern "C" void genode_resume_all_threads() void genode_resume_all_threads()
{ {
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); Cpu_session_component *csc = genode_child_resources()->cpu_session_component();
csc->resume_all_threads();
Thread_capability thread_cap = csc->first();
while (thread_cap.valid()) {
Cpu_thread_client(thread_cap).resume();
thread_cap = csc->next(thread_cap);
}
} }
int genode_detach(int pid) int genode_detach(int pid)
{ {
find_inferior (&all_threads, linux_detach_one_lwp, &pid);
genode_resume_all_threads(); genode_resume_all_threads();
return 0; return 0;
@ -146,86 +432,67 @@ int genode_detach(int pid)
int genode_kill(int pid) int genode_kill(int pid)
{ {
/* TODO */ /* TODO */
if (verbose) PDBG("genode_kill() called - not implemented\n"); if (verbose) PDBG("not implemented, just detaching instead...");
return genode_detach(pid); 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) 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()) { if (!cpu_thread) {
PERR("could not find thread capability for lwpid %lu", lwpid); PERR("%s: could not find CPU thread object for lwpid %lu",
__PRETTY_FUNCTION__, lwpid);
return; return;
} }
Cpu_thread_client cpu_thread(thread_cap); cpu_thread->single_step(single_step);
cpu_thread.single_step(single_step); cpu_thread->resume();
cpu_thread.resume();
} }
/* void genode_fetch_registers(struct regcache *regcache, int regno)
* 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()
{ {
unsigned long reg_content = 0;
Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); if (regno == -1) {
for (regno = 0; regno < the_low_target.num_regs; regno++) {
/* if (genode_fetch_register(regno, &reg_content) == 0)
* It can happen that the thread state of the thread which caused the supply_register(regcache, regno, &reg_content);
* page fault is not accessible yet. In that case, we'll retry until else
* it is accessible. supply_register(regcache, regno, 0);
*/
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);
} }
} 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) { if (!local_base) {
PWRN("Memory model: no memory at address %p", addr); PWRN("Memory model: no memory at address %p", addr);
return 0; throw No_memory_at_address();
} }
unsigned char value = unsigned char value =
@ -350,7 +617,7 @@ class Memory_model
void write(void *addr, unsigned char value) void write(void *addr, unsigned char value)
{ {
if (verbose) 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); Lock::Guard guard(_lock);
@ -363,7 +630,7 @@ class Memory_model
if (!local_base) { if (!local_base) {
PWRN("Memory model: no memory at address %p", addr); PWRN("Memory model: no memory at address %p", addr);
PWRN("(attempted to write %x)", (int)value); PWRN("(attempted to write %x)", (int)value);
return; throw No_memory_at_address();
} }
local_base[offset_in_region] = value; local_base[offset_in_region] = value;
@ -376,7 +643,7 @@ class Memory_model
*/ */
static Memory_model *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; 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) 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -18,27 +18,29 @@
#ifndef GENODE_LOW_H #ifndef GENODE_LOW_H
#define GENODE_LOW_H #define GENODE_LOW_H
#include <sys/types.h>
#include "server.h" #include "server.h"
int genode_signal_fd(); /* exception type */
struct No_memory_at_address { };
void genode_wait_for_target_main_thread(); /* interface for linux-low.c */
void genode_detect_all_threads();
void genode_stop_all_threads(); 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); 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); int genode_fetch_register(int regno, unsigned long *reg_content);
void genode_store_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); 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 */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * 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 * 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 getpid() { return -1; }
extern "C" int sigprocmask() { return -1; } extern "C" int sigprocmask() { 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() int main()
{ {
/* look for dynamic linker */ int argc = 3;
Dataspace_capability ldso_ds; const char *argv[] = { "gdbserver", "/dev/terminal", "target", 0 };
try {
Rom_connection ldso_rom("ld.lib.so");
ldso_ds = clone_rom(ldso_rom.dataspace());
} catch (...) {
PDBG("ld.lib.so not found");
}
/* extract target filename from config file */ return gdbserver_main(argc, argv);
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;
} }

View File

@ -18,9 +18,15 @@
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <pd_session/connection.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: private:
@ -41,9 +47,9 @@ class Pd_session_component : public Rpc_object<Pd_session>
Dataspace_pool &managed_ds_map) Dataspace_pool &managed_ds_map)
: :
_ep(ep), _pd(binary_name), _ep(ep), _pd(binary_name),
_address_space(_ep, managed_ds_map, _pd.address_space()), _address_space(_ep, managed_ds_map, _pd, _pd.address_space()),
_stack_area (_ep, managed_ds_map, _pd.stack_area()), _stack_area (_ep, managed_ds_map, _pd, _pd.stack_area()),
_linker_area (_ep, managed_ds_map, _pd.linker_area()) _linker_area (_ep, managed_ds_map, _pd, _pd.linker_area())
{ {
_ep.manage(this); _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 * space
*/ */
Region_map_component &region_map() { return _address_space; } Region_map_component &region_map() { return _address_space; }
Pd_session_capability core_pd_cap() { return _pd.cap(); }
/************************** /**************************
** Pd_session interface ** ** 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -18,31 +18,30 @@
#include "ram_session_component.h" #include "ram_session_component.h"
namespace Genode { namespace Gdb_monitor { class Ram_root; }
class Ram_root : public Root_component<Ram_session_component> class Gdb_monitor::Ram_root : public Root_component<Ram_session_component>
{ {
protected: protected:
Ram_session_component *_create_session(const char *args) Ram_session_component *_create_session(const char *args)
{ {
return new (md_alloc()) return new (md_alloc())
Ram_session_component(args); Ram_session_component(args);
} }
public: public:
/** /**
* Constructor * Constructor
* *
* \param session_ep entry point for managing ram session objects * \param session_ep entry point for managing ram session objects
* \param md_alloc meta-data allocator to be used by root component * \param md_alloc meta-data allocator to be used by root component
*/ */
Ram_root(Rpc_entrypoint *session_ep, Ram_root(Rpc_entrypoint *session_ep,
Allocator *md_alloc) Allocator *md_alloc)
: Root_component<Ram_session_component>(session_ep, md_alloc) : Root_component<Ram_session_component>(session_ep, md_alloc)
{ } { }
}; };
}
#endif /* _RAM_ROOT_H_ */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -18,7 +18,7 @@
#include "ram_session_component.h" #include "ram_session_component.h"
using namespace Genode; using namespace Genode;
using namespace Gdb_monitor;
Ram_session_component::Ram_session_component(const char *args) Ram_session_component::Ram_session_component(const char *args)
: _parent_ram_session(env()->parent()->session<Ram_session>(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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -18,9 +18,13 @@
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <ram_session/client.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: 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -15,19 +15,19 @@
#include <base/env.h> #include <base/env.h>
#include <base/printf.h> #include <base/printf.h>
#include <dataspace/client.h> #include <dataspace/client.h>
#include <util/retry.h>
/* local includes */ /* local includes */
#include "region_map_component.h" #include "region_map_component.h"
static bool const verbose = false; static bool const verbose = false;
using namespace Gdb_monitor;
using namespace Genode;
/**************************************
/**************************
** Region map component ** ** Region map component **
**************************/ **************************************/
using namespace Gdb_monitor;
Region_map_component::Region *Region_map_component::find_region(void *local_addr, addr_t *offset_in_region) 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, Region_map_component::Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map, Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map) Capability<Region_map> parent_region_map)
: :
_ep(ep), _ep(ep),
_pd(pd),
_parent_region_map(parent_region_map), _parent_region_map(parent_region_map),
_managed_ds_map(managed_ds_map) _managed_ds_map(managed_ds_map)
{ {
_ep.manage(this); _ep.manage(this);
if (verbose) if (verbose)
PDBG("Region_map_component()"); 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -16,8 +16,9 @@
#define _REGION_MAP_COMPONENT_H_ #define _REGION_MAP_COMPONENT_H_
/* Genode includes */ /* Genode includes */
#include <region_map/client.h>
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <pd_session/capability.h>
#include <region_map/client.h>
/* GDB monitor includes */ /* GDB monitor includes */
#include "dataspace_object.h" #include "dataspace_object.h"
@ -32,6 +33,8 @@ namespace Gdb_monitor {
Rpc_entrypoint &_ep; Rpc_entrypoint &_ep;
Pd_session_capability _pd;
Genode::Region_map_client _parent_region_map; Genode::Region_map_client _parent_region_map;
public: public:
@ -75,8 +78,9 @@ namespace Gdb_monitor {
/** /**
* Constructor * Constructor
*/ */
Region_map_component(Rpc_entrypoint &ep, Region_map_component(Rpc_entrypoint &ep,
Dataspace_pool &managed_ds_map, Dataspace_pool &managed_ds_map,
Pd_session_capability pd,
Capability<Region_map> parent_region_map); Capability<Region_map> parent_region_map);
~Region_map_component(); ~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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -16,111 +16,118 @@
/* Genode includes */ /* Genode includes */
#include <base/service.h> #include <base/service.h>
#include <dataspace/client.h>
#include <root/component.h> #include <root/component.h>
#include <rom_session/client.h> #include <rom_session/connection.h>
#include <util/arg_string.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; 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_ */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * 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" #include "signal_handler_thread.h"
using namespace Genode; using namespace Genode;
using namespace Gdb_monitor; using namespace Gdb_monitor;
static bool const verbose = false;
Signal_handler_thread::Signal_handler_thread(Signal_receiver *receiver) Signal_handler_thread::Signal_handler_thread(Signal_receiver *receiver)
: :
Thread_deprecated<2*4096>("sig_handler"), Thread_deprecated<SIGNAL_HANDLER_THREAD_STACK_SIZE>("sig_handler"),
_signal_receiver(receiver) _signal_receiver(receiver) { }
{
if (pipe(_pipefd))
PERR("could not create pipe");
}
void Signal_handler_thread::entry() void Signal_handler_thread::entry()
@ -42,18 +27,9 @@ void Signal_handler_thread::entry()
while(1) { while(1) {
Signal s = _signal_receiver->wait_for_signal(); Signal s = _signal_receiver->wait_for_signal();
if (verbose) Signal_dispatcher_base *signal_dispatcher =
PDBG("received exception signal"); dynamic_cast<Signal_dispatcher_base*>(s.context());
/* default is segmentation fault */ signal_dispatcher->dispatch(s.num());
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));
} }
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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -21,18 +21,19 @@ using namespace Genode;
namespace Gdb_monitor { 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: private:
int _pipefd[2];
Signal_receiver *_signal_receiver; Signal_receiver *_signal_receiver;
public: public:
Signal_handler_thread(Signal_receiver *receiver); Signal_handler_thread(Signal_receiver *receiver);
void entry(); 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 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 CC_OPT_linux-low += -Wno-unused-function
SRC_CC = genode-low.cc \ SRC_CC = genode-low.cc \
gdb_stub_thread.cc \
cpu_session_component.cc \ cpu_session_component.cc \
cpu_thread_component.cc \
ram_session_component.cc \ ram_session_component.cc \
region_map_component.cc \ region_map_component.cc \
signal_handler_thread.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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -29,8 +29,4 @@ struct user {
unsigned long int u_debugreg [8]; unsigned long int u_debugreg [8];
}; };
/* Missing in libc's sys/wait.h */
#define __WCLONE 0
#endif /* GDBSERVER_LIBC_DUMMIES_H */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -20,18 +20,23 @@
#include <gdbserver_libc_support.h> #include <gdbserver_libc_support.h>
enum __ptrace_request { enum __ptrace_request {
PTRACE_TRACEME, PTRACE_TRACEME = 0,
PTRACE_ATTACH, PTRACE_PEEKTEXT = 1,
PTRACE_KILL, PTRACE_PEEKUSER = 3,
PTRACE_DETACH, PTRACE_POKETEXT = 4,
PTRACE_SINGLESTEP, PTRACE_POKEUSER = 6,
PTRACE_CONT, PTRACE_CONT = 7,
PTRACE_PEEKTEXT, PTRACE_KILL = 8,
PTRACE_POKETEXT, PTRACE_SINGLESTEP = 9,
PTRACE_PEEKUSER, PTRACE_GETREGS = 12,
PTRACE_POKEUSER, PTRACE_SETREGS = 13,
PTRACE_GETREGS, PTRACE_ATTACH = 16,
PTRACE_SETREGS, PTRACE_DETACH = 17,
PTRACE_EVENT_CLONE = 3,
PTRACE_GETEVENTMSG = 0x4201,
PTRACE_GETREGSET = 0x4204,
}; };
extern long ptrace(enum __ptrace_request request, ...); 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -22,16 +22,20 @@ extern "C" {
#include <cpu_thread/client.h> #include <cpu_thread/client.h>
#include "cpu_session_component.h" #include "cpu_session_component.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
using namespace Genode; using namespace Genode;
using namespace Gdb_monitor; 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() 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; ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id;
@ -40,9 +44,10 @@ Thread_state get_current_thread_state()
return cpu_thread.state(); return cpu_thread.state();
} }
void set_current_thread_state(Thread_state 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; 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); 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * 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 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 */ #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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -22,107 +22,124 @@ extern "C" {
#include "reg-arm.h" #include "reg-arm.h"
#include "gdbserver_platform_helper.h" #include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
#undef PDBG
#define PDBG(...)
using namespace Genode; using namespace Genode;
static bool in_syscall(Thread_state const &thread_state) static bool in_syscall(Thread_state const &ts)
{ {
/* looking for syscall pattern: try {
* (PC-8: e1a0e00f mov lr, pc) /* looking for syscall pattern:
* PC-4: e3e0f00b mvn pc, #11 * (PC-8: e1a0e00f mov lr, pc)
* (PC: e1a02004 mov r2, r4) * 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) && if ((genode_read_memory_byte((void*)(ts.ip - 1)) == 0xe3) &&
(genode_read_memory_byte((void*)(thread_state.ip - 3)) == 0xf0) && (genode_read_memory_byte((void*)(ts.ip - 2)) == 0xe0) &&
(genode_read_memory_byte((void*)(thread_state.ip - 4)) == 0x0b)) (genode_read_memory_byte((void*)(ts.ip - 3)) == 0xf0) &&
return true; (genode_read_memory_byte((void*)(ts.ip - 4)) == 0x0b))
return true;
} catch (No_memory_at_address) {
return false;
}
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(); } try { ts = get_current_thread_state(); }
catch (...) { return 0; } 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) switch((enum reg_index)regno)
{ {
case R0: PDBG("cannot determine contents of register R0"); return -1; case R0: cannot_fetch_register("R0"); return -1;
case R1: PDBG("cannot determine contents of register R1"); return -1; case R1: cannot_fetch_register("R1"); return -1;
case R2: PDBG("cannot determine contents of register R2"); return -1; case R2: cannot_fetch_register("R2"); return -1;
case R3: PDBG("cannot determine contents of register R3"); return -1; case R3: cannot_fetch_register("R3"); return -1;
case R4: PDBG("cannot determine contents of register R4"); return -1; case R4: cannot_fetch_register("R4"); return -1;
case R5: PDBG("cannot determine contents of register R5"); return -1; case R5: cannot_fetch_register("R5"); return -1;
case R6: PDBG("cannot determine contents of register R6"); return -1; case R6: cannot_fetch_register("R6"); return -1;
case R7: PDBG("cannot determine contents of register R7"); return -1; case R7: cannot_fetch_register("R7"); return -1;
case R8: PDBG("cannot determine contents of register R8"); return -1; case R8: cannot_fetch_register("R8"); return -1;
case R9: PDBG("cannot determine contents of register R9"); return -1; case R9: cannot_fetch_register("R9"); return -1;
case R10: PDBG("cannot determine contents of register R10"); return -1; case R10: cannot_fetch_register("R10"); return -1;
case R11: case R11:
if (in_syscall(thread_state)) {
if (in_syscall(ts)) {
/* R11 can be calculated from SP. The offset can be found in /* R11 can be calculated from SP. The offset can be found in
* the disassembled 'Fiasco::l4_ipc()' function: * the disassembled 'Fiasco::l4_ipc()' function:
* add r11, sp, #8 -> r11 = sp + 8 * add r11, sp, #8 -> r11 = sp + 8
* sub sp, sp, #20 -> r11 = (sp + 20) + 8 * sub sp, sp, #20 -> r11 = (sp + 20) + 8
*/ */
*reg_content = (thread_state.sp + 20) + 8; *value = (ts.sp + 20) + 8;
PDBG("FP = %8lx", *reg_content);
/* for the debug output, if enabled */
fetch_register("R11", *value, *value);
return 0; return 0;
} else { } 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 R12: cannot_fetch_register("R12"); return -1;
case LR: PDBG("cannot determine contents of register LR"); return -1; case SP: fetch_register("SP ", ts.sp, *value); return 0;
case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0; case LR: cannot_fetch_register("LR"); return -1;
case F0: PDBG("cannot determine contents of register F0"); return -1; case PC: fetch_register("PC ", ts.ip, *value); return 0;
case F1: PDBG("cannot determine contents of register F1"); return -1; case F0: cannot_fetch_register("F0"); return -1;
case F2: PDBG("cannot determine contents of register F2"); return -1; case F1: cannot_fetch_register("F1"); return -1;
case F3: PDBG("cannot determine contents of register F3"); return -1; case F2: cannot_fetch_register("F2"); return -1;
case F4: PDBG("cannot determine contents of register F4"); return -1; case F3: cannot_fetch_register("F3"); return -1;
case F5: PDBG("cannot determine contents of register F5"); return -1; case F4: cannot_fetch_register("F4"); return -1;
case F6: PDBG("cannot determine contents of register F6"); return -1; case F5: cannot_fetch_register("F5"); return -1;
case F7: PDBG("cannot determine contents of register F7"); return -1; case F6: cannot_fetch_register("F6"); return -1;
case FPS: PDBG("cannot determine contents of register FPS"); return -1; case F7: cannot_fetch_register("F7"); return -1;
case CPSR: PDBG("cannot determine contents of register CPSR"); 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 { } else {
switch((enum reg_index)regno) switch((enum reg_index)regno)
{ {
case R0: *reg_content = thread_state.r0; PDBG("R0 = %8lx", *reg_content); return 0; case R0: fetch_register("R0 ", ts.r0, *value); return 0;
case R1: *reg_content = thread_state.r1; PDBG("R1 = %8lx", *reg_content); return 0; case R1: fetch_register("R1 ", ts.r1, *value); return 0;
case R2: *reg_content = thread_state.r2; PDBG("R2 = %8lx", *reg_content); return 0; case R2: fetch_register("R2 ", ts.r2, *value); return 0;
case R3: *reg_content = thread_state.r3; PDBG("R3 = %8lx", *reg_content); return 0; case R3: fetch_register("R3 ", ts.r3, *value); return 0;
case R4: *reg_content = thread_state.r4; PDBG("R4 = %8lx", *reg_content); return 0; case R4: fetch_register("R4 ", ts.r4, *value); return 0;
case R5: *reg_content = thread_state.r5; PDBG("R5 = %8lx", *reg_content); return 0; case R5: fetch_register("R5 ", ts.r5, *value); return 0;
case R6: *reg_content = thread_state.r6; PDBG("R6 = %8lx", *reg_content); return 0; case R6: fetch_register("R6 ", ts.r6, *value); return 0;
case R7: *reg_content = thread_state.r7; PDBG("R7 = %8lx", *reg_content); return 0; case R7: fetch_register("R7 ", ts.r7, *value); return 0;
case R8: *reg_content = thread_state.r8; PDBG("R8 = %8lx", *reg_content); return 0; case R8: fetch_register("R8 ", ts.r8, *value); return 0;
case R9: *reg_content = thread_state.r9; PDBG("R9 = %8lx", *reg_content); return 0; case R9: fetch_register("R9 ", ts.r9, *value); return 0;
case R10: *reg_content = thread_state.r10; PDBG("R10 = %8lx", *reg_content); return 0; case R10: fetch_register("R10 ", ts.r10, *value); return 0;
case R11: *reg_content = thread_state.r11; PDBG("FP = %8lx", *reg_content); return 0; case R11: fetch_register("R11 ", ts.r11, *value); return 0;
case R12: *reg_content = thread_state.r12; PDBG("R12 = %8lx", *reg_content); return 0; case R12: fetch_register("R12 ", ts.r12, *value); return 0;
case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0; case SP: fetch_register("SP ", ts.sp, *value); return 0;
case LR: *reg_content = thread_state.lr; PDBG("LR = %8lx", *reg_content); return 0; case LR: fetch_register("LR ", ts.lr, *value); return 0;
case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0; case PC: fetch_register("PC ", ts.ip, *value); return 0;
case F0: PDBG("cannot determine contents of register F0"); return -1; case F0: cannot_fetch_register("F0"); return -1;
case F1: PDBG("cannot determine contents of register F1"); return -1; case F1: cannot_fetch_register("F1"); return -1;
case F2: PDBG("cannot determine contents of register F2"); return -1; case F2: cannot_fetch_register("F2"); return -1;
case F3: PDBG("cannot determine contents of register F3"); return -1; case F3: cannot_fetch_register("F3"); return -1;
case F4: PDBG("cannot determine contents of register F4"); return -1; case F4: cannot_fetch_register("F4"); return -1;
case F5: PDBG("cannot determine contents of register F5"); return -1; case F5: cannot_fetch_register("F5"); return -1;
case F6: PDBG("cannot determine contents of register F6"); return -1; case F6: cannot_fetch_register("F6"); return -1;
case F7: PDBG("cannot determine contents of register F7"); return -1; case F7: cannot_fetch_register("F7"); return -1;
case FPS: PDBG("cannot determine contents of register FPS"); return -1; case FPS: cannot_fetch_register("FPS"); return -1;
case CPSR: *reg_content = thread_state.cpsr; PDBG("CPSR = %8lx", *reg_content); return 0; 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(); } try { ts = get_current_thread_state(); }
catch (...) { return; } 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"); PDBG("cannot set registers while thread is in syscall");
return; return;
} }
switch((enum reg_index)regno) switch((enum reg_index)regno)
{ {
case R0: thread_state.r0 = reg_content; PDBG("R0 = %8lx", reg_content); break; case R0: if (!store_register("R0 ", ts.r0, value)) return; break;
case R1: thread_state.r1 = reg_content; PDBG("R1 = %8lx", reg_content); break; case R1: if (!store_register("R1 ", ts.r1, value)) return; break;
case R2: thread_state.r2 = reg_content; PDBG("R2 = %8lx", reg_content); break; case R2: if (!store_register("R2 ", ts.r2, value)) return; break;
case R3: thread_state.r3 = reg_content; PDBG("R3 = %8lx", reg_content); break; case R3: if (!store_register("R3 ", ts.r3, value)) return; break;
case R4: thread_state.r4 = reg_content; PDBG("R4 = %8lx", reg_content); break; case R4: if (!store_register("R4 ", ts.r4, value)) return; break;
case R5: thread_state.r5 = reg_content; PDBG("R5 = %8lx", reg_content); break; case R5: if (!store_register("R5 ", ts.r5, value)) return; break;
case R6: thread_state.r6 = reg_content; PDBG("R6 = %8lx", reg_content); break; case R6: if (!store_register("R6 ", ts.r6, value)) return; break;
case R7: thread_state.r7 = reg_content; PDBG("R7 = %8lx", reg_content); break; case R7: if (!store_register("R7 ", ts.r7, value)) return; break;
case R8: thread_state.r8 = reg_content; PDBG("R8 = %8lx", reg_content); break; case R8: if (!store_register("R8 ", ts.r8, value)) return; break;
case R9: thread_state.r9 = reg_content; PDBG("R9 = %8lx", reg_content); break; case R9: if (!store_register("R9 ", ts.r9, value)) return; break;
case R10: thread_state.r10 = reg_content; PDBG("R10 = %8lx", reg_content); break; case R10: if (!store_register("R10 ", ts.r10, value)) return; break;
case R11: thread_state.r11 = reg_content; PDBG("FP = %8lx", reg_content); break; case R11: if (!store_register("R11 ", ts.r11, value)) return; break;
case R12: thread_state.r12 = reg_content; PDBG("R12 = %8lx", reg_content); break; case R12: if (!store_register("R12 ", ts.r12, value)) return; break;
case SP: thread_state.sp = reg_content; PDBG("SP = %8lx", reg_content); break; case SP: if (!store_register("SP ", ts.sp, value)) return; break;
case LR: thread_state.lr = reg_content; PDBG("LR = %8lx", reg_content); break; case LR: if (!store_register("LR ", ts.lr, value)) return; break;
case PC: thread_state.ip = reg_content; PDBG("PC = %8lx", reg_content); break; case PC: if (!store_register("PC ", ts.ip, value)) return; break;
case F0: PDBG("cannot set contents of register F0"); break; case F0: cannot_store_register("F0 ", value); return;
case F1: PDBG("cannot set contents of register F1"); break; case F1: cannot_store_register("F1 ", value); return;
case F2: PDBG("cannot set contents of register F2"); break; case F2: cannot_store_register("F2 ", value); return;
case F3: PDBG("cannot set contents of register F3"); break; case F3: cannot_store_register("F3 ", value); return;
case F4: PDBG("cannot set contents of register F4"); break; case F4: cannot_store_register("F4 ", value); return;
case F5: PDBG("cannot set contents of register F5"); break; case F5: cannot_store_register("F5 ", value); return;
case F6: PDBG("cannot set contents of register F6"); break; case F6: cannot_store_register("F6 ", value); return;
case F7: PDBG("cannot set contents of register F7"); break; case F7: cannot_store_register("F7 ", value); return;
case FPS: PDBG("cannot set contents of register FPS"); break; case FPS: cannot_store_register("FPS", value); return;
case CPSR: thread_state.cpsr = reg_content; PDBG("CPSR = %8lx", reg_content); break; 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -21,10 +21,7 @@ extern "C" {
#include "i386.h" #include "i386.h"
#include "cpu_session_component.h" #include "cpu_session_component.h"
#include "gdbserver_platform_helper.h" #include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
#undef PDBG
#define PDBG(...)
using namespace Genode; using namespace Genode;
@ -44,113 +41,146 @@ static bool in_syscall(Thread_state const &thread_state)
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(); } try { ts = get_current_thread_state(); }
catch (...) { return 0; } 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) switch((enum reg_index)regno)
{ {
case EAX: PDBG("cannot determine contents of register EAX"); return -1; case EAX: cannot_fetch_register("EAX"); return -1;
case ECX: PDBG("cannot determine contents of register ECX"); return -1; case ECX: cannot_fetch_register("ECX"); return -1;
case EDX: PDBG("cannot determine contents of register EDX"); return -1; case EDX: cannot_fetch_register("EDX"); return -1;
case EBX: 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 */ /* 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)) + *value = genode_read_memory_byte((void*)(ts.sp + 4))
(genode_read_memory_byte((void*)(thread_state.sp + 5)) << 8) + + (genode_read_memory_byte((void*)(ts.sp + 5)) << 8)
(genode_read_memory_byte((void*)(thread_state.sp + 6)) << 16) + + (genode_read_memory_byte((void*)(ts.sp + 6)) << 16)
(genode_read_memory_byte((void*)(thread_state.sp + 7)) << 24); + (genode_read_memory_byte((void*)(ts.sp + 7)) << 24);
PDBG("EBX = %8lx", *reg_content);
/* for the debug output, if enabled */
fetch_register("EBX", *value, *value);
return 0; return 0;
} else { } 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: 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 */ /* 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)) + *value = genode_read_memory_byte((void*)(ts.sp + 0))
(genode_read_memory_byte((void*)(thread_state.sp + 1)) << 8) + + (genode_read_memory_byte((void*)(ts.sp + 1)) << 8)
(genode_read_memory_byte((void*)(thread_state.sp + 2)) << 16) + + (genode_read_memory_byte((void*)(ts.sp + 2)) << 16)
(genode_read_memory_byte((void*)(thread_state.sp + 3)) << 24); + (genode_read_memory_byte((void*)(ts.sp + 3)) << 24);
PDBG("EBP = %8lx", *reg_content);
/* for the debug output, if enabled */
fetch_register("EBP", *value, *value);
return 0; return 0;
} else { } 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 ESI: cannot_fetch_register("ESI"); return -1;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0; case EDI: cannot_fetch_register("EDI"); return -1;
case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1; case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case CS: PDBG("cannot determine contents of register CS"); return -1; case EFL: cannot_fetch_register("EFL"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1; case CS: cannot_fetch_register("CS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1; case SS: cannot_fetch_register("SS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1; case DS: cannot_fetch_register("DS"); return -1;
case FS: PDBG("cannot determine contents of register FS"); return -1; case ES: cannot_fetch_register("ES"); return -1;
case GS: PDBG("cannot determine contents of register GS"); 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 { } else {
switch((enum reg_index)regno) switch((enum reg_index)regno)
{ {
case EAX: *reg_content = thread_state.eax; PDBG("EAX = %8lx", *reg_content); return 0; case EAX: fetch_register("EAX", ts.eax, *value); return 0;
case ECX: *reg_content = thread_state.ecx; PDBG("ECX = %8lx", *reg_content); return 0; case ECX: fetch_register("ECX", ts.ecx, *value); return 0;
case EDX: *reg_content = thread_state.edx; PDBG("EDX = %8lx", *reg_content); return 0; case EDX: fetch_register("EDX", ts.edx, *value); return 0;
case EBX: *reg_content = thread_state.ebx; PDBG("EBX = %8lx", *reg_content); return 0; case EBX: fetch_register("EBX", ts.ebx, *value); return 0;
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: *reg_content = thread_state.ebp; PDBG("EBP = %8lx", *reg_content); return 0; case EBP: fetch_register("EBP", ts.ebp, *value); return 0;
case ESI: *reg_content = thread_state.esi; PDBG("ESI = %8lx", *reg_content); return 0; case ESI: fetch_register("ESI", ts.esi, *value); return 0;
case EDI: *reg_content = thread_state.edi; PDBG("EDI = %8lx", *reg_content); return 0; case EDI: fetch_register("EDI", ts.edi, *value); return 0;
case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0; case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case EFL: *reg_content = thread_state.eflags; PDBG("EFLAGS = %8lx", *reg_content); return 0; case EFL: fetch_register("EFL", ts.eflags, *value); return 0;
case CS: PDBG("cannot determine contents of register CS"); return -1; case CS: cannot_fetch_register("CS"); return -1;
case SS: PDBG("cannot determine contents of register SS"); return -1; case SS: cannot_fetch_register("SS"); return -1;
case DS: PDBG("cannot determine contents of register DS"); return -1; case DS: cannot_fetch_register("DS"); return -1;
case ES: PDBG("cannot determine contents of register ES"); return -1; case ES: cannot_fetch_register("ES"); return -1;
case FS: *reg_content = thread_state.fs; PDBG("FS = %8lx", *reg_content); return 0; case FS: fetch_register("FS", ts.fs, *value); return 0;
case GS: *reg_content = thread_state.gs; PDBG("GS = %8lx", *reg_content); return 0; case GS: fetch_register("GS", ts.gs, *value); return 0;
default: PERR("unhandled register %d", regno); return -1;
} }
} }
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(); } try { ts = get_current_thread_state(); }
catch (...) { return; } 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"); PDBG("cannot set registers while thread is in syscall");
return; return;
} }
switch((enum reg_index)regno) switch((enum reg_index)regno)
{ {
case EAX: thread_state.eax = reg_content; PDBG("EAX = %8lx", reg_content); break; case EAX: if (!store_register("EAX", ts.eax, value)) return; break;
case ECX: thread_state.ecx = reg_content; PDBG("ECX = %8lx", reg_content); break; case ECX: if (!store_register("ECX", ts.ecx, value)) return; break;
case EDX: thread_state.edx = reg_content; PDBG("EDX = %8lx", reg_content); break; case EDX: if (!store_register("EDX", ts.edx, value)) return; break;
case EBX: thread_state.ebx = reg_content; PDBG("EBX = %8lx", reg_content); break; case EBX: if (!store_register("EBX", ts.ebx, value)) return; break;
case UESP: thread_state.sp = reg_content; PDBG("ESP = %8lx", reg_content); break; case UESP: if (!store_register("ESP", ts.sp, value)) return; break;
case EBP: thread_state.ebp = reg_content; PDBG("EBP = %8lx", reg_content); break; case EBP: if (!store_register("EBP", ts.ebp, value)) return; break;
case ESI: thread_state.esi = reg_content; PDBG("ESI = %8lx", reg_content); break; case ESI: if (!store_register("ESI", ts.esi, value)) return; break;
case EDI: thread_state.edi = reg_content; PDBG("EDI = %8lx", reg_content); break; case EDI: if (!store_register("EDI", ts.edi, value)) return; break;
case EIP: thread_state.ip = reg_content; PDBG("EIP = %8lx", reg_content); break; case EIP: if (!store_register("EIP", ts.ip, value)) return; break;
case EFL: thread_state.eflags = reg_content; PDBG("EFL = %8lx", reg_content); break; case EFL: if (!store_register("EFL", ts.eflags, value)) return; break;
case CS: PDBG("cannot set contents of register CS"); PDBG(" CS = %8lx", reg_content); break; case CS: cannot_store_register("CS", value); return;
case SS: PDBG("cannot set contents of register SS"); PDBG(" SS = %8lx", reg_content); break; case SS: cannot_store_register("SS", value); return;
case DS: PDBG("cannot set contents of register DS"); PDBG(" DS = %8lx", reg_content); break; case DS: cannot_store_register("DS", value); return;
case ES: PDBG("cannot set contents of register ES"); PDBG(" ES = %8lx", reg_content); break; case ES: cannot_store_register("ES", value); return;
case FS: thread_state.fs = reg_content; PDBG(" FS = %8lx", reg_content); break; case FS: if (!store_register("FS ", ts.fs, value)) return; break;
case GS: thread_state.gs = reg_content; PDBG(" GS = %8lx", reg_content); 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -14,43 +14,75 @@
#include "i386.h" #include "i386.h"
#include "cpu_session_component.h" #include "cpu_session_component.h"
#include "gdbserver_platform_helper.h" #include "gdbserver_platform_helper.h"
#include "gdb_stub_thread.h" #include "genode_child_resources.h"
using namespace Genode; 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(); } try { ts = get_current_thread_state(); }
catch (...) { return -1; } catch (...) {
PERR("%s: could not get current thread state", __PRETTY_FUNCTION__);
return -1;
}
switch((enum reg_index)regno) switch((enum reg_index)regno)
{ {
case EAX: *reg_content = thread_state.eax; return 0; case EAX: fetch_register("EAX", ts.eax, *value); return 0;
case ECX: *reg_content = thread_state.ecx; return 0; case ECX: fetch_register("ECX", ts.ecx, *value); return 0;
case EDX: *reg_content = thread_state.edx; return 0; case EDX: fetch_register("EDX", ts.edx, *value); return 0;
case EBX: *reg_content = thread_state.ebx; return 0; case EBX: fetch_register("EBX", ts.ebx, *value); return 0;
case UESP: *reg_content = thread_state.sp; return 0; case UESP: fetch_register("ESP", ts.sp, *value); return 0;
case EBP: *reg_content = thread_state.ebp; return 0; case EBP: fetch_register("EBP", ts.ebp, *value); return 0;
case ESI: *reg_content = thread_state.esi; return 0; case ESI: fetch_register("ESI", ts.esi, *value); return 0;
case EDI: *reg_content = thread_state.edi; return 0; case EDI: fetch_register("EDI", ts.edi, *value); return 0;
case EIP: *reg_content = thread_state.ip; return 0; case EIP: fetch_register("EIP", ts.ip, *value); return 0;
case EFL: *reg_content = thread_state.eflags; return 0; case EFL: fetch_register("EFL", ts.eflags, *value); return 0;
case CS: return -1; case CS: cannot_fetch_register("CS"); return -1;
case SS: return -1; case SS: cannot_fetch_register("SS"); return -1;
case DS: return -1; case DS: cannot_fetch_register("DS"); return -1;
case ES: return -1; case ES: cannot_fetch_register("ES"); return -1;
case FS: *reg_content = thread_state.fs; return 0; case FS: cannot_fetch_register("FS"); return -1;
case GS: *reg_content = thread_state.gs; return 0; case GS: cannot_fetch_register("GS"); return -1;
default: PERR("unhandled register %d", regno); return -1;
} }
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") { } Test_thread() : Thread_deprecated("test") { }
void func() void step_func()
{
/* nothing */
}
void sigsegv_func()
{ {
/* /*
* make sure that the main thread is sleeping in * 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 */ void entry() /* set a breakpoint here to test the 'info threads' command */
{ {
func(); step_func();
sigsegv_func();
Genode::sleep_forever(); Genode::sleep_forever();
} }

View File

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