winecfg: Update German resource.
[wine] / programs / winedbg / winedbg.c
1 /* Wine internal debugger
2  * Interface to Windows debugger API
3  * Copyright 2000-2004 Eric Pouech
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "debugger.h"
27
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "wine/library.h"
31
32 #include "wine/debug.h"
33
34 /* TODO list:
35  *
36  * - minidump
37  *      + allow winedbg in automatic mode to create a minidump (or add another option
38  *        for that)
39  *      + set a mode where winedbg would start (postmortem debugging) from a minidump
40  * - CPU adherence
41  *      + we always assume the stack grows as on i386 (ie downwards)
42  * - UI
43  *      + enable back the limited output (depth of structure printing and number of 
44  *        lines)
45  *      + make the output as close as possible to what gdb does
46  * - symbol management:
47  *      + symbol table loading is broken
48  *      + in symbol_get_lvalue, we don't do any scoping (as C does) between local and
49  *        global vars (we may need this to force some display for example). A solution
50  *        would be always to return arrays with: local vars, global vars, thunks
51  * - type management:
52  *      + some bits of internal types are missing (like type casts and the address
53  *        operator)
54  *      + the type for an enum's value is always inferred as int (winedbg & dbghelp)
55  *      + most of the code implies that sizeof(void*) = sizeof(int)
56  *      + all computations should be made on long long
57  *              o expr computations are in int:s
58  *              o bitfield size is on a 4-bytes
59  *      + array_index and deref should be the same function (or should share the same
60  *        core)
61  *      + segmented pointers are not correctly handled (and are hacked throughout the
62  *        code by testing against itype_none)
63  * - execution:
64  *      + set a better fix for gdb (proxy mode) than the step-mode hack
65  *      + implement function call in debuggee
66  *      + trampoline management is broken when getting 16 <=> 32 thunk destination
67  *        address
68  *      + thunking of delayed imports doesn't work as expected (ie, when stepping,
69  *        it currently stops at first insn with line number during the library 
70  *        loading). We should identify this (__wine_delay_import) and set a
71  *        breakpoint instead of single stepping the library loading.
72  *      + it's wrong to copy thread->step_over_bp into process->bp[0] (when 
73  *        we have a multi-thread debuggee). complete fix must include storing all
74  *        thread's step-over bp in process-wide bp array, and not to handle bp
75  *        when we have the wrong thread running into that bp
76  *      + code in CREATE_PROCESS debug event doesn't work on Windows, as we cannot
77  *        get the name of the main module this way. We should rewrite all this code
78  *        and store in struct dbg_process as early as possible (before process
79  *        creation or attachment), the name of the main module
80  * - global:
81  *      + define a better way to enable the wine extensions (either DBG SDK function
82  *        in dbghelp, or TLS variable, or environment variable or ...)
83  *      + audit all files to ensure that we check all potential return values from
84  *        every function call to catch the errors
85  *      + BTW check also whether the exception mechanism is the best way to return
86  *        errors (or find a proper fix for MinGW port)
87  *      + use Wine standard list mechanism for all list handling
88  */
89
90 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
91
92 struct dbg_process*     dbg_curr_process = NULL;
93 struct dbg_thread*      dbg_curr_thread = NULL;
94 DWORD                   dbg_curr_tid;
95 DWORD                   dbg_curr_pid;
96 CONTEXT                 dbg_context;
97 BOOL                    dbg_interactiveP = FALSE;
98 static char*            dbg_last_cmd_line = NULL;
99
100 static struct dbg_process*      dbg_process_list = NULL;
101 static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} dbg_action_mode;
102
103 struct dbg_internal_var         dbg_internal_vars[DBG_IV_LAST];
104 const struct dbg_internal_var*  dbg_context_vars;
105 static HANDLE                   dbg_houtput;
106
107 void    dbg_outputA(const char* buffer, int len)
108 {
109     static char line_buff[4096];
110     static unsigned int line_pos;
111
112     DWORD w, i;
113
114     while (len > 0)
115     {
116         unsigned int count = min( len, sizeof(line_buff) - line_pos );
117         memcpy( line_buff + line_pos, buffer, count );
118         buffer += count;
119         len -= count;
120         line_pos += count;
121         for (i = line_pos; i > 0; i--) if (line_buff[i-1] == '\n') break;
122         if (!i)  /* no newline found */
123         {
124             if (len > 0) i = line_pos;  /* buffer is full, flush anyway */
125             else break;
126         }
127         WriteFile(dbg_houtput, line_buff, i, &w, NULL);
128         memmove( line_buff, line_buff + i, line_pos - i );
129         line_pos -= i;
130     }
131 }
132
133 void    dbg_outputW(const WCHAR* buffer, int len)
134 {
135     char* ansi = NULL;
136     int newlen;
137         
138     /* do a serious Unicode to ANSI conversion
139      * FIXME: should CP_ACP be GetConsoleCP()?
140      */
141     newlen = WideCharToMultiByte(CP_ACP, 0, buffer, len, NULL, 0, NULL, NULL);
142     if (newlen)
143     {
144         if (!(ansi = HeapAlloc(GetProcessHeap(), 0, newlen))) return;
145         WideCharToMultiByte(CP_ACP, 0, buffer, len, ansi, newlen, NULL, NULL);
146         dbg_outputA(ansi, newlen);
147         HeapFree(GetProcessHeap(), 0, ansi);
148     }
149 }
150
151 int     dbg_printf(const char* format, ...)
152 {
153     static    char      buf[4*1024];
154     va_list     valist;
155     int         len;
156
157     va_start(valist, format);
158     len = vsnprintf(buf, sizeof(buf), format, valist);
159     va_end(valist);
160
161     if (len <= -1 || len >= sizeof(buf)) 
162     {
163         len = sizeof(buf) - 1;
164         buf[len] = 0;
165         buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
166     }
167     dbg_outputA(buf, len);
168     return len;
169 }
170
171 static  unsigned dbg_load_internal_vars(void)
172 {
173     HKEY                        hkey;
174     DWORD                       type = REG_DWORD;
175     DWORD                       val;
176     DWORD                       count = sizeof(val);
177     int                         i;
178     struct dbg_internal_var*    div = dbg_internal_vars;
179
180 /* initializes internal vars table */
181 #define  INTERNAL_VAR(_var,_val,_ref,_tid)                      \
182         div->val = _val; div->name = #_var; div->pval = _ref;   \
183         div->typeid = _tid; div++;
184 #include "intvar.h"
185 #undef   INTERNAL_VAR
186
187     /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
188     if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) 
189     {
190         WINE_ERR("Cannot create WineDbg key in registry\n");
191         return FALSE;
192     }
193
194     for (i = 0; i < DBG_IV_LAST; i++) 
195     {
196         if (!dbg_internal_vars[i].pval) 
197         {
198             if (!RegQueryValueEx(hkey, dbg_internal_vars[i].name, 0,
199                                  &type, (LPBYTE)&val, &count))
200                 dbg_internal_vars[i].val = val;
201             dbg_internal_vars[i].pval = &dbg_internal_vars[i].val;
202         }
203     }
204     RegCloseKey(hkey);
205     /* set up the debug variables for the CPU context */
206     dbg_context_vars = be_cpu->init_registers(&dbg_context);
207     return TRUE;
208 }
209
210 static  unsigned dbg_save_internal_vars(void)
211 {
212     HKEY                        hkey;
213     int                         i;
214
215     /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
216     if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) 
217     {
218         WINE_ERR("Cannot create WineDbg key in registry\n");
219         return FALSE;
220     }
221
222     for (i = 0; i < DBG_IV_LAST; i++) 
223     {
224         /* FIXME: type should be infered from basic type -if any- of intvar */
225         if (dbg_internal_vars[i].pval == &dbg_internal_vars[i].val)
226             RegSetValueEx(hkey, dbg_internal_vars[i].name, 0,
227                           REG_DWORD, (const void*)dbg_internal_vars[i].pval, 
228                           sizeof(*dbg_internal_vars[i].pval));
229     }
230     RegCloseKey(hkey);
231     return TRUE;
232 }
233
234 const struct dbg_internal_var* dbg_get_internal_var(const char* name)
235 {
236     const struct dbg_internal_var*      div;
237
238     for (div = &dbg_internal_vars[DBG_IV_LAST - 1]; div >= dbg_internal_vars; div--)
239     {
240         if (!strcmp(div->name, name)) return div;
241     }
242     for (div = dbg_context_vars; div->name; div++)
243     {
244         if (!strcasecmp(div->name, name)) return div;
245     }
246
247     return NULL;
248 }
249
250 struct dbg_process*     dbg_get_process(DWORD pid)
251 {
252     struct dbg_process* p;
253
254     for (p = dbg_process_list; p; p = p->next)
255         if (p->pid == pid) break;
256     return p;
257 }
258
259 struct dbg_process*     dbg_add_process(DWORD pid, HANDLE h)
260 {
261     /* FIXME: temporary */
262     extern struct be_process_io be_process_active_io;
263
264     struct dbg_process* p;
265
266     if ((p = dbg_get_process(pid)))
267     {
268         if (p->handle != 0)
269         {
270             WINE_ERR("Process (%lu) is already defined\n", pid);
271         }
272         else
273         {
274             p->handle = h;
275             p->imageName = NULL;
276         }
277         return p;
278     }
279
280     if (!(p = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process)))) return NULL;
281     p->handle = h;
282     p->pid = pid;
283     p->process_io = &be_process_active_io;
284     p->imageName = NULL;
285     p->threads = NULL;
286     p->continue_on_first_exception = FALSE;
287     p->next_bp = 1;  /* breakpoint 0 is reserved for step-over */
288     memset(p->bp, 0, sizeof(p->bp));
289     p->delayed_bp = NULL;
290     p->num_delayed_bp = 0;
291
292     p->next = dbg_process_list;
293     p->prev = NULL;
294     if (dbg_process_list) dbg_process_list->prev = p;
295     dbg_process_list = p;
296     return p;
297 }
298
299 void dbg_set_process_name(struct dbg_process* p, const char* imageName)
300 {
301     assert(p->imageName == NULL);
302     if (imageName)
303     {
304         char* tmp = HeapAlloc(GetProcessHeap(), 0, strlen(imageName) + 1);
305         if (tmp) p->imageName = strcpy(tmp, imageName);
306     }
307 }
308
309 void dbg_del_process(struct dbg_process* p)
310 {
311     int i;
312
313     while (p->threads) dbg_del_thread(p->threads);
314
315     for (i = 0; i < p->num_delayed_bp; i++)
316         if (p->delayed_bp[i].is_symbol)
317             HeapFree(GetProcessHeap(), 0, p->delayed_bp[i].u.symbol.name);
318
319     HeapFree(GetProcessHeap(), 0, p->delayed_bp);
320     if (p->prev) p->prev->next = p->next;
321     if (p->next) p->next->prev = p->prev;
322     if (p == dbg_process_list) dbg_process_list = p->next;
323     if (p == dbg_curr_process) dbg_curr_process = NULL;
324     HeapFree(GetProcessHeap(), 0, (char*)p->imageName);
325     HeapFree(GetProcessHeap(), 0, p);
326 }
327
328 static void dbg_init_current_process(void)
329 {
330 }
331
332 struct mod_loader_info
333 {
334     HANDLE              handle;
335     IMAGEHLP_MODULE*    imh_mod;
336 };
337
338 static BOOL CALLBACK mod_loader_cb(PSTR mod_name, DWORD base, void* ctx)
339 {
340     struct mod_loader_info*     mli = (struct mod_loader_info*)ctx;
341
342     if (!strcmp(mod_name, "<wine-loader>"))
343     {
344         if (SymGetModuleInfo(mli->handle, base, mli->imh_mod))
345             return FALSE; /* stop enum */
346     }
347     return TRUE;
348 }
349
350 BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod)
351 {
352     struct mod_loader_info  mli;
353     DWORD                   opt;
354
355     /* this will resynchronize builtin dbghelp's internal ELF module list */
356     SymLoadModule(hProcess, 0, 0, 0, 0, 0);
357     mli.handle  = hProcess;
358     mli.imh_mod = imh_mod;
359     imh_mod->SizeOfStruct = sizeof(*imh_mod);
360     imh_mod->BaseOfImage = 0;
361     /* this is a wine specific options to return also ELF modules in the
362      * enumeration
363      */
364     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
365     SymEnumerateModules(hProcess, mod_loader_cb, (void*)&mli);
366     SymSetOptions(opt);
367
368     return imh_mod->BaseOfImage != 0;
369 }
370
371 struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid)
372 {
373     struct dbg_thread*  t;
374
375     if (!p) return NULL;
376     for (t = p->threads; t; t = t->next)
377         if (t->tid == tid) break;
378     return t;
379 }
380
381 struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
382                                   HANDLE h, void* teb)
383 {
384     struct dbg_thread*  t = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread));
385
386     if (!t)
387         return NULL;
388
389     t->handle = h;
390     t->tid = tid;
391     t->teb = teb;
392     t->process = p;
393     t->exec_mode = dbg_exec_cont;
394     t->exec_count = 0;
395     t->step_over_bp.enabled = FALSE;
396     t->step_over_bp.refcount = 0;
397     t->in_exception = FALSE;
398     t->frames = NULL;
399     t->num_frames = 0;
400     t->curr_frame = -1;
401
402     snprintf(t->name, sizeof(t->name), "0x%08lx", tid);
403
404     t->next = p->threads;
405     t->prev = NULL;
406     if (p->threads) p->threads->prev = t;
407     p->threads = t;
408
409     return t;
410 }
411
412 static void dbg_init_current_thread(void* start)
413 {
414     if (start)
415     {
416         if (dbg_curr_process->threads && 
417             !dbg_curr_process->threads->next && /* first thread ? */
418             DBG_IVAR(BreakAllThreadsStartup)) 
419         {
420             ADDRESS     addr;
421
422             break_set_xpoints(FALSE);
423             addr.Mode   = AddrModeFlat;
424             addr.Offset = (DWORD)start;
425             break_add_break(&addr, TRUE);
426             break_set_xpoints(TRUE);
427         }
428     } 
429 }
430
431 void dbg_del_thread(struct dbg_thread* t)
432 {
433     HeapFree(GetProcessHeap(), 0, t->frames);
434     if (t->prev) t->prev->next = t->next;
435     if (t->next) t->next->prev = t->prev;
436     if (t == t->process->threads) t->process->threads = t->next;
437     if (t == dbg_curr_thread) dbg_curr_thread = NULL;
438     HeapFree(GetProcessHeap(), 0, t);
439 }
440
441 static unsigned dbg_handle_debug_event(DEBUG_EVENT* de);
442
443 /******************************************************************
444  *              dbg_attach_debuggee
445  *
446  * Sets the debuggee to <pid>
447  * cofe instructs winedbg what to do when first exception is received 
448  * (break=FALSE, continue=TRUE)
449  * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events
450  * until the first exception is received (aka: attach to an already running process)
451  */
452 BOOL dbg_attach_debuggee(DWORD pid, BOOL cofe, BOOL wfe)
453 {
454     DEBUG_EVENT         de;
455
456     if (!(dbg_curr_process = dbg_add_process(pid, 0))) return FALSE;
457
458     if (!DebugActiveProcess(pid)) 
459     {
460         dbg_printf("Can't attach process %lx: error %ld\n", pid, GetLastError());
461         dbg_del_process(dbg_curr_process);
462         return FALSE;
463     }
464     dbg_curr_process->continue_on_first_exception = cofe;
465
466     if (wfe) /* shall we proceed all debug events until we get an exception ? */
467     {
468         dbg_interactiveP = FALSE;
469         while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
470         {
471             if (dbg_handle_debug_event(&de)) break;
472         }
473         if (dbg_curr_process) dbg_interactiveP = TRUE;
474     }
475     return TRUE;
476 }
477
478 BOOL dbg_detach_debuggee(void)
479 {
480     /* remove all set breakpoints in debuggee code */
481     break_set_xpoints(FALSE);
482     /* needed for single stepping (ugly).
483      * should this be handled inside the server ??? 
484      */
485     be_cpu->single_step(&dbg_context, FALSE);
486     SetThreadContext(dbg_curr_thread->handle, &dbg_context);
487     if (dbg_curr_thread->in_exception)
488         ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, DBG_CONTINUE);
489     if (!DebugActiveProcessStop(dbg_curr_pid)) return FALSE;
490     dbg_del_process(dbg_curr_process);
491
492     return TRUE;
493 }
494
495 static unsigned dbg_fetch_context(void)
496 {
497     dbg_context.ContextFlags = CONTEXT_CONTROL
498         | CONTEXT_INTEGER
499 #ifdef CONTEXT_SEGMENTS
500         | CONTEXT_SEGMENTS
501 #endif
502 #ifdef CONTEXT_DEBUG_REGISTERS
503         | CONTEXT_DEBUG_REGISTERS
504 #endif
505         ;
506     if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context))
507     {
508         WINE_WARN("Can't get thread's context\n");
509         return FALSE;
510     }
511     return TRUE;
512 }
513
514 static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
515 {
516     ADDRESS     addr;
517     BOOL        is_break;
518
519     memory_get_current_pc(&addr);
520     break_suspend_execution();
521     dbg_curr_thread->excpt_record = *rec;
522     dbg_curr_thread->in_exception = TRUE;
523
524     if (!is_debug)
525     {
526         switch (addr.Mode)
527         {
528         case AddrModeFlat: dbg_printf(" in 32-bit code (0x%08lx)", addr.Offset); break;
529         case AddrModeReal: dbg_printf(" in vm86 code (%04x:%04lx)", addr.Segment, addr.Offset); break;
530         case AddrMode1616: dbg_printf(" in 16-bit code (%04x:%04lx)", addr.Segment, addr.Offset); break;
531         case AddrMode1632: dbg_printf(" in 32-bit code (%04x:%08lx)", addr.Segment, addr.Offset); break;
532         default: dbg_printf(" bad address");
533         }
534         dbg_printf(".\n");
535     }
536
537     /* this will resynchronize builtin dbghelp's internal ELF module list */
538     SymLoadModule(dbg_curr_process->handle, 0, 0, 0, 0, 0);
539
540     /*
541      * Do a quiet backtrace so that we have an idea of what the situation
542      * is WRT the source files.
543      */
544     stack_fetch_frames();
545     if (is_debug &&
546         break_should_continue(&addr, rec->ExceptionCode, &dbg_curr_thread->exec_count, &is_break))
547         return FALSE;
548
549     if (addr.Mode != dbg_curr_thread->addr_mode)
550     {
551         const char* name = NULL;
552         
553         switch (addr.Mode)
554         {
555         case AddrMode1616: name = "16 bit";     break;
556         case AddrMode1632: name = "32 bit";     break;
557         case AddrModeReal: name = "vm86";       break;
558         case AddrModeFlat: name = "32 bit";     break;
559         }
560         
561         dbg_printf("In %s mode.\n", name);
562         dbg_curr_thread->addr_mode = addr.Mode;
563     }
564     display_print();
565
566     if (!is_debug)
567     {
568         /* This is a real crash, dump some info */
569         be_cpu->print_context(dbg_curr_thread->handle, &dbg_context);
570         stack_info();
571         be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
572         stack_backtrace(dbg_curr_tid);
573     }
574     else
575     {
576         static char*        last_name;
577         static char*        last_file;
578
579         char                buffer[sizeof(SYMBOL_INFO) + 256];
580         SYMBOL_INFO*        si = (SYMBOL_INFO*)buffer;
581         void*               lin = memory_to_linear_addr(&addr);
582         DWORD64             disp64;
583         IMAGEHLP_LINE       il;
584         DWORD               disp;
585
586         si->SizeOfStruct = sizeof(*si);
587         si->MaxNameLen   = 256;
588         il.SizeOfStruct = sizeof(il);
589         if (SymFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp64, si) &&
590             SymGetLineFromAddr(dbg_curr_process->handle, (DWORD_PTR)lin, &disp, &il))
591         {
592             if ((!last_name || strcmp(last_name, si->Name)) ||
593                 (!last_file || strcmp(last_file, il.FileName)))
594             {
595                 HeapFree(GetProcessHeap(), 0, last_name);
596                 HeapFree(GetProcessHeap(), 0, last_file);
597                 last_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(si->Name) + 1), si->Name);
598                 last_file = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(il.FileName) + 1), il.FileName);
599                 dbg_printf("%s () at %s:%ld\n", last_name, last_file, il.LineNumber);
600             }
601         }
602     }
603     if (!is_debug || is_break ||
604         dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
605         dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
606     {
607         ADDRESS tmp = addr;
608         /* Show where we crashed */
609         memory_disasm_one_insn(&tmp);
610     }
611     source_list_from_addr(&addr, 0);
612
613     return TRUE;
614 }
615
616 static void dbg_exception_epilog(void)
617 {
618     break_restart_execution(dbg_curr_thread->exec_count);
619     /*
620      * This will have gotten absorbed into the breakpoint info
621      * if it was used.  Otherwise it would have been ignored.
622      * In any case, we don't mess with it any more.
623      */
624     if (dbg_curr_thread->exec_mode == dbg_exec_cont)
625         dbg_curr_thread->exec_count = 0;
626     dbg_curr_thread->in_exception = FALSE;
627 }
628
629 static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance)
630 {
631     BOOL                is_debug = FALSE;
632     THREADNAME_INFO*    pThreadName;
633     struct dbg_thread*  pThread;
634
635     assert(dbg_curr_thread);
636
637     WINE_TRACE("exception=%lx first_chance=%c\n",
638                rec->ExceptionCode, first_chance ? 'Y' : 'N');
639
640     switch (rec->ExceptionCode)
641     {
642     case EXCEPTION_BREAKPOINT:
643     case EXCEPTION_SINGLE_STEP:
644         is_debug = TRUE;
645         break;
646     case EXCEPTION_NAME_THREAD:
647         pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
648         if (pThreadName->dwThreadID == -1)
649             pThread = dbg_curr_thread;
650         else
651             pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID);
652
653         if (dbg_read_memory(pThreadName->szName, pThread->name, 9))
654             dbg_printf("Thread ID=0x%lx renamed using MS VC6 extension (name==\"%s\")\n",
655                        pThread->tid, pThread->name);
656         return DBG_CONTINUE;
657     }
658
659     if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) &&
660         !(rec->ExceptionFlags & EH_STACK_INVALID))
661     {
662         /* pass exception to program except for debug exceptions */
663         return DBG_EXCEPTION_NOT_HANDLED;
664     }
665
666     if (!is_debug)
667     {
668         /* print some infos */
669         dbg_printf("%s: ",
670                    first_chance ? "First chance exception" : "Unhandled exception");
671         switch (rec->ExceptionCode)
672         {
673         case EXCEPTION_INT_DIVIDE_BY_ZERO:
674             dbg_printf("divide by zero");
675             break;
676         case EXCEPTION_INT_OVERFLOW:
677             dbg_printf("overflow");
678             break;
679         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
680             dbg_printf("array bounds");
681             break;
682         case EXCEPTION_ILLEGAL_INSTRUCTION:
683             dbg_printf("illegal instruction");
684             break;
685         case EXCEPTION_STACK_OVERFLOW:
686             dbg_printf("stack overflow");
687             break;
688         case EXCEPTION_PRIV_INSTRUCTION:
689             dbg_printf("privileged instruction");
690             break;
691         case EXCEPTION_ACCESS_VIOLATION:
692             if (rec->NumberParameters == 2)
693                 dbg_printf("page fault on %s access to 0x%08lx",
694                            rec->ExceptionInformation[0] ? "write" : "read",
695                            rec->ExceptionInformation[1]);
696             else
697                 dbg_printf("page fault");
698             break;
699         case EXCEPTION_DATATYPE_MISALIGNMENT:
700             dbg_printf("Alignment");
701             break;
702         case DBG_CONTROL_C:
703             dbg_printf("^C");
704             break;
705         case CONTROL_C_EXIT:
706             dbg_printf("^C");
707             break;
708         case STATUS_POSSIBLE_DEADLOCK:
709         {
710             ADDRESS         addr;
711
712             addr.Mode   = AddrModeFlat;
713             addr.Offset = rec->ExceptionInformation[0];
714
715             dbg_printf("wait failed on critical section ");
716             print_address(&addr, FALSE);
717         }
718         if (!DBG_IVAR(BreakOnCritSectTimeOut))
719         {
720             dbg_printf("\n");
721             return DBG_EXCEPTION_NOT_HANDLED;
722         }
723         break;
724         case EXCEPTION_WINE_STUB:
725         {
726             char dll[32], name[64];
727             memory_get_string(dbg_curr_process,
728                               (void*)rec->ExceptionInformation[0], TRUE, FALSE,
729                               dll, sizeof(dll));
730             if (HIWORD(rec->ExceptionInformation[1]))
731                 memory_get_string(dbg_curr_process,
732                                   (void*)rec->ExceptionInformation[1], TRUE, FALSE,
733                                   name, sizeof(name));
734             else
735                 sprintf( name, "%ld", rec->ExceptionInformation[1] );
736             dbg_printf("unimplemented function %s.%s called", dll, name);
737         }
738         break;
739         case EXCEPTION_WINE_ASSERTION:
740             dbg_printf("assertion failed");
741             break;
742         case EXCEPTION_VM86_INTx:
743             dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
744             break;
745         case EXCEPTION_VM86_STI:
746             dbg_printf("sti in vm86 mode");
747             break;
748         case EXCEPTION_VM86_PICRETURN:
749             dbg_printf("PIC return in vm86 mode");
750             break;
751         case EXCEPTION_FLT_DENORMAL_OPERAND:
752             dbg_printf("denormal float operand");
753             break;
754         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
755             dbg_printf("divide by zero");
756             break;
757         case EXCEPTION_FLT_INEXACT_RESULT:
758             dbg_printf("inexact float result");
759             break;
760         case EXCEPTION_FLT_INVALID_OPERATION:
761             dbg_printf("invalid float operation");
762             break;
763         case EXCEPTION_FLT_OVERFLOW:
764             dbg_printf("floating pointer overflow");
765             break;
766         case EXCEPTION_FLT_UNDERFLOW:
767             dbg_printf("floating pointer underflow");
768             break;
769         case EXCEPTION_FLT_STACK_CHECK:
770             dbg_printf("floating point stack check");
771             break;
772         default:
773             dbg_printf("0x%08lx", rec->ExceptionCode);
774             break;
775         }
776     }
777     if( (rec->ExceptionFlags & EH_STACK_INVALID) ) {
778         dbg_printf( ", invalid program stack" );
779     }
780
781     if (dbg_action_mode == automatic_mode)
782     {
783         dbg_exception_prolog(is_debug, rec);
784         dbg_exception_epilog();
785         return 0;  /* terminate execution */
786     }
787
788     if (dbg_exception_prolog(is_debug, rec))
789     {
790         dbg_interactiveP = TRUE;
791         return 0;
792     }
793     dbg_exception_epilog();
794
795     return DBG_CONTINUE;
796 }
797
798 static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
799 {
800     char        buffer[256];
801     DWORD       cont = DBG_CONTINUE;
802
803     dbg_curr_pid = de->dwProcessId;
804     dbg_curr_tid = de->dwThreadId;
805
806     if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
807         dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
808     else
809         dbg_curr_thread = NULL;
810
811     switch (de->dwDebugEventCode)
812     {
813     case EXCEPTION_DEBUG_EVENT:
814         if (!dbg_curr_thread)
815         {
816             WINE_ERR("%08lx:%08lx: not a registered process or thread (perhaps a 16 bit one ?)\n",
817                      de->dwProcessId, de->dwThreadId);
818             break;
819         }
820
821         WINE_TRACE("%08lx:%08lx: exception code=%08lx\n",
822                    de->dwProcessId, de->dwThreadId,
823                    de->u.Exception.ExceptionRecord.ExceptionCode);
824
825         if (dbg_curr_process->continue_on_first_exception)
826         {
827             dbg_curr_process->continue_on_first_exception = FALSE;
828             if (!DBG_IVAR(BreakOnAttach)) break;
829         }
830         if (dbg_fetch_context())
831         {
832             cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
833                                         de->u.Exception.dwFirstChance);
834             if (cont && dbg_curr_thread)
835             {
836                 SetThreadContext(dbg_curr_thread->handle, &dbg_context);
837             }
838         }
839         break;
840
841     case CREATE_PROCESS_DEBUG_EVENT:
842         dbg_curr_process = dbg_add_process(de->dwProcessId,
843                                            de->u.CreateProcessInfo.hProcess);
844         if (dbg_curr_process == NULL)
845         {
846             WINE_ERR("Couldn't create process\n");
847             break;
848         }
849         memory_get_string_indirect(dbg_curr_process,
850                                    de->u.CreateProcessInfo.lpImageName,
851                                    de->u.CreateProcessInfo.fUnicode,
852                                    buffer, sizeof(buffer));
853         if (!buffer[0]) strcpy(buffer, "<Debugged Process>");
854
855         WINE_TRACE("%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n",
856                    de->dwProcessId, de->dwThreadId,
857                    buffer, de->u.CreateProcessInfo.lpImageName,
858                    (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress,
859                    de->u.CreateProcessInfo.dwDebugInfoFileOffset,
860                    de->u.CreateProcessInfo.nDebugInfoSize);
861         dbg_set_process_name(dbg_curr_process, buffer);
862
863         if (!SymInitialize(dbg_curr_process->handle, NULL, TRUE))
864             dbg_printf("Couldn't initiate DbgHelp\n");
865
866         WINE_TRACE("%08lx:%08lx: create thread I @%08lx\n",
867                    de->dwProcessId, de->dwThreadId,
868                    (unsigned long)(void*)de->u.CreateProcessInfo.lpStartAddress);
869
870         dbg_curr_thread = dbg_add_thread(dbg_curr_process,
871                                          de->dwThreadId,
872                                          de->u.CreateProcessInfo.hThread,
873                                          de->u.CreateProcessInfo.lpThreadLocalBase);
874         if (!dbg_curr_thread)
875         {
876             WINE_ERR("Couldn't create thread\n");
877             break;
878         }
879         dbg_init_current_process();
880         dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
881         break;
882
883     case EXIT_PROCESS_DEBUG_EVENT:
884         WINE_TRACE("%08lx:%08lx: exit process (%ld)\n",
885                    de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
886
887         if (dbg_curr_process == NULL)
888         {
889             WINE_ERR("Unknown process\n");
890             break;
891         }
892         if (!SymCleanup(dbg_curr_process->handle))
893             dbg_printf("Couldn't initiate DbgHelp\n");
894         /* just in case */
895         break_set_xpoints(FALSE);
896         /* kill last thread */
897         dbg_del_thread(dbg_curr_process->threads);
898         dbg_del_process(dbg_curr_process);
899
900         dbg_printf("Process of pid=0x%08lx has terminated\n", dbg_curr_pid);
901         break;
902
903     case CREATE_THREAD_DEBUG_EVENT:
904         WINE_TRACE("%08lx:%08lx: create thread D @%08lx\n",
905                    de->dwProcessId, de->dwThreadId,
906                    (unsigned long)(void*)de->u.CreateThread.lpStartAddress);
907
908         if (dbg_curr_process == NULL)
909         {
910             WINE_ERR("Unknown process\n");
911             break;
912         }
913         if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
914         {
915             WINE_TRACE("Thread already listed, skipping\n");
916             break;
917         }
918
919         dbg_curr_thread = dbg_add_thread(dbg_curr_process,
920                                          de->dwThreadId,
921                                          de->u.CreateThread.hThread,
922                                          de->u.CreateThread.lpThreadLocalBase);
923         if (!dbg_curr_thread)
924         {
925             WINE_ERR("Couldn't create thread\n");
926             break;
927         }
928         dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
929         break;
930
931     case EXIT_THREAD_DEBUG_EVENT:
932         WINE_TRACE("%08lx:%08lx: exit thread (%ld)\n",
933                    de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
934
935         if (dbg_curr_thread == NULL)
936         {
937             WINE_ERR("Unknown thread\n");
938             break;
939         }
940         /* FIXME: remove break point set on thread startup */
941         dbg_del_thread(dbg_curr_thread);
942         break;
943
944     case LOAD_DLL_DEBUG_EVENT:
945         if (dbg_curr_thread == NULL)
946         {
947             WINE_ERR("Unknown thread\n");
948             break;
949         }
950         memory_get_string_indirect(dbg_curr_process, 
951                                    de->u.LoadDll.lpImageName,
952                                    de->u.LoadDll.fUnicode,
953                                    buffer, sizeof(buffer));
954
955         WINE_TRACE("%08lx:%08lx: loads DLL %s @%08lx (%ld<%ld>)\n",
956                    de->dwProcessId, de->dwThreadId,
957                    buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll,
958                    de->u.LoadDll.dwDebugInfoFileOffset,
959                    de->u.LoadDll.nDebugInfoSize);
960         _strupr(buffer);
961         SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL,
962                       (unsigned long)de->u.LoadDll.lpBaseOfDll, 0);
963         break_set_xpoints(FALSE);
964         break_check_delayed_bp();
965         break_set_xpoints(TRUE);
966         if (DBG_IVAR(BreakOnDllLoad))
967         {
968             dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
969                        buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
970             if (dbg_fetch_context()) cont = 0;
971         }
972         break;
973
974     case UNLOAD_DLL_DEBUG_EVENT:
975         WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", 
976                    de->dwProcessId, de->dwThreadId,
977                    (unsigned long)de->u.UnloadDll.lpBaseOfDll);
978         break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
979         SymUnloadModule(dbg_curr_process->handle, 
980                         (unsigned long)de->u.UnloadDll.lpBaseOfDll);
981         break;
982
983     case OUTPUT_DEBUG_STRING_EVENT:
984         if (dbg_curr_thread == NULL)
985         {
986             WINE_ERR("Unknown thread\n");
987             break;
988         }
989
990         memory_get_string(dbg_curr_process,
991                           de->u.DebugString.lpDebugStringData, TRUE,
992                           de->u.DebugString.fUnicode, buffer, sizeof(buffer));
993         WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
994                    de->dwProcessId, de->dwThreadId, buffer);
995         break;
996
997     case RIP_EVENT:
998         WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
999                    de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
1000                    de->u.RipInfo.dwType);
1001         break;
1002
1003     default:
1004         WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
1005                    de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
1006     }
1007     if (!cont) return TRUE;  /* stop execution */
1008     ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
1009     return FALSE;  /* continue execution */
1010 }
1011
1012 static void dbg_resume_debuggee(DWORD cont)
1013 {
1014     if (dbg_curr_thread->in_exception)
1015     {
1016         ADDRESS         addr;
1017
1018         dbg_exception_epilog();
1019         memory_get_current_pc(&addr);
1020         WINE_TRACE("Exiting debugger      PC=0x%lx mode=%d count=%d\n",
1021                    addr.Offset, dbg_curr_thread->exec_mode,
1022                    dbg_curr_thread->exec_count);
1023         if (dbg_curr_thread)
1024         {
1025             if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
1026                 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
1027         }
1028     }
1029     dbg_interactiveP = FALSE;
1030     if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont))
1031         dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont);
1032 }
1033
1034 void dbg_wait_next_exception(DWORD cont, int count, int mode)
1035 {
1036     DEBUG_EVENT         de;
1037     ADDRESS             addr;
1038
1039     if (cont == DBG_CONTINUE)
1040     {
1041         dbg_curr_thread->exec_count = count;
1042         dbg_curr_thread->exec_mode = mode;
1043     }
1044     dbg_resume_debuggee(cont);
1045
1046     while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
1047     {
1048         if (dbg_handle_debug_event(&de)) break;
1049     }
1050     if (!dbg_curr_process) return;
1051     dbg_interactiveP = TRUE;
1052
1053     memory_get_current_pc(&addr);
1054     WINE_TRACE("Entering debugger     PC=0x%lx mode=%d count=%d\n",
1055                addr.Offset, dbg_curr_thread->exec_mode,
1056                dbg_curr_thread->exec_count);
1057 }
1058
1059 static  unsigned        dbg_main_loop(HANDLE hFile)
1060 {
1061     DEBUG_EVENT         de;
1062
1063     if (dbg_curr_process)
1064         dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid);
1065
1066     /* wait for first exception */
1067     while (WaitForDebugEvent(&de, INFINITE))
1068     {
1069         if (dbg_handle_debug_event(&de)) break;
1070     }
1071     switch (dbg_action_mode)
1072     {
1073     case automatic_mode:
1074         /* print some extra information */
1075         dbg_printf("Modules:\n");
1076         info_win32_module(0); /* print all modules */
1077         dbg_printf("Threads:\n");
1078         info_win32_threads();
1079         break;
1080     default:
1081         dbg_interactiveP = TRUE;
1082         parser_handle(hFile);
1083     }
1084     dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid);
1085
1086     return 0;
1087 }
1088
1089 static  unsigned dbg_start_debuggee(LPSTR cmdLine)
1090 {
1091     PROCESS_INFORMATION info;
1092     STARTUPINFOA        startup;
1093
1094     memset(&startup, 0, sizeof(startup));
1095     startup.cb = sizeof(startup);
1096     startup.dwFlags = STARTF_USESHOWWINDOW;
1097     startup.wShowWindow = SW_SHOWNORMAL;
1098
1099     /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1100      * while GUI:s don't
1101      */
1102     if (!CreateProcess(NULL, cmdLine, NULL, NULL,
1103                        FALSE, 
1104                        DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
1105                        NULL, NULL, &startup, &info))
1106     {
1107         dbg_printf("Couldn't start process '%s'\n", cmdLine);
1108         return FALSE;
1109     }
1110     if (!info.dwProcessId)
1111     {
1112         /* this happens when the program being run is not a Wine binary
1113          * (for example, a shell wrapper around a WineLib app)
1114          */
1115         /* Current fix: list running processes and let the user attach
1116          * to one of them (sic)
1117          * FIXME: implement a real fix => grab the process (from the
1118          * running processes) from its name
1119          */
1120         dbg_printf("Debuggee has been started (%s)\n"
1121                    "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
1122                    "Try to attach to one of those processes:\n", cmdLine);
1123         /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
1124         Sleep(100);
1125         info_win32_processes();
1126         return TRUE;
1127     }
1128     dbg_curr_pid = info.dwProcessId;
1129     if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0))) return FALSE;
1130
1131     return TRUE;
1132 }
1133
1134 void    dbg_run_debuggee(const char* args)
1135 {
1136     if (args)
1137     {
1138         WINE_FIXME("Re-running current program with %s as args is broken\n", args);
1139         return;
1140     }
1141     else 
1142     {
1143         DEBUG_EVENT     de;
1144
1145         if (!dbg_last_cmd_line)
1146         {
1147             dbg_printf("Cannot find previously used command line.\n");
1148             return;
1149         }
1150         dbg_start_debuggee(dbg_last_cmd_line);
1151         while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
1152         {
1153             if (dbg_handle_debug_event(&de)) break;
1154         }
1155         source_list_from_addr(NULL, 0);
1156     }
1157 }
1158
1159 BOOL dbg_interrupt_debuggee(void)
1160 {
1161     if (!dbg_process_list) return FALSE;
1162     /* FIXME: since we likely have a single process, signal the first process
1163      * in list
1164      */
1165     if (dbg_process_list->next) dbg_printf("Ctrl-C: only stopping the first process\n");
1166     else dbg_printf("Ctrl-C: stopping debuggee\n");
1167     dbg_process_list->continue_on_first_exception = FALSE;
1168     return DebugBreakProcess(dbg_process_list->handle);
1169 }
1170
1171 static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType)
1172 {
1173     if (dwCtrlType == CTRL_C_EVENT)
1174     {
1175         return dbg_interrupt_debuggee();
1176     }
1177     return FALSE;
1178 }
1179
1180 static void dbg_init_console(void)
1181 {
1182     /* set our control-C handler */
1183     SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
1184
1185     /* set our own title */
1186     SetConsoleTitle("Wine Debugger");
1187 }
1188
1189 static int dbg_winedbg_usage(void)
1190 {
1191     dbg_printf("Usage: winedbg [--command cmd|--file file|--auto] [--gdb [--no-start] [--with-xterm]] cmdline\n");
1192     return 1;
1193 }
1194
1195 struct backend_cpu* be_cpu;
1196 #ifdef __i386__
1197 extern struct backend_cpu be_i386;
1198 #elif __powerpc__
1199 extern struct backend_cpu be_ppc;
1200 #elif __ALPHA__
1201 extern struct backend_cpu be_alpha;
1202 #else
1203 # error CPU unknown
1204 #endif
1205
1206 int main(int argc, char** argv)
1207 {
1208     DWORD       retv = 0;
1209     unsigned    gdb_flags = 0;
1210     HANDLE      hFile = INVALID_HANDLE_VALUE;
1211
1212 #ifdef __i386__
1213     be_cpu = &be_i386;
1214 #elif __powerpc__
1215     be_cpu = &be_ppc;
1216 #elif __ALPHA__
1217     be_cpu = &be_alpha;
1218 #else
1219 # error CPU unknown
1220 #endif
1221     /* Initialize the output */
1222     dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE);
1223
1224     /* Initialize internal vars */
1225     if (!dbg_load_internal_vars()) return -1;
1226
1227     /* parse options */
1228     while (argc > 1 && argv[1][0] == '-')
1229     {
1230         if (!strcmp(argv[1], "--command"))
1231         {
1232             char        path[MAX_PATH], file[MAX_PATH];
1233             DWORD       w;
1234
1235             GetTempPath(sizeof(path), path);
1236             GetTempFileName(path, "WD", 0, file);
1237             argc--; argv++;
1238             hFile = CreateFileA(file, GENERIC_READ|GENERIC_WRITE|DELETE, FILE_SHARE_DELETE, 
1239                                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
1240             if (hFile == INVALID_HANDLE_VALUE)
1241             {
1242                 dbg_printf("Couldn't open temp file %s (%lu)\n", file, GetLastError());
1243                 return 1;
1244             }
1245             WriteFile(hFile, argv[1], strlen(argv[1]), &w, 0);
1246             WriteFile(hFile, "\nquit\n", 6, &w, 0);
1247             SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
1248
1249             argc--; argv++;
1250             continue;
1251         }
1252         if (!strcmp(argv[1], "--file"))
1253         {
1254             argc--; argv++;
1255             hFile = CreateFileA(argv[1], GENERIC_READ|DELETE, 0, 
1256                                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1257             if (hFile == INVALID_HANDLE_VALUE)
1258             {
1259                 dbg_printf("Couldn't open file %s (%lu)\n", argv[1], GetLastError());
1260                 return 1;
1261             }
1262             argc--; argv++;
1263             continue;
1264         }
1265         if (!strcmp(argv[1], "--auto"))
1266         {
1267             if (dbg_action_mode != none_mode) return dbg_winedbg_usage();
1268             dbg_action_mode = automatic_mode;
1269             /* force some internal variables */
1270             DBG_IVAR(BreakOnDllLoad) = 0;
1271             argc--; argv++;
1272             dbg_houtput = GetStdHandle(STD_ERROR_HANDLE);
1273             continue;
1274         }
1275         if (!strcmp(argv[1], "--gdb"))
1276         {
1277             if (dbg_action_mode != none_mode) return dbg_winedbg_usage();
1278             dbg_action_mode = gdb_mode;
1279             argc--; argv++;
1280             continue;
1281         }
1282         if (strcmp(argv[1], "--no-start") == 0 && dbg_action_mode == gdb_mode)
1283         {
1284             gdb_flags |= 1;
1285             argc--; argv++; /* as we don't use argv[0] */
1286             continue;
1287         }
1288         if (strcmp(argv[1], "--with-xterm") == 0 && dbg_action_mode == gdb_mode)
1289         {
1290             gdb_flags |= 2;
1291             argc--; argv++; /* as we don't use argv[0] */
1292             continue;
1293         }
1294         return dbg_winedbg_usage();
1295     }
1296
1297     if (dbg_action_mode == none_mode) dbg_action_mode = winedbg_mode;
1298
1299     /* try the form <myself> pid */
1300     if (dbg_curr_pid == 0 && argc == 2)
1301     {
1302         char*   ptr;
1303
1304         dbg_curr_pid = strtol(argv[1], &ptr, 10);
1305         if (dbg_curr_pid == 0 || ptr != argv[1] + strlen(argv[1]) ||
1306             !dbg_attach_debuggee(dbg_curr_pid, FALSE, FALSE))
1307             dbg_curr_pid = 0;
1308     }
1309
1310     /* try the form <myself> pid evt (Win32 JIT debugger) */
1311     if (dbg_curr_pid == 0 && argc == 3)
1312     {
1313         HANDLE  hEvent;
1314         DWORD   pid;
1315         char*   ptr;
1316
1317         if ((pid = strtol(argv[1], &ptr, 10)) != 0 && ptr != NULL &&
1318             (hEvent = (HANDLE)strtol(argv[2], &ptr, 10)) != 0 && ptr != NULL)
1319         {
1320             if (!dbg_attach_debuggee(pid, TRUE, FALSE))
1321             {
1322                 /* don't care about result */
1323                 SetEvent(hEvent);
1324                 goto leave;
1325             }
1326             if (!SetEvent(hEvent))
1327             {
1328                 WINE_ERR("Invalid event handle: %p\n", hEvent);
1329                 goto leave;
1330             }
1331             CloseHandle(hEvent);
1332             dbg_curr_pid = pid;
1333         }
1334     }
1335
1336     if (dbg_curr_pid == 0 && argc > 1)
1337     {
1338         int     i, len;
1339         LPSTR   cmdLine;
1340
1341         if (!(cmdLine = HeapAlloc(GetProcessHeap(), 0, len = 1))) goto oom_leave;
1342         cmdLine[0] = '\0';
1343
1344         for (i = 1; i < argc; i++)
1345         {
1346             len += strlen(argv[i]) + 1;
1347             if (!(cmdLine = HeapReAlloc(GetProcessHeap(), 0, cmdLine, len)))
1348                 goto oom_leave;
1349             strcat(cmdLine, argv[i]);
1350             cmdLine[len - 2] = ' ';
1351             cmdLine[len - 1] = '\0';
1352         }
1353
1354         if (!dbg_start_debuggee(cmdLine))
1355         {
1356             dbg_printf("Couldn't start process '%s'\n", cmdLine);
1357             goto leave;
1358         }
1359         dbg_last_cmd_line = cmdLine;
1360     }
1361     /* don't save local vars in gdb mode */
1362     if (dbg_action_mode == gdb_mode && dbg_curr_pid)
1363         return gdb_remote(gdb_flags);
1364
1365     dbg_init_console();
1366
1367     SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME)) |
1368                   SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS);
1369
1370     retv = dbg_main_loop(hFile);
1371     /* don't save modified variables in auto mode */
1372     if (dbg_action_mode != automatic_mode) dbg_save_internal_vars();
1373
1374 leave:
1375     return retv;
1376
1377 oom_leave:
1378     dbg_printf("Out of memory\n");
1379     return retv;
1380 }