#else
#include "RT1/PreGenRecordOf.hh"
#endif
+#include <regex.h>
/** alias for record of charstring */
typedef PreGenRecordOf::PREGEN__RECORD__OF__CHARSTRING charstring_list;
-// forward declarations
+// debugger forward declarations
class TTCN3_Debug_Scope;
class TTCN3_Debug_Function;
+// other forward declarations
+class Module_Param;
+
//////////////////////////////////////////////////////
////////////////// TTCN3_Debugger ////////////////////
class TTCN3_Debugger {
public:
+ struct variable_t;
+
+ typedef CHARSTRING (*print_function_t)(const variable_t&);
+ typedef boolean (*set_function_t)(variable_t&, Module_Param&);
+
/** type for keeping track of a variable */
struct variable_t {
/** pointer to the variable object, not owned */
- const void* value;
+ union {
+ /** container for non-constant variable objects */
+ void* value;
+ /** container for constant variable objects */
+ const void* cvalue;
+ };
/** variable name (used for looking up variables), not owned */
const char* name;
/** name of the variable's type, not owned */
const char* type_name;
/** variable printing function (using the variable object's log() function) */
- CHARSTRING (*print_function)(const variable_t&);
+ print_function_t print_function;
+ /** variable setting (overwriting) function (using the variable object's
+ * set_param() function) - set to NULL for constant variables */
+ set_function_t set_function;
};
/** this type pairs a debug scope with a name, used for storing global and
* component scopes */
struct named_scope_t {
/** scope name (module name for global scopes, or component type name for
- * component scopes), not owned*/
+ * component scopes), not owned */
const char* name;
/** scope pointer, owned */
TTCN3_Debug_Scope* scope;
};
+ /** type for storing a function call in the call stack */
+ struct function_call_t {
+ /** pointer to the debug function object */
+ TTCN3_Debug_Function* function;
+ /** TTCN-3 line number, where the function was called from */
+ int caller_line;
+ };
+
/** type for storing breakpoints */
struct breakpoint_t {
/** module name, owned */
char* module;
/** line number */
int line;
- // const char* batch_file;
- };
-
- /** list of commands coming from the user interface (parameters listed in comments) */
- enum debug_command_t {
- // on/off switch
- D_SWITCH_OFF, // 0
- D_SWITCH_ON, // 0
- // breakpoints
- D_ADD_BREAKPOINT, // 2, module name and line number
- D_REMOVE_BREAKPOINT, // 2, module name and line number
- D_SET_ERROR_BEHAVIOR, // 1, "yes" or "no"
- D_SET_FAIL_BEHAVIOR, // 1, "yes" or "no"
- // printing and overwriting data
- D_SET_OUTPUT, // 1-2, "stdout", "stderr" or "file" + file name
- D_SET_PROCESS, // 1, 'mtc' or component reference
- D_PRINT_CALL_STACK, // 0
- D_SET_STACK_LEVEL, // 1, stack level
- D_LIST_VARIABLES, // 1-2, "local", "global", "comp", "component" or "all", + optional filter (pattern)
- D_PRINT_VARIABLE, // 1+, list of variable names
- D_OVERWRITE_VARIABLE, // 2, variable name, new value (in module parameter syntax)
- D_PRINT_SNAPSHOTS, // 0
- D_SET_SNAPSHOT_BEHAVIOR, // TBD
- // stepping
- D_STEP_OVER, // 0
- D_STEP_INTO, // 0
- D_STEP_OUT, // 0
- D_RUN_TO_CURSOR, // 2, module name and line number
- // ending the halted state
- D_CONTINUE, // 0
- D_EXIT, // 0
- // batch files
- D_SET_HALTING_BATCH_FILE // TBD
+ /** batch file to be executed when the breakpoint is reached (optional) */
+ char* batch_file;
};
/** special breakpoint types, passed to breakpoint_entry() as the line parameter,
SBP_FAIL_VERDICT = -1
};
+ /** type for storing the settings of automatic breakpoints */
+ struct automatic_breakpoint_behavior_t {
+ /** indicates whether the breakpoint should be triggered by the associated event */
+ bool trigger;
+ /** batch file to be executed if the breakpoint is triggered (optional) */
+ char* batch_file;
+ };
+
+ /** stepping type */
+ enum stepping_t {
+ NOT_STEPPING,
+ STEP_OVER,
+ STEP_INTO,
+ STEP_OUT
+ };
+
private:
- /** the debugger's on/off switch */
+ /** indicates whether the debugger has been activated, meaning that the debugger's
+ * command line option (-n) was used during the build (switched automatically
+ * by generated code) */
+ bool enabled;
+
+ /** the debugger's on/off switch (switched by the user) */
bool active;
- /** the debugger's output file handler */
- FILE* output;
+ /** true if test execution has been halted (by a breakpoint or by the user) */
+ bool halted;
+
+ /** the debugger's output file handler (NULL if the debugger's output is only
+ * sent to the console) */
+ FILE* output_file;
+
+ /** name of the debugger's output file (NULL if the debugger's output is only
+ * sent to the console) */
+ char* output_file_name;
+
+ /** indicates whether the debugger's output should be sent to the console */
+ bool send_to_console;
/** list of all global and component variables, elements are owned */
Vector<variable_t*> variables;
/** list of component scopes */
Vector<named_scope_t> component_scopes;
- /** pointers to debug function objects (resembling a call stack), elements are not owned
- * the current function is always the last element in the array (the top element in the stack) */
- Vector<TTCN3_Debug_Function*> call_stack;
+ /** pointers to debug function objects and the lines they were called from
+ * (resembling a call stack), the current function is always the last element
+ * in the array (the top element in the stack) */
+ Vector<function_call_t> call_stack;
/** list of breakpoints */
Vector<breakpoint_t> breakpoints;
/** stores the last line hit by breakpoint_entry() */
breakpoint_t last_breakpoint_entry;
- /** current stack level (reset whenever a breakpoint is reached) */
+ /** current stack level (reset when test execution is halted or resumed) */
int stack_level;
- /** behavior triggered by setting the local verdict to FAIL
- * (a breakpoint is activated if set to true) */
- bool fail_behavior;
+ /** automatic breakpoint triggered by setting the local verdict to FAIL */
+ automatic_breakpoint_behavior_t fail_behavior;
+
+ /** automatic breakpoint triggered by setting the local verdict to ERROR */
+ automatic_breakpoint_behavior_t error_behavior;
- /** behavior triggered by setting the local verdict to ERROR
- * (a breakpoint is activated if set to true) */
- bool error_behavior;
+ /** batch file executed automatically when test execution is halted
+ * NULL if switched off
+ * is overridden by breakpoint-specific batch files */
+ char* global_batch_file;
+
+ /** result of the currently executing command */
+ char* command_result;
+
+ /** result of the last D_LIST_VARIABLES command */
+ char* last_variable_list;
+
+ /** stores which stepping option was requested by the user (if any) */
+ stepping_t stepping_type;
+
+ /** stores the size of the call stack when the last stepping operation was
+ * initiated */
+ size_t stepping_stack_size;
+
+ /** temporary breakpoint set by the 'run to cursor' operation */
+ breakpoint_t temporary_breakpoint;
+
+ /** true if an 'exit all' command was issued
+ * switched to false when test execution is restarted */
+ bool exiting;
+
+ /** test execution is automatically halted at start if set to true */
+ bool halt_at_start;
+
+ /** batch file executed automatically at the start of test execution
+ * if not set to NULL (not owned) */
+ const char* initial_batch_file;
//////////////////////////////////////////////////////
///////////////// internal functions /////////////////
//////////////////////////////////////////////////////
- /** switches the debugger off
- * handles the D_SWITCH_OFF command */
- void switch_off();
+ /** switches the debugger on or off
+ * handles the D_SWITCH command */
+ void switch_state(const char* p_state_str);
- /** switches the debugger on
- * handles the D_SWITCH_ON command */
- void switch_on();
-
- /** adds a new breakpoint at the specified module and line
+ /** adds a new breakpoint at the specified module and line with the specified
+ * batch file (if not NULL), or changes the batch file of an existing
+ * breakpoint
* handles the D_ADD_BREAKPOINT command */
- void add_breakpoint(const char* p_module, int p_line /*const char* batch_file*/);
+ void set_breakpoint(const char* p_module, int p_line, const char* batch_file);
/** removes the breakpoint from the specified module/line, if it exists
+ * can also be used to remove all breakpoints from the specified module or
+ * all breakpoints in all modules
* handles the D_REMOVE_BREAKPOINT command */
- void remove_breakpoint(const char* p_module, int p_line);
-
- /** sets the behavior of a special breakpoint type
- * @param p_state_str "yes" turns the special breakpoint on (as if it was an
- * actual breakpoint), "no" turns it off
- * handles the D_SET_ERROR_BEHAVIOR and D_SET_FAIL_BEHAVIOR commands */
- void set_special_breakpoint(special_breakpoint_t p_type, const char* p_state_str);
+ void remove_breakpoint(const char* p_module, const char* p_line);
+
+ /** switches an automatic breakpoint related to the specified event on or off
+ * and/or sets the batch file to run when the breakpoint is triggered
+ * @param p_event_str string representation of the event that triggers the
+ * breakpoint (either "error" or "fail")
+ * @param p_state_str "on" or "off", indicates the new state of the breakpoint
+ * @param p_batch_file name of the batch file to execute (NULL means don't
+ * execute anything)
+ * handles the D_SET_AUTOMATIC_BREAKPOINT command */
+ void set_automatic_breakpoint(const char* p_event_str, const char* p_state_str,
+ const char* p_batch_file);
/** prints the current call stack
* handles the D_PRINT_CALL_STACK command */
void print_call_stack();
- /** sets the current stack level to the specified level
+ /** sets the current stack level to the specified value
* handles the D_SET_STACK_LEVEL command */
void set_stack_level(int new_level);
- /** prints the specified variable
+ /** finds the variable with the specified name, and prints its value or an
+ * error message
* handles (one parameter of) the D_PRINT_VARIABLE command */
- void print_variable(const variable_t* p_var) const;
+ void print_variable(const char* p_var_name);
- /** sets the debugger's output to a different stream
+ void overwrite_variable(const char* p_var_name, int p_value_element_count,
+ char** p_value_elements);
+
+ /** sets the debugger's output to the console and/or a text file
* handles the D_SET_OUTPUT command
- * @param p_output_type "stdout", "stderr" or "file"
- * @param p_file_name output file name, if the output is a file, or NULL */
+ * @param p_output_type "console", "file" or "both"
+ * @param p_file_name output file name or NULL */
void set_output(const char* p_output_type, const char* p_file_name);
+ /** switches the global batch file on or off
+ * handles the D_SET_GLOBAL_BATCH_FILE command */
+ void set_global_batch_file(const char* p_state_str, const char* p_file_name);
+
+ /** resumes execution until the next breakpoint entry (in the stack levels
+ * specified by the stepping type arguments) is reached (or until test execution
+ * is halted for any other reason)
+ * handles the D_STEP_OVER, D_STEP_INTO and D_STEP_OUT commands */
+ void step(stepping_t p_stepping_type);
+
+ /** resumes execution until the specified location is reached
+ * (or until test execution is halted for any other reason)
+ * handles the D_RUN_TO_CURSOR command */
+ void run_to_cursor(const char* p_module, int p_line);
+
+ /** halts test execution, processing only debug commands
+ * @param p_batch_file batch file executed after the halt (if not NULL)
+ * @param p_run_global_batch indicates whether the global batch file should
+ * be executed after the halt (only if p_batch_file is NULL)
+ * handles the D_HALT command */
+ void halt(const char* p_batch_file, bool p_run_global_batch);
+
+ /** resumes the halted test execution
+ * handles the D_CONTINUE command */
+ void resume();
+
+ /** exits the current test or the execution of all tests
+ * handles the D_EXIT command */
+ void exit_(const char* p_what);
+
/** returns the index of the specified breakpoint, if found,
* otherwise returns breakpoints.size() */
size_t find_breakpoint(const char* p_module, int p_line) const;
/** returns the specified variable, if found, otherwise returns NULL */
TTCN3_Debugger::variable_t* find_variable(const void* p_value) const;
+
+ /** handles metacharacters in the specified file name skeleton
+ * @return final file name (must be freed by caller) */
+ static char* finalize_file_name(const char* p_file_name_skeleton);
+
+ /** initialization function, called when the first function is added to the
+ * call stack */
+ void test_execution_started();
+
+ /** clean up function, called when the last function is removed from the
+ * call stack */
+ void test_execution_finished();
public:
/** constructor - called once per process (at the beginning) */
////// methods called from TITAN generated code //////
//////////////////////////////////////////////////////
- /** creates, stores and returns a new global scope for the specified module */
+ /** activates the debugger */
+ void activate() { enabled = true; }
+
+ /** creates, stores and returns a new global scope for the specified module
+ * (this scope contains all global variables visible in the module) */
TTCN3_Debug_Scope* add_global_scope(const char* p_module);
- /** creates, stores and returns a new global scope for the specified module */
+ /** creates, stores and returns a new component scope for the specified component
+ * type (this scope contains all variables declared in the component type) */
TTCN3_Debug_Scope* add_component_scope(const char* p_component);
/** stores the string representation of the current function's return value
* the special parameter values (SBP_ERROR_VERDICT and SBP_FAIL_VERDICT) only
* trigger a breakpoint if their respective behaviors have been set to do so
* (does nothing if the debugger is switched off) */
- void breakpoint_entry(int p_line /*bool p_stepping_helper*/);
+ void breakpoint_entry(int p_line);
/** variable printing function for base types */
static CHARSTRING print_base_var(const variable_t& p_var);
+ /** variable setting function for base types */
+ static boolean set_base_var(variable_t& p_var, Module_Param& p_new_value);
+
/** variable printing function for value arrays */
template <typename T_type, unsigned int array_size, int index_offset>
static CHARSTRING print_value_array(const variable_t& p_var)
{
+ const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue;
TTCN_Logger::begin_event_log2str();
- ((VALUE_ARRAY<T_type, array_size, index_offset>*)p_var.value)->log();
+ ((VALUE_ARRAY<T_type, array_size, index_offset>*)ptr)->log();
return TTCN_Logger::end_event_log2str();
}
+ /** variable setting function for value arrays */
+ template <typename T_type, unsigned int array_size, int index_offset>
+ static boolean set_value_array(variable_t& p_var, Module_Param& p_new_value)
+ {
+ ((VALUE_ARRAY<T_type, array_size, index_offset>*)p_var.value)->set_param(p_new_value);
+ return TRUE;
+ }
+
/** variable printing function for template arrays */
template <typename T_value_type, typename T_template_type,
unsigned int array_size, int index_offset>
static CHARSTRING print_template_array(const variable_t& p_var)
{
+ const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue;
TTCN_Logger::begin_event_log2str();
((TEMPLATE_ARRAY<T_value_type, T_template_type, array_size,
- index_offset>*)p_var.value)->log();
+ index_offset>*)ptr)->log();
return TTCN_Logger::end_event_log2str();
}
+ /** variable setting function for template arrays */
+ template <typename T_value_type, typename T_template_type,
+ unsigned int array_size, int index_offset>
+ static boolean set_template_array(variable_t& p_var, Module_Param& p_new_value)
+ {
+ ((TEMPLATE_ARRAY<T_value_type, T_template_type, array_size,
+ index_offset>*)p_var.value)->set_param(p_new_value);
+ return TRUE;
+ }
+
/** variable printing function for port arrays */
template <typename T_type, unsigned int array_size, int index_offset>
static CHARSTRING print_port_array(const variable_t& p_var)
{
+ const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue;
TTCN_Logger::begin_event_log2str();
- ((PORT_ARRAY<T_type, array_size, index_offset>*)p_var.value)->log();
+ ((PORT_ARRAY<T_type, array_size, index_offset>*)ptr)->log();
return TTCN_Logger::end_event_log2str();
}
template <typename T_type, unsigned int array_size, int index_offset>
static CHARSTRING print_timer_array(const variable_t& p_var)
{
+ const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue;
TTCN_Logger::begin_event_log2str();
- ((TIMER_ARRAY<T_type, array_size, index_offset>*)p_var.value)->log();
+ ((TIMER_ARRAY<T_type, array_size, index_offset>*)ptr)->log();
return TTCN_Logger::end_event_log2str();
}
template <typename EXPR_TYPE>
static CHARSTRING print_lazy_param(const variable_t& p_var)
{
+ const void* ptr = p_var.set_function != NULL ? p_var.value : p_var.cvalue;
TTCN_Logger::begin_event_log2str();
- ((Lazy_Param<EXPR_TYPE>*)p_var.value)->log();
+ ((Lazy_Param<EXPR_TYPE>*)ptr)->log();
return TTCN_Logger::end_event_log2str();
}
////// methods called by other debugger classes //////
//////////////////////////////////////////////////////
+ /** returns true if the debugger is activated (through the compiler switch) */
+ bool is_activated() const { return enabled; }
+
/** returns true if the debugger is switched on */
bool is_on() const { return active; }
- /** prints formatted string to the debugger's output stream */
- void print(const char* fmt, ...) const;
+ /** returns true if test execution has been halted by the debugger */
+ bool is_halted() const { return halted; }
+
+ /** prints the formatted string to the console and/or output file
+ * (used for printing notifications or error messages) */
+ void print(int return_type, const char* fmt, ...) const;
+
+ /** adds the formatted string to the currently executed command's result string */
+ void add_to_result(const char* fmt, ...);
/** adds the specified function object pointer to the call stack
* (only if the debugger is switched on) */
* (only if the call stack is not empty) */
void remove_scope(TTCN3_Debug_Scope* p_scope);
- /** finds or creates, and returns the variable entry specified by the parameters
+ /** finds or creates, and returns the constant variable entry specified by
+ * the parameters
*
* if the call stack is empty, an entry for a global or component variable is
* created and stored in the main debugger object (if it doesn't already exist);
* 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*/
- const variable_t* add_variable(const void* p_value, const char* p_name, const char* p_type,
- CHARSTRING (*p_print_function)(const variable_t&));
+ * 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);
+
+ /** 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);
/** removes the variable entry for the specified local variable in the current
* function (only if the call stack is not empty) */
void add_snapshot(const char* p_snapshot);
/** executes a command received from the user interface */
- void execute_command(debug_command_t p_command, const charstring_list& p_arguments);
+ void execute_command(int p_command, int p_argument_count, char** p_arguments);
+
+ /** opens the debugger's output file for writing (if one has been set, but not
+ * opened, in the HC process) */
+ void open_output_file();
+
+ /** indicates whether an 'exit all' command has been issued
+ * (this causes the execution of tests in the current queue to stop) */
+ bool is_exiting() const { return exiting; }
+
+ /** sets the debugger to halt test execution at start (only in single mode) */
+ void set_halt_at_start() { halt_at_start = true; }
+
+ /** sets the specified batch file to be executed at the start of test execution
+ * (only in single mode) */
+ void set_initial_batch_file(const char* p_batch_file) {
+ initial_batch_file = p_batch_file;
+ }
};
/** the main debugger object */
/** list of pointers to local variable entries from the current function object or
* global or component variable entries from the main debugger object
* (the elements are not owned)*/
- Vector<const TTCN3_Debugger::variable_t*> variables;
+ Vector<TTCN3_Debugger::variable_t*> variables;
public:
//////////////////////////////////////////////////////
/** passes the parameters to the main debugger or current function object to
- * create and store a variable entry from them, and tracks this new variable
- * by storing a pointer to it
+ * create and store a (constant) variable entry from them, and tracks this new
+ * 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,
- CHARSTRING (*p_print_function)(const TTCN3_Debugger::variable_t&));
+ 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,
+ TTCN3_Debugger::set_function_t p_set_function);
//////////////////////////////////////////////////////
////// methods called by other debugger classes //////
bool has_variables() const { return !variables.empty(); }
/** returns the specified variable, if found, otherwise returns NULL */
- const TTCN3_Debugger::variable_t* find_variable(const char* p_name) const;
+ TTCN3_Debugger::variable_t* find_variable(const char* p_name) const;
- /** prints the names of variables in this scope that match the specified pattern
- * @param p_filter the mentioned pattern
+ /** prints the names of variables in this scope that match the specified
+ * @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(const char* p_filter, bool& p_first) const;
+ void list_variables(regex_t* p_posix_regexp, bool& p_first) const;
};
////// methods called from TITAN generated code //////
//////////////////////////////////////////////////////
- /** creates, stores and returns the variable entry of the local variable
+ /** creates, stores and returns the variable entry of the local (constant) variable
* specified by the parameters (only if the debugger is switched on) */
- const TTCN3_Debugger::variable_t* add_variable(const void* p_value, const char* p_name,
- const char* p_type, CHARSTRING (*p_print_function)(const TTCN3_Debugger::variable_t&));
+ 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);
+
+ /** 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,
+ TTCN3_Debugger::set_function_t p_set_function);
/** stores the string representation of the value returned by the function */
void set_return_value(const CHARSTRING& p_value);
- /** saves the function's initial snapshot (including the values on 'in' and
+ /** saves the function's initial snapshot (including the values of 'in' and
* 'inout' parameters) in the main debugger object
* (only if the debugger is switched on) */
void initial_snapshot() const;
/** searches for the variable entry with the specified name in the function's
* local variable list, the global scope (if any) and the component scope (if any),
* returns NULL, if the variable was not found */
- const TTCN3_Debugger::variable_t* find_variable(const char* p_name) const;
+ TTCN3_Debugger::variable_t* find_variable(const char* p_name) const;
/** prints the function's type, name and current values of parameters */
void print_function() const;
* - "all" - all variables visible in the function (i.e. all of the above)
* @param p_filter a pattern to filter variable names further */
void list_variables(const char* p_scope, const char* p_filter) const;
+
+ /** returns true if this instance belongs to a control part */
+ bool is_control_part() const;
+
+ /** returns true if this instance belongs to a test case */
+ bool is_test_case() const;
};
/** This macro stores a function's return value in the current function.