diff --git a/os/src/app/cli_monitor/arm/gdb_prefix.h b/os/src/app/cli_monitor/arm/gdb_prefix.h new file mode 100644 index 0000000000..796bdb4514 --- /dev/null +++ b/os/src/app/cli_monitor/arm/gdb_prefix.h @@ -0,0 +1,19 @@ +/* + * \brief Prefix of the GDB binary + * \author Christian Prochaska + * \date 2013-10-23 + */ + +/* + * Copyright (C) 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_PREFIX_H_ +#define _GDB_PREFIX_H_ + +static const char *gdb_prefix = "genode-arm-"; + +#endif /* _GDB_PREFIX_H_ */ diff --git a/os/src/app/cli_monitor/gdb_command.h b/os/src/app/cli_monitor/gdb_command.h new file mode 100644 index 0000000000..699a6320f9 --- /dev/null +++ b/os/src/app/cli_monitor/gdb_command.h @@ -0,0 +1,546 @@ +/* + * \brief Gdb command + * \author Norman Feske + * \author Christian Prochaska + * \date 2013-03-18 + */ + +/* + * Copyright (C) 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_COMMAND_H_ +#define _GDB_COMMAND_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include +#include +#include + +class Gdb_command_child : public Child +{ + private: + + Genode::Signal_context_capability _kill_gdb_sig_cap; + Terminal::Session &_terminal; + + bool _kill_requested; + + void _kill_gdb() + { + _kill_requested = true; + Genode::Signal_transmitter(_kill_gdb_sig_cap).submit(); + } + + public: + + Gdb_command_child(Ram &ram, + char const *label, + char const *binary, + Genode::Cap_session &cap_session, + Genode::size_t ram_quota, + Genode::size_t ram_limit, + Genode::Signal_context_capability yield_response_sig_cap, + Genode::Signal_context_capability kill_gdb_sig_cap, + Terminal::Session &terminal) + : Child(ram, label, binary, cap_session, ram_quota, ram_limit, + yield_response_sig_cap), + _kill_gdb_sig_cap(kill_gdb_sig_cap), + _terminal(terminal), + _kill_requested(false) + { } + + bool kill_requested() const { return _kill_requested; } + + /* + * Check if GDB-related (Noux) session-requests will be successful. + * If not, terminate the subsystem and tell the user about it. + */ + Genode::Service *resolve_session_request(const char *service_name, + const char *args) + { + if (_kill_requested) + return 0; + + Genode::Service *service = + Child::resolve_session_request(service_name, args); + + if (!service) { + tprintf(_terminal, "Error: GDB subsystem session request for service '%s' failed\n", + service_name); + PDBG("session request failed: service_name = %s, args = %s", service_name, args); + _kill_gdb(); + return 0; + } + + /* Find out if the session request comes from Noux */ + + const char *noux_label_suffix = " -> noux"; + + /* Arg::string() needs two extra bytes */ + size_t label_size = strlen(name()) + strlen(noux_label_suffix) + 2; + + char noux_label_buf[label_size]; + snprintf(noux_label_buf, sizeof(noux_label_buf), + "%s%s", name(), noux_label_suffix); + + char label_buf[label_size]; + Genode::Arg_string::find_arg(args, "label").string(label_buf, + sizeof(label_buf), + ""); + + if (strcmp(label_buf, noux_label_buf, label_size) == 0) { + /* Try to create and close the session */ + try { + Genode::Session_capability s = service->session(args, Genode::Affinity()); + service->close(s); + } catch (...) { + tprintf(_terminal, "Error: GDB subsystem session request for service '%s' failed\n", + service_name); + PDBG("session request failed: service_name = %s, args = %s", service_name, args); + _kill_gdb(); + return 0; + } + } + + return service; + } + +}; + + +struct Gdb_command : Command +{ + typedef Genode::Xml_node Xml_node; + typedef Genode::Signal_context_capability Signal_context_capability; + + struct Child_configuration_failed {}; /* exception */ + + Ram &_ram; + Child_registry &_children; + Genode::Cap_session &_cap; + Xml_node _config; + Process_arg_registry &_process_args; + List _arguments; + Signal_context_capability _yield_response_sigh_cap; + Signal_context_capability _kill_gdb_sig_cap; + + Gdb_command(Ram &ram, Genode::Cap_session &cap, Child_registry &children, + Xml_node config, Process_arg_registry &process_args, + Signal_context_capability yield_response_sigh_cap, + Signal_context_capability kill_gdb_sig_cap) + : + Command("gdb", "create new subsystem with GDB"), + _ram(ram), _children(children), _cap(cap), _config(config), + _process_args(process_args), + _yield_response_sigh_cap(yield_response_sigh_cap), + _kill_gdb_sig_cap(kill_gdb_sig_cap) + { + /* scan config for possible subsystem arguments */ + try { + Xml_node node = _config.sub_node("subsystem"); + for (;; node = node.next("subsystem")) { + + char name[Parameter::NAME_MAX_LEN]; + try { node.attribute("name").value(name, sizeof(name)); } + catch (Xml_node::Nonexistent_attribute) { + PWRN("Missing name in '' configuration"); + continue; + } + + char const *prefix = "config: "; + size_t const prefix_len = strlen(prefix); + + char help[Parameter::SHORT_HELP_MAX_LEN + prefix_len]; + strncpy(help, prefix, ~0); + try { node.attribute("help").value(help + prefix_len, + sizeof(help) - prefix_len); } + catch (Xml_node::Nonexistent_attribute) { + PWRN("Missing help in '' configuration"); + continue; + } + + _arguments.insert(new Argument(name, help)); + } + } catch (Xml_node::Nonexistent_sub_node) { /* end of list */ } + + add_parameter(new Parameter("--ram", Parameter::NUMBER, "initial RAM quota")); + add_parameter(new Parameter("--ram-limit", Parameter::NUMBER, "limit for expanding RAM quota")); + add_parameter(new Parameter("--gdb-ram-preserve", Parameter::NUMBER, + "RAM quota which GDB monitor should preserve for itself (default: 5M)")); + add_parameter(new Parameter("--verbose", Parameter::VOID, "show diagnostics")); + } + + /** + * Lookup subsystem in config + */ + Xml_node _subsystem_node(char const *name) + { + Xml_node node = _config.sub_node("subsystem"); + for (;; node = node.next("subsystem")) { + if (node.attribute("name").has_value(name)) + return node; + } + } + + /** + * Generate the config node for the GDB subsystem + */ + Xml_node _gdb_config_node(const char *binary_name, + const char *target_config_addr, + const size_t target_config_size, + Genode::Number_of_bytes gdb_ram_preserve, + Terminal::Session &terminal) + { + /* local exception types */ + struct Config_buffer_overflow { }; + struct Binary_elf_check_failed { }; + + try { + Genode::Attached_rom_dataspace gdb_command_config_ds("gdb_command_config"); + + enum { CONFIG_BUF_SIZE = 4*1024 }; + static char config_buf[CONFIG_BUF_SIZE]; + + int config_bytes_written = 0; + + /* + * Copy the first part of the config file template + */ + + Xml_node init_config_node(gdb_command_config_ds.local_addr(), + gdb_command_config_ds.size()); + + Xml_node noux_node = init_config_node.sub_node("start"); + for (;; noux_node = noux_node.next("start")) + if (noux_node.attribute("name").has_value("noux")) + break; + + Xml_node noux_config_node = noux_node.sub_node("config"); + + /* Genode::strncpy() makes the last character '\0', so we need to add 1 byte */ + size_t bytes_to_copy = (Genode::addr_t)noux_config_node.content_addr() - + (Genode::addr_t)init_config_node.addr() + 1; + + if ((sizeof(config_buf) - config_bytes_written) < bytes_to_copy) + throw Config_buffer_overflow(); + + strncpy(&config_buf[config_bytes_written], + init_config_node.addr(), + bytes_to_copy); + + /* subtract the byte for '\0' again */ + config_bytes_written += bytes_to_copy - 1; + + /* + * Create the GDB arguments for breaking in 'main()' + */ + + enum { GDB_MAIN_BREAKPOINT_ARGS_BUF_SIZE = 768 }; + static char gdb_main_breakpoint_args_buf[GDB_MAIN_BREAKPOINT_ARGS_BUF_SIZE]; + + try { + Genode::Attached_rom_dataspace binary_rom_ds(binary_name); + Genode::Elf_binary elf_binary((Genode::addr_t)binary_rom_ds.local_addr()); + + if (elf_binary.is_dynamically_linked()) { + + snprintf(gdb_main_breakpoint_args_buf, + sizeof(gdb_main_breakpoint_args_buf), + "\n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n \ + \n", + binary_name); + } else { + + snprintf(gdb_main_breakpoint_args_buf, + sizeof(gdb_main_breakpoint_args_buf), + "\n \ + \n \ + \n \ + \n", + binary_name); + } + } catch (...) { + throw Binary_elf_check_failed(); + } + + /* + * Insert the '' node for 'noux' + */ + + config_bytes_written += snprintf(&config_buf[config_bytes_written], + sizeof(config_buf) - config_bytes_written, "\n \ + \n \ + \n \ + \n \ + \n \ + \n \ + %s \ + \n \ + ", + gdb_prefix, + binary_name, + gdb_main_breakpoint_args_buf); + + /* + * Copy the second part of the config file template + */ + + Xml_node gdb_monitor_node = noux_node.next("start"); + + /* Genode::strncpy() makes the last character '\0', so we need to add 1 byte */ + bytes_to_copy = (Genode::addr_t)gdb_monitor_node.content_addr() - + (Genode::addr_t)noux_config_node.content_addr() + 1; + + if ((sizeof(config_buf) - config_bytes_written) < bytes_to_copy) + throw Config_buffer_overflow(); + + strncpy(&config_buf[config_bytes_written], + noux_config_node.content_addr(), + bytes_to_copy); + + /* subtract the byte for '\0' again */ + config_bytes_written += bytes_to_copy - 1; + + /* + * Create a zero-terminated string for the GDB target config node + */ + + char target_config[target_config_size + 1]; + if (target_config_addr) + Genode::strncpy(target_config, target_config_addr, sizeof(target_config)); + else + target_config[0] = '\0'; + + /* + * Insert the '' node for 'gdb_monitor' + */ + + config_bytes_written += Genode::snprintf(&config_buf[config_bytes_written], + (sizeof(config_buf) - config_bytes_written), "\n \ + \n \ + \n \ + %s \ + \n \ + \n \ + \ + ", + binary_name, + target_config, + (size_t)gdb_ram_preserve); + + /* + * Copy the third (and final) part of the config file template + */ + + /* Genode::strncpy() makes the last character '\0', so we need to add 1 byte */ + bytes_to_copy = ((Genode::addr_t)init_config_node.addr() + + init_config_node.size()) - + (Genode::addr_t)gdb_monitor_node.content_addr() + 1; + + if ((sizeof(config_buf) - config_bytes_written) < bytes_to_copy) + throw Config_buffer_overflow(); + + strncpy(&config_buf[config_bytes_written], + gdb_monitor_node.content_addr(), + bytes_to_copy); + + /* subtract the byte for '\0' again */ + config_bytes_written += bytes_to_copy - 1; + + return Xml_node(config_buf, config_bytes_written); + + } catch (Config_buffer_overflow) { + tprintf(terminal, "Error: the buffer for the generated GDB " + "subsystem configuration is too small.\n"); + throw Child_configuration_failed(); + } catch (Binary_elf_check_failed) { + tprintf(terminal, "Error: could not determine link type of the " + "GDB target binary.\n"); + throw Child_configuration_failed(); + } + + } + + void execute(Command_line &cmd, Terminal::Session &terminal) + { + /* check if the GDB-related ROM modules are available */ + try { + Genode::Rom_connection gdb_command_config("gdb_command_config"); + Genode::Rom_connection terminal_crosslink("terminal_crosslink"); + Genode::Rom_connection noux("noux"); + Genode::Rom_connection gdb_monitor("gdb_monitor"); + } catch (Genode::Rom_connection::Rom_connection_failed) { + tprintf(terminal, "Error: The 'gdb' command needs the following ROM " + "modules (of which some are currently missing): " + "gdb_command_config, terminal_crosslink, noux, ", + "gdb_monitor\n"); + return; + } + + Genode::Number_of_bytes ram = 0; + Genode::Number_of_bytes ram_limit = 0; + Genode::Number_of_bytes gdb_ram_preserve = 10*1024*1024; + + char name[128]; + name[0] = 0; + if (cmd.argument(0, name, sizeof(name)) == false) { + tprintf(terminal, "Error: no configuration name specified\n"); + return; + } + + char buf[128]; + if (cmd.argument(1, buf, sizeof(buf))) { + tprintf(terminal, "Error: unexpected argument \"%s\"\n", buf); + return; + } + + /* check if a configuration for the subsystem exists */ + try { _subsystem_node(name); } + catch (Xml_node::Nonexistent_sub_node) { + tprintf(terminal, "Error: no configuration for \"%s\"\n", name); + return; + } + + /* read default RAM quota from config */ + try { + Xml_node rsc = _subsystem_node(name).sub_node("resource"); + for (;; rsc = rsc.next("resource")) { + if (rsc.attribute("name").has_value("RAM")) { + rsc.attribute("quantum").value(&ram); + + if (rsc.has_attribute("limit")) + rsc.attribute("limit").value(&ram_limit); + break; + } + } + } catch (...) { } + + cmd.parameter("--ram", ram); + cmd.parameter("--ram-limit", ram_limit); + cmd.parameter("--gdb-ram-preserve", gdb_ram_preserve); + + /* account for cli_monitor local metadata */ + size_t preserve_ram = 100*1024; + if ((ram + preserve_ram) > Genode::env()->ram_session()->avail()) { + tprintf(terminal, "Error: RAM quota exceeds available quota\n"); + return; + } + + bool const verbose = cmd.parameter_exists("--verbose"); + + /* + * Determine binary name + * + * Use subsystem name by default, override with '' declaration. + */ + char binary_name[128]; + strncpy(binary_name, name, sizeof(binary_name)); + try { + Xml_node bin = _subsystem_node(name).sub_node("binary"); + bin.attribute("name").value(binary_name, sizeof(binary_name)); + } catch (...) { } + + /* generate unique child name */ + char label[Child_registry::CHILD_NAME_MAX_LEN]; + _children.unique_child_name(name, label, sizeof(label)); + + tprintf(terminal, "starting new subsystem '%s'\n", label); + + if (verbose) { + tprintf(terminal, " RAM quota: "); + tprint_bytes(terminal, ram); + tprintf(terminal,"\n"); + if (ram_limit) { + tprintf(terminal, " RAM limit: "); + tprint_bytes(terminal, ram_limit); + tprintf(terminal,"\n"); + } + tprintf(terminal, " binary: %s\n", binary_name); + } + + Child *child = 0; + try { + + /* create child configuration */ + const char *target_config_addr = 0; + size_t target_config_size = 0; + try { + Xml_node target_config_node = _subsystem_node(name).sub_node("config"); + target_config_addr = target_config_node.addr(); + target_config_size = target_config_node.size(); + } catch (...) { } + + Xml_node config_node = _gdb_config_node(binary_name, + target_config_addr, + target_config_size, + gdb_ram_preserve, + terminal); + + /* create child */ + child = new (Genode::env()->heap()) + Gdb_command_child(_ram, label, "init", _cap, ram, ram_limit, + _yield_response_sigh_cap, _kill_gdb_sig_cap, + terminal); + + /* configure child */ + try { + child->configure(config_node.addr(), config_node.size()); + if (verbose) + tprintf(terminal, " config: inline\n"); + } catch (...) { + if (verbose) + tprintf(terminal, " config: none\n"); + } + + } + catch (Child_configuration_failed) { + return; + } + catch (Genode::Rom_connection::Rom_connection_failed) { + tprintf(terminal, "Error: could not obtain ROM module \"%s\"\n", + binary_name); + return; + } + catch (Child::Quota_exceeded) { + tprintf(terminal, "Error: insufficient memory, need "); + tprint_bytes(terminal, ram + Child::DONATED_RAM_QUOTA); + tprintf(terminal, ", have "); + tprint_bytes(terminal, Genode::env()->ram_session()->avail()); + tprintf(terminal, "\n"); + return; + } + catch (Genode::Allocator::Out_of_memory) { + tprintf(terminal, "Error: could not allocate meta data, out of memory\n"); + return; + } + + _process_args.list.insert(&child->argument); + _children.insert(child); + child->start(); + } + + List &arguments() { return _arguments; } +}; + +#endif /* _GDB_COMMAND_H_ */ diff --git a/os/src/app/cli_monitor/gdb_command_config b/os/src/app/cli_monitor/gdb_command_config new file mode 100644 index 0000000000..5c912d5567 --- /dev/null +++ b/os/src/app/cli_monitor/gdb_command_config @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/os/src/app/cli_monitor/main.cc b/os/src/app/cli_monitor/main.cc index 3e9843ea94..11012a2ea3 100644 --- a/os/src/app/cli_monitor/main.cc +++ b/os/src/app/cli_monitor/main.cc @@ -29,6 +29,7 @@ #include #include #include +#include using Genode::Xml_node; @@ -101,6 +102,10 @@ int main(int argc, char **argv) static Signal_context yield_broadcast_sig_ctx; static Signal_context resource_avail_sig_ctx; + static Signal_context kill_gdb_sig_ctx; + static Signal_context_capability kill_gdb_sig_cap = + sig_rec.manage(&kill_gdb_sig_ctx); + static Ram ram(ram_preservation_from_config(), sig_rec.manage(&yield_broadcast_sig_ctx), sig_rec.manage(&resource_avail_sig_ctx)); @@ -109,6 +114,11 @@ int main(int argc, char **argv) commands.insert(new Help_command); Kill_command kill_command(children, process_args); commands.insert(&kill_command); + commands.insert(new Gdb_command(ram, cap, children, + Genode::config()->xml_node(), + process_args, + yield_response_sig_cap, + kill_gdb_sig_cap)); commands.insert(new Start_command(ram, cap, children, Genode::config()->xml_node(), process_args, @@ -164,6 +174,22 @@ int main(int argc, char **argv) child->yield(amount, true); } + if (signal.context() == &kill_gdb_sig_ctx) { + for (Child *child = children.first(); child; child = child->next()) { + Gdb_command_child *gdb_command_child = + dynamic_cast(child); + if (gdb_command_child && gdb_command_child->kill_requested()) { + tprintf(terminal, "Destroying GDB subsystem after an error occured.\n"); + process_args.list.remove(&gdb_command_child->argument); + children.remove(gdb_command_child); + Genode::destroy(Genode::env()->heap(), gdb_command_child); + line_editor.reset(); + break; + } + } + continue; + } + if (!line_editor.is_complete()) continue; diff --git a/os/src/app/cli_monitor/target.mk b/os/src/app/cli_monitor/target.mk index e6fa140576..1f3fe53048 100644 --- a/os/src/app/cli_monitor/target.mk +++ b/os/src/app/cli_monitor/target.mk @@ -2,3 +2,11 @@ TARGET = cli_monitor SRC_CC = main.cc LIBS = base cli_monitor config INC_DIR += $(PRG_DIR) + +ifeq ($(findstring arm, $(SPECS)), arm) +INC_DIR += $(PRG_DIR)/arm +else +ifeq ($(findstring x86, $(SPECS)), x86) +INC_DIR += $(PRG_DIR)/x86 +endif +endif diff --git a/os/src/app/cli_monitor/x86/gdb_prefix.h b/os/src/app/cli_monitor/x86/gdb_prefix.h new file mode 100644 index 0000000000..decbd52d7a --- /dev/null +++ b/os/src/app/cli_monitor/x86/gdb_prefix.h @@ -0,0 +1,19 @@ +/* + * \brief Prefix of the GDB binary + * \author Christian Prochaska + * \date 2013-10-23 + */ + +/* + * Copyright (C) 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_PREFIX_H_ +#define _GDB_PREFIX_H_ + +static const char *gdb_prefix = "genode-x86-"; + +#endif /* _GDB_PREFIX_H_ */ diff --git a/ports/run/noux_gdb.inc b/ports/run/noux_gdb.inc new file mode 100644 index 0000000000..211c55c4f6 --- /dev/null +++ b/ports/run/noux_gdb.inc @@ -0,0 +1,69 @@ +# +# Utility functions for run scripts using Noux GDB +# + + +# +# Return the name of the Noux GDB package for the configured platform +# +proc noux_gdb_pkg_name { } { + if {[have_spec arm]} { + return "gdb_arm" + } elseif {[have_spec x86]} { + return "gdb_x86" + } +} + + +# +# Create a tar archive for GDB (stripped) +# +proc create_gdb_tar { } { + exec sh -c "find bin/[noux_gdb_pkg_name]/ -type f | (xargs [cross_dev_prefix]strip || true) 2>/dev/null" + exec tar cfhv bin/gdb.tar -C bin/[noux_gdb_pkg_name] . +} + + +# +# Create a tar archive for a Noux application and its shared libraries (unstripped) +# +proc create_binary_tar { application_name application_binaries } { + foreach application_binary ${application_binaries} { + exec tar ufv bin/${application_name}.tar -h -C bin ${application_binary} + } +} + + +# +# Create a tar archive for the source code of a Noux application and its shared +# libraries. +# +# Currently, directories need to have their own tar records +# +proc create_source_tar { application_name application_binaries } { + exec mkdir -p bin/${application_name}-src + foreach application_binary $application_binaries { + set source_files [ exec [cross_dev_prefix]objdump -dl bin/${application_binary} | grep "^/.*:.*" | sed -e "s/:.*//" | uniq ] + foreach source_file ${source_files} { + # resolve '..' to avoid problems with 'tar' with parts like '/a/b/../' + # where '/a' exists, but '/a/b' does not + set source_file [file normalize ${source_file}] + if [file exists ${source_file}] { + set dirname [ exec dirname ${source_file}] + exec mkdir -p bin/${application_name}-src${dirname} + exec ln -sf ${source_file} bin/${application_name}-src${source_file} + } + } + } + exec tar chf bin/${application_name}-src.tar -C bin/${application_name}-src . +} + + +# +# Create tar archives for binaries and source code of a Noux application +# +proc create_binary_and_source_tars { application_name application_binaries } { + create_binary_tar ${application_name} ${application_binaries} + create_source_tar ${application_name} ${application_binaries} +} + diff --git a/ports/run/noux_gdb.run b/ports/run/noux_gdb.run index 329d5083a2..f4c6d1df08 100644 --- a/ports/run/noux_gdb.run +++ b/ports/run/noux_gdb.run @@ -3,13 +3,13 @@ if {![have_spec foc] || ![have_spec 32bit]} { exit 0 } +source ${genode_dir}/ports/run/noux_gdb.inc + if {[have_spec arm]} { - set gdb "gdb_arm" set tool_prefix "genode-arm-" } if {[have_spec x86]} { - set gdb "gdb_x86" set tool_prefix "genode-x86-" } @@ -17,57 +17,34 @@ if {[have_spec x86]} { # Uncomment the following line when working on the GDB source code. Otherwise, # the package may get recompiled, yet it does not get reinstalled into 'bin/'. # -#exec rm -rf noux-pkg/$gdb/ bin/$gdb/ +#exec rm -rf noux-pkg/[noux_gdb_pkg_name]/ bin/[noux_gdb_pkg_name]/ set build_components { core init drivers/timer noux lib/libc_noux drivers/framebuffer drivers/pci drivers/input drivers/usb server/terminal server/terminal_crosslink - server/ram_fs app/gdb_monitor + app/gdb_monitor test/gdb_monitor } -lappend build_components noux-pkg/$gdb +lappend build_components noux-pkg/[noux_gdb_pkg_name] + +# the application to be debugged with GDB +lappend build_components test/gdb_monitor +set gdb_target_binary_name test-gdb_monitor build $build_components -# tar archive for GDB - -exec sh -c "find bin/$gdb/ -type f | (xargs [cross_dev_prefix]strip || true) 2>/dev/null" -exec tar cfhv bin/gdb.tar -C bin/$gdb . - # names of the binaries needed for the GDB monitor test - -set test_binaries { +set gdb_target_binaries { test-gdb_monitor ld.lib.so libc.lib.so libc_log.lib.so } +lappend gdb_target_binaries ${gdb_target_binary_name} -# tar archive for the unstripped binaries of the GDB monitor test - -foreach test_binary $test_binaries { - exec tar ufv bin/test-gdb_monitor.tar -h -C bin $test_binary -} - -# tar archive for the source code of the GDB monitor test -# currently, directories need to have their own tar records - -exec mkdir -p bin/test-gdb_monitor-src -foreach test_binary $test_binaries { - set source_files [ exec [cross_dev_prefix]objdump -dl bin/$test_binary | grep "^/.*:.*" | sed -e "s/:.*//" | uniq ] - foreach source_file $source_files { - # resolve '..' to avoid problems with 'tar' with parts like '/a/b/../' - # where '/a' exists, but '/a/b' does not - set source_file [file normalize $source_file] - if [file exists $source_file] { - set dirname [ exec dirname $source_file] - exec mkdir -p bin/test-gdb_monitor-src$dirname - exec ln -sf $source_file bin/test-gdb_monitor-src$source_file - } - } -} -exec tar chf bin/test-gdb_monitor-src.tar -C bin/test-gdb_monitor-src . +create_gdb_tar +create_binary_and_source_tars ${gdb_target_binary_name} ${gdb_target_binaries} create_boot_directory @@ -149,39 +126,13 @@ append config { - - + } +append config " + " +append config { - - - - - - - - set interactive-mode off - directory /gdb/src - target remote /dev/gdb - symbol-file /gdb/ld.lib.so - b call_main - c - delete 1 - symbol-file /gdb/test-gdb_monitor - b main - set solib-search-path /gdb - sharedlibrary - c - delete 2 - set interactive-mode auto - - - - - - - @@ -197,17 +148,34 @@ append config { - - - - + } +append config " + + " +append config { } append config " - " + + + " append config { - - + + + + + + + } +append config " + " +append config { + + + + + + @@ -226,7 +194,7 @@ set boot_modules { core init timer ld.lib.so noux terminal terminal_crosslink libc.lib.so libm.lib.so libc_noux.lib.so ncurses.lib.so expat.lib.so libc_lock_pipe.lib.so libc_log.lib.so libc_terminal.lib.so - ram_fs gdb_monitor test-gdb_monitor + gdb_monitor test-gdb_monitor gdb.tar test-gdb_monitor.tar test-gdb_monitor-src.tar } diff --git a/ports/run/noux_gdb_dynamic.run b/ports/run/noux_gdb_dynamic.run new file mode 100644 index 0000000000..5f10020e95 --- /dev/null +++ b/ports/run/noux_gdb_dynamic.run @@ -0,0 +1,165 @@ +if {![have_spec foc] || ![have_spec 32bit]} { + puts "\nThe Noux GDB scenario is supported on 32-bit Fiasco.OC only\n" + exit 0 +} + +source ${genode_dir}/ports/run/noux_gdb.inc + +# +# Uncomment the following line when working on the GDB source code. Otherwise, +# the package may get recompiled, yet it does not get reinstalled into 'bin/'. +# +#exec rm -rf noux-pkg/[noux_gdb_pkg_name]/ bin/[noux_gdb_pkg_name]/ + +set build_components { + core init drivers/timer noux lib/libc_noux + drivers/uart + server/terminal_mux server/terminal_crosslink + server/terminal_log + app/cli_monitor + app/gdb_monitor +} +lappend build_components noux-pkg/[noux_gdb_pkg_name] + +lappend build_components test/gdb_monitor +set gdb_target_binary_name test-gdb_monitor + +build $build_components + +# names of the binaries needed for the GDB monitor test +set gdb_target_binaries { + ld.lib.so + libc.lib.so + libc_log.lib.so +} +lappend gdb_target_binaries ${gdb_target_binary_name} + +create_gdb_tar +create_binary_and_source_tars "gdb_target" ${gdb_target_binaries} + +create_boot_directory + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + } + +# use kernel debugger as UART on Fiasco.OC +append_if [have_spec foc] config { + } + +append config { + + + + + + } + +# on Fiasco.OC the kdb_uart_drv is always UART 0 +append_if [have_spec foc] config { + } + +# on all other kernels, direct terminal_mux to UART 1 (Qemu stdio, see below) +append_if [expr ![have_spec foc]] config { + } + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + } +append config " + " +append config { + + + + + + + + + + +} + +install_config $config + + +# +# Boot modules +# + +exec cp ${genode_dir}/os/src/app/cli_monitor/gdb_command_config bin + +# generic modules +set boot_modules { + core init timer ld.lib.so noux terminal_mux terminal_crosslink + libc.lib.so libm.lib.so libc_noux.lib.so ncurses.lib.so expat.lib.so + libc_lock_pipe.lib.so libc_log.lib.so libc_terminal.lib.so + cli_monitor gdb_monitor terminal_log gdb.tar + gdb_command_config + gdb_target.tar + gdb_target-src.tar +} +lappend boot_modules ${gdb_target_binary_name} + +# platform-specific modules +lappend_if [expr ![have_spec foc]] boot_modules uart_drv +lappend_if [have_spec foc] boot_modules kdb_uart_drv + +set fiasco_serial_esc_arg "" + +build_boot_image $boot_modules + +append qemu_args " -nographic " + +run_genode_until forever + +exec rm bin/gdb.tar