winedbg: Fixed regression: stack info was no longer working.
[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  * - execution:
62  *      + set a better fix for gdb (proxy mode) than the step-mode hack
63  *      + implement function call in debuggee
64  *      + trampoline management is broken when getting 16 <=> 32 thunk destination
65  *        address
66  *      + thunking of delayed imports doesn't work as expected (ie, when stepping,
67  *        it currently stops at first insn with line number during the library 
68  *        loading). We should identify this (__wine_delay_import) and set a
69  *        breakpoint instead of single stepping the library loading.
70  *      + it's wrong to copy thread->step_over_bp into process->bp[0] (when 
71  *        we have a multi-thread debuggee). complete fix must include storing all
72  *        thread's step-over bp in process-wide bp array, and not to handle bp
73  *        when we have the wrong thread running into that bp
74  *      + code in CREATE_PROCESS debug event doesn't work on Windows, as we cannot
75  *        get the name of the main module this way. We should rewrite all this code
76  *        and store in struct dbg_process as early as possible (before process
77  *        creation or attachment), the name of the main module
78  * - global:
79  *      + define a better way to enable the wine extensions (either DBG SDK function
80  *        in dbghelp, or TLS variable, or environment variable or ...)
81  *      + audit all files to ensure that we check all potential return values from
82  *        every function call to catch the errors
83  *      + BTW check also whether the exception mechanism is the best way to return
84  *        errors (or find a proper fix for MinGW port)
85  *      + use Wine standard list mechanism for all list handling
86  */
87
88 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
89
90 struct dbg_process*     dbg_curr_process = NULL;
91 struct dbg_thread*      dbg_curr_thread = NULL;
92 DWORD                   dbg_curr_tid;
93 DWORD                   dbg_curr_pid;
94 CONTEXT                 dbg_context;
95 BOOL                    dbg_interactiveP = FALSE;
96 static char*            dbg_last_cmd_line = NULL;
97
98 static struct dbg_process*      dbg_process_list = NULL;
99 static enum {none_mode = 0, winedbg_mode, automatic_mode, gdb_mode} dbg_action_mode;
100
101 struct dbg_internal_var         dbg_internal_vars[DBG_IV_LAST];
102 const struct dbg_internal_var*  dbg_context_vars;
103 static HANDLE                   dbg_houtput;
104
105 void    dbg_outputA(const char* buffer, int len)
106 {
107     static char line_buff[4096];
108     static unsigned int line_pos;
109
110     DWORD w, i;
111
112     while (len > 0)
113     {
114         unsigned int count = min( len, sizeof(line_buff) - line_pos );
115         memcpy( line_buff + line_pos, buffer, count );
116         buffer += count;
117         len -= count;
118         line_pos += count;
119         for (i = line_pos; i > 0; i--) if (line_buff[i-1] == '\n') break;
120         if (!i)  /* no newline found */
121         {
122             if (len > 0) i = line_pos;  /* buffer is full, flush anyway */
123             else break;
124         }
125         WriteFile(dbg_houtput, line_buff, i, &w, NULL);
126         memmove( line_buff, line_buff + i, line_pos - i );
127         line_pos -= i;
128     }
129 }
130
131 void    dbg_outputW(const WCHAR* buffer, int len)
132 {
133     char* ansi = NULL;
134     int newlen;
135         
136     /* do a serious Unicode to ANSI conversion
137      * FIXME: should CP_ACP be GetConsoleCP()?
138      */
139     newlen = WideCharToMultiByte(CP_ACP, 0, buffer, len, NULL, 0, NULL, NULL);
140     if (newlen)
141     {
142         if (!(ansi = HeapAlloc(GetProcessHeap(), 0, newlen))) return;
143         WideCharToMultiByte(CP_ACP, 0, buffer, len, ansi, newlen, NULL, NULL);
144         dbg_outputA(ansi, newlen);
145         HeapFree(GetProcessHeap(), 0, ansi);
146     }
147 }
148
149 int     dbg_printf(const char* format, ...)
150 {
151     static    char      buf[4*1024];
152     va_list     valist;
153     int         len;
154
155     va_start(valist, format);
156     len = vsnprintf(buf, sizeof(buf), format, valist);
157     va_end(valist);
158
159     if (len <= -1 || len >= sizeof(buf)) 
160     {
161         len = sizeof(buf) - 1;
162         buf[len] = 0;
163         buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
164     }
165     dbg_outputA(buf, len);
166     return len;
167 }
168
169 static  unsigned dbg_load_internal_vars(void)
170 {
171     HKEY                        hkey;
172     DWORD                       type = REG_DWORD;
173     DWORD                       val;
174     DWORD                       count = sizeof(val);
175     int                         i;
176     struct dbg_internal_var*    div = dbg_internal_vars;
177
178 /* initializes internal vars table */
179 #define  INTERNAL_VAR(_var,_val,_ref,_tid)                      \
180         div->val = _val; div->name = #_var; div->pval = _ref;   \
181         div->typeid = _tid; div++;
182 #include "intvar.h"
183 #undef   INTERNAL_VAR
184
185     /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
186     if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) 
187     {
188         WINE_ERR("Cannot create WineDbg key in registry\n");
189         return FALSE;
190     }
191
192     for (i = 0; i < DBG_IV_LAST; i++) 
193     {
194         if (!dbg_internal_vars[i].pval) 
195         {
196             if (!RegQueryValueEx(hkey, dbg_internal_vars[i].name, 0,
197                                  &type, (LPBYTE)&val, &count))
198                 dbg_internal_vars[i].val = val;
199             dbg_internal_vars[i].pval = &dbg_internal_vars[i].val;
200         }
201     }
202     RegCloseKey(hkey);
203     /* set up the debug variables for the CPU context */
204     dbg_context_vars = be_cpu->init_registers(&dbg_context);
205     return TRUE;
206 }
207
208 static  unsigned dbg_save_internal_vars(void)
209 {
210     HKEY                        hkey;
211     int                         i;
212
213     /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
214     if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey)) 
215     {
216         WINE_ERR("Cannot create WineDbg key in registry\n");
217         return FALSE;
218     }
219
220     for (i = 0; i < DBG_IV_LAST; i++) 
221     {
222         /* FIXME: type should be infered from basic type -if any- of intvar */
223         if (dbg_internal_vars[i].pval == &dbg_internal_vars[i].val)
224             RegSetValueEx(hkey, dbg_internal_vars[i].name, 0,
225                           REG_DWORD, (const void*)dbg_internal_vars[i].pval, 
226                           sizeof(*dbg_internal_vars[i].pval));
227     }
228     RegCloseKey(hkey);
229     return TRUE;
230 }
231
232 const struct dbg_internal_var* dbg_get_internal_var(const char* name)
233 {
234     const struct dbg_internal_var*      div;
235
236     for (div = &dbg_internal_vars[DBG_IV_LAST - 1]; div >= dbg_internal_vars; div--)
237     {
238         if (!strcmp(div->name, name)) return div;
239     }
240     for (div = dbg_context_vars; div->name; div++)
241     {
242         if (!strcasecmp(div->name, name)) return div;
243     }
244
245     return NULL;
246 }
247
248 struct dbg_process*     dbg_get_process(DWORD pid)
249 {
250     struct dbg_process* p;
251
252     for (p = dbg_process_list; p; p = p->next)
253         if (p->pid == pid) break;
254     return p;
255 }
256
257 struct dbg_process*     dbg_add_process(DWORD pid, HANDLE h)
258 {
259     /* FIXME: temporary */
260     extern struct be_process_io be_process_active_io;
261
262     struct dbg_process* p;
263
264     if ((p = dbg_get_process(pid)))
265     {
266         if (p->handle != 0)
267         {
268             WINE_ERR("Process (%lu) is already defined\n", pid);
269         }
270         else
271         {
272             p->handle = h;
273             p->imageName = NULL;
274         }
275         return p;
276     }
277
278     if (!(p = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process)))) return NULL;
279     p->handle = h;
280     p->pid = pid;
281     p->process_io = &be_process_active_io;
282     p->imageName = NULL;
283     p->threads = NULL;
284     p->continue_on_first_exception = FALSE;
285     p->next_bp = 1;  /* breakpoint 0 is reserved for step-over */
286     memset(p->bp, 0, sizeof(p->bp));
287     p->delayed_bp = NULL;
288     p->num_delayed_bp = 0;
289
290     p->next = dbg_process_list;
291     p->prev = NULL;
292     if (dbg_process_list) dbg_process_list->prev = p;
293     dbg_process_list = p;
294     return p;
295 }
296
297 void dbg_set_process_name(struct dbg_process* p, const char* imageName)
298 {
299     assert(p->imageName == NULL);
300     if (imageName)
301     {
302         char* tmp = HeapAlloc(GetProcessHeap(), 0, strlen(imageName) + 1);
303         if (tmp) p->imageName = strcpy(tmp, imageName);
304     }
305 }
306
307 void dbg_del_process(struct dbg_process* p)
308 {
309     int i;
310
311     while (p->threads) dbg_del_thread(p->threads);
312
313     for (i = 0; i < p->num_delayed_bp; i++)
314         if (p->delayed_bp[i].is_symbol)
315             HeapFree(GetProcessHeap(), 0, p->delayed_bp[i].u.symbol.name);
316
317     HeapFree(GetProcessHeap(), 0, p->delayed_bp);
318     if (p->prev) p->prev->next = p->next;
319     if (p->next) p->next->prev = p->prev;
320     if (p == dbg_process_list) dbg_process_list = p->next;
321     if (p == dbg_curr_process) dbg_curr_process = NULL;
322     HeapFree(GetProcessHeap(), 0, (char*)p->imageName);
323     HeapFree(GetProcessHeap(), 0, p);
324 }
325
326 static void dbg_init_current_process(void)
327 {
328 }
329
330 struct mod_loader_info
331 {
332     HANDLE              handle;
333     IMAGEHLP_MODULE*    imh_mod;
334 };
335
336 static BOOL CALLBACK mod_loader_cb(PSTR mod_name, DWORD base, void* ctx)
337 {
338     struct mod_loader_info*     mli = (struct mod_loader_info*)ctx;
339
340     if (!strcmp(mod_name, "<wine-loader>"))
341     {
342         if (SymGetModuleInfo(mli->handle, base, mli->imh_mod))
343             return FALSE; /* stop enum */
344     }
345     return TRUE;
346 }
347
348 BOOL dbg_get_debuggee_info(HANDLE hProcess, IMAGEHLP_MODULE* imh_mod)
349 {
350     struct mod_loader_info  mli;
351     DWORD                   opt;
352
353     /* this will resynchronize builtin dbghelp's internal ELF module list */
354     SymLoadModule(hProcess, 0, 0, 0, 0, 0);
355     mli.handle  = hProcess;
356     mli.imh_mod = imh_mod;
357     imh_mod->SizeOfStruct = sizeof(*imh_mod);
358     imh_mod->BaseOfImage = 0;
359     /* this is a wine specific options to return also ELF modules in the
360      * enumeration
361      */
362     SymSetOptions((opt = SymGetOptions()) | 0x40000000);
363     SymEnumerateModules(hProcess, mod_loader_cb, (void*)&mli);
364     SymSetOptions(opt);
365
366     return imh_mod->BaseOfImage != 0;
367 }
368
369 struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid)
370 {
371     struct dbg_thread*  t;
372
373     if (!p) return NULL;
374     for (t = p->threads; t; t = t->next)
375         if (t->tid == tid) break;
376     return t;
377 }
378
379 struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
380                                   HANDLE h, void* teb)
381 {
382     struct dbg_thread*  t = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread));
383
384     if (!t)
385         return NULL;
386
387     t->handle = h;
388     t->tid = tid;
389     t->teb = teb;
390     t->process = p;
391     t->exec_mode = dbg_exec_cont;
392     t->exec_count = 0;
393     t->step_over_bp.enabled = FALSE;
394     t->step_over_bp.refcount = 0;
395     t->stopped_xpoint = -1;
396     t->in_exception = FALSE;
397     t->frames = NULL;
398     t->num_frames = 0;
399     t->curr_frame = -1;
400     t->addr_mode = AddrModeFlat;
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, 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         SymLoadModule(dbg_curr_process->handle, de->u.LoadDll.hFile, buffer, NULL,
961                       (unsigned long)de->u.LoadDll.lpBaseOfDll, 0);
962         break_set_xpoints(FALSE);
963         break_check_delayed_bp();
964         break_set_xpoints(TRUE);
965         if (DBG_IVAR(BreakOnDllLoad))
966         {
967             dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
968                        buffer, (unsigned long)de->u.LoadDll.lpBaseOfDll);
969             if (dbg_fetch_context()) cont = 0;
970         }
971         break;
972
973     case UNLOAD_DLL_DEBUG_EVENT:
974         WINE_TRACE("%08lx:%08lx: unload DLL @%08lx\n", 
975                    de->dwProcessId, de->dwThreadId,
976                    (unsigned long)de->u.UnloadDll.lpBaseOfDll);
977         break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
978         SymUnloadModule(dbg_curr_process->handle, 
979                         (unsigned long)de->u.UnloadDll.lpBaseOfDll);
980         break;
981
982     case OUTPUT_DEBUG_STRING_EVENT:
983         if (dbg_curr_thread == NULL)
984         {
985             WINE_ERR("Unknown thread\n");
986             break;
987         }
988
989         memory_get_string(dbg_curr_process,
990                           de->u.DebugString.lpDebugStringData, TRUE,
991                           de->u.DebugString.fUnicode, buffer, sizeof(buffer));
992         WINE_TRACE("%08lx:%08lx: output debug string (%s)\n",
993                    de->dwProcessId, de->dwThreadId, buffer);
994         break;
995
996     case RIP_EVENT:
997         WINE_TRACE("%08lx:%08lx: rip error=%ld type=%ld\n",
998                    de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
999                    de->u.RipInfo.dwType);
1000         break;
1001
1002     default:
1003         WINE_TRACE("%08lx:%08lx: unknown event (%ld)\n",
1004                    de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
1005     }
1006     if (!cont) return TRUE;  /* stop execution */
1007     ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
1008     return FALSE;  /* continue execution */
1009 }
1010
1011 static void dbg_resume_debuggee(DWORD cont)
1012 {
1013     if (dbg_curr_thread->in_exception)
1014     {
1015         ADDRESS         addr;
1016
1017         dbg_exception_epilog();
1018         memory_get_current_pc(&addr);
1019         WINE_TRACE("Exiting debugger      PC=0x%lx mode=%d count=%d\n",
1020                    addr.Offset, dbg_curr_thread->exec_mode,
1021                    dbg_curr_thread->exec_count);
1022         if (dbg_curr_thread)
1023         {
1024             if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
1025                 dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
1026         }
1027     }
1028     dbg_interactiveP = FALSE;
1029     if (!ContinueDebugEvent(dbg_curr_pid, dbg_curr_tid, cont))
1030         dbg_printf("Cannot continue on %lu (%lu)\n", dbg_curr_tid, cont);
1031 }
1032
1033 void dbg_wait_next_exception(DWORD cont, int count, int mode)
1034 {
1035     DEBUG_EVENT         de;
1036     ADDRESS             addr;
1037
1038     if (cont == DBG_CONTINUE)
1039     {
1040         dbg_curr_thread->exec_count = count;
1041         dbg_curr_thread->exec_mode = mode;
1042     }
1043     dbg_resume_debuggee(cont);
1044
1045     while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
1046     {
1047         if (dbg_handle_debug_event(&de)) break;
1048     }
1049     if (!dbg_curr_process) return;
1050     dbg_interactiveP = TRUE;
1051
1052     memory_get_current_pc(&addr);
1053     WINE_TRACE("Entering debugger     PC=0x%lx mode=%d count=%d\n",
1054                addr.Offset, dbg_curr_thread->exec_mode,
1055                dbg_curr_thread->exec_count);
1056 }
1057
1058 static  unsigned        dbg_main_loop(HANDLE hFile)
1059 {
1060     DEBUG_EVENT         de;
1061
1062     if (dbg_curr_process)
1063         dbg_printf("WineDbg starting on pid 0x%lx\n", dbg_curr_pid);
1064
1065     /* wait for first exception */
1066     while (WaitForDebugEvent(&de, INFINITE))
1067     {
1068         if (dbg_handle_debug_event(&de)) break;
1069     }
1070     switch (dbg_action_mode)
1071     {
1072     case automatic_mode:
1073         /* print some extra information */
1074         dbg_printf("Modules:\n");
1075         info_win32_module(0); /* print all modules */
1076         dbg_printf("Threads:\n");
1077         info_win32_threads();
1078         break;
1079     default:
1080         dbg_interactiveP = TRUE;
1081         parser_handle(hFile);
1082     }
1083     dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid);
1084
1085     return 0;
1086 }
1087
1088 static  unsigned dbg_start_debuggee(LPSTR cmdLine)
1089 {
1090     PROCESS_INFORMATION info;
1091     STARTUPINFOA        startup;
1092
1093     memset(&startup, 0, sizeof(startup));
1094     startup.cb = sizeof(startup);
1095     startup.dwFlags = STARTF_USESHOWWINDOW;
1096     startup.wShowWindow = SW_SHOWNORMAL;
1097
1098     /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it
1099      * while GUI:s don't
1100      */
1101     if (!CreateProcess(NULL, cmdLine, NULL, NULL,
1102                        FALSE, 
1103                        DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
1104                        NULL, NULL, &startup, &info))
1105     {
1106         dbg_printf("Couldn't start process '%s'\n", cmdLine);
1107         return FALSE;
1108     }
1109     if (!info.dwProcessId)
1110     {
1111         /* this happens when the program being run is not a Wine binary
1112          * (for example, a shell wrapper around a WineLib app)
1113          */
1114         /* Current fix: list running processes and let the user attach
1115          * to one of them (sic)
1116          * FIXME: implement a real fix => grab the process (from the
1117          * running processes) from its name
1118          */
1119         dbg_printf("Debuggee has been started (%s)\n"
1120                    "But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
1121                    "Try to attach to one of those processes:\n", cmdLine);
1122         /* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
1123         Sleep(100);
1124         info_win32_processes();
1125         return TRUE;
1126     }
1127     dbg_curr_pid = info.dwProcessId;
1128     if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0))) return FALSE;
1129
1130     return TRUE;
1131 }
1132
1133 void    dbg_run_debuggee(const char* args)
1134 {
1135     if (args)
1136     {
1137         WINE_FIXME("Re-running current program with %s as args is broken\n", args);
1138         return;
1139     }
1140     else 
1141     {
1142         DEBUG_EVENT     de;
1143
1144         if (!dbg_last_cmd_line)
1145         {
1146             dbg_printf("Cannot find previously used command line.\n");
1147             return;
1148         }
1149         dbg_start_debuggee(dbg_last_cmd_line);
1150         while (dbg_curr_process && WaitForDebugEvent(&de, INFINITE))
1151         {
1152             if (dbg_handle_debug_event(&de)) break;
1153         }
1154         source_list_from_addr(NULL, 0);
1155     }
1156 }
1157
1158 BOOL dbg_interrupt_debuggee(void)
1159 {
1160     if (!dbg_process_list) return FALSE;
1161     /* FIXME: since we likely have a single process, signal the first process
1162      * in list
1163      */
1164     if (dbg_process_list->next) dbg_printf("Ctrl-C: only stopping the first process\n");
1165     else dbg_printf("Ctrl-C: stopping debuggee\n");
1166     dbg_process_list->continue_on_first_exception = FALSE;
1167     return DebugBreakProcess(dbg_process_list->handle);
1168 }
1169
1170 static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType)
1171 {
1172     if (dwCtrlType == CTRL_C_EVENT)
1173     {
1174         return dbg_interrupt_debuggee();
1175     }
1176     return FALSE;
1177 }
1178
1179 static void dbg_init_console(void)
1180 {
1181     /* set our control-C handler */
1182     SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
1183
1184     /* set our own title */
1185     SetConsoleTitle("Wine Debugger");
1186 }
1187
1188 static int dbg_winedbg_usage(void)
1189 {
1190     dbg_printf("Usage: winedbg [--command cmd|--file file|--auto] [--gdb [--no-start] [--with-xterm]] cmdline\n");
1191     return 1;
1192 }
1193
1194 struct backend_cpu* be_cpu;
1195 #ifdef __i386__
1196 extern struct backend_cpu be_i386;
1197 #elif __powerpc__
1198 extern struct backend_cpu be_ppc;
1199 #elif __ALPHA__
1200 extern struct backend_cpu be_alpha;
1201 #else
1202 # error CPU unknown
1203 #endif
1204
1205 int main(int argc, char** argv)
1206 {
1207     DWORD       retv = 0;
1208     unsigned    gdb_flags = 0;
1209     HANDLE      hFile = INVALID_HANDLE_VALUE;
1210
1211 #ifdef __i386__
1212     be_cpu = &be_i386;
1213 #elif __powerpc__
1214     be_cpu = &be_ppc;
1215 #elif __ALPHA__
1216     be_cpu = &be_alpha;
1217 #else
1218 # error CPU unknown
1219 #endif
1220     /* Initialize the output */
1221     dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE);
1222
1223     /* Initialize internal vars */
1224     if (!dbg_load_internal_vars()) return -1;
1225
1226     /* parse options */
1227     while (argc > 1 && argv[1][0] == '-')
1228     {
1229         if (!strcmp(argv[1], "--command"))
1230         {
1231             char        path[MAX_PATH], file[MAX_PATH];
1232             DWORD       w;
1233
1234             GetTempPath(sizeof(path), path);
1235             GetTempFileName(path, "WD", 0, file);
1236             argc--; argv++;
1237             hFile = CreateFileA(file, GENERIC_READ|GENERIC_WRITE|DELETE, FILE_SHARE_DELETE, 
1238                                 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
1239             if (hFile == INVALID_HANDLE_VALUE)
1240             {
1241                 dbg_printf("Couldn't open temp file %s (%lu)\n", file, GetLastError());
1242                 return 1;
1243             }
1244             WriteFile(hFile, argv[1], strlen(argv[1]), &w, 0);
1245             WriteFile(hFile, "\nquit\n", 6, &w, 0);
1246             SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
1247
1248             argc--; argv++;
1249             continue;
1250         }
1251         if (!strcmp(argv[1], "--file"))
1252         {
1253             argc--; argv++;
1254             hFile = CreateFileA(argv[1], GENERIC_READ|DELETE, 0, 
1255                                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1256             if (hFile == INVALID_HANDLE_VALUE)
1257             {
1258                 dbg_printf("Couldn't open file %s (%lu)\n", argv[1], GetLastError());
1259                 return 1;
1260             }
1261             argc--; argv++;
1262             continue;
1263         }
1264         if (!strcmp(argv[1], "--auto"))
1265         {
1266             if (dbg_action_mode != none_mode) return dbg_winedbg_usage();
1267             dbg_action_mode = automatic_mode;
1268             /* force some internal variables */
1269             DBG_IVAR(BreakOnDllLoad) = 0;
1270             argc--; argv++;
1271             dbg_houtput = GetStdHandle(STD_ERROR_HANDLE);
1272             continue;
1273         }
1274         if (!strcmp(argv[1], "--gdb"))
1275         {
1276             if (dbg_action_mode != none_mode) return dbg_winedbg_usage();
1277             dbg_action_mode = gdb_mode;
1278             argc--; argv++;
1279             continue;
1280         }
1281         if (strcmp(argv[1], "--no-start") == 0 && dbg_action_mode == gdb_mode)
1282         {
1283             gdb_flags |= 1;
1284             argc--; argv++; /* as we don't use argv[0] */
1285             continue;
1286         }
1287         if (strcmp(argv[1], "--with-xterm") == 0 && dbg_action_mode == gdb_mode)
1288         {
1289             gdb_flags |= 2;
1290             argc--; argv++; /* as we don't use argv[0] */
1291             continue;
1292         }
1293         return dbg_winedbg_usage();
1294     }
1295
1296     if (dbg_action_mode == none_mode) dbg_action_mode = winedbg_mode;
1297
1298     /* try the form <myself> pid */
1299     if (dbg_curr_pid == 0 && argc == 2)
1300     {
1301         char*   ptr;
1302
1303         dbg_curr_pid = strtol(argv[1], &ptr, 10);
1304         if (dbg_curr_pid == 0 || ptr != argv[1] + strlen(argv[1]) ||
1305             !dbg_attach_debuggee(dbg_curr_pid, FALSE, FALSE))
1306             dbg_curr_pid = 0;
1307     }
1308
1309     /* try the form <myself> pid evt (Win32 JIT debugger) */
1310     if (dbg_curr_pid == 0 && argc == 3)
1311     {
1312         HANDLE  hEvent;
1313         DWORD   pid;
1314         char*   ptr;
1315
1316         if ((pid = strtol(argv[1], &ptr, 10)) != 0 && ptr != NULL &&
1317             (hEvent = (HANDLE)strtol(argv[2], &ptr, 10)) != 0 && ptr != NULL)
1318         {
1319             if (!dbg_attach_debuggee(pid, TRUE, FALSE))
1320             {
1321                 /* don't care about result */
1322                 SetEvent(hEvent);
1323                 goto leave;
1324             }
1325             if (!SetEvent(hEvent))
1326             {
1327                 WINE_ERR("Invalid event handle: %p\n", hEvent);
1328                 goto leave;
1329             }
1330             CloseHandle(hEvent);
1331             dbg_curr_pid = pid;
1332         }
1333     }
1334
1335     if (dbg_curr_pid == 0 && argc > 1)
1336     {
1337         int     i, len;
1338         LPSTR   cmdLine;
1339
1340         if (!(cmdLine = HeapAlloc(GetProcessHeap(), 0, len = 1))) goto oom_leave;
1341         cmdLine[0] = '\0';
1342
1343         for (i = 1; i < argc; i++)
1344         {
1345             len += strlen(argv[i]) + 1;
1346             if (!(cmdLine = HeapReAlloc(GetProcessHeap(), 0, cmdLine, len)))
1347                 goto oom_leave;
1348             strcat(cmdLine, argv[i]);
1349             cmdLine[len - 2] = ' ';
1350             cmdLine[len - 1] = '\0';
1351         }
1352
1353         if (!dbg_start_debuggee(cmdLine))
1354         {
1355             dbg_printf("Couldn't start process '%s'\n", cmdLine);
1356             goto leave;
1357         }
1358         dbg_last_cmd_line = cmdLine;
1359     }
1360     /* don't save local vars in gdb mode */
1361     if (dbg_action_mode == gdb_mode && dbg_curr_pid)
1362         return gdb_remote(gdb_flags);
1363
1364     dbg_init_console();
1365
1366     SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME)) |
1367                   SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS);
1368
1369     retv = dbg_main_loop(hFile);
1370     /* don't save modified variables in auto mode */
1371     if (dbg_action_mode != automatic_mode) dbg_save_internal_vars();
1372
1373 leave:
1374     return retv;
1375
1376 oom_leave:
1377     dbg_printf("Out of memory\n");
1378     return retv;
1379 }