Sat Oct 28 23:51:48 1995 steve chamberlain <sac@slash.cygnus.com>
[deliverable/binutils-gdb.git] / gdb / win32-nat.c
CommitLineData
24e60978 1/* Target-vector operations for controlling win32 child processes, for GDB.
eb708f2e 2 Copyright 1995
24e60978
SC
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 */
45extern struct target_ops child_ops;
46
47/* The most recently read context. Inspect ContextFlags to see what
48 bits are valid. */
49
50static CONTEXT context;
51
52/* The process and thread handles for the above context. */
53
54static HANDLE current_process;
55static HANDLE current_thread;
56static int current_process_id;
57static int current_thread_id;
58
59/* Counts of things. */
60static int exception_count = 0;
61static int event_count = 0;
62
63/* User options. */
64static int new_console = 0;
65static 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
80struct regmappings
81 {
82 char *incontext;
83 int mask;
84 };
85
86static 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
119struct xlate_exception
120 {
121 int them;
122 enum target_signal us;
123 };
124
125
126static 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
136static void
137check (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
143static void
144child_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
157static void
158child_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
176static void
177handle_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
248static void
249handle_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
276static int
277child_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
340static void
341child_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
380static void
381child_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
401static void
402child_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 */
410static void
411child_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
24e60978 418
eb708f2e 419/* Start an inferior win32 child process and sets inferior_pid to its pid.
24e60978
SC
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
425static void
426child_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;
eb708f2e 437 char *args;
24e60978
SC
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
eb708f2e
SC
459 args = alloca (strlen (exec_file) + strlen (allargs) + 2);
460
461 strcpy (args, exec_file);
462 strcat (args, " ");
463 strcat (args, allargs);
464
24e60978 465 ret = CreateProcess (real_path,
eb708f2e 466 args,
24e60978
SC
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)
686941a9 476 error ("Error creating process %s, (error %d)\n", exec_file, GetLastError());
24e60978
SC
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
499static void
500child_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
510void
511child_stop ()
512{
513 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
514}
515
516int
eb708f2e
SC
517child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
518 int write, struct target_ops *target)
24e60978
SC
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
533void
534child_kill_inferior (void)
535{
536 CHECK (TerminateProcess (current_process, 0));
537 CHECK (CloseHandle (current_process));
538 CHECK (CloseHandle (current_thread));
539}
540
541void
542child_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
569static void
570child_prepare_to_store ()
571{
572 /* Do nothing, since we can store individual regs */
573}
574
575static int
576child_can_run ()
577{
578 return 1;
579}
580
581static void
582child_close ()
583{
584
585}
586struct 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
630void
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}
This page took 0.047462 seconds and 4 git commands to generate.