Make it possible to add auxiliary values to the existing array; this
[wine.git] / programs / winedbg / winedbg.c
blob78bea5ab24ef3bb38761c4b133c762d3980a9ecb
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /* Wine internal debugger
4 * Interface to Windows debugger API
5 * Copyright 2000 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "debugger.h"
31 #include "wincon.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winternl.h"
36 #include "excpt.h"
37 #include "wine/exception.h"
38 #include "wine/library.h"
39 #include "winnls.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
45 DBG_PROCESS* DEBUG_CurrProcess = NULL;
46 DBG_THREAD* DEBUG_CurrThread = NULL;
47 DWORD DEBUG_CurrTid;
48 DWORD DEBUG_CurrPid;
49 CONTEXT DEBUG_context;
50 BOOL DEBUG_InteractiveP = FALSE;
51 static BOOL DEBUG_InException = FALSE;
52 int curr_frame = 0;
53 static char* DEBUG_LastCmdLine = NULL;
55 static DBG_PROCESS* DEBUG_ProcessList = NULL;
56 static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} local_mode;
58 DBG_INTVAR DEBUG_IntVars[DBG_IV_LAST];
60 static HANDLE hOutput;
61 void DEBUG_OutputA(const char* buffer, int len)
63 WriteFile(hOutput, buffer, len, NULL, NULL);
66 void DEBUG_OutputW(const WCHAR* buffer, int len)
68 char* ansi = NULL;
69 int newlen;
71 /* do a serious Unicode to ANSI conversion
72 FIXME: should CP_ACP be GetConsoleCP()? */
73 newlen = WideCharToMultiByte(CP_ACP, 0, buffer, len, NULL, 0, NULL, NULL);
74 if(newlen)
76 ansi = (char*)DBG_alloc(newlen);
77 if(ansi)
79 WideCharToMultiByte(CP_ACP, 0, buffer, len, ansi, newlen, NULL, NULL);
83 /* fall back to a simple Unicode to ANSI conversion in case WC2MB failed */
84 if(!ansi)
86 ansi = DBG_alloc(len);
87 if(ansi)
89 int i;
90 for(i = 0; i < len; i++)
92 ansi[i] = (char)buffer[i];
95 newlen = len;
97 /* else we are having REALLY bad luck today */
100 if(ansi)
102 DEBUG_OutputA(ansi, newlen);
103 DBG_free(ansi);
107 int DEBUG_Printf(const char* format, ...)
109 static char buf[4*1024];
110 va_list valist;
111 int len;
113 va_start(valist, format);
114 len = vsnprintf(buf, sizeof(buf), format, valist);
115 va_end(valist);
117 if (len <= -1 || len >= sizeof(buf)) {
118 len = sizeof(buf) - 1;
119 buf[len] = 0;
120 buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
122 DEBUG_OutputA(buf, len);
123 return len;
126 static BOOL DEBUG_IntVarsRW(int read)
128 HKEY hkey;
129 DWORD type = REG_DWORD;
130 DWORD val;
131 DWORD count = sizeof(val);
132 int i;
133 DBG_INTVAR* div = DEBUG_IntVars;
135 if (read) {
136 /* initializes internal vars table */
137 #define INTERNAL_VAR(_var,_val,_ref,_typ) \
138 div->val = _val; div->name = #_var; div->pval = _ref; \
139 div->type = DEBUG_GetBasicType(_typ); div++;
140 #include "intvar.h"
141 #undef INTERNAL_VAR
144 if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) {
145 WINE_ERR("Cannot create WineDbg key in registry\n");
146 return FALSE;
149 for (i = 0; i < DBG_IV_LAST; i++) {
150 if (read) {
151 if (!DEBUG_IntVars[i].pval) {
152 if (!RegQueryValueEx(hkey, DEBUG_IntVars[i].name, 0,
153 &type, (LPSTR)&val, &count))
154 DEBUG_IntVars[i].val = val;
155 DEBUG_IntVars[i].pval = &DEBUG_IntVars[i].val;
156 } else {
157 *DEBUG_IntVars[i].pval = 0;
159 } else {
160 /* FIXME: type should be infered from basic type -if any- of intvar */
161 if (DEBUG_IntVars[i].pval == &DEBUG_IntVars[i].val)
162 RegSetValueEx(hkey, DEBUG_IntVars[i].name, 0,
163 type, (LPCVOID)DEBUG_IntVars[i].pval, count);
166 RegCloseKey(hkey);
167 return TRUE;
170 DBG_INTVAR* DEBUG_GetIntVar(const char* name)
172 int i;
174 for (i = 0; i < DBG_IV_LAST; i++) {
175 if (!strcmp(DEBUG_IntVars[i].name, name))
176 return &DEBUG_IntVars[i];
178 return NULL;
181 DBG_PROCESS* DEBUG_GetProcess(DWORD pid)
183 DBG_PROCESS* p;
185 for (p = DEBUG_ProcessList; p; p = p->next)
186 if (p->pid == pid) break;
187 return p;
190 DBG_PROCESS* DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName)
192 DBG_PROCESS* p;
194 if ((p = DEBUG_GetProcess(pid)))
196 if (p->handle != 0)
198 WINE_ERR("Process (%lu) is already defined\n", pid);
200 else
202 p->handle = h;
203 p->imageName = imageName ? DBG_strdup(imageName) : NULL;
205 return p;
208 if (!(p = DBG_alloc(sizeof(DBG_PROCESS)))) return NULL;
209 p->handle = h;
210 p->pid = pid;
211 p->imageName = imageName ? DBG_strdup(imageName) : NULL;
212 p->threads = NULL;
213 p->num_threads = 0;
214 p->continue_on_first_exception = FALSE;
215 p->modules = NULL;
216 p->num_modules = 0;
217 p->next_index = 0;
218 p->dbg_hdr_addr = 0;
219 p->delayed_bp = NULL;
220 p->num_delayed_bp = 0;
222 p->next = DEBUG_ProcessList;
223 p->prev = NULL;
224 if (DEBUG_ProcessList) DEBUG_ProcessList->prev = p;
225 DEBUG_ProcessList = p;
226 return p;
229 void DEBUG_DelProcess(DBG_PROCESS* p)
231 int i;
233 while (p->threads) DEBUG_DelThread(p->threads);
235 for (i = 0; i < p->num_delayed_bp; i++)
236 if (p->delayed_bp[i].is_symbol)
237 DBG_free(p->delayed_bp[i].u.symbol.name);
239 DBG_free(p->delayed_bp);
240 if (p->prev) p->prev->next = p->next;
241 if (p->next) p->next->prev = p->prev;
242 if (p == DEBUG_ProcessList) DEBUG_ProcessList = p->next;
243 if (p == DEBUG_CurrProcess) DEBUG_CurrProcess = NULL;
244 DBG_free((char*)p->imageName);
245 DBG_free(p);
248 static void DEBUG_InitCurrProcess(void)
252 BOOL DEBUG_ProcessGetString(char* buffer, int size, HANDLE hp, LPSTR addr)
254 DWORD sz;
255 *(WCHAR*)buffer = 0;
256 return (addr && ReadProcessMemory(hp, addr, buffer, size, &sz));
259 BOOL DEBUG_ProcessGetStringIndirect(char* buffer, int size, HANDLE hp, LPVOID addr, BOOL unicode)
261 LPVOID ad;
262 DWORD sz;
264 if (addr && ReadProcessMemory(hp, addr, &ad, sizeof(ad), &sz) && sz == sizeof(ad) && ad)
266 if (!unicode) ReadProcessMemory(hp, ad, buffer, size, &sz);
267 else
269 WCHAR *buffW = DBG_alloc( size * sizeof(WCHAR) );
270 ReadProcessMemory(hp, ad, buffW, size*sizeof(WCHAR), &sz);
271 WideCharToMultiByte( CP_ACP, 0, buffW, sz/sizeof(WCHAR), buffer, size, NULL, NULL );
272 DBG_free(buffW);
274 return TRUE;
276 *(WCHAR*)buffer = 0;
277 return FALSE;
280 DBG_THREAD* DEBUG_GetThread(DBG_PROCESS* p, DWORD tid)
282 DBG_THREAD* t;
284 if (!p) return NULL;
285 for (t = p->threads; t; t = t->next)
286 if (t->tid == tid) break;
287 return t;
290 DBG_THREAD* DEBUG_AddThread(DBG_PROCESS* p, DWORD tid,
291 HANDLE h, LPVOID start, LPVOID teb)
293 DBG_THREAD* t = DBG_alloc(sizeof(DBG_THREAD));
294 if (!t)
295 return NULL;
297 t->handle = h;
298 t->tid = tid;
299 t->start = start;
300 t->teb = teb;
301 t->process = p;
302 t->wait_for_first_exception = 0;
303 t->exec_mode = EXEC_CONT;
304 t->exec_count = 0;
306 snprintf(t->name, sizeof(t->name), "%08lx", tid);
308 p->num_threads++;
309 t->next = p->threads;
310 t->prev = NULL;
311 if (p->threads) p->threads->prev = t;
312 p->threads = t;
314 return t;
317 static void DEBUG_InitCurrThread(void)
319 if (DEBUG_CurrThread->start) {
320 if (DEBUG_CurrThread->process->num_threads == 1 ||
321 DBG_IVAR(BreakAllThreadsStartup)) {
322 DBG_VALUE value;
324 DEBUG_SetBreakpoints(FALSE);
325 value.type = NULL;
326 value.cookie = DV_TARGET;
327 value.addr.seg = 0;
328 value.addr.off = (DWORD)DEBUG_CurrThread->start;
329 DEBUG_AddBreakpointFromValue(&value);
330 DEBUG_SetBreakpoints(TRUE);
332 } else {
333 DEBUG_CurrThread->wait_for_first_exception = 1;
337 void DEBUG_DelThread(DBG_THREAD* t)
339 if (t->prev) t->prev->next = t->next;
340 if (t->next) t->next->prev = t->prev;
341 if (t == t->process->threads) t->process->threads = t->next;
342 t->process->num_threads--;
343 if (t == DEBUG_CurrThread) DEBUG_CurrThread = NULL;
344 DBG_free(t);
347 static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de);
349 /******************************************************************
350 * DEBUG_Attach
352 * Sets the debuggee to <pid>
353 * cofe instructs winedbg what to do when first exception is received
354 * (break=FALSE, continue=TRUE)
355 * wfe is set to TRUE if DEBUG_Attach should also proceed with all debug events
356 * until the first exception is received (aka: attach to an already running process)
358 BOOL DEBUG_Attach(DWORD pid, BOOL cofe, BOOL wfe)
360 DEBUG_EVENT de;
362 if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0, NULL))) return FALSE;
364 if (!DebugActiveProcess(pid)) {
365 DEBUG_Printf("Can't attach process %lx: error %ld\n", pid, GetLastError());
366 DEBUG_DelProcess(DEBUG_CurrProcess);
367 return FALSE;
369 DEBUG_CurrProcess->continue_on_first_exception = cofe;
371 if (wfe) /* shall we proceed all debug events until we get an exception ? */
373 DEBUG_InteractiveP = FALSE;
374 while (DEBUG_CurrProcess && WaitForDebugEvent(&de, INFINITE))
376 if (DEBUG_HandleDebugEvent(&de)) break;
378 if (DEBUG_CurrProcess) DEBUG_InteractiveP = TRUE;
380 return TRUE;
383 BOOL DEBUG_Detach(void)
385 /* remove all set breakpoints in debuggee code */
386 DEBUG_SetBreakpoints(FALSE);
387 /* needed for single stepping (ugly).
388 * should this be handled inside the server ??? */
389 #ifdef __i386__
390 DEBUG_context.EFlags &= ~STEP_FLAG;
391 #endif
392 SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
393 DebugActiveProcessStop(DEBUG_CurrProcess->pid);
394 DEBUG_DelProcess(DEBUG_CurrProcess);
395 /* FIXME: should zero out the symbol table too */
396 return TRUE;
399 static BOOL DEBUG_FetchContext(void)
401 DEBUG_context.ContextFlags = CONTEXT_CONTROL
402 | CONTEXT_INTEGER
403 #ifdef CONTEXT_SEGMENTS
404 | CONTEXT_SEGMENTS
405 #endif
406 #ifdef CONTEXT_DEBUG_REGISTERS
407 | CONTEXT_DEBUG_REGISTERS
408 #endif
410 if (!GetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context))
412 WINE_WARN("Can't get thread's context\n");
413 return FALSE;
415 return TRUE;
418 static BOOL DEBUG_ExceptionProlog(BOOL is_debug, BOOL force, DWORD code)
420 DBG_ADDR addr;
421 int newmode;
423 DEBUG_InException = TRUE;
424 DEBUG_GetCurrentAddress(&addr);
425 DEBUG_SuspendExecution();
427 if (!is_debug)
429 if (!addr.seg)
430 DEBUG_Printf(" in 32-bit code (0x%08lx)", addr.off);
431 else
432 switch (DEBUG_GetSelectorType(addr.seg))
434 case MODE_32:
435 DEBUG_Printf(" in 32-bit code (%04lx:%08lx)", addr.seg, addr.off);
436 break;
437 case MODE_16:
438 DEBUG_Printf(" in 16-bit code (%04lx:%04lx)", addr.seg, addr.off);
439 break;
440 case MODE_VM86:
441 DEBUG_Printf(" in vm86 code (%04lx:%04lx)", addr.seg, addr.off);
442 break;
443 case MODE_INVALID:
444 DEBUG_Printf(" bad CS (%lx)", addr.seg);
445 break;
447 DEBUG_Printf(".\n");
450 DEBUG_LoadEntryPoints("Loading new modules symbols:\n");
452 * Do a quiet backtrace so that we have an idea of what the situation
453 * is WRT the source files.
455 DEBUG_BackTrace(DEBUG_CurrTid, FALSE);
457 if (!force && is_debug &&
458 DEBUG_ShouldContinue(&addr, code,
459 &DEBUG_CurrThread->exec_count))
460 return FALSE;
462 if ((newmode = DEBUG_GetSelectorType(addr.seg)) == MODE_INVALID) newmode = MODE_32;
463 if (newmode != DEBUG_CurrThread->dbg_mode)
465 static const char * const names[] = { "???", "16-bit", "32-bit", "vm86" };
466 DEBUG_Printf("In %s mode.\n", names[newmode] );
467 DEBUG_CurrThread->dbg_mode = newmode;
470 DEBUG_DoDisplay();
472 if (!is_debug && !force) {
473 /* This is a real crash, dump some info */
474 DEBUG_InfoRegisters(&DEBUG_context);
475 DEBUG_InfoStack();
476 #ifdef __i386__
477 if (DEBUG_CurrThread->dbg_mode == MODE_16) {
478 DEBUG_InfoSegments(DEBUG_context.SegDs >> 3, 1);
479 if (DEBUG_context.SegEs != DEBUG_context.SegDs)
480 DEBUG_InfoSegments(DEBUG_context.SegEs >> 3, 1);
482 DEBUG_InfoSegments(DEBUG_context.SegFs >> 3, 1);
483 #endif
484 DEBUG_BackTrace(DEBUG_CurrTid, TRUE);
487 if (!is_debug ||
488 (DEBUG_CurrThread->exec_mode == EXEC_STEPI_OVER) ||
489 (DEBUG_CurrThread->exec_mode == EXEC_STEPI_INSTR)) {
491 struct list_id list;
493 /* Show where we crashed */
494 curr_frame = 0;
495 DEBUG_DisassembleInstruction(&addr);
497 /* resets list internal arguments so we can look at source code when needed */
498 DEBUG_FindNearestSymbol(&addr, TRUE, NULL, 0, &list);
499 if (list.sourcefile) DEBUG_List(&list, NULL, 0);
501 return TRUE;
504 static void DEBUG_ExceptionEpilog(void)
506 DEBUG_RestartExecution(DEBUG_CurrThread->exec_count);
508 * This will have gotten absorbed into the breakpoint info
509 * if it was used. Otherwise it would have been ignored.
510 * In any case, we don't mess with it any more.
512 if (DEBUG_CurrThread->exec_mode == EXEC_CONT)
513 DEBUG_CurrThread->exec_count = 0;
514 DEBUG_InException = FALSE;
517 static DWORD DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOOL force)
519 BOOL is_debug = FALSE;
520 THREADNAME_INFO *pThreadName;
521 DBG_THREAD *pThread;
523 assert(DEBUG_CurrThread);
525 switch (rec->ExceptionCode)
527 case EXCEPTION_BREAKPOINT:
528 case EXCEPTION_SINGLE_STEP:
529 is_debug = TRUE;
530 break;
531 case EXCEPTION_NAME_THREAD:
532 pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
533 if (pThreadName->dwThreadID == -1)
534 pThread = DEBUG_CurrThread;
535 else
536 pThread = DEBUG_GetThread(DEBUG_CurrProcess, pThreadName->dwThreadID);
538 if (ReadProcessMemory(DEBUG_CurrThread->process->handle, pThreadName->szName,
539 pThread->name, 9, NULL))
540 DEBUG_Printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
541 pThread->tid, pThread->name);
542 return DBG_CONTINUE;
545 if (first_chance && !is_debug && !force && !DBG_IVAR(BreakOnFirstChance))
547 /* pass exception to program except for debug exceptions */
548 return DBG_EXCEPTION_NOT_HANDLED;
551 if (!is_debug)
553 /* print some infos */
554 DEBUG_Printf("%s: ",
555 first_chance ? "First chance exception" : "Unhandled exception");
556 switch (rec->ExceptionCode)
558 case EXCEPTION_INT_DIVIDE_BY_ZERO:
559 DEBUG_Printf("divide by zero");
560 break;
561 case EXCEPTION_INT_OVERFLOW:
562 DEBUG_Printf("overflow");
563 break;
564 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
565 DEBUG_Printf("array bounds");
566 break;
567 case EXCEPTION_ILLEGAL_INSTRUCTION:
568 DEBUG_Printf("illegal instruction");
569 break;
570 case EXCEPTION_STACK_OVERFLOW:
571 DEBUG_Printf("stack overflow");
572 break;
573 case EXCEPTION_PRIV_INSTRUCTION:
574 DEBUG_Printf("privileged instruction");
575 break;
576 case EXCEPTION_ACCESS_VIOLATION:
577 if (rec->NumberParameters == 2)
578 DEBUG_Printf("page fault on %s access to 0x%08lx",
579 rec->ExceptionInformation[0] ? "write" : "read",
580 rec->ExceptionInformation[1]);
581 else
582 DEBUG_Printf("page fault");
583 break;
584 case EXCEPTION_DATATYPE_MISALIGNMENT:
585 DEBUG_Printf("Alignment");
586 break;
587 case DBG_CONTROL_C:
588 DEBUG_Printf("^C");
589 break;
590 case CONTROL_C_EXIT:
591 DEBUG_Printf("^C");
592 break;
593 case STATUS_POSSIBLE_DEADLOCK:
595 DBG_ADDR addr;
597 addr.seg = 0;
598 addr.off = rec->ExceptionInformation[0];
600 DEBUG_Printf("wait failed on critical section ");
601 DEBUG_PrintAddress(&addr, DEBUG_CurrThread->dbg_mode, FALSE);
603 if (!DBG_IVAR(BreakOnCritSectTimeOut))
605 DEBUG_Printf("\n");
606 return DBG_EXCEPTION_NOT_HANDLED;
608 break;
609 case EXCEPTION_WINE_STUB:
611 char dll[32], name[64];
612 DEBUG_ProcessGetString( dll, sizeof(dll), DEBUG_CurrThread->process->handle,
613 (char *)rec->ExceptionInformation[0] );
614 DEBUG_ProcessGetString( name, sizeof(name), DEBUG_CurrThread->process->handle,
615 (char *)rec->ExceptionInformation[1] );
616 DEBUG_Printf("unimplemented function %s.%s called", dll, name );
618 break;
619 case EXCEPTION_WINE_ASSERTION:
620 DEBUG_Printf("assertion failed");
621 break;
622 case EXCEPTION_VM86_INTx:
623 DEBUG_Printf("interrupt %02lx in vm86 mode",
624 rec->ExceptionInformation[0]);
625 break;
626 case EXCEPTION_VM86_STI:
627 DEBUG_Printf("sti in vm86 mode");
628 break;
629 case EXCEPTION_VM86_PICRETURN:
630 DEBUG_Printf("PIC return in vm86 mode");
631 break;
632 case EXCEPTION_FLT_DENORMAL_OPERAND:
633 DEBUG_Printf("denormal float operand");
634 break;
635 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
636 DEBUG_Printf("divide by zero");
637 break;
638 case EXCEPTION_FLT_INEXACT_RESULT:
639 DEBUG_Printf("inexact float result");
640 break;
641 case EXCEPTION_FLT_INVALID_OPERATION:
642 DEBUG_Printf("invalid float operation");
643 break;
644 case EXCEPTION_FLT_OVERFLOW:
645 DEBUG_Printf("floating pointer overflow");
646 break;
647 case EXCEPTION_FLT_UNDERFLOW:
648 DEBUG_Printf("floating pointer underflow");
649 break;
650 case EXCEPTION_FLT_STACK_CHECK:
651 DEBUG_Printf("floating point stack check");
652 break;
653 default:
654 DEBUG_Printf("%08lx", rec->ExceptionCode);
655 break;
659 if (local_mode == automatic_mode)
661 DEBUG_ExceptionProlog(is_debug, FALSE, rec->ExceptionCode);
662 DEBUG_ExceptionEpilog();
663 return 0; /* terminate execution */
666 if (DEBUG_ExceptionProlog(is_debug, force, rec->ExceptionCode))
668 DEBUG_InteractiveP = TRUE;
669 return 0;
671 DEBUG_ExceptionEpilog();
673 return DBG_CONTINUE;
676 static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de)
678 char buffer[256];
679 DWORD cont = DBG_CONTINUE;
681 DEBUG_CurrPid = de->dwProcessId;
682 DEBUG_CurrTid = de->dwThreadId;
684 if ((DEBUG_CurrProcess = DEBUG_GetProcess(de->dwProcessId)) != NULL)
685 DEBUG_CurrThread = DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId);
686 else
687 DEBUG_CurrThread = NULL;
689 switch (de->dwDebugEventCode)
691 case EXCEPTION_DEBUG_EVENT:
692 if (!DEBUG_CurrThread)
694 WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
695 de->dwProcessId, de->dwThreadId);
696 break;
699 WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
700 de->dwProcessId, de->dwThreadId,
701 de->u.Exception.ExceptionRecord.ExceptionCode);
703 if (DEBUG_CurrProcess->continue_on_first_exception)
705 DEBUG_CurrProcess->continue_on_first_exception = FALSE;
706 if (!DBG_IVAR(BreakOnAttach)) break;
709 if (DEBUG_FetchContext())
711 cont = DEBUG_HandleException(&de->u.Exception.ExceptionRecord,
712 de->u.Exception.dwFirstChance,
713 DEBUG_CurrThread->wait_for_first_exception);
714 if (cont && DEBUG_CurrThread)
716 DEBUG_CurrThread->wait_for_first_exception = 0;
717 SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context);
720 break;
722 case CREATE_THREAD_DEBUG_EVENT:
723 WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n", de->dwProcessId, de->dwThreadId,
724 (unsigned long)(LPVOID)de->u.CreateThread.lpStartAddress);
726 if (DEBUG_CurrProcess == NULL)
728 WINE_ERR("Unknown process\n");
729 break;
731 if (DEBUG_GetThread(DEBUG_CurrProcess, de->dwThreadId) != NULL)
733 WINE_TRACE("Thread already listed, skipping\n");
734 break;
737 DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,
738 de->dwThreadId,
739 de->u.CreateThread.hThread,
740 de->u.CreateThread.lpStartAddress,
741 de->u.CreateThread.lpThreadLocalBase);
742 if (!DEBUG_CurrThread)
744 WINE_ERR("Couldn't create thread\n");
745 break;
747 DEBUG_InitCurrThread();
748 break;
750 case CREATE_PROCESS_DEBUG_EVENT:
751 DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer),
752 de->u.CreateProcessInfo.hProcess,
753 de->u.CreateProcessInfo.lpImageName,
754 de->u.CreateProcessInfo.fUnicode);
756 WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
757 de->dwProcessId, de->dwThreadId,
758 buffer, de->u.CreateProcessInfo.lpImageName,
759 (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress,
760 de->u.CreateProcessInfo.dwDebugInfoFileOffset,
761 de->u.CreateProcessInfo.nDebugInfoSize);
763 DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
764 de->u.CreateProcessInfo.hProcess,
765 buffer[0] ? buffer : "<Debugged Process>");
766 if (DEBUG_CurrProcess == NULL)
768 WINE_ERR("Couldn't create process\n");
769 break;
772 WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
773 de->dwProcessId, de->dwThreadId,
774 (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress);
776 DEBUG_CurrThread = DEBUG_AddThread(DEBUG_CurrProcess,
777 de->dwThreadId,
778 de->u.CreateProcessInfo.hThread,
779 de->u.CreateProcessInfo.lpStartAddress,
780 de->u.CreateProcessInfo.lpThreadLocalBase);
781 if (!DEBUG_CurrThread)
783 WINE_ERR("Couldn't create thread\n");
784 break;
786 else
788 struct elf_info elf_info;
790 DEBUG_InitCurrProcess();
791 DEBUG_InitCurrThread();
793 elf_info.flags = ELF_INFO_MODULE;
795 if (DEBUG_ReadWineLoaderDbgInfo(DEBUG_CurrProcess->handle, &elf_info) != DIL_ERROR &&
796 DEBUG_SetElfSoLoadBreakpoint(&elf_info))
798 /* then load the main module's symbols */
799 DEBUG_LoadPEModule(DEBUG_CurrProcess->imageName,
800 de->u.CreateProcessInfo.hFile,
801 de->u.CreateProcessInfo.lpBaseOfImage);
803 else
805 DEBUG_DelThread(DEBUG_CurrProcess->threads);
806 DEBUG_DelProcess(DEBUG_CurrProcess);
807 DEBUG_Printf("Couldn't load process\n");
810 break;
812 case EXIT_THREAD_DEBUG_EVENT:
813 WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
814 de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
816 if (DEBUG_CurrThread == NULL)
818 WINE_ERR("Unknown thread\n");
819 break;
821 /* FIXME: remove break point set on thread startup */
822 DEBUG_DelThread(DEBUG_CurrThread);
823 break;
825 case EXIT_PROCESS_DEBUG_EVENT:
826 WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
827 de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
829 if (DEBUG_CurrProcess == NULL)
831 WINE_ERR("Unknown process\n");
832 break;
834 /* just in case */
835 DEBUG_SetBreakpoints(FALSE);
836 /* kill last thread */
837 DEBUG_DelThread(DEBUG_CurrProcess->threads);
838 DEBUG_DelProcess(DEBUG_CurrProcess);
840 DEBUG_Printf("Process of pid=%08lx has terminated\n", DEBUG_CurrPid);
841 break;
843 case LOAD_DLL_DEBUG_EVENT:
844 if (DEBUG_CurrThread == NULL)
846 WINE_ERR("Unknown thread\n");
847 break;
849 DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer),
850 DEBUG_CurrThread->process->handle,
851 de->u.LoadDll.lpImageName,
852 de->u.LoadDll.fUnicode);
854 WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
855 de->dwProcessId, de->dwThreadId,
856 buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
857 de->u.LoadDll.dwDebugInfoFileOffset,
858 de->u.LoadDll.nDebugInfoSize);
859 _strupr(buffer);
860 DEBUG_LoadPEModule(buffer, de->u.LoadDll.hFile, de->u.LoadDll.lpBaseOfDll);
861 DEBUG_CheckDelayedBP();
862 if (DBG_IVAR(BreakOnDllLoad))
864 DEBUG_Printf("Stopping on DLL %s loading at %08lx\n",
865 buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
866 if (DEBUG_FetchContext()) cont = 0;
868 break;
870 case UNLOAD_DLL_DEBUG_EVENT:
871 WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", de->dwProcessId, de->dwThreadId,
872 (unsigned long)de->u.UnloadDll.lpBaseOfDll);
873 break;
875 case OUTPUT_DEBUG_STRING_EVENT:
876 if (DEBUG_CurrThread == NULL)
878 WINE_ERR("Unknown thread\n");
879 break;
882 DEBUG_ProcessGetString(buffer, sizeof(buffer),
883 DEBUG_CurrThread->process->handle,
884 de->u.DebugString.lpDebugStringData);
886 /* FIXME unicode de->u.DebugString.fUnicode ? */
887 WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
888 de->dwProcessId, de->dwThreadId, buffer);
889 break;
891 case RIP_EVENT:
892 WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
893 de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
894 de->u.RipInfo.dwType);
895 break;
897 default:
898 WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
899 de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
901 if (!cont) return TRUE; /* stop execution */
902 ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
903 return FALSE; /* continue execution */
906 static void DEBUG_ResumeDebuggee(DWORD cont)
908 if (DEBUG_InException)
910 DEBUG_ExceptionEpilog();
911 #ifdef __i386__
912 WINE_TRACE("Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
913 DEBUG_context.Eip, DEBUG_context.EFlags,
914 DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count);
915 #else
916 WINE_TRACE("Exiting debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
917 0L, 0L,
918 DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count);
919 #endif
920 if (DEBUG_CurrThread)
922 if (!SetThreadContext(DEBUG_CurrThread->handle, &DEBUG_context))
923 DEBUG_Printf("Cannot set ctx on %lu\n", DEBUG_CurrTid);
924 DEBUG_CurrThread->wait_for_first_exception = 0;
927 DEBUG_InteractiveP = FALSE;
928 if (!ContinueDebugEvent(DEBUG_CurrPid, DEBUG_CurrTid, cont))
929 DEBUG_Printf("Cannot continue on %lu (%lu)\n", DEBUG_CurrTid, cont);
932 void DEBUG_WaitNextException(DWORD cont, int count, int mode)
934 DEBUG_EVENT de;
936 if (cont == DBG_CONTINUE)
938 DEBUG_CurrThread->exec_count = count;
939 DEBUG_CurrThread->exec_mode = mode;
941 DEBUG_ResumeDebuggee(cont);
943 while (DEBUG_CurrProcess && WaitForDebugEvent(&de, INFINITE))
945 if (DEBUG_HandleDebugEvent(&de)) break;
947 if (!DEBUG_CurrProcess) return;
948 DEBUG_InteractiveP = TRUE;
949 #ifdef __i386__
950 WINE_TRACE("Entering debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
951 DEBUG_context.Eip, DEBUG_context.EFlags,
952 DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count);
953 #else
954 WINE_TRACE("Entering debugger PC=%lx EFL=%08lx mode=%d count=%d\n",
955 0L, 0L,
956 DEBUG_CurrThread->exec_mode, DEBUG_CurrThread->exec_count);
957 #endif
960 static DWORD DEBUG_MainLoop(void)
962 DEBUG_EVENT de;
964 DEBUG_Printf("WineDbg starting on pid %lx\n", DEBUG_CurrPid);
966 /* wait for first exception */
967 while (WaitForDebugEvent(&de, INFINITE))
969 if (DEBUG_HandleDebugEvent(&de)) break;
971 if (local_mode == automatic_mode)
973 /* print some extra information */
974 DEBUG_Printf("Modules:\n");
975 DEBUG_WalkModules();
976 DEBUG_Printf("Threads:\n");
977 DEBUG_WalkThreads();
979 else
981 DEBUG_InteractiveP = TRUE;
982 DEBUG_Parser(NULL);
984 DEBUG_Printf("WineDbg terminated on pid %lx\n", DEBUG_CurrPid);
986 return 0;
989 static BOOL DEBUG_Start(LPSTR cmdLine)
991 PROCESS_INFORMATION info;
992 STARTUPINFOA startup;
994 memset(&startup, 0, sizeof(startup));
995 startup.cb = sizeof(startup);
996 startup.dwFlags = STARTF_USESHOWWINDOW;
997 startup.wShowWindow = SW_SHOWNORMAL;
999 /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1000 * while GUI:s don't
1002 if (!CreateProcess(NULL, cmdLine, NULL, NULL,
1003 FALSE, DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
1004 NULL, NULL, &startup, &info))
1006 DEBUG_Printf("Couldn't start process '%s'\n", cmdLine);
1007 return FALSE;
1009 DEBUG_CurrPid = info.dwProcessId;
1010 if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0, NULL))) return FALSE;
1012 return TRUE;
1015 void DEBUG_Run(const char* args)
1017 DBG_MODULE* wmod = DEBUG_GetProcessMainModule(DEBUG_CurrProcess);
1018 const char* pgm = (wmod) ? wmod->module_name : "none";
1020 if (args) {
1021 DEBUG_Printf("Run (%s) with '%s'\n", pgm, args);
1022 } else {
1023 if (!DEBUG_LastCmdLine) {
1024 DEBUG_Printf("Cannot find previously used command line.\n");
1025 return;
1027 DEBUG_Start(DEBUG_LastCmdLine);
1031 BOOL DEBUG_InterruptDebuggee(void)
1033 DEBUG_Printf("Ctrl-C: stopping debuggee\n");
1034 /* FIXME: since we likely have a single process, signal the first process
1035 * in list
1037 if (!DEBUG_ProcessList) return FALSE;
1038 DEBUG_ProcessList->continue_on_first_exception = FALSE;
1039 return DebugBreakProcess(DEBUG_ProcessList->handle);
1042 static BOOL WINAPI DEBUG_CtrlCHandler(DWORD dwCtrlType)
1044 if (dwCtrlType == CTRL_C_EVENT)
1046 return DEBUG_InterruptDebuggee();
1048 return FALSE;
1051 static void DEBUG_InitConsole(void)
1053 /* set our control-C handler */
1054 SetConsoleCtrlHandler(DEBUG_CtrlCHandler, TRUE);
1056 /* set our own title */
1057 SetConsoleTitle("Wine Debugger");
1060 static int DEBUG_Usage(void)
1062 DEBUG_Printf("Usage: winedbg [--debugmsg dbgoptions] [--auto] [--gdb] cmdline\n" );
1063 return 1;
1066 int main(int argc, char** argv)
1068 DWORD retv = 0;
1069 unsigned gdb_flags = 0;
1071 /* Initialize the output */
1072 hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
1074 /* Initialize the type handling stuff. */
1075 DEBUG_InitTypes();
1076 DEBUG_InitCVDataTypes();
1078 /* Initialize internal vars (types must have been initialized before) */
1079 if (!DEBUG_IntVarsRW(TRUE)) return -1;
1081 /* parse options */
1082 while (argc > 1 && argv[1][0] == '-')
1084 if (!strcmp( argv[1], "--auto" ))
1086 if (local_mode != none_mode) return DEBUG_Usage();
1087 local_mode = automatic_mode;
1088 hOutput=GetStdHandle(STD_ERROR_HANDLE);
1089 /* force some internal variables */
1090 DBG_IVAR(BreakOnDllLoad) = 0;
1091 argc--; argv++;
1092 continue;
1094 if (!strcmp( argv[1], "--gdb" ))
1096 if (local_mode != none_mode) return DEBUG_Usage();
1097 local_mode = gdb_mode;
1098 argc--; argv++;
1099 continue;
1101 if (strcmp( argv[1], "--no-start") == 0 && local_mode == gdb_mode)
1103 gdb_flags |= 1;
1104 argc--; argv++; /* as we don't use argv[0] */
1105 continue;
1107 if (strcmp(argv[1], "--with-xterm") == 0 && local_mode == gdb_mode)
1109 gdb_flags |= 2;
1110 argc--; argv++; /* as we don't use argv[0] */
1111 continue;
1113 if (!strcmp( argv[1], "--debugmsg" ) && argv[2])
1115 wine_dbg_parse_options( argv[2] );
1116 argc -= 2;
1117 argv += 2;
1118 continue;
1120 return DEBUG_Usage();
1123 if (local_mode == none_mode) local_mode = winedbg_mode;
1125 /* try the form <myself> pid */
1126 if (DEBUG_CurrPid == 0 && argc == 2)
1128 char* ptr;
1130 DEBUG_CurrPid = strtol(argv[1], &ptr, 10);
1131 if (DEBUG_CurrPid == 0 || ptr == NULL ||
1132 !DEBUG_Attach(DEBUG_CurrPid, local_mode != gdb_mode, FALSE))
1133 DEBUG_CurrPid = 0;
1136 /* try the form <myself> pid evt (Win32 JIT debugger) */
1137 if (DEBUG_CurrPid == 0 && argc == 3)
1139 HANDLE hEvent;
1140 DWORD pid;
1141 char* ptr;
1143 if ((pid = strtol(argv[1], &ptr, 10)) != 0 && ptr != NULL &&
1144 (hEvent = (HANDLE)strtol(argv[2], &ptr, 10)) != 0 && ptr != NULL)
1146 if (!DEBUG_Attach(pid, TRUE, FALSE))
1148 /* don't care about result */
1149 SetEvent(hEvent);
1150 goto leave;
1152 if (!SetEvent(hEvent))
1154 WINE_ERR("Invalid event handle: %p\n", hEvent);
1155 goto leave;
1157 CloseHandle(hEvent);
1158 DEBUG_CurrPid = pid;
1162 if (DEBUG_CurrPid == 0 && argc > 1)
1164 int i, len;
1165 LPSTR cmdLine;
1167 if (!(cmdLine = DBG_alloc(len = 1))) goto oom_leave;
1168 cmdLine[0] = '\0';
1170 for (i = 1; i < argc; i++)
1172 len += strlen(argv[i]) + 1;
1173 if (!(cmdLine = DBG_realloc(cmdLine, len))) goto oom_leave;
1174 strcat(cmdLine, argv[i]);
1175 cmdLine[len - 2] = ' ';
1176 cmdLine[len - 1] = '\0';
1179 if (!DEBUG_Start(cmdLine))
1181 DEBUG_Printf("Couldn't start process '%s'\n", cmdLine);
1182 goto leave;
1184 DBG_free(DEBUG_LastCmdLine);
1185 DEBUG_LastCmdLine = cmdLine;
1187 /* don't save local vars in gdb mode */
1188 if (local_mode == gdb_mode && DEBUG_CurrPid)
1189 return DEBUG_GdbRemote(gdb_flags);
1191 DEBUG_InitConsole();
1193 retv = DEBUG_MainLoop();
1194 /* don't save modified variables in auto mode */
1195 if (local_mode != automatic_mode) DEBUG_IntVarsRW(FALSE);
1197 leave:
1198 return retv;
1200 oom_leave:
1201 DEBUG_Printf("Out of memory\n");
1202 goto leave;