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