* Makefile.in (FLAGS_TO_PASS): Remote BISON.
[deliverable/binutils-gdb.git] / gdb / win32-nat.c
CommitLineData
24e60978
SC
1/* Target-vector operations for controlling win32 child processes, for GDB.
2 Copyright 1996
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
418/* Stub function which causes the inferior that runs it, to be ptrace-able
419 by its parent process. */
420
421
422/* Start an inferior Unix child process and sets inferior_pid to its pid.
423 EXEC_FILE is the file to run.
424 ALLARGS is a string containing the arguments to the program.
425 ENV is the environment vector to pass. Errors reported with error(). */
426
427
428static void
429child_create_inferior (exec_file, allargs, env)
430 char *exec_file;
431 char *allargs;
432 char **env;
433{
434 char *real_path;
435 STARTUPINFO si;
436 PROCESS_INFORMATION pi;
437 struct target_waitstatus dummy;
438 BOOL ret;
439 DWORD flags;
440
441 if (!exec_file)
442 {
443 error ("No executable specified, use `target exec'.\n");
444 }
445
446 memset (&si, 0, sizeof (si));
447 si.cb = sizeof (si);
448
449 /* A realpath is always the same size, or a bit shorter than a nice path. */
450 real_path = alloca (strlen (exec_file) + 1);
451 path_to_real_path (exec_file, real_path);
452
453 flags = DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS;
454
455 if (new_group)
456 flags |= CREATE_NEW_PROCESS_GROUP;
457
458 if (new_console)
459 flags |= CREATE_NEW_CONSOLE;
460
461 ret = CreateProcess (real_path,
462 allargs,
463 NULL, /* Security */
464 NULL, /* thread */
465 TRUE, /* inherit handles */
466 flags, /* start flags */
467 env,
468 NULL, /* current directory */
469 &si,
470 &pi);
471 if (!ret)
472 error ("Error creating process %s\n", exec_file);
473
474 exception_count = 0;
475 event_count = 0;
476
477 inferior_pid = pi.dwProcessId;
478 current_process = pi.hProcess;
479 current_thread = pi.hThread;
480 current_process_id = pi.dwProcessId;
481 current_thread_id = pi.dwThreadId;
482 push_target (&child_ops);
483 init_thread_list ();
484 init_wait_for_inferior ();
485 clear_proceed_status ();
486 target_terminal_init ();
487 target_terminal_inferior ();
488
489 /* Ignore the first trap */
490 child_wait (inferior_pid, &dummy);
491
492 proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
493}
494
495static void
496child_mourn_inferior ()
497{
498 unpush_target (&child_ops);
499 generic_mourn_inferior ();
500}
501
502
503/* Send a SIGINT to the process group. This acts just like the user typed a
504 ^C on the controlling terminal. */
505
506void
507child_stop ()
508{
509 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
510}
511
512int
513child_xfer_memory (CORE_ADDR memaddr, char *our, int len, int write, struct target_ops *target)
514{
515 DWORD done;
516 if (write)
517 {
518 WriteProcessMemory (current_process, memaddr, our, len, &done);
519 FlushInstructionCache (current_process, memaddr, len);
520 }
521 else
522 {
523 ReadProcessMemory (current_process, memaddr, our, len, &done);
524 }
525 return done;
526}
527
528void
529child_kill_inferior (void)
530{
531 CHECK (TerminateProcess (current_process, 0));
532 CHECK (CloseHandle (current_process));
533 CHECK (CloseHandle (current_thread));
534}
535
536void
537child_resume (int pid, int step, enum target_signal signal)
538{
539 DEBUG (("child_resume (%d, %d, %d);\n", pid, step, signal));
540
541 if (step)
542 {
543 /* Single step by setting t bit */
544 child_fetch_inferior_registers (PS_REGNUM);
545 context.EFlags |= FLAG_TRACE_BIT;
546 }
547
548 if (context.ContextFlags)
549 {
550 CHECK (SetThreadContext (current_thread, &context));
551 context.ContextFlags = 0;
552 }
553
554 if (signal)
555 {
556 fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.\n");
557 }
558
559 CHECK (ContinueDebugEvent (current_process_id,
560 current_thread_id,
561 DBG_CONTINUE));
562}
563
564static void
565child_prepare_to_store ()
566{
567 /* Do nothing, since we can store individual regs */
568}
569
570static int
571child_can_run ()
572{
573 return 1;
574}
575
576static void
577child_close ()
578{
579
580}
581struct target_ops child_ops =
582{
583 "child", /* to_shortname */
584 "Win32 child process", /* to_longname */
585 "Win32 child process (started by the \"run\" command).", /* to_doc */
586 child_open, /* to_open */
587 child_close, /* to_close */
588 child_attach, /* to_attach */
589 child_detach, /* to_detach */
590 child_resume, /* to_resume */
591 child_wait, /* to_wait */
592 child_fetch_inferior_registers,/* to_fetch_registers */
593 child_store_inferior_registers,/* to_store_registers */
594 child_prepare_to_store, /* to_child_prepare_to_store */
595 child_xfer_memory, /* to_xfer_memory */
596 child_files_info, /* to_files_info */
597 memory_insert_breakpoint, /* to_insert_breakpoint */
598 memory_remove_breakpoint, /* to_remove_breakpoint */
599 terminal_init_inferior, /* to_terminal_init */
600 terminal_inferior, /* to_terminal_inferior */
601 terminal_ours_for_output, /* to_terminal_ours_for_output */
602 terminal_ours, /* to_terminal_ours */
603 child_terminal_info, /* to_terminal_info */
604 child_kill_inferior, /* to_kill */
605 0, /* to_load */
606 0, /* to_lookup_symbol */
607 child_create_inferior, /* to_create_inferior */
608 child_mourn_inferior, /* to_mourn_inferior */
609 child_can_run, /* to_can_run */
610 0, /* to_notice_signals */
611 0, /* to_thread_alive */
612 child_stop, /* to_stop */
613 process_stratum, /* to_stratum */
614 0, /* to_next */
615 1, /* to_has_all_memory */
616 1, /* to_has_memory */
617 1, /* to_has_stack */
618 1, /* to_has_registers */
619 1, /* to_has_execution */
620 0, /* to_sections */
621 0, /* to_sections_end */
622 OPS_MAGIC /* to_magic */
623};
624
625void
626_initialize_inftarg ()
627{
628 add_show_from_set
629 (add_set_cmd ("new-console", class_support, var_boolean,
630 (char *) &new_console,
631 "Set creation of new console when creating child process.",
632 &setlist),
633 &showlist);
634
635 add_show_from_set
636 (add_set_cmd ("new-group", class_support, var_boolean,
637 (char *) &new_group,
638 "Set creation of new group when creating child process.",
639 &setlist),
640 &showlist);
641
642 add_target (&child_ops);
643}
This page took 0.045013 seconds and 4 git commands to generate.