Pentium Pro changes from John Hassey
[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},
9cbf6c0e 130 {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV},
24e60978
SC
131 {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP},
132 {DBG_CONTROL_C, TARGET_SIGNAL_INT},
133 {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP},
134 {-1, -1}};
135
136
137static void
138check (BOOL ok, const char *file, int line)
139{
140 if (!ok)
141 printf_filtered ("error return %s:%d was %d\n", file, line, GetLastError ());
142}
143
144static void
145child_fetch_inferior_registers (int r)
146{
147 if (r < 0)
148 {
149 for (r = 0; r < NUM_REGS; r++)
150 child_fetch_inferior_registers (r);
151 }
152 else
153 {
154 supply_register (r, mappings[r].incontext);
155 }
156}
157
158static void
159child_store_inferior_registers (int r)
160{
161 if (r < 0)
162 {
163 for (r = 0; r < NUM_REGS; r++)
164 child_store_inferior_registers (r);
165 }
166 else
167 {
168 read_register_gen (r, mappings[r].incontext);
169 }
170}
171
172
173/* Wait for child to do something. Return pid of child, or -1 in case
174 of error; store status through argument pointer OURSTATUS. */
175
176
177static void
178handle_load_dll (DEBUG_EVENT * event)
179{
180 DWORD dll_name_ptr;
181 DWORD done;
182
183 ReadProcessMemory (current_process,
184 (DWORD) event->u.LoadDll.lpImageName,
185 (char *) &dll_name_ptr,
186 sizeof (dll_name_ptr), &done);
187
188 /* See if we could read the address of a string, and that the
189 address isn't null. */
190
191 if (done == sizeof (dll_name_ptr) && dll_name_ptr)
192 {
193 char *dll_name;
194 int size = event->u.LoadDll.fUnicode ? sizeof (WCHAR) : sizeof (char);
195 int len = 0;
196 char b[2];
197 do
198 {
199 ReadProcessMemory (current_process,
200 dll_name_ptr + len * size,
201 &b,
202 size,
203 &done);
204 len++;
205 }
206 while ((b[0] != 0 || b[size - 1] != 0) && done == size);
207
208
209 dll_name = alloca (len);
210
211 if (event->u.LoadDll.fUnicode)
212 {
213 WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR));
214 ReadProcessMemory (current_process,
215 dll_name_ptr,
216 unicode_dll_name,
217 len * sizeof (WCHAR),
218 &done);
219
220 WideCharToMultiByte (CP_ACP, 0,
221 unicode_dll_name, len,
222 dll_name, len, 0, 0);
223 }
224 else
225 {
226 ReadProcessMemory (current_process,
227 dll_name_ptr,
228 dll_name,
229 len,
230 &done);
231 }
232
233 /* FIXME!! It would be nice to define one symbol which pointed to the
234 front of the dll if we can't find any symbols. */
235
236 context.ContextFlags = CONTEXT_FULL;
237 GetThreadContext (current_thread, &context);
238
239 symbol_file_add (dll_name, 0, (int) event->u.LoadDll.lpBaseOfDll, 0, 0, 0);
240
241 /* We strip off the path of the dll for tidiness. */
242 if (strrchr (dll_name, '\\'))
243 dll_name = strrchr (dll_name, '\\') + 1;
244 printf_unfiltered ("%x:%s\n", event->u.LoadDll.lpBaseOfDll, dll_name);
245 }
246}
247
248
249static void
250handle_exception (DEBUG_EVENT * event, struct target_waitstatus *ourstatus)
251{
252 int i;
253 int done = 0;
254 ourstatus->kind = TARGET_WAITKIND_STOPPED;
255
256 for (i = 0; !done && xlate[i].us > 0; i++)
257 {
258 if (xlate[i].them == event->u.Exception.ExceptionRecord.ExceptionCode)
259 {
260 ourstatus->value.sig = xlate[i].us;
261 done = 1;
262 break;
263 }
264 }
265
266 if (!done)
267 {
268 printf_unfiltered ("Want to know about exception code %08x\n",
269 event->u.Exception.ExceptionRecord.ExceptionCode);
270 ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
271 }
272 context.ContextFlags = CONTEXT_FULL;
273 GetThreadContext (current_thread, &context);
274 exception_count++;
275}
276
277static int
278child_wait (int pid, struct target_waitstatus *ourstatus)
279{
280 /* We loop when we get a non-standard exception rather than return
281 with a SPURIOUS because resume can try and step or modify things,
282 which needs a current_thread. But some of these exceptions mark
283 the birth or death of threads, which mean that the current thread
284 isn't necessarily what you think it is. */
285
286 while (1)
287 {
288 DEBUG_EVENT event;
289 BOOL t = WaitForDebugEvent (&event, INFINITE);
290
291 DEBUG (("%d = WaitForDebugEvent() code=%d pid=%d tid=%d)\n",
292 t,
293 event.dwDebugEventCode,
294 event.dwProcessId,
295 event.dwThreadId));
296
297 event_count++;
298
299 current_thread_id = event.dwThreadId;
300 current_process_id = event.dwProcessId;
301
302 switch (event.dwDebugEventCode)
303 {
304 case CREATE_THREAD_DEBUG_EVENT:
305 case EXIT_THREAD_DEBUG_EVENT:
306 case CREATE_PROCESS_DEBUG_EVENT:
307 break;
308
309 case EXIT_PROCESS_DEBUG_EVENT:
310 ourstatus->kind = TARGET_WAITKIND_EXITED;
311 ourstatus->value.integer = event.u.ExitProcess.dwExitCode;
312 CloseHandle (current_process);
313 CloseHandle (current_thread);
314 return current_process_id;
315 break;
316
317 case LOAD_DLL_DEBUG_EVENT:
318 handle_load_dll (&event);
319 break;
320 case EXCEPTION_DEBUG_EVENT:
321 handle_exception (&event, ourstatus);
322 return current_process_id;
323 default:
324 printf_unfiltered ("waitfor it %d %d %d %d\n", t,
325 event.dwDebugEventCode,
326 event.dwProcessId,
327 event.dwThreadId);
328 break;
329 }
330 CHECK (ContinueDebugEvent (current_process_id,
331 current_thread_id,
332 DBG_CONTINUE));
333 }
334}
335
336
337
338
339/* Attach to process PID, then initialize for debugging it. */
340
341static void
342child_attach (args, from_tty)
343 char *args;
344 int from_tty;
345{
346 BOOL ok;
347
348 if (!args)
349 error_no_arg ("process-id to attach");
350
351 current_process_id = strtoul (args, 0, 0);
352
353 ok = DebugActiveProcess (current_process_id);
354
355 if (!ok)
356 error ("Can't attach to process.");
357
358
359 exception_count = 0;
360 event_count = 0;
361
362 if (from_tty)
363 {
364 char *exec_file = (char *) get_exec_file (0);
365
366 if (exec_file)
367 printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
368 target_pid_to_str (current_process_id));
369 else
370 printf_unfiltered ("Attaching to %s\n",
371 target_pid_to_str (current_process_id));
372
373 gdb_flush (gdb_stdout);
374 }
375
376 inferior_pid = current_process_id;
377 push_target (&child_ops);
378}
379
380
381static void
382child_detach (args, from_tty)
383 char *args;
384 int from_tty;
385{
386 if (from_tty)
387 {
388 char *exec_file = get_exec_file (0);
389 if (exec_file == 0)
390 exec_file = "";
391 printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
392 target_pid_to_str (inferior_pid));
393 gdb_flush (gdb_stdout);
394 }
395 inferior_pid = 0;
396 unpush_target (&child_ops);
397}
398
399
400/* Print status information about what we're accessing. */
401
402static void
403child_files_info (ignore)
404 struct target_ops *ignore;
405{
406 printf_unfiltered ("\tUsing the running image of %s %s.\n",
407 attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
408}
409
410/* ARGSUSED */
411static void
412child_open (arg, from_tty)
413 char *arg;
414 int from_tty;
415{
416 error ("Use the \"run\" command to start a Unix child process.");
417}
418
24e60978 419
eb708f2e 420/* Start an inferior win32 child process and sets inferior_pid to its pid.
24e60978
SC
421 EXEC_FILE is the file to run.
422 ALLARGS is a string containing the arguments to the program.
423 ENV is the environment vector to pass. Errors reported with error(). */
424
425
426static void
427child_create_inferior (exec_file, allargs, env)
428 char *exec_file;
429 char *allargs;
430 char **env;
431{
432 char *real_path;
433 STARTUPINFO si;
434 PROCESS_INFORMATION pi;
435 struct target_waitstatus dummy;
436 BOOL ret;
437 DWORD flags;
eb708f2e 438 char *args;
24e60978
SC
439
440 if (!exec_file)
441 {
442 error ("No executable specified, use `target exec'.\n");
443 }
444
445 memset (&si, 0, sizeof (si));
446 si.cb = sizeof (si);
447
448 /* A realpath is always the same size, or a bit shorter than a nice path. */
449 real_path = alloca (strlen (exec_file) + 1);
450 path_to_real_path (exec_file, real_path);
451
452 flags = DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS;
453
454 if (new_group)
455 flags |= CREATE_NEW_PROCESS_GROUP;
456
457 if (new_console)
458 flags |= CREATE_NEW_CONSOLE;
459
eb708f2e
SC
460 args = alloca (strlen (exec_file) + strlen (allargs) + 2);
461
462 strcpy (args, exec_file);
463 strcat (args, " ");
464 strcat (args, allargs);
465
24e60978 466 ret = CreateProcess (real_path,
eb708f2e 467 args,
24e60978
SC
468 NULL, /* Security */
469 NULL, /* thread */
470 TRUE, /* inherit handles */
471 flags, /* start flags */
472 env,
473 NULL, /* current directory */
474 &si,
475 &pi);
476 if (!ret)
686941a9 477 error ("Error creating process %s, (error %d)\n", exec_file, GetLastError());
24e60978
SC
478
479 exception_count = 0;
480 event_count = 0;
481
482 inferior_pid = pi.dwProcessId;
483 current_process = pi.hProcess;
484 current_thread = pi.hThread;
485 current_process_id = pi.dwProcessId;
486 current_thread_id = pi.dwThreadId;
487 push_target (&child_ops);
488 init_thread_list ();
489 init_wait_for_inferior ();
490 clear_proceed_status ();
491 target_terminal_init ();
492 target_terminal_inferior ();
493
494 /* Ignore the first trap */
495 child_wait (inferior_pid, &dummy);
496
497 proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
498}
499
500static void
501child_mourn_inferior ()
502{
503 unpush_target (&child_ops);
504 generic_mourn_inferior ();
505}
506
507
508/* Send a SIGINT to the process group. This acts just like the user typed a
509 ^C on the controlling terminal. */
510
511void
512child_stop ()
513{
514 CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0));
515}
516
517int
eb708f2e
SC
518child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
519 int write, struct target_ops *target)
24e60978
SC
520{
521 DWORD done;
522 if (write)
523 {
524 WriteProcessMemory (current_process, memaddr, our, len, &done);
525 FlushInstructionCache (current_process, memaddr, len);
526 }
527 else
528 {
529 ReadProcessMemory (current_process, memaddr, our, len, &done);
530 }
531 return done;
532}
533
534void
535child_kill_inferior (void)
536{
537 CHECK (TerminateProcess (current_process, 0));
538 CHECK (CloseHandle (current_process));
539 CHECK (CloseHandle (current_thread));
540}
541
542void
543child_resume (int pid, int step, enum target_signal signal)
544{
545 DEBUG (("child_resume (%d, %d, %d);\n", pid, step, signal));
546
547 if (step)
548 {
549 /* Single step by setting t bit */
550 child_fetch_inferior_registers (PS_REGNUM);
551 context.EFlags |= FLAG_TRACE_BIT;
552 }
553
554 if (context.ContextFlags)
555 {
556 CHECK (SetThreadContext (current_thread, &context));
557 context.ContextFlags = 0;
558 }
559
560 if (signal)
561 {
562 fprintf_unfiltered (gdb_stderr, "Can't send signals to the child.\n");
563 }
564
565 CHECK (ContinueDebugEvent (current_process_id,
566 current_thread_id,
567 DBG_CONTINUE));
568}
569
570static void
571child_prepare_to_store ()
572{
573 /* Do nothing, since we can store individual regs */
574}
575
576static int
577child_can_run ()
578{
579 return 1;
580}
581
582static void
583child_close ()
584{
585
586}
587struct target_ops child_ops =
588{
589 "child", /* to_shortname */
590 "Win32 child process", /* to_longname */
591 "Win32 child process (started by the \"run\" command).", /* to_doc */
592 child_open, /* to_open */
593 child_close, /* to_close */
594 child_attach, /* to_attach */
595 child_detach, /* to_detach */
596 child_resume, /* to_resume */
597 child_wait, /* to_wait */
598 child_fetch_inferior_registers,/* to_fetch_registers */
599 child_store_inferior_registers,/* to_store_registers */
600 child_prepare_to_store, /* to_child_prepare_to_store */
601 child_xfer_memory, /* to_xfer_memory */
602 child_files_info, /* to_files_info */
603 memory_insert_breakpoint, /* to_insert_breakpoint */
604 memory_remove_breakpoint, /* to_remove_breakpoint */
605 terminal_init_inferior, /* to_terminal_init */
606 terminal_inferior, /* to_terminal_inferior */
607 terminal_ours_for_output, /* to_terminal_ours_for_output */
608 terminal_ours, /* to_terminal_ours */
609 child_terminal_info, /* to_terminal_info */
610 child_kill_inferior, /* to_kill */
611 0, /* to_load */
612 0, /* to_lookup_symbol */
613 child_create_inferior, /* to_create_inferior */
614 child_mourn_inferior, /* to_mourn_inferior */
615 child_can_run, /* to_can_run */
616 0, /* to_notice_signals */
617 0, /* to_thread_alive */
618 child_stop, /* to_stop */
619 process_stratum, /* to_stratum */
620 0, /* to_next */
621 1, /* to_has_all_memory */
622 1, /* to_has_memory */
623 1, /* to_has_stack */
624 1, /* to_has_registers */
625 1, /* to_has_execution */
626 0, /* to_sections */
627 0, /* to_sections_end */
628 OPS_MAGIC /* to_magic */
629};
630
631void
632_initialize_inftarg ()
633{
634 add_show_from_set
635 (add_set_cmd ("new-console", class_support, var_boolean,
636 (char *) &new_console,
637 "Set creation of new console when creating child process.",
638 &setlist),
639 &showlist);
640
641 add_show_from_set
642 (add_set_cmd ("new-group", class_support, var_boolean,
643 (char *) &new_group,
644 "Set creation of new group when creating child process.",
645 &setlist),
646 &showlist);
647
648 add_target (&child_ops);
649}
This page took 0.077229 seconds and 4 git commands to generate.