diff --git a/Makefile.cfg b/Makefile.cfg index 53425f351f20bc5aa3d1167497914415778b9feb..de4fe1f9a07c2c70f1dad08890c1acb71d9fd6d5 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -61,7 +61,7 @@ COVERAGE := no # Set it to 'yes' to enable extra features for the debugger UI in single mode # (this requires an extra library when linking the generated code). # Set it to 'no' to use a simplified debugger UI. -ADVANCED_DEBUGGER_UI := yes +ADVANCED_DEBUGGER_UI := no # Your platform. Allowed values: SOLARIS, SOLARIS8, LINUX, FREEBSD, # WIN32. Decided automagically if not defined (recommended). diff --git a/compiler2/DebuggerStuff.cc b/compiler2/DebuggerStuff.cc index 72de2f91af3c8ddcc8159a8d3284df25018bc123..955f462bdac7eac540fa318007cbab09653f353f 100644 --- a/compiler2/DebuggerStuff.cc +++ b/compiler2/DebuggerStuff.cc @@ -319,7 +319,17 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, print_function += ">"; } - return mputprintf(str, "%s%s_scope%sadd_variable(&%s, \"%s\", \"%s\", %s%s%s);\n", + string module_str; + if (scope_name != NULL && !strcmp(scope_name, "global")) { + // only store the module name for global variables + module_str = string("\"") + + var_ass->get_my_scope()->get_scope_mod()->get_modid().get_ttcnname() + string("\""); + } + else { + module_str = "NULL"; + } + + return mputprintf(str, "%s%s_scope%sadd_variable(&%s, \"%s\", \"%s\", %s, %s%s%s);\n", scope_name != NULL ? " " : "", // add indenting for global variables scope_name != NULL ? scope_name : "debug", // the prefix of the debugger scope: // ("global" for global variables, "debug" for local variables, @@ -331,6 +341,7 @@ char* generate_code_debugger_add_var(char* str, Common::Assignment* var_ass, // so the lazy parameter evaluation code is not generated) var_ass->get_id().get_ttcnname().c_str(), // variable name in TTCN-3 type_name.c_str(), // variable type in TTCN-3, with a suffix if it's a template + module_str.c_str(), // module name, where the variable was defined print_function.c_str(), // variable printing function is_constant ? "" : ", ", is_constant ? "" : set_function.c_str()); // variable overwriting function (not generated for constants) diff --git a/core/DebugCommands.hh b/core/DebugCommands.hh index a2ed895dede3199370f9549814e16638a7da260b..96bc6ec915093a024a2adbf4dc12d3c3cf55e2e5 100644 --- a/core/DebugCommands.hh +++ b/core/DebugCommands.hh @@ -23,26 +23,28 @@ #define D_SET_AUTOMATIC_BREAKPOINT 4 // 2-3, "error" or "fail", + "off", or "on" + optional batch file name #define D_SET_OUTPUT 5 // 1-2, "console", or "file" or "both", + file name #define D_SET_GLOBAL_BATCH_FILE 6 // 1-2, "off", or "on" + batch file name +#define D_PRINT_SETTINGS 7 // 0 // printing and overwriting data -#define D_SET_COMPONENT 7 // 1, "mtc" or component reference -#define D_PRINT_CALL_STACK 8 // 0 -#define D_SET_STACK_LEVEL 9 // 1, stack level -#define D_LIST_VARIABLES 10 // 1-2, "local", "global", "comp" or "all", + optional filter (pattern) -#define D_PRINT_VARIABLE 11 // 1+, list of variable names -#define D_OVERWRITE_VARIABLE 12 // 2, variable name, new value (in module parameter syntax) -#define D_PRINT_SNAPSHOTS 13 // 0 -#define D_SET_SNAPSHOT_BEHAVIOR 14 // TBD +#define D_LIST_COMPONENTS 8 // 0 +#define D_SET_COMPONENT 9 // 1, "mtc" or component reference +#define D_PRINT_CALL_STACK 10 // 0 +#define D_SET_STACK_LEVEL 11 // 1, stack level +#define D_LIST_VARIABLES 12 // 1-2, "local", "global", "comp" or "all", + optional filter (pattern) +#define D_PRINT_VARIABLE 13 // 1+, list of variable names +#define D_OVERWRITE_VARIABLE 14 // 2, variable name, new value (in module parameter syntax) +#define D_PRINT_SNAPSHOTS 15 // 0 +#define D_SET_SNAPSHOT_BEHAVIOR 16 // TBD // stepping -#define D_STEP_OVER 15 // 0 -#define D_STEP_INTO 16 // 0 -#define D_STEP_OUT 17 // 0 -#define D_RUN_TO_CURSOR 18 // 2, module name and line number +#define D_STEP_OVER 17 // 0 +#define D_STEP_INTO 18 // 0 +#define D_STEP_OUT 19 // 0 +#define D_RUN_TO_CURSOR 20 // 2, module name and line number // the halted state -#define D_HALT 19 // 0 -#define D_CONTINUE 20 // 0 -#define D_EXIT 21 // 1, "test" or "all" +#define D_HALT 21 // 0 +#define D_CONTINUE 22 // 0 +#define D_EXIT 23 // 1, "test" or "all" // initialization -#define D_SETUP 22 // 9+: +#define D_SETUP 24 // 9+: // 1 argument for D_SWITCH, // 2 arguments for D_SET_OUTPUT, // 2 arguments (2nd and 3rd) for D_SET_AUTOMATIC_BREAKPOINT, where the first argument is "error", @@ -60,7 +62,9 @@ #define D_SET_AUTOMATIC_BREAKPOINT_TEXT "dautobp" #define D_SET_OUTPUT_TEXT "doutput" #define D_SET_GLOBAL_BATCH_FILE_TEXT "dglobbatch" -#define D_SET_COMPONENT_TEXT "dcomp" +#define D_PRINT_SETTINGS_TEXT "dsettings" +#define D_LIST_COMPONENTS_TEXT "dlistcomp" +#define D_SET_COMPONENT_TEXT "dsetcomp" #define D_PRINT_CALL_STACK_TEXT "dprintstack" #define D_SET_STACK_LEVEL_TEXT "dstacklevel" #define D_LIST_VARIABLES_TEXT "dlistvar" diff --git a/core/Debugger.cc b/core/Debugger.cc index 97a8643e470bbdce9f132399f81e1770f021c9db..fb5da1538237355c560e9f158444c9b8b9a8b962 100644 --- a/core/Debugger.cc +++ b/core/Debugger.cc @@ -250,11 +250,53 @@ void TTCN3_Debugger::set_automatic_breakpoint(const char* p_event_str, *old_batch_file_ptr = p_batch_file != NULL ? mcopystr(p_batch_file) : NULL; } +void TTCN3_Debugger::print_settings() +{ + // on/off switch + add_to_result("Debugger is switched %s.\n", active ? "on" : "off"); + // output + char* final_file_name = finalize_file_name(output_file_name); + char* file_str = output_file != NULL ? mprintf("file '%s'", final_file_name) : NULL; + Free(final_file_name); + add_to_result("Output is printed to %s%s%s.\n", + send_to_console ? "the console" : "", + (send_to_console && output_file != NULL) ? " and to " : "", + output_file != NULL ? file_str : ""); + Free(file_str); + // global batch file + add_to_result("Global batch file%s%s.\n", global_batch_file != NULL ? ": " : "", + global_batch_file != NULL ? global_batch_file : " not set"); + // user breakpoints + if (breakpoints.empty()) { + add_to_result("No user breakpoints.\n"); + } + else { + add_to_result("User breakpoints:\n"); + for (size_t i = 0; i < breakpoints.size(); ++i) { + const breakpoint_t& bp = breakpoints[i]; + add_to_result("%s %d %s\n", bp.module, bp.line, + bp.batch_file != NULL ? bp.batch_file : ""); + } + } + // automatic breakpoints + add_to_result("Automatic breakpoints:\nerror %s %s\nfail %s %s", + error_behavior.trigger ? "on" : "off", + error_behavior.batch_file != NULL ? error_behavior.batch_file : "", + fail_behavior.trigger ? "on" : "off", + fail_behavior.batch_file != NULL ? fail_behavior.batch_file : ""); +} + +#define STACK_LEVEL (stack_level >= 0) ? (size_t)stack_level : (call_stack.size() - 1) + void TTCN3_Debugger::print_call_stack() { for (size_t i = call_stack.size(); i != 0; --i) { add_to_result("%d.\t", (int)call_stack.size() - (int)i + 1); call_stack[i - 1].function->print_function(); + if (i - 1 == (STACK_LEVEL)) { + // mark the active stack level with an asterisk + add_to_result("*"); + } if (i != 1) { add_to_result("\n"); } @@ -279,14 +321,13 @@ void TTCN3_Debugger::set_stack_level(int new_level) } } -#define STACK_LEVEL (stack_level >= 0) ? (size_t)stack_level : (call_stack.size() - 1) - void TTCN3_Debugger::print_variable(const char* p_var_name) { const variable_t* var = call_stack[STACK_LEVEL].function->find_variable(p_var_name); if (var != NULL) { - add_to_result("[%s] %s := %s", var->type_name, var->name, - (const char*)var->print_function(*var)); + add_to_result("[%s] %s%s%s := %s", var->type_name, + var->module != NULL ? var->module : "", var->module != NULL ? "." : "", + var->name, (const char*)var->print_function(*var)); } else { add_to_result("Variable '%s' not found.", p_var_name); @@ -1121,6 +1162,7 @@ void TTCN3_Debugger::remove_scope(TTCN3_Debug_Scope* p_scope) TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(const void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function) { if (call_stack.empty()) { @@ -1131,6 +1173,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(const void* p_value, var->cvalue = p_value; var->name = p_name; var->type_name = p_type; + var->module = p_module; var->print_function = p_print_function; var->set_function = NULL; variables.push_back(var); @@ -1140,7 +1183,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(const void* p_value, else if (active) { // it's a local variable for the top-most function return call_stack[call_stack.size() - 1].function->add_variable( - p_value, p_name, p_type, p_print_function); + p_value, p_name, p_type, p_module, p_print_function); } return NULL; } @@ -1148,6 +1191,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(const void* p_value, TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function, TTCN3_Debugger::set_function_t p_set_function) { @@ -1159,6 +1203,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(void* p_value, var->value = p_value; var->name = p_name; var->type_name = p_type; + var->module = p_module; var->print_function = p_print_function; var->set_function = p_set_function; variables.push_back(var); @@ -1168,7 +1213,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(void* p_value, else if (active) { // it's a local variable for the top-most function return call_stack[call_stack.size() - 1].function->add_variable( - p_value, p_name, p_type, p_print_function); + p_value, p_name, p_type, p_module, p_print_function, p_set_function); } return NULL; } @@ -1296,10 +1341,9 @@ void TTCN3_Debugger::execute_command(int p_command, int p_argument_count, CHECK_NOF_ARGUMENTS_RANGE(1, 2) set_global_batch_file(p_arguments[0], (p_argument_count == 2) ? p_arguments[1] : NULL); break; - case D_SET_COMPONENT: - print(DRET_NOTIFICATION, "Command " D_SET_COMPONENT_TEXT " %s.", - TTCN_Runtime::is_single() ? "is not available in single mode" : - "should have been sent to the Main Controller"); + case D_PRINT_SETTINGS: + CHECK_NOF_ARGUMENTS(0) + print_settings(); break; case D_PRINT_CALL_STACK: CHECK_CALL_STACK(true) @@ -1479,9 +1523,11 @@ TTCN3_Debug_Scope::~TTCN3_Debug_Scope() void TTCN3_Debug_Scope::add_variable(const void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function) { - TTCN3_Debugger::variable_t* var = ttcn3_debugger.add_variable(p_value, p_name, p_type, p_print_function); + TTCN3_Debugger::variable_t* var = ttcn3_debugger.add_variable(p_value, p_name, + p_type, p_module, p_print_function); if (var != NULL) { variables.push_back(var); } @@ -1490,11 +1536,12 @@ void TTCN3_Debug_Scope::add_variable(const void* p_value, void TTCN3_Debug_Scope::add_variable(void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function, TTCN3_Debugger::set_function_t p_set_function) { TTCN3_Debugger::variable_t* var = ttcn3_debugger.add_variable(p_value, p_name, - p_type, p_print_function, p_set_function); + p_type, p_module, p_print_function, p_set_function); if (var != NULL) { variables.push_back(var); } @@ -1503,19 +1550,35 @@ void TTCN3_Debug_Scope::add_variable(void* p_value, TTCN3_Debugger::variable_t* TTCN3_Debug_Scope::find_variable(const char* p_name) const { for (size_t i = 0; i < variables.size(); ++i) { - if (strcmp(variables[i]->name, p_name) == 0) { - return variables[i]; + TTCN3_Debugger::variable_t* var = variables[i]; + if (strcmp(var->name, p_name) == 0) { + // the string matches the variable's name + return var; + } + else if (var->module != NULL) { + size_t name_len = strlen(var->name); + size_t mod_len = strlen(var->module); + size_t len = strlen(p_name); + if (len == mod_len + name_len + 1 && p_name[mod_len] == '.' && + strncmp(p_name, var->module, mod_len) == 0 && + strncmp(p_name + mod_len + 1, var->name, name_len) == 0) { + // the string matches the variable's name prefixed by its module name + return var; + } } } return NULL; } -void TTCN3_Debug_Scope::list_variables(regex_t* p_posix_regexp, bool& p_first) const +void TTCN3_Debug_Scope::list_variables(regex_t* p_posix_regexp, bool& p_first, + const char* p_module) const { for (size_t i = 0; i < variables.size(); ++i) { if (p_posix_regexp == NULL || regexec(p_posix_regexp, variables[i]->name, 0, NULL, 0) == 0) { - ttcn3_debugger.add_to_result("%s%s", p_first ? "" : " ", variables[i]->name); + bool imported = p_module != NULL && strcmp(p_module, variables[i]->module) != 0; + ttcn3_debugger.add_to_result("%s%s%s%s", p_first ? "" : " ", + imported ? variables[i]->module : "", imported ? "." : "", variables[i]->name); p_first = false; } } @@ -1582,6 +1645,7 @@ TTCN3_Debug_Function::~TTCN3_Debug_Function() TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(const void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function) { if (ttcn3_debugger.is_on()) { @@ -1589,6 +1653,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(const void* p_val var->cvalue = p_value; var->name = p_name; var->type_name = p_type; + var->module = p_module; var->print_function = p_print_function; var->set_function = NULL; variables.push_back(var); @@ -1600,6 +1665,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(const void* p_val TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(void* p_value, const char* p_name, const char* p_type, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function, TTCN3_Debugger::set_function_t p_set_function) { @@ -1608,6 +1674,7 @@ TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(void* p_value, var->value = p_value; var->name = p_name; var->type_name = p_type; + var->module = p_module; var->print_function = p_print_function; var->set_function = p_set_function; variables.push_back(var); @@ -1759,10 +1826,10 @@ void TTCN3_Debug_Function::list_variables(const char* p_scope, const char* p_fil } } if (list_global && global_scope != NULL && global_scope->has_variables()) { - global_scope->list_variables(posix_regexp, first); + global_scope->list_variables(posix_regexp, first, module_name); } if (list_comp && component_scope != NULL && component_scope->has_variables()) { - component_scope->list_variables(posix_regexp, first); + component_scope->list_variables(posix_regexp, first, NULL); } if (first) { ttcn3_debugger.print(DRET_NOTIFICATION, "No variables found."); diff --git a/core/Debugger.hh b/core/Debugger.hh index be101ea0bd4c4c71477b30727c03f8bfbf7d9d4b..6b253b65fea67b09f1e2dbcc1164ec097df89411 100644 --- a/core/Debugger.hh +++ b/core/Debugger.hh @@ -64,6 +64,9 @@ public: const char* name; /** name of the variable's type, not owned */ const char* type_name; + /** name of the module the variable was declared in (only set for global + * variables, otherwise NULL), not owned */ + const char* module; /** variable printing function (using the variable object's log() function) */ print_function_t print_function; /** variable setting (overwriting) function (using the variable object's @@ -243,6 +246,10 @@ private: void set_automatic_breakpoint(const char* p_event_str, const char* p_state_str, const char* p_batch_file); + /** prints the debugger's settings + * handles the D_PRINT_SETTINGS command */ + void print_settings(); + /** prints the current call stack * handles the D_PRINT_CALL_STACK command */ void print_call_stack(); @@ -477,11 +484,12 @@ public: * if the call stack is not empty (and if the debugger is switched on), the * variable entry for a local variable is created and stored by the current function */ variable_t* add_variable(const void* p_value, const char* p_name, const char* p_type, - print_function_t p_print_function); + const char* p_module, print_function_t p_print_function); /** same as before, but for non-constant variables */ variable_t* add_variable(void* p_value, const char* p_name, const char* p_type, - print_function_t p_print_function, set_function_t p_set_function); + const char* p_module, print_function_t p_print_function, + set_function_t p_set_function); /** removes the variable entry for the specified local variable in the current * function (only if the call stack is not empty) */ @@ -559,11 +567,11 @@ public: * variable by storing a pointer to it * (local variables are only created and stored if the debugger is switched on) */ void add_variable(const void* p_value, const char* p_name, const char* p_type, - TTCN3_Debugger::print_function_t p_print_function); + const char* p_module, TTCN3_Debugger::print_function_t p_print_function); /** same as before, but for non-constant variables */ void add_variable(void* p_value, const char* p_name, const char* p_type, - TTCN3_Debugger::print_function_t p_print_function, + const char* p_module, TTCN3_Debugger::print_function_t p_print_function, TTCN3_Debugger::set_function_t p_set_function); ////////////////////////////////////////////////////// @@ -573,13 +581,19 @@ public: /** returns true if there is at least one variable in the scope object */ bool has_variables() const { return !variables.empty(); } - /** returns the specified variable, if found, otherwise returns NULL */ + /** returns the specified variable, if found, otherwise returns NULL + * (the name searched for can also be prefixed with the module name in + * case of global variables) */ TTCN3_Debugger::variable_t* find_variable(const char* p_name) const; - /** prints the names of variables in this scope that match the specified + /** prints the names of variables in this scope that match the specified; + * names of imported global variables are prefixed with their module's name * @param p_posix_regexp the pattern converted into a POSIX regex structure - * @param p_first true if no variables have been printed yet */ - void list_variables(regex_t* p_posix_regexp, bool& p_first) const; + * @param p_first true if no variables have been printed yet + * @param p_module name of the current module, if it's a global scope, + * otherwise NULL */ + void list_variables(regex_t* p_posix_regexp, bool& p_first, + const char* p_module) const; }; @@ -653,11 +667,13 @@ public: /** creates, stores and returns the variable entry of the local (constant) variable * specified by the parameters (only if the debugger is switched on) */ TTCN3_Debugger::variable_t* add_variable(const void* p_value, const char* p_name, - const char* p_type, TTCN3_Debugger::print_function_t p_print_function); + const char* p_type, const char* p_module, + TTCN3_Debugger::print_function_t p_print_function); /** same as before, but for non-constant variables */ TTCN3_Debugger::variable_t* add_variable(void* p_value, const char* p_name, - const char* p_type, TTCN3_Debugger::print_function_t p_print_function, + const char* p_type, const char* p_module, + TTCN3_Debugger::print_function_t p_print_function, TTCN3_Debugger::set_function_t p_set_function); /** stores the string representation of the value returned by the function */ diff --git a/core/DebuggerUI.cc b/core/DebuggerUI.cc index 37b75e7c0bd30e1e8440264c46c25a255ccbf120..aa583b25fff3b8901854a5c24a09075fbf53345e 100644 --- a/core/DebuggerUI.cc +++ b/core/DebuggerUI.cc @@ -48,9 +48,8 @@ const TTCN_Debugger_UI::command_t TTCN_Debugger_UI::debug_command_list[] = { D_SET_GLOBAL_BATCH_FILE_TEXT " on|off [batch_file_name]", "Set whether a batch file should be executed automatically when test execution " "is halted (breakpoint-specific batch files override this setting)." }, - { D_SET_COMPONENT_TEXT, D_SET_COMPONENT, - D_SET_COMPONENT_TEXT " mtc|<component_reference>", "Set the test component " - "to print debug information from (not available in single mode)." }, + { D_PRINT_SETTINGS_TEXT, D_PRINT_SETTINGS, D_PRINT_SETTINGS_TEXT, + "Prints the debugger's settings." }, { D_PRINT_CALL_STACK_TEXT, D_PRINT_CALL_STACK, D_PRINT_CALL_STACK_TEXT, "Print call stack." }, { D_SET_STACK_LEVEL_TEXT, D_SET_STACK_LEVEL, D_SET_STACK_LEVEL_TEXT " <level>", diff --git a/mctr2/cli/Cli.cc b/mctr2/cli/Cli.cc index bf10cfb2f0c8e49819d9590618f8f7f8f88a0a91..d76a83c076e33cc7568255f0a8dd35190e034b62 100644 --- a/mctr2/cli/Cli.cc +++ b/mctr2/cli/Cli.cc @@ -135,8 +135,12 @@ static const DebugCommand debug_command_list[] = { D_SET_GLOBAL_BATCH_FILE_TEXT " on|off [batch_file_name]", "Set whether a batch file should be executed automatically when test execution " "is halted (breakpoint-specific batch files override this setting)." }, + { D_PRINT_SETTINGS_TEXT, D_PRINT_SETTINGS, D_PRINT_SETTINGS_TEXT, + "Prints the debugger's settings." }, + { D_LIST_COMPONENTS_TEXT, D_LIST_COMPONENTS, D_LIST_COMPONENTS_TEXT, + "List the test components currently running debuggable code." }, { D_SET_COMPONENT_TEXT, D_SET_COMPONENT, - D_SET_COMPONENT_TEXT " mtc|<component_reference>", + D_SET_COMPONENT_TEXT " <component name>|<component_reference>", "Set the test component to print debug information from." }, { D_PRINT_CALL_STACK_TEXT, D_PRINT_CALL_STACK, D_PRINT_CALL_STACK_TEXT, "Print call stack." }, diff --git a/mctr2/mctr/MainController.cc b/mctr2/mctr/MainController.cc index 64f0dfe6fb6c0b7520b8b02ad61c86c25167e4bc..c869353d5c6041961f93173f692fac4561ff7d4a 100644 --- a/mctr2/mctr/MainController.cc +++ b/mctr2/mctr/MainController.cc @@ -5618,6 +5618,28 @@ void MainController::process_debug_return_value(Text_Buf& text_buf, char* log_so } } +static bool is_tc_debuggable(const component_struct* tc) +{ + if (tc->comp_ref == MTC_COMPREF || tc->comp_ref == SYSTEM_COMPREF) { + return true; // let these pass, they are checked later + } + switch (tc->tc_state) { + case TC_CREATE: + case TC_START: + case TC_STOP: + case TC_KILL: + case TC_CONNECT: + case TC_DISCONNECT: + case TC_MAP: + case TC_UNMAP: + case PTC_FUNCTION: + case PTC_STARTING: + return true; + default: + return false; + } +} + void MainController::process_debug_broadcast_req(component_struct* tc, int commandID) { // don't send the command back to the requesting component @@ -5626,7 +5648,7 @@ void MainController::process_debug_broadcast_req(component_struct* tc, int comma } for (component i = tc_first_comp_ref; i < n_components; ++i) { component_struct* comp = components[i]; - if (tc != comp && comp->tc_state != PTC_STALE && comp->tc_state != TC_EXITED) { + if (tc != comp && is_tc_debuggable(comp)) { send_debug_command(comp->tc_fd, commandID, ""); } } @@ -6483,36 +6505,72 @@ void MainController::debug_command(int commandID, char* arguments) lock(); if (mtc != NULL) { switch (commandID) { - case D_SET_COMPONENT: // handled by the MC - if (!strcmp(arguments, "mtc")) { - notify("Debugger %sset to print data from the MTC.", - debugger_active_tc == mtc ? "was already " : ""); - debugger_active_tc = mtc; + case D_LIST_COMPONENTS: // handled by the MC + if (*arguments != 0) { + notify("Invalid number of arguments, expected 0."); } else { - size_t len = strlen(arguments); - for (size_t i = 0; i < len; ++i) { - if (arguments[i] < '0' || arguments[i] > '9') { - notify("Argument 1 is invalid. Expected 'mtc' or integer value " - "(component reference)."); - unlock(); - return; + // the active component is marked with an asterisk + char* result = mprintf("%s(%d)%s", mtc->comp_name, mtc->comp_ref, + debugger_active_tc == mtc ? "*" : ""); + for (component i = FIRST_PTC_COMPREF; i < n_components; ++i) { + component_struct* comp = components[i]; + if (comp != NULL && is_tc_debuggable(comp)) { + if (comp->comp_name != NULL) { + result = mputprintf(result, " %s(%d)%s", comp->comp_name, comp->comp_ref, + debugger_active_tc == comp ? "*" : ""); + } + else { + result = mputprintf(result, " %d%s", comp->comp_ref, + debugger_active_tc == comp ? "*" : ""); + } } } - const component_struct* tc = lookup_component(strtol(arguments, NULL, 10)); - if (tc == NULL || tc->tc_state == PTC_STALE || tc->tc_state == TC_EXITED) { - notify("Invalid component reference %s.", arguments); + notify("%s", result); + Free(result); + } + break; + case D_SET_COMPONENT: { // handled by the MC + bool number = true; + size_t len = strlen(arguments); + for (size_t i = 0; i < len; ++i) { + if (arguments[i] < '0' || arguments[i] > '9') { + number = false; + break; } - else { - notify("Debugger %sset to print data from PTC %s%s%d%s.", - debugger_active_tc == tc ? "was already " : "", - tc->comp_name != NULL ? tc->comp_name : "", - tc->comp_name != NULL ? "(" : "", tc->comp_ref, - tc->comp_name != NULL ? ")" : ""); - debugger_active_tc = tc; + } + component_struct* tc = NULL; + if (number) { // component reference + tc = lookup_component(strtol(arguments, NULL, 10)); + } + else { // component name + for (component i = 1; i < n_components; ++i) { + component_struct *comp = components[i]; + if (comp != NULL && comp->comp_name != NULL && is_tc_debuggable(comp) + && !strcmp(comp->comp_name, arguments)) { + tc = comp; + break; + } } } - break; + if (tc == system) { + notify("Debugging is not available on %s(%d).", tc->comp_name, tc->comp_ref); + } + else if (tc == NULL || !is_tc_debuggable(tc)) { + notify("Component with %s %s does not exist or is not running anything.", + number ? "reference" : "name", arguments); + } + else { + notify("Debugger %sset to print data from %s %s%s%d%s.", + debugger_active_tc == tc ? "was already " : "", + tc == mtc ? "the" : "PTC", + tc->comp_name != NULL ? tc->comp_name : "", + tc->comp_name != NULL ? "(" : "", tc->comp_ref, + tc->comp_name != NULL ? ")" : ""); + debugger_active_tc = tc; + } + break; } + case D_PRINT_SETTINGS: case D_PRINT_CALL_STACK: case D_SET_STACK_LEVEL: case D_LIST_VARIABLES: @@ -6521,12 +6579,9 @@ void MainController::debug_command(int commandID, char* arguments) case D_PRINT_SNAPSHOTS: case D_STEP_OVER: case D_STEP_INTO: - case D_STEP_OUT: - // it's a data printing or stepping command, needs to be sent to the - // active component - if (debugger_active_tc == NULL || - debugger_active_tc->tc_state == PTC_STALE || - debugger_active_tc->tc_state == TC_EXITED) { + case D_STEP_OUT: + // it's a printing or stepping command, needs to be sent to the active component + if (debugger_active_tc == NULL || !is_tc_debuggable(debugger_active_tc)) { // set the MTC as active in the beginning or if the active PTC has // finished executing debugger_active_tc = mtc; @@ -6544,17 +6599,32 @@ void MainController::debug_command(int commandID, char* arguments) last_debug_command.command = commandID; Free(last_debug_command.arguments); last_debug_command.arguments = mcopystr(arguments); - // no break + // needs to be sent to all HCs and TCs + send_debug_command(mtc->tc_fd, commandID, arguments); + for (component i = FIRST_PTC_COMPREF; i < n_components; ++i) { + component_struct* comp = components[i]; + if (comp != NULL && comp->tc_state != PTC_STALE && comp->tc_state != TC_EXITED) { + send_debug_command(comp->tc_fd, commandID, arguments); + } + } + for (int i = 0; i < n_hosts; i++) { + host_struct* host = hosts[i]; + if (host->hc_state != HC_DOWN) { + send_debug_command(host->hc_fd, commandID, arguments); + } + } + break; case D_RUN_TO_CURSOR: case D_HALT: case D_CONTINUE: case D_EXIT: - // it's a global setting, a 'run to' command or a command related to the + // a 'run to' command or a command related to the // halted state, needs to be sent to all HCs and TCs send_debug_command(mtc->tc_fd, commandID, arguments); for (component i = FIRST_PTC_COMPREF; i < n_components; ++i) { component_struct* comp = components[i]; - if (comp != NULL && comp->tc_state != PTC_STALE && comp->tc_state != TC_EXITED) { + // only send it to the PTC if it is actually running something + if (comp != NULL && is_tc_debuggable(comp)) { send_debug_command(comp->tc_fd, commandID, arguments); } }