3 /* ex - Exception Handling (modified to fit into SimGrid from OSSP version) */
5 /* Copyright (c) 2005, 2006, 2007 Martin Quinson */
6 /* Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com> */
7 /* Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/> */
8 /* Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/> */
9 /* All rights reserved. */
11 /* This program is free software; you can redistribute it and/or modify it
12 * under the terms of the license (GNU LGPL) which comes with this package. */
17 #include "portable.h" /* execinfo when available */
20 #include "xbt/module.h" /* xbt_binary_name */
21 #include "xbt/synchro.h" /* xbt_thread_self */
23 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
24 #include "xbt/ex_interface.h"
26 #if (defined(WIN32) && defined(_M_IX86))
30 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex,xbt,"Exception mecanism");
32 #if (defined(WIN32) && defined(_M_IX86))
35 * Win32 (x86) implementation backtrace, backtrace_symbols
36 * : support for application self-debugging.
39 /* Pointer function to SymInitialize() */
40 typedef BOOL (WINAPI *xbt_pfn_sym_initialize_t)(HANDLE, PSTR , BOOL);
42 /* Pointer function to SymCleanup() */
43 typedef BOOL (WINAPI *xbt_pfn_sym_cleanup_t)(HANDLE hProcess);
45 /* Pointer function to SymFunctionTableAccess() */
46 typedef PVOID (WINAPI *xbt_pfn_sym_function_table_access_t)(HANDLE, DWORD);
48 /* Pointer function to SymGetLineFromAddr() */
49 typedef BOOL (WINAPI *xbt_pfn_sym_get_line_from_addr_t)(HANDLE, DWORD, PDWORD , PIMAGEHLP_LINE);
51 /* Pointer function to SymGetModuleBase() */
52 typedef DWORD (WINAPI *xbt_pfn_sym_get_module_base_t)(HANDLE,DWORD);
54 /* Pointer function to SymGetOptions() */
55 typedef DWORD (WINAPI *xbt_pfn_sym_get_options_t)(VOID);
57 /* Pointer function to SymGetSymFromAddr() */
58 typedef BOOL (WINAPI *xbt_pfn_sym_get_sym_from_addr_t)(HANDLE, DWORD, PDWORD , OUT PIMAGEHLP_SYMBOL);
60 /* Pointer function to SymSetOptions() */
61 typedef DWORD (WINAPI *xbt_pfn_sym_set_options_t)(DWORD);
63 /* Pointer function to StackWalk() */
64 typedef BOOL (WINAPI *xbt_pfn_stack_walk_t)(DWORD, HANDLE, HANDLE ,LPSTACKFRAME, PVOID,PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE);
66 /* This structure representes the debug_help library used interface */
67 typedef struct s_xbt_debug_help
70 HANDLE process_handle;
71 xbt_pfn_sym_initialize_t sym_initialize;
72 xbt_pfn_sym_cleanup_t sym_cleanup;
73 xbt_pfn_sym_function_table_access_t sym_function_table_access;
74 xbt_pfn_sym_get_line_from_addr_t sym_get_line_from_addr;
75 xbt_pfn_sym_get_module_base_t sym_get_module_base;
76 xbt_pfn_sym_get_options_t sym_get_options;
77 xbt_pfn_sym_get_sym_from_addr_t sym_get_sym_from_addr;
78 xbt_pfn_sym_set_options_t sym_set_options;
79 xbt_pfn_stack_walk_t stack_walk;
80 }s_xbt_debug_hlp_t,* xbt_debug_hlp_t;
83 /* the address to the unique reference to the debug help library interface */
84 static xbt_debug_hlp_t
87 /* initialize the debug help library */
89 dbg_hlp_init(HANDLE process_handle);
91 /* finalize the debug help library */
93 dbg_hlp_finalize(void);
96 * backtrace() function.
98 * Returns a backtrace for the calling program, in the array
99 * pointed to by buffer. A backtrace is the series of currently active
100 * function calls for the program. Each item in the array pointed to by
101 * buffer is of type void *, and is the return address from the corre-
102 * sponding stack frame. The size argument specifies the maximum number
103 * of addresses that can be stored in buffer. If the backtrace is larger
104 * than size, then the addresses corresponding to the size most recent
105 * function calls are returned; to obtain the complete backtrace, make
106 * sure that buffer and size are large enough.
110 backtrace (void **buffer, int size);
113 * backtrace_symbols() function.
115 * Given the set of addresses returned by backtrace() in buffer, back-
116 * trace_symbols() translates the addresses into an array of strings containing
117 * the name, the source file and the line number or the las called functions.
120 backtrace_symbols (void *const *buffer, int size);
124 /* default __ex_ctx callback function */
125 ex_ctx_t *__xbt_ex_ctx_default(void) {
126 /* Don't scream: this is a default which is never used (so, yes,
127 there is one setjump container by running entity).
129 This default gets overriden in xbt/xbt_os_thread.c so that it works in
130 real life and in simulation when using threads to implement the simulation
131 processes (ie, with pthreads and on windows).
133 It also gets overriden in xbt/context.c when using ucontextes (as well as
134 in Java for now, but after the java overhaul, it will get cleaned out)
136 static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
141 /* Change raw libc symbols to file names and line numbers */
142 void xbt_ex_setup_backtrace(xbt_ex_t *e);
144 void xbt_backtrace_current(xbt_ex_t *e) {
145 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE) || (defined(WIN32) && defined(_M_IX86))
146 e->used = backtrace((void**)e->bt,XBT_BACKTRACE_SIZE);
147 e->bt_strings = NULL;
148 xbt_ex_setup_backtrace(e);
152 void xbt_backtrace_display(xbt_ex_t *e) {
153 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE) || (defined(WIN32) && defined(_M_IX86))
157 fprintf(stderr,"(backtrace not set)\n");
159 fprintf(stderr,"Backtrace (displayed in thread %p):\n",
160 (void*)xbt_thread_self());
161 for (i=1; i<e->used; i++) /* no need to display "xbt_display_backtrace" */
162 fprintf(stderr,"---> %s\n",e->bt_strings[i] +4);
165 /* don't fool xbt_ex_free with uninitialized msg field */
171 ERROR0("No backtrace on this arch");
175 /** \brief show the backtrace of the current point (lovely while debuging) */
176 void xbt_backtrace_display_current(void) {
178 xbt_backtrace_current(&e);
179 xbt_backtrace_display(&e);
183 extern char **environ; /* the environment, as specified by the opengroup */
186 void xbt_ex_setup_backtrace(xbt_ex_t *e) {
187 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
189 /* to get the backtrace from the libc */
190 char **backtrace = backtrace_symbols (e->bt, e->used);
192 /* To build the commandline of addr2line */
195 /* to extract the addresses from the backtrace */
196 char **addrs=xbt_new(char*,e->used);
199 /* To read the output of addr2line */
201 char line_func[1024],line_pos[1024];
203 /* size (in char) of pointers on this arch */
206 /* To search for the right executable path when not trivial */
207 struct stat stat_buf;
208 char *binary_name = NULL;
210 /* Some arches only have stubs of backtrace, no implementation (hppa comes to mind) */
214 /* build the commandline */
215 if (stat(xbt_binary_name,&stat_buf)) {
216 /* Damn. binary not in current dir. We'll have to dig the PATH to find it */
218 for (i=0; environ[i]; i++) {
219 if (!strncmp("PATH=",environ[i], 5)) {
220 xbt_dynar_t path=xbt_str_split(environ[i] + 5, ":");
223 xbt_dynar_foreach(path, cpt, data) {
226 binary_name = bprintf("%s/%s",data,xbt_binary_name);
227 if (!stat(binary_name,&stat_buf)) {
229 DEBUG1("Looked in the PATH for the binary. Found %s",binary_name);
230 xbt_dynar_free(&path);
234 if (stat(binary_name,&stat_buf)) {
237 e->bt_strings = xbt_new(char*,1);
238 e->bt_strings[0] = bprintf("(binary '%s' not found the path)",xbt_binary_name);
241 xbt_dynar_free(&path);
246 binary_name = xbt_strdup(xbt_binary_name);
248 cmd = curr = xbt_new(char,strlen(ADDR2LINE)+25+strlen(binary_name)+32*e->used);
250 curr += sprintf(curr,"%s -f -e %s ",ADDR2LINE,binary_name);
253 for (i=0; i<e->used;i++) {
254 /* retrieve this address */
255 DEBUG2("Retrieving address number %d from '%s'", i, backtrace[i]);
256 snprintf(buff,256,"%s",strchr(backtrace[i],'[')+1);
259 if (strcmp(buff,"(nil)"))
260 addrs[i]=bprintf("%s", buff);
262 addrs[i]=bprintf("0x0");
263 DEBUG3("Set up a new address: %d, '%s'(%p)", i, addrs[i], addrs[i]);
265 /* Add it to the command line args */
266 curr+=sprintf(curr,"%s ",addrs[i]);
268 addr_len = strlen(addrs[0]);
270 /* parse the output and build a new backtrace */
271 e->bt_strings = xbt_new(char*,e->used);
273 VERB1("Fire a first command: '%s'", cmd);
274 pipe = popen(cmd, "r");
276 CRITICAL0("Cannot fork addr2line to display the backtrace");
280 for (i=0; i<e->used; i++) {
281 DEBUG2("Looking for symbol %d, addr = '%s'", i, addrs[i]);
282 fgets(line_func,1024,pipe);
283 line_func[strlen(line_func)-1]='\0';
284 fgets(line_pos,1024,pipe);
285 line_pos[strlen(line_pos)-1]='\0';
287 if (strcmp("??",line_func)) {
288 DEBUG2("Found static symbol %s() at %s", line_func, line_pos);
289 e->bt_strings[i] = bprintf("** In %s() at %s", line_func,line_pos);
291 /* Damn. The symbol is in a dynamic library. Let's get wild */
296 long int addr,offset=0;
303 /* let's look for the offset of this library in our addressing space */
304 maps_name=bprintf("/proc/%d/maps",(int)getpid());
305 maps=fopen(maps_name,"r");
307 sscanf(addrs[i],"%lx",&addr);
308 sprintf(maps_buff,"%#lx",addr);
310 if (strcmp(addrs[i],maps_buff)) {
311 CRITICAL2("Cannot parse backtrace address '%s' (addr=%#lx)",
314 DEBUG2("addr=%s (as string) =%#lx (as number)",addrs[i],addr);
317 long int first, last;
318 if (fgets(maps_buff,512,maps) == NULL)
321 maps_buff[strlen(maps_buff) -1]='\0';
322 DEBUG1("map line: %s", maps_buff);
324 sscanf(maps_buff,"%lx",&first);
325 p=strchr(maps_buff,'-')+1;
326 sscanf(p,"%lx",&last);
327 if (first < addr && addr < last) {
332 DEBUG3("%#lx in [%#lx-%#lx]", addr, first,last);
333 DEBUG0("Symbol found, map lines not further displayed (even if looking for next ones)");
340 VERB0("Problem while reading the maps file. Following backtrace will be mangled.");
341 DEBUG1("No dynamic. Static symbol: %s", backtrace[i]);
342 e->bt_strings[i] = bprintf("** In ?? (%s)", backtrace[i]);
346 /* Ok, Found the offset of the maps line containing the searched symbol.
347 We now need to substract this from the address we got from backtrace.
351 addrs[i] = bprintf("0x%0*lx",addr_len-2,addr-offset);
352 DEBUG2("offset=%#lx new addr=%s",offset,addrs[i]);
354 /* Got it. We have our new address. Let's get the library path and we
356 p = xbt_strdup(backtrace[i]);
358 /* library path not displayed in the map file either... */
360 sprintf(line_func,"??");
367 /* Here we go, fire an addr2line up */
368 subcmd = bprintf("%s -f -e %s %s",ADDR2LINE,p, addrs[i]);
370 VERB1("Fire a new command: '%s'",subcmd);
371 subpipe = popen(subcmd,"r");
373 CRITICAL0("Cannot fork addr2line to display the backtrace");
376 fgets(line_func,1024,subpipe);
377 line_func[strlen(line_func)-1]='\0';
378 fgets(line_pos,1024,subpipe);
379 line_pos[strlen(line_pos)-1]='\0';
384 /* check whether the trick worked */
385 if (strcmp("??",line_func)) {
386 DEBUG2("Found dynamic symbol %s() at %s", line_func, line_pos);
387 e->bt_strings[i] = bprintf("** In %s() at %s", line_func,line_pos);
389 /* damn, nothing to do here. Let's print the raw address */
390 DEBUG1("Dynamic symbol not found. Raw address = %s", backtrace[i]);
391 e->bt_strings[i] = bprintf("** In ?? at %s", backtrace[i]);
397 /* Mask the bottom of the stack */
398 if (!strncmp("main",line_func,strlen("main")) ||
399 !strncmp("xbt_thread_context_wrapper",line_func,strlen("xbt_thread_context_wrapper"))) {
401 for (j=i+1; j<e->used; j++)
405 if (!strncmp("xbt_thread_context_wrapper",line_func,strlen("xbt_thread_context_wrapper"))) {
407 e->bt_strings[i] = bprintf("** (in a separate thread)");
417 #elif (defined(WIN32) && defined (_M_IX86))
419 char **backtrace = backtrace_symbols (e->bt, e->used);
421 /* parse the output and build a new backtrace */
422 e->bt_strings = xbt_new(char*,e->used);
425 for(i=0; i<e->used; i++)
427 e->bt_strings[i] = xbt_strdup(backtrace[i]);
435 /** @brief shows an exception content and the associated stack if available */
436 void xbt_ex_display(xbt_ex_t *e) {
440 thrower = bprintf(" on host %s(%d)",e->host,e->pid);
443 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
445 "** Thrown by %s()%s\n",
446 gras_os_myname(),(*xbt_getpid)(),
447 xbt_ex_catname(e->category), e->value, e->msg,
448 e->procname,thrower?thrower:" in this process");
449 CRITICAL1("%s",e->msg);
454 if (!e->remote && !e->bt_strings)
455 xbt_ex_setup_backtrace(e);
457 #if (defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)) || (defined(WIN32) && defined(_M_IX86))
458 /* We have everything to build neat backtraces */
462 fprintf(stderr,"\n");
463 for (i=0; i<e->used; i++)
464 fprintf(stderr,"%s\n",e->bt_strings[i]);
468 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
469 e->file,e->line,e->func);
475 /* default __ex_terminate callback function */
476 void __xbt_ex_terminate_default(xbt_ex_t *e) {
482 /* the externally visible API */
483 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
484 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
487 void xbt_ex_free(xbt_ex_t e) {
490 if (e.msg) free(e.msg);
499 for (i=0; i<e.used; i++)
500 free((char*)e.bt_strings[i]);
501 free((char **)e.bt_strings);
503 /* memset(e,0,sizeof(xbt_ex_t)); */
506 /** \brief returns a short name for the given exception category */
507 const char * xbt_ex_catname(xbt_errcat_t cat) {
509 case unknown_error: return "unknown_err";
510 case arg_error: return "invalid_arg";
511 case mismatch_error: return "mismatch";
512 case not_found_error: return "not found";
513 case system_error: return "system_err";
514 case network_error: return "network_err";
515 case timeout_error: return "timeout";
516 case thread_error: return "thread_err";
517 default: return "INVALID_ERR";
521 #ifndef HAVE_EXECINFO_H
522 # if (defined(WIN32) && defined(_M_IX86))
524 backtrace (void **buffer, int size)
527 STACKFRAME* stack_frame;
530 IMAGEHLP_SYMBOL * pSym;
531 unsigned long offset = 0;
532 IMAGEHLP_LINE line_info = {0};
533 byte __buffer[(sizeof(SYMBOL_INFO) +MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
535 CONTEXT context = {CONTEXT_FULL};
536 GetThreadContext(GetCurrentThread(), &context);
538 /* ebp points on stack base */
539 /* esp points on stack pointer, ie on last stacked element (current element) */
542 _asm mov context.Eip, eax
544 _asm mov context.Esp, eax
545 _asm mov context.Ebp, ebp
547 dbg_hlp_init(GetCurrentProcess());
549 if((NULL == dbg_hlp) || (size <= 0) || (NULL == buffer))
555 for(pos = 0; pos < size; pos++)
560 pSym = (IMAGEHLP_SYMBOL*)__buffer;
562 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
563 pSym->MaxNameLength = MAX_SYM_NAME;
566 line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
571 stack_frame = (void*)calloc(1,sizeof(STACKFRAME));
579 stack_frame->AddrPC.Offset = context.Eip;
580 stack_frame->AddrPC.Mode = AddrModeFlat;
582 stack_frame->AddrFrame.Offset = context.Ebp;
583 stack_frame->AddrFrame.Mode = AddrModeFlat;
585 stack_frame->AddrStack.Offset = context.Esp;
586 stack_frame->AddrStack.Mode = AddrModeFlat;
588 if((*(dbg_hlp->stack_walk))(
589 IMAGE_FILE_MACHINE_I386,
590 dbg_hlp->process_handle,
595 dbg_hlp->sym_function_table_access,
596 dbg_hlp->sym_get_module_base,
600 if(stack_frame->AddrReturn.Offset)
603 if((*(dbg_hlp->sym_get_sym_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &offset,pSym))
605 if((*(dbg_hlp->sym_get_line_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &offset,&line_info))
606 buffer[pos++] = (void*)stack_frame;
611 free(stack_frame); /* no symbol or no line info */
630 backtrace_symbols (void *const *buffer, int size)
635 STACKFRAME* stack_frame;
636 IMAGEHLP_SYMBOL * pSym;
637 unsigned long offset = 0;
638 IMAGEHLP_LINE line_info = {0};
639 IMAGEHLP_MODULE module = {0};
640 byte __buffer[(sizeof(SYMBOL_INFO) +MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
642 if((NULL == dbg_hlp) || (size <= 0) || (NULL == buffer))
648 strings = (char**)calloc(size,sizeof(char*));
656 pSym = (IMAGEHLP_SYMBOL*)__buffer;
658 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
659 pSym->MaxNameLength = MAX_SYM_NAME;
662 line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
663 module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
665 for(pos = 0; pos < size; pos++)
667 stack_frame = (STACKFRAME*)(buffer[pos]);
669 if(NULL != stack_frame)
672 if((*(dbg_hlp->sym_get_sym_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &offset,pSym))
674 if((*(dbg_hlp->sym_get_line_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &offset,&line_info))
676 strings[pos] = bprintf("** In %s() at %s:%d", pSym->Name,line_info.FileName,line_info.LineNumber);
680 strings[pos] = bprintf("** In %s()", pSym->Name);
686 strings[pos] = xbt_strdup("** <no symbol>");
707 dbg_hlp_init(HANDLE process_handle)
711 /* debug help is already loaded */
716 dbg_hlp = (xbt_debug_hlp_t)calloc(1,sizeof(s_xbt_debug_hlp_t));
721 /* load the library */
722 dbg_hlp->instance = LoadLibraryA("Dbghelp.dll");
724 if(!(dbg_hlp->instance))
728 return (int)GetLastError();
731 /* get the pointers to debug help library exported functions */
733 if(!((dbg_hlp->sym_initialize) = (xbt_pfn_sym_initialize_t)GetProcAddress(dbg_hlp->instance,"SymInitialize")))
735 FreeLibrary(dbg_hlp->instance);
738 return (int)GetLastError();
741 if(!((dbg_hlp->sym_cleanup) = (xbt_pfn_sym_cleanup_t)GetProcAddress(dbg_hlp->instance,"SymCleanup")))
743 FreeLibrary(dbg_hlp->instance);
746 return (int)GetLastError();
749 if(!((dbg_hlp->sym_function_table_access) = (xbt_pfn_sym_function_table_access_t)GetProcAddress(dbg_hlp->instance,"SymFunctionTableAccess")))
751 FreeLibrary(dbg_hlp->instance);
754 return (int)GetLastError();
757 if(!((dbg_hlp->sym_get_line_from_addr) = (xbt_pfn_sym_get_line_from_addr_t)GetProcAddress(dbg_hlp->instance,"SymGetLineFromAddr")))
759 FreeLibrary(dbg_hlp->instance);
762 return (int)GetLastError();
765 if(!((dbg_hlp->sym_get_module_base) = (xbt_pfn_sym_get_module_base_t)GetProcAddress(dbg_hlp->instance,"SymGetModuleBase")))
767 FreeLibrary(dbg_hlp->instance);
770 return (int)GetLastError();
773 if(!((dbg_hlp->sym_get_options) = (xbt_pfn_sym_get_options_t)GetProcAddress(dbg_hlp->instance,"SymGetOptions")))
775 FreeLibrary(dbg_hlp->instance);
778 return (int)GetLastError();
781 if(!((dbg_hlp->sym_get_sym_from_addr) = (xbt_pfn_sym_get_sym_from_addr_t)GetProcAddress(dbg_hlp->instance,"SymGetSymFromAddr")))
783 FreeLibrary(dbg_hlp->instance);
786 return (int)GetLastError();
789 if(!((dbg_hlp->sym_set_options) = (xbt_pfn_sym_set_options_t)GetProcAddress(dbg_hlp->instance,"SymSetOptions")))
791 FreeLibrary(dbg_hlp->instance);
794 return (int)GetLastError();
797 if(!((dbg_hlp->stack_walk) = (xbt_pfn_stack_walk_t)GetProcAddress(dbg_hlp->instance,"StackWalk")))
799 FreeLibrary(dbg_hlp->instance);
802 return (int)GetLastError();
805 dbg_hlp->process_handle = process_handle;
807 (*(dbg_hlp->sym_set_options))((*(dbg_hlp->sym_get_options))() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS);
809 if(!(*(dbg_hlp->sym_initialize))(dbg_hlp->process_handle,0,1))
811 FreeLibrary(dbg_hlp->instance);
814 return (int)GetLastError();
822 dbg_hlp_finalize(void)
827 if(!(*(dbg_hlp->sym_cleanup))(dbg_hlp->process_handle))
828 return (int)GetLastError();
830 if(!FreeLibrary(dbg_hlp->instance))
831 return (int)GetLastError();
840 /* dummy implementation. We won't use the result, but ex.h needs it to be defined */
841 int backtrace (void **__array, int __size) {
851 XBT_TEST_SUITE("xbt_ex","Exception Handling");
853 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
857 xbt_test_add0("basic nested control flow");
861 xbt_test_fail1("M1: n=%d (!= 1)", n);
865 xbt_test_fail1("M2: n=%d (!= 2)", n);
867 THROW0(unknown_error,0,"something");
870 xbt_test_fail1("M3: n=%d (!= 3)", n);
877 xbt_test_fail1("M2: n=%d (!= 5)", n);
879 THROW0(unknown_error,0,"something");
882 xbt_test_fail1("M3: n=%d (!= 6)", n);
887 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
891 xbt_test_fail1("M4: n=%d (!= 7)", n);
896 xbt_test_fail1("M5: n=%d (!= 8)", n);
899 XBT_TEST_UNIT("value",test_value,"exception value passing") {
903 THROW0(unknown_error, 2, "toto");
905 xbt_test_add0("exception value passing");
906 if (ex.category != unknown_error)
907 xbt_test_fail1("category=%d (!= 1)", ex.category);
909 xbt_test_fail1("value=%d (!= 2)", ex.value);
910 if (strcmp(ex.msg,"toto"))
911 xbt_test_fail1("message=%s (!= toto)", ex.msg);
916 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
921 r1 = r2 = v1 = v2 = 1234;
925 THROW0(unknown_error, 0, "toto");
927 xbt_test_add0("variable preservation");
929 xbt_test_fail1("r1=%d (!= 1234)", r1);
931 xbt_test_fail1("v1=%d (!= 1234)", v1);
932 /* r2 is allowed to be destroyed because not volatile */
934 xbt_test_fail1("v2=%d (!= 5678)", v2);
939 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
944 xbt_test_add0("cleanup handling");
950 THROW0(1, 2, "blah");
953 xbt_test_fail1("v1 = %d (!= 5678)", v1);
957 xbt_test_fail1("v1 = %d (!= 5678)", v1);
958 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
959 xbt_test_fail0("unexpected exception contents");
963 xbt_test_fail0("xbt_ex_free not executed");
968 * The following is the example included in the documentation. It's a good
969 * idea to check its syntax even if we don't try to run it.
970 * And actually, it allows to put comments in the code despite doxygen.
972 static char *mallocex(int size) {
975 #define SMALLAMOUNT 10
976 #define TOOBIG 100000000
978 #if 0 /* this contains syntax errors, actually */
979 static void bad_example(void) {
980 struct {char*first;} *globalcontext;
985 char *cp1, *cp2, *cp3;
987 cp1 = mallocex(SMALLAMOUNT);
988 globalcontext->first = cp1;
989 cp2 = mallocex(TOOBIG);
990 cp3 = mallocex(SMALLAMOUNT);
994 if (cp3 != NULL) free(cp3);
995 if (cp2 != NULL) free(cp2);
996 if (cp1 != NULL) free(cp1);
998 printf("cp3=%s", cp3);
1001 /* end_of_bad_example */
1004 typedef struct {char *first;} global_context_t;
1006 static void good_example(void) {
1007 global_context_t *global_context=malloc(sizeof(global_context_t));
1012 char * volatile /*03*/ cp1 = NULL /*02*/;
1013 char * volatile /*03*/ cp2 = NULL /*02*/;
1014 char * volatile /*03*/ cp3 = NULL /*02*/;
1016 cp1 = mallocex(SMALLAMOUNT);
1017 global_context->first = cp1;
1018 cp1 = NULL /*05 give away*/;
1019 cp2 = mallocex(TOOBIG);
1020 cp3 = mallocex(SMALLAMOUNT);
1024 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
1029 /*05 cp1 was given away */
1031 /*05 global context untouched */
1035 /* end_of_good_example */
1037 #endif /* SIMGRID_TEST */