+
+#ifndef HAVE_EXECINFO_H
+# if (defined(WIN32) && defined(_M_IX86))
+int
+backtrace (void **buffer, int size)
+{
+ int pos = 0;
+ STACKFRAME* stack_frame;
+ int first = 1;
+
+ CONTEXT context = {CONTEXT_FULL};
+ GetThreadContext(GetCurrentThread(), &context);
+
+ /* ebp pointe sur la base de la pile */
+ /* esp pointe sur le stack pointer <=> sur le dernier élément déposé dans la pile (l'élément courant) */
+ _asm call $+5
+ _asm pop eax
+ _asm mov context.Eip, eax
+ _asm mov eax, esp
+ _asm mov context.Esp, eax
+ _asm mov context.Ebp, ebp
+
+ dbg_hlp_init(GetCurrentProcess());
+
+ if((NULL == dbg_hlp) || (size <= 0) || (NULL == buffer))
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ for(pos = 0; pos < size; pos++)
+ buffer[pos] = NULL;
+
+ pos = 0;
+
+ while(pos < size)
+ {
+ stack_frame = (void*)calloc(1,sizeof(STACKFRAME));
+
+ if(!stack_frame)
+ {
+ errno = ENOMEM;
+ break;
+ }
+
+ stack_frame->AddrPC.Offset = context.Eip;
+ stack_frame->AddrPC.Mode = AddrModeFlat;
+
+ stack_frame->AddrFrame.Offset = context.Ebp;
+ stack_frame->AddrFrame.Mode = AddrModeFlat;
+
+ stack_frame->AddrStack.Offset = context.Esp;
+ stack_frame->AddrStack.Mode = AddrModeFlat;
+
+ if((*(dbg_hlp->stack_walk))(
+ IMAGE_FILE_MACHINE_I386,
+ dbg_hlp->process_handle,
+ GetCurrentThread(),
+ stack_frame,
+ &context,
+ NULL,
+ dbg_hlp->sym_function_table_access,
+ dbg_hlp->sym_get_module_base,
+ NULL)
+ && !first)
+ {
+ if(stack_frame->AddrReturn.Offset)
+ buffer[pos++] = (void*)stack_frame;
+ else
+ {
+ free(stack_frame); /* no symbol */
+ break;
+ }
+ }
+ else
+ {
+ free(stack_frame);
+
+ if(first)
+ first = 0;
+ else
+ break;
+ }
+ }
+
+ return pos;
+}
+
+char **
+backtrace_symbols (void *const *buffer, int size)
+{
+ int pos;
+ int success = 0;
+ char** strings;
+ STACKFRAME* stack_frame;
+ char str[MAX_SYM_NAME] = {0};
+ IMAGEHLP_SYMBOL * pSym;
+ unsigned long displacement = 0;
+ IMAGEHLP_LINE line_info = {0};
+ IMAGEHLP_MODULE module = {0};
+ byte __buffer[(sizeof(SYMBOL_INFO) +MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
+
+ if((NULL == dbg_hlp) || (size <= 0) || (NULL == buffer))
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ strings = (char**)calloc(size,sizeof(char*));
+
+ if(NULL == strings)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ pSym = (IMAGEHLP_SYMBOL*)__buffer;
+
+ pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
+ pSym->MaxNameLength = MAX_SYM_NAME;
+
+
+ line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
+ module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
+
+ for(pos = 0; pos < size; pos++)
+ {
+ stack_frame = (STACKFRAME*)(buffer[pos]);
+
+ if(NULL != stack_frame)
+ {
+
+ if((*(dbg_hlp->sym_get_sym_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &displacement,pSym))
+ {
+ if((*(dbg_hlp->sym_get_line_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &displacement,&line_info))
+ {
+
+ sprintf(str,"** In %s() at %s:%d", pSym->Name,line_info.FileName,line_info.LineNumber);
+
+ strings[pos] = strdup(str);
+ memset(str,0,MAX_SYM_NAME);
+
+ success = 1;
+ }
+ }
+
+ free(stack_frame);
+ }
+ else
+ break;
+ }
+
+ if(!success)
+ {
+ free(strings);
+ strings = NULL;
+ }
+
+ dbg_hlp_finalize();
+
+ return strings;
+}
+
+void
+backtrace_symbols_fd(void *const *buffer, int size, int fd)
+{
+ int pos;
+ int success = 0;
+ STACKFRAME* stack_frame;
+ char str[MAX_SYM_NAME] = {0};
+ IMAGEHLP_SYMBOL * pSym;
+ unsigned long displacement = 0;
+ IMAGEHLP_LINE line_info = {0};
+ IMAGEHLP_MODULE module = {0};
+
+ byte __buffer[(sizeof(SYMBOL_INFO) +MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
+
+ if((NULL == dbg_hlp) || (size <= 0) || (NULL == buffer) || (-1 == fd))
+ {
+ errno = EINVAL;
+ return;
+ }
+
+ pSym = (IMAGEHLP_SYMBOL*)__buffer;
+
+ pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
+ pSym->MaxNameLength = MAX_SYM_NAME;
+
+
+ line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
+ module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
+
+ for(pos = 0; pos < size; pos++)
+ {
+ stack_frame = (STACKFRAME*)(buffer[pos]);
+
+ if(NULL != stack_frame)
+ {
+
+ if((*(dbg_hlp->sym_get_sym_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &displacement,pSym))
+ {
+ if((*(dbg_hlp->sym_get_line_from_addr))(dbg_hlp->process_handle,stack_frame->AddrPC.Offset, &displacement,&line_info))
+ {
+
+
+ sprintf(str,"** In %s() at %s:%d\n", pSym->Name,line_info.FileName,line_info.LineNumber);
+
+ if(-1 == write(fd,str,strlen(str)))
+ break;
+
+ memset(str,0,MAX_SYM_NAME);
+
+ success = 1;
+ }
+ }
+
+ free(stack_frame);
+ }
+ else
+ break;
+ }
+
+ dbg_hlp_finalize();
+
+}
+
+static int
+dbg_hlp_init(HANDLE process_handle)
+{
+ if(dbg_hlp)
+ {
+ /* debug help is already loaded */
+ return 0;
+ }
+
+ /* allocation */
+ dbg_hlp = (xbt_debug_hlp_t)calloc(1,sizeof(s_xbt_debug_hlp_t));
+
+ if(!dbg_hlp)
+ return ENOMEM;
+
+ /* load the library */
+ dbg_hlp->instance = LoadLibraryA("Dbghelp.dll");
+
+ if(!(dbg_hlp->instance))
+ {
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ /* get the pointers to debug help library exported functions */
+
+ if(!((dbg_hlp->sym_initialize) = (xbt_pfn_sym_initialize_t)GetProcAddress(dbg_hlp->instance,"SymInitialize")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_cleanup) = (xbt_pfn_sym_cleanup_t)GetProcAddress(dbg_hlp->instance,"SymCleanup")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_function_table_access) = (xbt_pfn_sym_function_table_access_t)GetProcAddress(dbg_hlp->instance,"SymFunctionTableAccess")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_get_line_from_addr) = (xbt_pfn_sym_get_line_from_addr_t)GetProcAddress(dbg_hlp->instance,"SymGetLineFromAddr")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_get_module_base) = (xbt_pfn_sym_get_module_base_t)GetProcAddress(dbg_hlp->instance,"SymGetModuleBase")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_get_options) = (xbt_pfn_sym_get_options_t)GetProcAddress(dbg_hlp->instance,"SymGetOptions")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_get_sym_from_addr) = (xbt_pfn_sym_get_sym_from_addr_t)GetProcAddress(dbg_hlp->instance,"SymGetSymFromAddr")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->sym_set_options) = (xbt_pfn_sym_set_options_t)GetProcAddress(dbg_hlp->instance,"SymSetOptions")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ if(!((dbg_hlp->stack_walk) = (xbt_pfn_stack_walk_t)GetProcAddress(dbg_hlp->instance,"StackWalk")))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+ dbg_hlp->process_handle = process_handle;
+
+ (*(dbg_hlp->sym_set_options))((*(dbg_hlp->sym_get_options))() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS);
+
+ if(!(*(dbg_hlp->sym_initialize))(dbg_hlp->process_handle,0,1))
+ {
+ FreeLibrary(dbg_hlp->instance);
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+ return (int)GetLastError();
+ }
+
+
+ return 0;
+}
+
+static int
+dbg_hlp_finalize(void)
+{
+ if(!dbg_hlp)
+ return EINVAL;
+
+ if(!(*(dbg_hlp->sym_cleanup))(dbg_hlp->process_handle))
+ return (int)GetLastError();
+
+ if(!FreeLibrary(dbg_hlp->instance))
+ return (int)GetLastError();
+
+ free(dbg_hlp);
+ dbg_hlp = NULL;
+
+ return 0;
+}
+# endif
+#else
+/* dummy implementation. We won't use the result, but ex.h needs it to be defined */
+int backtrace (void **__array, int __size) {
+ return 0;
+}
+
+#endif
+
+#ifdef SIMGRID_TEST
+#include <stdio.h>
+#include "xbt/ex.h"
+
+XBT_TEST_SUITE("xbt_ex","Exception Handling");
+
+XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
+ xbt_ex_t ex;
+ volatile int n=1;
+
+ xbt_test_add0("basic nested control flow");
+
+ TRY {
+ if (n != 1)
+ xbt_test_fail1("M1: n=%d (!= 1)", n);
+ n++;
+ TRY {
+ if (n != 2)
+ xbt_test_fail1("M2: n=%d (!= 2)", n);
+ n++;
+ THROW0(unknown_error,0,"something");
+ } CATCH (ex) {
+ if (n != 3)
+ xbt_test_fail1("M3: n=%d (!= 3)", n);
+ n++;
+ xbt_ex_free(ex);
+ }
+ n++;
+ TRY {
+ if (n != 5)
+ xbt_test_fail1("M2: n=%d (!= 5)", n);
+ n++;
+ THROW0(unknown_error,0,"something");
+ } CATCH (ex) {
+ if (n != 6)
+ xbt_test_fail1("M3: n=%d (!= 6)", n);
+ n++;
+ RETHROW;
+ n++;
+ }
+ xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
+ }
+ CATCH(ex) {
+ if (n != 7)
+ xbt_test_fail1("M4: n=%d (!= 7)", n);
+ n++;
+ xbt_ex_free(ex);
+ }
+ if (n != 8)
+ xbt_test_fail1("M5: n=%d (!= 8)", n);
+}
+
+XBT_TEST_UNIT("value",test_value,"exception value passing") {
+ xbt_ex_t ex;
+
+ TRY {
+ THROW0(unknown_error, 2, "toto");
+ } CATCH(ex) {
+ xbt_test_add0("exception value passing");
+ if (ex.category != unknown_error)
+ xbt_test_fail1("category=%d (!= 1)", ex.category);
+ if (ex.value != 2)
+ xbt_test_fail1("value=%d (!= 2)", ex.value);
+ if (strcmp(ex.msg,"toto"))
+ xbt_test_fail1("message=%s (!= toto)", ex.msg);
+ xbt_ex_free(ex);
+ }
+}
+
+XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
+ xbt_ex_t ex;
+ int r1, r2;
+ volatile int v1, v2;
+
+ r1 = r2 = v1 = v2 = 1234;
+ TRY {
+ r2 = 5678;
+ v2 = 5678;
+ THROW0(unknown_error, 0, "toto");
+ } CATCH(ex) {
+ xbt_test_add0("variable preservation");
+ if (r1 != 1234)
+ xbt_test_fail1("r1=%d (!= 1234)", r1);
+ if (v1 != 1234)
+ xbt_test_fail1("v1=%d (!= 1234)", v1);
+ /* r2 is allowed to be destroyed because not volatile */
+ if (v2 != 5678)
+ xbt_test_fail1("v2=%d (!= 5678)", v2);
+ xbt_ex_free(ex);
+ }
+}
+
+XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
+ xbt_ex_t ex;
+ volatile int v1;
+ int c;
+
+ xbt_test_add0("cleanup handling");
+
+ v1 = 1234;
+ c = 0;
+ TRY {
+ v1 = 5678;
+ THROW0(1, 2, "blah");
+ } CLEANUP {
+ if (v1 != 5678)
+ xbt_test_fail1("v1 = %d (!= 5678)", v1);
+ c = 1;
+ } CATCH(ex) {
+ if (v1 != 5678)
+ xbt_test_fail1("v1 = %d (!= 5678)", v1);
+ if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
+ xbt_test_fail0("unexpected exception contents");
+ xbt_ex_free(ex);
+ }
+ if (!c)
+ xbt_test_fail0("xbt_ex_free not executed");
+}
+
+
+/*
+ * The following is the example included in the documentation. It's a good
+ * idea to check its syntax even if we don't try to run it.
+ * And actually, it allows to put comments in the code despite doxygen.
+ */
+static char *mallocex(int size) {
+ return NULL;
+}
+#define SMALLAMOUNT 10
+#define TOOBIG 100000000
+
+#if 0 /* this contains syntax errors, actually */
+static void bad_example(void) {
+ struct {char*first;} *globalcontext;
+ ex_t ex;
+
+ /* BAD_EXAMPLE */
+ TRY {
+ char *cp1, *cp2, *cp3;
+
+ cp1 = mallocex(SMALLAMOUNT);
+ globalcontext->first = cp1;
+ cp2 = mallocex(TOOBIG);
+ cp3 = mallocex(SMALLAMOUNT);
+ strcpy(cp1, "foo");
+ strcpy(cp2, "bar");
+ } CLEANUP {
+ if (cp3 != NULL) free(cp3);
+ if (cp2 != NULL) free(cp2);
+ if (cp1 != NULL) free(cp1);
+ } CATCH(ex) {
+ printf("cp3=%s", cp3);
+ RETHROW;
+ }
+ /* end_of_bad_example */
+}
+#endif
+typedef struct {char *first;} global_context_t;
+
+static void good_example(void) {
+ global_context_t *global_context=malloc(sizeof(global_context_t));
+ xbt_ex_t ex;
+
+ /* GOOD_EXAMPLE */
+ { /*01*/
+ char * volatile /*03*/ cp1 = NULL /*02*/;
+ char * volatile /*03*/ cp2 = NULL /*02*/;
+ char * volatile /*03*/ cp3 = NULL /*02*/;
+ TRY {
+ cp1 = mallocex(SMALLAMOUNT);
+ global_context->first = cp1;
+ cp1 = NULL /*05 give away*/;
+ cp2 = mallocex(TOOBIG);
+ cp3 = mallocex(SMALLAMOUNT);
+ strcpy(cp1, "foo");
+ strcpy(cp2, "bar");
+ } CLEANUP { /*04*/
+ printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
+ if (cp3 != NULL)
+ free(cp3);
+ if (cp2 != NULL)
+ free(cp2);
+ /*05 cp1 was given away */
+ } CATCH(ex) {
+ /*05 global context untouched */
+ RETHROW;
+ }
+ }
+ /* end_of_good_example */
+}
+#endif /* SIMGRID_TEST */