* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
static char sccsid
[] = "@(#)hp300bsd-dep.c 6.10 (Berkeley) 5/12/91";
* Machine-dependent code for a Hewlett-Packard 9000/300, running bsd.
* Copyright (C) 1986, 1987, 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) any later version.
* 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
* 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.
static char rcsid
[] = "$Header: hp300bsd-dep.c,v 1.6 91/03/13 01:04:43 mccanne Exp $";
/* #include <fcntl.h> Can we live without this? */
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
#include <hp300/hp300/pte.h>
#include <sys/resource.h>
#include <sys/user.h> /* After a.out.h */
#include <machine/vmparam.h>
#include "symtab.h" /* XXX */
extern int kernel_debugging
;
#define KERNOFF ((unsigned)KERNBASE)
#define LOWRAM ((unsigned)0xfffffdce)
/* actually you can't really distinguish user and kernel by address */
#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr))
((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + ctob(UPAGES))
#define PT_ADDR_ANY ((caddr_t) 1)
* Convert from sysmap pte index to system virtual address & vice-versa.
* (why aren't these in one of the system vm macro files???)
#define smxtob(a) (sbr + (a) * sizeof(pte))
#define btosmx(b) (((b) - sbr) / sizeof(pte))
static int ok_to_cache();
* 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
)
return(ptrace(request
, pid
, arg3
, arg4
));
* It's a very, very bad idea to go away leaving
* breakpoints in a remote kernel or to leave it
* stopped at a breakpoint.
} else if (inferior_pid
!= 0) {
ptrace(PT_KILL
, inferior_pid
, 0, 0);
* This is used when GDB is exiting. It gives less chance of error.
ptrace(PT_KILL
, 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
? PT_STEP
: PT_CONTINUE
, inferior_pid
,
perror_with_name("ptrace");
* Start debugging the process whose number is PID.
ptrace(PT_ATTACH
, pid
, 0, 0);
perror_with_name("ptrace");
* Stop debugging the process whose number is PID and continue it
* with signal number SIGNAL. SIGNAL = 0 means just continue it.
ptrace(PT_DETACH
, inferior_pid
, PT_ADDR_ANY
, signal
);
perror_with_name("ptrace");
#endif /* ATTACH_DETACH */
offset
= (char *) &u
.u_kproc
.kp_proc
.p_regs
- (char *) &u
;
offset
= ptrace(PT_READ_U
, inferior_pid
, (caddr_t
)offset
, 0) -
offset
= (char *) &u
.u_ar0
- (char *) &u
;
offset
= ptrace(PT_READ_U
, inferior_pid
, (caddr_t
)offset
, 0) -
fetch_inferior_registers()
register unsigned int regaddr
;
char buf
[MAX_REGISTER_RAW_SIZE
];
remote_fetch_registers(registers
);
offset
= get_register_offset();
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(PT_READ_U
, inferior_pid
,
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
store_inferior_registers(regno
)
register unsigned int regaddr
;
remote_store_registers(registers
);
offset
= get_register_offset();
regaddr
= register_addr(regno
, offset
);
for (i
= 0; i
< REGISTER_RAW_SIZE(regno
); i
+= sizeof(int)) {
ptrace(PT_WRITE_U
, inferior_pid
, (caddr_t
)regaddr
,
*(int *) ®isters
[REGISTER_BYTE(regno
) + i
]);
sprintf(buf
, "writing register number %d(%d)",
for (regno
= 0; regno
< NUM_REGS
; regno
++) {
regaddr
= register_addr(regno
, offset
);
for (i
= 0; i
< REGISTER_RAW_SIZE(regno
);
ptrace(PT_WRITE_U
, inferior_pid
,
*(int *) ®isters
[REGISTER_BYTE(regno
) + i
]);
"writing register number %d(%d)",
* 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. */
register int count
= (((memaddr
+ len
) - addr
) + sizeof(int) - 1) /
/* Allocate buffer of that many longwords. */
register int *buffer
= (int *) alloca(count
* sizeof(int));
return (remote_read_inferior_memory(memaddr
, myaddr
, len
));
/* Read all the longwords */
for (i
= 0; i
< count
&& errno
== 0; i
++, addr
+= sizeof(int))
buffer
[i
] = ptrace(PT_READ_I
, inferior_pid
, (caddr_t
)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
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. */
register int count
= (((memaddr
+ len
) - addr
) + sizeof(int) - 1) /
/* 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
return (remote_write_inferior_memory(memaddr
, myaddr
, len
));
* Fill start and end extra bytes of buffer with existing memory
buffer
[0] = ptrace(PT_READ_I
, inferior_pid
, (caddr_t
)addr
, 0);
buffer
[count
- 1] = ptrace(PT_READ_I
, inferior_pid
,
(caddr_t
)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
&& errno
== 0; i
++, addr
+= sizeof(int))
ptrace(PT_WRITE_I
, inferior_pid
, (caddr_t
)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
#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. */
/* 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();
extern int (*core_file_hook
)();
* Kernel debugging routines.
static CORE_ADDR file_offset
;
static CORE_ADDR kernel_udot_va
;
#include <machine/frame.h>
if ((i
= lookup_misc_func(name
)) < 0)
error("kernel symbol `%s' not found.", name
);
return (misc_function_vector
[i
].address
);
* return true if 'len' bytes starting at 'addr' can be read out as
* longwords and/or locally cached (this is mostly for memory mapped
* i/o register access when debugging remote kernels).
static CORE_ADDR intiobase
, extiobase
;
intiobase
= ksym_lookup("intiobase");
(void)remote_read_inferior_memory(intiobase
, &intiobase
,
extiobase
= ksym_lookup("extiobase");
(void)remote_read_inferior_memory(extiobase
, &extiobase
,
if (addr
>= intiobase
&& addr
< intiobase
+ ctob(IIOMAPSIZE
))
if (addr
>= extiobase
&& addr
< extiobase
+ ctob(EIOMAPSIZE
))
IObase
= ksym_lookup("IObase");
if (addr
>= IObase
&& addr
< IObase
+ (IOTOP
- IOBASE
))
if (lseek(corechan
, addr
- file_offset
, L_SET
) == -1)
if (read(corechan
, dat
, len
) != len
)
* When looking at kernel data space through /dev/mem or with a core file, do
* virtual memory mapping.
CORE_ADDR oldaddr
= addr
;
static CORE_ADDR curstp
= -1;
* If we're looking at the kernel stack,
* munge the address to refer to the user space mapping instead;
* that way we get the requested process's kstack, not the running one.
if (addr
>= kstack
&& addr
< kstack
+ ctob(UPAGES
))
addr
= (addr
- kstack
) + curpcb
;
* Identify the current segment table.
* Since the given VA could come from either kernel
* or user space, the following heuristics don't always work.
else if (found_pcb
== 0) {
/* We have a pcb address, but haven't read it yet. Cheat. */
v
= vtophys((CORE_ADDR
)&((struct pcb
*)curpcb
)->pcb_ustp
);
physrd(v
, &curstp
, sizeof curstp
);
* Read the current segment table.
v
= stp
+ ((addr
>> SG_ISHIFT
) * sizeof pte
);
if (physrd(v
, (char *)&pte
, sizeof(pte
)))
if (*(int *)&pte
== SG_NV
)
v
= hp300_btop(addr
& SG_PMASK
);
addr
= (CORE_ADDR
)(hp300_ptob(pte
.pg_pfnum
) + v
*sizeof pte
);
* Addr is now address of the pte of the page we are interested in;
* get the pte and paste up the physical address.
if (physrd(addr
, (char *) &pte
, sizeof(pte
)))
if (pte
.pg_v
== 0 && pte
.pg_pfnum
== 0)
addr
= (CORE_ADDR
)hp300_ptob(pte
.pg_pfnum
) + (oldaddr
& PGOFSET
);
printf("vtophys(%x) -> %x\n", oldaddr
, addr
);
CORE_ADDR oldaddr
= addr
;
/* permit direct reference to physical memory */
if (kernel_udot_va
&& INUDOT(addr
)) {
addr
= kernel_udot_va
+ btop(addr
) * sizeof (struct pte
);
} else if (INKERNEL(addr
)) {
* In system space get system pte. If valid or reclaimable
* then physical address is combination of its page number
* and the page offset of the original address.
v
= smxtob(btop(addr
- KERNOFF
));
/* In p0 space must not be off end of region. */
/* address out of segment */
addr
= (CORE_ADDR
)(pcb
.pcb_p0br
+ v
);
* For p0/p1 address, user-level page table should be in
* kernel vm. Do second-level indirect by recursing.
* Addr is now address of the pte of the page we are interested in;
* get the pte and paste up the physical address.
if (physrd(addr
, (char *) &pte
, sizeof(pte
)))
if (pte
.pg_v
== 0 && (pte
.pg_fod
|| pte
.pg_pfnum
== 0))
addr
= (CORE_ADDR
)ptob(pte
.pg_pfnum
) + (oldaddr
& PGOFSET
);
printf("vtophys(%x) -> %x\n", oldaddr
, addr
);
CORE_ADDR paddr
= vtophys(addr
);
if (physrd(paddr
, (char *)&addr
, sizeof(addr
)) == 0);
if (physrd(uaddr
, (char *)&pcb
, sizeof pcb
))
error("cannot read pcb at %x\n", uaddr
);
printf("current pcb at %x\n", uaddr
);
if (physrd (uaddr
, (char *)&pcb
, sizeof pcb
))
error ("cannot read pcb at %x.\n", uaddr
);
printf("p0br %x p0lr %x p1br %x p1lr %x\n",
pcb
.pcb_p0br
, pcb
.pcb_p0lr
, pcb
.pcb_p1br
, pcb
.pcb_p1lr
);
kernel_udot_va
= (CORE_ADDR
) (pcb
.pcb_p1br
+ BTOPUSRSTACK
);
* get the register values out of the sys pcb and
* store them where `read_register' will find them.
supply_register(i
, &pcb
.pcb_regs
[i
-2]);
for (i
= 10; i
< 16; ++i
)
supply_register(i
, &pcb
.pcb_regs
[i
-4]);
/* fake 'scratch' regs d0, d1, a0, a1 */
supply_register(0, &i
); supply_register(1, &i
);
supply_register(8, &i
); supply_register(9, &i
);
i
= kvread(pcb
.pcb_regs
[10] + 4);
supply_register(PC_REGNUM
, &i
);
supply_register(PS_REGNUM
, &pcb
.pcb_ps
);
for (i
= FP0_REGNUM
; i
< NUM_REGS
; ++i
) {
REGISTER_U_ADDR(fpreg
, 0, i
);
supply_register(i
, ((char *)&pcb
) + fpreg
);
if ((stb
.st_mode
& S_IFMT
) == S_IFCHR
&& stb
.st_rdev
== makedev(2, 0))
* Must get value of lowram before we can read PCB.
/* /dev/mem == physical memory */
(void)physrd(LOWRAM
, (char *)&lowram
, sizeof(lowram
));
/* normal file -- use standard offset */
(void)physrd(ksym_lookup("lowram"), (char *)&lowram
,
lowram
= roundup(lowram
, NBPG
);
* Get system mapping information.
sbr
= ksym_lookup("Sysseg") + lowram
;
(void)physrd(sbr
, (char *)&sbr
, sizeof(sbr
));
sbr
+= lowram
; /* sbr is a physical address for NEWVM */
slr
= NPTEPG
* (NPTEPG
-1);
curpcb
= ksym_lookup("curpcb") + lowram
;
physrd(curpcb
, &curpcb
, sizeof curpcb
);
kstack
= ksym_lookup("kstack");
sbr
= ksym_lookup("Sysmap");
slr
= ksym_lookup("Syssize");
printf("sbr %x slr %x\n", sbr
, slr
);
* pcb where "panic" saved registers in first thing in current
read_pcb(vtophys(kstack
));
read_pcb(vtophys(ksym_lookup("u")));
panicstr
= kvread(ksym_lookup("panicstr"));
(void) kernel_core_file_hook(panicstr
, buf
, sizeof(buf
));
for (cp
= buf
; cp
< &buf
[sizeof(buf
)] && *cp
; cp
++)
if (!isascii(*cp
) || (!isprint(*cp
) && !isspace(*cp
)))
printf("panic: %s\n", buf
);
stack_end
= USRSTACK
+ ctob(UPAGES
);
error_no_arg("ps-style address for new current process");
error("not debugging kernel");
error("need kernel core file");
uaddr
= (u_int
) parse_and_eval_address(arg
);
/* p_addr is now a pcb virtual address */
read_pcb(vtophys(uaddr
));
set_current_frame(create_new_frame(read_register(FP_REGNUM
), read_pc()));
select_frame(get_current_frame(), 0);
* read len bytes from kernel virtual address 'addr' into local
* buffer 'buf'. Return 0 if read ok, 1 otherwise. On read
* errors, portion of buffer not read is zeroed.
kernel_core_file_hook(addr
, buf
, len
)
/* we can't read across a page boundary */
i
= min(len
, NBPG
- (addr
& PGOFSET
));
if (physrd(paddr
, buf
, i
)) {
core_file_command(filename
, from_tty
)
* Discard all vestiges of any previous core file and mark data and
/* Now, if a new core file was specified, open it and digest it. */
printf("No core file now.\n");
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
);
setup_kernel_debugging();
core_file_hook
= kernel_core_file_hook
;
} else if ((stb
.st_mode
& S_IFMT
) == S_IFCHR
&&
stb
.st_rdev
== makedev(2, 1)) {
/* looking at /dev/kmem */
data_offset
= data_start
= KERNOFF
;
stack_end
= stack_start
= data_end
;
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
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
- KERNEL_U_ADDR
;
NBPG
* u
.u_kproc
.kp_eproc
.e_vm
.vm_dsize
;
stack_start
= stack_end
-
NBPG
* u
.u_kproc
.kp_eproc
.e_vm
.vm_ssize
;
data_offset
= NBPG
* UPAGES
;
(UPAGES
+ u
.u_kproc
.kp_eproc
.e_vm
.vm_dsize
);
reg_offset
= (int) u
.u_kproc
.kp_proc
.p_regs
- USRSTACK
;
* 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
]) + 30);
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);
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
);
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
;
fstat(execchan
, &st_exec
);
exec_mtime
= st_exec
.st_mtime
;
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
);
0x4e714eb9, /* nop, jsr @#32323232 */
#define DUMMY_CALL_INDEX 1
0x4e424e71, /* trap 2, nop */
* Build `dummy' call instructions on inferior's stack to cause
* it to call a subroutine.
* N.B. - code in wait_for_inferior requires that sp < pc < fp when
* we take the trap 2 above so it will recognize that we stopped
* at a `dummy' call. So, after the call sp is *not* decremented
* to clean the arguments, code & other stuff we lay on the stack.
* Since the regs are restored to saved values at the breakpoint,
* sp will get reset correctly. Also, this restore means we don't
* have to construct frame linkage info to save pc & fp. The lack
* of frame linkage means we can't do a backtrace, etc., if the
* called function gets a fault or hits a breakpoint but code in
* run_stack_dummy makes this impossible anyway.
setup_dummy(sp
, funaddr
, nargs
, args
, struct_return_bytes
, pushfn
)
CORE_ADDR top
= sp
, struct_addr
, pc
;
i
= arg_stacklen(nargs
, args
) + struct_return_bytes
pc
= sp
- sizeof(dummy_code
);
sp
= pc
- padding
- struct_return_bytes
;
sp
= (*pushfn
)(sp
, *args
++);
STORE_STRUCT_RETURN(struct_addr
, sp
);
write_register(SP_REGNUM
, sp
);
dummy_code
[DUMMY_CALL_INDEX
] = (int)funaddr
;
write_memory(pc
, (char *)dummy_code
, sizeof(dummy_code
));
_initialize_hp300bsd_dep()
add_com ("process-address", class_obscure
, set_paddr_command
,
"The process identified by (ps-style) ADDR becomes the\n\
\"current\" process context for kernel debugging.");
add_com_alias ("paddr", "process-address", class_obscure
, 0);