debugger: added help in single mode UI, plus minor fixes
[deliverable/titan.core.git] / core / Error.cc
CommitLineData
d44e3c4f 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 * Balasko, Jeno
10 * Baranyi, Botond
11 * Beres, Szabolcs
12 * Delic, Adam
13 * Forstner, Matyas
14 * Herrlin, Thomas
15 * Raduly, Csaba
16 * Szabados, Kristof
17 * Szabo, Janos Zoltan – initial implementation
18 * Szalai, Gabor
19 *
20 ******************************************************************************/
970ed795
EL
21#include "Error.hh"
22#include "TitanLoggerApi.hh"
23
24#include <stdarg.h>
3abe9331 25#include <stdint.h>
970ed795
EL
26
27#include "../common/memory.h"
28#include "Logger.hh"
29#include "Runtime.hh"
30#include "Charstring.hh"
31
32#ifdef LINUX
33#include <ucontext.h>
34#include <dlfcn.h>
35#include <execinfo.h>
36
37#ifndef NO_CPP_DEMANGLE
38#include <cxxabi.h>
39using namespace __cxxabiv1;
40#endif
41
42#endif
43
44#ifdef LINUX
45
46const size_t MAX_DEPTH=100;
47
48void stacktrace(const ucontext_t& ctx)
49{
50 TTCN_Logger::log_event_str("\nStack trace:\n");
51
52 (void)ctx;
53 void *array[MAX_DEPTH];
54 size_t size;
55 char **strings;
56 size_t i;
57
58 size = backtrace (array, MAX_DEPTH);
59 strings = backtrace_symbols (array, size);
60
61 //printf ("Obtained %lu stack frames.\n", (unsigned long)size);
62
63 for (i = 0; i < size; i++) {
64 const char * symname = strings[i];
65
66 const char *begin = 0, *end = 0;
67 // The format is: /path/to/exe(_Z11mangledname+0xBAAD) [0x...]
68 // Mangled name starts here ---^ ends here--^
69 for (const char *j = symname; *j; ++j) {
70 if (*j == '(')
71 begin = j+1;
72 else if (*j == '+')
73 end = j;
74 }
75
76 char *dem = 0;
77 if (begin && end) {
78 size_t len = end - begin;
79 char *mangled = (char*)malloc(len + 1);
80 memcpy(mangled, begin, len);
81 mangled[len] = '\0';
82
83 int status;
84 dem = __cxa_demangle(mangled, NULL, 0, &status);
85
86 if(status == 0 && dem)
87 symname = dem;
88 }
89
90 if (TTCN_Logger::is_logger_up()) {
91 TTCN_Logger::log_event ("%2lu: %s%s\n", (unsigned long)i, symname, (end ? end : ""));
92 }
93 else {
94 fprintf (stderr, "%2lu: %s%s\n", (unsigned long)i, symname, (end ? end : ""));
95 }
96
97 if (dem)
98 free(dem);
99 }
100
101 free (strings);
102}
103
104void where_am_i(TTCN_Logger::Severity sev = TTCN_Logger::USER_UNQUALIFIED)
105{
106 ucontext_t uc;
107 int er = getcontext(&uc);
108 if (!er) {
109 TTCN_Logger::begin_event(sev);
110 stacktrace(uc);
111 TTCN_Logger::end_event();
112 }
113 else {
114 perror("getcontext");
115 }
116}
117
118
119static void signal_segv(int signum, siginfo_t* info, void*ptr) {
120 static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
121 ucontext_t *ucontext = (ucontext_t*)ptr;
122 fprintf(stderr, "\n\n!!! Segmentation Fault !!!\n\n");
123 fprintf(stderr, "info.si_signo = %d\n", signum);
124 fprintf(stderr, "info.si_errno = %d\n", info->si_errno);
125 fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]);
126 fprintf(stderr, "info.si_addr = %p\n", info->si_addr);
127
128 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
129 stacktrace(*ucontext);
130 TTCN_Logger::end_event();
131
132 fprintf(stderr, "\nGoodbye, cruel world!\n");
133 exit(-1);
134}
135
136int setup_sigsegv() {
137 struct sigaction action;
138 memset(&action, 0, sizeof(action));
139 action.sa_sigaction = signal_segv;
140 action.sa_flags = SA_SIGINFO;
141 if(sigaction(SIGSEGV, &action, NULL) < 0) {
142 perror("sigaction");
143 return 0;
144 }
145 return 1;
146}
147
148static void __attribute((constructor)) init(void) {
149 setup_sigsegv();
150}
151
152#elif defined(SOLARIS) || defined(SOLARIS8)
153
154/*
155 walks up call stack, printing library:routine+offset for each routine
156 */
157
158#include <dlfcn.h>
159#include <setjmp.h>
160#include<sys/types.h>
161#include <sys/reg.h>
162#include <sys/frame.h>
163
164#if defined(sparc) || defined(__sparc)
165#define FLUSHWIN() asm("ta 3");
166#define FRAME_PTR_INDEX 1
167#define SKIP_FRAMES 0
168#endif
169
170#if defined(i386) || defined(__i386)
171#define FLUSHWIN()
172#define FRAME_PTR_INDEX 3
173#define SKIP_FRAMES 1
174#endif
175
bad4a1d0 176// TODO: Values for __x86_64 are only guesses, not tested.
177#if defined(__x86_64)
178#define FLUSHWIN()
179#define FRAME_PTR_INDEX 7
180#define SKIP_FRAMES 1
181#endif
182
970ed795
EL
183#if defined(ppc) || defined(__ppc)
184#define FLUSHWIN()
185#define FRAME_PTR_INDEX 0
186#define SKIP_FRAMES 2
187#endif
188
189#include <cxxabi.h>
190
191
192/*
193 this function walks up call stack, calling user-supplied
194 function once for each stack frame, passing the pc and the user-supplied
195 usrarg as the argument.
196 */
197
198int cs_operate(int (*func)(void *, void *), void * usrarg)
199{
200 struct frame *sp;
201 jmp_buf env;
202 int i;
203 int * iptr;
204
205 FLUSHWIN();
206
207 setjmp(env);
208 iptr = (int*) env;
209
210 sp = (struct frame *) iptr[FRAME_PTR_INDEX];
211
212 for(i=0;i<SKIP_FRAMES && sp;i++)
213 sp = (struct frame*) sp->fr_savfp;
214
215 i = 0;
216
217 while(sp && sp->fr_savpc && ++i && (*func)((void*)sp->fr_savpc, usrarg)) {
218 sp = (struct frame*) sp->fr_savfp;
219 }
220
221 return(i);
222}
223
224void print_my_stack()
225{
226 int print_address(void *, void *);
227 cs_operate(print_address, NULL);
228}
229
230int print_address(void *pc, void * usrarg)
231{
232 Dl_info info;
233 const char * func;
234 const char * lib;
235
236 if(dladdr(pc, & info) == 0) {
237 func = "??";
238 lib = "??";
239 }
240 else {
241 lib = info.dli_fname;
242 func = info.dli_sname;
243 }
244
245 size_t len = strlen(lib);
246 for (--len; len > 0; --len) {
247 if (lib[len] == '/') break;
248 }
249 if (len > 0) lib += ++len;
250
251 int status = 42;
252 char *demangled = abi::__cxa_demangle(func, NULL, 0, &status);
253 if (status == 0) func = demangled;
254
255 if (TTCN_Logger::is_logger_up()) {
3abe9331 256 TTCN_Logger::log_event("%s:%s+%p\n",
970ed795
EL
257 lib,
258 func,
3abe9331 259 (void *)((uintptr_t)pc - (uintptr_t)info.dli_saddr)
260 );
970ed795
EL
261 }
262 else {
3abe9331 263 fprintf(stderr, "%s:%s+%p\n",
970ed795
EL
264 lib,
265 func,
3abe9331 266 (void *)((uintptr_t)pc - (uintptr_t)info.dli_saddr)
267 );
970ed795
EL
268 }
269
270 if (status == 0) free(demangled);
271 return(1);
272}
273
274void where_am_i(TTCN_Logger::Severity sev = TTCN_Logger::USER_UNQUALIFIED)
275{
276 TTCN_Logger::begin_event(sev);
277 print_my_stack();
278 TTCN_Logger::end_event();
279}
280
281#else
282
283void where_am_i(TTCN_Logger::Severity /*sev*/ = TTCN_Logger::USER_UNQUALIFIED)
284{
285 // You are on your own
286}
287#endif // LINUX
288
289
290TTCN_Error::~TTCN_Error()
291{
292 Free(error_msg);
293}
294
295
296void TTCN_error(const char *err_msg, ...)
297{
298 if (TTCN_Runtime::is_in_ttcn_try_block()) {
299 // Add location data as if it were logged
300 char* error_str = TTCN_Location::print_location(
301 TTCN_Logger::SINFO_STACK == TTCN_Logger::get_source_info_format(),
302 TTCN_Logger::SINFO_NONE != TTCN_Logger::get_source_info_format(),
303 TTCN_Logger::get_log_entity_name());
304 if (error_str) {
305 error_str = mputstr(error_str, " ");
306 }
307 error_str = mputstr(error_str, "Dynamic test case error: ");
308 va_list p_var;
309 va_start(p_var, err_msg);
310 error_str = mputprintf_va_list(error_str, err_msg, p_var);
311 va_end(p_var);
312 throw TTCN_Error(error_str);
313 } else {
314 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
315 if (TTCN_Logger::SINFO_NONE == TTCN_Logger::get_source_info_format())
316 {
317 //Always print some location info in case of dynamic testcase error
318 char * loc = TTCN_Location::print_location(false, true, false);
319 if (loc) {
320 TTCN_Logger::log_event_str(loc);
321 TTCN_Logger::log_event_str(": ");
322 Free(loc);
323 }
324 }
325 TTCN_Logger::log_event_str("Dynamic test case error: ");
326 va_list p_var;
327 va_start(p_var, err_msg);
328 TTCN_Logger::log_event_va_list(err_msg, p_var);
329 va_end(p_var);
330 TTCN_Logger::OS_error();
331 TTCN_Logger::end_event();
332#ifndef NDEBUG
333// the current implementation of the stack trace printout is misleading and cause more
334// trouble and misunderstanding than it solves
335// So it disabled in production compilation
336// It remains active in debug compilation
337 where_am_i(TTCN_Logger::ERROR_UNQUALIFIED);
338#endif
339 TTCN_Runtime::set_error_verdict();
340 TTCN_Logger::log_executor_runtime(
341 TitanLoggerApi::ExecutorRuntime_reason::performing__error__recovery);
342 throw TC_Error();
343 }
344}
345
346void TTCN_error_begin(const char *err_msg, ...)
347{
348 if (TTCN_Runtime::is_in_ttcn_try_block()) {
349 TTCN_Logger::begin_event_log2str();
350 // Add location data as if it were logged
351 char* loc = TTCN_Location::print_location(
352 TTCN_Logger::SINFO_STACK == TTCN_Logger::get_source_info_format(),
353 TTCN_Logger::SINFO_NONE != TTCN_Logger::get_source_info_format(),
354 TTCN_Logger::get_log_entity_name());
355 if (loc) {
356 TTCN_Logger::log_event_str(loc);
357 TTCN_Logger::log_event_str(" ");
358 Free(loc);
359 }
360 TTCN_Logger::log_event_str("Dynamic test case error: ");
361 va_list p_var;
362 va_start(p_var, err_msg);
363 TTCN_Logger::log_event_va_list(err_msg, p_var);
364 va_end(p_var);
365 } else {
366 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
367 TTCN_Logger::log_event_str("Dynamic test case error: ");
368 va_list p_var;
369 va_start(p_var, err_msg);
370 TTCN_Logger::log_event_va_list(err_msg, p_var);
371 va_end(p_var);
372 }
373}
374
375void TTCN_error_end()
376{
377 if (TTCN_Runtime::is_in_ttcn_try_block()) {
378 CHARSTRING error_str = TTCN_Logger::end_event_log2str();
379 throw TTCN_Error(mcopystr((const char*)error_str));
380 } else {
381 TTCN_Logger::OS_error();
382 TTCN_Logger::end_event();
383 TTCN_Runtime::set_error_verdict();
384 TTCN_Logger::log_executor_runtime(
385 TitanLoggerApi::ExecutorRuntime_reason::performing__error__recovery);
386 throw TC_Error();
387 }
388}
389
390void TTCN_warning(const char *warning_msg, ...)
391{
392 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED);
393 TTCN_Logger::log_event_str("Warning: ");
394 va_list p_var;
395 va_start(p_var, warning_msg);
396 TTCN_Logger::log_event_va_list(warning_msg, p_var);
397 va_end(p_var);
398 TTCN_Logger::end_event();
399}
400
401void TTCN_warning_begin(const char *warning_msg, ...)
402{
403 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED);
404 TTCN_Logger::log_event_str("Warning: ");
405 va_list p_var;
406 va_start(p_var, warning_msg);
407 TTCN_Logger::log_event_va_list(warning_msg, p_var);
408 va_end(p_var);
409}
410
411void TTCN_warning_end()
412{
413 TTCN_Logger::end_event();
414}
415
416void TTCN_pattern_error(const char *error_msg, ...)
417{
418 va_list p_var;
419 va_start(p_var, error_msg);
420 char *error_str = mprintf_va_list(error_msg, p_var);
421 va_end(p_var);
422 try {
423 TTCN_error("Charstring pattern: %s", error_str);
424 } catch (...) {
425 Free(error_str);
426 throw;
427 }
428}
429
430void TTCN_pattern_warning(const char *warning_msg, ...)
431{
432 va_list p_var;
433 va_start(p_var, warning_msg);
434 char *warning_str = mprintf_va_list(warning_msg, p_var);
435 va_end(p_var);
436 TTCN_warning("Charstring pattern: %s", warning_str);
437 Free(warning_str);
438}
This page took 0.038508 seconds and 5 git commands to generate.