From 5842b2065e06ecc1ee88847ea7b74b1b7024d334 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Tue, 17 May 2016 16:13:23 +0200 Subject: [PATCH] GDB monitor: stability improvements Fixes #1969 --- repos/ports/doc/gdb.txt | 2 +- repos/ports/lib/mk/gdbserver_libc_support.mk | 6 - .../mk/spec/fiasco_x86/gdbserver_platform.mk | 3 - .../lib/mk/spec/foc_arm/gdbserver_platform.mk | 4 +- .../mk/spec/foc_x86_32/gdbserver_platform.mk | 3 +- .../spec/linux_x86_32/gdbserver_platform.mk | 3 - .../mk/spec/nova_x86_32/gdbserver_platform.mk | 3 +- .../mk/spec/okl4_x86/gdbserver_platform.mk | 3 - .../spec/pistachio_x86/gdbserver_platform.mk | 3 - repos/ports/ports/gdb.hash | 2 +- repos/ports/ports/gdb.port | 1 + repos/ports/run/debug_nitpicker.run | 6 +- repos/ports/run/gdb_monitor.inc | 11 +- repos/ports/run/gdb_monitor.run | 220 +++-- repos/ports/run/gdb_monitor_interactive.run | 8 +- repos/ports/run/gdb_monitor_target_config.run | 2 +- repos/ports/run/noux_gdb.run | 15 +- repos/ports/src/app/gdb_monitor/app_child.h | 535 ++++++----- repos/ports/src/app/gdb_monitor/cpu_root.h | 81 +- .../app/gdb_monitor/cpu_session_component.cc | 376 +++++--- .../app/gdb_monitor/cpu_session_component.h | 64 +- .../app/gdb_monitor/cpu_thread_component.cc | 151 +++ .../app/gdb_monitor/cpu_thread_component.h | 260 +++++ .../src/app/gdb_monitor/dataspace_object.h | 1 + .../src/app/gdb_monitor/gdb_stub_thread.cc | 40 - .../src/app/gdb_monitor/gdb_stub_thread.h | 61 -- .../src/app/gdb_monitor/gdbserver/config.h | 4 +- .../app/gdb_monitor/gdbserver/genode-low.cc | 603 +++++++++--- .../app/gdb_monitor/gdbserver/genode-low.h | 26 +- .../app/gdb_monitor/gdbserver_genode.patch | 899 ++++++------------ .../app/gdb_monitor/genode_child_resources.h | 46 + repos/ports/src/app/gdb_monitor/main.cc | 114 +-- .../app/gdb_monitor/pd_session_component.h | 19 +- repos/ports/src/app/gdb_monitor/ram_root.h | 45 +- .../app/gdb_monitor/ram_session_component.cc | 4 +- .../app/gdb_monitor/ram_session_component.h | 10 +- .../app/gdb_monitor/region_map_component.cc | 15 +- .../app/gdb_monitor/region_map_component.h | 12 +- repos/ports/src/app/gdb_monitor/rom.h | 209 ++-- repos/ports/src/app/gdb_monitor/siginfo.patch | 279 ++++++ .../app/gdb_monitor/signal_handler_thread.cc | 36 +- .../app/gdb_monitor/signal_handler_thread.h | 9 +- repos/ports/src/app/gdb_monitor/target.mk | 4 +- repos/ports/src/app/gdb_monitor/thread_info.h | 43 - .../gdbserver_libc_support.c | 43 - .../gdbserver_libc_support.h | 6 +- .../lib/gdbserver_libc_support/sys/ptrace.h | 31 +- .../src/lib/gdbserver_libc_support/sys/wait.h | 37 + .../gdbserver_platform_helper.cc | 55 +- .../gdbserver_platform_helper.h | 14 +- .../gdbserver_platform/spec/fiasco_x86/low.cc | 82 -- .../gdbserver_platform/spec/foc/native_cpu.cc | 90 ++ .../gdbserver_platform/spec/foc_arm/low.cc | 238 ++--- .../gdbserver_platform/spec/foc_x86_32/low.cc | 184 ++-- .../spec/linux_x86_32/low.cc | 63 -- .../spec/nova/native_cpu.cc | 79 ++ .../spec/nova_x86_32/low.cc | 82 +- .../gdbserver_platform/spec/okl4_x86/low.cc | 82 -- .../spec/pistachio_x86/low.cc | 84 -- repos/ports/src/test/gdb_monitor/main.cc | 11 +- repos/ports/src/test/gdb_monitor/target.mk | 2 + 61 files changed, 3064 insertions(+), 2360 deletions(-) delete mode 100644 repos/ports/lib/mk/spec/fiasco_x86/gdbserver_platform.mk delete mode 100644 repos/ports/lib/mk/spec/linux_x86_32/gdbserver_platform.mk delete mode 100644 repos/ports/lib/mk/spec/okl4_x86/gdbserver_platform.mk delete mode 100644 repos/ports/lib/mk/spec/pistachio_x86/gdbserver_platform.mk create mode 100644 repos/ports/src/app/gdb_monitor/cpu_thread_component.cc create mode 100644 repos/ports/src/app/gdb_monitor/cpu_thread_component.h delete mode 100644 repos/ports/src/app/gdb_monitor/gdb_stub_thread.cc delete mode 100644 repos/ports/src/app/gdb_monitor/gdb_stub_thread.h create mode 100644 repos/ports/src/app/gdb_monitor/genode_child_resources.h create mode 100644 repos/ports/src/app/gdb_monitor/siginfo.patch delete mode 100644 repos/ports/src/app/gdb_monitor/thread_info.h delete mode 100644 repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.c create mode 100644 repos/ports/src/lib/gdbserver_libc_support/sys/wait.h delete mode 100644 repos/ports/src/lib/gdbserver_platform/spec/fiasco_x86/low.cc create mode 100644 repos/ports/src/lib/gdbserver_platform/spec/foc/native_cpu.cc delete mode 100644 repos/ports/src/lib/gdbserver_platform/spec/linux_x86_32/low.cc create mode 100644 repos/ports/src/lib/gdbserver_platform/spec/nova/native_cpu.cc delete mode 100644 repos/ports/src/lib/gdbserver_platform/spec/okl4_x86/low.cc delete mode 100644 repos/ports/src/lib/gdbserver_platform/spec/pistachio_x86/low.cc diff --git a/repos/ports/doc/gdb.txt b/repos/ports/doc/gdb.txt index b8b5d908b..e2f06911a 100644 --- a/repos/ports/doc/gdb.txt +++ b/repos/ports/doc/gdb.txt @@ -256,7 +256,7 @@ via 'make run/gdb_monitor_interactive'. It will execute the scenario on Qemu and use the UART to communicate with GDB. Qemu is instructed to redirect the second serial interface to a local socket (using the port 5555): ! -serial chardev:uart -! -chardev socket,id=uart,port=5555,host=localhost,server,nowait +! -chardev socket,id=uart,port=5555,host=localhost,server,nowait,ipv4 The used TCP port is then specified to the GDB as remote target: ! target remote localhost:5555 diff --git a/repos/ports/lib/mk/gdbserver_libc_support.mk b/repos/ports/lib/mk/gdbserver_libc_support.mk index e52d76297..b716c6fa0 100644 --- a/repos/ports/lib/mk/gdbserver_libc_support.mk +++ b/repos/ports/lib/mk/gdbserver_libc_support.mk @@ -1,7 +1 @@ INC_DIR += $(REP_DIR)/src/lib/gdbserver_libc_support - -SRC_C += gdbserver_libc_support.c - -LIBS += libc - -vpath %.c $(REP_DIR)/src/lib/gdbserver_libc_support diff --git a/repos/ports/lib/mk/spec/fiasco_x86/gdbserver_platform.mk b/repos/ports/lib/mk/spec/fiasco_x86/gdbserver_platform.mk deleted file mode 100644 index a389462f5..000000000 --- a/repos/ports/lib/mk/spec/fiasco_x86/gdbserver_platform.mk +++ /dev/null @@ -1,3 +0,0 @@ -SRC_CC = spec/fiasco_x86/low.cc - -include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc diff --git a/repos/ports/lib/mk/spec/foc_arm/gdbserver_platform.mk b/repos/ports/lib/mk/spec/foc_arm/gdbserver_platform.mk index 87a74cea8..5ed1b416f 100644 --- a/repos/ports/lib/mk/spec/foc_arm/gdbserver_platform.mk +++ b/repos/ports/lib/mk/spec/foc_arm/gdbserver_platform.mk @@ -1,4 +1,6 @@ -SRC_CC = spec/foc_arm/low.cc +SRC_CC = spec/foc_arm/low.cc \ + spec/foc/native_cpu.cc + SRC_C = reg-arm.c \ linux-arm-low.c diff --git a/repos/ports/lib/mk/spec/foc_x86_32/gdbserver_platform.mk b/repos/ports/lib/mk/spec/foc_x86_32/gdbserver_platform.mk index 7d18946b4..7d91ae743 100644 --- a/repos/ports/lib/mk/spec/foc_x86_32/gdbserver_platform.mk +++ b/repos/ports/lib/mk/spec/foc_x86_32/gdbserver_platform.mk @@ -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 diff --git a/repos/ports/lib/mk/spec/linux_x86_32/gdbserver_platform.mk b/repos/ports/lib/mk/spec/linux_x86_32/gdbserver_platform.mk deleted file mode 100644 index ae562c4c4..000000000 --- a/repos/ports/lib/mk/spec/linux_x86_32/gdbserver_platform.mk +++ /dev/null @@ -1,3 +0,0 @@ -SRC_CC = spec/linux_x86_32/low.cc - -include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc diff --git a/repos/ports/lib/mk/spec/nova_x86_32/gdbserver_platform.mk b/repos/ports/lib/mk/spec/nova_x86_32/gdbserver_platform.mk index bc3fade94..e173570aa 100644 --- a/repos/ports/lib/mk/spec/nova_x86_32/gdbserver_platform.mk +++ b/repos/ports/lib/mk/spec/nova_x86_32/gdbserver_platform.mk @@ -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 diff --git a/repos/ports/lib/mk/spec/okl4_x86/gdbserver_platform.mk b/repos/ports/lib/mk/spec/okl4_x86/gdbserver_platform.mk deleted file mode 100644 index 129224ed9..000000000 --- a/repos/ports/lib/mk/spec/okl4_x86/gdbserver_platform.mk +++ /dev/null @@ -1,3 +0,0 @@ -SRC_CC = spec/okl4_x86/low.cc - -include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc diff --git a/repos/ports/lib/mk/spec/pistachio_x86/gdbserver_platform.mk b/repos/ports/lib/mk/spec/pistachio_x86/gdbserver_platform.mk deleted file mode 100644 index 27f9a0431..000000000 --- a/repos/ports/lib/mk/spec/pistachio_x86/gdbserver_platform.mk +++ /dev/null @@ -1,3 +0,0 @@ -SRC_CC = spec/pistachio_x86/low.cc - -include $(REP_DIR)/lib/mk/spec/x86_32/gdbserver_platform.inc diff --git a/repos/ports/ports/gdb.hash b/repos/ports/ports/gdb.hash index 8798b2eb2..0b9c4d66a 100644 --- a/repos/ports/ports/gdb.hash +++ b/repos/ports/ports/gdb.hash @@ -1 +1 @@ -ca63e9871478fe3c800d7be3a26a5c4093d38f69 +408b65147b4253d1ffa3d9ebd7b197df2a666261 diff --git a/repos/ports/ports/gdb.port b/repos/ports/ports/gdb.port index bfcbf6afa..95a84e825 100644 --- a/repos/ports/ports/gdb.port +++ b/repos/ports/ports/gdb.port @@ -11,6 +11,7 @@ DIR(gdb) := src/noux-pkg/gdb GENODE_DIR := $(REP_DIR)/../.. PATCHES_DIR := $(GENODE_DIR)/tool/patches/gdb-$(VERSION) PATCHES := $(addprefix $(PATCHES_DIR)/,$(shell cat $(PATCHES_DIR)/series)) \ + $(REP_DIR)/src/app/gdb_monitor/siginfo.patch \ $(REP_DIR)/src/app/gdb_monitor/gdbserver_genode.patch \ $(REP_DIR)/src/noux-pkg/gdb/build.patch PATCH_OPT := -p1 -d ${DIR(gdb)} diff --git a/repos/ports/run/debug_nitpicker.run b/repos/ports/run/debug_nitpicker.run index 1e16685b3..65535c152 100644 --- a/repos/ports/run/debug_nitpicker.run +++ b/repos/ports/run/debug_nitpicker.run @@ -143,14 +143,14 @@ append qemu_args " -serial mon:stdio " # connect comport 1 with TCP port $local_port append qemu_args " -serial chardev:uart " -append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait " +append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 " -run_genode_until {.*Remote debugging using /dev/terminal.*} 30 +run_genode_until {.*\[init -> gdb_monitor\].*} 30 puts "GDB monitor is up, starting GDB in a new terminal" exec [terminal] -e "[gdb] bin/nitpicker -ex \"target remote localhost:$local_port\"" & -interact +interact -i [output_spawn_id] # vi: set ft=tcl : diff --git a/repos/ports/run/gdb_monitor.inc b/repos/ports/run/gdb_monitor.inc index 5a59e9fd2..c02d8f1e2 100644 --- a/repos/ports/run/gdb_monitor.inc +++ b/repos/ports/run/gdb_monitor.inc @@ -19,20 +19,17 @@ proc gdb_main_breakpoint_cmds { target_binary_name } { # don't ask for y/n when loading a new symbol file append gdb_cmds {-ex "set interactive-mode off" } - # load the symbols of ld.lib.so - append gdb_cmds {-ex "symbol-file bin/ld.lib.so" } - - # set a breakpoint in the 'Linker::Binary::call_entry_point' function - append gdb_cmds {-ex "b Linker::Binary::call_entry_point" } + # set a breakpoint in the 'binary_ready_hook_for_gdb' function + append gdb_cmds {-ex "b binary_ready_hook_for_gdb" } # continue execution until the breakpoint triggers append gdb_cmds {-ex "c" } - # delete the 'call_program_main()' breakpoint + # delete the 'binary_ready_hook_for_gdb' breakpoint append gdb_cmds {-ex "delete 1" } # load the symbols of the test application - append gdb_cmds "-ex \"symbol-file bin/$target_binary_name\" " + append gdb_cmds "-ex \"file bin/$target_binary_name\" " # set a breakpoint in the application's 'main()' function append gdb_cmds {-ex "b main" } diff --git a/repos/ports/run/gdb_monitor.run b/repos/ports/run/gdb_monitor.run index 749065e74..089527eb7 100644 --- a/repos/ports/run/gdb_monitor.run +++ b/repos/ports/run/gdb_monitor.run @@ -6,8 +6,8 @@ # # -# Only Genode/Fiasco.OC and Genode/NOVA supports all the tested features -# at this time +# Only the 32-bit NOVA and Fiasco.OC base platforms support most of the tested features +# at this time. # if {![have_include "power_on/qemu"] || (![have_spec foc] && ![have_spec nova])} { @@ -50,11 +50,11 @@ set config { - + - + @@ -109,9 +109,9 @@ append qemu_args " -serial mon:stdio " # connect comport 1 with TCP port $local_port append qemu_args " -serial chardev:uart " -append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait " +append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 " -run_genode_until {.*Remote debugging using /dev/terminal.*} 30 +run_genode_until {.*\[init -> gdb_monitor\].*} 30 set genode_id [output_spawn_id] puts "GDB monitor is up, starting GDB" @@ -123,128 +123,164 @@ set gdb_target_binary "test-gdb_monitor" # sequence of GDB commands to execute at startup set gdb_cmds "" append gdb_cmds {-ex "target remote localhost:$local_port" } - append gdb_cmds [gdb_main_breakpoint_cmds $gdb_target_binary] -# -# Test commands -# +# run GDB and redirect stderr to stdio to get the relevant output into the expect buffer +eval spawn [gdb] bin/ld.lib.so -n $gdb_cmds 2&>1 +set gdb_id [list $spawn_id $genode_id] -# test: breakpoint in shared library -append gdb_cmds {-ex "b puts" } -append gdb_cmds {-ex "c" } +puts "" +puts "----- test: breakpoint in 'main()' -----" +puts "" -# test: stack trace when not in syscall -append gdb_cmds {-ex "bt" } +run_genode_until {\(gdb\)} 60 $gdb_id -# test: modify variable -append gdb_cmds {-ex "print test_var" } -append gdb_cmds {-ex "set var test_var=2" } -append gdb_cmds {-ex "print test_var" } - -# test: 'call' command -if {![have_spec nova]} { -append gdb_cmds {-ex "call test_var_func()" } -} - -# test: thread info -append gdb_cmds {-ex "b Test_thread::entry()" } -append gdb_cmds {-ex "c" } -append gdb_cmds {-ex "info threads" } - -# test: single stepping -append gdb_cmds {-ex "step" } - -# test: catch segmentation fault -append gdb_cmds {-ex "c" } - -# test: stack trace when in syscall -append gdb_cmds {-ex "thread 1" } -append gdb_cmds {-ex "bt" } - -# quit -append gdb_cmds {-ex "q" } - -# run GDB and redirect stderr to stdio to get the relevant output into the expect buffer -eval spawn [gdb] bin/$gdb_target_binary -n -batch $gdb_cmds 2&>1 -set gdb_id $spawn_id - -set timeout 120 -expect { - -i [list $genode_id $gdb_id] - timeout { puts stderr "Error: Test execution timed out"; exit -2 } -} - -set gdb_output $expect_out(buffer) - -# -# Evaluate the test results -# - -if {![regexp {Breakpoint 2, main ()} $gdb_output]} { - puts stderr "Error: Breakpoint in main() did not trigger" +if {![regexp {Breakpoint 2, main ()} $output]} { + puts stderr "*** Error: Breakpoint in main() did not trigger" exit -1 } -if {![regexp {Breakpoint 3, puts (.*)} $gdb_output]} { - puts "Error: Breakpoint in shared library did not trigger" +puts "\n" +puts "----- test: breakpoint in shared library -----" +puts "" + +send "b puts\n" +run_genode_until {\(gdb\)} 20 $gdb_id +send "c\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {Breakpoint 3, puts ()} $output]} { + puts "*** Error: Breakpoint in shared library did not trigger" exit -1 } -if {![regexp {#0 puts} $gdb_output] || - ![regexp {in func2()} $gdb_output] || - ![regexp {in func1()} $gdb_output] || - ![regexp {in main ()} $gdb_output]} { +puts "\n" +puts "----- test: stack trace when not in syscall -----" +puts "" - puts stderr "Error: Stack trace when not in syscall is not as expected" +send "bt\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {#0 puts} $output] || + ![regexp {in func2()} $output] || + ![regexp {in func1()} $output] || + ![regexp {in main ()} $output]} { + + puts stderr "*** Error: Stack trace when not in syscall is not as expected" exit -1 } -if {![regexp {\$1 = 1} $gdb_output]} { - puts stderr "Error: first 'print test_var' command didn't result in the expected output" +puts "\n" +puts "----- test: modification of a variable value -----" +puts "" + +send "print test_var\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {\$1 = 1} $output]} { + puts stderr "*** Error: first 'print test_var' command didn't result in the expected output" exit -1 } -if {![regexp {\$2 = 2} $gdb_output]} { - puts stderr "Error: second 'print test_var' command didn't result in the expected output" +send "set var test_var=2\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +send "print test_var\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {\$2 = 2} $output]} { + puts stderr "*** Error: second 'print test_var' command didn't result in the expected output" exit -1 } -if {![have_spec nova]} { -if {![regexp {\$3 = 3} $gdb_output]} { - puts stderr "Error: 'call' command didn't result in the expected output" - exit -1 -} -} +puts "\n" +puts "----- test: 'call' command -----" +puts "" -if {![regexp {Breakpoint 4, Test_thread::entry()} $gdb_output]} { - puts stderr "Error: Breakpoint in test thread did not trigger" +send "call test_var_func()\n" +run_genode_until {\(gdb\)} 60 $gdb_id + +if {![regexp {\$3 = 3} $output]} { + puts stderr "*** Error: 'call' command didn't result in the expected output" exit -1 } -if {![regexp {\* 2 Thread 2 Test_thread::entry} $gdb_output] || - ![regexp { 1 Thread 1} $gdb_output]} { - puts stderr "Error: Thread info is not as expected" +puts "\n" +puts "----- test: thread info -----" +puts "" + +send "b Test_thread::entry()\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +send "c\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {Breakpoint 4, Test_thread::entry()} $output]} { + puts stderr "*** Error: Breakpoint in test thread did not trigger" exit -1 } -if {![regexp {38 static Timer::Connection timer} $gdb_output]} { - puts stderr "Error: Single stepping didn't result in the expected output" +send "info threads\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp { 4 Thread 3} $output] || + ![regexp {\* 3 Thread 4 Test_thread::entry} $output] || + ![regexp { 2 Thread 2} $output] || + ![regexp { 1 Thread 1} $output]} { + puts stderr "*** Error: Thread info is not as expected" exit -1 } -if {![regexp {Program received signal SIGSEGV, Segmentation fault.} $gdb_output]} { - puts stderr "Error: Segmentation fault exception was not catched" +puts "\n" +puts "----- test: step into function -----" +puts "" + +send "step\n" +run_genode_until {\(gdb\)} 30 $gdb_id + +send "thread 2\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {Test_thread::step_func} $output]} { + puts stderr "*** Error: Step into function didn't result in the expected output" exit -1 } -if {![regexp {Genode::Cancelable_lock::lock\(\)} $gdb_output] || - ![regexp {Genode::Thread::join\(\)} $gdb_output] || - ![regexp {in main \(\)} $gdb_output]} { +puts "\n" +puts "----- test: catching a segmentation fault -----" +puts "" - puts stderr "Error: Stack trace when in syscall is not as expected" +send "c\n" +run_genode_until {\(gdb\)} 20 $gdb_id + +if {![regexp {Program received signal SIGSEGV, Segmentation fault.} $output]} { + puts stderr "*** Error: Segmentation fault exception was not caught" exit -1 - } +# does not work well on ARM yet +if {![have_spec arm]} { + + puts "\n" + puts "----- test: stack trace when in syscall -----" + puts "" + + send "thread 2\n" + run_genode_until {\(gdb\)} 20 $gdb_id + + send "bt\n" + run_genode_until {\(gdb\)} 20 $gdb_id + + if {![regexp {Genode::Cancelable_lock::lock\(\)} $output] || + ![regexp {Genode::Thread::join\(\)} $output] || + ![regexp {in main \(\)} $output]} { + + puts stderr "*** Error: Stack trace when in syscall is not as expected" + exit -1 + + } +} + +puts "" + # vi: set ft=tcl : diff --git a/repos/ports/run/gdb_monitor_interactive.run b/repos/ports/run/gdb_monitor_interactive.run index 148d1cbc4..7f7afc354 100644 --- a/repos/ports/run/gdb_monitor_interactive.run +++ b/repos/ports/run/gdb_monitor_interactive.run @@ -39,11 +39,11 @@ set config { - + - + @@ -98,7 +98,7 @@ append qemu_args " -serial mon:stdio " # connect comport 1 with TCP port $local_port append qemu_args " -serial chardev:uart " -append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait " +append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 " run_genode_until {.*Remote debugging using /dev/terminal.*} 30 @@ -119,7 +119,7 @@ append gdb_cmds {-ex "set interactive-mode auto" } puts "command: [gdb] bin/$gdb_target_binary $gdb_cmds" -exec [terminal] -e "[gdb] bin/test-gdb_monitor $gdb_cmds" & +exec [terminal] -e "[gdb] bin/ld.lib.so $gdb_cmds" & interact -i [output_spawn_id] diff --git a/repos/ports/run/gdb_monitor_target_config.run b/repos/ports/run/gdb_monitor_target_config.run index 60fcf40e7..c159f549d 100644 --- a/repos/ports/run/gdb_monitor_target_config.run +++ b/repos/ports/run/gdb_monitor_target_config.run @@ -92,7 +92,7 @@ append qemu_args " -serial mon:stdio " # connect comport 1 with TCP port $local_port append qemu_args " -serial chardev:uart " -append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait " +append qemu_args " -chardev socket,id=uart,port=$local_port,host=localhost,server,nowait,ipv4 " run_genode_until {.*Remote debugging using /dev/terminal.*} 30 diff --git a/repos/ports/run/noux_gdb.run b/repos/ports/run/noux_gdb.run index c57b8ead1..b6b1ef2ee 100644 --- a/repos/ports/run/noux_gdb.run +++ b/repos/ports/run/noux_gdb.run @@ -1,5 +1,5 @@ -if {![have_spec foc] || ![have_spec 32bit]} { - puts "\nThe Noux GDB scenario is supported on 32-bit Fiasco.OC only\n" +if {![have_spec foc] && ![have_spec nova]} { + puts "\nThe Noux GDB scenario is supported on NOVA and Fiasco.OC only\n" exit 0 } @@ -126,7 +126,7 @@ append config { - + @@ -171,19 +171,18 @@ append config { } append config " - " + " append config { - - + } append config " - " + " append config { - + diff --git a/repos/ports/src/app/gdb_monitor/app_child.h b/repos/ports/src/app/gdb_monitor/app_child.h index 9bb31bda4..33a145ab3 100644 --- a/repos/ports/src/app/gdb_monitor/app_child.h +++ b/repos/ports/src/app/gdb_monitor/app_child.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2009-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -26,292 +26,333 @@ #include #include "cpu_root.h" -#include "gdb_stub_thread.h" -#include "ram_root.h" +#include "genode_child_resources.h" #include "pd_session_component.h" +#include "ram_root.h" #include "rom.h" -namespace Gdb_monitor { +namespace Gdb_monitor { class App_child; } - class App_child : public Child_policy, public Init::Child_policy_enforce_labeling - { - private: +class Gdb_monitor::App_child : public Child_policy, + public Init::Child_policy_enforce_labeling +{ + private: - enum { STACK_SIZE = 4*1024*sizeof(long) }; + enum { STACK_SIZE = 4*1024*sizeof(long) }; - const char *_unique_name; + const char *_unique_name; - Rpc_entrypoint _entrypoint; + Genode::Dataspace_capability _elf_ds; + Genode::Dataspace_capability _ldso_ds; - Service_registry *_parent_services; - Service_registry _local_services; + Rpc_entrypoint _entrypoint; - Init::Child_config _child_config; + Service_registry *_parent_services; + Service_registry _local_services; - Init::Child_policy_provide_rom_file _binary_policy; - Init::Child_policy_provide_rom_file _config_policy; + Genode::Rpc_entrypoint *_root_ep; - Gdb_stub_thread _gdb_stub_thread; - Dataspace_pool _managed_ds_map; + Init::Child_config _child_config; - Cpu_root _cpu_root; - Cpu_session_client _cpu_session; + Init::Child_policy_provide_rom_file _binary_policy; + Init::Child_policy_provide_rom_file _config_policy; - Ram_session_client _ram_session; + Genode_child_resources _genode_child_resources; - Pd_session_component _pd { _unique_name, _entrypoint, - _managed_ds_map }; + Signal_dispatcher _unresolved_page_fault_dispatcher; - Region_map_client _address_space { _pd.address_space() }; + Dataspace_pool _managed_ds_map; - Child::Initial_thread _initial_thread; + Pd_session_component _pd {_unique_name, _entrypoint, _managed_ds_map}; - Child _child; + Cpu_root _cpu_root; + Cpu_session_client _cpu_session; - Genode::Rpc_entrypoint *_root_ep; + Ram_session_client _ram_session; - Rom_service _rom_service; + Region_map_client _address_space { _pd.address_space() }; - Cpu_session_capability _get_cpu_session_cap() - { - _entrypoint.manage(&_cpu_root); - char args[64]; - Genode::snprintf(args, sizeof(args), "ram_quota=32K, label=\"%s\"", _unique_name); - return static_cap_cast(_cpu_root.session(args, Affinity())); - } + Child::Initial_thread _initial_thread; - /** - * Proxy for a service provided by the child - */ - class Child_service_root : public Genode::Rpc_object - { - private: + Parent_service _parent_pd_service { "" }; + Parent_service _parent_ram_service { "" }; + Parent_service _parent_cpu_service { "" }; - /** - * Root interface of the real service, provided by the child + Child *_child; + + Rom_service _rom_service; + + + Cpu_session_capability _get_cpu_session_cap() + { + _entrypoint.manage(&_cpu_root); + char args[64]; + Genode::snprintf(args, sizeof(args), "ram_quota=64K, label=\"%s\"", _unique_name); + return static_cap_cast(_cpu_root.session(args, Affinity())); + } + + /** + * Proxy for a service provided by the child + */ + class Child_service_root : public Genode::Rpc_object + { + 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 Session_pool; + + /** + * Per-session meta data + * + * For each session, we need to keep track of the quota + * attached to it - in order to revert the quota donation + * when the session gets closed. + */ + struct Child_session : public Session_pool::Entry + { + Genode::size_t ram_quota; + + Child_session(Genode::Session_capability cap, + Genode::size_t ram_quota) + : Session_pool::Entry(cap), ram_quota(ram_quota) { } + }; + + /** + * Data base containing per-session meta data + */ + Session_pool _sessions; + + public: + + /** + * Constructor + */ + + Child_service_root(Genode::Ram_session_capability child_ram, + Genode::Root_capability child_root) + : _child_root(child_root), _child_ram(child_ram) + { } + + /******************** + ** Root interface ** + ********************/ + + Session_capability session(Session_args const &args, + Affinity const &affinity) + { + using namespace Genode; + + Genode::size_t ram_quota = + Arg_string::find_arg(args.string(), + "ram_quota").ulong_value(0); + + /* forward session quota to child */ + env()->ram_session()->transfer_quota(_child_ram, ram_quota); + + Session_capability cap = _child_root.session(args, affinity); + + /* + * Keep information about donated quota in '_sessions' + * data base. */ - Genode::Root_client _child_root; + _sessions.insert(new (env()->heap()) + Child_session(cap, ram_quota)); + return cap; + } - /** - * Child's RAM session used for quota transfers - */ - Genode::Ram_session_capability _child_ram; + void upgrade(Session_capability session_cap, + Upgrade_args const &args) + { + using namespace Genode; - struct Child_session; - typedef Genode::Object_pool Session_pool; - - /** - * Per-session meta data - * - * For each session, we need to keep track of the quota - * attached to it - in order to revert the quota donation - * when the session gets closed. - */ - struct Child_session : public Session_pool::Entry - { - Genode::size_t ram_quota; - - Child_session(Genode::Session_capability cap, - Genode::size_t ram_quota) - : Session_pool::Entry(cap), ram_quota(ram_quota) { } - }; - - /** - * Data base containing per-session meta data - */ - Session_pool _sessions; - - public: - - /** - * Constructor - */ - Child_service_root(Genode::Ram_session_capability child_ram, - Genode::Root_capability child_root) - : _child_root(child_root), _child_ram(child_ram) - { } - - /******************** - ** Root interface ** - ********************/ - - Session_capability session(Session_args const &args, - Affinity const &affinity) - { - using namespace Genode; + auto lambda = [&] (Child_session *session) { + if (!session) { + PERR("attempt to upgrade unknown session"); + return; + } Genode::size_t ram_quota = Arg_string::find_arg(args.string(), - "ram_quota").ulong_value(0); + "ram_quota").ulong_value(0); /* forward session quota to child */ env()->ram_session()->transfer_quota(_child_ram, ram_quota); - Session_capability cap = _child_root.session(args, affinity); + session->ram_quota += ram_quota; - /* - * Keep information about donated quota in '_sessions' - * data base. - */ - _sessions.insert(new (env()->heap()) - Child_session(cap, ram_quota)); - return cap; - } + /* inform child about quota upgrade */ + _child_root.upgrade(session_cap, args); + }; - void upgrade(Session_capability session_cap, - Upgrade_args const &args) - { - using namespace Genode; - - auto lambda = [&] (Child_session *session) { - if (!session) { - PERR("attempt to upgrade unknown session"); - return; - } - - Genode::size_t ram_quota = - Arg_string::find_arg(args.string(), - "ram_quota").ulong_value(0); - - /* forward session quota to child */ - env()->ram_session()->transfer_quota(_child_ram, ram_quota); - - session->ram_quota += ram_quota; - - /* inform child about quota upgrade */ - _child_root.upgrade(session_cap, args); - }; - - _sessions.apply(session_cap, lambda); - } - - void close(Session_capability session_cap) - { - using namespace Genode; - - Child_session *session; - - auto lambda = [&] (Child_session *s) { - session = s; - - if (!session) { - PERR("attempt to close unknown session"); - return; - } - _sessions.remove(session); - }; - _sessions.apply(session_cap, lambda); - - Genode::size_t ram_quota = session->ram_quota; - destroy(env()->heap(), session); - - _child_root.close(session_cap); - - /* - * The child is expected to free enough quota to revert - * the quota donation. - */ - - Ram_session_client child_ram(_child_ram); - child_ram.transfer_quota(env()->ram_session_cap(), ram_quota); - } - }; - - public: - - /** - * Constructor - * - * \param root_ep entrypoint serving the root interfaces of the - * services provided by the child and announced - * towards the parent of GDB monitor - */ - App_child(const char *unique_name, - Genode::Dataspace_capability elf_ds, - Genode::Dataspace_capability ldso_ds, - Genode::Ram_session_capability ram_session, - Genode::Cap_session *cap_session, - Service_registry *parent_services, - Genode::Rpc_entrypoint *root_ep, - Xml_node target_node) - : Init::Child_policy_enforce_labeling(unique_name), - _unique_name(unique_name), - _entrypoint(cap_session, STACK_SIZE, "GDB monitor entrypoint name"), - _parent_services(parent_services), - _child_config(ram_session, target_node), - _binary_policy("binary", elf_ds, &_entrypoint), - _config_policy("config", _child_config.dataspace(), &_entrypoint), - _gdb_stub_thread(), - _cpu_root(&_entrypoint, env()->heap() /* should be _child.heap() */, &_gdb_stub_thread), - _cpu_session(_get_cpu_session_cap()), - _ram_session(ram_session), - _initial_thread(_cpu_session, _pd.cap(), unique_name), - _child(elf_ds, ldso_ds, _pd.cap(), _pd, - _ram_session, _ram_session, _cpu_session, _initial_thread, - *Genode::env()->rm_session(), _address_space, _entrypoint, *this), - _root_ep(root_ep), - _rom_service(&_entrypoint, _child.heap()) - { - _gdb_stub_thread.set_region_map_component(&_pd.region_map()); - _local_services.insert(&_rom_service); - _gdb_stub_thread.start(); - } - - ~App_child() - { - } - - /**************************** - ** Child-policy interface ** - ****************************/ - - const char *name() const { return _unique_name; } - - void filter_session_args(const char *, char *args, Genode::size_t args_len) - { - Init::Child_policy_enforce_labeling::filter_session_args(0, args, args_len); - } - - Service *resolve_session_request(const char *service_name, - const char *args) - { - Service *service = 0; - - /* check for binary file request */ - if ((service = _binary_policy.resolve_session_request(service_name, args))) - return service; - - /* check for config file request */ - if ((service = _config_policy.resolve_session_request(service_name, args))) - return service; - - service = _local_services.find(service_name); - if (service) - return service; - - service = _parent_services->find(service_name); - if (!service) { - service = new (env()->heap()) Parent_service(service_name); - _parent_services->insert(service); + _sessions.apply(session_cap, lambda); } + void close(Session_capability session_cap) + { + using namespace Genode; + + Child_session *session; + + auto lambda = [&] (Child_session *s) { + session = s; + + if (!session) { + PERR("attempt to close unknown session"); + return; + } + _sessions.remove(session); + }; + _sessions.apply(session_cap, lambda); + + Genode::size_t ram_quota = session->ram_quota; + destroy(env()->heap(), session); + + _child_root.close(session_cap); + + /* + * The child is expected to free enough quota to revert + * the quota donation. + */ + + Ram_session_client child_ram(_child_ram); + child_ram.transfer_quota(env()->ram_session_cap(), ram_quota); + } + }; + + void _dispatch_unresolved_page_fault(unsigned) + { + _genode_child_resources.cpu_session_component()->handle_unresolved_page_fault(); + } + + public: + + /** + * Constructor + * + * \param root_ep entrypoint serving the root interfaces of the + * services provided by the child and announced + * towards the parent of GDB monitor + */ + App_child(const char *unique_name, + Genode::Dataspace_capability elf_ds, + Genode::Dataspace_capability ldso_ds, + Genode::Ram_session_capability ram_session, + Genode::Cap_session *cap_session, + Service_registry *parent_services, + Genode::Rpc_entrypoint *root_ep, + Signal_receiver *signal_receiver, + Xml_node target_node) + : Init::Child_policy_enforce_labeling(unique_name), + _unique_name(unique_name), + _elf_ds(elf_ds), + _ldso_ds(ldso_ds), + _entrypoint(cap_session, STACK_SIZE, "GDB monitor entrypoint name"), + _parent_services(parent_services), + _root_ep(root_ep), + _child_config(ram_session, target_node), + _binary_policy("binary", elf_ds, &_entrypoint), + _config_policy("config", _child_config.dataspace(), &_entrypoint), + _unresolved_page_fault_dispatcher(*signal_receiver, + *this, + &App_child::_dispatch_unresolved_page_fault), + _cpu_root(&_entrypoint, &_entrypoint, env()->heap(), _pd.core_pd_cap(), + signal_receiver, &_genode_child_resources), + _cpu_session(_get_cpu_session_cap()), + _ram_session(ram_session), + _initial_thread(_cpu_session, _pd.cap(), unique_name), + _rom_service(&_entrypoint, env()->heap()) + { + _genode_child_resources.region_map_component(&_pd.region_map()); + _pd.region_map().fault_handler(_unresolved_page_fault_dispatcher); + _local_services.insert(&_rom_service); + } + + ~App_child() + { + destroy(env()->heap(), _child); + } + + Genode_child_resources *genode_child_resources() + { + return &_genode_child_resources; + } + + void start() + { + _child = new (env()->heap()) Child(_elf_ds, + _ldso_ds, + _pd.cap(), + _pd, + _ram_session, + _ram_session, + _cpu_session, + _initial_thread, + *Genode::env()->rm_session(), + _address_space, + _entrypoint, + *this); + } + + /**************************** + ** Child-policy interface ** + ****************************/ + + const char *name() const { return _unique_name; } + + void filter_session_args(const char *, char *args, Genode::size_t args_len) + { + Init::Child_policy_enforce_labeling::filter_session_args(0, args, args_len); + } + + Service *resolve_session_request(const char *service_name, + const char *args) + { + Service *service = 0; + + /* check for binary file request */ + if ((service = _binary_policy.resolve_session_request(service_name, args))) return service; + + /* check for config file request */ + if ((service = _config_policy.resolve_session_request(service_name, args))) + return service; + + service = _local_services.find(service_name); + if (service) + return service; + + service = _parent_services->find(service_name); + if (!service) { + service = new (env()->heap()) Parent_service(service_name); + _parent_services->insert(service); } - bool announce_service(const char *name, - Root_capability root, - Allocator *alloc, - Server *server) - { - /* create and announce proxy for the child's root interface */ - Child_service_root *r = new (alloc) - Child_service_root(_ram_session, root); + return service; + } - Genode::env()->parent()->announce(name, _root_ep->manage(r)); - return true; - } - }; -} + bool announce_service(const char *name, + Root_capability root, + Allocator *alloc, + Server *server) + { + /* create and announce proxy for the child's root interface */ + Child_service_root *r = new (alloc) + Child_service_root(_ram_session, root); + + Genode::env()->parent()->announce(name, _root_ep->manage(r)); + return true; + } +}; #endif /* _APP_CHILD_H_ */ diff --git a/repos/ports/src/app/gdb_monitor/cpu_root.h b/repos/ports/src/app/gdb_monitor/cpu_root.h index 2c71e5c33..e80cfc842 100644 --- a/repos/ports/src/app/gdb_monitor/cpu_root.h +++ b/repos/ports/src/app/gdb_monitor/cpu_root.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -21,43 +21,58 @@ #include /* 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 - { - private: - Gdb_stub_thread *_gdb_stub_thread; +class Gdb_monitor::Cpu_root : public Root_component +{ + private: - protected: + Rpc_entrypoint *_thread_ep; + Allocator *_md_alloc; + Pd_session_capability _core_pd; + Genode::Signal_receiver *_signal_receiver; + Genode_child_resources *_genode_child_resources; - Cpu_session_component *_create_session(const char *args) - { - Cpu_session_component *cpu_session_component = - new (md_alloc()) - Cpu_session_component(_gdb_stub_thread->exception_signal_receiver(), args); - _gdb_stub_thread->set_cpu_session_component(cpu_session_component); - return cpu_session_component; - } + protected: - public: + Cpu_session_component *_create_session(const char *args) + { + Cpu_session_component *cpu_session_component = + new (md_alloc()) + Cpu_session_component(_thread_ep, + _md_alloc, + _core_pd, + _signal_receiver, + args); + _genode_child_resources->cpu_session_component(cpu_session_component); + return cpu_session_component; + } - /** - * Constructor - * - * \param session_ep entry point for managing cpu session objects - * \param thread_ep entry point for managing threads - * \param md_alloc meta data allocator to be used by root component - */ - Cpu_root(Rpc_entrypoint *session_ep, - Allocator *md_alloc, - Gdb_stub_thread *gdb_stub_thread) - : - Root_component(session_ep, md_alloc), - _gdb_stub_thread(gdb_stub_thread) - { } - }; -} + public: + + /** + * Constructor + * + * \param session_ep entry point for managing cpu session objects + * \param thread_ep entry point for managing threads + * \param md_alloc meta data allocator to be used by root component + */ + Cpu_root(Rpc_entrypoint *session_ep, + Rpc_entrypoint *thread_ep, + Allocator *md_alloc, + Pd_session_capability core_pd, + Genode::Signal_receiver *signal_receiver, + Genode_child_resources *genode_child_resources) + : + Root_component(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_ */ diff --git a/repos/ports/src/app/gdb_monitor/cpu_session_component.cc b/repos/ports/src/app/gdb_monitor/cpu_session_component.cc index 0115c94cf..c2980c412 100644 --- a/repos/ports/src/app/gdb_monitor/cpu_session_component.cc +++ b/repos/ports/src/app/gdb_monitor/cpu_session_component.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -14,31 +14,69 @@ /* Genode includes */ #include #include +#include #include #include /* GDB monitor includes */ -#include "config.h" +#include "cpu_thread_component.h" -extern void genode_add_thread(unsigned long lwpid); +/* genode-low.cc */ extern void genode_remove_thread(unsigned long lwpid); using namespace Genode; using namespace Gdb_monitor; -/* FIXME: use an allocator */ -static unsigned long new_lwpid = GENODE_LWP_BASE; - -Thread_info *Cpu_session_component::_thread_info(Thread_capability thread_cap) +Cpu_session &Cpu_session_component::parent_cpu_session() { - Thread_info *thread_info = _thread_list.first(); - while (thread_info) { - if (thread_info->thread_cap().local_name() == thread_cap.local_name()) { - return thread_info; - break; - } - thread_info = thread_info->next(); + return _parent_cpu_session; +} + + +Rpc_entrypoint &Cpu_session_component::thread_ep() +{ + return *_thread_ep; +} + + +Signal_receiver *Cpu_session_component::exception_signal_receiver() +{ + return _exception_signal_receiver; +} + + +Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid) +{ + Cpu_thread_component *cpu_thread = _thread_list.first(); + while (cpu_thread) { + if (cpu_thread->lwpid() == lwpid) + return cpu_thread->thread_cap(); + cpu_thread = cpu_thread->next(); + } + return Thread_capability(); +} + + +Cpu_thread_component *Cpu_session_component::lookup_cpu_thread(unsigned long lwpid) +{ + Cpu_thread_component *cpu_thread = _thread_list.first(); + while (cpu_thread) { + if (cpu_thread->lwpid() == lwpid) + return cpu_thread; + cpu_thread = cpu_thread->next(); + } + return nullptr; +} + + +Cpu_thread_component *Cpu_session_component::lookup_cpu_thread(Thread_capability thread_cap) +{ + Cpu_thread_component *cpu_thread = _thread_list.first(); + while (cpu_thread) { + if (cpu_thread->thread_cap().local_name() == thread_cap.local_name()) + return cpu_thread; + cpu_thread = cpu_thread->next(); } return 0; } @@ -46,68 +84,150 @@ Thread_info *Cpu_session_component::_thread_info(Thread_capability thread_cap) unsigned long Cpu_session_component::lwpid(Thread_capability thread_cap) { - return _thread_info(thread_cap)->lwpid(); + return lookup_cpu_thread(thread_cap)->lwpid(); } -Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid) +int Cpu_session_component::signal_pipe_read_fd(Thread_capability thread_cap) { - Thread_info *thread_info = _thread_list.first(); - while (thread_info) { - if (thread_info->lwpid() == lwpid) { - return thread_info->thread_cap(); + return lookup_cpu_thread(thread_cap)->signal_pipe_read_fd(); +} + + +int Cpu_session_component::send_signal(Thread_capability thread_cap, + int signo) +{ + Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap); + + cpu_thread->pause(); + + switch (signo) { + case SIGSTOP: + Signal_transmitter(cpu_thread->sigstop_signal_context_cap()).submit(); + return 1; + case SIGINT: + Signal_transmitter(cpu_thread->sigint_signal_context_cap()).submit(); + return 1; + default: + PERR("unexpected signal %d", signo); + return 0; + } +} + + +/* + * This function delivers a SIGSEGV to the first thread with an unresolved + * page fault that it finds. Multiple page-faulted threads are currently + * not supported. + */ + +void Cpu_session_component::handle_unresolved_page_fault() +{ + /* + * It can happen that the thread state of the thread which caused the + * page fault is not accessible yet. In that case, we'll retry until + * it is accessible. + */ + + while (1) { + + Thread_capability thread_cap = first(); + + while (thread_cap.valid()) { + + try { + + Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap); + + Thread_state thread_state = cpu_thread->state(); + + if (thread_state.unresolved_page_fault) { + + /* + * On base-foc it is necessary to pause the thread before + * IP and SP are available in the thread state. + */ + cpu_thread->pause(); + cpu_thread->deliver_signal(SIGSEGV); + + return; + } + + } catch (Cpu_thread::State_access_failed) { } + + thread_cap = next(thread_cap); } - thread_info = thread_info->next(); + } - return Thread_capability(); } -Thread_capability -Cpu_session_component::create_thread(Capability pd, - Name const &name, - Affinity::Location location, - Weight weight, - addr_t utcb) +void Cpu_session_component::stop_new_threads(bool stop) { - Thread_capability thread_cap = - _parent_cpu_session.create_thread(pd, name, location, weight, utcb); - - if (thread_cap.valid()) { - Thread_info *thread_info = new (env()->heap()) Thread_info(thread_cap, new_lwpid++); - _thread_list.append(thread_info); - } - - return thread_cap; + _stop_new_threads = stop; } -//Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread) -//{ -// return _parent_cpu_session.utcb(thread); -//} - - -void Cpu_session_component::kill_thread(Thread_capability thread_cap) +bool Cpu_session_component::stop_new_threads() { - Thread_info *thread_info = _thread_info(thread_cap); + return _stop_new_threads; +} - if (thread_info) { - _exception_signal_receiver->dissolve(thread_info); - genode_remove_thread(thread_info->lwpid()); - _thread_list.remove(thread_info); - destroy(env()->heap(), thread_info); + +Lock &Cpu_session_component::stop_new_threads_lock() +{ + return _stop_new_threads_lock; +} + + +int Cpu_session_component::handle_initial_breakpoint(unsigned long lwpid) +{ + Cpu_thread_component *cpu_thread = _thread_list.first(); + while (cpu_thread) { + if (cpu_thread->lwpid() == lwpid) + return cpu_thread->handle_initial_breakpoint(); + cpu_thread = cpu_thread->next(); } + return 0; +} - _parent_cpu_session.kill_thread(thread_cap); + +void Cpu_session_component::pause_all_threads() +{ + Lock::Guard stop_new_threads_lock_guard(stop_new_threads_lock()); + + stop_new_threads(true); + + for (Cpu_thread_component *cpu_thread = _thread_list.first(); + cpu_thread; + cpu_thread = cpu_thread->next()) { + + cpu_thread->pause(); + } +} + + +void Cpu_session_component::resume_all_threads() +{ +Lock::Guard stop_new_threads_guard(stop_new_threads_lock()); + + stop_new_threads(false); + + for (Cpu_thread_component *cpu_thread = _thread_list.first(); + cpu_thread; + cpu_thread = cpu_thread->next()) { + + cpu_thread->single_step(false); + cpu_thread->resume(); + } } Thread_capability Cpu_session_component::first() { - Thread_info *thread_info = _thread_list.first(); - if (thread_info) - return thread_info->thread_cap(); + Cpu_thread_component *cpu_thread = _thread_list.first(); + if (cpu_thread) + return cpu_thread->thread_cap(); else return Thread_capability(); } @@ -115,77 +235,50 @@ Thread_capability Cpu_session_component::first() Thread_capability Cpu_session_component::next(Thread_capability thread_cap) { - Thread_info *next_thread_info = _thread_info(thread_cap)->next(); - if (next_thread_info) - return next_thread_info->thread_cap(); + Cpu_thread_component *next_cpu_thread = lookup_cpu_thread(thread_cap)->next(); + if (next_cpu_thread) + return next_cpu_thread->thread_cap(); else return Thread_capability(); } -//int Cpu_session_component::start(Thread_capability thread_cap, -// addr_t ip, addr_t sp) -//{ -// Thread_info *thread_info = _thread_info(thread_cap); -// -// if (thread_info) -// exception_handler(thread_cap, _exception_signal_receiver->manage(thread_info)); -// -// int result = _parent_cpu_session.start(thread_cap, ip, sp); -// -// if (thread_info) { -// /* pause the first thread */ -// if (thread_info->lwpid() == GENODE_LWP_BASE) -// pause(thread_cap); -// -// genode_add_thread(thread_info->lwpid()); -// } -// -// return result; -//} - - -//void Cpu_session_component::pause(Thread_capability thread_cap) -//{ -// _parent_cpu_session.pause(thread_cap); -//} - - -//void Cpu_session_component::resume(Thread_capability thread_cap) -//{ -// _parent_cpu_session.resume(thread_cap); -//} - - -//void Cpu_session_component::cancel_blocking(Thread_capability thread_cap) -//{ -// _parent_cpu_session.cancel_blocking(thread_cap); -//} - - -//void Cpu_session_component::state(Thread_capability thread_cap, -// Thread_state const &state) -//{ -// _parent_cpu_session.state(thread_cap, state); -//} - - -//Thread_state Cpu_session_component::state(Thread_capability thread_cap) -//{ -// return _parent_cpu_session.state(thread_cap); -//} - - -void Cpu_session_component::exception_sigh(Signal_context_capability sigh_cap) +Thread_capability Cpu_session_component::create_thread(Capability pd, + Cpu_session::Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb) { - _parent_cpu_session.exception_sigh(sigh_cap); + Cpu_thread_component *cpu_thread = + new (_md_alloc) Cpu_thread_component(*this, _core_pd, name, + affinity, weight, utcb); + + _thread_list.append(cpu_thread); + + return cpu_thread->cap(); } -//void Cpu_session_component::single_step(Thread_capability thread_cap, bool enable) -//{ -// _parent_cpu_session.single_step(thread_cap, enable); -//} +void Cpu_session_component::kill_thread(Thread_capability thread_cap) +{ + Cpu_thread_component *cpu_thread = lookup_cpu_thread(thread_cap); + + if (cpu_thread) { + genode_remove_thread(cpu_thread->lwpid()); + _thread_list.remove(cpu_thread); + destroy(_md_alloc, cpu_thread); + } else + PERR("%s: could not find thread info for the given thread capability", + __PRETTY_FUNCTION__); + + _parent_cpu_session.kill_thread(thread_cap); +} + + +void Cpu_session_component::exception_sigh(Signal_context_capability handler) +{ + _parent_cpu_session.exception_sigh(handler); +} Affinity::Space Cpu_session_component::affinity_space() const @@ -194,56 +287,49 @@ Affinity::Space Cpu_session_component::affinity_space() const } -//void Cpu_session_component::affinity(Thread_capability thread_cap, -// Affinity::Location location) -//{ -// _parent_cpu_session.affinity(thread_cap, location); -//} - - Dataspace_capability Cpu_session_component::trace_control() { return _parent_cpu_session.trace_control(); } -//unsigned Cpu_session_component::trace_control_index(Thread_capability thread) -//{ -// return _parent_cpu_session.trace_control_index(thread); -//} - - -//Dataspace_capability Cpu_session_component::trace_buffer(Thread_capability thread) -//{ -// return _parent_cpu_session.trace_buffer(thread); -//} - - -//Dataspace_capability Cpu_session_component::trace_policy(Thread_capability thread) -//{ -// return _parent_cpu_session.trace_policy(thread); -//} - - Capability Cpu_session_component::native_cpu() { - return _parent_cpu_session.native_cpu(); + return _native_cpu_cap; } -Cpu_session_component::Cpu_session_component(Signal_receiver *exception_signal_receiver, const char *args) -: _parent_cpu_session(env()->parent()->session(args)), - _exception_signal_receiver(exception_signal_receiver) +Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep, + Allocator *md_alloc, + Pd_session_capability core_pd, + Signal_receiver *exception_signal_receiver, + const char *args) +: _thread_ep(thread_ep), + _md_alloc(md_alloc), + _core_pd(core_pd), + _parent_cpu_session(env()->parent()->session(args)), + _exception_signal_receiver(exception_signal_receiver), + _native_cpu_cap(_setup_native_cpu()) { } Cpu_session_component::~Cpu_session_component() { + for (Cpu_thread_component *cpu_thread = _thread_list.first(); + cpu_thread; cpu_thread = _thread_list.first()) { + _thread_list.remove(cpu_thread); + destroy(_md_alloc, cpu_thread); + } + + _cleanup_native_cpu(); } + int Cpu_session_component::ref_account(Cpu_session_capability) { return -1; } + int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; } + Cpu_session::Quota Cpu_session_component::quota() { return Quota(); } diff --git a/repos/ports/src/app/gdb_monitor/cpu_session_component.h b/repos/ports/src/app/gdb_monitor/cpu_session_component.h index b919749fc..ce678faf4 100644 --- a/repos/ports/src/app/gdb_monitor/cpu_session_component.h +++ b/repos/ports/src/app/gdb_monitor/cpu_session_component.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -15,40 +15,77 @@ #define _CPU_SESSION_COMPONENT_H_ /* Genode includes */ +#include #include +#include #include +#include /* GDB monitor includes */ -#include "thread_info.h" +#include "append_list.h" -using namespace Genode; -using namespace Gdb_monitor; - -class Cpu_session_component : public Rpc_object +namespace Gdb_monitor { + class Cpu_session_component; + class Cpu_thread_component; + using namespace Genode; +} + +class Gdb_monitor::Cpu_session_component : public Rpc_object +{ + private: + Rpc_entrypoint *_thread_ep; + Allocator *_md_alloc; + + Pd_session_capability _core_pd; + Cpu_session_client _parent_cpu_session; Signal_receiver *_exception_signal_receiver; - Append_list _thread_list; + Append_list _thread_list; - Thread_info *_thread_info(Thread_capability thread_cap); + bool _stop_new_threads = true; + Lock _stop_new_threads_lock; + + Capability _native_cpu_cap; + + Capability _setup_native_cpu(); + void _cleanup_native_cpu(); public: /** * Constructor */ - Cpu_session_component(Signal_receiver *exception_signal_receiver, const char *args); + Cpu_session_component(Rpc_entrypoint *thread_ep, + Allocator *md_alloc, + Pd_session_capability core_pd, + Signal_receiver *exception_signal_receiver, + const char *args); /** * Destructor */ ~Cpu_session_component(); - unsigned long lwpid(Thread_capability thread_cap); + Cpu_session &parent_cpu_session(); + Rpc_entrypoint &thread_ep(); + Signal_receiver *exception_signal_receiver(); Thread_capability thread_cap(unsigned long lwpid); + unsigned long lwpid(Thread_capability thread_cap); + Cpu_thread_component *lookup_cpu_thread(unsigned long lwpid); + Cpu_thread_component *lookup_cpu_thread(Thread_capability thread_cap); + int signal_pipe_read_fd(Thread_capability thread_cap); + int send_signal(Thread_capability thread_cap, int signo); + void handle_unresolved_page_fault(); + void stop_new_threads(bool stop); + bool stop_new_threads(); + Lock &stop_new_threads_lock(); + int handle_initial_breakpoint(unsigned long lwpid); + void pause_all_threads(); + void resume_all_threads(); Thread_capability first(); Thread_capability next(Thread_capability); @@ -56,8 +93,11 @@ class Cpu_session_component : public Rpc_object ** CPU session interface ** ***************************/ - Thread_capability create_thread(Capability, Name const &, - Affinity::Location, Weight, addr_t) override; + Thread_capability create_thread(Capability, + Name const &, + Affinity::Location, + Weight, + addr_t) override; void kill_thread(Thread_capability) override; void exception_sigh(Signal_context_capability handler) override; Affinity::Space affinity_space() const override; diff --git a/repos/ports/src/app/gdb_monitor/cpu_thread_component.cc b/repos/ports/src/app/gdb_monitor/cpu_thread_component.cc new file mode 100644 index 000000000..bb2093045 --- /dev/null +++ b/repos/ports/src/app/gdb_monitor/cpu_thread_component.cc @@ -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(); +} diff --git a/repos/ports/src/app/gdb_monitor/cpu_thread_component.h b/repos/ports/src/app/gdb_monitor/cpu_thread_component.h new file mode 100644 index 000000000..7462c4c2a --- /dev/null +++ b/repos/ports/src/app/gdb_monitor/cpu_thread_component.h @@ -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 +#include +#include + +/* libc includes */ +#include +#include + +#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, + public Append_list::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 _exception_dispatcher; + Signal_dispatcher _sigstop_dispatcher; + Signal_dispatcher _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, + 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_ */ diff --git a/repos/ports/src/app/gdb_monitor/dataspace_object.h b/repos/ports/src/app/gdb_monitor/dataspace_object.h index af239e7f6..e44f3480b 100644 --- a/repos/ports/src/app/gdb_monitor/dataspace_object.h +++ b/repos/ports/src/app/gdb_monitor/dataspace_object.h @@ -41,6 +41,7 @@ namespace Gdb_monitor { Region_map_component *region_map_component() { return _region_map_component; } }; + } #endif /* _DATASPACE_OBJECT_H_ */ diff --git a/repos/ports/src/app/gdb_monitor/gdb_stub_thread.cc b/repos/ports/src/app/gdb_monitor/gdb_stub_thread.cc deleted file mode 100644 index f4c2fd7cf..000000000 --- a/repos/ports/src/app/gdb_monitor/gdb_stub_thread.cc +++ /dev/null @@ -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 - -#include "gdb_stub_thread.h" - -using namespace Genode; -using namespace Gdb_monitor; - -Gdb_stub_thread::Gdb_stub_thread() -: - Thread_deprecated("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(); -}; diff --git a/repos/ports/src/app/gdb_monitor/gdb_stub_thread.h b/repos/ports/src/app/gdb_monitor/gdb_stub_thread.h deleted file mode 100644 index 3aa4de2b7..000000000 --- a/repos/ports/src/app/gdb_monitor/gdb_stub_thread.h +++ /dev/null @@ -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 - -#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 - { - 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_ */ diff --git a/repos/ports/src/app/gdb_monitor/gdbserver/config.h b/repos/ports/src/app/gdb_monitor/gdbserver/config.h index 11e191e8a..8f92aec9c 100644 --- a/repos/ports/src/app/gdb_monitor/gdbserver/config.h +++ b/repos/ports/src/app/gdb_monitor/gdbserver/config.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -28,4 +28,4 @@ #define __GENODE__ /* first process id */ -#define GENODE_LWP_BASE 1 +#define GENODE_MAIN_LWPID 1 diff --git a/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.cc b/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.cc index 3bc1421c5..2b6f9a3b5 100644 --- a/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.cc +++ b/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.cc @@ -6,137 +6,423 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ +#include +#include +#include +#include + extern "C" { #define private _private #include "genode-low.h" +#include "server.h" #include "linux-low.h" #define _private private int linux_detach_one_lwp (struct inferior_list_entry *entry, void *args); } -#include #include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include "app_child.h" #include "cpu_session_component.h" - -#include "gdb_stub_thread.h" +#include "cpu_thread_component.h" +#include "genode_child_resources.h" +#include "rom.h" +#include "signal_handler_thread.h" static bool verbose = false; +static int _new_thread_pipe[2]; + +/* + * When 'waitpid()' reports a SIGTRAP, this variable stores the lwpid of the + * corresponding thread. This information is used in the initial breakpoint + * handler to let the correct thread handle the event. + */ +static unsigned long sigtrap_lwpid; + using namespace Genode; using namespace Gdb_monitor; +static Genode_child_resources *_genode_child_resources = 0; -static Lock &main_thread_ready_lock() + +Genode_child_resources *genode_child_resources() { - static Lock _main_thread_ready_lock(Lock::LOCKED); - return _main_thread_ready_lock; + return _genode_child_resources; } -static Lock &gdbserver_ready_lock() +static void genode_stop_thread(unsigned long lwpid) { - static Lock _gdbserver_ready_lock(Lock::LOCKED); - return _gdbserver_ready_lock; -} + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid); -Gdb_stub_thread *gdb_stub_thread() -{ - return (Gdb_stub_thread*)(current_process()->_private->gdb_stub_thread); -} - - -extern "C" int genode_signal_fd() -{ - return gdb_stub_thread()->signal_fd(); -} - - -void genode_add_thread(unsigned long lwpid) -{ - if (lwpid == GENODE_LWP_BASE) { - main_thread_ready_lock().unlock(); - } else { - if (lwpid == GENODE_LWP_BASE + 1) { - /* make sure gdbserver is ready to attach new threads */ - gdbserver_ready_lock().lock(); - } - linux_attach_lwp(lwpid); + if (!cpu_thread) { + PERR("%s: could not find CPU thread object for lwpid %lu", + __PRETTY_FUNCTION__, lwpid); + return; } + + cpu_thread->pause(); +} + + +extern "C" pid_t waitpid(pid_t pid, int *status, int flags) +{ + extern int remote_desc; + + fd_set readset; + + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + + while(1) { + + FD_ZERO (&readset); + + if (remote_desc != -1) + FD_SET (remote_desc, &readset); + + if (pid == -1) { + + FD_SET(_new_thread_pipe[0], &readset); + + Thread_capability thread_cap = csc->first(); + + while (thread_cap.valid()) { + FD_SET(csc->signal_pipe_read_fd(thread_cap), &readset); + thread_cap = csc->next(thread_cap); + } + + } else { + + FD_SET(csc->signal_pipe_read_fd(csc->thread_cap(pid)), &readset); + } + + struct timeval wnohang_timeout = {0, 0}; + struct timeval *timeout = (flags & WNOHANG) ? &wnohang_timeout : NULL; + + /* TODO: determine the highest fd in the set for optimization */ + int res = select(FD_SETSIZE, &readset, 0, 0, timeout); + + if (res > 0) { + + if ((remote_desc != -1) && FD_ISSET(remote_desc, &readset)) { + + /* received input from GDB */ + + int cc; + char c = 0; + + cc = read (remote_desc, &c, 1); + + if (cc == 1 && c == '\003' && current_inferior != NULL) { + /* this causes a SIGINT to be delivered to one of the threads */ + (*the_target->request_interrupt)(); + continue; + } else { + if (verbose) + PDBG("input_interrupt, count = %d c = %d ('%c')", cc, c, c); + } + + } else if (FD_ISSET(_new_thread_pipe[0], &readset)) { + + unsigned long lwpid = GENODE_MAIN_LWPID; + + genode_stop_thread(lwpid); + + *status = W_STOPCODE(SIGTRAP) | (PTRACE_EVENT_CLONE << 16); + + return lwpid; + + } else { + + /* received a signal */ + + Thread_capability thread_cap = csc->first(); + + while (thread_cap.valid()) { + if (FD_ISSET(csc->signal_pipe_read_fd(thread_cap), &readset)) + break; + thread_cap = csc->next(thread_cap); + } + + if (!thread_cap.valid()) + continue; + + int signal; + read(csc->signal_pipe_read_fd(thread_cap), &signal, sizeof(signal)); + + unsigned long lwpid = csc->lwpid(thread_cap); + + if (verbose) + PDBG("thread %lu received signal %d", lwpid, signal); + + if (signal == SIGTRAP) { + + sigtrap_lwpid = lwpid; + + } else if (signal == SIGSTOP) { + + /* + * Check if a SIGTRAP is pending + * + * This can happen if a single-stepped thread gets paused while gdbserver + * handles a signal of a different thread and the exception signal after + * the single step has not arrived yet. In this case, the SIGTRAP must be + * delivered first, otherwise gdbserver would single-step the thread again. + */ + + Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid); + + Thread_state thread_state = cpu_thread->state(); + + if (thread_state.exception) { + /* resend the SIGSTOP signal */ + csc->send_signal(cpu_thread->cap(), SIGSTOP); + continue; + } + + } else if (signal == SIGINFO) { + + if (verbose) + PDBG("received SIGINFO for new lwpid %lu", lwpid); + + if (lwpid != GENODE_MAIN_LWPID) + write(_new_thread_pipe[1], &lwpid, sizeof(lwpid)); + + /* + * First signal of a new thread. On Genode originally a + * SIGTRAP, but gdbserver expects SIGSTOP. + */ + + signal = SIGSTOP; + } + + *status = W_STOPCODE(signal); + + return lwpid; + } + + } else { + + return res; + + } + } +} + + +extern "C" long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data) +{ + const char *request_str = 0; + + switch (request) { + case PTRACE_TRACEME: request_str = "PTRACE_TRACEME"; break; + case PTRACE_PEEKTEXT: request_str = "PTRACE_PEEKTEXT"; break; + case PTRACE_PEEKUSER: request_str = "PTRACE_PEEKUSER"; break; + case PTRACE_POKETEXT: request_str = "PTRACE_POKETEXT"; break; + case PTRACE_POKEUSER: request_str = "PTRACE_POKEUSER"; break; + case PTRACE_CONT: request_str = "PTRACE_CONT"; break; + case PTRACE_KILL: request_str = "PTRACE_KILL"; break; + case PTRACE_SINGLESTEP: request_str = "PTRACE_SINGLESTEP"; break; + case PTRACE_GETREGS: request_str = "PTRACE_GETREGS"; break; + case PTRACE_SETREGS: request_str = "PTRACE_SETREGS"; break; + case PTRACE_ATTACH: request_str = "PTRACE_ATTACH"; break; + case PTRACE_DETACH: request_str = "PTRACE_DETACH"; break; + case PTRACE_GETEVENTMSG: + /* + * Only PTRACE_EVENT_CLONE is currently supported. + * + * Read the lwpid of the new thread from the pipe. + */ + read(_new_thread_pipe[0], data, sizeof(unsigned long)); + return 0; + case PTRACE_GETREGSET: request_str = "PTRACE_GETREGSET"; break; + } + + PWRN("ptrace(%s (0x%x)) called - not implemented!", request_str, request); + + errno = EINVAL; + return -1; +} + + +extern "C" int fork() +{ + /* create the thread announcement pipe */ + + if (pipe(_new_thread_pipe) != 0) { + PERR("could not create the 'new thread' pipe"); + return -1; + } + + /* look for dynamic linker */ + + Dataspace_capability ldso_cap; + try { + Rom_connection ldso_rom("ld.lib.so"); + ldso_cap = clone_rom(ldso_rom.dataspace()); + } catch (...) { + PDBG("ld.lib.so not found"); + } + + /* extract target filename from config file */ + + static char filename[32] = ""; + + try { + config()->xml_node().sub_node("target").attribute("name").value(filename, sizeof(filename)); + } catch (Xml_node::Nonexistent_sub_node) { + PERR("Error: Missing '' sub node."); + return -1; + } catch (Xml_node::Nonexistent_attribute) { + PERR("Error: Missing 'name' attribute of '' 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 config node"); + return -1; + } + + Number_of_bytes ram_quota = env()->ram_session()->avail() - preserved_ram_quota; + + /* start the application */ + char *unique_name = filename; + Capability file_cap; + try { + static Rom_connection rom(filename, unique_name); + file_cap = rom.dataspace(); + } catch (Rom_connection::Rom_connection_failed) { + Genode::printf("Error: Could not access file \"%s\" from ROM service.\n", filename); + return -1; + } + + /* copy ELF image to writable dataspace */ + Genode::size_t elf_size = Dataspace_client(file_cap).size(); + Dataspace_capability elf_cap = clone_rom(file_cap); + + /* create ram session for child with some of our own quota */ + static Ram_connection ram; + ram.ref_account(env()->ram_session_cap()); + env()->ram_session()->transfer_quota(ram.cap(), (Genode::size_t)ram_quota - elf_size); + + /* cap session for allocating capabilities for parent interfaces */ + static Cap_connection cap_session; + + static Service_registry parent_services; + + enum { CHILD_ROOT_EP_STACK = 1024*sizeof(addr_t) }; + static Rpc_entrypoint child_root_ep(&cap_session, CHILD_ROOT_EP_STACK, + "child_root_ep"); + + static Signal_receiver signal_receiver; + + static Gdb_monitor::Signal_handler_thread + signal_handler_thread(&signal_receiver); + signal_handler_thread.start(); + + App_child *child = new (env()->heap()) App_child(unique_name, + elf_cap, + ldso_cap, + ram.cap(), + &cap_session, + &parent_services, + &child_root_ep, + &signal_receiver, + target_node); + + _genode_child_resources = child->genode_child_resources(); + + child->start(); + + return GENODE_MAIN_LWPID; +} + + +extern "C" int kill(pid_t pid, int sig) +{ + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + + Thread_capability thread_cap = csc->thread_cap(pid); + + if (!thread_cap.valid()) { + PERR("%s: could not find thread capability for lwpid %d", + __PRETTY_FUNCTION__, pid); + return -1; + } + + return csc->send_signal(thread_cap, sig); +} + + +extern "C" int initial_breakpoint_handler(CORE_ADDR addr) +{ + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + return csc->handle_initial_breakpoint(sigtrap_lwpid); +} + + +void genode_set_initial_breakpoint_at(CORE_ADDR addr) +{ + set_breakpoint_at(addr, initial_breakpoint_handler); } void genode_remove_thread(unsigned long lwpid) { - int pid = GENODE_LWP_BASE; + int pid = GENODE_MAIN_LWPID; linux_detach_one_lwp((struct inferior_list_entry *) - find_thread_ptid(ptid_build(GENODE_LWP_BASE, lwpid, 0)), &pid); -} - - -void genode_wait_for_target_main_thread() -{ - /* gdbserver is now ready to attach new threads */ - gdbserver_ready_lock().unlock(); - - /* wait until the target's main thread has been created */ - main_thread_ready_lock().lock(); -} - - -extern "C" void genode_detect_all_threads() -{ - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); - - Thread_capability thread_cap = csc->next(csc->first()); /* second thread */ - - while (thread_cap.valid()) { - linux_attach_lwp(csc->lwpid(thread_cap)); - thread_cap = csc->next(thread_cap); - } + find_thread_ptid(ptid_build(GENODE_MAIN_LWPID, lwpid, 0)), &pid); } extern "C" void genode_stop_all_threads() { - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); - - Thread_capability thread_cap = csc->first(); - - while (thread_cap.valid()) { - Cpu_thread_client(thread_cap).pause(); - thread_cap = csc->next(thread_cap); - } + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + csc->pause_all_threads(); } -extern "C" void genode_resume_all_threads() +void genode_resume_all_threads() { - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); - - Thread_capability thread_cap = csc->first(); - - while (thread_cap.valid()) { - Cpu_thread_client(thread_cap).resume(); - thread_cap = csc->next(thread_cap); - } + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); + csc->resume_all_threads(); } int genode_detach(int pid) { - find_inferior (&all_threads, linux_detach_one_lwp, &pid); - genode_resume_all_threads(); return 0; @@ -146,86 +432,67 @@ int genode_detach(int pid) int genode_kill(int pid) { /* TODO */ - if (verbose) PDBG("genode_kill() called - not implemented\n"); + if (verbose) PDBG("not implemented, just detaching instead..."); return genode_detach(pid); } -void genode_interrupt_thread(unsigned long lwpid) -{ - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); - - Thread_capability thread_cap = csc->thread_cap(lwpid); - - if (!thread_cap.valid()) { - PERR("could not find thread capability for lwpid %lu", lwpid); - return; - } - - Cpu_thread_client(thread_cap).pause(); -} - - void genode_continue_thread(unsigned long lwpid, int single_step) { - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); - Thread_capability thread_cap = csc->thread_cap(lwpid); + Cpu_thread_component *cpu_thread = csc->lookup_cpu_thread(lwpid); - if (!thread_cap.valid()) { - PERR("could not find thread capability for lwpid %lu", lwpid); + if (!cpu_thread) { + PERR("%s: could not find CPU thread object for lwpid %lu", + __PRETTY_FUNCTION__, lwpid); return; } - Cpu_thread_client cpu_thread(thread_cap); - cpu_thread.single_step(single_step); - cpu_thread.resume(); + cpu_thread->single_step(single_step); + cpu_thread->resume(); } -/* - * This function returns the first thread with a page fault that it finds. - * Multiple page-faulted threads are currently not supported. - */ - -unsigned long genode_find_segfault_lwpid() +void genode_fetch_registers(struct regcache *regcache, int regno) { + unsigned long reg_content = 0; - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); - - /* - * It can happen that the thread state of the thread which caused the - * page fault is not accessible yet. In that case, we'll retry until - * it is accessible. - */ - - while (1) { - - Thread_capability thread_cap = csc->first(); - - while (thread_cap.valid()) { - - try { - - Thread_state thread_state = Cpu_thread_client(thread_cap).state(); - - if (thread_state.unresolved_page_fault) { - - /* - * On base-foc it is necessary to pause the thread before - * IP and SP are available in the thread state. - */ - Cpu_thread_client(thread_cap).pause(); - - return csc->lwpid(thread_cap); - } - - } catch (Cpu_thread::State_access_failed) { } - - thread_cap = csc->next(thread_cap); + if (regno == -1) { + for (regno = 0; regno < the_low_target.num_regs; regno++) { + if (genode_fetch_register(regno, ®_content) == 0) + supply_register(regcache, regno, ®_content); + else + supply_register(regcache, regno, 0); } + } else { + if (genode_fetch_register(regno, ®_content) == 0) + supply_register(regcache, regno, ®_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, ®_content); + genode_store_register(regno, reg_content); + } + } + } else { + if ((size_t)register_size(regno) <= sizeof(reg_content)) { + collect_register(regcache, regno, ®_content); + genode_store_register(regno, reg_content); + } } } @@ -335,7 +602,7 @@ class Memory_model if (!local_base) { PWRN("Memory model: no memory at address %p", addr); - return 0; + throw No_memory_at_address(); } unsigned char value = @@ -350,7 +617,7 @@ class Memory_model void write(void *addr, unsigned char value) { if (verbose) - Genode::printf("write addr=%p, value=%x\n", addr, value); + Genode::printf("write addr=%p, value=%x\n", addr, value); Lock::Guard guard(_lock); @@ -363,7 +630,7 @@ class Memory_model if (!local_base) { PWRN("Memory model: no memory at address %p", addr); PWRN("(attempted to write %x)", (int)value); - return; + throw No_memory_at_address(); } local_base[offset_in_region] = value; @@ -376,7 +643,7 @@ class Memory_model */ static Memory_model *memory_model() { - static Memory_model inst(gdb_stub_thread()->region_map_component()); + static Memory_model inst(genode_child_resources()->region_map_component()); return &inst; } @@ -387,7 +654,55 @@ unsigned char genode_read_memory_byte(void *addr) } +int genode_read_memory(CORE_ADDR memaddr, unsigned char *myaddr, int len) +{ + if (verbose) + PDBG("genode_read_memory(%llx, %p, %d)", memaddr, myaddr, len); + + if (myaddr) + try { + for (int i = 0; i < len; i++) + myaddr[i] = genode_read_memory_byte((void*)((unsigned long)memaddr + i)); + } catch (No_memory_at_address) { + return EFAULT; + } + + return 0; +} + + void genode_write_memory_byte(void *addr, unsigned char value) { - return memory_model()->write(addr, value); + memory_model()->write(addr, value); +} + + +int genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +{ + if (verbose) + PDBG("genode_write_memory(%llx, %p, %d)", memaddr, myaddr, len); + + if (myaddr && (len > 0)) { + if (debug_threads) { + /* Dump up to four bytes. */ + unsigned int val = * (unsigned int *) myaddr; + if (len == 1) + val = val & 0xff; + else if (len == 2) + val = val & 0xffff; + else if (len == 3) + val = val & 0xffffff; + fprintf(stderr, "Writing %0*x to 0x%08lx", 2 * ((len < 4) ? len : 4), + val, (long)memaddr); + } + + for (int i = 0; i < len; i++) + try { + genode_write_memory_byte((void*)((unsigned long)memaddr + i), myaddr[i]); + } catch (No_memory_at_address) { + return EFAULT; + } + } + + return 0; } diff --git a/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.h b/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.h index 19fb10b37..7d69e9f2c 100644 --- a/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.h +++ b/repos/ports/src/app/gdb_monitor/gdbserver/genode-low.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -18,27 +18,29 @@ #ifndef GENODE_LOW_H #define GENODE_LOW_H +#include + #include "server.h" -int genode_signal_fd(); +/* exception type */ +struct No_memory_at_address { }; -void genode_wait_for_target_main_thread(); -void genode_detect_all_threads(); +/* interface for linux-low.c */ void genode_stop_all_threads(); -void genode_resume_all_threads(); - -ptid_t genode_wait_for_signal_or_gdb_interrupt(struct target_waitstatus *status); void genode_continue_thread(unsigned long lwpid, int single_step); -unsigned long genode_find_segfault_lwpid(); +int genode_kill(int pid); +int genode_detach(int pid); +void genode_fetch_registers(struct regcache *regcache, int regno); +void genode_store_registers(struct regcache *regcache, int regno); +int genode_read_memory(CORE_ADDR memaddr, unsigned char *myaddr, int len); +int genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len); + +/* interface for genode-low.cc and low.cc */ int genode_fetch_register(int regno, unsigned long *reg_content); void genode_store_register(int regno, unsigned long reg_content); unsigned char genode_read_memory_byte(void *addr); -void genode_write_memory_byte(void *addr, unsigned char value); - -int genode_detach(int pid); -int genode_kill(int pid); #endif /* GENODE_LOW_H */ diff --git a/repos/ports/src/app/gdb_monitor/gdbserver_genode.patch b/repos/ports/src/app/gdb_monitor/gdbserver_genode.patch index 30793a88c..5ddca3b25 100644 --- a/repos/ports/src/app/gdb_monitor/gdbserver_genode.patch +++ b/repos/ports/src/app/gdb_monitor/gdbserver_genode.patch @@ -4,92 +4,85 @@ From: Christian Prochaska --- - gdb/gdbserver/linux-arm-low.c | 4 + - gdb/gdbserver/linux-low.c | 223 ++++++++++++++++++++++++++++++++++------- - gdb/gdbserver/linux-low.h | 5 + - gdb/gdbserver/linux-x86-low.c | 43 +++++++- - gdb/gdbserver/remote-utils.c | 80 +++++++++++++++ - gdb/gdbserver/server.c | 52 ++++++++-- - gdb/gdbserver/server.h | 4 - - 7 files changed, 356 insertions(+), 55 deletions(-) + gdb/gdbserver/linux-arm-low.c | 13 +++++ + gdb/gdbserver/linux-low.c | 114 +++++++++++++++++++++++++++++++++++++++++ + gdb/gdbserver/linux-low.h | 2 + + gdb/gdbserver/linux-x86-low.c | 53 +++++++++++++++++++ + gdb/gdbserver/remote-utils.c | 12 ++++ + gdb/gdbserver/server.c | 30 +++++++++-- + gdb/gdbserver/server.h | 4 + + 7 files changed, 217 insertions(+), 11 deletions(-) diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c -index babb20c..d14c8cc 100644 +index babb20c..23d9e60 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c -@@ -25,6 +25,7 @@ +@@ -25,6 +25,9 @@ #ifndef ELFMAG0 #include #endif ++#ifdef __GENODE__ +#include ++#endif #include /* Defined in auto-generated files. */ -@@ -306,6 +307,7 @@ static void +@@ -209,7 +212,11 @@ static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 }; + is used for gdbserver, so single threaded debugging should work + OK, but for multi-threaded debugging we only insert the current + ABI's breakpoint instruction. For now at least. */ ++#ifdef __GENODE__ ++static const unsigned long arm_eabi_breakpoint = 0xe7ffdefe; ++#else + static const unsigned long arm_eabi_breakpoint = 0xe7f001f0; ++#endif + + static int + arm_breakpoint_at (CORE_ADDR where) +@@ -306,6 +313,11 @@ static void arm_arch_setup (void) { arm_hwcap = 0; -+#if 0 ++ ++#ifndef __GENODE__ ++ ++ /* Genode: 'init_registers_arm_with_*()' functions not generated */ ++ if (arm_get_hwcap (&arm_hwcap) == 0) { init_registers_arm (); -@@ -347,7 +349,7 @@ arm_arch_setup (void) +@@ -347,6 +359,7 @@ arm_arch_setup (void) return; } -- +#endif + /* The default configuration uses legacy FPA registers, probably simulated. */ - init_registers_arm (); diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c -index 81b8540..5b31da5 100644 +index e597e2f..62215fc 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c -@@ -19,6 +19,7 @@ - +@@ -20,6 +20,10 @@ #include "server.h" #include "linux-low.h" -+#include "genode-low.h" ++#ifdef __GENODE__ ++#include "genode-low.h" ++#endif ++ #include #include -@@ -281,6 +282,7 @@ elf_64_file_p (const char *file) - static void - delete_lwp (struct lwp_info *lwp) - { -+ if (debug_threads) printf("delete_lwp()\n"); - remove_thread (get_lwp_thread (lwp)); - remove_inferior (&all_lwps, &lwp->head); - free (lwp->arch_private); -@@ -535,6 +537,8 @@ get_stop_pc (struct lwp_info *lwp) - static void * - add_lwp (ptid_t ptid) - { -+ printf("add_lwp(%u, %lu, %lu)\n", ptid.pid, ptid.lwp, ptid.tid); -+ - struct lwp_info *lwp; - - lwp = (struct lwp_info *) xmalloc (sizeof (*lwp)); -@@ -547,6 +551,9 @@ add_lwp (ptid_t ptid) - - add_inferior_to_list (&all_lwps, &lwp->head); - -+ /* FIXME: this is not always true? */ -+ lwp->stopped = 1; -+ - return lwp; - } - -@@ -606,6 +613,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) + #include +@@ -606,6 +610,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) ptid_t ptid; struct lwp_info *new_lwp; -+#if 0 ++#ifndef __GENODE__ if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0) { if (!initial) -@@ -621,6 +629,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) +@@ -621,6 +626,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid, strerror (errno), errno); } @@ -97,40 +90,41 @@ index 81b8540..5b31da5 100644 if (initial) /* NOTE/FIXME: This lwp might have not been the tgid. */ -@@ -637,10 +646,11 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) +@@ -637,6 +643,9 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) new_lwp = (struct lwp_info *) add_lwp (ptid); add_thread (ptid, new_lwp); -+#if 0 ++#ifdef __GENODE__ ++ new_lwp->stopped = 1; ++#else /* We need to wait for SIGSTOP before being able to make the next ptrace call on this LWP. */ new_lwp->must_set_ptrace_flags = 1; -- +@@ -675,6 +684,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) + end of the list, and so the new thread has not yet reached + wait_for_sigstop (but will). */ + new_lwp->stop_expected = 1; +#endif - /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH - brings it to a halt. + } -@@ -689,6 +699,10 @@ linux_attach (unsigned long pid) + void +@@ -689,6 +699,7 @@ linux_attach (unsigned long pid) linux_attach_lwp_1 (pid, 1); linux_add_process (pid, 1); -+ /* must be called after 'add_thread()', because 'current_inferior' must be set */ -+ the_low_target.arch_setup(); -+ -+#if 0 ++#ifndef __GENODE__ if (!non_stop) { struct thread_info *thread; -@@ -698,7 +712,7 @@ linux_attach (unsigned long pid) +@@ -698,6 +709,7 @@ linux_attach (unsigned long pid) thread = find_thread_ptid (ptid_build (pid, pid, 0)); thread->last_resume_kind = resume_stop; } -- +#endif + return 0; } - -@@ -812,7 +826,11 @@ linux_kill (int pid) +@@ -812,7 +824,11 @@ linux_kill (int pid) return 0; } @@ -142,46 +136,53 @@ index 81b8540..5b31da5 100644 linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; -@@ -822,6 +840,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) +@@ -822,6 +838,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) if (ptid_get_pid (entry->id) != pid) return 0; -+#if 0 ++#ifndef __GENODE__ /* If this process is stopped but is expecting a SIGSTOP, then make sure we take care of that now. This isn't absolutely guaranteed to collect the SIGSTOP, but is fairly likely to. */ -@@ -833,13 +852,15 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) +@@ -833,13 +850,16 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) linux_resume_one_lwp (lwp, 0, 0, NULL); linux_wait_for_event (lwp->head.id, &wstat, __WALL); } -- +#endif + /* Flush any pending changes to the process's registers. */ regcache_invalidate_one ((struct inferior_list_entry *) get_lwp_thread (lwp)); -+#if 0 ++#ifndef __GENODE__ /* Finally, let it resume. */ ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0); +#endif delete_lwp (lwp); return 0; -@@ -2460,6 +2481,13 @@ async_file_mark (void) - be awakened anyway. */ - } +@@ -1071,6 +1091,10 @@ retry: -+static int mark_as_stopped(struct inferior_list_entry *entry, void *arg) -+{ -+ struct lwp_info *lwp = (struct lwp_info *) entry; -+ lwp->stopped = 1; -+ return 0; -+} -+ - static ptid_t - linux_wait (ptid_t ptid, - struct target_waitstatus *ourstatus, int target_options) -@@ -2469,18 +2497,28 @@ linux_wait (ptid_t ptid, + if (WIFSTOPPED (*wstatp) && WSTOPSIG (*wstatp) == SIGTRAP) + { ++#ifdef __GENODE__ ++ /* no watchpoint support yet */ ++ child->stopped_by_watchpoint = 0; ++#else + if (the_low_target.stopped_by_watchpoint == NULL) + { + child->stopped_by_watchpoint = 0; +@@ -1096,7 +1120,8 @@ retry: + + current_inferior = saved_inferior; + } +- } ++#endif ++ } + + /* Store the STOP_PC, with adjustment applied. This depends on the + architecture being defined already (so that CHILD has a valid +@@ -2469,18 +2494,22 @@ linux_wait (ptid_t ptid, if (debug_threads) fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid)); @@ -191,13 +192,7 @@ index 81b8540..5b31da5 100644 async_file_flush (); +#endif -+#ifdef __GENODE__ -+ /* TODO: get some information from wait_for_signal_or_gdb_interrupt() */ -+ event_ptid = genode_wait_for_signal_or_gdb_interrupt(ourstatus); -+ find_inferior (&all_lwps, mark_as_stopped, NULL); -+#else event_ptid = linux_wait_1 (ptid, ourstatus, target_options); -+#endif +#ifndef __GENODE__ /* If at least one stop was reported, there may be more. A single @@ -210,22 +205,23 @@ index 81b8540..5b31da5 100644 return event_ptid; } -@@ -2785,6 +2823,8 @@ static void - linux_resume_one_lwp (struct lwp_info *lwp, - int step, int signal, siginfo_t *info) - { -+ printf("linux_resume_one_lwp(step = %d, signal = %d)\n", step, signal); -+ - struct thread_info *saved_inferior; - int fast_tp_collecting; - -@@ -2958,10 +2998,15 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n", +@@ -2958,10 +2987,25 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n", lwp->stopped = 0; lwp->stopped_by_watchpoint = 0; lwp->stepping = step; + +#ifdef __GENODE__ ++ ++ /* ++ * On Linux, the thread would get stopped immediately after resuming ++ * if a SIGSTOP is pending. This is not the case on Genode, so we ++ * just keep the thread stopped. ++ */ ++ if (lwp->stop_expected) ++ return; ++ + genode_continue_thread(lwpid_of(lwp), step); ++ +#else ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), 0, /* Coerce to a uintptr_t first to avoid potential gcc warning @@ -235,325 +231,170 @@ index 81b8540..5b31da5 100644 current_inferior = saved_inferior; if (errno) -@@ -3325,6 +3370,8 @@ finish_step_over (struct lwp_info *lwp) - static int - linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) - { -+ if (debug_threads) printf("linux_resume_one_thread()\n"); -+ - struct lwp_info *lwp; - struct thread_info *thread; - int step; -@@ -3436,6 +3483,8 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) +@@ -5009,6 +5053,13 @@ linux_core_of_thread (ptid_t ptid) static void - linux_resume (struct thread_resume *resume_info, size_t n) + linux_process_qsupported (const char *query) { -+ if (debug_threads) printf("linux_resume(%zd)\n", n); -+ - struct thread_resume_array array = { resume_info, n }; - struct lwp_info *need_step_over = NULL; - int any_pending; -@@ -3484,6 +3533,8 @@ linux_resume (struct thread_resume *resume_info, size_t n) - - if (need_step_over) - start_step_over (need_step_over); -+ -+ if (debug_threads) printf("linux_resume() finished\n"); - } - - /* This function is called once per thread. We check the thread's -@@ -3958,6 +4009,26 @@ linux_fetch_registers (struct regcache *regcache, int regno) - #endif - } - -+static void -+genode_fetch_registers (struct regcache *regcache, int regno) -+{ -+ unsigned long reg_content = 0; -+ -+ if (regno == -1) { -+ for (regno = 0; regno < the_low_target.num_regs; regno++) { -+ if (genode_fetch_register(regno, ®_content) == 0) -+ supply_register(regcache, regno, ®_content); -+ else -+ supply_register(regcache, regno, 0); -+ } -+ } else { -+ if (genode_fetch_register(regno, ®_content) == 0) -+ supply_register(regcache, regno, ®_content); -+ else -+ supply_register(regcache, regno, 0); -+ } -+} -+ - void - linux_store_registers (struct regcache *regcache, int regno) - { -@@ -3970,6 +4041,28 @@ linux_store_registers (struct regcache *regcache, int regno) - #endif - } - -+void -+genode_store_registers (struct regcache *regcache, int regno) -+{ -+ if (debug_threads) printf("genode_store_registers(): regno = %d\n", regno); -+ -+ unsigned long reg_content = 0; -+ -+ if (regno == -1) { -+ for (regno = 0; regno < the_low_target.num_regs; regno++) { -+ if (register_size(regno) <= sizeof(reg_content)) { -+ collect_register(regcache, regno, ®_content); -+ genode_store_register(regno, reg_content); -+ } -+ } -+ } else { -+ if (register_size(regno) <= sizeof(reg_content)) { -+ collect_register(regcache, regno, ®_content); -+ genode_store_register(regno, reg_content); -+ } -+ } -+} -+ - - /* Copy LEN bytes from inferior's memory starting at MEMADDR - to debugger memory starting at MYADDR. */ -@@ -4040,6 +4133,17 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) - return 0; - } - -+static int -+genode_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) -+{ -+ int i; -+ if (debug_threads) printf("genode_read_memory(%llx, %p, %d)\n", memaddr, myaddr, len); -+ if (myaddr) -+ for (i = 0; i < len; i++) -+ myaddr[i] = genode_read_memory_byte((void*)(unsigned long)memaddr + i); -+ return 0; -+} -+ - /* Copy LEN bytes of data from debugger memory at MYADDR to inferior's - memory at MEMADDR. On failure (cannot write to the inferior) - returns the value of errno. */ -@@ -4121,6 +4225,34 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) - return 0; - } - -+static int -+genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) -+{ -+ int i; -+ -+ if (debug_threads) -+ printf("genode_write_memory(%llx, %p, %d)\n", 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\n", 2 * ((len < 4) ? len : 4), -+ val, (long)memaddr); -+ } -+ for (i = 0; i < len; i++) -+ genode_write_memory_byte((void*)(unsigned long)memaddr + i, myaddr[i]); -+ } -+ return 0; -+} -+ - /* Non-zero if the kernel supports PTRACE_O_TRACEFORK. */ - static int linux_supports_tracefork_flag; - -@@ -4296,6 +4428,10 @@ linux_look_up_symbols (void) - static void - linux_request_interrupt (void) - { -+ /* FIXME: currently all threads get interrupted */ ++#ifdef __GENODE__ ++ /* ++ * 'qSupported' is the first command sent by GDB when attaching to the ++ * server, so when at this location, GDB has just (re-)attached itself. ++ */ + genode_stop_all_threads(); -+ -+#if 0 - extern unsigned long signal_pid; - - if (!ptid_equal (cont_thread, null_ptid) -@@ -4306,10 +4442,19 @@ linux_request_interrupt (void) - - lwp = get_thread_lwp (current_inferior); - lwpid = lwpid_of (lwp); -+#ifdef __GENODE__ -+ genode_interrupt_thread(lwpid); -+#else - kill_lwp (lwpid, SIGINT); -+#endif /* __GENODE__ */ - } - else -- kill_lwp (signal_pid, SIGINT); -+#ifdef __GENODE__ -+ genode_interrupt_thread(lwpid); -+#else -+ kill_lwp (lwpid, SIGINT); -+#endif /* __GENODE__ */ +#endif + if (the_low_target.process_qsupported != NULL) + the_low_target.process_qsupported (query); } - - /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET -@@ -5108,28 +5253,28 @@ linux_emit_ops (void) - } - +@@ -5110,26 +5161,56 @@ linux_emit_ops (void) static struct target_ops linux_target_ops = { -- linux_create_inferior, -+ /*linux_create_inferior*/NULL, + linux_create_inferior, linux_attach, -- linux_kill, -- linux_detach, -- linux_mourn, -- linux_join, ++#ifndef __GENODE__ + linux_kill, + linux_detach, + linux_mourn, + linux_join, ++#else + genode_kill, + genode_detach, -+ /*linux_mourn*/NULL, -+ /*linux_join*/NULL, ++ NULL, ++ NULL, ++#endif linux_thread_alive, linux_resume, linux_wait, -- linux_fetch_registers, -- linux_store_registers, ++#ifndef __GENODE__ + linux_fetch_registers, + linux_store_registers, ++#else + genode_fetch_registers, + genode_store_registers, ++#endif linux_prepare_to_access_memory, linux_done_accessing_memory, -- linux_read_memory, -- linux_write_memory, -- linux_look_up_symbols, ++#ifndef __GENODE__ + linux_read_memory, + linux_write_memory, ++#else + genode_read_memory, + genode_write_memory, -+ /*linux_look_up_symbols*/NULL, ++#endif ++#ifndef __GENODE__ + linux_look_up_symbols, ++#else ++ NULL, ++#endif linux_request_interrupt, -- linux_read_auxv, -+ /*linux_read_auxv*/NULL, ++#ifndef __GENODE__ + linux_read_auxv, ++#else ++ NULL, ++#endif linux_insert_point, linux_remove_point, -- linux_stopped_by_watchpoint, -- linux_stopped_data_address, -+ /*linux_stopped_by_watchpoint*/NULL, -+ /*linux_stopped_data_address*/NULL, ++#ifndef __GENODE__ + linux_stopped_by_watchpoint, + linux_stopped_data_address, ++#else ++ NULL, ++ NULL, ++#endif #if defined(__UCLIBC__) && defined(HAS_NOMMU) linux_read_offsets, #else -@@ -5140,32 +5285,32 @@ static struct target_ops linux_target_ops = { +@@ -5140,6 +5221,7 @@ static struct target_ops linux_target_ops = { #else NULL, #endif -- linux_qxfer_spu, -- hostio_last_error_from_errno, -- linux_qxfer_osdata, -- linux_xfer_siginfo, -- linux_supports_non_stop, -- linux_async, -- linux_start_non_stop, -- linux_supports_multi_process, -+ /*linux_qxfer_spu*/NULL, -+ /*hostio_last_error_from_errno*/NULL, -+ /*linux_qxfer_osdata*/NULL, -+ /*linux_xfer_siginfo*/NULL, -+ /*linux_supports_non_stop*/NULL, -+ /*linux_async*/NULL, -+ /*linux_start_non_stop*/NULL, -+ /*linux_supports_multi_process*/NULL, ++#ifndef __GENODE__ + linux_qxfer_spu, + hostio_last_error_from_errno, + linux_qxfer_osdata, +@@ -5148,13 +5230,28 @@ static struct target_ops linux_target_ops = { + linux_async, + linux_start_non_stop, + linux_supports_multi_process, ++#else ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++#endif #ifdef USE_THREAD_DB thread_db_handle_monitor_command, #else NULL, #endif -- linux_core_of_thread, -- linux_process_qsupported, -- linux_supports_tracepoints, -- linux_read_pc, -- linux_write_pc, -- linux_thread_stopped, -+ /*linux_core_of_thread*/NULL, -+ /*linux_process_qsupported*/NULL, -+ /*linux_supports_tracepoints*/NULL, -+ /*linux_read_pc*/NULL, -+ /*linux_write_pc*/NULL, -+ /*linux_thread_stopped*/NULL, - NULL, -- linux_pause_all, -- linux_unpause_all, -- linux_cancel_breakpoints, -- linux_stabilize_threads, -- linux_install_fast_tracepoint_jump_pad, -- linux_emit_ops -+ /*linux_pause_all*/NULL, -+ /*linux_unpause_all*/NULL, -+ /*linux_cancel_breakpoints*/NULL, -+ /*linux_stabilize_threads*/NULL, -+ /*linux_install_fast_tracepoint_jump_pad*/NULL, -+ /*linux_emit_ops*/NULL ++#ifndef __GENODE__ + linux_core_of_thread, ++#else ++ NULL, ++#endif + linux_process_qsupported, ++#ifndef __GENODE__ + linux_supports_tracepoints, + linux_read_pc, + linux_write_pc, +@@ -5166,6 +5263,19 @@ static struct target_ops linux_target_ops = { + linux_stabilize_threads, + linux_install_fast_tracepoint_jump_pad, + linux_emit_ops ++#else ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++#endif }; static void -@@ -5181,11 +5326,14 @@ linux_init_signals () - void - initialize_low (void) - { -+#if 0 - struct sigaction sigchld_action; - memset (&sigchld_action, 0, sizeof (sigchld_action)); -+#endif - set_target_ops (&linux_target_ops); +@@ -5187,7 +5297,9 @@ initialize_low (void) set_breakpoint_data (the_low_target.breakpoint, the_low_target.breakpoint_len); -+#if 0 linux_init_signals (); ++#ifndef __GENODE__ linux_test_for_tracefork (); - #ifdef HAVE_LINUX_REGSETS -@@ -5198,4 +5346,5 @@ initialize_low (void) - sigemptyset (&sigchld_action.sa_mask); - sigchld_action.sa_flags = SA_RESTART; - sigaction (SIGCHLD, &sigchld_action, NULL); +#endif - } + #ifdef HAVE_LINUX_REGSETS + for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++) + ; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h -index 6635bc6..ae172bd 100644 +index d449e1b..0bbcbfd 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h -@@ -21,7 +21,7 @@ - #include +@@ -22,7 +22,9 @@ #endif --#include "gdb_proc_service.h" -+//#include "gdb_proc_service.h" + #include ++#ifndef __GENODE__ + #include "gdb_proc_service.h" ++#endif #ifdef HAVE_LINUX_REGSETS typedef void (*regset_fill_func) (struct regcache *, void *); -@@ -56,6 +56,9 @@ struct process_info_private - /* libthread_db-specific additions. Not NULL if this process has loaded - thread_db, and it is active. */ - struct thread_db *thread_db; -+ -+ /* Genode-specific additions */ -+ void *gdb_stub_thread; - }; - - struct lwp_info; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c -index 69c6b57..cffa803 100644 +index 82dcf83..e98e3bd 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c -@@ -28,8 +28,15 @@ +@@ -28,8 +28,17 @@ #include "i386-xstate.h" #include "elf/common.h" --#include "gdb_proc_service.h" -- -+//#include "gdb_proc_service.h" -+ ++#ifndef __GENODE__ + #include "gdb_proc_service.h" ++#endif + +#ifdef __GENODE__ +/* Defined in auto-generated file i386.c. */ +void init_registers_i386 (void); @@ -564,7 +405,7 @@ index 69c6b57..cffa803 100644 /* Defined in auto-generated file i386-linux.c. */ void init_registers_i386_linux (void); /* Defined in auto-generated file amd64-linux.c. */ -@@ -40,11 +47,22 @@ void init_registers_i386_avx_linux (void); +@@ -40,10 +49,24 @@ void init_registers_i386_avx_linux (void); void init_registers_amd64_avx_linux (void); /* Defined in auto-generated file i386-mmx-linux.c. */ void init_registers_i386_mmx_linux (void); @@ -574,36 +415,38 @@ index 69c6b57..cffa803 100644 /* Backward compatibility for gdb without XML support. */ +#ifdef __GENODE__ ++ +static const char *xmltarget_i386_linux_no_xml = "@\ +i386\ +"; - ++ +#ifdef __x86_64__ +static const char *xmltarget_amd64_linux_no_xml = "@\ +i386:x86-64\ +"; +#endif ++ +#else + static const char *xmltarget_i386_linux_no_xml = "@\ i386\ - GNU/Linux\ -@@ -56,8 +74,15 @@ static const char *xmltarget_amd64_linux_no_xml = "@\ - GNU/Linux\ +@@ -57,7 +80,15 @@ static const char *xmltarget_amd64_linux_no_xml = "@\ "; #endif -+#endif /* __GENODE__ */ ++#endif /* __GENODE__ */ ++ +#ifdef __GENODE__ +#ifndef __x86_64__ +#include "i386.h" +#endif /* __x86_64__ */ +#else #include -+#endif /* __GENODE__ */ ++#endif #include #include #include -@@ -273,8 +298,10 @@ x86_fill_gregset (struct regcache *regcache, void *buf) +@@ -273,8 +304,10 @@ x86_fill_gregset (struct regcache *regcache, void *buf) for (i = 0; i < I386_NUM_REGS; i++) collect_register (regcache, i, ((char *) buf) + i386_regmap[i]); @@ -614,7 +457,7 @@ index 69c6b57..cffa803 100644 } static void -@@ -295,8 +322,10 @@ x86_store_gregset (struct regcache *regcache, const void *buf) +@@ -295,8 +328,10 @@ x86_store_gregset (struct regcache *regcache, const void *buf) for (i = 0; i < I386_NUM_REGS; i++) supply_register (regcache, i, ((char *) buf) + i386_regmap[i]); @@ -625,7 +468,7 @@ index 69c6b57..cffa803 100644 } static void -@@ -414,7 +443,15 @@ x86_set_pc (struct regcache *regcache, CORE_ADDR pc) +@@ -414,7 +449,15 @@ x86_set_pc (struct regcache *regcache, CORE_ADDR pc) } } @@ -641,180 +484,91 @@ index 69c6b57..cffa803 100644 #define x86_breakpoint_len 1 static int -@@ -2576,7 +2613,7 @@ struct linux_target_ops the_low_target = +@@ -423,7 +466,7 @@ x86_breakpoint_at (CORE_ADDR pc) + unsigned char c; + + (*the_target->read_memory) (pc, &c, 1); +- if (c == 0xCC) ++ if (c == x86_breakpoint[0]) + return 1; + + return 0; +@@ -2561,7 +2604,11 @@ struct linux_target_ops the_low_target = + x86_breakpoint, + x86_breakpoint_len, + NULL, ++#ifndef __GENODE__ + 1, ++#else ++ 0, /* With the HLT instruction, the PC does not get incremented */ ++#endif + x86_breakpoint_at, + x86_insert_point, + x86_remove_point, +@@ -2576,7 +2623,11 @@ struct linux_target_ops the_low_target = x86_siginfo_fixup, x86_linux_new_process, x86_linux_new_thread, -- x86_linux_prepare_to_resume, -+ /*x86_linux_prepare_to_resume*/NULL, ++#ifndef __GENODE__ + x86_linux_prepare_to_resume, ++#else ++ NULL, ++#endif x86_linux_process_qsupported, x86_supports_tracepoints, x86_get_thread_area, diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c -index 650ddf8..728da30 100644 +index 650ddf8..7a53e77 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c -@@ -18,11 +18,14 @@ - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -+#include "genode-low.h" -+ +@@ -21,6 +21,12 @@ #include "server.h" #include "terminal.h" #include "target.h" - #include - #include -+#include - #if HAVE_SYS_IOCTL_H - #include - #endif -@@ -171,7 +174,6 @@ handle_accept_event (int err, gdb_client_data client_data) - - #ifndef USE_WIN32API - close (listen_desc); /* No longer need this */ -- - signal (SIGPIPE, SIG_IGN); /* If we don't do this, then gdbserver simply - exits when the remote side dies. */ - #else -@@ -186,6 +188,12 @@ handle_accept_event (int err, gdb_client_data client_data) - - enable_async_notification (remote_desc); - -+ /* stop all threads */ -+ genode_stop_all_threads(); -+ -+ /* find all existing threads and tell gdbserver about it */ -+ genode_detect_all_threads(); -+ - /* Register the event loop handler. */ - add_file_handler (remote_desc, handle_serial_event, NULL); - -@@ -280,6 +288,14 @@ remote_open (char *name) - - /* Register the event loop handler. */ - add_file_handler (remote_desc, handle_serial_event, NULL); + +#ifdef __GENODE__ -+ /* FIXME: find better place */ -+ genode_stop_all_threads(); -+ /* find all existing threads and tell gdbserver about it */ -+ genode_detect_all_threads(); ++#include ++#include "genode-low.h" +#endif + - #endif /* USE_WIN32API */ - } - else -@@ -857,6 +873,68 @@ input_interrupt (int unused) - } - } + #include + #include + #if HAVE_SYS_IOCTL_H +@@ -106,8 +112,10 @@ struct sym_cache -+ -+ptid_t -+genode_wait_for_signal_or_gdb_interrupt (struct target_waitstatus *status) -+{ -+ printf("genode_wait_for_signal_or_gdb_interrupt\n"); -+ -+ ptid_t event_ptid; -+ -+ fd_set readset; -+ -+ FD_ZERO (&readset); -+ FD_SET (remote_desc, &readset); -+ FD_SET (genode_signal_fd(), &readset); -+ -+ while(1) { -+ if (select ((remote_desc > genode_signal_fd() ? remote_desc : genode_signal_fd()) + 1, &readset, 0, 0, NULL) > 0) -+ { -+ if (debug_threads) printf("select() returned\n"); -+ int cc; -+ char c = 0; -+ if (FD_ISSET(remote_desc, &readset)) { -+ /* received input from GDB */ -+ cc = read (remote_desc, &c, 1); -+ -+ if (cc == 1 && c == '\003' && current_inferior != NULL) { -+ (*the_target->request_interrupt) (); -+ event_ptid = current_inferior->entry.id; -+ status->kind = TARGET_WAITKIND_STOPPED; -+ status->value.sig = TARGET_SIGNAL_INT; -+ return event_ptid; -+ } else -+ { -+ fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n", -+ cc, c, c); -+ } -+ } else { -+ /* received a signal */ -+ unsigned long sig; -+ read(genode_signal_fd(), &sig, sizeof(sig)); -+ printf("received signal %ld\n", sig); -+ if (current_inferior == NULL) continue; -+ -+ event_ptid.pid = GENODE_LWP_BASE; -+ event_ptid.tid = 0; -+ genode_stop_all_threads(); -+ -+ if (sig > 0) { -+ event_ptid.lwp = sig; -+ status->kind = TARGET_WAITKIND_STOPPED; -+ status->value.sig = TARGET_SIGNAL_TRAP; -+ } else { -+ event_ptid.lwp = genode_find_segfault_lwpid(); -+ status->kind = TARGET_WAITKIND_STOPPED; -+ status->value.sig = TARGET_SIGNAL_SEGV; -+ } -+ return event_ptid; -+ } -+ } -+ } -+} -+ -+ - /* Check if the remote side sent us an interrupt request (^C). */ - void - check_remote_input_interrupt_request (void) + int remote_debug = 0; + struct ui_file *gdb_stdlog; +- +-static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR; ++#ifndef __GENODE__ ++static ++#endif ++gdb_fildes_t remote_desc = INVALID_DESCRIPTOR; + static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR; + + /* FIXME headerize? */ diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c -index 2f4484f..79c89d4 100644 +index 2f4484f..124c98d 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c -@@ -18,8 +18,13 @@ - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ +@@ -20,6 +20,11 @@ -+ -+#include "genode-low.h" -+ #include "server.h" ++#ifdef __GENODE__ ++#include "genode-low.h" +#include "linux-low.h" ++#endif + #if HAVE_UNISTD_H #include #endif -@@ -47,7 +52,7 @@ static char **program_argv, **wrapper_argv; - - /* Enable miscellaneous debugging output. The name is historical - it - was originally used to debug LinuxThreads support. */ --int debug_threads; -+int debug_threads = 0; - - /* Enable debugging of h/w breakpoint/watchpoint support. */ - int debug_hw_points; -@@ -1740,6 +1745,7 @@ static void gdb_wants_all_threads_stopped (void); - void - handle_v_cont (char *own_buf) - { -+ if (debug_threads) printf("handle_v_cont()\n"); - char *p, *q; - int n = 0, i = 0; - struct thread_resume *resume_info; -@@ -2055,11 +2061,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) +@@ -2055,11 +2060,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) return; } } - -+#if 0 ++#ifndef __GENODE__ if (strncmp (own_buf, "vFile:", 6) == 0 && handle_vFile (own_buf, packet_len, new_packet_len)) return; @@ -823,120 +577,43 @@ index 2f4484f..79c89d4 100644 if (strncmp (own_buf, "vAttach;", 8) == 0) { if (!multi_process && target_running ()) -@@ -2114,6 +2120,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) - static void - myresume (char *own_buf, int step, int sig) - { -+ if (debug_threads) printf("myresume()\n"); - struct thread_resume resume_info[2]; - int n = 0; - int valid_cont_thread; -@@ -2250,6 +2257,7 @@ gdb_reattached_process (struct inferior_list_entry *entry) - static void - handle_status (char *own_buf) - { -+ if (debug_threads) printf("handle_status()\n"); - /* GDB is connected, don't forward events to the target anymore. */ - for_each_inferior (&all_processes, gdb_reattached_process); - -@@ -2286,7 +2294,7 @@ handle_status (char *own_buf) - strcpy (own_buf, "W00"); - } - } -- -+#if 0 - static void - gdbserver_version (void) - { -@@ -2328,7 +2336,7 @@ gdbserver_show_disableable (FILE *stream) - "T stop reply packet\n" - " threads \tAll of the above\n"); - } -- -+#endif - - #undef require_running - #define require_running(BUF) \ -@@ -2449,8 +2457,9 @@ join_inferiors_callback (struct inferior_list_entry *entry) +@@ -2449,7 +2454,11 @@ join_inferiors_callback (struct inferior_list_entry *entry) } int --main (int argc, char *argv[]) -+gdbserver_main(char *port, void *gdb_stub_thread) ++#ifdef __GENODE__ ++gdbserver_main (int argc, char *argv[]) ++#else + main (int argc, char *argv[]) ++#endif { -+#if 0 int bad_attach; int pid; - char *arg_end, *port; -@@ -2584,7 +2593,7 @@ main (int argc, char *argv[]) - gdbserver_usage (stderr); - exit (1); - } -- -+#endif - initialize_inferiors (); - initialize_async_io (); - initialize_low (); -@@ -2594,6 +2603,7 @@ main (int argc, char *argv[]) - own_buf = xmalloc (PBUFSIZ + 1); - mem_buf = xmalloc (PBUFSIZ); - -+#if 0 - if (pid == 0 && *next_arg != NULL) - { - int i, n; -@@ -2647,6 +2657,12 @@ main (int argc, char *argv[]) - fprintf (stderr, "No program to debug. GDBserver exiting.\n"); - exit (1); - } -+#endif -+ -+#ifdef __GENODE__ -+ /* wait until the target's main thread is ready */ -+ genode_wait_for_target_main_thread(); -+#endif - - while (1) - { -@@ -2655,6 +2671,15 @@ main (int argc, char *argv[]) - /* Be sure we're out of tfind mode. */ - current_traceframe = -1; - -+#ifdef __GENODE__ -+ /* attach to child */ -+ myattach(GENODE_LWP_BASE); -+ signal_pid = GENODE_LWP_BASE; -+ struct process_info *pi = current_process(); -+ struct process_info_private *pip = pi->private; -+ pip->gdb_stub_thread = gdb_stub_thread; -+#endif -+ - remote_open (port); - - if (setjmp (toplevel) != 0) -@@ -2755,6 +2780,7 @@ process_serial_event (void) +@@ -2754,6 +2763,9 @@ process_serial_event (void) + response_needed = 1; i = 0; ++#ifdef __GENODE ++ if (debug_threads) printf("GDB command = %s\n", own_buf); ++#endif ch = own_buf[i++]; -+ //if (debug_threads) printf("GDB command = %s\n", own_buf); switch (ch) { - case 'q': -@@ -2844,7 +2870,9 @@ process_serial_event (void) +@@ -2844,7 +2856,9 @@ process_serial_event (void) gone. */ for_each_inferior (&all_processes, join_inferiors_callback); -+#if 0 ++#ifndef __GENODE__ exit (0); +#endif } } break; -@@ -3076,7 +3104,11 @@ process_serial_event (void) +@@ -3076,7 +3090,11 @@ process_serial_event (void) return 0; } else -+#if 0 ++#ifndef __GENODE__ exit (0); +#else + return 0; @@ -944,12 +621,14 @@ index 2f4484f..79c89d4 100644 case 'T': { -@@ -3140,14 +3172,14 @@ process_serial_event (void) +@@ -3140,14 +3158,16 @@ process_serial_event (void) own_buf[0] = '\0'; break; } - ++#ifdef __GENODE__ + if (debug_threads) printf("GDBserver response = %s\n", own_buf); ++#endif if (new_packet_len != -1) putpkt_binary (own_buf, new_packet_len); else @@ -957,11 +636,11 @@ index 2f4484f..79c89d4 100644 response_needed = 0; - -+#if 0 ++#ifndef __GENODE__ if (!extended_protocol && have_ran && !target_running ()) { /* In non-stop, defer exiting until GDB had a chance to query -@@ -3159,7 +3191,7 @@ process_serial_event (void) +@@ -3159,7 +3179,7 @@ process_serial_event (void) exit (0); } } diff --git a/repos/ports/src/app/gdb_monitor/genode_child_resources.h b/repos/ports/src/app/gdb_monitor/genode_child_resources.h new file mode 100644 index 000000000..a0da1c84e --- /dev/null +++ b/repos/ports/src/app/gdb_monitor/genode_child_resources.h @@ -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_ */ diff --git a/repos/ports/src/app/gdb_monitor/main.cc b/repos/ports/src/app/gdb_monitor/main.cc index 156b5ad19..e6bc869c1 100644 --- a/repos/ports/src/app/gdb_monitor/main.cc +++ b/repos/ports/src/app/gdb_monitor/main.cc @@ -5,29 +5,12 @@ */ /* - * Copyright (C) 2010-2013 Genode Labs GmbH + * Copyright (C) 2010-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include "app_child.h" -#include "rom.h" - -using namespace Genode; -using namespace Gdb_monitor; /* * Suppress messages of libc dummy functions @@ -36,92 +19,21 @@ extern "C" int _sigaction() { return -1; } extern "C" int getpid() { return -1; } extern "C" int sigprocmask() { return -1; } extern "C" int _sigprocmask() { return -1; } +extern "C" int sigsuspend() { return -1; } +/* + * version.c + */ +extern "C" const char version[] = "7.3.1"; +extern "C" const char host_name[] = ""; + + +extern "C" int gdbserver_main(int argc, const char *argv[]); int main() { - /* look for dynamic linker */ - Dataspace_capability ldso_ds; - try { - Rom_connection ldso_rom("ld.lib.so"); - ldso_ds = clone_rom(ldso_rom.dataspace()); - } catch (...) { - PDBG("ld.lib.so not found"); - } + int argc = 3; + const char *argv[] = { "gdbserver", "/dev/terminal", "target", 0 }; - /* extract target filename from config file */ - - static char filename[32] = ""; - - try { - config()->xml_node().sub_node("target").attribute("name").value(filename, sizeof(filename)); - } catch (Xml_node::Nonexistent_sub_node) { - PERR("Error: Missing '' sub node."); - return -1; - } catch (Xml_node::Nonexistent_attribute) { - PERR("Error: Missing 'name' attribute of '' 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 config node"); - return -1; - } - - Number_of_bytes ram_quota = env()->ram_session()->avail() - preserved_ram_quota; - - /* start the application */ - char *unique_name = filename; - Capability 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 elf_cap = clone_rom(file_cap); - - /* create ram session for child with some of our own quota */ - static Ram_connection ram; - ram.ref_account(env()->ram_session_cap()); - env()->ram_session()->transfer_quota(ram.cap(), (Genode::size_t)ram_quota - elf_size); - - /* cap session for allocating capabilities for parent interfaces */ - static Cap_connection cap_session; - - static Service_registry parent_services; - - enum { CHILD_ROOT_EP_STACK = 4096 }; - static Rpc_entrypoint child_root_ep(&cap_session, CHILD_ROOT_EP_STACK, - "child_root_ep"); - - new (env()->heap()) App_child(unique_name, - elf_cap, - ldso_ds, - ram.cap(), - &cap_session, - &parent_services, - &child_root_ep, - target_node); - sleep_forever(); - - return 0; + return gdbserver_main(argc, argv); } diff --git a/repos/ports/src/app/gdb_monitor/pd_session_component.h b/repos/ports/src/app/gdb_monitor/pd_session_component.h index e74653965..d62ecc218 100644 --- a/repos/ports/src/app/gdb_monitor/pd_session_component.h +++ b/repos/ports/src/app/gdb_monitor/pd_session_component.h @@ -18,9 +18,15 @@ #include #include -using namespace Genode; +/* GDB monitor includes */ +#include "region_map_component.h" -class Pd_session_component : public Rpc_object +namespace Gdb_monitor { + class Pd_session_component; + using namespace Genode; +} + +class Gdb_monitor::Pd_session_component : public Rpc_object { private: @@ -41,9 +47,9 @@ class Pd_session_component : public Rpc_object Dataspace_pool &managed_ds_map) : _ep(ep), _pd(binary_name), - _address_space(_ep, managed_ds_map, _pd.address_space()), - _stack_area (_ep, managed_ds_map, _pd.stack_area()), - _linker_area (_ep, managed_ds_map, _pd.linker_area()) + _address_space(_ep, managed_ds_map, _pd, _pd.address_space()), + _stack_area (_ep, managed_ds_map, _pd, _pd.stack_area()), + _linker_area (_ep, managed_ds_map, _pd, _pd.linker_area()) { _ep.manage(this); } @@ -54,11 +60,12 @@ class Pd_session_component : public Rpc_object } /** - * Accessor used to let the GDB stub thread access the PD's address + * Accessor used to let the GDB monitor access the PD's address * space */ Region_map_component ®ion_map() { return _address_space; } + Pd_session_capability core_pd_cap() { return _pd.cap(); } /************************** ** Pd_session interface ** diff --git a/repos/ports/src/app/gdb_monitor/ram_root.h b/repos/ports/src/app/gdb_monitor/ram_root.h index 30216861b..2478767a1 100644 --- a/repos/ports/src/app/gdb_monitor/ram_root.h +++ b/repos/ports/src/app/gdb_monitor/ram_root.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -18,31 +18,30 @@ #include "ram_session_component.h" -namespace Genode { +namespace Gdb_monitor { class Ram_root; } - class Ram_root : public Root_component - { - protected: +class Gdb_monitor::Ram_root : public Root_component +{ + protected: - Ram_session_component *_create_session(const char *args) - { - return new (md_alloc()) - Ram_session_component(args); - } + Ram_session_component *_create_session(const char *args) + { + return new (md_alloc()) + Ram_session_component(args); + } - public: + public: - /** - * Constructor - * - * \param session_ep entry point for managing ram session objects - * \param md_alloc meta-data allocator to be used by root component - */ - Ram_root(Rpc_entrypoint *session_ep, - Allocator *md_alloc) - : Root_component(session_ep, md_alloc) - { } - }; -} + /** + * Constructor + * + * \param session_ep entry point for managing ram session objects + * \param md_alloc meta-data allocator to be used by root component + */ + Ram_root(Rpc_entrypoint *session_ep, + Allocator *md_alloc) + : Root_component(session_ep, md_alloc) + { } +}; #endif /* _RAM_ROOT_H_ */ diff --git a/repos/ports/src/app/gdb_monitor/ram_session_component.cc b/repos/ports/src/app/gdb_monitor/ram_session_component.cc index 538e1a541..d5c18ab76 100644 --- a/repos/ports/src/app/gdb_monitor/ram_session_component.cc +++ b/repos/ports/src/app/gdb_monitor/ram_session_component.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -18,7 +18,7 @@ #include "ram_session_component.h" using namespace Genode; - +using namespace Gdb_monitor; Ram_session_component::Ram_session_component(const char *args) : _parent_ram_session(env()->parent()->session(args)) diff --git a/repos/ports/src/app/gdb_monitor/ram_session_component.h b/repos/ports/src/app/gdb_monitor/ram_session_component.h index b69b6011f..69fc7002c 100644 --- a/repos/ports/src/app/gdb_monitor/ram_session_component.h +++ b/repos/ports/src/app/gdb_monitor/ram_session_component.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -18,9 +18,13 @@ #include #include -using namespace Genode; +namespace Gdb_monitor +{ + class Ram_session_component; + using namespace Genode; +} -class Ram_session_component : public Rpc_object +class Gdb_monitor::Ram_session_component : public Rpc_object { private: diff --git a/repos/ports/src/app/gdb_monitor/region_map_component.cc b/repos/ports/src/app/gdb_monitor/region_map_component.cc index 24948215d..ccb7eb525 100644 --- a/repos/ports/src/app/gdb_monitor/region_map_component.cc +++ b/repos/ports/src/app/gdb_monitor/region_map_component.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -15,19 +15,19 @@ #include #include #include +#include /* local includes */ #include "region_map_component.h" static bool const verbose = false; -using namespace Gdb_monitor; -using namespace Genode; - -/************************** +/************************************** ** Region map component ** - **************************/ + **************************************/ + +using namespace Gdb_monitor; Region_map_component::Region *Region_map_component::find_region(void *local_addr, addr_t *offset_in_region) { @@ -140,13 +140,16 @@ Dataspace_capability Region_map_component::dataspace() Region_map_component::Region_map_component(Rpc_entrypoint &ep, Dataspace_pool &managed_ds_map, + Pd_session_capability pd, Capability parent_region_map) : _ep(ep), + _pd(pd), _parent_region_map(parent_region_map), _managed_ds_map(managed_ds_map) { _ep.manage(this); + if (verbose) PDBG("Region_map_component()"); } diff --git a/repos/ports/src/app/gdb_monitor/region_map_component.h b/repos/ports/src/app/gdb_monitor/region_map_component.h index 7e6c3c141..7c63127e4 100644 --- a/repos/ports/src/app/gdb_monitor/region_map_component.h +++ b/repos/ports/src/app/gdb_monitor/region_map_component.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2006-2013 Genode Labs GmbH + * Copyright (C) 2006-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -16,8 +16,9 @@ #define _REGION_MAP_COMPONENT_H_ /* Genode includes */ -#include #include +#include +#include /* GDB monitor includes */ #include "dataspace_object.h" @@ -32,6 +33,8 @@ namespace Gdb_monitor { Rpc_entrypoint &_ep; + Pd_session_capability _pd; + Genode::Region_map_client _parent_region_map; public: @@ -75,8 +78,9 @@ namespace Gdb_monitor { /** * Constructor */ - Region_map_component(Rpc_entrypoint &ep, - Dataspace_pool &managed_ds_map, + Region_map_component(Rpc_entrypoint &ep, + Dataspace_pool &managed_ds_map, + Pd_session_capability pd, Capability parent_region_map); ~Region_map_component(); diff --git a/repos/ports/src/app/gdb_monitor/rom.h b/repos/ports/src/app/gdb_monitor/rom.h index 1df8a6022..1a489aada 100644 --- a/repos/ports/src/app/gdb_monitor/rom.h +++ b/repos/ports/src/app/gdb_monitor/rom.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -16,111 +16,118 @@ /* Genode includes */ #include +#include #include -#include +#include #include -namespace Gdb_monitor { - +namespace Gdb_monitor +{ + class Rom_session_component; + class Rom_root; + class Rom_service; using namespace Genode; - - /** - * Clone a ROM dataspace in RAM - */ - Capability clone_rom(Capability rom_cap) - { - Genode::size_t rom_size = Dataspace_client(rom_cap).size(); - Capability clone_cap = env()->ram_session()->alloc(rom_size); - - if (!clone_cap.valid()) { - PERR("%s: memory allocation for cloned dataspace failed", __func__); - return Capability(); - } - - 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 - { - private: - - Capability _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 dataspace() - { - return static_cap_cast( - static_cap_cast(_clone_cap)); - } - - void release() { } - - void sigh(Genode::Signal_context_capability) { } - }; - - - class Rom_root : public Root_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(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(char const *args, Affinity const &affinity) { - return _root.session(args, affinity); } - - void upgrade(Capability, char const *) { } - - void close(Capability cap) { _root.close(cap); } - }; } +/** + * Clone a ROM dataspace in RAM + */ +static Genode::Capability +clone_rom(Genode::Capability rom_cap) +{ + using namespace Genode; + + Genode::size_t rom_size = Dataspace_client(rom_cap).size(); + Capability clone_cap = env()->ram_session()->alloc(rom_size); + + if (!clone_cap.valid()) { + PERR("%s: memory allocation for cloned dataspace failed", __func__); + return Capability(); + } + + 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 +{ + private: + + Capability _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 dataspace() + { + return static_cap_cast( + static_cap_cast(_clone_cap)); + } + + void release() { } + + void sigh(Genode::Signal_context_capability) { } +}; + + +class Gdb_monitor::Rom_root : public Root_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(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(char const *args, Affinity const &affinity) { + return _root.session(args, affinity); } + + void upgrade(Capability, char const *) { } + + void close(Capability cap) { _root.close(cap); } +}; + #endif /* _ROM_H_ */ diff --git a/repos/ports/src/app/gdb_monitor/siginfo.patch b/repos/ports/src/app/gdb_monitor/siginfo.patch new file mode 100644 index 000000000..673b84185 --- /dev/null +++ b/repos/ports/src/app/gdb_monitor/siginfo.patch @@ -0,0 +1,279 @@ +From 0bcbef9314d6679d1fbbb0114683d06de0196623 Mon Sep 17 00:00:00 2001 + +From: Christian Prochaska + +Message-Id: <0bcbef9314d6679d1fbbb0114683d06de0196623.1341578007.git.chris@arachsys.com> +From: Chris Webb +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 +. 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 +--- + 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 + #endif + ++#include + #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 diff --git a/repos/ports/src/app/gdb_monitor/signal_handler_thread.cc b/repos/ports/src/app/gdb_monitor/signal_handler_thread.cc index 5e8af7b65..0389269cc 100644 --- a/repos/ports/src/app/gdb_monitor/signal_handler_thread.cc +++ b/repos/ports/src/app/gdb_monitor/signal_handler_thread.cc @@ -5,36 +5,21 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include - -/* libc includes */ -#include - -/* GDB monitor includes */ -#include "thread_info.h" #include "signal_handler_thread.h" using namespace Genode; using namespace Gdb_monitor; -static bool const verbose = false; - Signal_handler_thread::Signal_handler_thread(Signal_receiver *receiver) : - Thread_deprecated<2*4096>("sig_handler"), - _signal_receiver(receiver) -{ - if (pipe(_pipefd)) - PERR("could not create pipe"); - -} + Thread_deprecated("sig_handler"), + _signal_receiver(receiver) { } void Signal_handler_thread::entry() @@ -42,18 +27,9 @@ void Signal_handler_thread::entry() while(1) { Signal s = _signal_receiver->wait_for_signal(); - if (verbose) - PDBG("received exception signal"); + Signal_dispatcher_base *signal_dispatcher = + dynamic_cast(s.context()); - /* default is segmentation fault */ - unsigned long sig = 0; - - if (Thread_info *thread_info = dynamic_cast(s.context())) - /* thread trapped */ - sig = thread_info->lwpid(); - - write(_pipefd[1], &sig, sizeof(sig)); + signal_dispatcher->dispatch(s.num()); } - - sleep_forever(); }; diff --git a/repos/ports/src/app/gdb_monitor/signal_handler_thread.h b/repos/ports/src/app/gdb_monitor/signal_handler_thread.h index 247085b88..06b3c0077 100644 --- a/repos/ports/src/app/gdb_monitor/signal_handler_thread.h +++ b/repos/ports/src/app/gdb_monitor/signal_handler_thread.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -21,18 +21,19 @@ using namespace Genode; namespace Gdb_monitor { - class Signal_handler_thread : public Thread_deprecated<2*4096> + enum { SIGNAL_HANDLER_THREAD_STACK_SIZE = 2*1024*sizeof(addr_t) }; + + class Signal_handler_thread + : public Thread_deprecated { private: - int _pipefd[2]; Signal_receiver *_signal_receiver; public: Signal_handler_thread(Signal_receiver *receiver); void entry(); - int pipe_read_fd() { return _pipefd[0]; } }; } diff --git a/repos/ports/src/app/gdb_monitor/target.mk b/repos/ports/src/app/gdb_monitor/target.mk index 2b96f9023..47197bf62 100644 --- a/repos/ports/src/app/gdb_monitor/target.mk +++ b/repos/ports/src/app/gdb_monitor/target.mk @@ -28,13 +28,13 @@ SRC_C = event-loop.c \ SRC_C += linux-low.c -CC_OPT += -DGDBSERVER +CC_OPT += -DGDBSERVER -DPKGVERSION="\"7.3.1\"" -DREPORT_BUGS_TO="\"\"" CC_OPT_linux-low += -Wno-unused-function SRC_CC = genode-low.cc \ - gdb_stub_thread.cc \ cpu_session_component.cc \ + cpu_thread_component.cc \ ram_session_component.cc \ region_map_component.cc \ signal_handler_thread.cc \ diff --git a/repos/ports/src/app/gdb_monitor/thread_info.h b/repos/ports/src/app/gdb_monitor/thread_info.h deleted file mode 100644 index 6e54ac1f1..000000000 --- a/repos/ports/src/app/gdb_monitor/thread_info.h +++ /dev/null @@ -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 - -#include "append_list.h" - -namespace Gdb_monitor { - - using namespace Genode; - - class Thread_info : public Signal_context, public Append_list::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_ */ diff --git a/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.c b/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.c deleted file mode 100644 index 796b5c15f..000000000 --- a/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.c +++ /dev/null @@ -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 -#include - -#include - -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; -} diff --git a/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.h b/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.h index 553a7e7fc..1ea3d0707 100644 --- a/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.h +++ b/repos/ports/src/lib/gdbserver_libc_support/gdbserver_libc_support.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -29,8 +29,4 @@ struct user { unsigned long int u_debugreg [8]; }; -/* Missing in libc's sys/wait.h */ - -#define __WCLONE 0 - #endif /* GDBSERVER_LIBC_DUMMIES_H */ diff --git a/repos/ports/src/lib/gdbserver_libc_support/sys/ptrace.h b/repos/ports/src/lib/gdbserver_libc_support/sys/ptrace.h index 129d049eb..7f12ade6b 100644 --- a/repos/ports/src/lib/gdbserver_libc_support/sys/ptrace.h +++ b/repos/ports/src/lib/gdbserver_libc_support/sys/ptrace.h @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -20,18 +20,23 @@ #include enum __ptrace_request { - PTRACE_TRACEME, - PTRACE_ATTACH, - PTRACE_KILL, - PTRACE_DETACH, - PTRACE_SINGLESTEP, - PTRACE_CONT, - PTRACE_PEEKTEXT, - PTRACE_POKETEXT, - PTRACE_PEEKUSER, - PTRACE_POKEUSER, - PTRACE_GETREGS, - PTRACE_SETREGS, + PTRACE_TRACEME = 0, + PTRACE_PEEKTEXT = 1, + PTRACE_PEEKUSER = 3, + PTRACE_POKETEXT = 4, + PTRACE_POKEUSER = 6, + PTRACE_CONT = 7, + PTRACE_KILL = 8, + PTRACE_SINGLESTEP = 9, + PTRACE_GETREGS = 12, + PTRACE_SETREGS = 13, + PTRACE_ATTACH = 16, + PTRACE_DETACH = 17, + + PTRACE_EVENT_CLONE = 3, + + PTRACE_GETEVENTMSG = 0x4201, + PTRACE_GETREGSET = 0x4204, }; extern long ptrace(enum __ptrace_request request, ...); diff --git a/repos/ports/src/lib/gdbserver_libc_support/sys/wait.h b/repos/ports/src/lib/gdbserver_libc_support/sys/wait.h new file mode 100644 index 000000000..609cbe90e --- /dev/null +++ b/repos/ports/src/lib/gdbserver_libc_support/sys/wait.h @@ -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 */ diff --git a/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.cc b/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.cc index c9c6aac66..27140720a 100644 --- a/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.cc +++ b/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -22,16 +22,20 @@ extern "C" { #include #include "cpu_session_component.h" -#include "gdb_stub_thread.h" +#include "genode_child_resources.h" using namespace Genode; using namespace Gdb_monitor; -extern Gdb_stub_thread *gdb_stub_thread(); +extern Genode_child_resources *genode_child_resources(); + + +static constexpr bool verbose = false; + Thread_state get_current_thread_state() { - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id; @@ -40,9 +44,10 @@ Thread_state get_current_thread_state() return cpu_thread.state(); } + void set_current_thread_state(Thread_state thread_state) { - Cpu_session_component *csc = gdb_stub_thread()->cpu_session_component(); + Cpu_session_component *csc = genode_child_resources()->cpu_session_component(); ptid_t ptid = ((struct inferior_list_entry*)current_inferior)->id; @@ -51,3 +56,43 @@ void set_current_thread_state(Thread_state thread_state) cpu_thread.state(thread_state); } + +void fetch_register(const char *reg_name, + addr_t thread_state_reg, + unsigned long &value) +{ + value = thread_state_reg; + + if (verbose) + PDBG("%s = %8lx", reg_name, value); +} + + +void cannot_fetch_register(const char *reg_name) +{ + if (verbose) + PDBG("cannot fetch register %s", reg_name); +} + + +bool store_register(const char *reg_name, + addr_t &thread_state_reg, + unsigned long value) +{ + if (verbose) + PDBG("%s = %8lx", reg_name, value); + + if (thread_state_reg == value) + return false; + + thread_state_reg = value; + + return true; +} + + +void cannot_store_register(const char *reg_name, unsigned long value) +{ + if (verbose) + PDBG("cannot set contents of register %s (%8lx)", reg_name, value); +} diff --git a/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.h b/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.h index abda7c6f0..3dab14f0c 100644 --- a/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.h +++ b/repos/ports/src/lib/gdbserver_platform/gdbserver_platform_helper.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -21,4 +21,16 @@ Genode::Thread_state get_current_thread_state(); void set_current_thread_state(Genode::Thread_state thread_state); +void fetch_register(const char *reg_name, + Genode::addr_t thread_state_reg, + unsigned long &value); + +void cannot_fetch_register(const char *reg_name); + +bool store_register(const char *reg_name, + Genode::addr_t &thread_state_reg, + unsigned long value); + +void cannot_store_register(const char *reg_name, unsigned long value); + #endif /* GDBSERVER_PLATFORM_HELPER_H */ diff --git a/repos/ports/src/lib/gdbserver_platform/spec/fiasco_x86/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/fiasco_x86/low.cc deleted file mode 100644 index 03a719203..000000000 --- a/repos/ports/src/lib/gdbserver_platform/spec/fiasco_x86/low.cc +++ /dev/null @@ -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 -#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"); -} - diff --git a/repos/ports/src/lib/gdbserver_platform/spec/foc/native_cpu.cc b/repos/ports/src/lib/gdbserver_platform/spec/foc/native_cpu.cc new file mode 100644 index 000000000..fb512ee01 --- /dev/null +++ b/repos/ports/src/lib/gdbserver_platform/spec/foc/native_cpu.cc @@ -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 + +/* 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 +{ + 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 +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); +} diff --git a/repos/ports/src/lib/gdbserver_platform/spec/foc_arm/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/foc_arm/low.cc index a6a9081e1..ea12b9374 100644 --- a/repos/ports/src/lib/gdbserver_platform/spec/foc_arm/low.cc +++ b/repos/ports/src/lib/gdbserver_platform/spec/foc_arm/low.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -22,107 +22,124 @@ extern "C" { #include "reg-arm.h" #include "gdbserver_platform_helper.h" -#include "gdb_stub_thread.h" - -#undef PDBG -#define PDBG(...) +#include "genode_child_resources.h" using namespace Genode; -static bool in_syscall(Thread_state const &thread_state) +static bool in_syscall(Thread_state const &ts) { - /* looking for syscall pattern: - * (PC-8: e1a0e00f mov lr, pc) - * PC-4: e3e0f00b mvn pc, #11 - * (PC: e1a02004 mov r2, r4) - */ - if ((genode_read_memory_byte((void*)(thread_state.ip - 1)) == 0xe3) && - (genode_read_memory_byte((void*)(thread_state.ip - 2)) == 0xe0) && - (genode_read_memory_byte((void*)(thread_state.ip - 3)) == 0xf0) && - (genode_read_memory_byte((void*)(thread_state.ip - 4)) == 0x0b)) - return true; - + try { + /* looking for syscall pattern: + * (PC-8: e1a0e00f mov lr, pc) + * PC-4: e3e0f00b mvn pc, #11 + * (PC: e1a02004 mov r2, r4) + */ + if ((genode_read_memory_byte((void*)(ts.ip - 1)) == 0xe3) && + (genode_read_memory_byte((void*)(ts.ip - 2)) == 0xe0) && + (genode_read_memory_byte((void*)(ts.ip - 3)) == 0xf0) && + (genode_read_memory_byte((void*)(ts.ip - 4)) == 0x0b)) + return true; + } catch (No_memory_at_address) { + return false; + } return false; } -extern "C" int genode_fetch_register(int regno, unsigned long *reg_content) +extern "C" int genode_fetch_register(int regno, unsigned long *value) { - Thread_state thread_state; + Thread_state ts; - try { thread_state = get_current_thread_state(); } - catch (...) { return 0; } + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return -1; + } + + if (in_syscall(ts) || ts.unresolved_page_fault) { - if (in_syscall(thread_state) || thread_state.unresolved_page_fault) { switch((enum reg_index)regno) { - case R0: PDBG("cannot determine contents of register R0"); return -1; - case R1: PDBG("cannot determine contents of register R1"); return -1; - case R2: PDBG("cannot determine contents of register R2"); return -1; - case R3: PDBG("cannot determine contents of register R3"); return -1; - case R4: PDBG("cannot determine contents of register R4"); return -1; - case R5: PDBG("cannot determine contents of register R5"); return -1; - case R6: PDBG("cannot determine contents of register R6"); return -1; - case R7: PDBG("cannot determine contents of register R7"); return -1; - case R8: PDBG("cannot determine contents of register R8"); return -1; - case R9: PDBG("cannot determine contents of register R9"); return -1; - case R10: PDBG("cannot determine contents of register R10"); return -1; + case R0: cannot_fetch_register("R0"); return -1; + case R1: cannot_fetch_register("R1"); return -1; + case R2: cannot_fetch_register("R2"); return -1; + case R3: cannot_fetch_register("R3"); return -1; + case R4: cannot_fetch_register("R4"); return -1; + case R5: cannot_fetch_register("R5"); return -1; + case R6: cannot_fetch_register("R6"); return -1; + case R7: cannot_fetch_register("R7"); return -1; + case R8: cannot_fetch_register("R8"); return -1; + case R9: cannot_fetch_register("R9"); return -1; + case R10: cannot_fetch_register("R10"); return -1; + case R11: - if (in_syscall(thread_state)) { + + if (in_syscall(ts)) { /* R11 can be calculated from SP. The offset can be found in * the disassembled 'Fiasco::l4_ipc()' function: * add r11, sp, #8 -> r11 = sp + 8 * sub sp, sp, #20 -> r11 = (sp + 20) + 8 */ - *reg_content = (thread_state.sp + 20) + 8; - PDBG("FP = %8lx", *reg_content); + *value = (ts.sp + 20) + 8; + + /* for the debug output, if enabled */ + fetch_register("R11", *value, *value); + return 0; } else { - PDBG("cannot determine contents of register R11"); return -1; + + cannot_fetch_register("R11"); + + return -1; } - case R12: PDBG("cannot determine contents of register R12"); return -1; - case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0; - case LR: PDBG("cannot determine contents of register LR"); return -1; - case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0; - case F0: PDBG("cannot determine contents of register F0"); return -1; - case F1: PDBG("cannot determine contents of register F1"); return -1; - case F2: PDBG("cannot determine contents of register F2"); return -1; - case F3: PDBG("cannot determine contents of register F3"); return -1; - case F4: PDBG("cannot determine contents of register F4"); return -1; - case F5: PDBG("cannot determine contents of register F5"); return -1; - case F6: PDBG("cannot determine contents of register F6"); return -1; - case F7: PDBG("cannot determine contents of register F7"); return -1; - case FPS: PDBG("cannot determine contents of register FPS"); return -1; - case CPSR: PDBG("cannot determine contents of register CPSR"); return -1; + + case R12: cannot_fetch_register("R12"); return -1; + case SP: fetch_register("SP ", ts.sp, *value); return 0; + case LR: cannot_fetch_register("LR"); return -1; + case PC: fetch_register("PC ", ts.ip, *value); return 0; + case F0: cannot_fetch_register("F0"); return -1; + case F1: cannot_fetch_register("F1"); return -1; + case F2: cannot_fetch_register("F2"); return -1; + case F3: cannot_fetch_register("F3"); return -1; + case F4: cannot_fetch_register("F4"); return -1; + case F5: cannot_fetch_register("F5"); return -1; + case F6: cannot_fetch_register("F6"); return -1; + case F7: cannot_fetch_register("F7"); return -1; + case FPS: cannot_fetch_register("FPS"); return -1; + case CPSR: cannot_fetch_register("CPSR"); return -1; + default: PERR("unhandled register %d", regno); return -1; } + } else { + switch((enum reg_index)regno) { - case R0: *reg_content = thread_state.r0; PDBG("R0 = %8lx", *reg_content); return 0; - case R1: *reg_content = thread_state.r1; PDBG("R1 = %8lx", *reg_content); return 0; - case R2: *reg_content = thread_state.r2; PDBG("R2 = %8lx", *reg_content); return 0; - case R3: *reg_content = thread_state.r3; PDBG("R3 = %8lx", *reg_content); return 0; - case R4: *reg_content = thread_state.r4; PDBG("R4 = %8lx", *reg_content); return 0; - case R5: *reg_content = thread_state.r5; PDBG("R5 = %8lx", *reg_content); return 0; - case R6: *reg_content = thread_state.r6; PDBG("R6 = %8lx", *reg_content); return 0; - case R7: *reg_content = thread_state.r7; PDBG("R7 = %8lx", *reg_content); return 0; - case R8: *reg_content = thread_state.r8; PDBG("R8 = %8lx", *reg_content); return 0; - case R9: *reg_content = thread_state.r9; PDBG("R9 = %8lx", *reg_content); return 0; - case R10: *reg_content = thread_state.r10; PDBG("R10 = %8lx", *reg_content); return 0; - case R11: *reg_content = thread_state.r11; PDBG("FP = %8lx", *reg_content); return 0; - case R12: *reg_content = thread_state.r12; PDBG("R12 = %8lx", *reg_content); return 0; - case SP: *reg_content = thread_state.sp; PDBG("SP = %8lx", *reg_content); return 0; - case LR: *reg_content = thread_state.lr; PDBG("LR = %8lx", *reg_content); return 0; - case PC: *reg_content = thread_state.ip; PDBG("PC = %8lx", *reg_content); return 0; - case F0: PDBG("cannot determine contents of register F0"); return -1; - case F1: PDBG("cannot determine contents of register F1"); return -1; - case F2: PDBG("cannot determine contents of register F2"); return -1; - case F3: PDBG("cannot determine contents of register F3"); return -1; - case F4: PDBG("cannot determine contents of register F4"); return -1; - case F5: PDBG("cannot determine contents of register F5"); return -1; - case F6: PDBG("cannot determine contents of register F6"); return -1; - case F7: PDBG("cannot determine contents of register F7"); return -1; - case FPS: PDBG("cannot determine contents of register FPS"); return -1; - case CPSR: *reg_content = thread_state.cpsr; PDBG("CPSR = %8lx", *reg_content); return 0; + case R0: fetch_register("R0 ", ts.r0, *value); return 0; + case R1: fetch_register("R1 ", ts.r1, *value); return 0; + case R2: fetch_register("R2 ", ts.r2, *value); return 0; + case R3: fetch_register("R3 ", ts.r3, *value); return 0; + case R4: fetch_register("R4 ", ts.r4, *value); return 0; + case R5: fetch_register("R5 ", ts.r5, *value); return 0; + case R6: fetch_register("R6 ", ts.r6, *value); return 0; + case R7: fetch_register("R7 ", ts.r7, *value); return 0; + case R8: fetch_register("R8 ", ts.r8, *value); return 0; + case R9: fetch_register("R9 ", ts.r9, *value); return 0; + case R10: fetch_register("R10 ", ts.r10, *value); return 0; + case R11: fetch_register("R11 ", ts.r11, *value); return 0; + case R12: fetch_register("R12 ", ts.r12, *value); return 0; + case SP: fetch_register("SP ", ts.sp, *value); return 0; + case LR: fetch_register("LR ", ts.lr, *value); return 0; + case PC: fetch_register("PC ", ts.ip, *value); return 0; + case F0: cannot_fetch_register("F0"); return -1; + case F1: cannot_fetch_register("F1"); return -1; + case F2: cannot_fetch_register("F2"); return -1; + case F3: cannot_fetch_register("F3"); return -1; + case F4: cannot_fetch_register("F4"); return -1; + case F5: cannot_fetch_register("F5"); return -1; + case F6: cannot_fetch_register("F6"); return -1; + case F7: cannot_fetch_register("F7"); return -1; + case FPS: cannot_fetch_register("FPS"); return -1; + case CPSR: fetch_register("CPSR", ts.cpsr, *value); return 0; + default: PERR("unhandled register %d", regno); return -1; } } @@ -130,48 +147,51 @@ extern "C" int genode_fetch_register(int regno, unsigned long *reg_content) } -extern "C" void genode_store_register(int regno, unsigned long reg_content) +extern "C" void genode_store_register(int regno, unsigned long value) { - Thread_state thread_state; + Thread_state ts; - try { thread_state = get_current_thread_state(); } - catch (...) { return; } + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return; + } - if (in_syscall(thread_state)) { + if (in_syscall(ts)) { PDBG("cannot set registers while thread is in syscall"); return; } switch((enum reg_index)regno) { - case R0: thread_state.r0 = reg_content; PDBG("R0 = %8lx", reg_content); break; - case R1: thread_state.r1 = reg_content; PDBG("R1 = %8lx", reg_content); break; - case R2: thread_state.r2 = reg_content; PDBG("R2 = %8lx", reg_content); break; - case R3: thread_state.r3 = reg_content; PDBG("R3 = %8lx", reg_content); break; - case R4: thread_state.r4 = reg_content; PDBG("R4 = %8lx", reg_content); break; - case R5: thread_state.r5 = reg_content; PDBG("R5 = %8lx", reg_content); break; - case R6: thread_state.r6 = reg_content; PDBG("R6 = %8lx", reg_content); break; - case R7: thread_state.r7 = reg_content; PDBG("R7 = %8lx", reg_content); break; - case R8: thread_state.r8 = reg_content; PDBG("R8 = %8lx", reg_content); break; - case R9: thread_state.r9 = reg_content; PDBG("R9 = %8lx", reg_content); break; - case R10: thread_state.r10 = reg_content; PDBG("R10 = %8lx", reg_content); break; - case R11: thread_state.r11 = reg_content; PDBG("FP = %8lx", reg_content); break; - case R12: thread_state.r12 = reg_content; PDBG("R12 = %8lx", reg_content); break; - case SP: thread_state.sp = reg_content; PDBG("SP = %8lx", reg_content); break; - case LR: thread_state.lr = reg_content; PDBG("LR = %8lx", reg_content); break; - case PC: thread_state.ip = reg_content; PDBG("PC = %8lx", reg_content); break; - case F0: PDBG("cannot set contents of register F0"); break; - case F1: PDBG("cannot set contents of register F1"); break; - case F2: PDBG("cannot set contents of register F2"); break; - case F3: PDBG("cannot set contents of register F3"); break; - case F4: PDBG("cannot set contents of register F4"); break; - case F5: PDBG("cannot set contents of register F5"); break; - case F6: PDBG("cannot set contents of register F6"); break; - case F7: PDBG("cannot set contents of register F7"); break; - case FPS: PDBG("cannot set contents of register FPS"); break; - case CPSR: thread_state.cpsr = reg_content; PDBG("CPSR = %8lx", reg_content); break; + case R0: if (!store_register("R0 ", ts.r0, value)) return; break; + case R1: if (!store_register("R1 ", ts.r1, value)) return; break; + case R2: if (!store_register("R2 ", ts.r2, value)) return; break; + case R3: if (!store_register("R3 ", ts.r3, value)) return; break; + case R4: if (!store_register("R4 ", ts.r4, value)) return; break; + case R5: if (!store_register("R5 ", ts.r5, value)) return; break; + case R6: if (!store_register("R6 ", ts.r6, value)) return; break; + case R7: if (!store_register("R7 ", ts.r7, value)) return; break; + case R8: if (!store_register("R8 ", ts.r8, value)) return; break; + case R9: if (!store_register("R9 ", ts.r9, value)) return; break; + case R10: if (!store_register("R10 ", ts.r10, value)) return; break; + case R11: if (!store_register("R11 ", ts.r11, value)) return; break; + case R12: if (!store_register("R12 ", ts.r12, value)) return; break; + case SP: if (!store_register("SP ", ts.sp, value)) return; break; + case LR: if (!store_register("LR ", ts.lr, value)) return; break; + case PC: if (!store_register("PC ", ts.ip, value)) return; break; + case F0: cannot_store_register("F0 ", value); return; + case F1: cannot_store_register("F1 ", value); return; + case F2: cannot_store_register("F2 ", value); return; + case F3: cannot_store_register("F3 ", value); return; + case F4: cannot_store_register("F4 ", value); return; + case F5: cannot_store_register("F5 ", value); return; + case F6: cannot_store_register("F6 ", value); return; + case F7: cannot_store_register("F7 ", value); return; + case FPS: cannot_store_register("FPS", value); return; + case CPSR: if (!store_register("CPSR", ts.cpsr, value)) return; break; } - set_current_thread_state(thread_state); + set_current_thread_state(ts); } diff --git a/repos/ports/src/lib/gdbserver_platform/spec/foc_x86_32/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/foc_x86_32/low.cc index bd5d700d9..a42c508e2 100644 --- a/repos/ports/src/lib/gdbserver_platform/spec/foc_x86_32/low.cc +++ b/repos/ports/src/lib/gdbserver_platform/spec/foc_x86_32/low.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -21,10 +21,7 @@ extern "C" { #include "i386.h" #include "cpu_session_component.h" #include "gdbserver_platform_helper.h" -#include "gdb_stub_thread.h" - -#undef PDBG -#define PDBG(...) +#include "genode_child_resources.h" using namespace Genode; @@ -44,113 +41,146 @@ static bool in_syscall(Thread_state const &thread_state) return false; } -extern "C" int genode_fetch_register(int regno, unsigned long *reg_content) +extern "C" int genode_fetch_register(int regno, unsigned long *value) { - Thread_state thread_state; + Thread_state ts; - try { thread_state = get_current_thread_state(); } - catch (...) { return 0; } + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return -1; + } + + if (in_syscall(ts) || ts.unresolved_page_fault) { - if (in_syscall(thread_state) || thread_state.unresolved_page_fault) { switch((enum reg_index)regno) { - case EAX: PDBG("cannot determine contents of register EAX"); return -1; - case ECX: PDBG("cannot determine contents of register ECX"); return -1; - case EDX: PDBG("cannot determine contents of register EDX"); return -1; + case EAX: cannot_fetch_register("EAX"); return -1; + case ECX: cannot_fetch_register("ECX"); return -1; + case EDX: cannot_fetch_register("EDX"); return -1; + case EBX: - if (in_syscall(thread_state)) { + + if (in_syscall(ts)) { + /* When in a syscall, the user EBX has been pushed onto the stack at address ESP+4 */ - *reg_content = genode_read_memory_byte((void*)(thread_state.sp + 4)) + - (genode_read_memory_byte((void*)(thread_state.sp + 5)) << 8) + - (genode_read_memory_byte((void*)(thread_state.sp + 6)) << 16) + - (genode_read_memory_byte((void*)(thread_state.sp + 7)) << 24); - PDBG("EBX = %8lx", *reg_content); + *value = genode_read_memory_byte((void*)(ts.sp + 4)) + + (genode_read_memory_byte((void*)(ts.sp + 5)) << 8) + + (genode_read_memory_byte((void*)(ts.sp + 6)) << 16) + + (genode_read_memory_byte((void*)(ts.sp + 7)) << 24); + + /* for the debug output, if enabled */ + fetch_register("EBX", *value, *value); + return 0; + } else { - PDBG("cannot determine contents of register EBX"); return -1; + + cannot_fetch_register("EBX"); + + return -1; } - case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0; + + case UESP: fetch_register("ESP", ts.sp, *value); return 0; + case EBP: - if (in_syscall(thread_state)) { + + if (in_syscall(ts)) { + /* When in a syscall, the user EBP has been pushed onto the stack at address ESP+0 */ - *reg_content = genode_read_memory_byte((void*)(thread_state.sp + 0)) + - (genode_read_memory_byte((void*)(thread_state.sp + 1)) << 8) + - (genode_read_memory_byte((void*)(thread_state.sp + 2)) << 16) + - (genode_read_memory_byte((void*)(thread_state.sp + 3)) << 24); - PDBG("EBP = %8lx", *reg_content); + *value = genode_read_memory_byte((void*)(ts.sp + 0)) + + (genode_read_memory_byte((void*)(ts.sp + 1)) << 8) + + (genode_read_memory_byte((void*)(ts.sp + 2)) << 16) + + (genode_read_memory_byte((void*)(ts.sp + 3)) << 24); + + /* for the debug output, if enabled */ + fetch_register("EBP", *value, *value); + return 0; + } else { - PDBG("cannot determine contents of register EBP"); return -1; + + cannot_fetch_register("EBP"); + + return -1; } - case ESI: PDBG("cannot determine contents of register ESI"); return -1; - case EDI: PDBG("cannot determine contents of register EDI"); return -1; - case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0; - case EFL: PDBG("cannot determine contents of register EFLAGS"); return -1; - case CS: PDBG("cannot determine contents of register CS"); return -1; - case SS: PDBG("cannot determine contents of register SS"); return -1; - case DS: PDBG("cannot determine contents of register DS"); return -1; - case ES: PDBG("cannot determine contents of register ES"); return -1; - case FS: PDBG("cannot determine contents of register FS"); return -1; - case GS: PDBG("cannot determine contents of register GS"); return -1; + + case ESI: cannot_fetch_register("ESI"); return -1; + case EDI: cannot_fetch_register("EDI"); return -1; + case EIP: fetch_register("EIP", ts.ip, *value); return 0; + case EFL: cannot_fetch_register("EFL"); return -1; + case CS: cannot_fetch_register("CS"); return -1; + case SS: cannot_fetch_register("SS"); return -1; + case DS: cannot_fetch_register("DS"); return -1; + case ES: cannot_fetch_register("ES"); return -1; + case FS: cannot_fetch_register("FS"); return -1; + case GS: cannot_fetch_register("GS"); return -1; + default: PERR("unhandled register %d", regno); return -1; } + } else { + switch((enum reg_index)regno) { - case EAX: *reg_content = thread_state.eax; PDBG("EAX = %8lx", *reg_content); return 0; - case ECX: *reg_content = thread_state.ecx; PDBG("ECX = %8lx", *reg_content); return 0; - case EDX: *reg_content = thread_state.edx; PDBG("EDX = %8lx", *reg_content); return 0; - case EBX: *reg_content = thread_state.ebx; PDBG("EBX = %8lx", *reg_content); return 0; - case UESP: *reg_content = thread_state.sp; PDBG("ESP = %8lx", *reg_content); return 0; - case EBP: *reg_content = thread_state.ebp; PDBG("EBP = %8lx", *reg_content); return 0; - case ESI: *reg_content = thread_state.esi; PDBG("ESI = %8lx", *reg_content); return 0; - case EDI: *reg_content = thread_state.edi; PDBG("EDI = %8lx", *reg_content); return 0; - case EIP: *reg_content = thread_state.ip; PDBG("EIP = %8lx", *reg_content); return 0; - case EFL: *reg_content = thread_state.eflags; PDBG("EFLAGS = %8lx", *reg_content); return 0; - case CS: PDBG("cannot determine contents of register CS"); return -1; - case SS: PDBG("cannot determine contents of register SS"); return -1; - case DS: PDBG("cannot determine contents of register DS"); return -1; - case ES: PDBG("cannot determine contents of register ES"); return -1; - case FS: *reg_content = thread_state.fs; PDBG("FS = %8lx", *reg_content); return 0; - case GS: *reg_content = thread_state.gs; PDBG("GS = %8lx", *reg_content); return 0; + case EAX: fetch_register("EAX", ts.eax, *value); return 0; + case ECX: fetch_register("ECX", ts.ecx, *value); return 0; + case EDX: fetch_register("EDX", ts.edx, *value); return 0; + case EBX: fetch_register("EBX", ts.ebx, *value); return 0; + case UESP: fetch_register("ESP", ts.sp, *value); return 0; + case EBP: fetch_register("EBP", ts.ebp, *value); return 0; + case ESI: fetch_register("ESI", ts.esi, *value); return 0; + case EDI: fetch_register("EDI", ts.edi, *value); return 0; + case EIP: fetch_register("EIP", ts.ip, *value); return 0; + case EFL: fetch_register("EFL", ts.eflags, *value); return 0; + case CS: cannot_fetch_register("CS"); return -1; + case SS: cannot_fetch_register("SS"); return -1; + case DS: cannot_fetch_register("DS"); return -1; + case ES: cannot_fetch_register("ES"); return -1; + case FS: fetch_register("FS", ts.fs, *value); return 0; + case GS: fetch_register("GS", ts.gs, *value); return 0; + default: PERR("unhandled register %d", regno); return -1; } } return -1; } -extern "C" void genode_store_register(int regno, unsigned long reg_content) +extern "C" void genode_store_register(int regno, unsigned long value) { - Thread_state thread_state; + Thread_state ts; - try { thread_state = get_current_thread_state(); } - catch (...) { return; } + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return; + } - if (in_syscall(thread_state)) { + if (in_syscall(ts)) { PDBG("cannot set registers while thread is in syscall"); return; } switch((enum reg_index)regno) { - case EAX: thread_state.eax = reg_content; PDBG("EAX = %8lx", reg_content); break; - case ECX: thread_state.ecx = reg_content; PDBG("ECX = %8lx", reg_content); break; - case EDX: thread_state.edx = reg_content; PDBG("EDX = %8lx", reg_content); break; - case EBX: thread_state.ebx = reg_content; PDBG("EBX = %8lx", reg_content); break; - case UESP: thread_state.sp = reg_content; PDBG("ESP = %8lx", reg_content); break; - case EBP: thread_state.ebp = reg_content; PDBG("EBP = %8lx", reg_content); break; - case ESI: thread_state.esi = reg_content; PDBG("ESI = %8lx", reg_content); break; - case EDI: thread_state.edi = reg_content; PDBG("EDI = %8lx", reg_content); break; - case EIP: thread_state.ip = reg_content; PDBG("EIP = %8lx", reg_content); break; - case EFL: thread_state.eflags = reg_content; PDBG("EFL = %8lx", reg_content); break; - case CS: PDBG("cannot set contents of register CS"); PDBG(" CS = %8lx", reg_content); break; - case SS: PDBG("cannot set contents of register SS"); PDBG(" SS = %8lx", reg_content); break; - case DS: PDBG("cannot set contents of register DS"); PDBG(" DS = %8lx", reg_content); break; - case ES: PDBG("cannot set contents of register ES"); PDBG(" ES = %8lx", reg_content); break; - case FS: thread_state.fs = reg_content; PDBG(" FS = %8lx", reg_content); break; - case GS: thread_state.gs = reg_content; PDBG(" GS = %8lx", reg_content); break; - + case EAX: if (!store_register("EAX", ts.eax, value)) return; break; + case ECX: if (!store_register("ECX", ts.ecx, value)) return; break; + case EDX: if (!store_register("EDX", ts.edx, value)) return; break; + case EBX: if (!store_register("EBX", ts.ebx, value)) return; break; + case UESP: if (!store_register("ESP", ts.sp, value)) return; break; + case EBP: if (!store_register("EBP", ts.ebp, value)) return; break; + case ESI: if (!store_register("ESI", ts.esi, value)) return; break; + case EDI: if (!store_register("EDI", ts.edi, value)) return; break; + case EIP: if (!store_register("EIP", ts.ip, value)) return; break; + case EFL: if (!store_register("EFL", ts.eflags, value)) return; break; + case CS: cannot_store_register("CS", value); return; + case SS: cannot_store_register("SS", value); return; + case DS: cannot_store_register("DS", value); return; + case ES: cannot_store_register("ES", value); return; + case FS: if (!store_register("FS ", ts.fs, value)) return; break; + case GS: if (!store_register("GS ", ts.gs, value)) return; break; + default: PERR("unhandled register %d", regno); return; } - set_current_thread_state(thread_state); + set_current_thread_state(ts); } diff --git a/repos/ports/src/lib/gdbserver_platform/spec/linux_x86_32/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/linux_x86_32/low.cc deleted file mode 100644 index ada2ce068..000000000 --- a/repos/ports/src/lib/gdbserver_platform/spec/linux_x86_32/low.cc +++ /dev/null @@ -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 -#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"); -} - diff --git a/repos/ports/src/lib/gdbserver_platform/spec/nova/native_cpu.cc b/repos/ports/src/lib/gdbserver_platform/spec/nova/native_cpu.cc new file mode 100644 index 000000000..d5caf0d7b --- /dev/null +++ b/repos/ports/src/lib/gdbserver_platform/spec/nova/native_cpu.cc @@ -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 + +/* 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 +{ + 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 +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); +} diff --git a/repos/ports/src/lib/gdbserver_platform/spec/nova_x86_32/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/nova_x86_32/low.cc index 53a48cf03..e8573e4c3 100644 --- a/repos/ports/src/lib/gdbserver_platform/spec/nova_x86_32/low.cc +++ b/repos/ports/src/lib/gdbserver_platform/spec/nova_x86_32/low.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2012-2013 Genode Labs GmbH + * Copyright (C) 2012-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -14,43 +14,75 @@ #include "i386.h" #include "cpu_session_component.h" #include "gdbserver_platform_helper.h" -#include "gdb_stub_thread.h" +#include "genode_child_resources.h" using namespace Genode; -extern "C" int genode_fetch_register(int regno, unsigned long *reg_content) +extern "C" int genode_fetch_register(int regno, unsigned long *value) { - Thread_state thread_state; + Thread_state ts; - try { thread_state = get_current_thread_state(); } - catch (...) { return -1; } + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return -1; + } switch((enum reg_index)regno) { - case EAX: *reg_content = thread_state.eax; return 0; - case ECX: *reg_content = thread_state.ecx; return 0; - case EDX: *reg_content = thread_state.edx; return 0; - case EBX: *reg_content = thread_state.ebx; return 0; - case UESP: *reg_content = thread_state.sp; return 0; - case EBP: *reg_content = thread_state.ebp; return 0; - case ESI: *reg_content = thread_state.esi; return 0; - case EDI: *reg_content = thread_state.edi; return 0; - case EIP: *reg_content = thread_state.ip; return 0; - case EFL: *reg_content = thread_state.eflags; return 0; - case CS: return -1; - case SS: return -1; - case DS: return -1; - case ES: return -1; - case FS: *reg_content = thread_state.fs; return 0; - case GS: *reg_content = thread_state.gs; return 0; + case EAX: fetch_register("EAX", ts.eax, *value); return 0; + case ECX: fetch_register("ECX", ts.ecx, *value); return 0; + case EDX: fetch_register("EDX", ts.edx, *value); return 0; + case EBX: fetch_register("EBX", ts.ebx, *value); return 0; + case UESP: fetch_register("ESP", ts.sp, *value); return 0; + case EBP: fetch_register("EBP", ts.ebp, *value); return 0; + case ESI: fetch_register("ESI", ts.esi, *value); return 0; + case EDI: fetch_register("EDI", ts.edi, *value); return 0; + case EIP: fetch_register("EIP", ts.ip, *value); return 0; + case EFL: fetch_register("EFL", ts.eflags, *value); return 0; + case CS: cannot_fetch_register("CS"); return -1; + case SS: cannot_fetch_register("SS"); return -1; + case DS: cannot_fetch_register("DS"); return -1; + case ES: cannot_fetch_register("ES"); return -1; + case FS: cannot_fetch_register("FS"); return -1; + case GS: cannot_fetch_register("GS"); return -1; + default: PERR("unhandled register %d", regno); return -1; } return -1; } -extern "C" void genode_store_register(int regno, unsigned long reg_content) +extern "C" void genode_store_register(int regno, unsigned long value) { - PDBG("not implemented yet for this platform"); -} + Thread_state ts; + try { ts = get_current_thread_state(); } + catch (...) { + PERR("%s: could not get current thread state", __PRETTY_FUNCTION__); + return; + } + + switch ((enum reg_index)regno) + { + case EAX: if (!store_register("EAX", ts.eax, value)) return; break; + case ECX: if (!store_register("ECX", ts.ecx, value)) return; break; + case EDX: if (!store_register("EDX", ts.edx, value)) return; break; + case EBX: if (!store_register("EBX", ts.ebx, value)) return; break; + case UESP: if (!store_register("ESP", ts.sp, value)) return; break; + case EBP: if (!store_register("EBP", ts.ebp, value)) return; break; + case ESI: if (!store_register("ESI", ts.esi, value)) return; break; + case EDI: if (!store_register("EDI", ts.edi, value)) return; break; + case EIP: if (!store_register("EIP", ts.ip, value)) return; break; + case EFL: if (!store_register("EFL", ts.eflags, value)) return; break; + case CS: cannot_store_register("CS", value); return; + case SS: cannot_store_register("SS", value); return; + case DS: cannot_store_register("DS", value); return; + case ES: cannot_store_register("ES", value); return; + case FS: cannot_store_register("FS", value); return; + case GS: cannot_store_register("GS", value); return; + default: PERR("unhandled register %d", regno); return; + } + + set_current_thread_state(ts); +} diff --git a/repos/ports/src/lib/gdbserver_platform/spec/okl4_x86/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/okl4_x86/low.cc deleted file mode 100644 index e296eb119..000000000 --- a/repos/ports/src/lib/gdbserver_platform/spec/okl4_x86/low.cc +++ /dev/null @@ -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 -#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"); -} - diff --git a/repos/ports/src/lib/gdbserver_platform/spec/pistachio_x86/low.cc b/repos/ports/src/lib/gdbserver_platform/spec/pistachio_x86/low.cc deleted file mode 100644 index 6046dd7b3..000000000 --- a/repos/ports/src/lib/gdbserver_platform/spec/pistachio_x86/low.cc +++ /dev/null @@ -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 -#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"); -} - diff --git a/repos/ports/src/test/gdb_monitor/main.cc b/repos/ports/src/test/gdb_monitor/main.cc index 2f36849aa..018eea41b 100644 --- a/repos/ports/src/test/gdb_monitor/main.cc +++ b/repos/ports/src/test/gdb_monitor/main.cc @@ -29,7 +29,12 @@ class Test_thread : public Genode::Thread_deprecated<2*4096> Test_thread() : Thread_deprecated("test") { } - void func() + void step_func() + { + /* nothing */ + } + + void sigsegv_func() { /* * make sure that the main thread is sleeping in @@ -43,7 +48,9 @@ class Test_thread : public Genode::Thread_deprecated<2*4096> void entry() /* set a breakpoint here to test the 'info threads' command */ { - func(); + step_func(); + + sigsegv_func(); Genode::sleep_forever(); } diff --git a/repos/ports/src/test/gdb_monitor/target.mk b/repos/ports/src/test/gdb_monitor/target.mk index 72a18a09a..00b7e5909 100644 --- a/repos/ports/src/test/gdb_monitor/target.mk +++ b/repos/ports/src/test/gdb_monitor/target.mk @@ -1,3 +1,5 @@ TARGET = test-gdb_monitor SRC_CC = main.cc LIBS = libc + +CC_OLEVEL = -O0