Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Other try at killing that singleton
[simgrid.git] / src / xbt / backtrace_windows.c
1 /* $Id$ */
2
3 /* backtrace_windows - backtrace displaying on windows platform             */
4 /* This file is included by ex.c on need (windows x86)                      */
5
6 /*  Copyright (c) 2007 The SimGrid team                                     */
7 /*  All rights reserved.                                                    */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 /* 
13  * Win32 (x86) implementation backtrace, backtrace_symbols:
14  *  support for application self-debugging.
15  */
16
17 #include <dbghelp.h>
18
19
20 /* Pointer function to SymInitialize() */
21 BOOL (* fun_initialize) (HANDLE, PSTR, BOOL);
22 void (*fun_cleanup)(void);
23 void *fun_function_table_access;
24 void *fun_get_line_from_addr;
25 void *fun_get_module_base;
26 void *fun_get_options;
27 void *fun_set_options;
28 void *fun_get_sym_from_addr;
29 void *fun_stack_walk;
30
31 #if 0
32 BOOL(WINAPI * fun_initialize) (HANDLE, PSTR, BOOL);
33
34 /* Pointer function to SymCleanup() */
35 static BOOL(WINAPI * fun_cleanup) (HANDLE hProcess);
36
37 /* Pointer function to SymFunctionTableAccess() */
38 static PVOID(WINAPI * fun_function_table_access) (HANDLE, DWORD);
39
40 /* Pointer function to SymGetLineFromAddr() */
41 static BOOL(WINAPI * fun_get_line_from_addr) (HANDLE, DWORD,
42                                                 PDWORD,
43                                                 PIMAGEHLP_LINE);
44
45 /* Pointer function to SymGetModuleBase() */
46 static DWORD(WINAPI * fun_get_module_base) (HANDLE, DWORD);
47
48 /* Pointer function to SymGetOptions() */
49 static DWORD(WINAPI * fun_get_options) (VOID);
50
51 /* Pointer function to SymGetSymFromAddr() */
52 static BOOL(WINAPI * fun_get_sym_from_addr) (HANDLE, DWORD, PDWORD,
53                                                OUT PIMAGEHLP_SYMBOL);
54
55 /* Pointer function to SymSetOptions() */
56 static DWORD(WINAPI * fun_set_options) (DWORD);
57
58 /* Pointer function to StackWalk() */
59 static BOOL(WINAPI * fun_stack_walk) (DWORD, HANDLE, HANDLE,
60                                             LPSTACKFRAME, PVOID,
61                                             PREAD_PROCESS_MEMORY_ROUTINE,
62                                             PFUNCTION_TABLE_ACCESS_ROUTINE,
63                                             PGET_MODULE_BASE_ROUTINE,
64                                             PTRANSLATE_ADDRESS_ROUTINE);
65 #endif
66
67 static HINSTANCE hlp_dbg_instance = NULL;
68 static HANDLE process_handle = NULL;
69
70
71 /* Module creation/destruction: nothing to do on linux */
72 void xbt_backtrace_init(void) { 
73   process_handle = GetCurrentProcess();
74
75   if (hlp_dbg_instance) {
76     /* debug help is already loaded */
77     return;
78   }
79
80   /* load the library */
81   hlp_dbg_instance = LoadLibraryA("Dbghelp.dll");
82
83   if (!hlp_dbg_instance)
84     return;
85  
86   /* get the pointers to debug help library exported functions */
87   fun_initialize = GetProcAddress(hlp_dbg_instance, "SymInitialize");
88   fun_cleanup = GetProcAddress(hlp_dbg_instance, "SymCleanup");
89   fun_function_table_access = GetProcAddress(hlp_dbg_instance, "SymFunctionTableAccess");
90   fun_get_line_from_addr = GetProcAddress(hlp_dbg_instance, "SymGetLineFromAddr");
91   fun_get_module_base = GetProcAddress(hlp_dbg_instance, "SymGetModuleBase");
92   fun_get_options = GetProcAddress(hlp_dbg_instance, "SymGetOptions");
93   fun_get_sym_from_addr = GetProcAddress(hlp_dbg_instance, "SymGetSymFromAddr");
94   fun_set_options = GetProcAddress(hlp_dbg_instance, "SymSetOptions");
95   fun_stack_walk = GetProcAddress(hlp_dbg_instance, "StackWalk");
96
97   /* Check that everything worked well */
98   if (!fun_initialize ||
99       !fun_cleanup ||
100       !fun_function_table_access || 
101       !fun_get_line_from_addr ||
102       !fun_get_module_base ||
103       !fun_get_options ||
104       !fun_get_sym_from_addr ||
105       !fun_set_options ||
106       !fun_stack_walk
107       ) {
108     FreeLibrary(hlp_dbg_instance);
109     hlp_dbg_instance = NULL;
110     return;
111   }
112
113   (*fun_set_options) ((*fun_get_options) () |
114                         SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS);
115
116   if (!(*fun_initialize) (process_handle, 0, 1)) {
117     FreeLibrary(hlp_dbg_instance);
118     hlp_dbg_instance = NULL;
119   }
120 }
121 void xbt_backtrace_exit(void) { 
122   if (!hlp_dbg_instance)
123     return;
124
125   if ((*fun_cleanup) (process_handle))
126     FreeLibrary(hlp_dbg_instance);
127
128   hlp_dbg_instance = NULL;
129 }
130
131 /*
132  * backtrace() function.
133  *
134  * Returns a backtrace for the calling program, in  the  array
135  * pointed  to  by  buffer.  A backtrace is the series of currently active
136  * function calls for the program.  Each item in the array pointed  to  by
137  * buffer  is  of  type  void *, and is the return address from the corre-
138  * sponding stack frame.  The size argument specifies the  maximum  number
139  * of  addresses that can be stored in buffer.  If the backtrace is larger
140  * than size, then the addresses corresponding to  the  size  most  recent
141  * function  calls  are  returned;  to obtain the complete backtrace, make
142  * sure that buffer and size are large enough.
143  */
144
145 int backtrace(void **buffer, int size);
146
147 /*
148  * backtrace_symbols() function.
149  *
150  * Given the set of addresses returned by  backtrace()  in  buffer,  back-
151  * trace_symbols()  translates the addresses into an array of strings containing
152  * the name, the source file and the line number or the las called functions.
153  */
154 char **backtrace_symbols(void *const *buffer, int size);
155
156 void xbt_ex_setup_backtrace(xbt_ex_t * e)
157 {
158   int i;
159   char **backtrace_syms = backtrace_symbols(e->bt, e->used);
160
161   e->used = backtrace((void **) e->bt, XBT_BACKTRACE_SIZE);
162   e->bt_strings = NULL;
163   /* parse the output and build a new backtrace */
164   e->bt_strings = xbt_new(char *, e->used);
165
166
167   for (i = 0; i < e->used; i++)
168     e->bt_strings[i] = backtrace_syms[i];
169
170   free(backtrace_syms);
171 }
172
173 int backtrace(void **buffer, int size)
174 {
175   int pos = 0;
176   STACKFRAME *stack_frame;
177   int first = 1;
178
179   IMAGEHLP_SYMBOL *pSym;
180   unsigned long offset = 0;
181   IMAGEHLP_LINE line_info = { 0 };
182   byte
183     __buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) +
184               sizeof(ULONG64) - 1) / sizeof(ULONG64)];
185
186   CONTEXT context = { CONTEXT_FULL };
187   GetThreadContext(GetCurrentThread(), &context);
188
189   /* ebp points on stack base */
190   /* esp points on stack pointer, ie on last stacked element (current element) */
191   _asm call $ + 5
192   _asm pop eax
193   _asm mov context.Eip, eax
194   _asm mov eax, esp
195   _asm mov context.Esp, eax
196   _asm mov context.Ebp, ebp 
197
198   if ((NULL == hlp_dbg_instance) || (size <= 0) || (NULL == buffer)) {
199     errno = EINVAL;
200     return 0;
201   }
202
203   for (pos = 0; pos < size; pos++)
204     buffer[pos] = NULL;
205
206   pos = 0;
207
208   pSym = (IMAGEHLP_SYMBOL *) __buffer;
209
210   pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
211   pSym->MaxNameLength = MAX_SYM_NAME;
212
213
214   line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
215
216
217   while (pos < size) {
218     stack_frame = (void *) xbt_new0(STACKFRAME, 1);
219
220     stack_frame->AddrPC.Offset = context.Eip;
221     stack_frame->AddrPC.Mode = AddrModeFlat;
222
223     stack_frame->AddrFrame.Offset = context.Ebp;
224     stack_frame->AddrFrame.Mode = AddrModeFlat;
225
226     stack_frame->AddrStack.Offset = context.Esp;
227     stack_frame->AddrStack.Mode = AddrModeFlat;
228
229     if ((*fun_stack_walk) (IMAGE_FILE_MACHINE_I386,
230                            process_handle,
231                            GetCurrentThread(),
232                            stack_frame,
233                            &context,
234                            NULL,
235                            fun_function_table_access,
236                            fun_get_module_base, NULL)
237         && !first) {
238       if (stack_frame->AddrReturn.Offset) {
239
240         if ((*fun_get_sym_from_addr) (process_handle, stack_frame->AddrPC.Offset, &offset, pSym)) {
241           if ((*fun_get_line_from_addr) (process_handle, stack_frame->AddrPC.Offset, &offset, &line_info))
242             buffer[pos++] = (void *) stack_frame;
243         }
244       } else {
245         free(stack_frame);      /* no symbol or no line info */
246         break;
247       }
248     } else {
249       free(stack_frame);
250
251       if (first)
252         first = 0;
253       else
254         break;
255     }
256   }
257
258   return pos;
259 }
260
261 char **backtrace_symbols(void *const *buffer, int size)
262 {
263   int pos;
264   int success = 0;
265   char **strings;
266   STACKFRAME *stack_frame;
267   IMAGEHLP_SYMBOL *pSym;
268   unsigned long offset = 0;
269   IMAGEHLP_LINE line_info = { 0 };
270   IMAGEHLP_MODULE module = { 0 };
271   byte
272     __buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) +
273               sizeof(ULONG64) - 1) / sizeof(ULONG64)];
274
275   if ((NULL == hlp_dbg_instance) || (size <= 0) || (NULL == buffer)) {
276     errno = EINVAL;
277     return NULL;
278   }
279
280   strings = xbt_new0(char *, size);
281
282   pSym = (IMAGEHLP_SYMBOL *) __buffer;
283
284   pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
285   pSym->MaxNameLength = MAX_SYM_NAME;
286
287
288   line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE);
289   module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
290
291   for (pos = 0; pos < size; pos++) {
292     stack_frame = (STACKFRAME *) (buffer[pos]);
293
294     if (NULL != stack_frame) {
295
296       if ((*fun_get_sym_from_addr) (process_handle, stack_frame->AddrPC.Offset, &offset, pSym)) {
297         if ((*fun_get_line_from_addr) (process_handle, stack_frame->AddrPC.Offset, &offset, &line_info)) {
298           strings[pos] =
299             bprintf("**   In %s() at %s:%d", pSym->Name, line_info.FileName,
300                     line_info.LineNumber);
301         } else {
302           strings[pos] = bprintf("**   In %s()", pSym->Name);
303         }
304         success = 1;
305       } else {
306         strings[pos] = xbt_strdup("**   <no symbol>");
307       }
308
309       free(stack_frame);
310     } else
311       break;
312   }
313
314   if (!success) {
315     free(strings);
316     strings = NULL;
317   }
318
319   return strings;
320 }