winedbg: Change ADDRESS variables to ADDRESS64 so we can handle 64-bit addresses.
[wine] / programs / winedbg / tgt_active.c
1 /*
2  * Wine debugger - back-end for an active target
3  *
4  * Copyright 2000-2006 Eric Pouech
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdarg.h>
27
28 #include "debugger.h"
29 #include "winternl.h"
30 #include "wine/debug.h"
31 #include "wine/exception.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
34
35 static char*            dbg_last_cmd_line;
36 static struct be_process_io be_process_active_io;
37
38 static void dbg_init_current_process(void)
39 {
40 }
41
42 static void dbg_init_current_thread(void* start)
43 {
44     if (start)
45     {
46         if (dbg_curr_process->threads && 
47             !dbg_curr_process->threads->next && /* first thread ? */
48             DBG_IVAR(BreakAllThreadsStartup)) 
49         {
50             ADDRESS64   addr;
51
52             break_set_xpoints(FALSE);
53             addr.Mode   = AddrModeFlat;
54             addr.Offset = (DWORD)start;
55             break_add_break(&addr, TRUE, TRUE);
56             break_set_xpoints(TRUE);
57         }
58     } 
59 }
60
61 static unsigned dbg_handle_debug_event(DEBUG_EVENT* de);
62
63 /******************************************************************
64  *              dbg_attach_debuggee
65  *
66  * Sets the debuggee to <pid>
67  * cofe instructs winedbg what to do when first exception is received 
68  * (break=FALSE, continue=TRUE)
69  * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
70  * until the first exception is received (aka: attach to an already running process)
71  */
72 BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe)
73 {
74     DEBUG_EVENT         de;
75
76     if (!(dbg_curr_process = dbg_add_process(&be_process_active_io, pid, 0))) return FALSE;
77
78     if (!DebugActiveProcess(pid)) 
79     {
80         dbg_printf("Can't attach process %lx: error %ld\n", pid, GetLastError());
81         dbg_del_process(dbg_curr_process);
82         return FALSE;
83     }
84     dbg_curr_process->continue_on_first_exception = cofe;
85
86     SetEnvironmentVariableA("DBGHELP_NOLIVE", NULL);
87
88     if (wfe) /* shall we proceed all debug events until we get an exception ? */
89     {
90         dbg_interactiveP = FALSE;
91         while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
92         {
93             if (dbg_handle_debug_event(&de)) break;
94         }
95         if (dbg_curr_process) dbg_interactiveP = TRUE;
96     }
97     return TRUE;
98 }
99
100 static unsigned dbg_fetch_context(void)
101 {
102     dbg_context.ContextFlags = CONTEXT_CONTROL
103         | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT
104 #ifdef CONTEXT_SEGMENTS
105         | CONTEXT_SEGMENTS
106 #endif
107 #ifdef CONTEXT_DEBUG_REGISTERS
108         | CONTEXT_DEBUG_REGISTERS
109 #endif
110         ;
111     if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context))
112     {
113         WINE_WARN("Can't get thread's context\n");
114         return FALSE;
115     }
116     return TRUE;
117 }
118
119 static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
120 {
121     ADDRESS64   addr;
122     BOOL        is_break;
123     char        hexbuf[MAX_OFFSET_TO_STR_LEN];
124
125     memory_get_current_pc(&addr);
126     break_suspend_execution();
127     dbg_curr_thread->excpt_record = *rec;
128     dbg_curr_thread->in_exception = TRUE;
129
130     if (!is_debug)
131     {
132         switch (addr.Mode)
133         {
134         case AddrModeFlat:
135             dbg_printf(" in 32-bit code (%s)",
136                        memory_offset_to_string(hexbuf, addr.Offset, 0));
137             break;
138         case AddrModeReal:
139             dbg_printf(" in vm86 code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
140             break;
141         case AddrMode1616:
142             dbg_printf(" in 16-bit code (%04x:%04x)", addr.Segment, (unsigned) addr.Offset);
143             break;
144         case AddrMode1632:
145             dbg_printf(" in 32-bit code (%04x:%08lx)", addr.Segment, (unsigned long) addr.Offset);
146             break;
147         default: dbg_printf(" bad address");
148         }
149         dbg_printf(".\n");
150     }
151
152     /* this will resynchronize builtin dbghelp's internal ELF module list */
153     SymLoadModule(dbg_curr_process->handle, 0, 0, 0, 0, 0);
154
155     /*
156      * Do a quiet backtrace so that we have an idea of what the situation
157      * is WRT the source files.
158      */
159     stack_fetch_frames();
160     if (is_debug &&
161         break_should_continue(&addr, rec->ExceptionCode, &dbg_curr_thread->exec_count, &is_break))
162         return FALSE;
163
164     if (addr.Mode != dbg_curr_thread->addr_mode)
165     {
166         const char* name = NULL;
167         
168         switch (addr.Mode)
169         {
170         case AddrMode1616: name = "16 bit";     break;
171         case AddrMode1632: name = "32 bit";     break;
172         case AddrModeReal: name = "vm86";       break;
173         case AddrModeFlat: name = "32 bit";     break;
174         }
175         
176         dbg_printf("In %s mode.\n", name);
177         dbg_curr_thread->addr_mode = addr.Mode;
178     }
179     display_print();
180
181     if (!is_debug)
182     {
183         /* This is a real crash, dump some info */
184         be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0);
185         stack_info();
186         be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
187         stack_backtrace(dbg_curr_tid);
188     }
189     else
190     {
191         static char*        last_name;
192         static char*        last_file;
193
194         char                buffer[sizeof(SYMBOL_INFO) + 256];
195         SYMBOL_INFO*        si = (SYMBOL_INFO*)buffer;
196         void*               lin = memory_to_linear_addr(&addr);
197         DWORD64             disp64;
198         IMAGEHLP_LINE       il;
199         DWORD               disp;
200
201         si->SizeOfStruct = sizeof(*si);
202         si->MaxNameLen   = 256;
203         il.SizeOfStruct = sizeof(il);
204         if (SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si) &&
205             SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
206         {
207             if ((!last_name || strcmp(last_name, si->Name)) ||
208                 (!last_file || strcmp(last_file, il.FileName)))
209             {
210                 HeapFree(GetProcessHeap(), 0, last_name);
211                 HeapFree(GetProcessHeap(), 0, last_file);
212                 last_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(si->Name) + 1), si->Name);
213                 last_file = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(il.FileName) + 1), il.FileName);
214                 dbg_printf("%s () at %s:%ld\n", last_name, last_file, il.LineNumber);
215             }
216         }
217     }
218     if (!is_debug || is_break ||
219         dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
220         dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
221     {
222         ADDRESS64 tmp = addr;
223         /* Show where we crashed */
224         memory_disasm_one_insn(&tmp);
225     }
226     source_list_from_addr(&addr, 0);
227
228     return TRUE;
229 }
230
231 static void dbg_exception_epilog(void)
232 {
233     break_restart_execution(dbg_curr_thread->exec_count);
234     /*
235      * This will have gotten absorbed into the breakpoint info
236      * if it was used.  Otherwise it would have been ignored.
237      * In any case, we don't mess with it any more.
238      */
239     if (dbg_curr_thread->exec_mode == dbg_exec_cont)
240         dbg_curr_thread->exec_count = 0;
241     dbg_curr_thread->in_exception = FALSE;
242 }
243
244 static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance)
245 {
246     BOOL                is_debug = FALSE;
247     THREADNAME_INFO*    pThreadName;
248     struct dbg_thread*  pThread;
249
250     assert(dbg_curr_thread);
251
252     WINE_TRACE("exception=%lx first_chance=%c\n",
253                rec->ExceptionCode, first_chance ? 'Y' : 'N');
254
255     switch (rec->ExceptionCode)
256     {
257     case EXCEPTION_BREAKPOINT:
258     case EXCEPTION_SINGLE_STEP:
259         is_debug = TRUE;
260         break;
261     case EXCEPTION_NAME_THREAD:
262         pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
263         if (pThreadName->dwThreadID == -1)
264             pThread = dbg_curr_thread;
265         else
266             pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID);
267
268         if (dbg_read_memory(pThreadName->szName, pThread->name, 9))
269             dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
270                        pThread->tid, pThread->name);
271         return DBG_CONTINUE;
272     }
273
274     if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) &&
275         !(rec->ExceptionFlags & EH_STACK_INVALID))
276     {
277         /* pass exception to program except for debug exceptions */
278         return DBG_EXCEPTION_NOT_HANDLED;
279     }
280
281     if (!is_debug)
282     {
283         /* print some infos */
284         dbg_printf("%s: ",
285                    first_chance ? "First chance exception" : "Unhandled exception");
286         switch (rec->ExceptionCode)
287         {
288         case EXCEPTION_INT_DIVIDE_BY_ZERO:
289             dbg_printf("divide by zero");
290             break;
291         case EXCEPTION_INT_OVERFLOW:
292             dbg_printf("overflow");
293             break;
294         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
295             dbg_printf("array bounds");
296             break;
297         case EXCEPTION_ILLEGAL_INSTRUCTION:
298             dbg_printf("illegal instruction");
299             break;
300         case EXCEPTION_STACK_OVERFLOW:
301             dbg_printf("stack overflow");
302             break;
303         case EXCEPTION_PRIV_INSTRUCTION:
304             dbg_printf("privileged instruction");
305             break;
306         case EXCEPTION_ACCESS_VIOLATION:
307             if (rec->NumberParameters == 2)
308                 dbg_printf("page fault on %s access to 0x%08lx",
309                            rec->ExceptionInformation[0] ? "write" : "read",
310                            rec->ExceptionInformation[1]);
311             else
312                 dbg_printf("page fault");
313             break;
314         case EXCEPTION_DATATYPE_MISALIGNMENT:
315             dbg_printf("Alignment");
316             break;
317         case DBG_CONTROL_C:
318             dbg_printf("^C");
319             break;
320         case CONTROL_C_EXIT:
321             dbg_printf("^C");
322             break;
323         case STATUS_POSSIBLE_DEADLOCK:
324         {
325             ADDRESS64       addr;
326
327             addr.Mode   = AddrModeFlat;
328             addr.Offset = rec->ExceptionInformation[0];
329
330             dbg_printf("wait failed on critical section ");
331             print_address(&addr, FALSE);
332         }
333         if (!DBG_IVAR(BreakOnCritSectTimeOut))
334         {
335             dbg_printf("\n");
336             return DBG_EXCEPTION_NOT_HANDLED;
337         }
338         break;
339         case EXCEPTION_WINE_STUB:
340         {
341             char dll[32], name[64];
342             memory_get_string(dbg_curr_process,
343                               (void*)rec->ExceptionInformation[0], TRUE, FALSE,
344                               dll, sizeof(dll));
345             if (HIWORD(rec->ExceptionInformation[1]))
346                 memory_get_string(dbg_curr_process,
347                                   (void*)rec->ExceptionInformation[1], TRUE, FALSE,
348                                   name, sizeof(name));
349             else
350                 sprintf( name, "%ld", rec->ExceptionInformation[1] );
351             dbg_printf("unimplemented function %s.%s called", dll, name);
352         }
353         break;
354         case EXCEPTION_WINE_ASSERTION:
355             dbg_printf("assertion failed");
356             break;
357         case EXCEPTION_VM86_INTx:
358             dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
359             break;
360         case EXCEPTION_VM86_STI:
361             dbg_printf("sti in vm86 mode");
362             break;
363         case EXCEPTION_VM86_PICRETURN:
364             dbg_printf("PIC return in vm86 mode");
365             break;
366         case EXCEPTION_FLT_DENORMAL_OPERAND:
367             dbg_printf("denormal float operand");
368             break;
369         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
370             dbg_printf("divide by zero");
371             break;
372         case EXCEPTION_FLT_INEXACT_RESULT:
373             dbg_printf("inexact float result");
374             break;
375         case EXCEPTION_FLT_INVALID_OPERATION:
376             dbg_printf("invalid float operation");
377             break;
378         case EXCEPTION_FLT_OVERFLOW:
379             dbg_printf("floating pointer overflow");
380             break;
381         case EXCEPTION_FLT_UNDERFLOW:
382             dbg_printf("floating pointer underflow");
383             break;
384         case EXCEPTION_FLT_STACK_CHECK:
385             dbg_printf("floating point stack check");
386             break;
387         default:
388             dbg_printf("0x%08lx", rec->ExceptionCode);
389             break;
390         }
391     }
392     if( (rec->ExceptionFlags & EH_STACK_INVALID) ) {
393         dbg_printf( ", invalid program stack" );
394     }
395
396     if (dbg_exception_prolog(is_debug, rec))
397     {
398         dbg_interactiveP = TRUE;
399         return 0;
400     }
401     dbg_exception_epilog();
402
403     return DBG_CONTINUE;
404 }
405
406 static BOOL tgt_process_active_close_process(struct dbg_process* pcs, BOOL kill);
407
408 static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
409 {
410     char        buffer[256];
411     DWORD       cont = DBG_CONTINUE;
412
413     dbg_curr_pid = de->dwProcessId;
414     dbg_curr_tid = de->dwThreadId;
415
416     if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
417         dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
418     else
419         dbg_curr_thread = NULL;
420
421     switch (de->dwDebugEventCode)
422     {
423     case EXCEPTION_DEBUG_EVENT:
424         if (!dbg_curr_thread)
425         {
426             WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
427                      de->dwProcessId, de->dwThreadId);
428             break;
429         }
430
431         WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
432                    de->dwProcessId, de->dwThreadId,
433                    de->u.Exception.ExceptionRecord.ExceptionCode);
434
435         if (dbg_curr_process->continue_on_first_exception)
436         {
437             dbg_curr_process->continue_on_first_exception = FALSE;
438             if (!DBG_IVAR(BreakOnAttach)) break;
439         }
440         if (dbg_fetch_context())
441         {
442             cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
443                                         de->u.Exception.dwFirstChance);
444             if (cont && dbg_curr_thread)
445             {
446                 SetThreadContext(dbg_curr_thread->handle, &dbg_context);
447             }
448         }
449         break;
450
451     case CREATE_PROCESS_DEBUG_EVENT:
452         dbg_curr_process = dbg_add_process(&be_process_active_io, de->dwProcessId,
453                                            de->u.CreateProcessInfo.hProcess);
454         if (dbg_curr_process == NULL)
455         {
456             WINE_ERR("Couldn't create process\n");
457             break;
458         }
459         memory_get_string_indirect(dbg_curr_process,
460                                    de->u.CreateProcessInfo.lpImageName,
461                                    de->u.CreateProcessInfo.fUnicode,
462                                    buffer, sizeof(buffer));
463         if (!buffer[0]) strcpy(buffer, "<Debugged Process>");
464
465         WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
466                    de->dwProcessId, de->dwThreadId,
467                    buffer, de->u.CreateProcessInfo.lpImageName,
468                    (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress,
469                    de->u.CreateProcessInfo.dwDebugInfoFileOffset,
470                    de->u.CreateProcessInfo.nDebugInfoSize);
471         dbg_set_process_name(dbg_curr_process, buffer);
472
473         if (!SymInitialize(dbg_curr_process->handle, NULL, TRUE))
474             dbg_printf("Couldn't initiate DbgHelp\n");
475
476         WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
477                    de->dwProcessId, de->dwThreadId,
478                    (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress);
479
480         dbg_curr_thread = dbg_add_thread(dbg_curr_process,
481                                          de->dwThreadId,
482                                          de->u.CreateProcessInfo.hThread,
483                                          de->u.CreateProcessInfo.lpThreadLocalBase);
484         if (!dbg_curr_thread)
485         {
486             WINE_ERR("Couldn't create thread\n");
487             break;
488         }
489         dbg_init_current_process();
490         dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
491         break;
492
493     case EXIT_PROCESS_DEBUG_EVENT:
494         WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
495                    de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
496
497         if (dbg_curr_process == NULL)
498         {
499             WINE_ERR("Unknown process\n");
500             break;
501         }
502         tgt_process_active_close_process(dbg_curr_process, FALSE);
503         dbg_printf("Process of pid=0x%08lx has terminated\n", de->dwProcessId);
504         break;
505
506     case CREATE_THREAD_DEBUG_EVENT:
507         WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
508                    de->dwProcessId, de->dwThreadId,
509                    (unsigned long)(void*)de->u.CreateThread.lpStartAddress);
510
511         if (dbg_curr_process == NULL)
512         {
513             WINE_ERR("Unknown process\n");
514             break;
515         }
516         if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
517         {
518             WINE_TRACE("Thread already listed, skipping\n");
519             break;
520         }
521
522         dbg_curr_thread = dbg_add_thread(dbg_curr_process,
523                                          de->dwThreadId,
524                                          de->u.CreateThread.hThread,
525                                          de->u.CreateThread.lpThreadLocalBase);
526         if (!dbg_curr_thread)
527         {
528             WINE_ERR("Couldn't create thread\n");
529             break;
530         }
531         dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
532         break;
533
534     case EXIT_THREAD_DEBUG_EVENT:
535         WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
536                    de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
537
538         if (dbg_curr_thread == NULL)
539         {
540             WINE_ERR("Unknown thread\n");
541             break;
542         }
543         /* FIXME: remove break point set on thread startup */
544         dbg_del_thread(dbg_curr_thread);
545         break;
546
547     case LOAD_DLL_DEBUG_EVENT:
548         if (dbg_curr_thread == NULL)
549         {
550             WINE_ERR("Unknown thread\n");
551             break;
552         }
553         memory_get_string_indirect(dbg_curr_process, 
554                                    de->u.LoadDll.lpImageName,
555                                    de->u.LoadDll.fUnicode,
556                                    buffer, sizeof(buffer));
557
558         WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
559                    de->dwProcessId, de->dwThreadId,
560                    buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
561                    de->u.LoadDll.dwDebugInfoFileOffset,
562                    de->u.LoadDll.nDebugInfoSize);
563         SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL,
564                       (unsigned long)de->u.LoadDll.lpBaseOfDll, 0);
565         break_set_xpoints(FALSE);
566         break_check_delayed_bp();
567         break_set_xpoints(TRUE);
568         if (DBG_IVAR(BreakOnDllLoad))
569         {
570             dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
571                        buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
572             if (dbg_fetch_context()) cont = 0;
573         }
574         break;
575
576     case UNLOAD_DLL_DEBUG_EVENT:
577         WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", 
578                    de->dwProcessId, de->dwThreadId,
579                    (unsigned long)de->u.UnloadDll.lpBaseOfDll);
580         break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
581         SymUnloadModule(dbg_curr_process->handle, 
582                         (unsigned long)de->u.UnloadDll.lpBaseOfDll);
583         break;
584
585     case OUTPUT_DEBUG_STRING_EVENT:
586         if (dbg_curr_thread == NULL)
587         {
588             WINE_ERR("Unknown thread\n");
589             break;
590         }
591
592         memory_get_string(dbg_curr_process,
593                           de->u.DebugString.lpDebugStringData, TRUE,
594                           de->u.DebugString.fUnicode, buffer, sizeof(buffer));
595         WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
596                    de->dwProcessId, de->dwThreadId, buffer);
597         break;
598
599     case RIP_EVENT:
600         WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
601                    de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
602                    de->u.RipInfo.dwType);
603         break;
604
605     default:
606         WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
607                    de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
608     }
609     if (!cont) return TRUE;  /* stop execution */
610     ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
611     return FALSE;  /* continue execution */
612 }
613
614 static void dbg_resume_debuggee(DWORD cont)
615 {
616     if (dbg_curr_thread->in_exception)
617     {
618         ADDRESS64       addr;
619         char            hexbuf[MAX_OFFSET_TO_STR_LEN];
620
621         dbg_exception_epilog();
622         memory_get_current_pc(&addr);
623         WINE_TRACE("Exiting debugger      PC=%s mode=%d count=%d\n",
624                    memory_offset_to_string(hexbuf, addr.Offset, 0),
625                    dbg_curr_thread->exec_mode,
626                    dbg_curr_thread->exec_count);
627         if (dbg_curr_thread)
628         {
629             if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
630                 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
631         }
632     }
633     dbg_interactiveP = FALSE;
634     if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont))
635         dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont);
636 }
637
638 void dbg_wait_next_exception(DWORD cont, int count, int mode)
639 {
640     DEBUG_EVENT         de;
641     ADDRESS64           addr;
642     char                hexbuf[MAX_OFFSET_TO_STR_LEN];
643
644     if (cont == DBG_CONTINUE)
645     {
646         dbg_curr_thread->exec_count = count;
647         dbg_curr_thread->exec_mode = mode;
648     }
649     dbg_resume_debuggee(cont);
650
651     while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
652     {
653         if (dbg_handle_debug_event(&de)) break;
654     }
655     if (!dbg_curr_process) return;
656     dbg_interactiveP = TRUE;
657
658     memory_get_current_pc(&addr);
659     WINE_TRACE("Entering debugger     PC=%s mode=%d count=%d\n",
660                memory_offset_to_string(hexbuf, addr.Offset, 0),
661                dbg_curr_thread->exec_mode,
662                dbg_curr_thread->exec_count);
663 }
664
665 static void     dbg_wait_for_first_exception(void)
666 {
667     DEBUG_EVENT         de;
668
669     if (dbg_curr_process)
670         dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid);
671
672     /* wait for first exception */
673     while (WaitForDebugEvent(&de, INFINITE))
674     {
675         if (dbg_handle_debug_event(&de)) break;
676     }
677 }
678
679 static  unsigned dbg_start_debuggee(LPSTR cmdLine)
680 {
681     PROCESS_INFORMATION info;
682     STARTUPINFOA        startup;
683
684     memset(&startup, 0, sizeof(startup));
685     startup.cb = sizeof(startup);
686     startup.dwFlags = STARTF_USESHOWWINDOW;
687     startup.wShowWindow = SW_SHOWNORMAL;
688
689     /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
690      * while GUI:s don't
691      */
692     if (!CreateProcess(NULL, cmdLine, NULL, NULL,
693                        FALSE, 
694                        DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
695                        NULL, NULL, &startup, &info))
696     {
697         dbg_printf("Couldn't start process '%s'\n", cmdLine);
698         return FALSE;
699     }
700     if (!info.dwProcessId)
701     {
702         /* this happens when the program being run is not a Wine binary
703          * (for example, a shell wrapper around a WineLib app)
704          */
705         /* Current fix: list running processes and let the user attach
706          * to one of them (sic)
707          * FIXME: implement a real fix => grab the process (from the
708          * running processes) from its name
709          */
710         dbg_printf("Debuggee has been started (%s)\n"
711                    "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
712                    "Try to attach to one of those processes:\n", cmdLine);
713         /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
714         Sleep(100);
715         info_win32_processes();
716         return TRUE;
717     }
718     dbg_curr_pid = info.dwProcessId;
719     if (!(dbg_curr_process = dbg_add_process(&be_process_active_io, dbg_curr_pid, 0))) return FALSE;
720     dbg_wait_for_first_exception();
721
722     return TRUE;
723 }
724
725 void    dbg_run_debuggee(const char* args)
726 {
727     if (args)
728     {
729         WINE_FIXME("Re-running current program with %s as args is broken\n", args);
730         return;
731     }
732     else 
733     {
734         DEBUG_EVENT     de;
735
736         if (!dbg_last_cmd_line)
737         {
738             dbg_printf("Cannot find previously used command line.\n");
739             return;
740         }
741         dbg_start_debuggee(dbg_last_cmd_line);
742         while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
743         {
744             if (dbg_handle_debug_event(&de)) break;
745         }
746         source_list_from_addr(NULL, 0);
747     }
748 }
749
750 static BOOL     str2int(const char* str, DWORD* val)
751 {
752     char*   ptr;
753
754     *val = strtol(str, &ptr, 10);
755     return str < ptr && !*ptr;
756 }
757
758
759 /******************************************************************
760  *              dbg_active_attach
761  *
762  * Tries to attach to a running process
763  * Handles the <pid> or <pid> <evt> forms
764  */
765 enum dbg_start  dbg_active_attach(int argc, char* argv[])
766 {
767     DWORD       pid, evt;
768
769     /* try the form <myself> pid */
770     if (argc == 1 && str2int(argv[0], &pid) && pid != 0)
771     {
772         if (!dbg_attach_debuggee(pid, FALSE, FALSE))
773             return start_error_init;
774     }
775     /* try the form <myself> pid evt (Win32 JIT debugger) */
776     else if (argc == 2 && str2int(argv[0], &pid) && pid != 0 &&
777              str2int(argv[1], &evt) && evt != 0)
778     {
779         if (!dbg_attach_debuggee(pid, TRUE, FALSE))
780         {
781             /* don't care about result */
782             SetEvent((HANDLE)evt);
783             return start_error_init;
784         }
785         if (!SetEvent((HANDLE)evt))
786         {
787             WINE_ERR("Invalid event handle: %lx\n", evt);
788             return start_error_init;
789         }
790         CloseHandle((HANDLE)evt);
791     }
792     else return start_error_parse;
793
794     dbg_curr_pid = pid;
795     dbg_wait_for_first_exception();
796     return start_ok;
797 }
798
799 /******************************************************************
800  *              dbg_active_launch
801  *
802  * Launches a debuggee (with its arguments) from argc/argv
803  */
804 enum dbg_start    dbg_active_launch(int argc, char* argv[])
805 {
806     int         i, len;
807     LPSTR       cmd_line;
808
809     if (argc == 0) return start_error_parse;
810
811     if (!(cmd_line = HeapAlloc(GetProcessHeap(), 0, len = 1)))
812     {
813     oom_leave:
814         dbg_printf("Out of memory\n");
815         return start_error_init;
816     }
817     cmd_line[0] = '\0';
818
819     for (i = 0; i < argc; i++)
820     {
821         len += strlen(argv[i]) + 1;
822         if (!(cmd_line = HeapReAlloc(GetProcessHeap(), 0, cmd_line, len)))
823             goto oom_leave;
824         strcat(cmd_line, argv[i]);
825         cmd_line[len - 2] = ' ';
826         cmd_line[len - 1] = '\0';
827     }
828
829     if (!dbg_start_debuggee(cmd_line))
830     {
831         HeapFree(GetProcessHeap(), 0, cmd_line);
832         return start_error_init;
833     }
834     HeapFree(GetProcessHeap(), 0, dbg_last_cmd_line);
835     dbg_last_cmd_line = cmd_line;
836     return start_ok;
837 }
838
839 /******************************************************************
840  *              dbg_active_auto
841  *
842  * Starts (<pid> or <pid> <evt>) in automatic mode
843  */
844 enum dbg_start dbg_active_auto(int argc, char* argv[])
845 {
846     HANDLE              hFile;
847     enum dbg_start      ds = start_error_parse;
848
849     if (!strcmp(argv[0], "--auto"))
850     {
851         /* auto mode */
852         argc--; argv++;
853         ds = dbg_active_attach(argc, argv);
854         if (ds != start_ok) return ds;
855         hFile = parser_generate_command_file("echo Modules:", "info share",
856                                              "echo Threads:", "info threads",
857                                              NULL);
858     }
859     else if (!strcmp(argv[0], "--minidump"))
860     {
861         const char*     file = NULL;
862         char            tmp[8 + 1 + MAX_PATH]; /* minidump <file> */
863
864         argc--; argv++;
865         /* hard stuff now ; we can get things like:
866          * --minidump <pid>                     1 arg
867          * --minidump <pid> <evt>               2 args
868          * --minidump <file> <pid>              2 args
869          * --minidump <file> <pid> <evt>        3 args
870          */
871         switch (argc)
872         {
873         case 1:
874             ds = dbg_active_attach(argc, argv);
875             break;
876         case 2:
877             if ((ds = dbg_active_attach(argc, argv)) != start_ok)
878             {
879                 file = argv[0];
880                 ds = dbg_active_attach(argc - 1, argv + 1);
881             }
882             break;
883         case 3:
884             file = argv[0];
885             ds = dbg_active_attach(argc - 1, argv + 1);
886             break;
887         default:
888             return start_error_parse;
889         }
890         if (ds != start_ok) return ds;
891         memcpy(tmp, "minidump \"", 10);
892         if (!file)
893         {
894             char        path[MAX_PATH];
895
896             GetTempPath(sizeof(path), path);
897             GetTempFileName(path, "WD", 0, tmp + 10);
898         }
899         else strcpy(tmp + 10, file);
900         strcat(tmp, "\"");
901         if (!file)
902         {
903             /* FIXME: should generate unix name as well */
904             dbg_printf("Capturing program state in %s\n", tmp + 9);
905         }
906         hFile = parser_generate_command_file(tmp, NULL);
907     }
908     else return start_error_parse;
909     if (hFile == INVALID_HANDLE_VALUE) return start_error_parse;
910
911     dbg_interactiveP = TRUE;
912     parser_handle(hFile);
913
914     return start_ok;
915 }
916
917 static BOOL tgt_process_active_close_process(struct dbg_process* pcs, BOOL kill)
918 {
919     if (pcs == dbg_curr_process)
920     {
921         /* remove all set breakpoints in debuggee code */
922         break_set_xpoints(FALSE);
923         /* needed for single stepping (ugly).
924          * should this be handled inside the server ??? 
925          */
926         be_cpu->single_step(&dbg_context, FALSE);
927         if (dbg_curr_thread->in_exception)
928         {
929             SetThreadContext(dbg_curr_thread->handle, &dbg_context);
930             ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, DBG_CONTINUE);
931         }
932         if (!kill && !DebugActiveProcessStop(dbg_curr_pid)) return FALSE;
933     }
934     SymCleanup(pcs->handle);
935     dbg_del_process(pcs);
936
937     return TRUE;
938 }
939
940 static struct be_process_io be_process_active_io =
941 {
942     tgt_process_active_close_process,
943     ReadProcessMemory,
944     WriteProcessMemory,
945 };