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