Sat Oct 28 23:51:48 1995 steve chamberlain <sac@slash.cygnus.com>
[external/binutils.git] / gdb / win32-nat.c
1 /* Target-vector operations for controlling win32 child processes, for GDB.
2    Copyright 1995
3    Free Software Foundation, Inc.
4
5    Contributed by Cygnus Support.
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without eve nthe implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22 /* by Steve Chamberlain, sac@cygnus.com */
23
24 #include "defs.h"
25 #include "frame.h"              /* required by inferior.h */
26 #include "inferior.h"
27 #include "target.h"
28 #include "wait.h"
29 #include "gdbcore.h"
30 #include "command.h"
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <windows.h>
35 #include "buildsym.h"
36 #include "gdb_string.h"
37 #include "thread.h"
38 #include "gdbcmd.h"
39
40 #define CHECK(x) check (x, __FILE__,__LINE__)
41 #define DEBUG(x) if (remote_debug) printf x
42
43
44 /* Forward declaration */
45 extern struct target_ops child_ops;
46
47 /* The most recently read context. Inspect ContextFlags to see what 
48    bits are valid. */
49
50 static CONTEXT context;
51
52 /* The process and thread handles for the above context. */
53
54 static HANDLE current_process;
55 static HANDLE current_thread;
56 static int current_process_id;
57 static int current_thread_id;
58
59 /* Counts of things. */
60 static int exception_count = 0;
61 static int event_count = 0;
62
63 /* User options. */
64 static int new_console = 0;
65 static int new_group = 0;
66
67 /* This vector maps GDB's idea of a register's number into an address
68    in the win32 exception context vector. 
69
70    It also contains the bit mask needed to load the register in question.  
71
72    One day we could read a reg, we could inspect the context we
73    already have loaded, if it doesn't have the bit set that we need,
74    we read that set of registers in using GetThreadContext.  If the
75    context already contains what we need, we just unpack it. Then to
76    write a register, first we have to ensure that the context contains
77    the other regs of the group, and then we copy the info in and set
78    out bit. */
79
80 struct regmappings
81   {
82     char *incontext;
83     int mask;
84   };
85
86 static const struct regmappings
87   mappings[] =
88 {
89   {(char *) &context.Eax, CONTEXT_INTEGER},
90   {(char *) &context.Ecx, CONTEXT_INTEGER},
91   {(char *) &context.Edx, CONTEXT_INTEGER},
92   {(char *) &context.Ebx, CONTEXT_INTEGER},
93   {(char *) &context.Esp, CONTEXT_CONTROL},
94   {(char *) &context.Ebp, CONTEXT_CONTROL},
95   {(char *) &context.Esi, CONTEXT_INTEGER},
96   {(char *) &context.Edi, CONTEXT_INTEGER},
97   {(char *) &context.Eip, CONTEXT_CONTROL},
98   {(char *) &context.EFlags, CONTEXT_CONTROL},
99   {(char *) &context.SegCs, CONTEXT_SEGMENTS},
100   {(char *) &context.SegSs, CONTEXT_SEGMENTS},
101   {(char *) &context.SegDs, CONTEXT_SEGMENTS},
102   {(char *) &context.SegEs, CONTEXT_SEGMENTS},
103   {(char *) &context.SegFs, CONTEXT_SEGMENTS},
104   {(char *) &context.SegGs, CONTEXT_SEGMENTS},
105   {&context.FloatSave.RegisterArea[0 * 10], CONTEXT_FLOATING_POINT},
106   {&context.FloatSave.RegisterArea[1 * 10], CONTEXT_FLOATING_POINT},
107   {&context.FloatSave.RegisterArea[2 * 10], CONTEXT_FLOATING_POINT},
108   {&context.FloatSave.RegisterArea[3 * 10], CONTEXT_FLOATING_POINT},
109   {&context.FloatSave.RegisterArea[4 * 10], CONTEXT_FLOATING_POINT},
110   {&context.FloatSave.RegisterArea[5 * 10], CONTEXT_FLOATING_POINT},
111   {&context.FloatSave.RegisterArea[6 * 10], CONTEXT_FLOATING_POINT},
112   {&context.FloatSave.RegisterArea[7 * 10], CONTEXT_FLOATING_POINT},
113 };
114
115
116 /* This vector maps the target's idea of an exception (extracted
117    from the DEBUG_EVENT structure) to GDB's idea. */
118
119 struct xlate_exception
120   {
121     int them;
122     enum target_signal us;
123   };
124
125
126 static const struct xlate_exception
127   xlate[] =
128 {
129   {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV},
130   {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
131   {DBG_CONTROL_C, TARGET_SIGNAL_INT},
132   {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
133   {-1, -1}};
134
135
136 static void 
137 check (BOOL ok, const char *file, int line)
138 {
139   if (!ok)
140     printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
141 }
142
143 static void
144 child_fetch_inferior_registers (int r)
145 {
146   if (r < 0)
147     {
148       for (r = 0; r < NUM_REGS; r++)
149         child_fetch_inferior_registers (r);
150     }
151   else
152     {
153       supply_register (r, mappings[r].incontext);
154     }
155 }
156
157 static void
158 child_store_inferior_registers (int r)
159 {
160   if (r < 0)
161     {
162       for (r = 0; r < NUM_REGS; r++)
163         child_store_inferior_registers (r);
164     }
165   else
166     {
167       read_register_gen (r, mappings[r].incontext);
168     }
169 }
170
171
172 /* Wait for child to do something.  Return pid of child, or -1 in case
173    of error; store status through argument pointer OURSTATUS.  */
174
175
176 static void 
177 handle_load_dll (DEBUG_EVENT * event)
178 {
179   DWORD dll_name_ptr;
180   DWORD done;
181
182   ReadProcessMemory (current_process,
183                      (DWORD) event->u.LoadDll.lpImageName,
184                      (char *) &dll_name_ptr,
185                      sizeof (dll_name_ptr), &done);
186
187   /* See if we could read the address of a string, and that the 
188      address isn't null. */
189
190   if (done == sizeof (dll_name_ptr) && dll_name_ptr)
191     {
192       char *dll_name;
193       int size = event->u.LoadDll.fUnicode ? sizeof (WCHAR) : sizeof (char);
194       int len = 0;
195       char b[2];
196       do
197         {
198           ReadProcessMemory (current_process,
199                              dll_name_ptr + len * size,
200                              &b,
201                              size,
202                              &done);
203           len++;
204         }
205       while ((b[0] != 0 || b[size - 1] != 0) && done == size);
206
207
208       dll_name = alloca (len);
209
210       if (event->u.LoadDll.fUnicode)
211         {
212           WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR));
213           ReadProcessMemory (current_process,
214                              dll_name_ptr,
215                              unicode_dll_name,
216                              len * sizeof (WCHAR),
217                              &done);
218
219           WideCharToMultiByte (CP_ACP, 0,
220                                unicode_dll_name, len,
221                                dll_name, len, 0, 0);
222         }
223       else
224         {
225           ReadProcessMemory (current_process,
226                              dll_name_ptr,
227                              dll_name,
228                              len,
229                              &done);
230         }
231
232       /* FIXME!! It would be nice to define one symbol which pointed to the 
233          front of the dll if we can't find any symbols. */
234
235       context.ContextFlags = CONTEXT_FULL;
236       GetThreadContext (current_thread, &context);
237
238       symbol_file_add (dll_name, 0, (int) event->u.LoadDll.lpBaseOfDll, 0, 0, 0);
239
240       /* We strip off the path of the dll for tidiness. */
241       if (strrchr (dll_name, '\\'))
242         dll_name = strrchr (dll_name, '\\') + 1;
243       printf_unfiltered ("%x:%s\n", event->u.LoadDll.lpBaseOfDll, dll_name);
244     }
245 }
246
247
248 static void
249 handle_exception (DEBUG_EVENT * event, struct target_waitstatus *ourstatus)
250 {
251   int i;
252   int done = 0;
253   ourstatus->kind = TARGET_WAITKIND_STOPPED;
254
255   for (i = 0; !done && xlate[i].us > 0; i++)
256     {
257       if (xlate[i].them == event->u.Exception.ExceptionRecord.ExceptionCode)
258         {
259           ourstatus->value.sig = xlate[i].us;
260           done = 1;
261           break;
262         }
263     }
264
265   if (!done)
266     {
267       printf_unfiltered ("Want to know about exception code %08x\n",
268                          event->u.Exception.ExceptionRecord.ExceptionCode);
269       ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
270     }
271   context.ContextFlags = CONTEXT_FULL;
272   GetThreadContext (current_thread, &context);
273   exception_count++;
274 }
275
276 static int
277 child_wait (int pid, struct target_waitstatus *ourstatus)
278 {
279   /* We loop when we get a non-standard exception rather than return
280      with a SPURIOUS because resume can try and step or modify things,
281      which needs a current_thread.  But some of these exceptions mark
282      the birth or death of threads, which mean that the current thread
283      isn't necessarily what you think it is. */
284
285   while (1)
286     {
287       DEBUG_EVENT event;
288       BOOL t = WaitForDebugEvent (&event, INFINITE);
289
290       DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
291               t,
292               event.dwDebugEventCode,
293               event.dwProcessId,
294               event.dwThreadId));
295
296       event_count++;
297
298       current_thread_id = event.dwThreadId;
299       current_process_id = event.dwProcessId;
300
301       switch (event.dwDebugEventCode)
302         {
303         case CREATE_THREAD_DEBUG_EVENT:
304         case EXIT_THREAD_DEBUG_EVENT:
305         case CREATE_PROCESS_DEBUG_EVENT:
306           break;
307
308         case EXIT_PROCESS_DEBUG_EVENT:
309           ourstatus->kind = TARGET_WAITKIND_EXITED;
310           ourstatus->value.integer = event.u.ExitProcess.dwExitCode;
311           CloseHandle (current_process);
312           CloseHandle (current_thread);
313           return current_process_id;
314           break;
315
316         case LOAD_DLL_DEBUG_EVENT:
317           handle_load_dll (&event);
318           break;
319         case EXCEPTION_DEBUG_EVENT:
320           handle_exception (&event, ourstatus);
321           return current_process_id;
322         default:
323           printf_unfiltered ("waitfor it %d %d %d %d\n", t,
324                              event.dwDebugEventCode,
325                              event.dwProcessId,
326                              event.dwThreadId);
327           break;
328         }
329       CHECK (ContinueDebugEvent (current_process_id,
330                                  current_thread_id,
331                                  DBG_CONTINUE));
332     }
333 }
334
335
336
337
338 /* Attach to process PID, then initialize for debugging it.  */
339
340 static void
341 child_attach (args, from_tty)
342      char *args;
343      int from_tty;
344 {
345   BOOL ok;
346
347   if (!args)
348     error_no_arg ("process-id to attach");
349
350   current_process_id = strtoul (args, 0, 0);
351
352   ok = DebugActiveProcess (current_process_id);
353
354   if (!ok)
355     error ("Can't attach to process.");
356
357
358   exception_count = 0;
359   event_count = 0;
360
361   if (from_tty)
362     {
363       char *exec_file = (char *) get_exec_file (0);
364
365       if (exec_file)
366         printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
367                            target_pid_to_str (current_process_id));
368       else
369         printf_unfiltered ("Attaching to %s\n",
370                            target_pid_to_str (current_process_id));
371
372       gdb_flush (gdb_stdout);
373     }
374
375   inferior_pid = current_process_id;
376   push_target (&child_ops);
377 }
378
379
380 static void
381 child_detach (args, from_tty)
382      char *args;
383      int from_tty;
384 {
385   if (from_tty)
386     {
387       char *exec_file = get_exec_file (0);
388       if (exec_file == 0)
389         exec_file = "";
390       printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
391                          target_pid_to_str (inferior_pid));
392       gdb_flush (gdb_stdout);
393     }
394   inferior_pid = 0;
395   unpush_target (&child_ops);
396 }
397
398
399 /* Print status information about what we're accessing.  */
400
401 static void
402 child_files_info (ignore)
403      struct target_ops *ignore;
404 {
405   printf_unfiltered ("\tUsing the running image of %s %s.\n",
406       attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
407 }
408
409 /* ARGSUSED */
410 static void
411 child_open (arg, from_tty)
412      char *arg;
413      int from_tty;
414 {
415   error ("Use the \"run\" command to start a Unix child process.");
416 }
417
418
419 /* Start an inferior win32 child process and sets inferior_pid to its pid.
420    EXEC_FILE is the file to run.
421    ALLARGS is a string containing the arguments to the program.
422    ENV is the environment vector to pass.  Errors reported with error().  */
423
424
425 static void
426 child_create_inferior (exec_file, allargs, env)
427      char *exec_file;
428      char *allargs;
429      char **env;
430 {
431   char *real_path;
432   STARTUPINFO si;
433   PROCESS_INFORMATION pi;
434   struct target_waitstatus dummy;
435   BOOL ret;
436   DWORD flags;
437   char *args;
438
439   if (!exec_file)
440     {
441       error ("No executable specified, use `target exec'.\n");
442     }
443
444   memset (&si, 0, sizeof (si));
445   si.cb = sizeof (si);
446
447   /* A realpath is always the same size, or a bit shorter than a nice path. */
448   real_path = alloca (strlen (exec_file) + 1);
449   path_to_real_path (exec_file, real_path);
450
451   flags = DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS;
452
453   if (new_group)
454     flags |= CREATE_NEW_PROCESS_GROUP;
455
456   if (new_console)
457     flags |= CREATE_NEW_CONSOLE;
458
459   args = alloca (strlen (exec_file) + strlen (allargs) + 2);
460
461   strcpy (args, exec_file);
462   strcat (args, " ");
463   strcat (args, allargs);
464
465   ret = CreateProcess (real_path,
466                        args,
467                        NULL,    /* Security */
468                        NULL,    /* thread */
469                        TRUE,    /* inherit handles */
470                        flags,   /* start flags */
471                        env,
472                        NULL,    /* current directory */
473                        &si,
474                        &pi);
475   if (!ret)
476     error ("Error creating process %s, (error %d)\n", exec_file, GetLastError());
477
478   exception_count = 0;
479   event_count = 0;
480
481   inferior_pid = pi.dwProcessId;
482   current_process = pi.hProcess;
483   current_thread = pi.hThread;
484   current_process_id = pi.dwProcessId;
485   current_thread_id = pi.dwThreadId;
486   push_target (&child_ops);
487   init_thread_list ();
488   init_wait_for_inferior ();
489   clear_proceed_status ();
490   target_terminal_init ();
491   target_terminal_inferior ();
492
493   /* Ignore the first trap */
494   child_wait (inferior_pid, &dummy);
495
496   proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
497 }
498
499 static void
500 child_mourn_inferior ()
501 {
502   unpush_target (&child_ops);
503   generic_mourn_inferior ();
504 }
505
506
507 /* Send a SIGINT to the process group.  This acts just like the user typed a
508    ^C on the controlling terminal. */
509
510 void
511 child_stop ()
512 {
513   CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
514 }
515
516 int
517 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
518                    int write, struct target_ops *target)
519 {
520   DWORD done;
521   if (write)
522     {
523       WriteProcessMemory (current_process, memaddr, our, len, &done);
524       FlushInstructionCache (current_process, memaddr, len);
525     }
526   else
527     {
528       ReadProcessMemory (current_process, memaddr, our, len, &done);
529     }
530   return done;
531 }
532
533 void
534 child_kill_inferior (void)
535 {
536   CHECK (TerminateProcess (current_process, 0));
537   CHECK (CloseHandle (current_process));
538   CHECK (CloseHandle (current_thread));
539 }
540
541 void
542 child_resume (int pid, int step, enum target_signal signal)
543 {
544   DEBUG (("child_resume (%d, %d, %d);\n", pid, step, signal));
545
546   if (step)
547     {
548       /* Single step by setting t bit */
549       child_fetch_inferior_registers (PS_REGNUM);
550       context.EFlags |= FLAG_TRACE_BIT;
551     }
552
553   if (context.ContextFlags)
554     {
555       CHECK (SetThreadContext (current_thread, &context));
556       context.ContextFlags = 0;
557     }
558
559   if (signal)
560     {
561       fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.\n");
562     }
563
564   CHECK (ContinueDebugEvent (current_process_id,
565                              current_thread_id,
566                              DBG_CONTINUE));
567 }
568
569 static void
570 child_prepare_to_store ()
571 {
572   /* Do nothing, since we can store individual regs */
573 }
574
575 static int
576 child_can_run ()
577 {
578   return 1;
579 }
580
581 static void
582 child_close ()
583 {
584
585 }
586 struct target_ops child_ops =
587 {
588   "child",                      /* to_shortname */
589   "Win32 child process",        /* to_longname */
590   "Win32 child process (started by the \"run\" command).",      /* to_doc */
591   child_open,                   /* to_open */
592   child_close,                  /* to_close */
593   child_attach,                 /* to_attach */
594   child_detach,                 /* to_detach */
595   child_resume,                 /* to_resume */
596   child_wait,                   /* to_wait */
597   child_fetch_inferior_registers,/* to_fetch_registers */
598   child_store_inferior_registers,/* to_store_registers */
599   child_prepare_to_store,       /* to_child_prepare_to_store */
600   child_xfer_memory,            /* to_xfer_memory */
601   child_files_info,             /* to_files_info */
602   memory_insert_breakpoint,     /* to_insert_breakpoint */
603   memory_remove_breakpoint,     /* to_remove_breakpoint */
604   terminal_init_inferior,       /* to_terminal_init */
605   terminal_inferior,            /* to_terminal_inferior */
606   terminal_ours_for_output,     /* to_terminal_ours_for_output */
607   terminal_ours,                /* to_terminal_ours */
608   child_terminal_info,          /* to_terminal_info */
609   child_kill_inferior,          /* to_kill */
610   0,                            /* to_load */
611   0,                            /* to_lookup_symbol */
612   child_create_inferior,        /* to_create_inferior */
613   child_mourn_inferior,         /* to_mourn_inferior */
614   child_can_run,                /* to_can_run */
615   0,                            /* to_notice_signals */
616   0,                            /* to_thread_alive */
617   child_stop,                   /* to_stop */
618   process_stratum,              /* to_stratum */
619   0,                            /* to_next */
620   1,                            /* to_has_all_memory */
621   1,                            /* to_has_memory */
622   1,                            /* to_has_stack */
623   1,                            /* to_has_registers */
624   1,                            /* to_has_execution */
625   0,                            /* to_sections */
626   0,                            /* to_sections_end */
627   OPS_MAGIC                     /* to_magic */
628 };
629
630 void
631 _initialize_inftarg ()
632 {
633   add_show_from_set
634     (add_set_cmd ("new-console", class_support, var_boolean,
635                   (char *) &new_console,
636                   "Set creation of new console when creating child process.",
637                   &setlist),
638      &showlist);
639
640   add_show_from_set
641     (add_set_cmd ("new-group", class_support, var_boolean,
642                   (char *) &new_group,
643                   "Set creation of new group when creating child process.",
644                   &setlist),
645      &showlist);
646
647   add_target (&child_ops);
648 }