* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
static char sccsid
[] = "@(#)default-dep.c 6.3 (Berkeley) 5/8/91";
/* Low level interface to ptrace, for GDB when running under Unix.
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
This file is part of GDB.
GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* #include <fcntl.h> Can we live without this? */
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
#include <sys/user.h> /* After a.out.h */
/* This function simply calls ptrace with the given arguments.
It exists so that all calls to ptrace are isolated in this
machine-dependent file. */
call_ptrace (request
, pid
, arg3
, arg4
)
int request
, pid
, arg3
, arg4
;
return ptrace (request
, pid
, arg3
, arg4
);
ptrace (8, inferior_pid
, 0, 0);
/* This is used when GDB is exiting. It gives less chance of error.*/
ptrace (8, inferior_pid
, 0, 0);
/* Resume execution of the inferior process.
If STEP is nonzero, single-step it.
If SIGNAL is nonzero, give it that signal. */
remote_resume (step
, signal
);
ptrace (step
? 9 : 7, inferior_pid
, 1, signal
);
perror_with_name ("ptrace");
fetch_inferior_registers ()
register unsigned int regaddr
;
char buf
[MAX_REGISTER_RAW_SIZE
];
unsigned int offset
= (char *) &u
.u_ar0
- (char *) &u
;
offset
= ptrace (3, inferior_pid
, offset
, 0) - KERNEL_U_ADDR
;
for (regno
= 0; regno
< NUM_REGS
; regno
++)
regaddr
= register_addr (regno
, offset
);
for (i
= 0; i
< REGISTER_RAW_SIZE (regno
); i
+= sizeof (int))
*(int *) &buf
[i
] = ptrace (3, inferior_pid
, regaddr
, 0);
supply_register (regno
, buf
);
/* Store our register values back into the inferior.
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
store_inferior_registers (regno
)
register unsigned int regaddr
;
unsigned int offset
= (char *) &u
.u_ar0
- (char *) &u
;
offset
= ptrace (3, inferior_pid
, offset
, 0) - KERNEL_U_ADDR
;
regaddr
= register_addr (regno
, offset
);
ptrace (6, inferior_pid
, regaddr
, read_register (regno
));
sprintf (buf
, "writing register number %d", regno
);
else for (regno
= 0; regno
< NUM_REGS
; regno
++)
regaddr
= register_addr (regno
, offset
);
ptrace (6, inferior_pid
, regaddr
, read_register (regno
));
sprintf (buf
, "writing all regs, number %d", regno
);
/* Copy LEN bytes from inferior's memory starting at MEMADDR
to debugger memory starting at MYADDR.
On failure (cannot read from inferior, usually because address is out
of bounds) returns the value of errno. */
read_inferior_memory (memaddr
, myaddr
, len
)
/* Round starting address down to longword boundary. */
register CORE_ADDR addr
= memaddr
& - sizeof (int);
/* Round ending address up; get number of longwords that makes. */
= (((memaddr
+ len
) - addr
) + sizeof (int) - 1) / sizeof (int);
/* Allocate buffer of that many longwords. */
register int *buffer
= (int *) alloca (count
* sizeof (int));
/* Read all the longwords */
for (i
= 0; i
< count
; i
++, addr
+= sizeof (int))
/* This is now done by read_memory, because when this function did it,
reading a byte or short int hardware port read whole longs, causing
such as bus errors and unexpected hardware operation. This would
also be a problem with ptrace if the inferior process could read
or write hardware registers, but that's not usually the case. */
buffer
[i
] = remote_fetch_word (addr
);
buffer
[i
] = ptrace (1, inferior_pid
, addr
, 0);
/* Copy appropriate bytes out of the buffer. */
bcopy ((char *) buffer
+ (memaddr
& (sizeof (int) - 1)), myaddr
, len
);
/* Copy LEN bytes of data from debugger memory at MYADDR
to inferior's memory at MEMADDR.
On failure (cannot write the inferior)
returns the value of errno. */
write_inferior_memory (memaddr
, myaddr
, len
)
/* Round starting address down to longword boundary. */
register CORE_ADDR addr
= memaddr
& - sizeof (int);
/* Round ending address up; get number of longwords that makes. */
= (((memaddr
+ len
) - addr
) + sizeof (int) - 1) / sizeof (int);
/* Allocate buffer of that many longwords. */
register int *buffer
= (int *) alloca (count
* sizeof (int));
/* Fill start and end extra bytes of buffer with existing memory data. */
return (remote_write_inferior_memory(memaddr
, myaddr
, len
));
buffer
[0] = ptrace (1, inferior_pid
, addr
, 0);
buffer
[count
- 1] = ptrace (1, inferior_pid
,
addr
+ (count
- 1) * sizeof (int), 0);
/* Copy data to be written over corresponding part of buffer */
bcopy (myaddr
, (char *) buffer
+ (memaddr
& (sizeof (int) - 1)), len
);
/* Write the entire buffer. */
for (i
= 0; i
< count
; i
++, addr
+= sizeof (int))
ptrace (4, inferior_pid
, addr
, buffer
[i
]);
/* Work with core dump and executable files, for GDB.
This code would be in core.c if it weren't machine-dependent. */
#endif /* no N_TXTADDR */
#define N_DATADDR(hdr) hdr.a_text
#endif /* no N_DATADDR */
/* Make COFF and non-COFF names for things a little more compatible
to reduce conditionals later. */
#define AOUTHDR struct exec
extern char *sys_siglist
[];
/* Hook for `exec_file_command' command to call. */
extern void (*exec_file_display_hook
) ();
/* File names of core file and executable file. */
/* Descriptors on which core file and executable file are open.
Note that the execchan is closed when an inferior is created
and reopened if the inferior dies or is killed. */
/* Last modification time of executable file.
Also used in source.c to compare against mtime of a source file. */
/* Virtual addresses of bounds of the two areas of memory in the core file. */
extern CORE_ADDR data_start
;
extern CORE_ADDR data_end
;
extern CORE_ADDR stack_start
;
extern CORE_ADDR stack_end
;
/* Virtual addresses of bounds of two areas of memory in the exec file.
Note that the data area in the exec file is used only when there is no core file. */
extern CORE_ADDR text_start
;
extern CORE_ADDR text_end
;
extern CORE_ADDR exec_data_start
;
extern CORE_ADDR exec_data_end
;
/* Address in executable file of start of text area data. */
/* Address in executable file of start of data area data. */
extern int exec_data_offset
;
/* Address in core file of start of data area data. */
/* Address in core file of start of stack area data. */
/* various coff data structures */
#endif /* not COFF_FORMAT */
/* a.out header saved in core file. */
extern AOUTHDR core_aouthdr
;
/* a.out header of exec file. */
extern AOUTHDR exec_aouthdr
;
extern void validate_files ();
core_file_command (filename
, from_tty
)
/* Discard all vestiges of any previous core file
and mark data and stack spaces as empty. */
stack_start
= STACK_END_ADDR
;
stack_end
= STACK_END_ADDR
;
/* Now, if a new core file was specified, open it and digest it. */
filename
= tilde_expand (filename
);
make_cleanup (free
, filename
);
error ("To look at a core file, you must kill the inferior with \"kill\".");
corechan
= open (filename
, O_RDONLY
, 0);
perror_with_name (filename
);
/* 4.2-style (and perhaps also sysV-style) core dump file. */
val
= myread (corechan
, &u
, sizeof u
);
perror_with_name ("Not a core file: reading upage");
error ("Not a core file: could only read %d bytes", val
);
/* We are depending on exec_file_command having been called
previously to set exec_data_start. Since the executable
and the core file share the same text segment, the address
of the data segment will be the same in both. */
data_start
= exec_data_start
;
data_end
= data_start
+ NBPG
* u
.u_dsize
;
stack_start
= stack_end
- NBPG
* u
.u_ssize
;
data_offset
= NBPG
* UPAGES
;
stack_offset
= NBPG
* (UPAGES
+ u
.u_dsize
);
/* Some machines put an absolute address in here and some put
the offset in the upage of the regs. */
reg_offset
= (int) u
.u_ar0
;
if (reg_offset
> NBPG
* UPAGES
)
reg_offset
-= KERNEL_U_ADDR
;
/* I don't know where to find this info.
So, for now, mark it as not available. */
N_SET_MAGIC (core_aouthdr
, 0);
/* Read the register values out of the core file and store
them where `read_register' will find them. */
for (regno
= 0; regno
< NUM_REGS
; regno
++)
char buf
[MAX_REGISTER_RAW_SIZE
];
val
= lseek (corechan
, register_addr (regno
, reg_offset
), 0);
|| (val
= myread (corechan
, buf
, sizeof buf
)) < 0)
char * buffer
= (char *) alloca (strlen (reg_names
[regno
])
strcpy (buffer
, "Reading register ");
strcat (buffer
, reg_names
[regno
]);
perror_with_name (buffer
);
supply_register (regno
, buf
);
corefile
= savestring (filename
, strlen (filename
));
corefile
= concat (current_directory
, "/", filename
);
set_current_frame ( create_new_frame (read_register (FP_REGNUM
),
select_frame (get_current_frame (), 0);
printf ("No core file now.\n");
exec_file_command (filename
, from_tty
)
/* Eliminate all traces of old exec file.
Mark text segment as empty. */
data_end
-= exec_data_start
;
/* Now open and digest the file the user requested, if any. */
filename
= tilde_expand (filename
);
make_cleanup (free
, filename
);
execchan
= openp (getenv ("PATH"), 1, filename
, O_RDONLY
, 0,
perror_with_name (filename
);
if (read_file_hdr (execchan
, &file_hdr
) < 0)
error ("\"%s\": not in executable format.", execfile
);
aout_hdrsize
= file_hdr
.f_opthdr
;
num_sections
= file_hdr
.f_nscns
;
if (read_aout_hdr (execchan
, &exec_aouthdr
, aout_hdrsize
) < 0)
error ("\"%s\": can't read optional aouthdr", execfile
);
if (read_section_hdr (execchan
, _TEXT
, &text_hdr
, num_sections
,
error ("\"%s\": can't read text section header", execfile
);
if (read_section_hdr (execchan
, _DATA
, &data_hdr
, num_sections
,
error ("\"%s\": can't read data section header", execfile
);
text_start
= exec_aouthdr
.text_start
;
text_end
= text_start
+ exec_aouthdr
.tsize
;
text_offset
= text_hdr
.s_scnptr
;
exec_data_start
= exec_aouthdr
.data_start
;
exec_data_end
= exec_data_start
+ exec_aouthdr
.dsize
;
exec_data_offset
= data_hdr
.s_scnptr
;
data_start
= exec_data_start
;
data_end
+= exec_data_start
;
exec_mtime
= file_hdr
.f_timdat
;
#else /* not COFF_FORMAT */
HEADER_SEEK_FD (execchan
);
val
= myread (execchan
, &exec_aouthdr
, sizeof (AOUTHDR
));
perror_with_name (filename
);
text_start
= N_TXTADDR (exec_aouthdr
);
exec_data_start
= N_DATADDR (exec_aouthdr
);
text_offset
= N_TXTOFF (exec_aouthdr
);
exec_data_offset
= N_TXTOFF (exec_aouthdr
) + exec_aouthdr
.a_text
;
text_end
= text_start
+ exec_aouthdr
.a_text
;
exec_data_end
= exec_data_start
+ exec_aouthdr
.a_data
;
data_start
= exec_data_start
;
data_end
+= exec_data_start
;
if (fstat (execchan
, &st_exec
) < 0)
perror_with_name (filename
);
exec_mtime
= st_exec
.st_mtime
;
#endif /* not COFF_FORMAT */
printf ("No exec file now.\n");
/* Tell display code (if any) about the changed file name. */
if (exec_file_display_hook
)
(*exec_file_display_hook
) (filename
);