7e86c0c4ee36f94fe27f96c36a6dda33e59ca100
[deliverable/titan.core.git] / core / Debugger.cc
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
20 TTCN3_Debugger ttcn3_debugger;
21
22 void 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
33 void 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
44 void 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
58 void 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
71 void 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
107 void 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
115 void 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
125 void 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
130 void 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
161 size_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
171 TTCN3_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
181 TTCN3_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
193 TTCN3_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
213 TTCN3_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
222 TTCN3_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
231 void 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
238 void 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
299 CHARSTRING 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
407 void 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
416 void TTCN3_Debugger::add_function(TTCN3_Debug_Function* p_function)
417 {
418 if (active) {
419 call_stack.push_back(p_function);
420 }
421 }
422
423 void 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
430 void 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
437 void 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
444 const 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
470 void 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
477 const 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
487 const 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
497 void 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
540 void 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
632 TTCN3_Debug_Scope::TTCN3_Debug_Scope()
633 {
634 ttcn3_debugger.add_scope(this);
635 }
636
637 TTCN3_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
645 void 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
656 const 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
666 void 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
679 TTCN3_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
698 TTCN3_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
734 const 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
751 void TTCN3_Debug_Function::set_return_value(const CHARSTRING& p_value)
752 {
753 return_value = p_value;
754 }
755
756 void 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
782 void TTCN3_Debug_Function::add_scope(TTCN3_Debug_Scope* p_scope)
783 {
784 scopes.push_back(p_scope);
785 }
786
787 void 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
794 void 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
805 const 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
822 void 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
838 void 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.048579 seconds and 4 git commands to generate.