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