1 /* Wine internal debugger
2 * Interface to Windows debugger API
3 * Copyright 2000-2004 Eric Pouech
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "wine/port.h"
29 #include "wine/exception.h"
30 #include "wine/library.h"
32 #include "wine/debug.h"
37 * + allow winedbg in automatic mode to create a minidump (or add another option
39 * + set a mode where winedbg would start (postmortem debugging) from a minidump
41 * + we always assume the stack grows as on i386 (ie downwards)
43 * + enable back the limited output (depth of structure printing and number of
45 * + make the output as close as possible to what gdb does
46 * - symbol management:
47 * + symbol table loading is broken
48 * + in symbol_get_lvalue, we don't do any scoping (as C does) between local and
49 * global vars (we may need this to force some display for example). A solution
50 * would be always to return arrays with: local vars, global vars, thunks
52 * + some bits of internal types are missing (like type casts and the address
54 * + the type for an enum's value is always inferred as int (winedbg & dbghelp)
55 * + most of the code implies that sizeof(void*) = sizeof(int)
56 * + all computations should be made on long long
57 * o expr computations are in int:s
58 * o bitfield size is on a 4-bytes
59 * + array_index and deref should be the same function (or should share the same
62 * + set a better fix for gdb (proxy mode) than the step-mode hack
63 * + implement function call in debuggee
64 * + trampoline management is broken when getting 16 <=> 32 thunk destination
66 * + thunking of delayed imports doesn't work as expected (ie, when stepping,
67 * it currently stops at first insn with line number during the library
68 * loading). We should identify this (__wine_delay_import) and set a
69 * breakpoint instead of single stepping the library loading.
70 * + it's wrong to copy thread->step_over_bp into process->bp[0] (when
71 * we have a multi-thread debuggee). complete fix must include storing all
72 * thread's step-over bp in process-wide bp array, and not to handle bp
73 * when we have the wrong thread running into that bp
74 * + code in CREATE_PROCESS debug event doesn't work on Windows, as we cannot
75 * get the name of the main module this way. We should rewrite all this code
76 * and store in struct dbg_process as early as possible (before process
77 * creation or attachment), the name of the main module
79 * + define a better way to enable the wine extensions (either DBG SDK function
80 * in dbghelp, or TLS variable, or environment variable or ...)
81 * + audit all files to ensure that we check all potential return values from
82 * every function call to catch the errors
83 * + BTW check also whether the exception mechanism is the best way to return
84 * errors (or find a proper fix for MinGW port)
85 * + use Wine standard list mechanism for all list handling
88 WINE_DEFAULT_DEBUG_CHANNEL(winedbg
);
90 struct dbg_process
* dbg_curr_process
= NULL
;
91 struct dbg_thread
* dbg_curr_thread
= NULL
;
95 BOOL dbg_interactiveP
= FALSE
;
97 static struct dbg_process
* dbg_process_list
= NULL
;
99 struct dbg_internal_var dbg_internal_vars
[DBG_IV_LAST
];
100 const struct dbg_internal_var
* dbg_context_vars
;
101 static HANDLE dbg_houtput
;
103 void dbg_outputA(const char* buffer
, int len
)
105 static char line_buff
[4096];
106 static unsigned int line_pos
;
112 unsigned int count
= min( len
, sizeof(line_buff
) - line_pos
);
113 memcpy( line_buff
+ line_pos
, buffer
, count
);
117 for (i
= line_pos
; i
> 0; i
--) if (line_buff
[i
-1] == '\n') break;
118 if (!i
) /* no newline found */
120 if (len
> 0) i
= line_pos
; /* buffer is full, flush anyway */
123 WriteFile(dbg_houtput
, line_buff
, i
, &w
, NULL
);
124 memmove( line_buff
, line_buff
+ i
, line_pos
- i
);
129 void dbg_outputW(const WCHAR
* buffer
, int len
)
134 /* do a serious Unicode to ANSI conversion
135 * FIXME: should CP_ACP be GetConsoleCP()?
137 newlen
= WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, NULL
, 0, NULL
, NULL
);
140 if (!(ansi
= HeapAlloc(GetProcessHeap(), 0, newlen
))) return;
141 WideCharToMultiByte(CP_ACP
, 0, buffer
, len
, ansi
, newlen
, NULL
, NULL
);
142 dbg_outputA(ansi
, newlen
);
143 HeapFree(GetProcessHeap(), 0, ansi
);
147 int dbg_printf(const char* format
, ...)
149 static char buf
[4*1024];
153 va_start(valist
, format
);
154 len
= vsnprintf(buf
, sizeof(buf
), format
, valist
);
157 if (len
<= -1 || len
>= sizeof(buf
))
159 len
= sizeof(buf
) - 1;
161 buf
[len
- 1] = buf
[len
- 2] = buf
[len
- 3] = '.';
163 dbg_outputA(buf
, len
);
167 static unsigned dbg_load_internal_vars(void)
170 DWORD type
= REG_DWORD
;
172 DWORD count
= sizeof(val
);
174 struct dbg_internal_var
* div
= dbg_internal_vars
;
176 /* initializes internal vars table */
177 #define INTERNAL_VAR(_var,_val,_ref,_tid) \
178 div->val = _val; div->name = #_var; div->pval = _ref; \
179 div->typeid = _tid; div++;
183 /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
184 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
186 WINE_ERR("Cannot create WineDbg key in registry\n");
190 for (i
= 0; i
< DBG_IV_LAST
; i
++)
192 if (!dbg_internal_vars
[i
].pval
)
194 if (!RegQueryValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
195 &type
, (LPBYTE
)&val
, &count
))
196 dbg_internal_vars
[i
].val
= val
;
197 dbg_internal_vars
[i
].pval
= &dbg_internal_vars
[i
].val
;
201 /* set up the debug variables for the CPU context */
202 dbg_context_vars
= be_cpu
->init_registers(&dbg_context
);
206 static unsigned dbg_save_internal_vars(void)
211 /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
212 if (RegCreateKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\WineDbg", &hkey
))
214 WINE_ERR("Cannot create WineDbg key in registry\n");
218 for (i
= 0; i
< DBG_IV_LAST
; i
++)
220 /* FIXME: type should be infered from basic type -if any- of intvar */
221 if (dbg_internal_vars
[i
].pval
== &dbg_internal_vars
[i
].val
)
222 RegSetValueEx(hkey
, dbg_internal_vars
[i
].name
, 0,
223 REG_DWORD
, (const void*)dbg_internal_vars
[i
].pval
,
224 sizeof(*dbg_internal_vars
[i
].pval
));
230 const struct dbg_internal_var
* dbg_get_internal_var(const char* name
)
232 const struct dbg_internal_var
* div
;
234 for (div
= &dbg_internal_vars
[DBG_IV_LAST
- 1]; div
>= dbg_internal_vars
; div
--)
236 if (!strcmp(div
->name
, name
)) return div
;
238 for (div
= dbg_context_vars
; div
->name
; div
++)
240 if (!strcasecmp(div
->name
, name
)) return div
;
246 struct dbg_process
* dbg_get_process(DWORD pid
)
248 struct dbg_process
* p
;
250 for (p
= dbg_process_list
; p
; p
= p
->next
)
251 if (p
->pid
== pid
) break;
255 struct dbg_process
* dbg_add_process(DWORD pid
, HANDLE h
)
257 /* FIXME: temporary */
258 extern struct be_process_io be_process_active_io
;
260 struct dbg_process
* p
;
262 if ((p
= dbg_get_process(pid
)))
266 WINE_ERR("Process (%lu) is already defined\n", pid
);
276 if (!(p
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process
)))) return NULL
;
279 p
->process_io
= &be_process_active_io
;
282 p
->continue_on_first_exception
= FALSE
;
283 p
->next_bp
= 1; /* breakpoint 0 is reserved for step-over */
284 memset(p
->bp
, 0, sizeof(p
->bp
));
285 p
->delayed_bp
= NULL
;
286 p
->num_delayed_bp
= 0;
288 p
->next
= dbg_process_list
;
290 if (dbg_process_list
) dbg_process_list
->prev
= p
;
291 dbg_process_list
= p
;
295 void dbg_set_process_name(struct dbg_process
* p
, const char* imageName
)
297 assert(p
->imageName
== NULL
);
300 char* tmp
= HeapAlloc(GetProcessHeap(), 0, strlen(imageName
) + 1);
301 if (tmp
) p
->imageName
= strcpy(tmp
, imageName
);
305 void dbg_del_process(struct dbg_process
* p
)
309 while (p
->threads
) dbg_del_thread(p
->threads
);
311 for (i
= 0; i
< p
->num_delayed_bp
; i
++)
312 if (p
->delayed_bp
[i
].is_symbol
)
313 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
[i
].u
.symbol
.name
);
315 HeapFree(GetProcessHeap(), 0, p
->delayed_bp
);
316 if (p
->prev
) p
->prev
->next
= p
->next
;
317 if (p
->next
) p
->next
->prev
= p
->prev
;
318 if (p
== dbg_process_list
) dbg_process_list
= p
->next
;
319 if (p
== dbg_curr_process
) dbg_curr_process
= NULL
;
320 HeapFree(GetProcessHeap(), 0, (char*)p
->imageName
);
321 HeapFree(GetProcessHeap(), 0, p
);
324 struct mod_loader_info
327 IMAGEHLP_MODULE
* imh_mod
;
330 static BOOL CALLBACK
mod_loader_cb(PSTR mod_name
, DWORD base
, void* ctx
)
332 struct mod_loader_info
* mli
= (struct mod_loader_info
*)ctx
;
334 if (!strcmp(mod_name
, "<wine-loader>"))
336 if (SymGetModuleInfo(mli
->handle
, base
, mli
->imh_mod
))
337 return FALSE
; /* stop enum */
342 BOOL
dbg_get_debuggee_info(HANDLE hProcess
, IMAGEHLP_MODULE
* imh_mod
)
344 struct mod_loader_info mli
;
347 /* this will resynchronize builtin dbghelp's internal ELF module list */
348 SymLoadModule(hProcess
, 0, 0, 0, 0, 0);
349 mli
.handle
= hProcess
;
350 mli
.imh_mod
= imh_mod
;
351 imh_mod
->SizeOfStruct
= sizeof(*imh_mod
);
352 imh_mod
->BaseOfImage
= 0;
353 /* this is a wine specific options to return also ELF modules in the
356 SymSetOptions((opt
= SymGetOptions()) | 0x40000000);
357 SymEnumerateModules(hProcess
, mod_loader_cb
, (void*)&mli
);
360 return imh_mod
->BaseOfImage
!= 0;
363 struct dbg_thread
* dbg_get_thread(struct dbg_process
* p
, DWORD tid
)
365 struct dbg_thread
* t
;
368 for (t
= p
->threads
; t
; t
= t
->next
)
369 if (t
->tid
== tid
) break;
373 struct dbg_thread
* dbg_add_thread(struct dbg_process
* p
, DWORD tid
,
376 struct dbg_thread
* t
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread
));
385 t
->exec_mode
= dbg_exec_cont
;
387 t
->step_over_bp
.enabled
= FALSE
;
388 t
->step_over_bp
.refcount
= 0;
389 t
->stopped_xpoint
= -1;
390 t
->in_exception
= FALSE
;
394 t
->addr_mode
= AddrModeFlat
;
396 snprintf(t
->name
, sizeof(t
->name
), "0x%08lx", tid
);
398 t
->next
= p
->threads
;
400 if (p
->threads
) p
->threads
->prev
= t
;
406 void dbg_del_thread(struct dbg_thread
* t
)
408 HeapFree(GetProcessHeap(), 0, t
->frames
);
409 if (t
->prev
) t
->prev
->next
= t
->next
;
410 if (t
->next
) t
->next
->prev
= t
->prev
;
411 if (t
== t
->process
->threads
) t
->process
->threads
= t
->next
;
412 if (t
== dbg_curr_thread
) dbg_curr_thread
= NULL
;
413 HeapFree(GetProcessHeap(), 0, t
);
416 BOOL
dbg_interrupt_debuggee(void)
418 if (!dbg_process_list
) return FALSE
;
419 /* FIXME: since we likely have a single process, signal the first process
422 if (dbg_process_list
->next
) dbg_printf("Ctrl-C: only stopping the first process\n");
423 else dbg_printf("Ctrl-C: stopping debuggee\n");
424 dbg_process_list
->continue_on_first_exception
= FALSE
;
425 return DebugBreakProcess(dbg_process_list
->handle
);
428 static BOOL WINAPI
ctrl_c_handler(DWORD dwCtrlType
)
430 if (dwCtrlType
== CTRL_C_EVENT
)
432 return dbg_interrupt_debuggee();
437 static void dbg_init_console(void)
439 /* set our control-C handler */
440 SetConsoleCtrlHandler(ctrl_c_handler
, TRUE
);
442 /* set our own title */
443 SetConsoleTitle("Wine Debugger");
446 static int dbg_winedbg_usage(void)
448 dbg_printf("Usage: winedbg [--command cmd|--file file|--auto] [--gdb [--no-start] [--with-xterm]] cmdline\n");
452 struct backend_cpu
* be_cpu
;
454 extern struct backend_cpu be_i386
;
456 extern struct backend_cpu be_ppc
;
458 extern struct backend_cpu be_alpha
;
463 int main(int argc
, char** argv
)
466 HANDLE hFile
= INVALID_HANDLE_VALUE
;
478 /* Initialize the output */
479 dbg_houtput
= GetStdHandle(STD_OUTPUT_HANDLE
);
481 /* Initialize internal vars */
482 if (!dbg_load_internal_vars()) return -1;
484 /* as we don't care about exec name */
487 if (argc
&& !strcmp(argv
[0], "--gdb"))
489 retv
= gdb_main(argc
, argv
);
490 if (retv
== -1) dbg_winedbg_usage();
494 dbg_action_mode
= winedbg_mode
;
496 SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME
)) |
497 SYMOPT_LOAD_LINES
| SYMOPT_DEFERRED_LOADS
| SYMOPT_AUTO_PUBLICS
);
499 if (argc
&& !strcmp(argv
[0], "--auto"))
501 /* force some internal variables */
502 DBG_IVAR(BreakOnDllLoad
) = 0;
503 dbg_houtput
= GetStdHandle(STD_ERROR_HANDLE
);
504 ds
= dbg_active_auto(argc
, argv
);
509 while (argc
> 0 && argv
[0][0] == '-')
511 if (!strcmp(argv
[0], "--command"))
513 char path
[MAX_PATH
], file
[MAX_PATH
];
516 GetTempPath(sizeof(path
), path
);
517 GetTempFileName(path
, "WD", 0, file
);
519 hFile
= CreateFileA(file
, GENERIC_READ
|GENERIC_WRITE
|DELETE
, FILE_SHARE_DELETE
,
520 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_DELETE_ON_CLOSE
, 0);
521 if (hFile
== INVALID_HANDLE_VALUE
)
523 dbg_printf("Couldn't open temp file %s (%lu)\n", file
, GetLastError());
526 WriteFile(hFile
, argv
[0], strlen(argv
[0]), &w
, 0);
527 WriteFile(hFile
, "\nquit\n", 6, &w
, 0);
528 SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
);
533 if (!strcmp(argv
[0], "--file"))
536 hFile
= CreateFileA(argv
[0], GENERIC_READ
|DELETE
, 0,
537 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
538 if (hFile
== INVALID_HANDLE_VALUE
)
540 dbg_printf("Couldn't open file %s (%lu)\n", argv
[0], GetLastError());
546 return dbg_winedbg_usage();
548 if (!argc
) ds
= start_ok
;
549 else if ((ds
= dbg_active_attach(argc
, argv
)) == start_error_parse
)
550 ds
= dbg_active_launch(argc
, argv
);
554 case start_ok
: break;
555 case start_error_parse
: return dbg_winedbg_usage();
556 case start_error_init
: return -1;
558 retv
= dbg_main_loop(hFile
);
559 /* don't save modified variables in auto mode */
560 if (dbg_action_mode
!= automatic_mode
) dbg_save_internal_vars();