Debugger - Stage 1 (artf511247)
[deliverable/titan.core.git] / core / Debugger.cc
CommitLineData
7329404e
BB
1/******************************************************************************
2 * Copyright (c) 2000-2016 Ericsson Telecom AB
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *
10 * Baranyi, Botond – initial implementation
11 *
12 ******************************************************************************/
13
14#include "Debugger.hh"
15
16//////////////////////////////////////////////////////
17////////////////// TTCN3_Debugger ////////////////////
18//////////////////////////////////////////////////////
19
20TTCN3_Debugger ttcn3_debugger;
21
22void TTCN3_Debugger::switch_off()
23{
24 if (!active) {
25 print("The debugger is already switched off.\n");
26 }
27 else {
28 print("Debugger switched off.\n");
29 }
30 active = false;
31}
32
33void TTCN3_Debugger::switch_on()
34{
35 if (active) {
36 print("The debugger is already switched on.\n");
37 }
38 else {
39 print("Debugger switched on.\n");
40 }
41 active = true;
42}
43
44void TTCN3_Debugger::add_breakpoint(const char* p_module, int p_line /*const char* batch_file*/)
45{
46 if (find_breakpoint(p_module, p_line) == breakpoints.size()) {
47 breakpoint_t bp;
48 bp.module = mcopystr(p_module);
49 bp.line = p_line;
50 breakpoints.push_back(bp);
51 print("Breakpoint added in module '%s' at line %d.\n", p_module, p_line);
52 }
53 else {
54 print("Breakpoint already set in module '%s' at line %d.\n", p_module, p_line);
55 }
56}
57
58void TTCN3_Debugger::remove_breakpoint(const char* p_module, int p_line)
59{
60 size_t pos = find_breakpoint(p_module, p_line);
61 if (pos != breakpoints.size()) {
62 Free(breakpoints[pos].module);
63 breakpoints.erase_at(pos);
64 print("Breakpoint removed in module '%s' from line %d.\n", p_module, p_line);
65 }
66 else {
67 print("No breakpoint found in module '%s' at line %d.\n", p_module, p_line);
68 }
69}
70
71void TTCN3_Debugger::set_special_breakpoint(special_breakpoint_t p_type, const char* p_state_str)
72{
73 bool new_state;
74 if (!strcmp(p_state_str, "yes")) {
75 new_state = true;
76 }
77 else if(!strcmp(p_state_str, "no")) {
78 new_state = false;
79 }
80 // else if "batch"
81 else {
82 print("Argument 1 is invalid.\n");
83 return;
84 }
85 const char* sbp_type_str;
86 bool state_changed;
87 switch (p_type) {
88 case SBP_FAIL_VERDICT:
89 state_changed = (fail_behavior != new_state);
90 fail_behavior = new_state;
91 sbp_type_str = "Fail";
92 break;
93 case SBP_ERROR_VERDICT:
94 state_changed = (error_behavior != new_state);
95 error_behavior = new_state;
96 sbp_type_str = "Error";
97 break;
98 default:
99 // should never happen
100 return;
101 }
102 print("%s verdict behavior %sset to %s.\n", sbp_type_str,
103 state_changed ? "" : "was already ",
104 new_state ? "halt the program" : "do nothing");
105}
106
107void TTCN3_Debugger::print_call_stack()
108{
109 for (size_t i = call_stack.size(); i != 0; --i) {
110 print("%d.\t", (int)call_stack.size() - (int)i + 1);
111 call_stack[i - 1]->print_function();
112 }
113}
114
115void TTCN3_Debugger::set_stack_level(int new_level)
116{
117 if (new_level < 0 || (size_t)new_level > call_stack.size()) {
118 print("Invalid new stack level.\n");
119 }
120 else {
121 stack_level = new_level;
122 }
123}
124
125void TTCN3_Debugger::print_variable(const TTCN3_Debugger::variable_t* p_var) const
126{
127 print("%s := %s\n", p_var->name, (const char*)p_var->print_function(*p_var));
128}
129
130void TTCN3_Debugger::set_output(const char* p_output_type, const char* p_file_name)
131{
132 FILE* new_fp;
133 if (!strcmp(p_output_type, "stdout")) {
134 new_fp = stdout;
135 }
136 else if (!strcmp(p_output_type, "stderr")) {
137 new_fp = stderr;
138 }
139 else if (!strcmp(p_output_type, "file")) {
140 if (p_file_name == NULL) {
141 print("Missing output file name.\n");
142 return;
143 }
144 new_fp = fopen(p_file_name, "w");
145 if (new_fp == NULL) {
146 print("Failed to open file '%s' for writing.\n");
147 return;
148 }
149 }
150 else {
151 print("Argument 1 is invalid.\n");
152 return;
153 }
154 // don't close the previous file, if the command's parameters are invalid
155 if (output != stdout && output != stderr) {
156 fclose(output);
157 }
158 output = new_fp;
159}
160
161size_t TTCN3_Debugger::find_breakpoint(const char* p_module, int p_line) const
162{
163 for (size_t i = 0; i < breakpoints.size(); ++i) {
164 if (!strcmp(breakpoints[i].module, p_module) && breakpoints[i].line == p_line) {
165 return i;
166 }
167 }
168 return breakpoints.size();
169}
170
171TTCN3_Debugger::variable_t* TTCN3_Debugger::find_variable(const void* p_value) const
172{
173 for (size_t i = 0; i < variables.size(); ++i) {
174 if (variables[i]->value == p_value) {
175 return variables[i];
176 }
177 }
178 return NULL;
179}
180
181TTCN3_Debugger::TTCN3_Debugger()
182{
183 active = false;
184 output = stderr;
185 snapshots = NULL;
186 last_breakpoint_entry.module = NULL;
187 last_breakpoint_entry.line = 0;
188 stack_level = -1;
189 fail_behavior = false;
190 error_behavior = false;
191}
192
193TTCN3_Debugger::~TTCN3_Debugger()
194{
195 if (output != stdout && output != stderr) {
196 fclose(output);
197 }
198 for (size_t i = 0; i < breakpoints.size(); ++i) {
199 Free(breakpoints[i].module);
200 }
201 for (size_t i = 0; i < global_scopes.size(); ++i) {
202 delete global_scopes[i].scope;
203 }
204 for (size_t i = 0; i < component_scopes.size(); ++i) {
205 delete component_scopes[i].scope;
206 }
207 for (size_t i = 0; i < variables.size(); ++i) {
208 delete variables[i];
209 }
210 Free(snapshots);
211}
212
213TTCN3_Debug_Scope* TTCN3_Debugger::add_global_scope(const char* p_module)
214{
215 named_scope_t global_scope;
216 global_scope.name = p_module;
217 global_scope.scope = new TTCN3_Debug_Scope();
218 global_scopes.push_back(global_scope);
219 return global_scope.scope;
220}
221
222TTCN3_Debug_Scope* TTCN3_Debugger::add_component_scope(const char* p_component)
223{
224 named_scope_t component_scope;
225 component_scope.name = p_component;
226 component_scope.scope = new TTCN3_Debug_Scope();
227 component_scopes.push_back(component_scope);
228 return component_scope.scope;
229}
230
231void TTCN3_Debugger::set_return_value(const CHARSTRING& p_value)
232{
233 if (active) {
234 call_stack[call_stack.size() - 1]->set_return_value(p_value);
235 }
236}
237
238void TTCN3_Debugger::breakpoint_entry(int p_line /*bool p_stepping_helper*/)
239{
240 if (active && !call_stack.empty()) {
241 const char* module_name = call_stack[call_stack.size() - 1]->get_module_name();
242 bool trigger = false;
243 const char* trigger_type;
244 int actual_line;
245 switch (p_line) {
246 case SBP_FAIL_VERDICT:
247 trigger = fail_behavior;
248 trigger_type = "Fail verdict";
249 actual_line = last_breakpoint_entry.line;
250 break;
251 case SBP_ERROR_VERDICT:
252 trigger = error_behavior;
253 trigger_type = "Error verdict";
254 actual_line = last_breakpoint_entry.line;
255 break;
256 default:
257 // code lines
258 trigger = (last_breakpoint_entry.line == 0 || p_line != last_breakpoint_entry.line ||
259 module_name != last_breakpoint_entry.module) &&
260 find_breakpoint(module_name, p_line) != breakpoints.size();
261 trigger_type = "Breakpoint";
262 actual_line = p_line;
263 break;
264 }
265 // make sure it's not the same breakpoint entry as last time
266 if (trigger) {
267 stack_level = call_stack.size() - 1;
268 print("%s reached in module '%s' at line %d.\n", trigger_type,
269 module_name, actual_line);
270 ///////////////////////////////////////////////////////////////////////////////////
271 /*print("##################################################\n");
272 print("Call stack:\n");
273 charstring_list params = NULL_VALUE;
274 execute_command(D_PRINT_CALL_STACK, params);
275 print("##################################################\n");
276 print("Variables: ");
277 params[0] = "global";
278 execute_command(D_LIST_VARIABLES, params);
279 params.set_size(0);
280 size_t idx = 0;
281 const TTCN3_Debug_Scope* glob_scope = get_global_scope(module_name);
282 for (size_t i = 0; i < variables.size(); ++i) {
283 if (glob_scope->find_variable(variables[i]->name) != NULL) {
284 params[idx++] = variables[i]->name;
285 }
286 }
287 execute_command(D_PRINT_VARIABLE, params);
288 print("##################################################\n");
289 print("Function call snapshots:\n");
290 params.set_size(0);
291 execute_command(D_PRINT_SNAPSHOTS, params);*/
292 ///////////////////////////////////////////////////////////////////////////////////
293 }
294 last_breakpoint_entry.module = (char*)module_name;
295 last_breakpoint_entry.line = p_line;
296 }
297}
298
299CHARSTRING TTCN3_Debugger::print_base_var(const TTCN3_Debugger::variable_t& p_var)
300{
301 TTCN_Logger::begin_event_log2str();
302 if (!strcmp(p_var.type_name, "bitstring")) {
303 ((const BITSTRING*)p_var.value)->log();
304 }
305 else if (!strcmp(p_var.type_name, "bitstring template")) {
306 ((const BITSTRING_template*)p_var.value)->log();
307 }
308 else if (!strcmp(p_var.type_name, "boolean")) {
309 ((const BOOLEAN*)p_var.value)->log();
310 }
311 else if (!strcmp(p_var.type_name, "boolean template")) {
312 ((const BOOLEAN_template*)p_var.value)->log();
313 }
314 else if (!strcmp(p_var.type_name, "charstring")) {
315 ((const CHARSTRING*)p_var.value)->log();
316 }
317 else if (!strcmp(p_var.type_name, "charstring template")) {
318 ((const CHARSTRING_template*)p_var.value)->log();
319 }
320 else if (!strcmp(p_var.type_name, "float")) {
321 ((const FLOAT*)p_var.value)->log();
322 }
323 else if (!strcmp(p_var.type_name, "float template")) {
324 ((const FLOAT_template*)p_var.value)->log();
325 }
326 else if (!strcmp(p_var.type_name, "hexstring")) {
327 ((const HEXSTRING*)p_var.value)->log();
328 }
329 else if (!strcmp(p_var.type_name, "hexstring template")) {
330 ((const HEXSTRING_template*)p_var.value)->log();
331 }
332 else if (!strcmp(p_var.type_name, "integer")) {
333 ((const INTEGER*)p_var.value)->log();
334 }
335 else if (!strcmp(p_var.type_name, "integer template")) {
336 ((const INTEGER_template*)p_var.value)->log();
337 }
338 else if (!strcmp(p_var.type_name, "objid")) {
339 ((const OBJID*)p_var.value)->log();
340 }
341 else if (!strcmp(p_var.type_name, "objid template")) {
342 ((const OBJID_template*)p_var.value)->log();
343 }
344 else if (!strcmp(p_var.type_name, "octetstring")) {
345 ((const OCTETSTRING*)p_var.value)->log();
346 }
347 else if (!strcmp(p_var.type_name, "octetstring template")) {
348 ((const OCTETSTRING_template*)p_var.value)->log();
349 }
350 else if (!strcmp(p_var.type_name, "universal charstring")) {
351 ((const UNIVERSAL_CHARSTRING*)p_var.value)->log();
352 }
353 else if (!strcmp(p_var.type_name, "universal charstring template")) {
354 ((const UNIVERSAL_CHARSTRING_template*)p_var.value)->log();
355 }
356 else if (!strcmp(p_var.type_name, "verdicttype")) {
357 ((const VERDICTTYPE*)p_var.value)->log();
358 }
359 else if (!strcmp(p_var.type_name, "verdicttype template")) {
360 ((const VERDICTTYPE_template*)p_var.value)->log();
361 }
362 else if (!strcmp(p_var.type_name, "component")) {
363 ((const COMPONENT*)p_var.value)->log();
364 }
365 else if (!strcmp(p_var.type_name, "component template")) {
366 ((const COMPONENT_template*)p_var.value)->log();
367 }
368 else if (!strcmp(p_var.type_name, "default")) {
369 ((const DEFAULT*)p_var.value)->log();
370 }
371 else if (!strcmp(p_var.type_name, "default template")) {
372 ((const DEFAULT_template*)p_var.value)->log();
373 }
374 else if (!strcmp(p_var.type_name, "timer")) {
375 ((const TIMER*)p_var.value)->log();
376 }
377 else if (!strcmp(p_var.type_name, "NULL")) {
378 ((const ASN_NULL*)p_var.value)->log();
379 }
380 else if (!strcmp(p_var.type_name, "NULL template")) {
381 ((const ASN_NULL_template*)p_var.value)->log();
382 }
383 else if (!strcmp(p_var.type_name, "CHARACTER STRING")) {
384 ((const CHARACTER_STRING*)p_var.value)->log();
385 }
386 else if (!strcmp(p_var.type_name, "CHARACTER STRING template")) {
387 ((const CHARACTER_STRING_template*)p_var.value)->log();
388 }
389 else if (!strcmp(p_var.type_name, "EMBEDDED PDV")) {
390 ((const EMBEDDED_PDV*)p_var.value)->log();
391 }
392 else if (!strcmp(p_var.type_name, "EMBEDDED PDV template")) {
393 ((const EMBEDDED_PDV_template*)p_var.value)->log();
394 }
395 else if (!strcmp(p_var.type_name, "EXTERNAL")) {
396 ((const EXTERNAL*)p_var.value)->log();
397 }
398 else if (!strcmp(p_var.type_name, "EXTERNAL template")) {
399 ((const EXTERNAL_template*)p_var.value)->log();
400 }
401 else {
402 TTCN_Logger::log_event_str("<unrecognized value or template>");
403 }
404 return TTCN_Logger::end_event_log2str();
405}
406
407void TTCN3_Debugger::print(const char* fmt, ...) const
408{
409 va_list parameters;
410 va_start(parameters, fmt);
411 vfprintf(output, fmt, parameters);
412 va_end(parameters);
413 fflush(output);
414}
415
416void TTCN3_Debugger::add_function(TTCN3_Debug_Function* p_function)
417{
418 if (active) {
419 call_stack.push_back(p_function);
420 }
421}
422
423void TTCN3_Debugger::add_scope(TTCN3_Debug_Scope* p_scope)
424{
425 if (active && !call_stack.empty()) {
426 call_stack[call_stack.size() - 1]->add_scope(p_scope);
427 }
428}
429
430void TTCN3_Debugger::remove_function(TTCN3_Debug_Function* p_function)
431{
432 if (!call_stack.empty() && call_stack[call_stack.size() - 1] == p_function) {
433 call_stack.erase_at(call_stack.size() - 1);
434 }
435}
436
437void TTCN3_Debugger::remove_scope(TTCN3_Debug_Scope* p_scope)
438{
439 if (!call_stack.empty()) {
440 call_stack[call_stack.size() - 1]->remove_scope(p_scope);
441 }
442}
443
444const TTCN3_Debugger::variable_t* TTCN3_Debugger::add_variable(const void* p_value,
445 const char* p_name,
446 const char* p_type,
447 CHARSTRING (*p_print_function)(const TTCN3_Debugger::variable_t&))
448{
449
450 if (call_stack.empty()) {
451 // no call stack yet, so this is a global or component variable
452 variable_t* var = find_variable(p_value);
453 if (var == NULL) {
454 var = new TTCN3_Debugger::variable_t;
455 var->value = p_value;
456 var->name = p_name;
457 var->type_name = p_type;
458 var->print_function = p_print_function;
459 variables.push_back(var);
460 }
461 return var;
462 }
463 else if (active) {
464 // it's a local variable for the top-most function
465 return call_stack[call_stack.size() - 1]->add_variable(p_value, p_name, p_type, p_print_function);
466 }
467 return NULL;
468}
469
470void TTCN3_Debugger::remove_variable(const variable_t* p_var)
471{
472 if (active && !call_stack.empty()) {
473 call_stack[call_stack.size() - 1]->remove_variable(p_var);
474 }
475}
476
477const TTCN3_Debug_Scope* TTCN3_Debugger::get_global_scope(const char* p_module) const
478{
479 for (size_t i = 0; i < global_scopes.size(); ++i) {
480 if (strcmp(global_scopes[i].name, p_module) == 0) {
481 return global_scopes[i].scope;
482 }
483 }
484 return NULL;
485}
486
487const TTCN3_Debug_Scope* TTCN3_Debugger::get_component_scope(const char* p_component) const
488{
489 for (size_t i = 0; i < component_scopes.size(); ++i) {
490 if (strcmp(component_scopes[i].name, p_component) == 0) {
491 return component_scopes[i].scope;
492 }
493 }
494 return NULL;
495}
496
497void TTCN3_Debugger::add_snapshot(const char* p_snapshot)
498{
499 snapshots = mputstr(snapshots, p_snapshot);
500}
501
502#define CHECK_NOF_ARGUMENTS(exp_num) \
503 if (exp_num != p_arguments.size_of()) { \
504 print("Invalid number of arguments. Expected %d, got %d.\n", \
505 (int)exp_num, (int)p_arguments.size_of()); \
506 return; \
507 }
508
509#define CHECK_NOF_ARGUMENTS_RANGE(min, max) \
510 if ((int)min > p_arguments.size_of() || (int)max < p_arguments.size_of()) { \
511 print("Invalid number of arguments. Expected at least %d and at most %d, got %d.\n", \
512 (int)min, (int)max, p_arguments.size_of()); \
513 return; \
514 }
515
516#define CHECK_NOF_ARGUMENTS_MIN(min) \
517 if ((int)min > p_arguments.size_of()) { \
518 print("Invalid number of arguments. Expected at least %d, got %d.\n", \
519 (int)min, p_arguments.size_of()); \
520 return; \
521 }
522
523#define CHECK_INT_ARGUMENT(arg_idx) \
524 { \
525 const char* str = (const char*)p_arguments[arg_idx]; \
526 for (int i = 0; i < p_arguments[arg_idx].lengthof(); ++i) { \
527 if (str[i] < '0' || str[i] > '9') { \
528 print("Argument %d is not an integer.\n", (int)(arg_idx + 1)); \
529 return; \
530 } \
531 } \
532 }
533
534#define CHECK_CALL_STACK \
535 if (call_stack.empty()) { \
536 print("This command can only be executed when the program is running.\n"); \
537 return; \
538 }
539
540void TTCN3_Debugger::execute_command(TTCN3_Debugger::debug_command_t p_command,
541 const charstring_list& p_arguments)
542{
543 if (!active && p_command != D_SWITCH_ON && p_command != D_SWITCH_OFF) {
544 print("Cannot run debug commands while the debugger is switched off.\n");
545 return;
546 }
547 for (int i = 0; i < p_arguments.size_of(); ++i) {
548 if (!p_arguments[i].is_bound()) {
549 print("Argument %d is unbound.\n", i + 1);
550 return;
551 }
552 }
553 switch (p_command) {
554 case D_SWITCH_OFF:
555 CHECK_NOF_ARGUMENTS(0)
556 switch_off();
557 break;
558 case D_SWITCH_ON:
559 CHECK_NOF_ARGUMENTS(0)
560 switch_on();
561 break;
562 case D_ADD_BREAKPOINT:
563 CHECK_NOF_ARGUMENTS(2)
564 CHECK_INT_ARGUMENT(1)
565 add_breakpoint(p_arguments[0], str2int(p_arguments[1]));
566 break;
567 case D_REMOVE_BREAKPOINT:
568 CHECK_NOF_ARGUMENTS(2)
569 CHECK_INT_ARGUMENT(1)
570 remove_breakpoint(p_arguments[0], str2int(p_arguments[1]));
571 break;
572 case D_SET_ERROR_BEHAVIOR:
573 CHECK_NOF_ARGUMENTS(1)
574 set_special_breakpoint(SBP_ERROR_VERDICT, p_arguments[0]);
575 break;
576 case D_SET_FAIL_BEHAVIOR:
577 CHECK_NOF_ARGUMENTS(1)
578 set_special_breakpoint(SBP_FAIL_VERDICT, p_arguments[0]);
579 break;
580 // ...
581 case D_SET_OUTPUT:
582 CHECK_NOF_ARGUMENTS_RANGE(1, 2)
583 set_output(p_arguments[0], (p_arguments.size_of() == 2) ? (const char*)p_arguments[1] : NULL);
584 break;
585 // ...
586 case D_PRINT_CALL_STACK:
587 CHECK_CALL_STACK
588 CHECK_NOF_ARGUMENTS(0)
589 print_call_stack();
590 break;
591 case D_SET_STACK_LEVEL:
592 CHECK_CALL_STACK
593 CHECK_NOF_ARGUMENTS(1)
594 CHECK_INT_ARGUMENT(0)
595 set_stack_level(str2int(p_arguments[0]));
596 break;
597 case D_LIST_VARIABLES:
598 CHECK_CALL_STACK
599 CHECK_NOF_ARGUMENTS_RANGE(1, 2)
600 call_stack[stack_level]->list_variables(p_arguments[0],
601 (p_arguments.size_of() == 2) ? (const char*)p_arguments[1] : NULL);
602 break;
603 case D_PRINT_VARIABLE:
604 CHECK_CALL_STACK
605 CHECK_NOF_ARGUMENTS_MIN(1)
606 for (int i = 0; i < p_arguments.size_of(); ++i) {
607 const variable_t* var = call_stack[stack_level]->find_variable(p_arguments[i]);
608 if (var != NULL) {
609 print_variable(var);
610 }
611 else {
612 print("Variable '%s' not found.\n", (const char*)p_arguments[i]);
613 }
614 }
615 break;
616 // ...
617 case D_PRINT_SNAPSHOTS:
618 CHECK_NOF_ARGUMENTS(0)
619 print("%s", snapshots);
620 break;
621 // ...
622 default:
623 print("Command not implemented.\n");
624 break;
625 }
626}
627
628//////////////////////////////////////////////////////
629//////////////// TTCN3_Debug_Scope ///////////////////
630//////////////////////////////////////////////////////
631
632TTCN3_Debug_Scope::TTCN3_Debug_Scope()
633{
634 ttcn3_debugger.add_scope(this);
635}
636
637TTCN3_Debug_Scope::~TTCN3_Debug_Scope()
638{
639 for (size_t i = 0; i < variables.size(); ++i) {
640 ttcn3_debugger.remove_variable(variables[i]);
641 }
642 ttcn3_debugger.remove_scope(this);
643}
644
645void TTCN3_Debug_Scope::add_variable(const void* p_value,
646 const char* p_name,
647 const char* p_type,
648 CHARSTRING (*p_print_function)(const TTCN3_Debugger::variable_t&))
649{
650 const TTCN3_Debugger::variable_t* var = ttcn3_debugger.add_variable(p_value, p_name, p_type, p_print_function);
651 if (var != NULL) {
652 variables.push_back(var);
653 }
654}
655
656const TTCN3_Debugger::variable_t* TTCN3_Debug_Scope::find_variable(const char* p_name) const
657{
658 for (size_t i = 0; i < variables.size(); ++i) {
659 if (strcmp(variables[i]->name, p_name) == 0) {
660 return variables[i];
661 }
662 }
663 return NULL;
664}
665
666void TTCN3_Debug_Scope::list_variables(const char* p_filter, bool& p_first) const
667{
668 for (size_t i = 0; i < variables.size(); ++i) {
669 // the filter is currently ignored
670 ttcn3_debugger.print("%s%s", p_first ? "" : " ", variables[i]->name);
671 p_first = false;
672 }
673}
674
675//////////////////////////////////////////////////////
676/////////////// TTCN3_Debug_Function /////////////////
677//////////////////////////////////////////////////////
678
679TTCN3_Debug_Function::TTCN3_Debug_Function(const char* p_name,
680 const char* p_type,
681 const char* p_module,
682 const charstring_list& p_parameter_names,
683 const charstring_list& p_parameter_types,
684 const char* p_component_name)
685: function_name(p_name), function_type(p_type), module_name(p_module)
686, parameter_names(new charstring_list(p_parameter_names))
687, parameter_types(new charstring_list(p_parameter_types))
688{
689 ttcn3_debugger.add_function(this);
690 global_scope = ttcn3_debugger.get_global_scope(p_module);
691 component_scope = (p_component_name != NULL) ?
692 ttcn3_debugger.get_component_scope(p_component_name) : NULL;
693 if (function_name == NULL) {
694 function_name = p_module; // for control parts
695 }
696}
697
698TTCN3_Debug_Function::~TTCN3_Debug_Function()
699{
700 if (ttcn3_debugger.is_on()) {
701 char* snapshot = mprintf("[%s]\tfinished\t%s(", function_type, function_name);
702 if (parameter_names->size_of() > 0) {
703 for (int i = 0; i < parameter_names->size_of(); ++i) {
704 if (i > 0) {
705 snapshot = mputstr(snapshot, ", ");
706 }
707 snapshot = mputprintf(snapshot, "[%s] %s := ", (const char*)((*parameter_types)[i]),
708 (const char*)((*parameter_names)[i]));
709 if ((*parameter_types)[i] == "out" || (*parameter_types)[i] == "inout") {
710 const TTCN3_Debugger::variable_t* parameter = find_variable((*parameter_names)[i]);
711 snapshot = mputstr(snapshot, parameter->print_function(*parameter));
712 }
713 else {
714 snapshot = mputc(snapshot, '-');
715 }
716 }
717 }
718 snapshot = mputc(snapshot, ')');
719 if (return_value.is_bound()) {
720 snapshot = mputprintf(snapshot, " returned %s", (const char*)return_value);
721 }
722 snapshot = mputc(snapshot, '\n');
723 ttcn3_debugger.add_snapshot(snapshot);
724 Free(snapshot);
725 }
726 for (size_t i = 0; i < variables.size(); ++i) {
727 delete variables[i];
728 }
729 delete parameter_names;
730 delete parameter_types;
731 ttcn3_debugger.remove_function(this);
732}
733
734const TTCN3_Debugger::variable_t* TTCN3_Debug_Function::add_variable(const void* p_value,
735 const char* p_name,
736 const char* p_type,
737 CHARSTRING (*p_print_function)(const TTCN3_Debugger::variable_t&))
738{
739 if (ttcn3_debugger.is_on()) {
740 TTCN3_Debugger::variable_t* var = new TTCN3_Debugger::variable_t;
741 var->value = p_value;
742 var->name = p_name;
743 var->type_name = p_type;
744 var->print_function = p_print_function;
745 variables.push_back(var);
746 return var;
747 }
748 return NULL;
749}
750
751void TTCN3_Debug_Function::set_return_value(const CHARSTRING& p_value)
752{
753 return_value = p_value;
754}
755
756void TTCN3_Debug_Function::initial_snapshot() const
757{
758 if (ttcn3_debugger.is_on()) {
759 char* snapshot = mprintf("[%s]\tstarted \t%s(", function_type, function_name);
760 if (parameter_names->size_of() > 0) {
761 for (int i = 0; i < parameter_names->size_of(); ++i) {
762 if (i > 0) {
763 snapshot = mputstr(snapshot, ", ");
764 }
765 snapshot = mputprintf(snapshot, "[%s] %s := ", (const char*)((*parameter_types)[i]),
766 (const char*)((*parameter_names)[i]));
767 if ((*parameter_types)[i] == "in" || (*parameter_types)[i] == "inout") {
768 const TTCN3_Debugger::variable_t* parameter = find_variable((*parameter_names)[i]);
769 snapshot = mputstr(snapshot, parameter->print_function(*parameter));
770 }
771 else {
772 snapshot = mputc(snapshot, '-');
773 }
774 }
775 }
776 snapshot = mputstr(snapshot, ")\n");
777 ttcn3_debugger.add_snapshot(snapshot);
778 Free(snapshot);
779 }
780}
781
782void TTCN3_Debug_Function::add_scope(TTCN3_Debug_Scope* p_scope)
783{
784 scopes.push_back(p_scope);
785}
786
787void TTCN3_Debug_Function::remove_scope(TTCN3_Debug_Scope* p_scope)
788{
789 if (scopes[scopes.size() - 1] == p_scope) {
790 scopes.erase_at(scopes.size() - 1);
791 }
792}
793
794void TTCN3_Debug_Function::remove_variable(const TTCN3_Debugger::variable_t* p_var)
795{
796 for (size_t i = 0; i < variables.size(); ++i) {
797 if (variables[i] == p_var) {
798 variables.erase_at(i);
799 delete p_var;
800 break;
801 }
802 }
803}
804
805const TTCN3_Debugger::variable_t* TTCN3_Debug_Function::find_variable(const char* p_name) const
806{
807 for (size_t i = 0; i < variables.size(); ++i) {
808 if (strcmp(variables[i]->name, p_name) == 0) {
809 return variables[i];
810 }
811 }
812 // it's not a local variable, it might still be a global or component variable
813 if (component_scope != NULL) {
814 const TTCN3_Debugger::variable_t* res = component_scope->find_variable(p_name);
815 if (res != NULL) {
816 return res;
817 }
818 }
819 return (global_scope != NULL) ? global_scope->find_variable(p_name) : NULL;
820}
821
822void TTCN3_Debug_Function::print_function() const
823{
824 ttcn3_debugger.print("[%s]\t%s(", function_type, function_name);
825 if (parameter_names->size_of() > 0) {
826 for (int i = 0; i < parameter_names->size_of(); ++i) {
827 if (i > 0) {
828 ttcn3_debugger.print(", ");
829 }
830 const TTCN3_Debugger::variable_t* parameter = find_variable((*parameter_names)[i]);
831 ttcn3_debugger.print("[%s] %s := %s", (const char*)(*parameter_types)[i],
832 (const char*)(*parameter_names)[i], (const char*)parameter->print_function(*parameter));
833 }
834 }
835 ttcn3_debugger.print(")\n");
836}
837
838void TTCN3_Debug_Function::list_variables(const char* p_scope, const char* p_filter) const
839{
840 bool first = true;
841 bool list_local = false;
842 bool list_global = false;
843 bool list_comp = false;
844 if (!strcmp(p_scope, "local")) {
845 list_local = true;
846 }
847 else if (!strcmp(p_scope, "global")) {
848 list_global = true;
849 }
850 else if (!strcmp(p_scope, "comp") || !strcmp(p_scope, "component")) {
851 list_comp = true;
852 }
853 else {
854 if (strcmp(p_scope, "all")) {
855 ttcn3_debugger.print("Invalid scope. Listing variables in all scopes.\n");
856 }
857 list_local = true;
858 list_global = true;
859 list_comp = true;
860 }
861 if (list_local) {
862 for (size_t i = 0; i < variables.size(); ++i) {
863 ttcn3_debugger.print("%s%s", first ? "" : " ", variables[i]->name);
864 first = false;
865 }
866 }
867 if (list_global && global_scope != NULL && global_scope->has_variables()) {
868 global_scope->list_variables(p_filter, first);
869 }
870 if (list_comp && component_scope != NULL && component_scope->has_variables()) {
871 component_scope->list_variables(p_filter, first);
872 }
873 if (first) {
874 ttcn3_debugger.print("No variables found.");
875 }
876 ttcn3_debugger.print("\n");
877}
878
This page took 0.053852 seconds and 5 git commands to generate.