* gdb_ptrace.h (PT_TRACE_ME): Define to zero if not already
[deliverable/binutils-gdb.git] / gdb / inf-ptrace.c
CommitLineData
2c4a536d 1/* Low-level child interface to ptrace.
5bf970f9
AC
2
3 Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
8785ced0
MK
4 1998, 1999, 2000, 2001, 2002, 2004, 2005
5 Free Software Foundation, Inc.
5bf970f9
AC
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24#include "defs.h"
5bf970f9 25#include "command.h"
2c4a536d
MK
26#include "inferior.h"
27#include "inflow.h"
5bf970f9 28#include "gdbcore.h"
2c4a536d 29#include "observer.h"
8785ced0 30#include "regcache.h"
5bf970f9 31
8785ced0 32#include "gdb_assert.h"
2c4a536d
MK
33#include "gdb_string.h"
34#include "gdb_ptrace.h"
34a17005 35#include "gdb_wait.h"
5bf970f9
AC
36#include <signal.h>
37
2c4a536d
MK
38#include "inf-child.h"
39
40/* HACK: Save the ptrace ops returned by inf_ptrace_target. */
5bf970f9 41static struct target_ops *ptrace_ops_hack;
c7c14b96
MK
42\f
43
4b8a1a28 44/* Prepare to be traced. */
5bf970f9
AC
45
46static void
c7c14b96 47inf_ptrace_me (void)
5bf970f9 48{
c7c14b96 49 /* "Trace me, Dr. Memory!" */
4b8a1a28 50 ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3)0, 0);
5bf970f9
AC
51}
52
4b8a1a28 53/* Start tracing PID. */
5bf970f9
AC
54
55static void
c7c14b96 56inf_ptrace_him (int pid)
5bf970f9 57{
c7c14b96 58 push_target (ptrace_ops_hack);
5bf970f9 59
c7c14b96
MK
60 /* On some targets, there must be some explicit synchronization
61 between the parent and child processes after the debugger
62 forks, and before the child execs the debuggee program. This
63 call basically gives permission for the child to exec. */
5bf970f9 64
c7c14b96 65 target_acknowledge_created_inferior (pid);
5bf970f9 66
c7c14b96
MK
67 /* START_INFERIOR_TRAPS_EXPECTED is defined in inferior.h, and will
68 be 1 or 2 depending on whether we're starting without or with a
69 shell. */
70 startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
71
72 /* On some targets, there must be some explicit actions taken after
73 the inferior has been started up. */
74 target_post_startup_inferior (pid_to_ptid (pid));
5bf970f9
AC
75}
76
4b8a1a28
MK
77/* Start a new inferior Unix child process. EXEC_FILE is the file to
78 run, ALLARGS is a string containing the arguments to the program.
79 ENV is the environment vector to pass. If FROM_TTY is non-zero, be
80 chatty about it. */
5bf970f9 81
c7c14b96
MK
82static void
83inf_ptrace_create_inferior (char *exec_file, char *allargs, char **env,
84 int from_tty)
5bf970f9 85{
c7c14b96
MK
86 fork_inferior (exec_file, allargs, env, inf_ptrace_me, inf_ptrace_him,
87 NULL, NULL);
4b8a1a28 88
c7c14b96
MK
89 /* We are at the first instruction we care about. */
90 observer_notify_inferior_created (&current_target, from_tty);
4b8a1a28 91
c7c14b96
MK
92 /* Pedal to the metal... */
93 proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
5bf970f9
AC
94}
95
4b8a1a28
MK
96/* Clean up a rotting corpse of an inferior after it died. */
97
c7c14b96
MK
98static void
99inf_ptrace_mourn_inferior (void)
5bf970f9 100{
4b8a1a28
MK
101 int status;
102
103 /* Wait just one more time to collect the inferior's exit status.
104 Don not check whether this succeeds though, since we may be
105 dealing with a process that we attached to. Such a process will
106 only report its exit status to its origional parent. */
107 waitpid (ptid_get_pid (inferior_ptid), &status, 0);
108
c7c14b96
MK
109 unpush_target (ptrace_ops_hack);
110 generic_mourn_inferior ();
5bf970f9
AC
111}
112
4b8a1a28
MK
113/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
114 be chatty about it. */
5bf970f9
AC
115
116static void
117inf_ptrace_attach (char *args, int from_tty)
118{
119 char *exec_file;
4b8a1a28 120 pid_t pid;
5bf970f9
AC
121 char *dummy;
122
123 if (!args)
e2e0b3e5 124 error_no_arg (_("process-id to attach"));
5bf970f9
AC
125
126 dummy = args;
127 pid = strtol (args, &dummy, 0);
f6ffd89b 128 /* Some targets don't set errno on errors, grrr! */
6e1e94ea 129 if (pid == 0 && args == dummy)
8a3fe4f8 130 error (_("Illegal process-id: %s."), args);
5bf970f9 131
f6ffd89b 132 if (pid == getpid ()) /* Trying to masturbate? */
8a3fe4f8 133 error (_("I refuse to debug myself!"));
5bf970f9
AC
134
135 if (from_tty)
136 {
4b8a1a28 137 exec_file = get_exec_file (0);
5bf970f9
AC
138
139 if (exec_file)
a3f17187 140 printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
5bf970f9
AC
141 target_pid_to_str (pid_to_ptid (pid)));
142 else
a3f17187 143 printf_unfiltered (_("Attaching to %s\n"),
5bf970f9
AC
144 target_pid_to_str (pid_to_ptid (pid)));
145
146 gdb_flush (gdb_stdout);
147 }
148
6e1e94ea
MK
149#ifdef PT_ATTACH
150 errno = 0;
4b8a1a28 151 ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0);
6e1e94ea 152 if (errno != 0)
e2e0b3e5 153 perror_with_name (("ptrace"));
6e1e94ea
MK
154 attach_flag = 1;
155#else
8a3fe4f8 156 error (_("This system does not support attaching to a process"));
6e1e94ea 157#endif
5bf970f9
AC
158
159 inferior_ptid = pid_to_ptid (pid);
160 push_target (ptrace_ops_hack);
12b8a2cb
DJ
161
162 /* Do this first, before anything has had a chance to query the
163 inferior's symbol table or similar. */
164 observer_notify_inferior_created (&current_target, from_tty);
5bf970f9
AC
165}
166
4b8a1a28
MK
167/* Detach from the inferior, optionally passing it the signal
168 specified ARGS. If FROM_TTY is non-zero, be chatty about it. */
5bf970f9
AC
169
170static void
171inf_ptrace_detach (char *args, int from_tty)
172{
4b8a1a28 173 pid_t pid = ptid_get_pid (inferior_ptid);
6e1e94ea 174 int sig = 0;
5bf970f9
AC
175
176 if (from_tty)
177 {
178 char *exec_file = get_exec_file (0);
179 if (exec_file == 0)
180 exec_file = "";
a3f17187 181 printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
5bf970f9
AC
182 target_pid_to_str (pid_to_ptid (pid)));
183 gdb_flush (gdb_stdout);
184 }
185 if (args)
6e1e94ea 186 sig = atoi (args);
5bf970f9 187
6e1e94ea 188#ifdef PT_DETACH
4b8a1a28
MK
189 /* We'd better not have left any breakpoints in the program or it'll
190 die when it hits one. Alsno note that this may only work if we
191 previously attached to the inferior. It *might* work if we
192 started the process ourselves. */
6e1e94ea 193 errno = 0;
4b8a1a28 194 ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig);
6e1e94ea 195 if (errno != 0)
e2e0b3e5 196 perror_with_name (("ptrace"));
6e1e94ea
MK
197 attach_flag = 0;
198#else
8a3fe4f8 199 error (_("This system does not support detaching from a process"));
6e1e94ea 200#endif
5bf970f9
AC
201
202 inferior_ptid = null_ptid;
203 unpush_target (ptrace_ops_hack);
204}
205
4b8a1a28
MK
206/* Kill the inferior. */
207
5bf970f9 208static void
4b8a1a28 209inf_ptrace_kill (void)
5bf970f9 210{
4b8a1a28 211 pid_t pid = ptid_get_pid (inferior_ptid);
c7c14b96 212 int status;
c7c14b96
MK
213
214 if (pid == 0)
215 return;
216
4b8a1a28
MK
217 ptrace (PT_KILL, pid, (PTRACE_TYPE_ARG3)0, 0);
218 waitpid (pid, &status, 0);
219
c7c14b96 220 target_mourn_inferior ();
5bf970f9
AC
221}
222
4b8a1a28 223/* Stop the inferior. */
c7c14b96 224
5bf970f9 225static void
c7c14b96 226inf_ptrace_stop (void)
5bf970f9 227{
4b8a1a28
MK
228 /* Send a SIGINT to the process group. This acts just like the user
229 typed a ^C on the controlling terminal. Note that using a
230 negative process number in kill() is a System V-ism. The proper
231 BSD interface is killpg(). However, all modern BSDs support the
232 System V interface too. */
c7c14b96 233 kill (-inferior_process_group, SIGINT);
5bf970f9
AC
234}
235
4b8a1a28
MK
236/* Resume execution of thread PTID, or all threads if PTID is -1. If
237 STEP is nonzero, single-step it. If SIGNAL is nonzero, give it
238 that signal. */
5bf970f9
AC
239
240static void
c7c14b96 241inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
5bf970f9 242{
4b8a1a28 243 pid_t pid = ptid_get_pid (ptid);
c7c14b96 244 int request = PT_CONTINUE;
c7c14b96
MK
245
246 if (pid == -1)
4b8a1a28
MK
247 /* Resume all threads. Traditionally ptrace() only supports
248 single-threaded processes, so simply resume the inferior. */
249 pid = ptid_get_pid (inferior_ptid);
c7c14b96
MK
250
251 if (step)
252 {
253 /* If this system does not support PT_STEP, a higher level
254 function will have called single_step() to transmute the step
255 request into a continue request (by setting breakpoints on
256 all possible successor instructions), so we don't have to
257 worry about that here. */
258 request = PT_STEP;
259 }
260
261 /* An address of (PTRACE_TYPE_ARG3)1 tells ptrace to continue from
262 where it was. If GDB wanted it to start some other way, we have
4b8a1a28 263 already written a new program counter value to the child. */
c7c14b96 264 errno = 0;
4b8a1a28 265 ptrace (request, pid, (PTRACE_TYPE_ARG3)1, target_signal_to_host (signal));
c7c14b96
MK
266 if (errno != 0)
267 perror_with_name (("ptrace"));
5bf970f9
AC
268}
269
4b8a1a28
MK
270/* Wait for the child specified by PTID to do something. Return the
271 process ID of the child, or MINUS_ONE_PTID in case of error; store
272 the status in *OURSTATUS. */
5bf970f9 273
c7c14b96
MK
274static ptid_t
275inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
5bf970f9 276{
4b8a1a28
MK
277 pid_t pid;
278 int status, save_errno;
5bf970f9 279
c7c14b96
MK
280 do
281 {
4b8a1a28 282 set_sigint_trap ();
c7c14b96 283 set_sigio_trap ();
5bf970f9 284
4b8a1a28
MK
285 do
286 {
287 pid = waitpid (ptid_get_pid (ptid), &status, 0);
288 save_errno = errno;
289 }
290 while (pid == -1 && errno == EINTR);
5bf970f9 291
c7c14b96 292 clear_sigio_trap ();
c7c14b96 293 clear_sigint_trap ();
5bf970f9 294
c7c14b96
MK
295 if (pid == -1)
296 {
c7c14b96 297 fprintf_unfiltered (gdb_stderr,
4b8a1a28 298 _("Child process unexpectedly missing: %s.\n"),
c7c14b96
MK
299 safe_strerror (save_errno));
300
301 /* Claim it exited with unknown signal. */
302 ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
303 ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
4b8a1a28 304 return minus_one_ptid;
c7c14b96
MK
305 }
306
4b8a1a28
MK
307 /* Ignore terminated detached child processes. */
308 if (!WIFSTOPPED (status) && pid != ptid_get_pid (inferior_ptid))
309 pid = -1;
c7c14b96 310 }
4b8a1a28 311 while (pid == -1);
c7c14b96
MK
312
313 store_waitstatus (ourstatus, status);
314 return pid_to_ptid (pid);
5bf970f9
AC
315}
316
4b8a1a28
MK
317/* Attempt a transfer all LEN bytes starting at OFFSET between the
318 inferior's OBJECT:ANNEX space and GDB's READBUF/WRITEBUF buffer.
319 Return the number of bytes actually transferred. */
5bf970f9
AC
320
321static LONGEST
322inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
961cb7b5
MK
323 const char *annex, gdb_byte *readbuf,
324 const gdb_byte *writebuf,
325 ULONGEST offset, LONGEST len)
5bf970f9 326{
4b8a1a28
MK
327 pid_t pid = ptid_get_pid (inferior_ptid);
328
5bf970f9
AC
329 switch (object)
330 {
331 case TARGET_OBJECT_MEMORY:
f929a579
AC
332#ifdef PT_IO
333 /* OpenBSD 3.1, NetBSD 1.6 and FreeBSD 5.0 have a new PT_IO
334 request that promises to be much more efficient in reading
335 and writing data in the traced process's address space. */
336 {
337 struct ptrace_io_desc piod;
4b8a1a28 338
f929a579
AC
339 /* NOTE: We assume that there are no distinct address spaces
340 for instruction and data. */
341 piod.piod_op = writebuf ? PIOD_WRITE_D : PIOD_READ_D;
342 piod.piod_addr = writebuf ? (void *) writebuf : readbuf;
343 piod.piod_offs = (void *) (long) offset;
344 piod.piod_len = len;
345
346 errno = 0;
4b8a1a28 347 if (ptrace (PT_IO, pid, (caddr_t)&piod, 0) == 0)
f929a579
AC
348 /* Return the actual number of bytes read or written. */
349 return piod.piod_len;
350 /* If the PT_IO request is somehow not supported, fallback on
351 using PT_WRITE_D/PT_READ_D. Otherwise we will return zero
352 to indicate failure. */
353 if (errno != EINVAL)
354 return 0;
355 }
356#endif
357 {
358 union
359 {
360 PTRACE_TYPE_RET word;
4b8a1a28 361 gdb_byte byte[sizeof (PTRACE_TYPE_RET)];
f929a579
AC
362 } buffer;
363 ULONGEST rounded_offset;
364 LONGEST partial_len;
4b8a1a28 365
cb85a953
AC
366 /* Round the start offset down to the next long word
367 boundary. */
f929a579 368 rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
4b8a1a28 369
cb85a953
AC
370 /* Since ptrace will transfer a single word starting at that
371 rounded_offset the partial_len needs to be adjusted down to
372 that (remember this function only does a single transfer).
373 Should the required length be even less, adjust it down
374 again. */
375 partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset;
376 if (partial_len > len)
f929a579 377 partial_len = len;
4b8a1a28 378
f929a579
AC
379 if (writebuf)
380 {
cb85a953
AC
381 /* If OFFSET:PARTIAL_LEN is smaller than
382 ROUNDED_OFFSET:WORDSIZE then a read/modify write will
383 be needed. Read in the entire word. */
f929a579 384 if (rounded_offset < offset
cb85a953
AC
385 || (offset + partial_len
386 < rounded_offset + sizeof (PTRACE_TYPE_RET)))
f929a579 387 /* Need part of initial word -- fetch it. */
4b8a1a28
MK
388 buffer.word = ptrace (PT_READ_I, pid,
389 (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
390
f929a579
AC
391 /* Copy data to be written over corresponding part of
392 buffer. */
f6ffd89b
MK
393 memcpy (buffer.byte + (offset - rounded_offset),
394 writebuf, partial_len);
4b8a1a28 395
f929a579 396 errno = 0;
4b8a1a28
MK
397 ptrace (PT_WRITE_D, pid,
398 (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
f929a579
AC
399 if (errno)
400 {
401 /* Using the appropriate one (I or D) is necessary for
402 Gould NP1, at least. */
403 errno = 0;
4b8a1a28
MK
404 ptrace (PT_WRITE_I, pid,
405 (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
f929a579
AC
406 if (errno)
407 return 0;
408 }
409 }
4b8a1a28 410
f929a579
AC
411 if (readbuf)
412 {
413 errno = 0;
4b8a1a28
MK
414 buffer.word = ptrace (PT_READ_I, pid,
415 (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
f929a579
AC
416 if (errno)
417 return 0;
418 /* Copy appropriate bytes out of the buffer. */
419 memcpy (readbuf, buffer.byte + (offset - rounded_offset),
420 partial_len);
421 }
4b8a1a28 422
f929a579
AC
423 return partial_len;
424 }
5bf970f9
AC
425
426 case TARGET_OBJECT_UNWIND_TABLE:
427 return -1;
428
429 case TARGET_OBJECT_AUXV:
430 return -1;
431
432 case TARGET_OBJECT_WCOOKIE:
433 return -1;
434
435 default:
436 return -1;
437 }
438}
439
4b8a1a28 440/* Return non-zero if the thread specified by PTID is alive. */
c7c14b96
MK
441
442static int
443inf_ptrace_thread_alive (ptid_t ptid)
444{
4b8a1a28
MK
445 /* ??? Is kill the right way to do this? */
446 return (kill (ptid_get_pid (ptid), 0) != -1);
c7c14b96
MK
447}
448
449/* Print status information about what we're accessing. */
450
451static void
452inf_ptrace_files_info (struct target_ops *ignore)
453{
4b8a1a28
MK
454 printf_filtered (_("\tUsing the running image of %s %s.\n"),
455 attach_flag ? "attached" : "child",
456 target_pid_to_str (inferior_ptid));
5bf970f9
AC
457}
458
8785ced0
MK
459/* Create a prototype ptrace target. The client can override it with
460 local methods. */
461
5bf970f9
AC
462struct target_ops *
463inf_ptrace_target (void)
464{
465 struct target_ops *t = inf_child_target ();
8785ced0 466
5bf970f9 467 t->to_attach = inf_ptrace_attach;
5bf970f9
AC
468 t->to_detach = inf_ptrace_detach;
469 t->to_resume = inf_ptrace_resume;
470 t->to_wait = inf_ptrace_wait;
5bf970f9 471 t->to_files_info = inf_ptrace_files_info;
4b8a1a28 472 t->to_kill = inf_ptrace_kill;
5bf970f9 473 t->to_create_inferior = inf_ptrace_create_inferior;
5bf970f9 474 t->to_mourn_inferior = inf_ptrace_mourn_inferior;
5bf970f9 475 t->to_thread_alive = inf_ptrace_thread_alive;
4b8a1a28 476 t->to_pid_to_str = normal_pid_to_str;
5bf970f9 477 t->to_stop = inf_ptrace_stop;
c7c14b96 478 t->to_xfer_partial = inf_ptrace_xfer_partial;
8785ced0 479
c7c14b96 480 ptrace_ops_hack = t;
8785ced0
MK
481 return t;
482}
483\f
484
4b8a1a28 485/* Pointer to a function that returns the offset within the user area
8785ced0
MK
486 where a particular register is stored. */
487static CORE_ADDR (*inf_ptrace_register_u_offset)(int);
488
489/* Fetch register REGNUM from the inferior. */
490
491static void
492inf_ptrace_fetch_register (int regnum)
493{
494 CORE_ADDR addr;
495 size_t size;
496 PTRACE_TYPE_RET *buf;
497 int pid, i;
498
499 /* Cater for systems like GNU/Linux, that implement threads as
500 seperate processes. */
501 pid = ptid_get_lwp (inferior_ptid);
502 if (pid == 0)
503 pid = ptid_get_pid (inferior_ptid);
504
505 /* This isn't really an address, but ptrace thinks of it as one. */
506 addr = inf_ptrace_register_u_offset (regnum);
507 size = register_size (current_gdbarch, regnum);
508
509 gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
510 buf = alloca (size);
511
512 /* Read the register contents from the inferior a chuck at the time. */
513 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
514 {
515 errno = 0;
4b8a1a28 516 buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)addr, 0);
8785ced0 517 if (errno != 0)
4b8a1a28
MK
518 error (_("Couldn't read register %s (#%d): %s."),
519 REGISTER_NAME (regnum), regnum, safe_strerror (errno));
8785ced0
MK
520
521 addr += sizeof (PTRACE_TYPE_RET);
522 }
523 regcache_raw_supply (current_regcache, regnum, buf);
524}
525
526/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
527 for all registers. */
528
529static void
530inf_ptrace_fetch_registers (int regnum)
531{
532 if (regnum == -1)
533 for (regnum = 0; regnum < NUM_REGS; regnum++)
534 inf_ptrace_fetch_register (regnum);
535 else
536 inf_ptrace_fetch_register (regnum);
537}
538
539/* Store register REGNUM into the inferior. */
540
541static void
542inf_ptrace_store_register (int regnum)
543{
544 CORE_ADDR addr;
545 size_t size;
546 PTRACE_TYPE_RET *buf;
547 int pid, i;
548
549 /* Cater for systems like GNU/Linux, that implement threads as
550 seperate processes. */
551 pid = ptid_get_lwp (inferior_ptid);
552 if (pid == 0)
553 pid = ptid_get_pid (inferior_ptid);
554
555 /* This isn't really an address, but ptrace thinks of it as one. */
556 addr = inf_ptrace_register_u_offset (regnum);
557 size = register_size (current_gdbarch, regnum);
558
559 gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
560 buf = alloca (size);
561
562 /* Write the register contents into the inferior a chunk at the time. */
563 regcache_raw_collect (current_regcache, regnum, buf);
564 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
565 {
566 errno = 0;
4b8a1a28 567 ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)addr, buf[i]);
8785ced0 568 if (errno != 0)
4b8a1a28
MK
569 error (_("Couldn't write register %s (#%d): %s."),
570 REGISTER_NAME (regnum), regnum, safe_strerror (errno));
8785ced0
MK
571
572 addr += sizeof (PTRACE_TYPE_RET);
573 }
574}
575
576/* Store register REGNUM back into the inferior. If REGNUM is -1, do
577 this for all registers. */
578
579void
580inf_ptrace_store_registers (int regnum)
581{
582 if (regnum == -1)
583 for (regnum = 0; regnum < NUM_REGS; regnum++)
584 inf_ptrace_store_register (regnum);
585 else
586 inf_ptrace_store_register (regnum);
587}
588
589/* Create a "traditional" ptrace target. REGISTER_U_OFFSET should be
590 a function returning the offset within the user area where a
591 particular register is stored. */
592
593struct target_ops *
594inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int))
595{
596 struct target_ops *t = inf_ptrace_target();
597
598 gdb_assert (register_u_offset);
599 inf_ptrace_register_u_offset = register_u_offset;
600 t->to_fetch_registers = inf_ptrace_fetch_registers;
601 t->to_store_registers = inf_ptrace_store_registers;
602
5bf970f9
AC
603 return t;
604}
This page took 0.119891 seconds and 4 git commands to generate.