mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-22 01:34:09 +00:00
Removed most unused files (about 8M total).
This commit is contained in:
parent
574c224708
commit
b3174ab1ce
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=27071
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,9 +0,0 @@
|
|||
|
||||
/* Define if fpregset_t type is available. */
|
||||
#undef HAVE_FPREGSET_T
|
||||
|
||||
/* Define if gregset_t type is available. */
|
||||
#undef HAVE_GREGSET_T
|
||||
|
||||
/* Define if the "%Lg" format works to print long doubles. */
|
||||
#undef PRINTF_HAS_LONG_DOUBLE
|
|
@ -1,243 +0,0 @@
|
|||
/* Low level Alpha interface, for GDB when running native.
|
||||
Copyright 1993, 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
/* Size of elements in jmpbuf */
|
||||
|
||||
#define JB_ELEMENT_SIZE 8
|
||||
|
||||
/* The definition for JB_PC in machine/reg.h is wrong.
|
||||
And we can't get at the correct definition in setjmp.h as it is
|
||||
not always available (eg. if _POSIX_SOURCE is defined which is the
|
||||
default). As the defintion is unlikely to change (see comment
|
||||
in <setjmp.h>, define the correct value here. */
|
||||
|
||||
#undef JB_PC
|
||||
#define JB_PC 2
|
||||
|
||||
/* Figure out where the longjmp will land.
|
||||
We expect the first arg to be a pointer to the jmp_buf structure from which
|
||||
we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
|
||||
This routine returns true on success. */
|
||||
|
||||
int
|
||||
get_longjmp_target (pc)
|
||||
CORE_ADDR *pc;
|
||||
{
|
||||
CORE_ADDR jb_addr;
|
||||
char raw_buffer[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
jb_addr = read_register(A0_REGNUM);
|
||||
|
||||
if (target_read_memory(jb_addr + JB_PC * JB_ELEMENT_SIZE, raw_buffer,
|
||||
sizeof(CORE_ADDR)))
|
||||
return 0;
|
||||
|
||||
*pc = extract_address (raw_buffer, sizeof(CORE_ADDR));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the register values out of the core file and store
|
||||
them where `read_register' will find them.
|
||||
|
||||
CORE_REG_SECT points to the register values themselves, read into memory.
|
||||
CORE_REG_SIZE is the size of that area.
|
||||
WHICH says which set of registers we are handling (0 = int, 2 = float
|
||||
on machines where they are discontiguous).
|
||||
REG_ADDR is the offset from u.u_ar0 to the register values relative to
|
||||
core_reg_sect. This is used with old-fashioned core files to
|
||||
locate the registers in a large upage-plus-stack ".reg" section.
|
||||
Original upage address X is at location core_reg_sect+x+reg_addr.
|
||||
*/
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned reg_addr;
|
||||
{
|
||||
register int regno;
|
||||
register int addr;
|
||||
int bad_reg = -1;
|
||||
|
||||
/* Table to map a gdb regnum to an index in the core register section.
|
||||
The floating point register values are garbage in OSF/1.2 core files. */
|
||||
static int core_reg_mapping[NUM_REGS] =
|
||||
{
|
||||
#define EFL (EF_SIZE / 8)
|
||||
EF_V0, EF_T0, EF_T1, EF_T2, EF_T3, EF_T4, EF_T5, EF_T6,
|
||||
EF_T7, EF_S0, EF_S1, EF_S2, EF_S3, EF_S4, EF_S5, EF_S6,
|
||||
EF_A0, EF_A1, EF_A2, EF_A3, EF_A4, EF_A5, EF_T8, EF_T9,
|
||||
EF_T10, EF_T11, EF_RA, EF_T12, EF_AT, EF_GP, EF_SP, -1,
|
||||
EFL+0, EFL+1, EFL+2, EFL+3, EFL+4, EFL+5, EFL+6, EFL+7,
|
||||
EFL+8, EFL+9, EFL+10, EFL+11, EFL+12, EFL+13, EFL+14, EFL+15,
|
||||
EFL+16, EFL+17, EFL+18, EFL+19, EFL+20, EFL+21, EFL+22, EFL+23,
|
||||
EFL+24, EFL+25, EFL+26, EFL+27, EFL+28, EFL+29, EFL+30, EFL+31,
|
||||
EF_PC, -1
|
||||
};
|
||||
static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
if (CANNOT_FETCH_REGISTER (regno))
|
||||
{
|
||||
supply_register (regno, zerobuf);
|
||||
continue;
|
||||
}
|
||||
addr = 8 * core_reg_mapping[regno];
|
||||
if (addr < 0 || addr >= core_reg_size)
|
||||
{
|
||||
if (bad_reg < 0)
|
||||
bad_reg = regno;
|
||||
}
|
||||
else
|
||||
{
|
||||
supply_register (regno, core_reg_sect + addr);
|
||||
}
|
||||
}
|
||||
if (bad_reg >= 0)
|
||||
{
|
||||
error ("Register %s not found in core file.", reg_names[bad_reg]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Map gdb internal register number to a ptrace ``address''.
|
||||
These ``addresses'' are defined in <sys/ptrace.h> */
|
||||
|
||||
#define REGISTER_PTRACE_ADDR(regno) \
|
||||
(regno < FP0_REGNUM ? GPR_BASE + (regno) \
|
||||
: regno == PC_REGNUM ? PC \
|
||||
: regno >= FP0_REGNUM ? FPR_BASE + ((regno) - FP0_REGNUM) \
|
||||
: 0)
|
||||
|
||||
/* Return the ptrace ``address'' of register REGNO. */
|
||||
|
||||
unsigned int
|
||||
register_addr (regno, blockend)
|
||||
int regno;
|
||||
int blockend;
|
||||
{
|
||||
return REGISTER_PTRACE_ADDR (regno);
|
||||
}
|
||||
|
||||
int
|
||||
kernel_u_size ()
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
#ifdef USE_PROC_FS
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register long *regp = gregsetp->regs;
|
||||
static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
|
||||
|
||||
for (regi = 0; regi < 31; regi++)
|
||||
supply_register (regi, (char *)(regp + regi));
|
||||
|
||||
supply_register (PC_REGNUM, (char *)(regp + 31));
|
||||
|
||||
/* Fill inaccessible registers with zero. */
|
||||
supply_register (ZERO_REGNUM, zerobuf);
|
||||
supply_register (FP_REGNUM, zerobuf);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register long *regp = gregsetp->regs;
|
||||
|
||||
for (regi = 0; regi < 31; regi++)
|
||||
if ((regno == -1) || (regno == regi))
|
||||
*(regp + regi) = *(long *) ®isters[REGISTER_BYTE (regi)];
|
||||
|
||||
if ((regno == -1) || (regno == PC_REGNUM))
|
||||
*(regp + 31) = *(long *) ®isters[REGISTER_BYTE (PC_REGNUM)];
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we do the same thing for floating-point registers.
|
||||
* Again, see the comments in m68k-tdep.c.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register long *regp = fpregsetp->regs;
|
||||
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
supply_register (regi + FP0_REGNUM, (char *)(regp + regi));
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (fpregsetp, regno)
|
||||
fpregset_t *fpregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register long *regp = fpregsetp->regs;
|
||||
|
||||
for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
*(regp + regi - FP0_REGNUM) =
|
||||
*(long *) ®isters[REGISTER_BYTE (regi)];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Register that we are able to handle alpha core file formats. */
|
||||
|
||||
static struct core_fns alpha_core_fns =
|
||||
{
|
||||
bfd_target_aout_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_alpha ()
|
||||
{
|
||||
add_core_fns (&alpha_core_fns);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,16 +0,0 @@
|
|||
.text
|
||||
.global _convert_from_extended
|
||||
|
||||
_convert_from_extended:
|
||||
|
||||
ldfe f0,[a1]
|
||||
stfd f0,[a2]
|
||||
movs pc,lr
|
||||
|
||||
.global _convert_to_extended
|
||||
|
||||
_convert_to_extended:
|
||||
|
||||
ldfd f0,[a1]
|
||||
stfe f0,[a2]
|
||||
movs pc,lr
|
|
@ -1,826 +0,0 @@
|
|||
/* Target-dependent code for the Acorn Risc Machine, for GDB, the GNU Debugger.
|
||||
Copyright 1988, 1989, 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#if 0
|
||||
#include "gdbcore.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#define N_TXTADDR(hdr) 0x8000
|
||||
#define N_DATADDR(hdr) (hdr.a_text + 0x8000)
|
||||
|
||||
#include <sys/user.h> /* After a.out.h */
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in corefile.c if it weren't machine-dependent. */
|
||||
|
||||
/* Structure to describe the chain of shared libraries used
|
||||
by the execfile.
|
||||
e.g. prog shares Xt which shares X11 which shares c. */
|
||||
|
||||
struct shared_library {
|
||||
struct exec_header header;
|
||||
char name[SHLIBLEN];
|
||||
CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */
|
||||
long data_offset; /* offset of data section in file */
|
||||
int chan; /* file descriptor for the file */
|
||||
struct shared_library *shares; /* library this one shares */
|
||||
};
|
||||
static struct shared_library *shlib = 0;
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
static CORE_ADDR unshared_text_start;
|
||||
|
||||
/* extended header from exec file (for shared library info) */
|
||||
|
||||
static struct exec_header exec_header;
|
||||
|
||||
void
|
||||
exec_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Eliminate all traces of old exec file.
|
||||
Mark text segment as empty. */
|
||||
|
||||
if (execfile)
|
||||
free (execfile);
|
||||
execfile = 0;
|
||||
data_start = 0;
|
||||
data_end -= exec_data_start;
|
||||
text_start = 0;
|
||||
unshared_text_start = 0;
|
||||
text_end = 0;
|
||||
exec_data_start = 0;
|
||||
exec_data_end = 0;
|
||||
if (execchan >= 0)
|
||||
close (execchan);
|
||||
execchan = -1;
|
||||
if (shlib) {
|
||||
close_shared_library(shlib);
|
||||
shlib = 0;
|
||||
}
|
||||
|
||||
/* Now open and digest the file the user requested, if any. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
filename = tilde_expand (filename);
|
||||
make_cleanup (free, filename);
|
||||
|
||||
execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&execfile);
|
||||
if (execchan < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
{
|
||||
struct stat st_exec;
|
||||
|
||||
#ifdef HEADER_SEEK_FD
|
||||
HEADER_SEEK_FD (execchan);
|
||||
#endif
|
||||
|
||||
val = myread (execchan, &exec_header, sizeof exec_header);
|
||||
exec_aouthdr = exec_header.a_exec;
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
text_start = 0x8000;
|
||||
|
||||
/* Look for shared library if needed */
|
||||
if (exec_header.a_exec.a_magic & MF_USES_SL)
|
||||
shlib = open_shared_library(exec_header.a_shlibname, text_start);
|
||||
|
||||
text_offset = N_TXTOFF (exec_aouthdr);
|
||||
exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
|
||||
|
||||
if (shlib) {
|
||||
unshared_text_start = shared_text_end(shlib) & ~0x7fff;
|
||||
stack_start = shlib->header.a_exec.a_sldatabase;
|
||||
stack_end = STACK_END_ADDR;
|
||||
} else
|
||||
unshared_text_start = 0x8000;
|
||||
text_end = unshared_text_start + exec_aouthdr.a_text;
|
||||
|
||||
exec_data_start = unshared_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;
|
||||
}
|
||||
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Read from the program's memory (except for inferior processes).
|
||||
This function is misnamed, since it only reads, never writes; and
|
||||
since it will use the core file and/or executable file as necessary.
|
||||
|
||||
It should be extended to write as well as read, FIXME, for patching files.
|
||||
|
||||
Return 0 if address could be read, EIO if addresss out of bounds. */
|
||||
|
||||
int
|
||||
xfer_core_file (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
register int i;
|
||||
register int val;
|
||||
int xferchan;
|
||||
char **xferfile;
|
||||
int fileptr;
|
||||
int returnval = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
xferfile = 0;
|
||||
xferchan = 0;
|
||||
|
||||
/* Determine which file the next bunch of addresses reside in,
|
||||
and where in the file. Set the file's read/write pointer
|
||||
to point at the proper place for the desired address
|
||||
and set xferfile and xferchan for the correct file.
|
||||
|
||||
If desired address is nonexistent, leave them zero.
|
||||
|
||||
i is set to the number of bytes that can be handled
|
||||
along with the next address.
|
||||
|
||||
We put the most likely tests first for efficiency. */
|
||||
|
||||
/* Note that if there is no core file
|
||||
data_start and data_end are equal. */
|
||||
if (memaddr >= data_start && memaddr < data_end)
|
||||
{
|
||||
i = min (len, data_end - memaddr);
|
||||
fileptr = memaddr - data_start + data_offset;
|
||||
xferfile = &corefile;
|
||||
xferchan = corechan;
|
||||
}
|
||||
/* Note that if there is no core file
|
||||
stack_start and stack_end define the shared library data. */
|
||||
else if (memaddr >= stack_start && memaddr < stack_end)
|
||||
{
|
||||
if (corechan < 0) {
|
||||
struct shared_library *lib;
|
||||
for (lib = shlib; lib; lib = lib->shares)
|
||||
if (memaddr >= lib->header.a_exec.a_sldatabase &&
|
||||
memaddr < lib->header.a_exec.a_sldatabase +
|
||||
lib->header.a_exec.a_data)
|
||||
break;
|
||||
if (lib) {
|
||||
i = min (len, lib->header.a_exec.a_sldatabase +
|
||||
lib->header.a_exec.a_data - memaddr);
|
||||
fileptr = lib->data_offset + memaddr -
|
||||
lib->header.a_exec.a_sldatabase;
|
||||
xferfile = execfile;
|
||||
xferchan = lib->chan;
|
||||
}
|
||||
} else {
|
||||
i = min (len, stack_end - memaddr);
|
||||
fileptr = memaddr - stack_start + stack_offset;
|
||||
xferfile = &corefile;
|
||||
xferchan = corechan;
|
||||
}
|
||||
}
|
||||
else if (corechan < 0
|
||||
&& memaddr >= exec_data_start && memaddr < exec_data_end)
|
||||
{
|
||||
i = min (len, exec_data_end - memaddr);
|
||||
fileptr = memaddr - exec_data_start + exec_data_offset;
|
||||
xferfile = &execfile;
|
||||
xferchan = execchan;
|
||||
}
|
||||
else if (memaddr >= text_start && memaddr < text_end)
|
||||
{
|
||||
struct shared_library *lib;
|
||||
for (lib = shlib; lib; lib = lib->shares)
|
||||
if (memaddr >= lib->text_start &&
|
||||
memaddr < lib->text_start + lib->header.a_exec.a_text)
|
||||
break;
|
||||
if (lib) {
|
||||
i = min (len, lib->header.a_exec.a_text +
|
||||
lib->text_start - memaddr);
|
||||
fileptr = memaddr - lib->text_start + text_offset;
|
||||
xferfile = &execfile;
|
||||
xferchan = lib->chan;
|
||||
} else {
|
||||
i = min (len, text_end - memaddr);
|
||||
fileptr = memaddr - unshared_text_start + text_offset;
|
||||
xferfile = &execfile;
|
||||
xferchan = execchan;
|
||||
}
|
||||
}
|
||||
else if (memaddr < text_start)
|
||||
{
|
||||
i = min (len, text_start - memaddr);
|
||||
}
|
||||
else if (memaddr >= text_end
|
||||
&& memaddr < (corechan >= 0? data_start : exec_data_start))
|
||||
{
|
||||
i = min (len, data_start - memaddr);
|
||||
}
|
||||
else if (corechan >= 0
|
||||
&& memaddr >= data_end && memaddr < stack_start)
|
||||
{
|
||||
i = min (len, stack_start - memaddr);
|
||||
}
|
||||
else if (corechan < 0 && memaddr >= exec_data_end)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
else if (memaddr >= stack_end && stack_end != 0)
|
||||
{
|
||||
i = min (len, - memaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Address did not classify into one of the known ranges.
|
||||
This shouldn't happen; we catch the endpoints. */
|
||||
fatal ("Internal: Bad case logic in xfer_core_file.");
|
||||
}
|
||||
|
||||
/* Now we know which file to use.
|
||||
Set up its pointer and transfer the data. */
|
||||
if (xferfile)
|
||||
{
|
||||
if (*xferfile == 0)
|
||||
if (xferfile == &execfile)
|
||||
error ("No program file to examine.");
|
||||
else
|
||||
error ("No core dump file or running program to examine.");
|
||||
val = lseek (xferchan, fileptr, 0);
|
||||
if (val < 0)
|
||||
perror_with_name (*xferfile);
|
||||
val = myread (xferchan, myaddr, i);
|
||||
if (val < 0)
|
||||
perror_with_name (*xferfile);
|
||||
}
|
||||
/* If this address is for nonexistent memory,
|
||||
read zeros if reading, or do nothing if writing.
|
||||
Actually, we never right. */
|
||||
else
|
||||
{
|
||||
memset (myaddr, '\0', i);
|
||||
returnval = EIO;
|
||||
}
|
||||
|
||||
memaddr += i;
|
||||
myaddr += i;
|
||||
len -= i;
|
||||
}
|
||||
return returnval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* APCS (ARM procedure call standard) defines the following prologue:
|
||||
|
||||
mov ip, sp
|
||||
[stmfd sp!, {a1,a2,a3,a4}]
|
||||
stmfd sp!, {...,fp,ip,lr,pc}
|
||||
[stfe f7, [sp, #-12]!]
|
||||
[stfe f6, [sp, #-12]!]
|
||||
[stfe f5, [sp, #-12]!]
|
||||
[stfe f4, [sp, #-12]!]
|
||||
sub fp, ip, #nn // nn == 20 or 4 depending on second ins
|
||||
*/
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue(pc)
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
CORE_ADDR skip_pc = pc;
|
||||
#if 0
|
||||
union insn_fmt op;
|
||||
|
||||
op.ins = read_memory_integer(skip_pc, 4);
|
||||
/* look for the "mov ip,sp" */
|
||||
if (op.generic.type != TYPE_ARITHMETIC ||
|
||||
op.arith.opcode != OPCODE_MOV ||
|
||||
op.arith.dest != SPTEMP ||
|
||||
op.arith.operand2 != SP) return pc;
|
||||
skip_pc += 4;
|
||||
/* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */
|
||||
op.ins = read_memory_integer(skip_pc, 4);
|
||||
if (op.generic.type == TYPE_BLOCK_BRANCH &&
|
||||
op.generic.subtype == SUBTYPE_BLOCK &&
|
||||
op.block.mask == 0xf &&
|
||||
op.block.base == SP &&
|
||||
op.block.is_load == 0 &&
|
||||
op.block.writeback == 1 &&
|
||||
op.block.increment == 0 &&
|
||||
op.block.before == 1) skip_pc += 4;
|
||||
/* skip the "stmfd sp!,{...,fp,ip,lr,pc} */
|
||||
op.ins = read_memory_integer(skip_pc, 4);
|
||||
if (op.generic.type != TYPE_BLOCK_BRANCH ||
|
||||
op.generic.subtype != SUBTYPE_BLOCK ||
|
||||
/* the mask should look like 110110xxxxxx0000 */
|
||||
(op.block.mask & 0xd800) != 0xd800 ||
|
||||
op.block.base != SP ||
|
||||
op.block.is_load != 0 ||
|
||||
op.block.writeback != 1 ||
|
||||
op.block.increment != 0 ||
|
||||
op.block.before != 1) return pc;
|
||||
skip_pc += 4;
|
||||
/* check for "sub fp,ip,#nn" */
|
||||
op.ins = read_memory_integer(skip_pc, 4);
|
||||
if (op.generic.type != TYPE_ARITHMETIC ||
|
||||
op.arith.opcode != OPCODE_SUB ||
|
||||
op.arith.dest != FP ||
|
||||
op.arith.operand1 != SPTEMP) return pc;
|
||||
#endif
|
||||
return skip_pc + 4;
|
||||
}
|
||||
|
||||
void
|
||||
arm_frame_find_saved_regs (frame_info, saved_regs_addr)
|
||||
struct frame_info *frame_info;
|
||||
struct frame_saved_regs *saved_regs_addr;
|
||||
{
|
||||
register int regnum;
|
||||
register int frame;
|
||||
register int next_addr;
|
||||
register int return_data_save;
|
||||
register int saved_register_mask;
|
||||
|
||||
memset (saved_regs_addr, '\0', sizeof (*saved_regs_addr));
|
||||
frame = frame_info->frame;
|
||||
return_data_save = read_memory_integer (frame, 4) & 0x03fffffc - 12;
|
||||
saved_register_mask = read_memory_integer (return_data_save, 4);
|
||||
next_addr = frame - 12;
|
||||
for (regnum = 4; regnum < 10; regnum++)
|
||||
if (saved_register_mask & (1 << regnum))
|
||||
{
|
||||
next_addr -= 4;
|
||||
saved_regs_addr->regs[regnum] = next_addr;
|
||||
}
|
||||
if (read_memory_integer (return_data_save + 4, 4) == 0xed6d7103)
|
||||
{
|
||||
next_addr -= 12;
|
||||
saved_regs_addr->regs[F0_REGNUM + 7] = next_addr;
|
||||
}
|
||||
if (read_memory_integer (return_data_save + 8, 4) == 0xed6d6103)
|
||||
{
|
||||
next_addr -= 12;
|
||||
saved_regs_addr->regs[F0_REGNUM + 6] = next_addr;
|
||||
}
|
||||
if (read_memory_integer (return_data_save + 12, 4) == 0xed6d5103)
|
||||
{
|
||||
next_addr -= 12;
|
||||
saved_regs_addr->regs[F0_REGNUM + 5] = next_addr;
|
||||
}
|
||||
if (read_memory_integer(return_data_save + 16, 4) == 0xed6d4103)
|
||||
{
|
||||
next_addr -= 12;
|
||||
saved_regs_addr->regs[F0_REGNUM + 4] = next_addr;
|
||||
}
|
||||
saved_regs_addr->regs[SP_REGNUM] = next_addr;
|
||||
saved_regs_addr->regs[PC_REGNUM] = frame - 4;
|
||||
saved_regs_addr->regs[PS_REGNUM] = frame - 4;
|
||||
saved_regs_addr->regs[FP_REGNUM] = frame - 12;
|
||||
}
|
||||
|
||||
static void
|
||||
print_fpu_flags(flags)
|
||||
int flags;
|
||||
{
|
||||
if (flags & (1 << 0)) fputs("IVO ", stdout);
|
||||
if (flags & (1 << 1)) fputs("DVZ ", stdout);
|
||||
if (flags & (1 << 2)) fputs("OFL ", stdout);
|
||||
if (flags & (1 << 3)) fputs("UFL ", stdout);
|
||||
if (flags & (1 << 4)) fputs("INX ", stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void
|
||||
arm_float_info()
|
||||
{
|
||||
register unsigned long status = read_register(FPS_REGNUM);
|
||||
int type;
|
||||
|
||||
type = (status >> 24) & 127;
|
||||
printf("%s FPU type %d\n",
|
||||
(status & (1<<31)) ? "Hardware" : "Software",
|
||||
type);
|
||||
fputs("mask: ", stdout);
|
||||
print_fpu_flags(status >> 16);
|
||||
fputs("flags: ", stdout);
|
||||
print_fpu_flags(status);
|
||||
}
|
||||
|
||||
|
||||
static void arm_othernames()
|
||||
{
|
||||
static int toggle;
|
||||
static char *original[] = ORIGINAL_REGISTER_NAMES;
|
||||
static char *extra_crispy[] = ADDITIONAL_REGISTER_NAMES;
|
||||
|
||||
memcpy (reg_names, toggle ? extra_crispy : original, sizeof(original));
|
||||
toggle = !toggle;
|
||||
}
|
||||
void
|
||||
_initialize_arm_tdep ()
|
||||
{
|
||||
tm_print_insn = print_insn_little_arm;
|
||||
add_com ("othernames", class_obscure, arm_othernames);
|
||||
}
|
||||
|
||||
/* FIXME: Fill in with the 'right thing', see asm
|
||||
template in arm-convert.s */
|
||||
|
||||
void
|
||||
convert_from_extended (ptr, dbl)
|
||||
void *ptr;
|
||||
double *dbl;
|
||||
{
|
||||
*dbl = *(double*)ptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
convert_to_extended (dbl, ptr)
|
||||
void *ptr;
|
||||
double *dbl;
|
||||
{
|
||||
*(double*)ptr = *dbl;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
arm_nullified_insn (inst)
|
||||
unsigned long inst;
|
||||
{
|
||||
unsigned long cond = inst & 0xf0000000;
|
||||
unsigned long status_reg;
|
||||
|
||||
if (cond == INST_AL || cond == INST_NV)
|
||||
return 0;
|
||||
|
||||
status_reg = read_register (PS_REGNUM);
|
||||
|
||||
switch (cond)
|
||||
{
|
||||
case INST_EQ:
|
||||
return ((status_reg & FLAG_Z) == 0);
|
||||
case INST_NE:
|
||||
return ((status_reg & FLAG_Z) != 0);
|
||||
case INST_CS:
|
||||
return ((status_reg & FLAG_C) == 0);
|
||||
case INST_CC:
|
||||
return ((status_reg & FLAG_C) != 0);
|
||||
case INST_MI:
|
||||
return ((status_reg & FLAG_N) == 0);
|
||||
case INST_PL:
|
||||
return ((status_reg & FLAG_N) != 0);
|
||||
case INST_VS:
|
||||
return ((status_reg & FLAG_V) == 0);
|
||||
case INST_VC:
|
||||
return ((status_reg & FLAG_V) != 0);
|
||||
case INST_HI:
|
||||
return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
|
||||
case INST_LS:
|
||||
return (((status_reg & (FLAG_C | FLAG_Z)) ^ FLAG_C) == 0);
|
||||
case INST_GE:
|
||||
return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0));
|
||||
case INST_LT:
|
||||
return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
|
||||
case INST_GT:
|
||||
return (((status_reg & FLAG_Z) != 0) ||
|
||||
(((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)));
|
||||
case INST_LE:
|
||||
return (((status_reg & FLAG_Z) == 0) &&
|
||||
(((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* taken from remote-arm.c .. */
|
||||
|
||||
#define submask(x) ((1L << ((x) + 1)) - 1)
|
||||
#define bit(obj,st) (((obj) & (1L << (st))) >> st)
|
||||
#define bits(obj,st,fn) \
|
||||
(((obj) & submask (fn) & ~ submask ((st) - 1)) >> (st))
|
||||
#define sbits(obj,st,fn) \
|
||||
((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
|
||||
#define BranchDest(addr,instr) \
|
||||
((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
|
||||
#define ARM_PC_32 1
|
||||
|
||||
static unsigned long
|
||||
shifted_reg_val (inst, carry, pc_val)
|
||||
unsigned long inst;
|
||||
int carry;
|
||||
unsigned long pc_val;
|
||||
{
|
||||
unsigned long res, shift;
|
||||
int rm = bits (inst, 0, 3);
|
||||
unsigned long shifttype = bits (inst, 5, 6);
|
||||
|
||||
if (bit(inst, 4))
|
||||
{
|
||||
int rs = bits (inst, 8, 11);
|
||||
shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF;
|
||||
}
|
||||
else
|
||||
shift = bits (inst, 7, 11);
|
||||
|
||||
res = (rm == 15
|
||||
? ((pc_val | (ARM_PC_32 ? 0 : read_register (PS_REGNUM)))
|
||||
+ (bit (inst, 4) ? 12 : 8))
|
||||
: read_register (rm));
|
||||
|
||||
switch (shifttype)
|
||||
{
|
||||
case 0: /* LSL */
|
||||
res = shift >= 32 ? 0 : res << shift;
|
||||
break;
|
||||
|
||||
case 1: /* LSR */
|
||||
res = shift >= 32 ? 0 : res >> shift;
|
||||
break;
|
||||
|
||||
case 2: /* ASR */
|
||||
if (shift >= 32) shift = 31;
|
||||
res = ((res & 0x80000000L)
|
||||
? ~((~res) >> shift) : res >> shift);
|
||||
break;
|
||||
|
||||
case 3: /* ROR/RRX */
|
||||
shift &= 31;
|
||||
if (shift == 0)
|
||||
res = (res >> 1) | (carry ? 0x80000000L : 0);
|
||||
else
|
||||
res = (res >> shift) | (res << (32-shift));
|
||||
break;
|
||||
}
|
||||
|
||||
return res & 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
CORE_ADDR
|
||||
arm_get_next_pc (pc)
|
||||
CORE_ADDR pc;
|
||||
{
|
||||
unsigned long pc_val = (unsigned long) pc;
|
||||
unsigned long this_instr = read_memory_integer (pc, 4);
|
||||
unsigned long status = read_register (PS_REGNUM);
|
||||
CORE_ADDR nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */
|
||||
|
||||
if (! arm_nullified_insn (this_instr))
|
||||
{
|
||||
switch (bits(this_instr, 24, 27))
|
||||
{
|
||||
case 0x0: case 0x1: /* data processing */
|
||||
case 0x2: case 0x3:
|
||||
{
|
||||
unsigned long operand1, operand2, result = 0;
|
||||
unsigned long rn;
|
||||
int c;
|
||||
|
||||
if (bits(this_instr, 12, 15) != 15)
|
||||
break;
|
||||
|
||||
if (bits (this_instr, 22, 25) == 0
|
||||
&& bits (this_instr, 4, 7) == 9) /* multiply */
|
||||
error ("Illegal update to pc in instruction");
|
||||
|
||||
/* Multiply into PC */
|
||||
c = (status & FLAG_C) ? 1 : 0;
|
||||
rn = bits (this_instr, 16, 19);
|
||||
operand1 = (rn == 15) ? pc_val + 8 : read_register (rn);
|
||||
|
||||
if (bit (this_instr, 25))
|
||||
{
|
||||
unsigned long immval = bits (this_instr, 0, 7);
|
||||
unsigned long rotate = 2 * bits (this_instr, 8, 11);
|
||||
operand2 = ((immval >> rotate) | (immval << (32-rotate))
|
||||
& 0xffffffff);
|
||||
}
|
||||
else /* operand 2 is a shifted register */
|
||||
operand2 = shifted_reg_val (this_instr, c, pc_val);
|
||||
|
||||
switch (bits (this_instr, 21, 24))
|
||||
{
|
||||
case 0x0: /*and*/
|
||||
result = operand1 & operand2;
|
||||
break;
|
||||
|
||||
case 0x1: /*eor*/
|
||||
result = operand1 ^ operand2;
|
||||
break;
|
||||
|
||||
case 0x2: /*sub*/
|
||||
result = operand1 - operand2;
|
||||
break;
|
||||
|
||||
case 0x3: /*rsb*/
|
||||
result = operand2 - operand1;
|
||||
break;
|
||||
|
||||
case 0x4: /*add*/
|
||||
result = operand1 + operand2;
|
||||
break;
|
||||
|
||||
case 0x5: /*adc*/
|
||||
result = operand1 + operand2 + c;
|
||||
break;
|
||||
|
||||
case 0x6: /*sbc*/
|
||||
result = operand1 - operand2 + c;
|
||||
break;
|
||||
|
||||
case 0x7: /*rsc*/
|
||||
result = operand2 - operand1 + c;
|
||||
break;
|
||||
|
||||
case 0x8: case 0x9: case 0xa: case 0xb: /* tst, teq, cmp, cmn */
|
||||
result = (unsigned long) nextpc;
|
||||
break;
|
||||
|
||||
case 0xc: /*orr*/
|
||||
result = operand1 | operand2;
|
||||
break;
|
||||
|
||||
case 0xd: /*mov*/
|
||||
/* Always step into a function. */
|
||||
result = operand2;
|
||||
break;
|
||||
|
||||
case 0xe: /*bic*/
|
||||
result = operand1 & ~operand2;
|
||||
break;
|
||||
|
||||
case 0xf: /*mvn*/
|
||||
result = ~operand2;
|
||||
break;
|
||||
}
|
||||
nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
|
||||
|
||||
if (nextpc == pc)
|
||||
error ("Infinite loop detected");
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x4: case 0x5: /* data transfer */
|
||||
case 0x6: case 0x7:
|
||||
if (bit (this_instr, 20))
|
||||
{
|
||||
/* load */
|
||||
if (bits (this_instr, 12, 15) == 15)
|
||||
{
|
||||
/* rd == pc */
|
||||
unsigned long rn;
|
||||
unsigned long base;
|
||||
|
||||
if (bit (this_instr, 22))
|
||||
error ("Illegal update to pc in instruction");
|
||||
|
||||
/* byte write to PC */
|
||||
rn = bits (this_instr, 16, 19);
|
||||
base = (rn == 15) ? pc_val + 8 : read_register (rn);
|
||||
if (bit (this_instr, 24))
|
||||
{
|
||||
/* pre-indexed */
|
||||
int c = (status & FLAG_C) ? 1 : 0;
|
||||
unsigned long offset =
|
||||
(bit (this_instr, 25)
|
||||
? shifted_reg_val (this_instr, c, pc_val)
|
||||
: bits (this_instr, 0, 11));
|
||||
|
||||
if (bit (this_instr, 23))
|
||||
base += offset;
|
||||
else
|
||||
base -= offset;
|
||||
}
|
||||
nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
|
||||
4);
|
||||
|
||||
nextpc = ADDR_BITS_REMOVE (nextpc);
|
||||
|
||||
if (nextpc == pc)
|
||||
error ("Infinite loop detected");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8: case 0x9: /* block transfer */
|
||||
if (bit (this_instr, 20))
|
||||
{
|
||||
/* LDM */
|
||||
if (bit (this_instr, 15))
|
||||
{
|
||||
/* loading pc */
|
||||
int offset = 0;
|
||||
|
||||
if (bit (this_instr, 23))
|
||||
{
|
||||
/* up */
|
||||
unsigned long reglist = bits (this_instr, 0, 14);
|
||||
unsigned long regbit;
|
||||
|
||||
for (; reglist != 0; reglist &= ~regbit)
|
||||
{
|
||||
regbit = reglist & (-reglist);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if (bit (this_instr, 24)) /* pre */
|
||||
offset += 4;
|
||||
}
|
||||
else if (bit (this_instr, 24))
|
||||
offset = -4;
|
||||
|
||||
{
|
||||
unsigned long rn_val =
|
||||
read_register (bits (this_instr, 16, 19));
|
||||
nextpc =
|
||||
(CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
|
||||
+ offset),
|
||||
4);
|
||||
}
|
||||
nextpc = ADDR_BITS_REMOVE (nextpc);
|
||||
if (nextpc == pc)
|
||||
error ("Infinite loop detected");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xb: /* branch & link */
|
||||
case 0xa: /* branch */
|
||||
{
|
||||
nextpc = BranchDest (pc, this_instr);
|
||||
|
||||
nextpc = ADDR_BITS_REMOVE (nextpc);
|
||||
if (nextpc == pc)
|
||||
error ("Infinite loop detected");
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xc: case 0xd:
|
||||
case 0xe: /* coproc ops */
|
||||
case 0xf: /* SWI */
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "Bad bit-field extraction\n");
|
||||
return (pc);
|
||||
}
|
||||
}
|
||||
|
||||
return nextpc;
|
||||
}
|
||||
|
|
@ -1,276 +0,0 @@
|
|||
/* Acorn Risc Machine host machine support.
|
||||
Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "arm-opcode.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#define N_TXTADDR(hdr) 0x8000
|
||||
#define N_DATADDR(hdr) (hdr.a_text + 0x8000)
|
||||
|
||||
#include "gdbcore.h"
|
||||
|
||||
#include <sys/user.h> /* After a.out.h */
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno; /* Original value discarded */
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct user u;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0)
|
||||
- KERNEL_U_ADDR;
|
||||
|
||||
registers_fetched ();
|
||||
|
||||
for (regno = 0; regno < 16; regno++)
|
||||
{
|
||||
regaddr = offset + regno * 4;
|
||||
*(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
if (regno == PC_REGNUM)
|
||||
*(int *)&buf[0] = GET_PC_PART(*(int *)&buf[0]);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
*(int *)&buf[0] = ptrace (PT_READ_U, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (offset + PC*4), 0);
|
||||
supply_register (PS_REGNUM, buf); /* set virtual register ps same as pc */
|
||||
|
||||
/* read the floating point registers */
|
||||
offset = (char *) &u.u_fp_regs - (char *)&u;
|
||||
*(int *)buf = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0);
|
||||
supply_register (FPS_REGNUM, buf);
|
||||
for (regno = 16; regno < 24; regno++) {
|
||||
regaddr = offset + 4 + 12 * (regno - 16);
|
||||
for (i = 0; i < 12; i += sizeof(int))
|
||||
*(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (regaddr + i), 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). */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct user u;
|
||||
unsigned long value;
|
||||
unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
|
||||
offset = ptrace (PT_READ_U, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0)
|
||||
- KERNEL_U_ADDR;
|
||||
|
||||
if (regno >= 0) {
|
||||
if (regno >= 16) return;
|
||||
regaddr = offset + 4 * regno;
|
||||
errno = 0;
|
||||
value = read_register(regno);
|
||||
if (regno == PC_REGNUM)
|
||||
value = SET_PC_PART(read_register (PS_REGNUM), value);
|
||||
ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, value);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else for (regno = 0; regno < 15; regno++)
|
||||
{
|
||||
regaddr = offset + regno * 4;
|
||||
errno = 0;
|
||||
value = read_register(regno);
|
||||
if (regno == PC_REGNUM)
|
||||
value = SET_PC_PART(read_register (PS_REGNUM), value);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, value);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing all regs, number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in corefile.c if it weren't machine-dependent. */
|
||||
|
||||
/* Structure to describe the chain of shared libraries used
|
||||
by the execfile.
|
||||
e.g. prog shares Xt which shares X11 which shares c. */
|
||||
|
||||
struct shared_library {
|
||||
struct exec_header header;
|
||||
char name[SHLIBLEN];
|
||||
CORE_ADDR text_start; /* CORE_ADDR of 1st byte of text, this file */
|
||||
long data_offset; /* offset of data section in file */
|
||||
int chan; /* file descriptor for the file */
|
||||
struct shared_library *shares; /* library this one shares */
|
||||
};
|
||||
static struct shared_library *shlib = 0;
|
||||
|
||||
/* Hook for `exec_file_command' command to call. */
|
||||
|
||||
extern void (*exec_file_display_hook) ();
|
||||
|
||||
static CORE_ADDR unshared_text_start;
|
||||
|
||||
/* extended header from exec file (for shared library info) */
|
||||
|
||||
static struct exec_header exec_header;
|
||||
|
||||
void
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
filename = tilde_expand (filename);
|
||||
make_cleanup (free, filename);
|
||||
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the program with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
|
||||
unsigned int reg_offset, fp_reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name ("Not a core file: reading upage");
|
||||
if (val != sizeof u)
|
||||
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;
|
||||
fp_reg_offset = (char *) &u.u_fp_regs - (char *)&u;
|
||||
|
||||
/* 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. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
if (regno < 16)
|
||||
val = lseek (corechan, reg_offset + 4 * regno, 0);
|
||||
else if (regno < 24)
|
||||
val = lseek (corechan, fp_reg_offset + 4 + 12*(regno - 24), 0);
|
||||
else if (regno == 24)
|
||||
val = lseek (corechan, fp_reg_offset, 0);
|
||||
else if (regno == 25)
|
||||
val = lseek (corechan, reg_offset + 4 * PC, 0);
|
||||
if (val < 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);
|
||||
}
|
||||
|
||||
if (regno == PC_REGNUM)
|
||||
*(int *)buf = GET_PC_PART(*(int *)buf);
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename, NULL);
|
||||
}
|
||||
|
||||
flush_cached_frames ();
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf ("No core file now.\n");
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/* Handle COFF SVR3 shared libraries for GDB, the GNU Debugger.
|
||||
Copyright 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "frame.h"
|
||||
#include "bfd.h"
|
||||
#include "gdbcore.h"
|
||||
#include "symtab.h"
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
coff_solib_add -- add a shared library files to the symtab list. We
|
||||
examine the `.lib' section of the exec file and determine the names of
|
||||
the shared libraries.
|
||||
|
||||
This function is responsible for discovering those names and
|
||||
addresses, and saving sufficient information about them to allow
|
||||
their symbols to be read at a later time.
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void coff_solib_add (char *arg_string, int from_tty,
|
||||
struct target_ops *target)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
coff_solib_add (arg_string, from_tty, target)
|
||||
char *arg_string;
|
||||
int from_tty;
|
||||
struct target_ops *target;
|
||||
{
|
||||
asection *libsect;
|
||||
|
||||
libsect = bfd_get_section_by_name (exec_bfd, ".lib");
|
||||
|
||||
if (libsect)
|
||||
{
|
||||
int libsize;
|
||||
unsigned char *lib;
|
||||
struct libent
|
||||
{
|
||||
bfd_byte len[4];
|
||||
bfd_byte nameoffset[4];
|
||||
};
|
||||
|
||||
libsize = bfd_section_size (exec_bfd, libsect);
|
||||
|
||||
lib = (unsigned char *) alloca (libsize);
|
||||
|
||||
bfd_get_section_contents (exec_bfd, libsect, lib, 0, libsize);
|
||||
|
||||
while (libsize > 0)
|
||||
{
|
||||
struct libent *ent;
|
||||
struct objfile *objfile;
|
||||
int len, nameoffset;
|
||||
char *filename;
|
||||
|
||||
ent = (struct libent *)lib;
|
||||
|
||||
len = bfd_get_32 (exec_bfd, ent->len);
|
||||
|
||||
nameoffset = bfd_get_32 (exec_bfd, ent->nameoffset);
|
||||
|
||||
if (len <= 0)
|
||||
break;
|
||||
|
||||
filename = (char *)ent + nameoffset * 4;
|
||||
|
||||
objfile = symbol_file_add (filename, from_tty,
|
||||
0, /* addr */
|
||||
0, /* not mainline */
|
||||
0, /* not mapped */
|
||||
0); /* Not readnow */
|
||||
libsize -= len * 4;
|
||||
lib += len * 4;
|
||||
}
|
||||
|
||||
/* Getting new symbols may change our opinion about what is
|
||||
frameless. */
|
||||
reinit_frame_cache ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
coff_solib_create_inferior_hook -- shared library startup support
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void coff_solib_create_inferior_hook()
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
When gdb starts up the inferior, the kernel maps in the shared
|
||||
libraries. We get here with the target stopped at it's first
|
||||
instruction, and the libraries already mapped. At this point, this
|
||||
function gets called via expansion of the macro
|
||||
SOLIB_CREATE_INFERIOR_HOOK.
|
||||
*/
|
||||
|
||||
void
|
||||
coff_solib_create_inferior_hook()
|
||||
{
|
||||
coff_solib_add ((char *) 0, 0, (struct target_ops *) 0);
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/* COFF (SVR3) Shared library declarations for GDB, the GNU Debugger.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef __STDC__ /* Forward decl's for prototypes */
|
||||
struct target_ops;
|
||||
#endif
|
||||
|
||||
/* Called when we free all symtabs, to free the shared library information
|
||||
as well. */
|
||||
|
||||
#if 0
|
||||
#define CLEAR_SOLIB coff_clear_solib
|
||||
|
||||
extern void
|
||||
coff_clear_solib PARAMS ((void));
|
||||
#endif
|
||||
|
||||
/* Called to add symbols from a shared library to gdb's symbol table. */
|
||||
|
||||
#define SOLIB_ADD(filename, from_tty, targ) \
|
||||
coff_solib_add (filename, from_tty, targ)
|
||||
|
||||
extern void
|
||||
coff_solib_add PARAMS ((char *, int, struct target_ops *));
|
||||
|
||||
/* Function to be called when the inferior starts up, to discover the names
|
||||
of shared libraries that are dynamically linked, the base addresses to
|
||||
which they are linked, and sufficient information to read in their symbols
|
||||
at a later time. */
|
||||
|
||||
#define SOLIB_CREATE_INFERIOR_HOOK(PID) coff_solib_create_inferior_hook()
|
||||
|
||||
extern void
|
||||
coff_solib_create_inferior_hook PARAMS((void)); /* solib.c */
|
||||
|
||||
/* If we can't set a breakpoint, and it's in a shared library, just
|
||||
disable it. */
|
||||
|
||||
#if 0
|
||||
#define DISABLE_UNSETTABLE_BREAK(addr) coff_solib_address(addr)
|
||||
|
||||
extern int
|
||||
solib_address PARAMS ((CORE_ADDR)); /* solib.c */
|
||||
#endif
|
|
@ -1,2 +0,0 @@
|
|||
/* This is just a dummy file to symlink to when GDB is configured as a
|
||||
cross-only debugger. */
|
|
@ -1,46 +0,0 @@
|
|||
/* Common declarations for the GNU Hurd
|
||||
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
Written by Miles Bader <miles@gnu.ai.mit.edu>
|
||||
|
||||
The GNU Hurd 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 2, or (at
|
||||
your option) any later version.
|
||||
|
||||
The GNU Hurd 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef __NM_GNU_H__
|
||||
#define __NM_GNU_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <mach.h>
|
||||
#include <mach/exception.h>
|
||||
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
|
||||
#undef target_pid_to_str
|
||||
#define target_pid_to_str(pid) gnu_target_pid_to_str(pid)
|
||||
extern char *gnu_target_pid_to_str (int pid);
|
||||
|
||||
/* Before storing, we need to read all the registers. */
|
||||
#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES)
|
||||
|
||||
/* Don't do wait_for_inferior on attach. */
|
||||
#define ATTACH_NO_WAIT
|
||||
|
||||
/* Use SVR4 style shared library support */
|
||||
#define SVR4_SHARED_LIBS
|
||||
#define NO_CORE_OPS
|
||||
|
||||
#define MAINTENANCE_CMDS 1
|
||||
|
||||
#endif /* __NM_GNU_H__ */
|
|
@ -1,83 +0,0 @@
|
|||
/* Native-dependent definitions for LynxOS.
|
||||
Copyright 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef NM_LYNX_H
|
||||
#define NM_LYNX_H
|
||||
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
/* sys/kernel.h should define this, but doesn't always, sigh. */
|
||||
#ifndef __LYNXOS
|
||||
#define __LYNXOS
|
||||
#endif
|
||||
#include <sys/mem.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/itimer.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/proc.h>
|
||||
#include "thread.h"
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0 to get the offset in
|
||||
the core file of the register values. */
|
||||
|
||||
#define KERNEL_U_ADDR USRSTACK
|
||||
|
||||
#undef FLOAT_INFO /* No float info yet */
|
||||
|
||||
/* As of LynxOS 2.2.2 (beta 8/15/94), this is int. Previous versions seem to
|
||||
have had no prototype, so I'm not sure why GDB used to define this to
|
||||
char *. */
|
||||
#define PTRACE_ARG3_TYPE int
|
||||
|
||||
/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
|
||||
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
|
||||
/* Thread ID of stopped thread. */
|
||||
|
||||
#define WIFTID(x) (((union wait *)&x)->w_tid)
|
||||
|
||||
/* Override child_wait in inftarg.c */
|
||||
|
||||
#define CHILD_WAIT
|
||||
|
||||
/* Override child_resume in infptrace.c */
|
||||
|
||||
#define CHILD_RESUME
|
||||
|
||||
/* Override child_thread_alive in intarg.c */
|
||||
|
||||
#define CHILD_THREAD_ALIVE
|
||||
|
||||
#include "target.h"
|
||||
|
||||
extern int child_wait PARAMS ((int pid, struct target_waitstatus *status));
|
||||
|
||||
/* Lynx needs a special definition of this so that we can
|
||||
print out the pid and thread number seperatly. */
|
||||
|
||||
#undef target_pid_to_str
|
||||
|
||||
#define target_pid_to_str(PID) lynx_pid_to_str (PID)
|
||||
|
||||
extern char *lynx_pid_to_str PARAMS ((int pid));
|
||||
|
||||
#endif /* NM_LYNX_H */
|
|
@ -1,123 +0,0 @@
|
|||
/* Mach 3.0 common definitions and global vars.
|
||||
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef NM_M3_H
|
||||
#define NM_M3_H
|
||||
|
||||
#include <mach.h>
|
||||
|
||||
/* Mach3 doesn't declare errno in <errno.h>. */
|
||||
extern int errno;
|
||||
|
||||
/* Task port of our debugged inferior. */
|
||||
|
||||
extern task_t inferior_task;
|
||||
|
||||
/* Thread port of the current thread in the inferior. */
|
||||
|
||||
extern thread_t current_thread;
|
||||
|
||||
/* If nonzero, we must suspend/abort && resume threads
|
||||
* when setting or getting the state.
|
||||
*/
|
||||
extern int must_suspend_thread;
|
||||
|
||||
#define PREPARE_TO_PROCEED(select_it) mach3_prepare_to_proceed(select_it)
|
||||
|
||||
/* Try to get the privileged host port for authentication to machid
|
||||
*
|
||||
* If you can get this, you may debug anything on this host.
|
||||
*
|
||||
* If you can't, gdb gives it's own task port as the
|
||||
* authentication port
|
||||
*/
|
||||
#define mach_privileged_host_port() task_by_pid(-1)
|
||||
|
||||
/*
|
||||
* This is the MIG ID number of the emulator/server bsd_execve() RPC call.
|
||||
*
|
||||
* It SHOULD never change, but if it does, gdb `run'
|
||||
* command won't work until you fix this define.
|
||||
*
|
||||
*/
|
||||
#define MIG_EXEC_SYSCALL_ID 101000
|
||||
|
||||
/* If our_message_port gets a msg with this ID,
|
||||
* GDB suspends it's inferior and enters command level.
|
||||
* (Useful at least if ^C does not work)
|
||||
*/
|
||||
#define GDB_MESSAGE_ID_STOP 0x41151
|
||||
|
||||
/* wait3 WNOHANG is defined in <sys/wait.h> but
|
||||
* for some reason gdb does not want to include
|
||||
* that file.
|
||||
*
|
||||
* If your system defines WNOHANG differently, this has to be changed.
|
||||
*/
|
||||
#define WNOHANG 1
|
||||
|
||||
/* Before storing, we need to read all the registers. */
|
||||
|
||||
#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES)
|
||||
|
||||
/* Check if the inferior exists */
|
||||
#define MACH_ERROR_NO_INFERIOR \
|
||||
do if (!MACH_PORT_VALID (inferior_task)) \
|
||||
error ("Inferior task does not exist."); while(0)
|
||||
|
||||
/* Error handler for mach calls */
|
||||
#define CHK(str,ret) \
|
||||
do if (ret != KERN_SUCCESS) \
|
||||
error ("Gdb %s [%d] %s : %s\n",__FILE__,__LINE__,str, \
|
||||
mach_error_string(ret)); while(0)
|
||||
|
||||
/* This is from POE9 emulator/emul_stack.h
|
||||
*/
|
||||
/*
|
||||
* Top of emulator stack holds link and reply port.
|
||||
*/
|
||||
struct emul_stack_top {
|
||||
struct emul_stack_top *link;
|
||||
mach_port_t reply_port;
|
||||
};
|
||||
|
||||
#define EMULATOR_STACK_SIZE (4096*4)
|
||||
|
||||
#define THREAD_ALLOWED_TO_BREAK(mid) mach_thread_for_breakpoint (mid)
|
||||
|
||||
#define THREAD_PARSE_ID(arg) mach_thread_parse_id (arg)
|
||||
|
||||
#define THREAD_OUTPUT_ID(mid) mach_thread_output_id (mid)
|
||||
|
||||
#define ATTACH_TO_THREAD attach_to_thread
|
||||
|
||||
/* Don't do wait_for_inferior on attach. */
|
||||
#define ATTACH_NO_WAIT
|
||||
|
||||
/* Do Mach 3 dependent operations when ^C or a STOP is requested */
|
||||
#define DO_QUIT() mach3_quit ()
|
||||
|
||||
#if 0
|
||||
/* This is bogus. It is NOT OK to quit out of target_wait. */
|
||||
/* If in mach_msg() and ^C is typed set immediate_quit */
|
||||
#define REQUEST_QUIT() mach3_request_quit ()
|
||||
#endif
|
||||
|
||||
#endif /* NM_M3_H */
|
|
@ -1,86 +0,0 @@
|
|||
/* Native-dependent definitions for NetBSD.
|
||||
Copyright 1994, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
to get the offset in the core file of the register values. */
|
||||
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#define KERNEL_U_ADDR USRSTACK
|
||||
|
||||
#define PTRACE_ARG3_TYPE char*
|
||||
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
|
||||
#define ATTACH_DETACH
|
||||
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
|
||||
/* make structure definitions match up with those expected in solib.c */
|
||||
#define link_object sod
|
||||
#define lo_name sod_name
|
||||
#define lo_library sod_library
|
||||
#define lo_unused sod_reserved
|
||||
#define lo_major sod_major
|
||||
#define lo_minor sod_minor
|
||||
#define lo_next sod_next
|
||||
|
||||
#define link_map so_map
|
||||
#define lm_addr som_addr
|
||||
#define lm_name som_path
|
||||
#define lm_next som_next
|
||||
#define lm_lop som_sod
|
||||
#define lm_lob som_sodbase
|
||||
#define lm_rwt som_write
|
||||
#define lm_ld som_dynamic
|
||||
#define lm_lpd som_spd
|
||||
|
||||
#define link_dynamic_2 section_dispatch_table
|
||||
#define ld_loaded sdt_loaded
|
||||
#define ld_need sdt_sods
|
||||
#define ld_rules sdt_filler1
|
||||
#define ld_got sdt_got
|
||||
#define ld_plt sdt_plt
|
||||
#define ld_rel sdt_rel
|
||||
#define ld_hash sdt_hash
|
||||
#define ld_stab sdt_nzlist
|
||||
#define ld_stab_hash sdt_filler2
|
||||
#define ld_buckets sdt_buckets
|
||||
#define ld_symbols sdt_strings
|
||||
#define ld_symb_size sdt_str_sz
|
||||
#define ld_text sdt_text_sz
|
||||
#define ld_plt_sz sdt_plt_sz
|
||||
|
||||
#define rtc_symb rt_symbol
|
||||
#define rtc_sp rt_sp
|
||||
#define rtc_next rt_next
|
||||
|
||||
#define ld_debug so_debug
|
||||
#define ldd_version dd_version
|
||||
#define ldd_in_debugger dd_in_debugger
|
||||
#define ldd_sym_loaded dd_sym_loaded
|
||||
#define ldd_bp_addr dd_bpt_addr
|
||||
#define ldd_bp_inst dd_bpt_shadow
|
||||
#define ldd_cp dd_cc
|
||||
|
||||
#define link_dynamic _dynamic
|
||||
#define ld_version d_version
|
||||
#define ldd d_debug
|
||||
#define ld_un d_un
|
||||
#define ld_2 d_sdt
|
|
@ -1,34 +0,0 @@
|
|||
/* Definitions for running gdb on a host machine running any flavor of SVR4.
|
||||
Copyright 1991, 1992 Free Software Foundation, Inc.
|
||||
Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
|
||||
/* Use SVR4 style shared library support */
|
||||
|
||||
#define SVR4_SHARED_LIBS
|
||||
|
||||
/* SVR4 has /proc support, so use it instead of ptrace. */
|
||||
|
||||
#define USE_PROC_FS
|
||||
|
||||
/* SVR4 machines can easily do attach and detach via /proc (procfs.c)
|
||||
support */
|
||||
|
||||
#define ATTACH_DETACH
|
|
@ -1,34 +0,0 @@
|
|||
/* Macro definitions for LynxOS targets.
|
||||
Copyright 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef TM_LYNX_H
|
||||
#define TM_LYNX_H
|
||||
|
||||
/* Override number of expected traps from sysv. */
|
||||
#define START_INFERIOR_TRAPS_EXPECTED 2
|
||||
|
||||
#include "coff-solib.h" /* COFF shared library support */
|
||||
|
||||
/* Lynx's signal.h doesn't seem to have any macros for what signal numbers
|
||||
the real-time events are. */
|
||||
#define REALTIME_LO 33
|
||||
/* One more than the last one. */
|
||||
#define REALTIME_HI 64
|
||||
|
||||
#endif /* TM_LYNX_H */
|
|
@ -1,19 +0,0 @@
|
|||
/* Target machine sub-description for NetBSD.
|
||||
This is included by other tm-*.h files to specify NetBSD-specific stuff.
|
||||
Copyright 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
@ -1,31 +0,0 @@
|
|||
/* Target machine sub-description for SunOS version 4.
|
||||
This is included by other tm-*.h files to specify SunOS-specific stuff.
|
||||
Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
|
||||
/* Return non-zero if we are in a shared library trampoline code stub. */
|
||||
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \
|
||||
lookup_solib_trampoline_symbol_by_pc (pc)
|
||||
|
||||
/* If PC is in a shared library trampoline code, return the PC
|
||||
where the function itself actually starts. If not, return 0. */
|
||||
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc)
|
|
@ -1,45 +0,0 @@
|
|||
/* Macro definitions for GDB on all SVR4 target systems.
|
||||
Copyright 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* For SVR4 shared libraries, each call to a library routine goes through
|
||||
a small piece of trampoline code in the ".plt" section.
|
||||
The horribly ugly wait_for_inferior() routine uses this macro to detect
|
||||
when we have stepped into one of these fragments.
|
||||
We do not use lookup_solib_trampoline_symbol_by_pc, because
|
||||
we cannot always find the shared library trampoline symbols
|
||||
(e.g. on Irix5). */
|
||||
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) in_plt_section((pc), (name))
|
||||
extern int in_plt_section PARAMS ((CORE_ADDR, char *));
|
||||
|
||||
/* If PC is in a shared library trampoline code, return the PC
|
||||
where the function itself actually starts. If not, return 0. */
|
||||
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc)
|
||||
|
||||
/* It is unknown which, if any, SVR4 assemblers do not accept dollar signs
|
||||
in identifiers. The default in G++ is to use dots instead, for all SVR4
|
||||
systems, so we make that our default also. FIXME: There should be some
|
||||
way to get G++ to tell us what CPLUS_MARKER it is using, perhaps by
|
||||
stashing it in the debugging information as part of the name of an
|
||||
invented symbol ("gcc_cplus_marker$" for example). */
|
||||
|
||||
#undef CPLUS_MARKER
|
||||
#define CPLUS_MARKER '.'
|
|
@ -1,96 +0,0 @@
|
|||
/* Parameters for hosting on an PowerPC, for GDB, the GNU debugger.
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
Contributed by Cygnus Corporation.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* The following text is taken from config/rs6000.mh:
|
||||
* # The IBM version of /usr/include/rpc/rpc.h has a bug -- it says
|
||||
* # `extern fd_set svc_fdset;' without ever defining the type fd_set.
|
||||
* # Unfortunately this occurs in the vx-share code, which is not configured
|
||||
* # like the rest of GDB (e.g. it doesn't include "defs.h").
|
||||
* # We circumvent this bug by #define-ing fd_set here, but undefining it in
|
||||
* # the xm-rs6000.h file before ordinary modules try to use it. FIXME, IBM!
|
||||
* MH_CFLAGS='-Dfd_set=int'
|
||||
* So, here we do the undefine...which has to occur before we include
|
||||
* <sys/select.h> below.
|
||||
*/
|
||||
#undef fd_set
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
/* Big end is at the low address */
|
||||
|
||||
#define HOST_BYTE_ORDER BIG_ENDIAN
|
||||
|
||||
/* At least as of AIX 3.2, we have termios. */
|
||||
#define HAVE_TERMIOS 1
|
||||
/* #define HAVE_TERMIO 1 */
|
||||
|
||||
#define USG 1
|
||||
#define HAVE_SIGSETMASK 1
|
||||
|
||||
#define FIVE_ARG_PTRACE
|
||||
|
||||
/* AIX declares the mem functions differently than defs.h does. AIX is
|
||||
right, but defs.h works on more old systems. For now, override it. */
|
||||
|
||||
#define MEM_FNS_DECLARED 1
|
||||
|
||||
/* This system requires that we open a terminal with O_NOCTTY for it to
|
||||
not become our controlling terminal. */
|
||||
|
||||
#define USE_O_NOCTTY
|
||||
|
||||
/* Brain death inherited from PC's pervades. */
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
|
||||
/* The IBM compiler requires this in order to properly compile alloca(). */
|
||||
#pragma alloca
|
||||
|
||||
/* There is no vfork. */
|
||||
|
||||
#define vfork fork
|
||||
|
||||
/* Signal handler for SIGWINCH `window size changed'. */
|
||||
|
||||
#define SIGWINCH_HANDLER aix_resizewindow
|
||||
extern void aix_resizewindow ();
|
||||
|
||||
/* `lines_per_page' and `chars_per_line' are local to utils.c. Rectify this. */
|
||||
|
||||
#define SIGWINCH_HANDLER_BODY \
|
||||
\
|
||||
/* Respond to SIGWINCH `window size changed' signal, and reset GDB's \
|
||||
window settings approproatelt. */ \
|
||||
\
|
||||
void \
|
||||
aix_resizewindow () \
|
||||
{ \
|
||||
int fd = fileno (stdout); \
|
||||
if (isatty (fd)) { \
|
||||
int val; \
|
||||
\
|
||||
val = atoi (termdef (fd, 'l')); \
|
||||
if (val > 0) \
|
||||
lines_per_page = val; \
|
||||
val = atoi (termdef (fd, 'c')); \
|
||||
if (val > 0) \
|
||||
chars_per_line = val; \
|
||||
} \
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/* Host-dependent definitions for any CPU running LynxOS.
|
||||
Copyright 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* for INT_MIN, to avoid "INT_MIN redefined" warnings from defs.h */
|
||||
|
||||
#include <limits.h>
|
|
@ -1,81 +0,0 @@
|
|||
/* Macro definitions for running GDB on Apple Macintoshes.
|
||||
Copyright (C) 1994, 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "mpw.h"
|
||||
|
||||
#include "fopen-bin.h"
|
||||
|
||||
#include "spin.h"
|
||||
|
||||
#define CANT_FORK
|
||||
|
||||
/* Map these standard functions to versions that can do I/O in a console
|
||||
window. */
|
||||
|
||||
#define printf hacked_printf
|
||||
#define fprintf hacked_fprintf
|
||||
#define vprintf hacked_vfprintf
|
||||
#define fputs hacked_fputs
|
||||
#define fputc hacked_fputc
|
||||
#undef putc
|
||||
#define putc hacked_putc
|
||||
#define fflush hacked_fflush
|
||||
|
||||
#define fgetc hacked_fgetc
|
||||
|
||||
#define POSIX_UTIME
|
||||
|
||||
/* No declaration of strdup in MPW's string.h, oddly enough. */
|
||||
|
||||
char *strdup (char *s1);
|
||||
|
||||
/* '.' indicates drivers on the Mac, so we need a different filename. */
|
||||
|
||||
#define GDBINIT_FILENAME "_gdbinit"
|
||||
|
||||
/* Commas are more common to separate dirnames in a path on Macs. */
|
||||
|
||||
#define DIRNAME_SEPARATOR ','
|
||||
|
||||
/* This is a real crufty hack. */
|
||||
|
||||
#define HAVE_TERMIO
|
||||
|
||||
/* Addons to the basic MPW-supported signal list. */
|
||||
|
||||
#ifndef SIGQUIT
|
||||
#define SIGQUIT (1<<6)
|
||||
#endif
|
||||
#ifndef SIGHUP
|
||||
#define SIGHUP (1<<7)
|
||||
#endif
|
||||
|
||||
/* If __STDC__ is on, then this definition will be missing. */
|
||||
|
||||
#ifndef fileno
|
||||
#define fileno(p) (p)->_file
|
||||
#endif
|
||||
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#endif
|
||||
|
||||
extern int StandAlone;
|
||||
|
||||
extern int mac_app;
|
|
@ -1,37 +0,0 @@
|
|||
/* Host-dependent definitions for any CPU running NetBSD.
|
||||
Copyright 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* We have to include these files now, so that GDB will not make
|
||||
competing definitions in defs.h. */
|
||||
#include <limits.h>
|
||||
|
||||
#include <machine/endian.h>
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define HOST_BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#define HOST_BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* NetBSD has termios facilities. */
|
||||
#define HAVE_TERMIOS
|
||||
|
||||
#if 0
|
||||
#define CC_HAS_LONG_LONG 1
|
||||
#define PRINTF_HAS_LONG_LONG 1
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
/* Definitions for running gdb on a host machine running any flavor of SVR4.
|
||||
Copyright 1991, 1992 Free Software Foundation, Inc.
|
||||
Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* SVR4 has termios facilities. */
|
||||
|
||||
#undef HAVE_TERMIO
|
||||
#define HAVE_TERMIOS
|
||||
|
||||
/* SVR4 is a derivative of System V Release 3 (USG) */
|
||||
|
||||
#define USG
|
||||
|
||||
/* Use setpgid(0,0) to run inferior in a separate process group */
|
||||
|
||||
#define NEED_POSIX_SETPGID
|
||||
|
||||
/* We have to include these files now, so that GDB will not make
|
||||
competing definitions in defs.h. */
|
||||
#include <limits.h>
|
|
@ -1,130 +0,0 @@
|
|||
/* Machine independent GDB support for core files on systems using "regsets".
|
||||
Copyright 1993-1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
/* N O T E S
|
||||
|
||||
This file is used by most systems that implement /proc. For these systems,
|
||||
the general registers are laid out the same way in both the core file and
|
||||
the gregset_p structure. The current exception to this is Irix-4.*, where
|
||||
the gregset_p structure is split up into two pieces in the core file.
|
||||
|
||||
The general register and floating point register sets are manipulated by
|
||||
separate ioctl's. This file makes the assumption that if FP0_REGNUM is
|
||||
defined, then support for the floating point register set is desired,
|
||||
regardless of whether or not the actual target has floating point hardware.
|
||||
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <time.h>
|
||||
#ifdef HAVE_SYS_PROCFS_H
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "command.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
fetch_core_registers -- fetch current registers from core file
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void fetch_core_registers (char *core_reg_sect,
|
||||
unsigned core_reg_size,
|
||||
int which, unsigned in reg_addr)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Read the values of either the general register set (WHICH equals 0)
|
||||
or the floating point register set (WHICH equals 2) from the core
|
||||
file data (pointed to by CORE_REG_SECT), and update gdb's idea of
|
||||
their current values. The CORE_REG_SIZE parameter is ignored.
|
||||
|
||||
NOTES
|
||||
|
||||
Use the indicated sizes to validate the gregset and fpregset
|
||||
structures.
|
||||
*/
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned int reg_addr; /* Unused in this version */
|
||||
{
|
||||
#if defined (HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T)
|
||||
gregset_t gregset;
|
||||
fpregset_t fpregset;
|
||||
|
||||
if (which == 0)
|
||||
{
|
||||
if (core_reg_size != sizeof (gregset))
|
||||
{
|
||||
warning ("wrong size gregset struct in core file");
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
|
||||
supply_gregset (&gregset);
|
||||
}
|
||||
}
|
||||
else if (which == 2)
|
||||
{
|
||||
if (core_reg_size != sizeof (fpregset))
|
||||
{
|
||||
warning ("wrong size fpregset struct in core file");
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
|
||||
#if defined (FP0_REGNUM)
|
||||
supply_fpregset (&fpregset);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* defined(HAVE_GREGSET_T) && defined (HAVE_FPREGSET_T) */
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle ELF file formats using standard
|
||||
procfs "regset" structures. */
|
||||
|
||||
static struct core_fns regset_core_fns =
|
||||
{
|
||||
bfd_target_elf_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_regset ()
|
||||
{
|
||||
add_core_fns (®set_core_fns);
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
/* Machine independent support for Solaris 2 core files for GDB.
|
||||
Copyright 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
/* Solaris comes with two flavours of core files, cores generated by
|
||||
an ELF executable and cores generated by programs that were
|
||||
run under BCP (the part of Solaris which allows it to run SunOS4
|
||||
a.out files).
|
||||
This file combines the core register fetching from core-regset.c
|
||||
and sparc-nat.c to be able to read both flavours. */
|
||||
|
||||
#include "defs.h"
|
||||
#undef gregset_t
|
||||
#undef fpregset_t
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/regset.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "command.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned int reg_addr; /* Unused in this version */
|
||||
{
|
||||
prgregset_t prgregset;
|
||||
prfpregset_t prfpregset;
|
||||
|
||||
if (which == 0)
|
||||
{
|
||||
if (core_reg_size == sizeof (prgregset))
|
||||
{
|
||||
memcpy ((char *) &prgregset, core_reg_sect, sizeof (prgregset));
|
||||
supply_gregset (&prgregset);
|
||||
}
|
||||
else if (core_reg_size == sizeof (struct regs))
|
||||
{
|
||||
#define gregs ((struct regs *)core_reg_sect)
|
||||
/* G0 *always* holds 0. */
|
||||
*(int *)®isters[REGISTER_BYTE (0)] = 0;
|
||||
|
||||
/* The globals and output registers. */
|
||||
memcpy (®isters[REGISTER_BYTE (G1_REGNUM)], &gregs->r_g1,
|
||||
15 * REGISTER_RAW_SIZE (G1_REGNUM));
|
||||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = gregs->r_ps;
|
||||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = gregs->r_pc;
|
||||
*(int *)®isters[REGISTER_BYTE (NPC_REGNUM)] = gregs->r_npc;
|
||||
*(int *)®isters[REGISTER_BYTE (Y_REGNUM)] = gregs->r_y;
|
||||
|
||||
/* My best guess at where to get the locals and input
|
||||
registers is exactly where they usually are, right above
|
||||
the stack pointer. If the core dump was caused by a bus error
|
||||
from blowing away the stack pointer (as is possible) then this
|
||||
won't work, but it's worth the try. */
|
||||
{
|
||||
int sp;
|
||||
|
||||
sp = *(int *)®isters[REGISTER_BYTE (SP_REGNUM)];
|
||||
if (0 != target_read_memory (sp,
|
||||
®isters[REGISTER_BYTE (L0_REGNUM)],
|
||||
16 * REGISTER_RAW_SIZE (L0_REGNUM)))
|
||||
{
|
||||
warning ("couldn't read input and local registers from core file\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warning ("wrong size gregset struct in core file");
|
||||
}
|
||||
}
|
||||
else if (which == 2)
|
||||
{
|
||||
if (core_reg_size == sizeof (prfpregset))
|
||||
{
|
||||
memcpy ((char *) &prfpregset, core_reg_sect, sizeof (prfpregset));
|
||||
supply_fpregset (&prfpregset);
|
||||
}
|
||||
else if (core_reg_size >= sizeof (struct fpu))
|
||||
{
|
||||
#define fpuregs ((struct fpu *) core_reg_sect)
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &fpuregs->fpu_fr,
|
||||
sizeof (fpuregs->fpu_fr));
|
||||
memcpy (®isters[REGISTER_BYTE (FPS_REGNUM)], &fpuregs->fpu_fsr,
|
||||
sizeof (FPU_FSR_TYPE));
|
||||
}
|
||||
else
|
||||
{
|
||||
warning ("wrong size fpregset struct in core file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle solaris core file formats. */
|
||||
|
||||
static struct core_fns solaris_core_fns =
|
||||
{
|
||||
bfd_target_elf_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_solaris ()
|
||||
{
|
||||
add_core_fns (&solaris_core_fns);
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/* Remote debugging interface for CPU32Bug Rom monitor for GDB, the GNU debugger.
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
|
||||
Written by Stu Grossman of Cygnus Support
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
|
||||
static void cpu32bug_open PARAMS ((char *args, int from_tty));
|
||||
|
||||
static void
|
||||
cpu32bug_supply_register (regname, regnamelen, val, vallen)
|
||||
char *regname;
|
||||
int regnamelen;
|
||||
char *val;
|
||||
int vallen;
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (regnamelen != 2)
|
||||
return;
|
||||
|
||||
switch (regname[0])
|
||||
{
|
||||
case 'S':
|
||||
if (regname[1] != 'R')
|
||||
return;
|
||||
regno = PS_REGNUM;
|
||||
break;
|
||||
case 'P':
|
||||
if (regname[1] != 'C')
|
||||
return;
|
||||
regno = PC_REGNUM;
|
||||
break;
|
||||
case 'D':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + D0_REGNUM;
|
||||
break;
|
||||
case 'A':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + A0_REGNUM;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_supply_register (regno, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* This array of registers needs to match the indexes used by GDB. The
|
||||
* whole reason this exists is because the various ROM monitors use
|
||||
* different names than GDB does, and don't support all the
|
||||
* registers either. So, typing "info reg sp" becomes an "A7".
|
||||
*/
|
||||
|
||||
static char *cpu32bug_regnames[NUM_REGS] =
|
||||
{
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
||||
"SR", "PC",
|
||||
};
|
||||
|
||||
/*
|
||||
* Define the monitor command strings. Since these are passed directly
|
||||
* through to a printf style function, we need can include formatting
|
||||
* strings. We also need a CR or LF on the end.
|
||||
*/
|
||||
|
||||
static struct target_ops cpu32bug_ops;
|
||||
|
||||
static char *cpu32bug_inits[] = {"\r", NULL};
|
||||
|
||||
static struct monitor_ops cpu32bug_cmds =
|
||||
{
|
||||
MO_CLR_BREAK_USES_ADDR,
|
||||
cpu32bug_inits, /* Init strings */
|
||||
"g\r", /* continue command */
|
||||
"t\r", /* single step */
|
||||
NULL, /* interrupt command */
|
||||
"br %x\r", /* set a breakpoint */
|
||||
"nobr %x\r", /* clear a breakpoint */
|
||||
"nobr\r", /* clear all breakpoints */
|
||||
"bf %x:%x %x;b\r", /* fill (start count val) */
|
||||
{
|
||||
"ms %x %02x\r", /* setmem.cmdb (addr, value) */
|
||||
"ms %x %04x\r", /* setmem.cmdw (addr, value) */
|
||||
"ms %x %08x\r", /* setmem.cmdl (addr, value) */
|
||||
NULL, /* setmem.cmdll (addr, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL, /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"md %x:%x;b\r", /* getmem.cmdb (addr, len) */
|
||||
"md %x:%x;b\r", /* getmem.cmdw (addr, len) */
|
||||
"md %x:%x;b\r", /* getmem.cmdl (addr, len) */
|
||||
NULL, /* getmem.cmdll (addr, len) */
|
||||
" ", /* getmem.resp_delim */
|
||||
NULL, /* getmem.term */
|
||||
NULL, /* getmem.term_cmd */
|
||||
},
|
||||
{
|
||||
"rs %s %x\r", /* setreg.cmd (name, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"rs %s\r", /* getreg.cmd (name) */
|
||||
"=", /* getreg.resp_delim */
|
||||
NULL, /* getreg.term */
|
||||
NULL /* getreg.term_cmd */
|
||||
},
|
||||
"rd\r", /* dump_registers */
|
||||
"\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)", /* register_pattern */
|
||||
cpu32bug_supply_register, /* supply_register */
|
||||
NULL, /* load_routine (defaults to SRECs) */
|
||||
"lo\r", /* download command */
|
||||
"lo\r\n", /* load response */
|
||||
"CPU32Bug>", /* monitor command prompt */
|
||||
"\r", /* end-of-line terminator */
|
||||
NULL, /* optional command terminator */
|
||||
&cpu32bug_ops, /* target operations */
|
||||
SERIAL_1_STOPBITS, /* number of stop bits */
|
||||
cpu32bug_regnames, /* registers names */
|
||||
MONITOR_OPS_MAGIC /* magic */
|
||||
};
|
||||
|
||||
static void
|
||||
cpu32bug_open(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
monitor_open (args, &cpu32bug_cmds, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_cpu32bug_rom ()
|
||||
{
|
||||
init_monitor_ops (&cpu32bug_ops);
|
||||
|
||||
cpu32bug_ops.to_shortname = "cpu32bug";
|
||||
cpu32bug_ops.to_longname = "CPU32Bug monitor";
|
||||
cpu32bug_ops.to_doc = "Debug via the CPU32Bug monitor.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
cpu32bug_ops.to_open = cpu32bug_open;
|
||||
|
||||
add_target (&cpu32bug_ops);
|
||||
}
|
|
@ -1,523 +0,0 @@
|
|||
/* Native support for Motorola 88k running Harris CX/UX.
|
||||
Copyright 1988, 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include "gdbcore.h"
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "bfd.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "symtab.h"
|
||||
|
||||
#ifndef USER /* added to support BCS ptrace_user */
|
||||
#define USER ptrace_user
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#include "symtab.h"
|
||||
#include "setjmp.h"
|
||||
#include "value.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
/* CX/UX provides them already, but as word offsets instead of char offsets */
|
||||
#define SXIP_OFFSET (PT_SXIP * 4)
|
||||
#define SNIP_OFFSET (PT_SNIP * 4)
|
||||
#define SFIP_OFFSET (PT_SFIP * 4)
|
||||
#define PSR_OFFSET (PT_PSR * sizeof(int))
|
||||
#define FPSR_OFFSET (PT_FPSR * sizeof(int))
|
||||
#define FPCR_OFFSET (PT_FPCR * sizeof(int))
|
||||
|
||||
#define XREGADDR(r) (((char *)&u.pt_x0-(char *)&u) + \
|
||||
((r)-X0_REGNUM)*sizeof(X_REGISTER_RAW_TYPE))
|
||||
|
||||
extern int have_symbol_file_p();
|
||||
|
||||
extern jmp_buf stack_jmp;
|
||||
|
||||
extern int errno;
|
||||
extern char registers[REGISTER_BYTES];
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno; /* Original value discarded */
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct USER u;
|
||||
unsigned int offset;
|
||||
|
||||
offset = (char *) &u.pt_r0 - (char *) &u;
|
||||
regaddr = offset; /* byte offset to r0;*/
|
||||
|
||||
/* offset = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) - KERNEL_U_ADDR; */
|
||||
for (regno = 0; regno < PC_REGNUM; regno++)
|
||||
{
|
||||
/*regaddr = register_addr (regno, offset);*/
|
||||
/* 88k enhancement */
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
/* now load up registers 32-37; special pc registers */
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) PSR_OFFSET,0);
|
||||
supply_register (PSR_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPSR_OFFSET,0);
|
||||
supply_register (FPSR_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPCR_OFFSET,0);
|
||||
supply_register (FPCR_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET ,0);
|
||||
supply_register (SXIP_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET,0);
|
||||
supply_register (SNIP_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET,0);
|
||||
supply_register (SFIP_REGNUM, buf);
|
||||
|
||||
if (target_is_m88110)
|
||||
{
|
||||
for (regaddr = XREGADDR(X0_REGNUM), regno = X0_REGNUM;
|
||||
regno < NUM_REGS;
|
||||
regno++, regaddr += 16)
|
||||
{
|
||||
X_REGISTER_RAW_TYPE xval;
|
||||
|
||||
*(int *) &xval.w1 = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
*(int *) &xval.w2 = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (regaddr+4), 0);
|
||||
*(int *) &xval.w3 = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (regaddr+8), 0);
|
||||
*(int *) &xval.w4 = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (regaddr+12), 0);
|
||||
supply_register(regno, (void *)&xval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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). */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct USER u;
|
||||
|
||||
unsigned int offset = (char *) &u.pt_r0 - (char *) &u;
|
||||
|
||||
regaddr = offset;
|
||||
|
||||
/* Don't try to deal with EXIP_REGNUM or ENIP_REGNUM, because I think either
|
||||
svr3 doesn't run on an 88110, or the kernel isolates the different (not
|
||||
completely sure this is true, but seems to be. */
|
||||
if (regno >= 0)
|
||||
{
|
||||
/* regaddr = register_addr (regno, offset); */
|
||||
if (regno < PC_REGNUM)
|
||||
{
|
||||
regaddr = offset + regno * sizeof (int);
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else if (regno == PSR_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) PSR_OFFSET, read_register(regno));
|
||||
else if (regno == FPSR_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPSR_OFFSET, read_register(regno));
|
||||
else if (regno == FPCR_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPCR_OFFSET, read_register(regno));
|
||||
else if (regno == SXIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET, read_register(regno));
|
||||
else if (regno == SNIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET, read_register(regno));
|
||||
else if (regno == SFIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET, read_register(regno));
|
||||
else if (target_is_m88110 && regno < NUM_REGS)
|
||||
{
|
||||
X_REGISTER_RAW_TYPE xval;
|
||||
|
||||
read_register_bytes(REGISTER_BYTE(regno), (char *)&xval,
|
||||
sizeof(X_REGISTER_RAW_TYPE));
|
||||
regaddr = XREGADDR(regno);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, xval.w1);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+4, xval.w2);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+8, xval.w3);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr+12, xval.w4);
|
||||
}
|
||||
else
|
||||
printf_unfiltered ("Bad register number for store_inferior routine\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regno = 0; regno < PC_REGNUM; regno++)
|
||||
{
|
||||
/* regaddr = register_addr (regno, offset); */
|
||||
errno = 0;
|
||||
regaddr = offset + regno * sizeof (int);
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) PSR_OFFSET, read_register(regno));
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPSR_OFFSET,read_register(regno));
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) FPCR_OFFSET,read_register(regno));
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET,read_register(SXIP_REGNUM));
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET,read_register(SNIP_REGNUM));
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET,read_register(SFIP_REGNUM));
|
||||
if (target_is_m88110)
|
||||
{
|
||||
for (regno = X0_REGNUM; regno < NUM_REGS; regno++)
|
||||
{
|
||||
X_REGISTER_RAW_TYPE xval;
|
||||
|
||||
read_register_bytes(REGISTER_BYTE(regno), (char *)&xval,
|
||||
sizeof(X_REGISTER_RAW_TYPE));
|
||||
regaddr = XREGADDR(regno);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, xval.w1);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+4), xval.w2);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+8), xval.w3);
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) (regaddr+12), xval.w4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* blockend is the address of the end of the user structure */
|
||||
|
||||
m88k_register_u_addr (blockend, regnum)
|
||||
int blockend, regnum;
|
||||
{
|
||||
struct USER u;
|
||||
int ustart = blockend - sizeof (struct USER);
|
||||
|
||||
if (regnum < PSR_REGNUM)
|
||||
return (ustart + ((int) &u.pt_r0 - (int) &u) +
|
||||
REGISTER_SIZE * regnum);
|
||||
else if (regnum == PSR_REGNUM)
|
||||
return (ustart + ((int) &u.pt_psr) - (int) &u);
|
||||
else if (regnum == FPSR_REGNUM)
|
||||
return (ustart + ((int) &u.pt_fpsr) - (int) &u);
|
||||
else if (regnum == FPCR_REGNUM)
|
||||
return (ustart + ((int) &u.pt_fpcr) - (int) &u);
|
||||
else if (regnum == SXIP_REGNUM)
|
||||
return (ustart + SXIP_OFFSET);
|
||||
else if (regnum == SNIP_REGNUM)
|
||||
return (ustart + SNIP_OFFSET);
|
||||
else if (regnum == SFIP_REGNUM)
|
||||
return (ustart + SFIP_OFFSET);
|
||||
else if (target_is_m88110)
|
||||
return (ustart + ((int) &u.pt_x0 - (int) &u) + /* Must be X register */
|
||||
sizeof(u.pt_x0) * (regnum - X0_REGNUM));
|
||||
else
|
||||
return (blockend + REGISTER_SIZE * regnum);
|
||||
}
|
||||
|
||||
#ifdef USE_PROC_FS
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
|
||||
for (regi=0; regi <= SP_REGNUM; regi++)
|
||||
supply_register (regi, (char *) (regp + regi));
|
||||
|
||||
supply_register (SXIP_REGNUM, (char *) (regp + R_XIP));
|
||||
supply_register (SNIP_REGNUM, (char *) (regp + R_NIP));
|
||||
supply_register (SFIP_REGNUM, (char *) (regp + R_FIP));
|
||||
supply_register (PSR_REGNUM, (char *) (regp + R_PSR));
|
||||
supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR));
|
||||
supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR));
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
extern char registers[];
|
||||
|
||||
for (regi = 0 ; regi <= R_R31 ; regi++)
|
||||
if ((regno == -1) || (regno == regi))
|
||||
*(regp + regi) = *(int *) ®isters[REGISTER_BYTE(regi)];
|
||||
|
||||
if ((regno == -1) || (regno == SXIP_REGNUM))
|
||||
*(regp + R_XIP) = *(int *) ®isters[REGISTER_BYTE(SXIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == SNIP_REGNUM))
|
||||
*(regp + R_NIP) = *(int *) ®isters[REGISTER_BYTE(SNIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == SFIP_REGNUM))
|
||||
*(regp + R_FIP) = *(int *) ®isters[REGISTER_BYTE(SFIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == PSR_REGNUM))
|
||||
*(regp + R_PSR) = *(int *) ®isters[REGISTER_BYTE(PSR_REGNUM)];
|
||||
if ((regno == -1) || (regno == FPSR_REGNUM))
|
||||
*(regp + R_FPSR) = *(int *) ®isters[REGISTER_BYTE(FPSR_REGNUM)];
|
||||
if ((regno == -1) || (regno == FPCR_REGNUM))
|
||||
*(regp + R_FPCR) = *(int *) ®isters[REGISTER_BYTE(FPCR_REGNUM)];
|
||||
}
|
||||
|
||||
#endif /* USE_PROC_FS */
|
||||
|
||||
/* This support adds the equivalent of adb's % command. When
|
||||
the `add-shared-symbol-files' command is given, this routine scans
|
||||
the dynamic linker's link map and reads the minimal symbols
|
||||
from each shared object file listed in the map. */
|
||||
|
||||
struct link_map {
|
||||
unsigned long l_addr; /* address at which object is mapped */
|
||||
char *l_name; /* full name of loaded object */
|
||||
void *l_ld; /* dynamic structure of object */
|
||||
struct link_map *l_next; /* next link object */
|
||||
struct link_map *l_prev; /* previous link object */
|
||||
};
|
||||
|
||||
#define LINKS_MAP_POINTER "_ld_tail"
|
||||
#define LIBC_FILE "/usr/lib/libc.so.1"
|
||||
#define SHARED_OFFSET 0xf0001000
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1023 /* maximum size of path name on OS */
|
||||
#endif
|
||||
|
||||
void
|
||||
add_shared_symbol_files ()
|
||||
{
|
||||
void *desc;
|
||||
struct link_map *ld_map, *lm, lms;
|
||||
struct minimal_symbol *minsym;
|
||||
struct objfile *objfile;
|
||||
char *path_name;
|
||||
|
||||
if (! inferior_pid)
|
||||
{
|
||||
warning ("The program has not yet been started.");
|
||||
return;
|
||||
}
|
||||
|
||||
objfile = symbol_file_add (LIBC_FILE, 0, 0, 0, 0, 1);
|
||||
minsym = lookup_minimal_symbol (LINKS_MAP_POINTER, objfile);
|
||||
|
||||
ld_map = (struct link_map *)
|
||||
read_memory_integer (((int)SYMBOL_VALUE_ADDRESS(minsym) + SHARED_OFFSET), 4);
|
||||
lm = ld_map;
|
||||
while (lm)
|
||||
{
|
||||
int local_errno = 0;
|
||||
|
||||
read_memory ((CORE_ADDR)lm, (char*)&lms, sizeof (struct link_map));
|
||||
if (lms.l_name)
|
||||
{
|
||||
if (target_read_string ((CORE_ADDR)lms.l_name, &path_name,
|
||||
PATH_MAX, &local_errno))
|
||||
{
|
||||
symbol_file_add (path_name, 1, lms.l_addr, 0, 0, 0);
|
||||
free(path_name);
|
||||
}
|
||||
}
|
||||
/* traverse links in reverse order so that we get the
|
||||
the symbols the user actually gets. */
|
||||
lm = lms.l_prev;
|
||||
}
|
||||
|
||||
/* Getting new symbols may change our opinion about what is
|
||||
frameless. */
|
||||
reinit_frame_cache ();
|
||||
}
|
||||
|
||||
#if defined(_ES_MP)
|
||||
|
||||
#include <sys/regset.h>
|
||||
|
||||
unsigned int
|
||||
m88k_harris_core_register_addr (regno, reg_ptr)
|
||||
int regno, reg_ptr;
|
||||
{
|
||||
unsigned int word_offset;
|
||||
|
||||
switch (regno)
|
||||
{
|
||||
case PSR_REGNUM:
|
||||
word_offset = R_EPSR;
|
||||
break;
|
||||
case FPSR_REGNUM:
|
||||
word_offset = R_FPSR;
|
||||
break;
|
||||
case FPCR_REGNUM:
|
||||
word_offset = R_FPCR;
|
||||
break;
|
||||
case SXIP_REGNUM:
|
||||
word_offset = R_EXIP;
|
||||
break;
|
||||
case SNIP_REGNUM:
|
||||
word_offset = R_ENIP;
|
||||
break;
|
||||
case SFIP_REGNUM:
|
||||
word_offset = R_EFIP;
|
||||
break;
|
||||
default:
|
||||
if (regno <= FP_REGNUM)
|
||||
word_offset = regno;
|
||||
else
|
||||
word_offset = ((regno - X0_REGNUM) * 4);
|
||||
}
|
||||
return (word_offset * 4);
|
||||
}
|
||||
|
||||
#endif /* _ES_MP */
|
||||
|
||||
void
|
||||
_initialize_m88k_nat()
|
||||
{
|
||||
#ifdef _ES_MP
|
||||
/* Enable 88110 support, as we don't support the 88100 under ES/MP. */
|
||||
|
||||
target_is_m88110 = 1;
|
||||
#elif defined(_CX_UX)
|
||||
/* Determine whether we're running on an 88100 or an 88110. */
|
||||
target_is_m88110 = (sinfo(SYSMACHINE,0) == SYS5800);
|
||||
#endif /* _CX_UX */
|
||||
}
|
||||
|
||||
#ifdef _ES_MP
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
|
||||
for (regi = 0 ; regi < R_R31 ; regi++)
|
||||
{
|
||||
supply_register (regi, (char *) (regp + regi));
|
||||
}
|
||||
supply_register (PSR_REGNUM, (char *) (regp + R_EPSR));
|
||||
supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR));
|
||||
supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR));
|
||||
supply_register (SXIP_REGNUM, (char *) (regp + R_EXIP));
|
||||
supply_register (SNIP_REGNUM, (char *) (regp + R_ENIP));
|
||||
supply_register (SFIP_REGNUM, (char *) (regp + R_EFIP));
|
||||
}
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), unpack the register contents and supply them as gdb's
|
||||
idea of the current floating point register values. */
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
register int regi;
|
||||
char *from;
|
||||
|
||||
for (regi = FP0_REGNUM ; regi <= FPLAST_REGNUM ; regi++)
|
||||
{
|
||||
from = (char *) &((*fpregsetp)[regi-FP0_REGNUM]);
|
||||
supply_register (regi, from);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _ES_MP */
|
||||
|
||||
#ifdef _CX_UX
|
||||
|
||||
#include <sys/regset.h>
|
||||
|
||||
unsigned int m88k_harris_core_register_addr(int regno, int reg_ptr)
|
||||
{
|
||||
unsigned int word_offset;
|
||||
|
||||
switch (regno) {
|
||||
case PSR_REGNUM : word_offset = R_PSR; break;
|
||||
case FPSR_REGNUM : word_offset = R_FPSR; break;
|
||||
case FPCR_REGNUM : word_offset = R_FPCR; break;
|
||||
case SXIP_REGNUM : word_offset = R_XIP; break;
|
||||
case SNIP_REGNUM : word_offset = R_NIP; break;
|
||||
case SFIP_REGNUM : word_offset = R_FIP; break;
|
||||
default :
|
||||
if (regno <= FP_REGNUM)
|
||||
word_offset = regno;
|
||||
else
|
||||
word_offset = ((regno - X0_REGNUM) * 4) + R_X0;
|
||||
}
|
||||
return (word_offset * 4);
|
||||
}
|
||||
|
||||
#endif /* _CX_UX */
|
File diff suppressed because it is too large
Load diff
|
@ -1,91 +0,0 @@
|
|||
/* Common things used by the various *gnu-nat.c files
|
||||
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
Written by Miles Bader <miles@gnu.ai.mit.edu>
|
||||
|
||||
The GNU Hurd 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 2, or (at
|
||||
your option) any later version.
|
||||
|
||||
The GNU Hurd 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef __GNU_NAT_H__
|
||||
#define __GNU_NAT_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <mach.h>
|
||||
|
||||
struct inf;
|
||||
|
||||
extern struct inf *current_inferior;
|
||||
|
||||
/* Converts a GDB pid to a struct proc. */
|
||||
struct proc *inf_tid_to_thread (struct inf *inf, int tid);
|
||||
|
||||
/* A proc is either a thread, or the task (there can only be one task proc
|
||||
because it always has the same TID, PROC_TID_TASK). */
|
||||
struct proc
|
||||
{
|
||||
thread_t port; /* The task or thread port. */
|
||||
int tid; /* The GDB pid (actually a thread id). */
|
||||
int num; /* An id number for threads, to print. */
|
||||
|
||||
mach_port_t saved_exc_port; /* The task/thread's real exception port. */
|
||||
mach_port_t exc_port; /* Our replacement, which for. */
|
||||
|
||||
int sc; /* Desired suspend count. */
|
||||
int cur_sc; /* Implemented suspend count. */
|
||||
int run_sc; /* Default sc when the program is running. */
|
||||
int pause_sc; /* Default sc when gdb has control. */
|
||||
int resume_sc; /* Sc resulting form the last resume. */
|
||||
|
||||
thread_state_data_t state; /* Registers, &c. */
|
||||
int state_valid : 1; /* True if STATE is up to date. */
|
||||
int state_changed : 1;
|
||||
|
||||
int aborted : 1; /* True if thread_abort has been called. */
|
||||
|
||||
/* Bit mask of registers fetched by gdb. This is used when we re-fetch
|
||||
STATE after aborting the thread, to detect that gdb may have out-of-date
|
||||
information. */
|
||||
unsigned long fetched_regs;
|
||||
|
||||
struct inf *inf; /* Where we come from. */
|
||||
|
||||
struct proc *next;
|
||||
};
|
||||
|
||||
/* The task has a thread entry with this TID. */
|
||||
#define PROC_TID_TASK (-1)
|
||||
|
||||
#define proc_is_task(proc) ((proc)->tid == PROC_TID_TASK)
|
||||
#define proc_is_thread(proc) ((proc)->tid != PROC_TID_TASK)
|
||||
|
||||
extern int __proc_pid (struct proc *proc);
|
||||
|
||||
extern thread_state_t proc_get_state (struct proc *proc, int will_modify);
|
||||
|
||||
#define proc_debug(_proc, msg, args...) \
|
||||
do { struct proc *__proc = (_proc); \
|
||||
debug ("{proc %d/%d %p}: " msg, \
|
||||
__proc_pid (__proc), __proc->tid, __proc , ##args); } while (0)
|
||||
|
||||
#if MAINTENANCE_CMDS
|
||||
extern int gnu_debug_flag;
|
||||
#define debug(msg, args...) \
|
||||
do { if (gnu_debug_flag) \
|
||||
fprintf (stderr, "%s: " msg "\r\n", __FUNCTION__ , ##args); } while (0)
|
||||
#else
|
||||
#define debug(msg, args...) (void)0
|
||||
#endif
|
||||
|
||||
#endif /* __GNU_NAT_H__ */
|
|
@ -1,35 +0,0 @@
|
|||
/* Host-dependent code for dos running GO32 for GDB, the GNU debugger.
|
||||
Copyright 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
sigsetmask (mask)
|
||||
int mask;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
strlwr (str)
|
||||
char *str;
|
||||
{
|
||||
for (; *str; str++)
|
||||
*str = tolower(*str);
|
||||
}
|
|
@ -1,915 +0,0 @@
|
|||
/****************************************************************************
|
||||
|
||||
THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
|
||||
HP offers the following for use in the public domain. HP makes no
|
||||
warranty with regard to the software or it's performance and the
|
||||
user accepts the software "AS IS" with all faults.
|
||||
|
||||
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
|
||||
*
|
||||
* Module name: remcom.c $
|
||||
* Revision: 1.34 $
|
||||
* Date: 91/03/09 12:29:49 $
|
||||
* Contributor: Lake Stevens Instrument Division$
|
||||
*
|
||||
* Description: low level support for gdb debugger. $
|
||||
*
|
||||
* Considerations: only works on target hardware $
|
||||
*
|
||||
* Written by: Glenn Engel $
|
||||
* ModuleState: Experimental $
|
||||
*
|
||||
* NOTES: See Below $
|
||||
*
|
||||
* Modified for 386 by Jim Kingdon, Cygnus Support.
|
||||
*
|
||||
* To enable debugger support, two things need to happen. One, a
|
||||
* call to set_debug_traps() is necessary in order to allow any breakpoints
|
||||
* or error conditions to be properly intercepted and reported to gdb.
|
||||
* Two, a breakpoint needs to be generated to begin communication. This
|
||||
* is most easily accomplished by a call to breakpoint(). Breakpoint()
|
||||
* simulates a breakpoint by executing a trap #1.
|
||||
*
|
||||
* The external function exceptionHandler() is
|
||||
* used to attach a specific handler to a specific 386 vector number.
|
||||
* It should use the same privilege level it runs at. It should
|
||||
* install it as an interrupt gate so that interrupts are masked
|
||||
* while the handler runs.
|
||||
* Also, need to assign exceptionHook and oldExceptionHook.
|
||||
*
|
||||
* Because gdb will sometimes write to the stack area to execute function
|
||||
* calls, this program cannot rely on using the supervisor stack so it
|
||||
* uses it's own stack area reserved in the int array remcomStack.
|
||||
*
|
||||
*************
|
||||
*
|
||||
* The following gdb commands are supported:
|
||||
*
|
||||
* command function Return value
|
||||
*
|
||||
* g return the value of the CPU registers hex data or ENN
|
||||
* G set the value of the CPU registers OK or ENN
|
||||
*
|
||||
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
|
||||
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
|
||||
*
|
||||
* c Resume at current address SNN ( signal NN)
|
||||
* cAA..AA Continue at address AA..AA SNN
|
||||
*
|
||||
* s Step one instruction SNN
|
||||
* sAA..AA Step one instruction from AA..AA SNN
|
||||
*
|
||||
* k kill
|
||||
*
|
||||
* ? What was the last sigval ? SNN (signal NN)
|
||||
*
|
||||
* All commands and responses are sent with a packet which includes a
|
||||
* checksum. A packet consists of
|
||||
*
|
||||
* $<packet info>#<checksum>.
|
||||
*
|
||||
* where
|
||||
* <packet info> :: <characters representing the command or response>
|
||||
* <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
|
||||
*
|
||||
* When a packet is received, it is first acknowledged with either '+' or '-'.
|
||||
* '+' indicates a successful transfer. '-' indicates a failed transfer.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Host: Reply:
|
||||
* $m0,10#2a +$00010203040506070809101112131415#42
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/************************************************************************
|
||||
*
|
||||
* external low-level support routines
|
||||
*/
|
||||
typedef void (*ExceptionHook)(int); /* pointer to function with int parm */
|
||||
typedef void (*Function)(); /* pointer to a function */
|
||||
|
||||
extern putDebugChar(); /* write a single character */
|
||||
extern getDebugChar(); /* read and return a single char */
|
||||
|
||||
extern Function exceptionHandler(); /* assign an exception handler */
|
||||
extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */
|
||||
|
||||
/************************************************************************/
|
||||
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
|
||||
/* at least NUMREGBYTES*2 are needed for register packets */
|
||||
#define BUFMAX 400
|
||||
|
||||
static char initialized; /* boolean flag. != 0 means we've been initialized */
|
||||
|
||||
int remote_debug;
|
||||
/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
|
||||
|
||||
void waitabit();
|
||||
|
||||
static const char hexchars[]="0123456789abcdef";
|
||||
|
||||
/* Number of bytes of registers. */
|
||||
#define NUMREGBYTES 64
|
||||
enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
|
||||
PC /* also known as eip */,
|
||||
PS /* also known as eflags */,
|
||||
CS, SS, DS, ES, FS, GS};
|
||||
|
||||
/*
|
||||
* these should not be static cuz they can be used outside this module
|
||||
*/
|
||||
int registers[NUMREGBYTES/4];
|
||||
|
||||
#define STACKSIZE 10000
|
||||
int remcomStack[STACKSIZE/sizeof(int)];
|
||||
static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
|
||||
|
||||
/*
|
||||
* In many cases, the system will want to continue exception processing
|
||||
* when a continue command is given.
|
||||
* oldExceptionHook is a function to invoke in this case.
|
||||
*/
|
||||
|
||||
static ExceptionHook oldExceptionHook;
|
||||
|
||||
/*************************** ASSEMBLY CODE MACROS *************************/
|
||||
/* */
|
||||
|
||||
extern void
|
||||
return_to_prog ();
|
||||
|
||||
/* Restore the program's registers (including the stack pointer, which
|
||||
means we get the right stack and don't have to worry about popping our
|
||||
return address and any stack frames and so on) and return. */
|
||||
asm(".text");
|
||||
asm(".globl _return_to_prog");
|
||||
asm("_return_to_prog:");
|
||||
asm(" movw _registers+44, %ss");
|
||||
asm(" movl _registers+16, %esp");
|
||||
asm(" movl _registers+4, %ecx");
|
||||
asm(" movl _registers+8, %edx");
|
||||
asm(" movl _registers+12, %ebx");
|
||||
asm(" movl _registers+20, %ebp");
|
||||
asm(" movl _registers+24, %esi");
|
||||
asm(" movl _registers+28, %edi");
|
||||
asm(" movw _registers+48, %ds");
|
||||
asm(" movw _registers+52, %es");
|
||||
asm(" movw _registers+56, %fs");
|
||||
asm(" movw _registers+60, %gs");
|
||||
asm(" movl _registers+36, %eax");
|
||||
asm(" pushl %eax"); /* saved eflags */
|
||||
asm(" movl _registers+40, %eax");
|
||||
asm(" pushl %eax"); /* saved cs */
|
||||
asm(" movl _registers+32, %eax");
|
||||
asm(" pushl %eax"); /* saved eip */
|
||||
asm(" movl _registers, %eax");
|
||||
/* use iret to restore pc and flags together so
|
||||
that trace flag works right. */
|
||||
asm(" iret");
|
||||
|
||||
#define BREAKPOINT() asm(" int $3");
|
||||
|
||||
/* Put the error code here just in case the user cares. */
|
||||
int gdb_i386errcode;
|
||||
/* Likewise, the vector number here (since GDB only gets the signal
|
||||
number through the usual means, and that's not very specific). */
|
||||
int gdb_i386vector = -1;
|
||||
|
||||
/* GDB stores segment registers in 32-bit words (that's just the way
|
||||
m-i386v.h is written). So zero the appropriate areas in registers. */
|
||||
#define SAVE_REGISTERS1() \
|
||||
asm ("movl %eax, _registers"); \
|
||||
asm ("movl %ecx, _registers+4"); \
|
||||
asm ("movl %edx, _registers+8"); \
|
||||
asm ("movl %ebx, _registers+12"); \
|
||||
asm ("movl %ebp, _registers+20"); \
|
||||
asm ("movl %esi, _registers+24"); \
|
||||
asm ("movl %edi, _registers+28"); \
|
||||
asm ("movw $0, %ax"); \
|
||||
asm ("movw %ds, _registers+48"); \
|
||||
asm ("movw %ax, _registers+50"); \
|
||||
asm ("movw %es, _registers+52"); \
|
||||
asm ("movw %ax, _registers+54"); \
|
||||
asm ("movw %fs, _registers+56"); \
|
||||
asm ("movw %ax, _registers+58"); \
|
||||
asm ("movw %gs, _registers+60"); \
|
||||
asm ("movw %ax, _registers+62");
|
||||
#define SAVE_ERRCODE() \
|
||||
asm ("popl %ebx"); \
|
||||
asm ("movl %ebx, _gdb_i386errcode");
|
||||
#define SAVE_REGISTERS2() \
|
||||
asm ("popl %ebx"); /* old eip */ \
|
||||
asm ("movl %ebx, _registers+32"); \
|
||||
asm ("popl %ebx"); /* old cs */ \
|
||||
asm ("movl %ebx, _registers+40"); \
|
||||
asm ("movw %ax, _registers+42"); \
|
||||
asm ("popl %ebx"); /* old eflags */ \
|
||||
asm ("movl %ebx, _registers+36"); \
|
||||
/* Now that we've done the pops, we can save the stack pointer."); */ \
|
||||
asm ("movw %ss, _registers+44"); \
|
||||
asm ("movw %ax, _registers+46"); \
|
||||
asm ("movl %esp, _registers+16");
|
||||
|
||||
/* See if mem_fault_routine is set, if so just IRET to that address. */
|
||||
#define CHECK_FAULT() \
|
||||
asm ("cmpl $0, _mem_fault_routine"); \
|
||||
asm ("jne mem_fault");
|
||||
|
||||
asm (".text");
|
||||
asm ("mem_fault:");
|
||||
/* OK to clobber temp registers; we're just going to end up in set_mem_err. */
|
||||
/* Pop error code from the stack and save it. */
|
||||
asm (" popl %eax");
|
||||
asm (" movl %eax, _gdb_i386errcode");
|
||||
|
||||
asm (" popl %eax"); /* eip */
|
||||
/* We don't want to return there, we want to return to the function
|
||||
pointed to by mem_fault_routine instead. */
|
||||
asm (" movl _mem_fault_routine, %eax");
|
||||
asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */
|
||||
asm (" popl %edx"); /* eflags */
|
||||
|
||||
/* Remove this stack frame; when we do the iret, we will be going to
|
||||
the start of a function, so we want the stack to look just like it
|
||||
would after a "call" instruction. */
|
||||
asm (" leave");
|
||||
|
||||
/* Push the stuff that iret wants. */
|
||||
asm (" pushl %edx"); /* eflags */
|
||||
asm (" pushl %ecx"); /* cs */
|
||||
asm (" pushl %eax"); /* eip */
|
||||
|
||||
/* Zero mem_fault_routine. */
|
||||
asm (" movl $0, %eax");
|
||||
asm (" movl %eax, _mem_fault_routine");
|
||||
|
||||
asm ("iret");
|
||||
|
||||
#define CALL_HOOK() asm("call _remcomHandler");
|
||||
|
||||
/* This function is called when a i386 exception occurs. It saves
|
||||
* all the cpu regs in the _registers array, munges the stack a bit,
|
||||
* and invokes an exception handler (remcom_handler).
|
||||
*
|
||||
* stack on entry: stack on exit:
|
||||
* old eflags vector number
|
||||
* old cs (zero-filled to 32 bits)
|
||||
* old eip
|
||||
*
|
||||
*/
|
||||
extern void _catchException3();
|
||||
asm(".text");
|
||||
asm(".globl __catchException3");
|
||||
asm("__catchException3:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $3");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 1. */
|
||||
extern void _catchException1();
|
||||
asm(".text");
|
||||
asm(".globl __catchException1");
|
||||
asm("__catchException1:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $1");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 0. */
|
||||
extern void _catchException0();
|
||||
asm(".text");
|
||||
asm(".globl __catchException0");
|
||||
asm("__catchException0:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $0");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 4. */
|
||||
extern void _catchException4();
|
||||
asm(".text");
|
||||
asm(".globl __catchException4");
|
||||
asm("__catchException4:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $4");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 5. */
|
||||
extern void _catchException5();
|
||||
asm(".text");
|
||||
asm(".globl __catchException5");
|
||||
asm("__catchException5:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $5");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 6. */
|
||||
extern void _catchException6();
|
||||
asm(".text");
|
||||
asm(".globl __catchException6");
|
||||
asm("__catchException6:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $6");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 7. */
|
||||
extern void _catchException7();
|
||||
asm(".text");
|
||||
asm(".globl __catchException7");
|
||||
asm("__catchException7:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $7");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 8. */
|
||||
extern void _catchException8();
|
||||
asm(".text");
|
||||
asm(".globl __catchException8");
|
||||
asm("__catchException8:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $8");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 9. */
|
||||
extern void _catchException9();
|
||||
asm(".text");
|
||||
asm(".globl __catchException9");
|
||||
asm("__catchException9:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $9");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 10. */
|
||||
extern void _catchException10();
|
||||
asm(".text");
|
||||
asm(".globl __catchException10");
|
||||
asm("__catchException10:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $10");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 12. */
|
||||
extern void _catchException12();
|
||||
asm(".text");
|
||||
asm(".globl __catchException12");
|
||||
asm("__catchException12:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $12");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 16. */
|
||||
extern void _catchException16();
|
||||
asm(".text");
|
||||
asm(".globl __catchException16");
|
||||
asm("__catchException16:");
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $16");
|
||||
CALL_HOOK();
|
||||
|
||||
/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */
|
||||
|
||||
/* Same thing for exception 13. */
|
||||
extern void _catchException13 ();
|
||||
asm (".text");
|
||||
asm (".globl __catchException13");
|
||||
asm ("__catchException13:");
|
||||
CHECK_FAULT();
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $13");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 11. */
|
||||
extern void _catchException11 ();
|
||||
asm (".text");
|
||||
asm (".globl __catchException11");
|
||||
asm ("__catchException11:");
|
||||
CHECK_FAULT();
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $11");
|
||||
CALL_HOOK();
|
||||
|
||||
/* Same thing for exception 14. */
|
||||
extern void _catchException14 ();
|
||||
asm (".text");
|
||||
asm (".globl __catchException14");
|
||||
asm ("__catchException14:");
|
||||
CHECK_FAULT();
|
||||
SAVE_REGISTERS1();
|
||||
SAVE_ERRCODE();
|
||||
SAVE_REGISTERS2();
|
||||
asm ("pushl $14");
|
||||
CALL_HOOK();
|
||||
|
||||
/*
|
||||
* remcomHandler is a front end for handle_exception. It moves the
|
||||
* stack pointer into an area reserved for debugger use.
|
||||
*/
|
||||
asm("_remcomHandler:");
|
||||
asm(" popl %eax"); /* pop off return address */
|
||||
asm(" popl %eax"); /* get the exception number */
|
||||
asm(" movl _stackPtr, %esp"); /* move to remcom stack area */
|
||||
asm(" pushl %eax"); /* push exception onto stack */
|
||||
asm(" call _handle_exception"); /* this never returns */
|
||||
|
||||
void _returnFromException()
|
||||
{
|
||||
return_to_prog ();
|
||||
}
|
||||
|
||||
int hex(ch)
|
||||
char ch;
|
||||
{
|
||||
if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
|
||||
if ((ch >= '0') && (ch <= '9')) return (ch-'0');
|
||||
if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* scan for the sequence $<data>#<checksum> */
|
||||
void getpacket(buffer)
|
||||
char * buffer;
|
||||
{
|
||||
unsigned char checksum;
|
||||
unsigned char xmitcsum;
|
||||
int i;
|
||||
int count;
|
||||
char ch;
|
||||
|
||||
do {
|
||||
/* wait around for the start character, ignore all other characters */
|
||||
while ((ch = (getDebugChar() & 0x7f)) != '$');
|
||||
checksum = 0;
|
||||
xmitcsum = -1;
|
||||
|
||||
count = 0;
|
||||
|
||||
/* now, read until a # or end of buffer is found */
|
||||
while (count < BUFMAX) {
|
||||
ch = getDebugChar() & 0x7f;
|
||||
if (ch == '#') break;
|
||||
checksum = checksum + ch;
|
||||
buffer[count] = ch;
|
||||
count = count + 1;
|
||||
}
|
||||
buffer[count] = 0;
|
||||
|
||||
if (ch == '#') {
|
||||
xmitcsum = hex(getDebugChar() & 0x7f) << 4;
|
||||
xmitcsum += hex(getDebugChar() & 0x7f);
|
||||
if ((remote_debug ) && (checksum != xmitcsum)) {
|
||||
fprintf (stderr ,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
|
||||
checksum,xmitcsum,buffer);
|
||||
}
|
||||
|
||||
if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */
|
||||
else {
|
||||
putDebugChar('+'); /* successful transfer */
|
||||
/* if a sequence char is present, reply the sequence ID */
|
||||
if (buffer[2] == ':') {
|
||||
putDebugChar( buffer[0] );
|
||||
putDebugChar( buffer[1] );
|
||||
/* remove sequence chars from buffer */
|
||||
count = strlen(buffer);
|
||||
for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (checksum != xmitcsum);
|
||||
|
||||
}
|
||||
|
||||
/* send the packet in buffer. */
|
||||
|
||||
|
||||
void putpacket(buffer)
|
||||
char * buffer;
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
char ch;
|
||||
|
||||
/* $<packet info>#<checksum>. */
|
||||
do {
|
||||
putDebugChar('$');
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
|
||||
while (ch=buffer[count]) {
|
||||
if (! putDebugChar(ch)) return;
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
putDebugChar('#');
|
||||
putDebugChar(hexchars[checksum >> 4]);
|
||||
putDebugChar(hexchars[checksum % 16]);
|
||||
|
||||
} while ((getDebugChar() & 0x7f) != '+');
|
||||
|
||||
}
|
||||
|
||||
char remcomInBuffer[BUFMAX];
|
||||
char remcomOutBuffer[BUFMAX];
|
||||
static short error;
|
||||
|
||||
|
||||
void debug_error(format, parm)
|
||||
char * format;
|
||||
char * parm;
|
||||
{
|
||||
if (remote_debug) fprintf (stderr,format,parm);
|
||||
}
|
||||
|
||||
/* Address of a routine to RTE to if we get a memory fault. */
|
||||
static void (*volatile mem_fault_routine)() = NULL;
|
||||
|
||||
/* Indicate to caller of mem2hex or hex2mem that there has been an
|
||||
error. */
|
||||
static volatile int mem_err = 0;
|
||||
|
||||
void
|
||||
set_mem_err ()
|
||||
{
|
||||
mem_err = 1;
|
||||
}
|
||||
|
||||
/* These are separate functions so that they are so short and sweet
|
||||
that the compiler won't save any registers (if there is a fault
|
||||
to mem_fault, they won't get restored, so there better not be any
|
||||
saved). */
|
||||
int
|
||||
get_char (addr)
|
||||
char *addr;
|
||||
{
|
||||
return *addr;
|
||||
}
|
||||
|
||||
void
|
||||
set_char (addr, val)
|
||||
char *addr;
|
||||
int val;
|
||||
{
|
||||
*addr = val;
|
||||
}
|
||||
|
||||
/* convert the memory pointed to by mem into hex, placing result in buf */
|
||||
/* return a pointer to the last char put in buf (null) */
|
||||
/* If MAY_FAULT is non-zero, then we should set mem_err in response to
|
||||
a fault; if zero treat a fault like any other fault in the stub. */
|
||||
char* mem2hex(mem, buf, count, may_fault)
|
||||
char* mem;
|
||||
char* buf;
|
||||
int count;
|
||||
int may_fault;
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
if (may_fault)
|
||||
mem_fault_routine = set_mem_err;
|
||||
for (i=0;i<count;i++) {
|
||||
ch = get_char (mem++);
|
||||
if (may_fault && mem_err)
|
||||
return (buf);
|
||||
*buf++ = hexchars[ch >> 4];
|
||||
*buf++ = hexchars[ch % 16];
|
||||
}
|
||||
*buf = 0;
|
||||
if (may_fault)
|
||||
mem_fault_routine = NULL;
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/* convert the hex array pointed to by buf into binary to be placed in mem */
|
||||
/* return a pointer to the character AFTER the last byte written */
|
||||
char* hex2mem(buf, mem, count, may_fault)
|
||||
char* buf;
|
||||
char* mem;
|
||||
int count;
|
||||
int may_fault;
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
if (may_fault)
|
||||
mem_fault_routine = set_mem_err;
|
||||
for (i=0;i<count;i++) {
|
||||
ch = hex(*buf++) << 4;
|
||||
ch = ch + hex(*buf++);
|
||||
set_char (mem++, ch);
|
||||
if (may_fault && mem_err)
|
||||
return (mem);
|
||||
}
|
||||
if (may_fault)
|
||||
mem_fault_routine = NULL;
|
||||
return(mem);
|
||||
}
|
||||
|
||||
/* this function takes the 386 exception vector and attempts to
|
||||
translate this number into a unix compatible signal value */
|
||||
int computeSignal( exceptionVector )
|
||||
int exceptionVector;
|
||||
{
|
||||
int sigval;
|
||||
switch (exceptionVector) {
|
||||
case 0 : sigval = 8; break; /* divide by zero */
|
||||
case 1 : sigval = 5; break; /* debug exception */
|
||||
case 3 : sigval = 5; break; /* breakpoint */
|
||||
case 4 : sigval = 16; break; /* into instruction (overflow) */
|
||||
case 5 : sigval = 16; break; /* bound instruction */
|
||||
case 6 : sigval = 4; break; /* Invalid opcode */
|
||||
case 7 : sigval = 8; break; /* coprocessor not available */
|
||||
case 8 : sigval = 7; break; /* double fault */
|
||||
case 9 : sigval = 11; break; /* coprocessor segment overrun */
|
||||
case 10 : sigval = 11; break; /* Invalid TSS */
|
||||
case 11 : sigval = 11; break; /* Segment not present */
|
||||
case 12 : sigval = 11; break; /* stack exception */
|
||||
case 13 : sigval = 11; break; /* general protection */
|
||||
case 14 : sigval = 11; break; /* page fault */
|
||||
case 16 : sigval = 7; break; /* coprocessor error */
|
||||
default:
|
||||
sigval = 7; /* "software generated"*/
|
||||
}
|
||||
return (sigval);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
|
||||
/* RETURN NUMBER OF CHARS PROCESSED */
|
||||
/**********************************************/
|
||||
int hexToInt(char **ptr, int *intValue)
|
||||
{
|
||||
int numChars = 0;
|
||||
int hexValue;
|
||||
|
||||
*intValue = 0;
|
||||
|
||||
while (**ptr)
|
||||
{
|
||||
hexValue = hex(**ptr);
|
||||
if (hexValue >=0)
|
||||
{
|
||||
*intValue = (*intValue <<4) | hexValue;
|
||||
numChars ++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
(*ptr)++;
|
||||
}
|
||||
|
||||
return (numChars);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does all command procesing for interfacing to gdb.
|
||||
*/
|
||||
void handle_exception(int exceptionVector)
|
||||
{
|
||||
int sigval;
|
||||
int addr, length;
|
||||
char * ptr;
|
||||
int newPC;
|
||||
|
||||
gdb_i386vector = exceptionVector;
|
||||
|
||||
if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n",
|
||||
exceptionVector,
|
||||
registers[ PS ],
|
||||
registers[ PC ]);
|
||||
|
||||
/* reply to host that an exception has occurred */
|
||||
sigval = computeSignal( exceptionVector );
|
||||
remcomOutBuffer[0] = 'S';
|
||||
remcomOutBuffer[1] = hexchars[sigval >> 4];
|
||||
remcomOutBuffer[2] = hexchars[sigval % 16];
|
||||
remcomOutBuffer[3] = 0;
|
||||
|
||||
putpacket(remcomOutBuffer);
|
||||
|
||||
while (1==1) {
|
||||
error = 0;
|
||||
remcomOutBuffer[0] = 0;
|
||||
getpacket(remcomInBuffer);
|
||||
switch (remcomInBuffer[0]) {
|
||||
case '?' : remcomOutBuffer[0] = 'S';
|
||||
remcomOutBuffer[1] = hexchars[sigval >> 4];
|
||||
remcomOutBuffer[2] = hexchars[sigval % 16];
|
||||
remcomOutBuffer[3] = 0;
|
||||
break;
|
||||
case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */
|
||||
break;
|
||||
case 'g' : /* return the value of the CPU registers */
|
||||
mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES, 0);
|
||||
break;
|
||||
case 'G' : /* set the value of the CPU registers - return OK */
|
||||
hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES, 0);
|
||||
strcpy(remcomOutBuffer,"OK");
|
||||
break;
|
||||
|
||||
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||||
case 'm' :
|
||||
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
|
||||
ptr = &remcomInBuffer[1];
|
||||
if (hexToInt(&ptr,&addr))
|
||||
if (*(ptr++) == ',')
|
||||
if (hexToInt(&ptr,&length))
|
||||
{
|
||||
ptr = 0;
|
||||
mem_err = 0;
|
||||
mem2hex((char*) addr, remcomOutBuffer, length, 1);
|
||||
if (mem_err) {
|
||||
strcpy (remcomOutBuffer, "E03");
|
||||
debug_error ("memory fault");
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
strcpy(remcomOutBuffer,"E01");
|
||||
debug_error("malformed read memory command: %s",remcomInBuffer);
|
||||
}
|
||||
break;
|
||||
|
||||
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
||||
case 'M' :
|
||||
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
|
||||
ptr = &remcomInBuffer[1];
|
||||
if (hexToInt(&ptr,&addr))
|
||||
if (*(ptr++) == ',')
|
||||
if (hexToInt(&ptr,&length))
|
||||
if (*(ptr++) == ':')
|
||||
{
|
||||
mem_err = 0;
|
||||
hex2mem(ptr, (char*) addr, length, 1);
|
||||
|
||||
if (mem_err) {
|
||||
strcpy (remcomOutBuffer, "E03");
|
||||
debug_error ("memory fault");
|
||||
} else {
|
||||
strcpy(remcomOutBuffer,"OK");
|
||||
}
|
||||
|
||||
ptr = 0;
|
||||
}
|
||||
if (ptr)
|
||||
{
|
||||
strcpy(remcomOutBuffer,"E02");
|
||||
debug_error("malformed write memory command: %s",remcomInBuffer);
|
||||
}
|
||||
break;
|
||||
|
||||
/* cAA..AA Continue at address AA..AA(optional) */
|
||||
/* sAA..AA Step one instruction from AA..AA(optional) */
|
||||
case 'c' :
|
||||
case 's' :
|
||||
/* try to read optional parameter, pc unchanged if no parm */
|
||||
ptr = &remcomInBuffer[1];
|
||||
if (hexToInt(&ptr,&addr))
|
||||
registers[ PC ] = addr;
|
||||
|
||||
newPC = registers[ PC];
|
||||
|
||||
/* clear the trace bit */
|
||||
registers[ PS ] &= 0xfffffeff;
|
||||
|
||||
/* set the trace bit if we're stepping */
|
||||
if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x100;
|
||||
|
||||
/*
|
||||
* If we found a match for the PC AND we are not returning
|
||||
* as a result of a breakpoint (33),
|
||||
* trace exception (9), nmi (31), jmp to
|
||||
* the old exception handler as if this code never ran.
|
||||
*/
|
||||
#if 0
|
||||
/* Don't really think we need this, except maybe for protection
|
||||
exceptions. */
|
||||
/*
|
||||
* invoke the previous handler.
|
||||
*/
|
||||
if (oldExceptionHook)
|
||||
(*oldExceptionHook) (frame->exceptionVector);
|
||||
newPC = registers[ PC ]; /* pc may have changed */
|
||||
#endif /* 0 */
|
||||
|
||||
_returnFromException(); /* this is a jump */
|
||||
|
||||
break;
|
||||
|
||||
/* kill the program */
|
||||
case 'k' : /* do nothing */
|
||||
#if 0
|
||||
/* Huh? This doesn't look like "nothing".
|
||||
m68k-stub.c and sparc-stub.c don't have it. */
|
||||
BREAKPOINT();
|
||||
#endif
|
||||
break;
|
||||
} /* switch */
|
||||
|
||||
/* reply to the request */
|
||||
putpacket(remcomOutBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* this function is used to set up exception handlers for tracing and
|
||||
breakpoints */
|
||||
void set_debug_traps()
|
||||
{
|
||||
extern void remcomHandler();
|
||||
int exception;
|
||||
|
||||
stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
|
||||
|
||||
exceptionHandler (0, _catchException0);
|
||||
exceptionHandler (1, _catchException1);
|
||||
exceptionHandler (3, _catchException3);
|
||||
exceptionHandler (4, _catchException4);
|
||||
exceptionHandler (5, _catchException5);
|
||||
exceptionHandler (6, _catchException6);
|
||||
exceptionHandler (7, _catchException7);
|
||||
exceptionHandler (8, _catchException8);
|
||||
exceptionHandler (9, _catchException9);
|
||||
exceptionHandler (10, _catchException10);
|
||||
exceptionHandler (11, _catchException11);
|
||||
exceptionHandler (12, _catchException12);
|
||||
exceptionHandler (13, _catchException13);
|
||||
exceptionHandler (14, _catchException14);
|
||||
exceptionHandler (16, _catchException16);
|
||||
|
||||
if (exceptionHook != remcomHandler)
|
||||
{
|
||||
oldExceptionHook = exceptionHook;
|
||||
exceptionHook = remcomHandler;
|
||||
}
|
||||
|
||||
/* In case GDB is started before us, ack any packets (presumably
|
||||
"$?#xx") sitting there. */
|
||||
putDebugChar ('+');
|
||||
|
||||
initialized = 1;
|
||||
|
||||
}
|
||||
|
||||
/* This function will generate a breakpoint exception. It is used at the
|
||||
beginning of a program to sync up with a debugger and can be used
|
||||
otherwise as a quick means to stop program execution and "break" into
|
||||
the debugger. */
|
||||
|
||||
void breakpoint()
|
||||
{
|
||||
if (initialized)
|
||||
#if 0
|
||||
handle_exception(3);
|
||||
#else
|
||||
BREAKPOINT();
|
||||
#endif
|
||||
waitabit();
|
||||
}
|
||||
|
||||
int waitlimit = 1000000;
|
||||
|
||||
#if 0
|
||||
void
|
||||
bogon()
|
||||
{
|
||||
waitabit();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
waitabit()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < waitlimit; i++) ;
|
||||
}
|
|
@ -1,360 +0,0 @@
|
|||
/* Intel 386 native support.
|
||||
Copyright (C) 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "language.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
/* Does AIX define this in <errno.h>? */
|
||||
extern int errno;
|
||||
|
||||
#ifndef NO_SYS_REG_H
|
||||
#include <sys/reg.h>
|
||||
#endif
|
||||
|
||||
#include "floatformat.h"
|
||||
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/* this table must line up with REGISTER_NAMES in tm-i386v.h */
|
||||
/* symbols like 'EAX' come from <sys/reg.h> */
|
||||
static int regmap[] =
|
||||
{
|
||||
EAX, ECX, EDX, EBX,
|
||||
USP, EBP, ESI, EDI,
|
||||
EIP, EFL, CS, SS,
|
||||
DS, ES, FS, GS,
|
||||
};
|
||||
|
||||
/* blockend is the value of u.u_ar0, and points to the
|
||||
* place where GS is stored
|
||||
*/
|
||||
|
||||
int
|
||||
i386_register_u_addr (blockend, regnum)
|
||||
int blockend;
|
||||
int regnum;
|
||||
{
|
||||
#if 0
|
||||
/* this will be needed if fp registers are reinstated */
|
||||
/* for now, you can look at them with 'info float'
|
||||
* sys5 wont let you change them with ptrace anyway
|
||||
*/
|
||||
if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM)
|
||||
{
|
||||
int ubase, fpstate;
|
||||
struct user u;
|
||||
ubase = blockend + 4 * (SS + 1) - KSTKSZ;
|
||||
fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
|
||||
return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (blockend + 4 * regmap[regnum]);
|
||||
|
||||
}
|
||||
|
||||
/* The code below only work on the aix ps/2 (i386-ibm-aix) -
|
||||
* mtranle@paris - Sat Apr 11 10:34:12 1992
|
||||
*/
|
||||
|
||||
struct env387
|
||||
{
|
||||
unsigned short control;
|
||||
unsigned short r0;
|
||||
unsigned short status;
|
||||
unsigned short r1;
|
||||
unsigned short tag;
|
||||
unsigned short r2;
|
||||
unsigned long eip;
|
||||
unsigned short code_seg;
|
||||
unsigned short opcode;
|
||||
unsigned long operand;
|
||||
unsigned short operand_seg;
|
||||
unsigned short r3;
|
||||
unsigned char regs[8][10];
|
||||
};
|
||||
|
||||
static
|
||||
print_387_status (status, ep)
|
||||
unsigned short status;
|
||||
struct env387 *ep;
|
||||
{
|
||||
int i;
|
||||
int bothstatus;
|
||||
int top;
|
||||
int fpreg;
|
||||
unsigned char *p;
|
||||
|
||||
bothstatus = ((status != 0) && (ep->status != 0));
|
||||
if (status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("u: ");
|
||||
print_387_status_word (status);
|
||||
}
|
||||
|
||||
if (ep->status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("e: ");
|
||||
print_387_status_word (ep->status);
|
||||
}
|
||||
|
||||
print_387_control_word (ep->control);
|
||||
printf_unfiltered ("last exception: ");
|
||||
printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode));
|
||||
printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg));
|
||||
printf_unfiltered ("%s; ", local_hex_string(ep->eip));
|
||||
printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg));
|
||||
printf_unfiltered (":%s\n", local_hex_string(ep->operand));
|
||||
|
||||
top = ((ep->status >> 11) & 7);
|
||||
|
||||
printf_unfiltered ("regno tag msb lsb value\n");
|
||||
for (fpreg = 7; fpreg >= 0; fpreg--)
|
||||
{
|
||||
double val;
|
||||
|
||||
printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
|
||||
|
||||
switch ((ep->tag >> ((7 - fpreg) * 2)) & 3)
|
||||
{
|
||||
case 0: printf_unfiltered ("valid "); break;
|
||||
case 1: printf_unfiltered ("zero "); break;
|
||||
case 2: printf_unfiltered ("trap "); break;
|
||||
case 3: printf_unfiltered ("empty "); break;
|
||||
}
|
||||
for (i = 9; i >= 0; i--)
|
||||
printf_unfiltered ("%02x", ep->regs[fpreg][i]);
|
||||
|
||||
i387_to_double ((char *)ep->regs[fpreg], (char *)&val);
|
||||
printf_unfiltered (" %#g\n", val);
|
||||
}
|
||||
}
|
||||
|
||||
static struct env387 core_env387;
|
||||
|
||||
void
|
||||
i386_float_info ()
|
||||
{
|
||||
struct env387 fps;
|
||||
int fpsaved = 0;
|
||||
/* We need to reverse the order of the registers. Apparently AIX stores
|
||||
the highest-numbered ones first. */
|
||||
struct env387 fps_fixed;
|
||||
int i;
|
||||
|
||||
if (inferior_pid)
|
||||
{
|
||||
char buf[10];
|
||||
unsigned short status;
|
||||
|
||||
ptrace (PT_READ_FPR, inferior_pid, buf, offsetof(struct env387, status));
|
||||
memcpy (&status, buf, sizeof (status));
|
||||
fpsaved = status;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((fpsaved = core_env387.status) != 0)
|
||||
memcpy(&fps, &core_env387, sizeof(fps));
|
||||
}
|
||||
|
||||
if (fpsaved == 0)
|
||||
{
|
||||
printf_unfiltered ("no floating point status saved\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (inferior_pid)
|
||||
{
|
||||
int offset;
|
||||
for (offset = 0; offset < sizeof(fps); offset += 10)
|
||||
{
|
||||
char buf[10];
|
||||
ptrace (PT_READ_FPR, inferior_pid, buf, offset);
|
||||
memcpy ((char *)&fps.control + offset, buf,
|
||||
MIN(10, sizeof(fps) - offset));
|
||||
}
|
||||
}
|
||||
fps_fixed = fps;
|
||||
for (i = 0; i < 8; ++i)
|
||||
memcpy (fps_fixed.regs[i], fps.regs[7 - i], 10);
|
||||
print_387_status (0, &fps_fixed);
|
||||
}
|
||||
|
||||
/* Fetch one register. */
|
||||
static void
|
||||
fetch_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
if (regno < FP0_REGNUM)
|
||||
*(int *)buf = ptrace (PT_READ_GPR, inferior_pid,
|
||||
PT_REG(regmap[regno]), 0, 0);
|
||||
else
|
||||
ptrace (PT_READ_FPR, inferior_pid, buf,
|
||||
(regno - FP0_REGNUM)*10 + offsetof(struct env387, regs));
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno < 0)
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
fetch_register (regno);
|
||||
else
|
||||
fetch_register (regno);
|
||||
}
|
||||
|
||||
/* store one register */
|
||||
static void
|
||||
store_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char buf[80];
|
||||
extern char registers[];
|
||||
errno = 0;
|
||||
if (regno < FP0_REGNUM)
|
||||
ptrace (PT_WRITE_GPR, inferior_pid, PT_REG(regmap[regno]),
|
||||
*(int *) ®isters[REGISTER_BYTE (regno)], 0);
|
||||
else
|
||||
ptrace (PT_WRITE_FPR, inferior_pid, ®isters[REGISTER_BYTE (regno)],
|
||||
(regno - FP0_REGNUM)*10 + offsetof(struct env387, regs));
|
||||
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (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). */
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno < 0)
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
store_register (regno);
|
||||
else
|
||||
store_register (regno);
|
||||
}
|
||||
|
||||
#ifndef CD_AX /* defined in sys/i386/coredump.h */
|
||||
# define CD_AX 0
|
||||
# define CD_BX 1
|
||||
# define CD_CX 2
|
||||
# define CD_DX 3
|
||||
# define CD_SI 4
|
||||
# define CD_DI 5
|
||||
# define CD_BP 6
|
||||
# define CD_SP 7
|
||||
# define CD_FL 8
|
||||
# define CD_IP 9
|
||||
# define CD_CS 10
|
||||
# define CD_DS 11
|
||||
# define CD_ES 12
|
||||
# define CD_FS 13
|
||||
# define CD_GS 14
|
||||
# define CD_SS 15
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The order here in core_regmap[] has to be the same as in
|
||||
* regmap[] above.
|
||||
*/
|
||||
static int core_regmap[] =
|
||||
{
|
||||
CD_AX, CD_CX, CD_DX, CD_BX,
|
||||
CD_SP, CD_BP, CD_SI, CD_DI,
|
||||
CD_IP, CD_FL, CD_CS, CD_SS,
|
||||
CD_DS, CD_ES, CD_FS, CD_GS,
|
||||
};
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned int reg_addr; /* ignored */
|
||||
{
|
||||
|
||||
if (which == 0)
|
||||
{
|
||||
/* Integer registers */
|
||||
|
||||
#define cd_regs(n) ((int *)core_reg_sect)[n]
|
||||
#define regs(n) *((int *) ®isters[REGISTER_BYTE (n)])
|
||||
|
||||
int i;
|
||||
for (i = 0; i < FP0_REGNUM; i++)
|
||||
regs(i) = cd_regs(core_regmap[i]);
|
||||
}
|
||||
else if (which == 2)
|
||||
{
|
||||
/* Floating point registers */
|
||||
|
||||
if (core_reg_size >= sizeof (core_env387))
|
||||
memcpy (&core_env387, core_reg_sect, core_reg_size);
|
||||
else
|
||||
fprintf_unfiltered (gdb_stderr, "Couldn't read float regs from core file\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle i386aix core file formats.
|
||||
FIXME: is this really bfd_target_unknown_flavour? */
|
||||
|
||||
static struct core_fns i386aix_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_i386aix ()
|
||||
{
|
||||
add_core_fns (&i386aix_core_fns);
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/* Low level interface to I386 running the GNU Hurd
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "floatformat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mach.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/exception.h>
|
||||
#include <mach_error.h>
|
||||
|
||||
#include "gnu-nat.h"
|
||||
|
||||
/* Hmmm... Should this not be here?
|
||||
* Now for i386_float_info() target_has_execution
|
||||
*/
|
||||
#include <target.h>
|
||||
|
||||
/* @@@ Should move print_387_status() to i387-tdep.c */
|
||||
extern void print_387_control_word (); /* i387-tdep.h */
|
||||
extern void print_387_status_word ();
|
||||
|
||||
/* Find offsets to thread states at compile time.
|
||||
* If your compiler does not grok this, calculate offsets
|
||||
* offsets yourself and use them (or get a compatible compiler :-)
|
||||
*/
|
||||
|
||||
#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg)
|
||||
|
||||
/* at reg_offset[i] is the offset to the i386_thread_state
|
||||
* location where the gdb registers[i] is stored.
|
||||
*/
|
||||
|
||||
static int reg_offset[] =
|
||||
{
|
||||
REG_OFFSET(eax), REG_OFFSET(ecx), REG_OFFSET(edx), REG_OFFSET(ebx),
|
||||
REG_OFFSET(uesp), REG_OFFSET(ebp), REG_OFFSET(esi), REG_OFFSET(edi),
|
||||
REG_OFFSET(eip), REG_OFFSET(efl), REG_OFFSET(cs), REG_OFFSET(ss),
|
||||
REG_OFFSET(ds), REG_OFFSET(es), REG_OFFSET(fs), REG_OFFSET(gs)
|
||||
};
|
||||
|
||||
#define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum])
|
||||
|
||||
/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
|
||||
* Caller knows that the regs handled in one transaction are of same size.
|
||||
*/
|
||||
#define FETCH_REGS(state, regnum, count) \
|
||||
memcpy (®isters[REGISTER_BYTE (regnum)], \
|
||||
REG_ADDR (state, regnum), \
|
||||
count * REGISTER_RAW_SIZE (regnum))
|
||||
|
||||
/* Store COUNT contiguous registers to thread STATE starting from REGNUM */
|
||||
#define STORE_REGS(state, regnum, count) \
|
||||
memcpy (REG_ADDR (state, regnum), \
|
||||
®isters[REGISTER_BYTE (regnum)], \
|
||||
count * REGISTER_RAW_SIZE (regnum))
|
||||
|
||||
/*
|
||||
* Fetch inferiors registers for gdb.
|
||||
* REG specifies which (as gdb views it) register, -1 for all.
|
||||
*/
|
||||
void
|
||||
gnu_fetch_registers (int reg)
|
||||
{
|
||||
thread_state_t state;
|
||||
struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
|
||||
if (!thread)
|
||||
error ("fetch inferior registers: %d: Invalid thread", inferior_pid);
|
||||
|
||||
state = proc_get_state (thread, 0);
|
||||
|
||||
if (! state)
|
||||
warning ("Couldn't fetch register %s.", reg_names[reg]);
|
||||
else if (reg >= 0)
|
||||
{
|
||||
proc_debug (thread, "fetching register: %s", reg_names[reg]);
|
||||
supply_register (reg, REG_ADDR(state, reg));
|
||||
thread->fetched_regs |= (1 << reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "fetching all registers");
|
||||
for (reg = 0; reg < NUM_REGS; reg++)
|
||||
supply_register (reg, REG_ADDR(state, reg));
|
||||
thread->fetched_regs = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
* If REG is -1, do this for all registers.
|
||||
* Otherwise, REG specifies which register
|
||||
*
|
||||
* On mach3 all registers are always saved in one call.
|
||||
*/
|
||||
void
|
||||
gnu_store_registers (reg)
|
||||
int reg;
|
||||
{
|
||||
int was_aborted, was_valid;
|
||||
thread_state_t state;
|
||||
thread_state_data_t old_state;
|
||||
struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
|
||||
if (! thread)
|
||||
error ("store inferior registers: %d: Invalid thread", inferior_pid);
|
||||
|
||||
proc_debug (thread, "storing register %s.", reg_names[reg]);
|
||||
|
||||
was_aborted = thread->aborted;
|
||||
was_valid = thread->state_valid;
|
||||
if (! was_aborted && was_valid)
|
||||
bcopy (&thread->state, &old_state, sizeof (old_state));
|
||||
|
||||
state = proc_get_state (thread, 1);
|
||||
|
||||
if (! state)
|
||||
warning ("Couldn't store register %s.", reg_names[reg]);
|
||||
else
|
||||
{
|
||||
if (! was_aborted && was_valid)
|
||||
/* See which registers have changed after aborting the thread. */
|
||||
{
|
||||
int check_reg;
|
||||
for (check_reg = 0; check_reg < NUM_REGS; check_reg++)
|
||||
if ((thread->fetched_regs & (1 << check_reg))
|
||||
&& bcmp (REG_ADDR (&old_state, check_reg),
|
||||
REG_ADDR (state, check_reg),
|
||||
REGISTER_RAW_SIZE (check_reg)))
|
||||
/* Register CHECK_REG has changed! Ack! */
|
||||
{
|
||||
warning ("Register %s changed after thread was aborted.",
|
||||
reg_names [check_reg]);
|
||||
if (reg >= 0 && reg != check_reg)
|
||||
/* Update gdb's copy of the register. */
|
||||
supply_register (check_reg, REG_ADDR (state, check_reg));
|
||||
else
|
||||
warning ("... also writing this register! Suspicious...");
|
||||
}
|
||||
}
|
||||
|
||||
if (reg >= 0)
|
||||
{
|
||||
proc_debug (thread, "storing register: %s", reg_names[reg]);
|
||||
STORE_REGS (state, reg, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_debug (thread, "storing all registers");
|
||||
for (reg = 0; reg < NUM_REGS; reg++)
|
||||
STORE_REGS (state, reg, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* jtv@hut.fi: I copied and modified this 387 code from
|
||||
* gdb/i386-xdep.c. Modifications for Mach 3.0.
|
||||
*
|
||||
* i387 status dumper. See also i387-tdep.c
|
||||
*/
|
||||
struct env387
|
||||
{
|
||||
unsigned short control;
|
||||
unsigned short r0;
|
||||
unsigned short status;
|
||||
unsigned short r1;
|
||||
unsigned short tag;
|
||||
unsigned short r2;
|
||||
unsigned long eip;
|
||||
unsigned short code_seg;
|
||||
unsigned short opcode;
|
||||
unsigned long operand;
|
||||
unsigned short operand_seg;
|
||||
unsigned short r3;
|
||||
unsigned char regs[8][10];
|
||||
};
|
||||
/* This routine is machine independent?
|
||||
* Should move it to i387-tdep.c but you need to export struct env387
|
||||
*/
|
||||
static
|
||||
print_387_status (status, ep)
|
||||
unsigned short status;
|
||||
struct env387 *ep;
|
||||
{
|
||||
int i;
|
||||
int bothstatus;
|
||||
int top;
|
||||
int fpreg;
|
||||
unsigned char *p;
|
||||
|
||||
bothstatus = ((status != 0) && (ep->status != 0));
|
||||
if (status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("u: ");
|
||||
print_387_status_word (status);
|
||||
}
|
||||
|
||||
if (ep->status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("e: ");
|
||||
print_387_status_word (ep->status);
|
||||
}
|
||||
|
||||
print_387_control_word (ep->control);
|
||||
printf_unfiltered ("last exception: ");
|
||||
printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode));
|
||||
printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg));
|
||||
printf_unfiltered ("%s; ", local_hex_string(ep->eip));
|
||||
printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg));
|
||||
printf_unfiltered (":%s\n", local_hex_string(ep->operand));
|
||||
|
||||
top = (ep->status >> 11) & 7;
|
||||
|
||||
printf_unfiltered ("regno tag msb lsb value\n");
|
||||
for (fpreg = 7; fpreg >= 0; fpreg--)
|
||||
{
|
||||
double val;
|
||||
|
||||
printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
|
||||
|
||||
switch ((ep->tag >> (fpreg * 2)) & 3)
|
||||
{
|
||||
case 0: printf_unfiltered ("valid "); break;
|
||||
case 1: printf_unfiltered ("zero "); break;
|
||||
case 2: printf_unfiltered ("trap "); break;
|
||||
case 3: printf_unfiltered ("empty "); break;
|
||||
}
|
||||
for (i = 9; i >= 0; i--)
|
||||
printf_unfiltered ("%02x", ep->regs[fpreg][i]);
|
||||
|
||||
floatformat_to_double (&floatformat_i387_ext, (char *)ep->regs[fpreg],
|
||||
&val);
|
||||
printf_unfiltered (" %g\n", val);
|
||||
}
|
||||
if (ep->r0)
|
||||
printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string(ep->r0));
|
||||
if (ep->r1)
|
||||
printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string(ep->r1));
|
||||
if (ep->r2)
|
||||
printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string(ep->r2));
|
||||
if (ep->r3)
|
||||
printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string(ep->r3));
|
||||
}
|
||||
|
||||
/*
|
||||
* values that go into fp_kind (from <i386/fpreg.h>)
|
||||
*/
|
||||
#define FP_NO 0 /* no fp chip, no emulator (no fp support) */
|
||||
#define FP_SW 1 /* no fp chip, using software emulator */
|
||||
#define FP_HW 2 /* chip present bit */
|
||||
#define FP_287 2 /* 80287 chip present */
|
||||
#define FP_387 3 /* 80387 chip present */
|
||||
|
||||
typedef struct fpstate {
|
||||
#if 1
|
||||
unsigned char state[FP_STATE_BYTES]; /* "hardware" state */
|
||||
#else
|
||||
struct env387 state; /* Actually this */
|
||||
#endif
|
||||
int status; /* Duplicate status */
|
||||
} *fpstate_t;
|
||||
|
||||
/* Mach 3 specific routines.
|
||||
*/
|
||||
static int
|
||||
get_i387_state (fstate)
|
||||
struct fpstate *fstate;
|
||||
{
|
||||
error_t err;
|
||||
thread_state_data_t state;
|
||||
unsigned int fsCnt = i386_FLOAT_STATE_COUNT;
|
||||
struct i386_float_state *fsp;
|
||||
struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid);
|
||||
|
||||
if (!thread)
|
||||
error ("get_i387_state: Invalid thread");
|
||||
|
||||
proc_abort (thread, 0); /* Make sure THREAD's in a reasonable state. */
|
||||
|
||||
err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt);
|
||||
if (err)
|
||||
{
|
||||
warning ("Can not get live floating point state: %s",
|
||||
mach_error_string (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsp = (struct i386_float_state *)state;
|
||||
/* The 387 chip (also 486 counts) or a software emulator? */
|
||||
if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW))
|
||||
return 0;
|
||||
|
||||
/* Clear the target then copy thread's float state there.
|
||||
Make a copy of the status word, for some reason?
|
||||
*/
|
||||
memset (fstate, 0, sizeof (struct fpstate));
|
||||
|
||||
fstate->status = fsp->exc_status;
|
||||
|
||||
memcpy (fstate->state, (char *)&fsp->hw_state, FP_STATE_BYTES);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by "info float" command
|
||||
*/
|
||||
void
|
||||
i386_mach3_float_info()
|
||||
{
|
||||
char buf [sizeof (struct fpstate) + 2 * sizeof (int)];
|
||||
int valid = 0;
|
||||
fpstate_t fps;
|
||||
|
||||
if (target_has_execution)
|
||||
valid = get_i387_state (buf);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
warning ("no floating point status saved");
|
||||
return;
|
||||
}
|
||||
|
||||
fps = (fpstate_t) buf;
|
||||
|
||||
print_387_status (fps->status, (struct env387 *)fps->state);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/* Target-dependent code for Intel 386 running LynxOS.
|
||||
Copyright 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
|
||||
/* Return the PC of the caller from the call frame. Assumes the subr prologue
|
||||
has already been executed, and the frame pointer setup. If this is the
|
||||
outermost frame, we check to see if we are in a system call by examining the
|
||||
previous instruction. If so, then the return PC is actually at SP+4 because
|
||||
system calls use a different calling sequence. */
|
||||
|
||||
CORE_ADDR
|
||||
i386lynx_saved_pc_after_call (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
char opcode[7];
|
||||
static const unsigned char call_inst[] = {0x9a, 0, 0, 0, 0, 8, 0}; /* lcall 0x8,0x0 */
|
||||
|
||||
read_memory (frame->pc - 7, opcode, 7);
|
||||
if (memcmp (opcode, call_inst, 7) == 0)
|
||||
return read_memory_integer (read_register (SP_REGNUM) + 4, 4);
|
||||
|
||||
return read_memory_integer (read_register (SP_REGNUM), 4);
|
||||
}
|
|
@ -1,421 +0,0 @@
|
|||
/* Low level interface to I386 running mach 3.0.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "floatformat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mach.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/exception.h>
|
||||
#include <mach_error.h>
|
||||
|
||||
/* Hmmm... Should this not be here?
|
||||
* Now for i386_float_info() target_has_execution
|
||||
*/
|
||||
#include <target.h>
|
||||
|
||||
/* This mess is duplicated in bfd/i386mach3.h
|
||||
*
|
||||
* This is an ugly way to hack around the incorrect
|
||||
* definition of UPAGES in i386/machparam.h.
|
||||
*
|
||||
* The definition should specify the size reserved
|
||||
* for "struct user" in core files in PAGES,
|
||||
* but instead it gives it in 512-byte core-clicks
|
||||
* for i386 and i860.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#if UPAGES == 16
|
||||
#define UAREA_SIZE ctob(UPAGES)
|
||||
#elif UPAGES == 2
|
||||
#define UAREA_SIZE (NBPG*UPAGES)
|
||||
#else
|
||||
FIXME!! UPAGES is neither 2 nor 16
|
||||
#endif
|
||||
|
||||
/* @@@ Should move print_387_status() to i387-tdep.c */
|
||||
extern void print_387_control_word (); /* i387-tdep.h */
|
||||
extern void print_387_status_word ();
|
||||
|
||||
#define private static
|
||||
|
||||
|
||||
/* Find offsets to thread states at compile time.
|
||||
* If your compiler does not grok this, calculate offsets
|
||||
* offsets yourself and use them (or get a compatible compiler :-)
|
||||
*/
|
||||
|
||||
#define REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg)
|
||||
|
||||
/* at reg_offset[i] is the offset to the i386_thread_state
|
||||
* location where the gdb registers[i] is stored.
|
||||
*/
|
||||
|
||||
static int reg_offset[] =
|
||||
{
|
||||
REG_OFFSET(eax), REG_OFFSET(ecx), REG_OFFSET(edx), REG_OFFSET(ebx),
|
||||
REG_OFFSET(uesp), REG_OFFSET(ebp), REG_OFFSET(esi), REG_OFFSET(edi),
|
||||
REG_OFFSET(eip), REG_OFFSET(efl), REG_OFFSET(cs), REG_OFFSET(ss),
|
||||
REG_OFFSET(ds), REG_OFFSET(es), REG_OFFSET(fs), REG_OFFSET(gs)
|
||||
};
|
||||
|
||||
#define REG_ADDRESS(state,regnum) ((char *)(state)+reg_offset[regnum])
|
||||
|
||||
/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
|
||||
* Caller knows that the regs handled in one transaction are of same size.
|
||||
*/
|
||||
#define FETCH_REGS(state, regnum, count) \
|
||||
memcpy (®isters[REGISTER_BYTE (regnum)], \
|
||||
REG_ADDRESS (state, regnum), \
|
||||
count*REGISTER_SIZE)
|
||||
|
||||
/* Store COUNT contiguous registers to thread STATE starting from REGNUM */
|
||||
#define STORE_REGS(state, regnum, count) \
|
||||
memcpy (REG_ADDRESS (state, regnum), \
|
||||
®isters[REGISTER_BYTE (regnum)], \
|
||||
count*REGISTER_SIZE)
|
||||
|
||||
/*
|
||||
* Fetch inferiors registers for gdb.
|
||||
* REGNO specifies which (as gdb views it) register, -1 for all.
|
||||
*/
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
kern_return_t ret;
|
||||
thread_state_data_t state;
|
||||
unsigned int stateCnt = i386_THREAD_STATE_COUNT;
|
||||
int index;
|
||||
|
||||
if (! MACH_PORT_VALID (current_thread))
|
||||
error ("fetch inferior registers: Invalid thread");
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 1);
|
||||
|
||||
ret = thread_get_state (current_thread,
|
||||
i386_THREAD_STATE,
|
||||
state,
|
||||
&stateCnt);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
warning ("fetch_inferior_registers: %s ",
|
||||
mach_error_string (ret));
|
||||
#if 0
|
||||
/* It may be more effective to store validate all of them,
|
||||
* since we fetched them all anyway
|
||||
*/
|
||||
else if (regno != -1)
|
||||
supply_register (regno, (char *)state+reg_offset[regno]);
|
||||
#endif
|
||||
else
|
||||
{
|
||||
for (index = 0; index < NUM_REGS; index++)
|
||||
supply_register (index, (char *)state+reg_offset[index]);
|
||||
}
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
* If REGNO is -1, do this for all registers.
|
||||
* Otherwise, REGNO specifies which register
|
||||
*
|
||||
* On mach3 all registers are always saved in one call.
|
||||
*/
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
kern_return_t ret;
|
||||
thread_state_data_t state;
|
||||
unsigned int stateCnt = i386_THREAD_STATE_COUNT;
|
||||
register int index;
|
||||
|
||||
if (! MACH_PORT_VALID (current_thread))
|
||||
error ("store inferior registers: Invalid thread");
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 1);
|
||||
|
||||
/* Fetch the state of the current thread */
|
||||
ret = thread_get_state (current_thread,
|
||||
i386_THREAD_STATE,
|
||||
state,
|
||||
&stateCnt);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
{
|
||||
warning ("store_inferior_registers (get): %s",
|
||||
mach_error_string (ret));
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* move gdb's registers to thread's state
|
||||
*
|
||||
* Since we save all registers anyway, save the ones
|
||||
* that gdb thinks are valid (e.g. ignore the regno
|
||||
* parameter)
|
||||
*/
|
||||
#if 0
|
||||
if (regno != -1)
|
||||
STORE_REGS (state, regno, 1);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (index = 0; index < NUM_REGS; index++)
|
||||
STORE_REGS (state, index, 1);
|
||||
}
|
||||
|
||||
/* Write gdb's current view of register to the thread
|
||||
*/
|
||||
ret = thread_set_state (current_thread,
|
||||
i386_THREAD_STATE,
|
||||
state,
|
||||
i386_THREAD_STATE_COUNT);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
warning ("store_inferior_registers (set): %s",
|
||||
mach_error_string (ret));
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return the address in the core dump or inferior of register REGNO.
|
||||
* BLOCKEND should be the address of the end of the UPAGES area read
|
||||
* in memory, but it's not?
|
||||
*
|
||||
* Currently our UX server dumps the whole thread state to the
|
||||
* core file. If your UX does something else, adapt the routine
|
||||
* below to return the offset to the given register.
|
||||
*
|
||||
* Called by core-aout.c(fetch_core_registers)
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
register_addr (regno, blockend)
|
||||
int regno;
|
||||
int blockend;
|
||||
{
|
||||
unsigned int addr;
|
||||
|
||||
if (regno < 0 || regno >= NUM_REGS)
|
||||
error ("Invalid register number %d.", regno);
|
||||
|
||||
/* UAREA_SIZE == 8 kB in i386 */
|
||||
addr = (unsigned int)REG_ADDRESS (UAREA_SIZE - sizeof(struct i386_thread_state), regno);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* jtv@hut.fi: I copied and modified this 387 code from
|
||||
* gdb/i386-xdep.c. Modifications for Mach 3.0.
|
||||
*
|
||||
* i387 status dumper. See also i387-tdep.c
|
||||
*/
|
||||
struct env387
|
||||
{
|
||||
unsigned short control;
|
||||
unsigned short r0;
|
||||
unsigned short status;
|
||||
unsigned short r1;
|
||||
unsigned short tag;
|
||||
unsigned short r2;
|
||||
unsigned long eip;
|
||||
unsigned short code_seg;
|
||||
unsigned short opcode;
|
||||
unsigned long operand;
|
||||
unsigned short operand_seg;
|
||||
unsigned short r3;
|
||||
unsigned char regs[8][10];
|
||||
};
|
||||
/* This routine is machine independent?
|
||||
* Should move it to i387-tdep.c but you need to export struct env387
|
||||
*/
|
||||
private
|
||||
print_387_status (status, ep)
|
||||
unsigned short status;
|
||||
struct env387 *ep;
|
||||
{
|
||||
int i;
|
||||
int bothstatus;
|
||||
int top;
|
||||
int fpreg;
|
||||
unsigned char *p;
|
||||
|
||||
bothstatus = ((status != 0) && (ep->status != 0));
|
||||
if (status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("u: ");
|
||||
print_387_status_word (status);
|
||||
}
|
||||
|
||||
if (ep->status != 0)
|
||||
{
|
||||
if (bothstatus)
|
||||
printf_unfiltered ("e: ");
|
||||
print_387_status_word (ep->status);
|
||||
}
|
||||
|
||||
print_387_control_word (ep->control);
|
||||
printf_unfiltered ("last exception: ");
|
||||
printf_unfiltered ("opcode %s; ", local_hex_string(ep->opcode));
|
||||
printf_unfiltered ("pc %s:", local_hex_string(ep->code_seg));
|
||||
printf_unfiltered ("%s; ", local_hex_string(ep->eip));
|
||||
printf_unfiltered ("operand %s", local_hex_string(ep->operand_seg));
|
||||
printf_unfiltered (":%s\n", local_hex_string(ep->operand));
|
||||
|
||||
top = (ep->status >> 11) & 7;
|
||||
|
||||
printf_unfiltered ("regno tag msb lsb value\n");
|
||||
for (fpreg = 7; fpreg >= 0; fpreg--)
|
||||
{
|
||||
double val;
|
||||
|
||||
printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
|
||||
|
||||
switch ((ep->tag >> (fpreg * 2)) & 3)
|
||||
{
|
||||
case 0: printf_unfiltered ("valid "); break;
|
||||
case 1: printf_unfiltered ("zero "); break;
|
||||
case 2: printf_unfiltered ("trap "); break;
|
||||
case 3: printf_unfiltered ("empty "); break;
|
||||
}
|
||||
for (i = 9; i >= 0; i--)
|
||||
printf_unfiltered ("%02x", ep->regs[fpreg][i]);
|
||||
|
||||
floatformat_to_double (&floatformat_i387_ext, (char *)ep->regs[fpreg],
|
||||
&val);
|
||||
printf_unfiltered (" %g\n", val);
|
||||
}
|
||||
if (ep->r0)
|
||||
printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string(ep->r0));
|
||||
if (ep->r1)
|
||||
printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string(ep->r1));
|
||||
if (ep->r2)
|
||||
printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string(ep->r2));
|
||||
if (ep->r3)
|
||||
printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string(ep->r3));
|
||||
}
|
||||
|
||||
/*
|
||||
* values that go into fp_kind (from <i386/fpreg.h>)
|
||||
*/
|
||||
#define FP_NO 0 /* no fp chip, no emulator (no fp support) */
|
||||
#define FP_SW 1 /* no fp chip, using software emulator */
|
||||
#define FP_HW 2 /* chip present bit */
|
||||
#define FP_287 2 /* 80287 chip present */
|
||||
#define FP_387 3 /* 80387 chip present */
|
||||
|
||||
typedef struct fpstate {
|
||||
#if 1
|
||||
unsigned char state[FP_STATE_BYTES]; /* "hardware" state */
|
||||
#else
|
||||
struct env387 state; /* Actually this */
|
||||
#endif
|
||||
int status; /* Duplicate status */
|
||||
} *fpstate_t;
|
||||
|
||||
/* Mach 3 specific routines.
|
||||
*/
|
||||
private boolean_t
|
||||
get_i387_state (fstate)
|
||||
struct fpstate *fstate;
|
||||
{
|
||||
kern_return_t ret;
|
||||
thread_state_data_t state;
|
||||
unsigned int fsCnt = i386_FLOAT_STATE_COUNT;
|
||||
struct i386_float_state *fsp;
|
||||
|
||||
ret = thread_get_state (current_thread,
|
||||
i386_FLOAT_STATE,
|
||||
state,
|
||||
&fsCnt);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
{
|
||||
warning ("Can not get live floating point state: %s",
|
||||
mach_error_string (ret));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fsp = (struct i386_float_state *)state;
|
||||
/* The 387 chip (also 486 counts) or a software emulator? */
|
||||
if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW))
|
||||
return FALSE;
|
||||
|
||||
/* Clear the target then copy thread's float state there.
|
||||
Make a copy of the status word, for some reason?
|
||||
*/
|
||||
memset (fstate, 0, sizeof (struct fpstate));
|
||||
|
||||
fstate->status = fsp->exc_status;
|
||||
|
||||
memcpy (fstate->state, (char *)&fsp->hw_state, FP_STATE_BYTES);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private boolean_t
|
||||
get_i387_core_state (fstate)
|
||||
struct fpstate *fstate;
|
||||
{
|
||||
/* Not implemented yet. Core files do not contain float state. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by "info float" command
|
||||
*/
|
||||
void
|
||||
i386_mach3_float_info()
|
||||
{
|
||||
char buf [sizeof (struct fpstate) + 2 * sizeof (int)];
|
||||
boolean_t valid = FALSE;
|
||||
fpstate_t fps;
|
||||
|
||||
if (target_has_execution)
|
||||
valid = get_i387_state (buf);
|
||||
#if 0
|
||||
else if (WE HAVE CORE FILE) /* @@@@ Core files not supported */
|
||||
valid = get_i387_core_state (buf);
|
||||
#endif
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
warning ("no floating point status saved");
|
||||
return;
|
||||
}
|
||||
|
||||
fps = (fpstate_t) buf;
|
||||
|
||||
print_387_status (fps->status, (struct env387 *)fps->state);
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/* Native dependent code for Mach 386's for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/user.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
#include <sys/core.h>
|
||||
|
||||
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno; /* Original value discarded */
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_state inferior_fp_registers;
|
||||
extern char registers[];
|
||||
|
||||
registers_fetched ();
|
||||
|
||||
ptrace (PTRACE_GETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers);
|
||||
ptrace (PTRACE_GETFPREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_fp_registers);
|
||||
|
||||
memcpy (registers, &inferior_registers, sizeof inferior_registers);
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
inferior_fp_registers.f_st,
|
||||
sizeof inferior_fp_registers.f_st);
|
||||
memcpy (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
&inferior_fp_registers.f_ctrl,
|
||||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st);
|
||||
}
|
||||
|
||||
/* 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). */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_state inferior_fp_registers;
|
||||
extern char registers[];
|
||||
|
||||
memcpy (&inferior_registers, registers, 20 * 4);
|
||||
|
||||
memcpy (inferior_fp_registers.f_st,®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof inferior_fp_registers.f_st);
|
||||
memcpy (&inferior_fp_registers.f_ctrl,
|
||||
®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.f_st);
|
||||
|
||||
#ifdef PTRACE_FP_BUG
|
||||
if (regno == FP_REGNUM || regno == -1)
|
||||
/* Storing the frame pointer requires a gross hack, in which an
|
||||
instruction that moves eax into ebp gets single-stepped. */
|
||||
{
|
||||
int stack = inferior_registers.r_reg[SP_REGNUM];
|
||||
int stuff = ptrace (PTRACE_PEEKDATA, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) stack);
|
||||
int reg = inferior_registers.r_reg[EAX];
|
||||
inferior_registers.r_reg[EAX] =
|
||||
inferior_registers.r_reg[FP_REGNUM];
|
||||
ptrace (PTRACE_SETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers);
|
||||
ptrace (PTRACE_POKEDATA, inferior_pid, (PTRACE_ARG3_TYPE) stack, 0xc589);
|
||||
ptrace (PTRACE_SINGLESTEP, inferior_pid, (PTRACE_ARG3_TYPE) stack, 0);
|
||||
wait (0);
|
||||
ptrace (PTRACE_POKEDATA, inferior_pid, (PTRACE_ARG3_TYPE) stack, stuff);
|
||||
inferior_registers.r_reg[EAX] = reg;
|
||||
}
|
||||
#endif
|
||||
ptrace (PTRACE_SETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers);
|
||||
ptrace (PTRACE_SETFPREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_fp_registers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Work with core files, for GDB. */
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned int reg_addr; /* Unused in this version */
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
switch (which) {
|
||||
case 0:
|
||||
case 1:
|
||||
memcpy (registers, core_reg_sect, core_reg_size);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#ifdef FP0_REGNUM
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
core_reg_sect,
|
||||
core_reg_size); /* FIXME, probably bogus */
|
||||
#endif
|
||||
#ifdef FPC_REGNUM
|
||||
memcpy (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
&corestr.c_fpu.f_fpstatus.f_ctrl,
|
||||
sizeof corestr.c_fpu.f_fpstatus -
|
||||
sizeof corestr.c_fpu.f_fpstatus.f_st);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle i386mach core file formats.
|
||||
FIXME: is this really bfd_target_unknown_flavour? */
|
||||
|
||||
static struct core_fns i386mach_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_i386mach ()
|
||||
{
|
||||
add_core_fns (&i386mach_core_fns);
|
||||
}
|
|
@ -1,371 +0,0 @@
|
|||
/* Intel 386 native support for SYSV systems (pre-SVR4).
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "language.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#ifdef USG
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||
#include <sys/debugreg.h>
|
||||
#endif
|
||||
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#ifndef NO_SYS_REG_H
|
||||
#include <sys/reg.h>
|
||||
#endif
|
||||
|
||||
#include "floatformat.h"
|
||||
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/* this table must line up with REGISTER_NAMES in tm-i386v.h */
|
||||
/* symbols like 'EAX' come from <sys/reg.h> */
|
||||
static int regmap[] =
|
||||
{
|
||||
EAX, ECX, EDX, EBX,
|
||||
UESP, EBP, ESI, EDI,
|
||||
EIP, EFL, CS, SS,
|
||||
DS, ES, FS, GS,
|
||||
};
|
||||
|
||||
/* blockend is the value of u.u_ar0, and points to the
|
||||
* place where GS is stored
|
||||
*/
|
||||
|
||||
int
|
||||
i386_register_u_addr (blockend, regnum)
|
||||
int blockend;
|
||||
int regnum;
|
||||
{
|
||||
struct user u;
|
||||
int fpstate;
|
||||
int ubase;
|
||||
|
||||
ubase = blockend;
|
||||
/* FIXME: Should have better way to test floating point range */
|
||||
if (regnum >= FP0_REGNUM && regnum <= (FP0_REGNUM + 7))
|
||||
{
|
||||
#ifdef KSTKSZ /* SCO, and others? */
|
||||
ubase += 4 * (SS + 1) - KSTKSZ;
|
||||
fpstate = ubase + ((char *)&u.u_fps.u_fpstate - (char *)&u);
|
||||
return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
|
||||
#else
|
||||
fpstate = ubase + ((char *)&u.i387.st_space - (char *)&u);
|
||||
return (fpstate + 10 * (regnum - FP0_REGNUM));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ubase + 4 * regmap[regnum]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
kernel_u_size ()
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||
|
||||
#if !defined (offsetof)
|
||||
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
/* Record the value of the debug control register. */
|
||||
static int debug_control_mirror;
|
||||
|
||||
/* Record which address associates with which register. */
|
||||
static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
|
||||
|
||||
static int
|
||||
i386_insert_aligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
|
||||
int));
|
||||
|
||||
static int
|
||||
i386_insert_nonaligned_watchpoint PARAMS ((int, CORE_ADDR, CORE_ADDR, int,
|
||||
int));
|
||||
|
||||
/* Insert a watchpoint. */
|
||||
|
||||
int
|
||||
i386_insert_watchpoint (pid, addr, len, rw)
|
||||
int pid;
|
||||
CORE_ADDR addr;
|
||||
int len;
|
||||
int rw;
|
||||
{
|
||||
return i386_insert_aligned_watchpoint (pid, addr, addr, len, rw);
|
||||
}
|
||||
|
||||
static int
|
||||
i386_insert_aligned_watchpoint (pid, waddr, addr, len, rw)
|
||||
int pid;
|
||||
CORE_ADDR waddr;
|
||||
CORE_ADDR addr;
|
||||
int len;
|
||||
int rw;
|
||||
{
|
||||
int i;
|
||||
int read_write_bits, len_bits;
|
||||
int free_debug_register;
|
||||
int register_number;
|
||||
|
||||
/* Look for a free debug register. */
|
||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||
{
|
||||
if (address_lookup[i - DR_FIRSTADDR] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more debug registers! */
|
||||
if (i > DR_LASTADDR)
|
||||
return -1;
|
||||
|
||||
read_write_bits = ((rw & 1) ? DR_RW_READ : 0) | ((rw & 2) ? DR_RW_WRITE : 0);
|
||||
|
||||
if (len == 1)
|
||||
len_bits = DR_LEN_1;
|
||||
else if (len == 2)
|
||||
{
|
||||
if (addr % 2)
|
||||
return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
|
||||
len_bits = DR_LEN_2;
|
||||
}
|
||||
|
||||
else if (len == 4)
|
||||
{
|
||||
if (addr % 4)
|
||||
return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
|
||||
len_bits = DR_LEN_4;
|
||||
}
|
||||
else
|
||||
return i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw);
|
||||
|
||||
free_debug_register = i;
|
||||
register_number = free_debug_register - DR_FIRSTADDR;
|
||||
debug_control_mirror |=
|
||||
((read_write_bits | len_bits)
|
||||
<< (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
|
||||
debug_control_mirror |=
|
||||
(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
|
||||
debug_control_mirror |= DR_LOCAL_SLOWDOWN;
|
||||
debug_control_mirror &= ~DR_CONTROL_RESERVED;
|
||||
|
||||
ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
|
||||
debug_control_mirror);
|
||||
ptrace (6, pid, offsetof (struct user, u_debugreg[free_debug_register]),
|
||||
addr);
|
||||
|
||||
/* Record where we came from. */
|
||||
address_lookup[register_number] = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i386_insert_nonaligned_watchpoint (pid, waddr, addr, len, rw)
|
||||
int pid;
|
||||
CORE_ADDR waddr;
|
||||
CORE_ADDR addr;
|
||||
int len;
|
||||
int rw;
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int rv;
|
||||
|
||||
static int size_try_array[16] = {
|
||||
1, 1, 1, 1, /* trying size one */
|
||||
2, 1, 2, 1, /* trying size two */
|
||||
2, 1, 2, 1, /* trying size three */
|
||||
4, 1, 2, 1 /* trying size four */
|
||||
};
|
||||
|
||||
rv = 0;
|
||||
while (len > 0)
|
||||
{
|
||||
align = addr % 4;
|
||||
/* Four is the maximum length for 386. */
|
||||
size = (len > 4) ? 3 : len - 1;
|
||||
size = size_try_array[size * 4 + align];
|
||||
|
||||
rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
|
||||
if (rv)
|
||||
{
|
||||
i386_remove_watchpoint (pid, waddr, size);
|
||||
return rv;
|
||||
}
|
||||
addr += size;
|
||||
len -= size;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Remove a watchpoint. */
|
||||
|
||||
int
|
||||
i386_remove_watchpoint (pid, addr, len)
|
||||
int pid;
|
||||
CORE_ADDR addr;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
int register_number;
|
||||
|
||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||
{
|
||||
register_number = i - DR_FIRSTADDR;
|
||||
if (address_lookup[register_number] == addr)
|
||||
{
|
||||
debug_control_mirror &=
|
||||
~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
|
||||
address_lookup[register_number] = 0;
|
||||
}
|
||||
}
|
||||
ptrace (6, pid, offsetof (struct user, u_debugreg[DR_CONTROL]),
|
||||
debug_control_mirror);
|
||||
ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if stopped by a watchpoint. */
|
||||
|
||||
CORE_ADDR
|
||||
i386_stopped_by_watchpoint (pid)
|
||||
int pid;
|
||||
{
|
||||
int i;
|
||||
int status;
|
||||
|
||||
status = ptrace (3, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
|
||||
ptrace (6, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0);
|
||||
|
||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||
{
|
||||
if (status & (1 << (i - DR_FIRSTADDR)))
|
||||
return address_lookup[i - DR_FIRSTADDR];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */
|
||||
|
||||
#if 0
|
||||
/* using FLOAT_INFO as is would be a problem. FLOAT_INFO is called
|
||||
via a command xxx and eventually calls ptrace without ever having
|
||||
traversed the target vector. This would be terribly impolite
|
||||
behaviour for a sun4 hosted remote gdb.
|
||||
|
||||
A fix might be to move this code into the "info registers" command.
|
||||
rich@cygnus.com 15 Sept 92. */
|
||||
i386_float_info ()
|
||||
{
|
||||
struct user u; /* just for address computations */
|
||||
int i;
|
||||
/* fpstate defined in <sys/user.h> */
|
||||
struct fpstate *fpstatep;
|
||||
char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
|
||||
unsigned int uaddr;
|
||||
char fpvalid = 0;
|
||||
unsigned int rounded_addr;
|
||||
unsigned int rounded_size;
|
||||
extern int corechan;
|
||||
int skip;
|
||||
|
||||
uaddr = (char *)&u.u_fpvalid - (char *)&u;
|
||||
if (target_has_execution)
|
||||
{
|
||||
unsigned int data;
|
||||
unsigned int mask;
|
||||
|
||||
rounded_addr = uaddr & -sizeof (int);
|
||||
data = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
|
||||
mask = 0xff << ((uaddr - rounded_addr) * 8);
|
||||
|
||||
fpvalid = ((data & mask) != 0);
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
if (lseek (corechan, uaddr, 0) < 0)
|
||||
perror ("seek on core file");
|
||||
if (myread (corechan, &fpvalid, 1) < 0)
|
||||
perror ("read on core file");
|
||||
|
||||
}
|
||||
#endif /* no core support yet */
|
||||
|
||||
if (fpvalid == 0)
|
||||
{
|
||||
printf_unfiltered ("no floating point status saved\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
|
||||
if (target_has_execution)
|
||||
{
|
||||
int *ip;
|
||||
|
||||
rounded_addr = uaddr & -sizeof (int);
|
||||
rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) +
|
||||
sizeof (int) - 1) / sizeof (int);
|
||||
skip = uaddr - rounded_addr;
|
||||
|
||||
ip = (int *)buf;
|
||||
for (i = 0; i < rounded_size; i++)
|
||||
{
|
||||
*ip++ = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) rounded_addr, 0);
|
||||
rounded_addr += sizeof (int);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
if (lseek (corechan, uaddr, 0) < 0)
|
||||
perror_with_name ("seek on core file");
|
||||
if (myread (corechan, buf, sizeof (struct fpstate)) < 0)
|
||||
perror_with_name ("read from core file");
|
||||
skip = 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
fpstatep = (struct fpstate *)(buf + skip);
|
||||
print_387_status (fpstatep->status, (struct env387 *)fpstatep->state);
|
||||
}
|
||||
|
||||
#endif /* never */
|
|
@ -1,163 +0,0 @@
|
|||
/* Native-dependent code for SVR4 Unix running on i386's, for GDB.
|
||||
Copyright 1988, 1989, 1991, 1992, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#ifdef HAVE_SYS_PROCFS_H
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* The /proc interface divides the target machine's register set up into
|
||||
two different sets, the general register set (gregset) and the floating
|
||||
point register set (fpregset). For each set, there is an ioctl to get
|
||||
the current register set and another ioctl to set the current values.
|
||||
|
||||
The actual structure passed through the ioctl interface is, of course,
|
||||
naturally machine dependent, and is different for each set of registers.
|
||||
For the i386 for example, the general register set is typically defined
|
||||
by:
|
||||
|
||||
typedef int gregset_t[19]; (in <sys/regset.h>)
|
||||
|
||||
#define GS 0 (in <sys/reg.h>)
|
||||
#define FS 1
|
||||
...
|
||||
#define UESP 17
|
||||
#define SS 18
|
||||
|
||||
and the floating point set by:
|
||||
|
||||
typedef struct fpregset
|
||||
{
|
||||
union
|
||||
{
|
||||
struct fpchip_state // fp extension state //
|
||||
{
|
||||
int state[27]; // 287/387 saved state //
|
||||
int status; // status word saved at exception //
|
||||
} fpchip_state;
|
||||
struct fp_emul_space // for emulators //
|
||||
{
|
||||
char fp_emul[246];
|
||||
char fp_epad[2];
|
||||
} fp_emul_space;
|
||||
int f_fpregs[62]; // union of the above //
|
||||
} fp_reg_set;
|
||||
long f_wregs[33]; // saved weitek state //
|
||||
} fpregset_t;
|
||||
|
||||
These routines provide the packing and unpacking of gregset_t and
|
||||
fpregset_t formatted data.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GREGSET_T
|
||||
|
||||
/* This is a duplicate of the table in i386-xdep.c. */
|
||||
|
||||
static int regmap[] =
|
||||
{
|
||||
EAX, ECX, EDX, EBX,
|
||||
UESP, EBP, ESI, EDI,
|
||||
EIP, EFL, CS, SS,
|
||||
DS, ES, FS, GS,
|
||||
};
|
||||
|
||||
|
||||
/* FIXME: These routine absolutely depends upon (NUM_REGS - NUM_FREGS)
|
||||
being less than or equal to the number of registers that can be stored
|
||||
in a gregset_t. Note that with the current scheme there will typically
|
||||
be more registers actually stored in a gregset_t that what we know
|
||||
about. This is bogus and should be fixed. */
|
||||
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
extern int regmap[];
|
||||
|
||||
for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++)
|
||||
{
|
||||
supply_register (regi, (char *) (regp + regmap[regi]));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
extern char registers[];
|
||||
extern int regmap[];
|
||||
|
||||
for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
*(regp + regmap[regi]) = *(int *) ®isters[REGISTER_BYTE (regi)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_GREGSET_T */
|
||||
|
||||
#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T)
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), unpack the register contents and supply them as gdb's
|
||||
idea of the current floating point register values. */
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
register int regi;
|
||||
|
||||
/* FIXME: see m68k-tdep.c for an example, for the m68k. */
|
||||
}
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), update the register specified by REGNO from gdb's idea
|
||||
of the current floating point register set. If REGNO is -1, update
|
||||
them all. */
|
||||
|
||||
void
|
||||
fill_fpregset (fpregsetp, regno)
|
||||
fpregset_t *fpregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
char *to;
|
||||
char *from;
|
||||
extern char registers[];
|
||||
|
||||
/* FIXME: see m68k-tdep.c for an example, for the m68k. */
|
||||
}
|
||||
|
||||
#endif /* defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) */
|
||||
|
||||
#endif /* HAVE_SYS_PROCFS_H */
|
|
@ -1,192 +0,0 @@
|
|||
/* Native support for the SGI Iris running IRIX version 4, for GDB.
|
||||
Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1995
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
|
||||
and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
|
||||
Implemented for Irix 4.x by Garrett A. Wollman.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <setjmp.h> /* For JB_XXX. */
|
||||
|
||||
/* Size of elements in jmpbuf */
|
||||
|
||||
#define JB_ELEMENT_SIZE 4
|
||||
|
||||
typedef unsigned int greg_t; /* why isn't this defined? */
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *)(gregsetp->gp_regs);
|
||||
static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
|
||||
|
||||
/* FIXME: somewhere, there should be a #define for the meaning
|
||||
of this magic number 32; we should use that. */
|
||||
for(regi = 0; regi < 32; regi++)
|
||||
supply_register (regi, (char *)(regp + regi));
|
||||
|
||||
supply_register (PC_REGNUM, (char *)&(gregsetp->gp_pc));
|
||||
supply_register (HI_REGNUM, (char *)&(gregsetp->gp_mdhi));
|
||||
supply_register (LO_REGNUM, (char *)&(gregsetp->gp_mdlo));
|
||||
supply_register (CAUSE_REGNUM, (char *)&(gregsetp->gp_cause));
|
||||
|
||||
/* Fill inaccessible registers with zero. */
|
||||
supply_register (BADVADDR_REGNUM, zerobuf);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *)(gregsetp->gp_regs);
|
||||
|
||||
/* same FIXME as above wrt 32*/
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
if ((regno == -1) || (regno == regi))
|
||||
*(regp + regi) = *(greg_t *) ®isters[REGISTER_BYTE (regi)];
|
||||
|
||||
if ((regno == -1) || (regno == PC_REGNUM))
|
||||
gregsetp->gp_pc = *(greg_t *) ®isters[REGISTER_BYTE (PC_REGNUM)];
|
||||
|
||||
if ((regno == -1) || (regno == CAUSE_REGNUM))
|
||||
gregsetp->gp_cause = *(greg_t *) ®isters[REGISTER_BYTE (CAUSE_REGNUM)];
|
||||
|
||||
if ((regno == -1) || (regno == HI_REGNUM))
|
||||
gregsetp->gp_mdhi = *(greg_t *) ®isters[REGISTER_BYTE (HI_REGNUM)];
|
||||
|
||||
if ((regno == -1) || (regno == LO_REGNUM))
|
||||
gregsetp->gp_mdlo = *(greg_t *) ®isters[REGISTER_BYTE (LO_REGNUM)];
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we do the same thing for floating-point registers.
|
||||
* We don't bother to condition on FP0_REGNUM since any
|
||||
* reasonable MIPS configuration has an R3010 in it.
|
||||
*
|
||||
* Again, see the comments in m68k-tdep.c.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
register int regi;
|
||||
static char zerobuf[MAX_REGISTER_RAW_SIZE] = {0};
|
||||
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
supply_register (FP0_REGNUM + regi,
|
||||
(char *)&fpregsetp->fp_r.fp_regs[regi]);
|
||||
|
||||
supply_register (FCRCS_REGNUM, (char *)&fpregsetp->fp_csr);
|
||||
|
||||
/* FIXME: how can we supply FCRIR_REGNUM? SGI doesn't tell us. */
|
||||
supply_register (FCRIR_REGNUM, zerobuf);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (fpregsetp, regno)
|
||||
fpregset_t *fpregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
char *from, *to;
|
||||
|
||||
for (regi = FP0_REGNUM; regi < FP0_REGNUM + 32; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
from = (char *) ®isters[REGISTER_BYTE (regi)];
|
||||
to = (char *) &(fpregsetp->fp_r.fp_regs[regi - FP0_REGNUM]);
|
||||
memcpy(to, from, REGISTER_RAW_SIZE (regi));
|
||||
}
|
||||
}
|
||||
|
||||
if ((regno == -1) || (regno == FCRCS_REGNUM))
|
||||
fpregsetp->fp_csr = *(unsigned *) ®isters[REGISTER_BYTE(FCRCS_REGNUM)];
|
||||
}
|
||||
|
||||
|
||||
/* Figure out where the longjmp will land.
|
||||
We expect the first arg to be a pointer to the jmp_buf structure from which
|
||||
we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
|
||||
This routine returns true on success. */
|
||||
|
||||
int
|
||||
get_longjmp_target (pc)
|
||||
CORE_ADDR *pc;
|
||||
{
|
||||
char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
|
||||
CORE_ADDR jb_addr;
|
||||
|
||||
jb_addr = read_register (A0_REGNUM);
|
||||
|
||||
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
|
||||
TARGET_PTR_BIT / TARGET_CHAR_BIT))
|
||||
return 0;
|
||||
|
||||
*pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which; /* Unused */
|
||||
unsigned int reg_addr; /* Unused */
|
||||
{
|
||||
if (core_reg_size != REGISTER_BYTES)
|
||||
{
|
||||
warning ("wrong size gregset struct in core file");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy ((char *)registers, core_reg_sect, core_reg_size);
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle irix4 core file formats.
|
||||
FIXME: is this really bfd_target_unknown_flavour? */
|
||||
|
||||
static struct core_fns irix4_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_irix4 ()
|
||||
{
|
||||
add_core_fns (&irix4_core_fns);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +0,0 @@
|
|||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <machine/reg.h>
|
||||
int rloc[] = {
|
||||
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, FP, SP, PS, PC
|
||||
};
|
|
@ -1,35 +0,0 @@
|
|||
/* Main loop for the standalone kernel debugger, for GDB, the GNU Debugger.
|
||||
Copyright 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
static char *args[] = {"kdb", "kdb-symbols", 0};
|
||||
|
||||
static char *environment[] = {0};
|
||||
|
||||
char **environ;
|
||||
|
||||
start ()
|
||||
{
|
||||
INIT_STACK (kdb_stack_beg, kdb_stack_end);
|
||||
|
||||
environ = environment;
|
||||
|
||||
main (2, args, environment);
|
||||
}
|
|
@ -1,838 +0,0 @@
|
|||
/* Native-dependent code for LynxOS.
|
||||
Copyright 1993, 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/fpp.h>
|
||||
|
||||
static unsigned long registers_addr PARAMS ((int pid));
|
||||
|
||||
#define X(ENTRY)(offsetof(struct econtext, ENTRY))
|
||||
|
||||
#ifdef I386
|
||||
/* Mappings from tm-i386v.h */
|
||||
|
||||
static int regmap[] =
|
||||
{
|
||||
X(eax),
|
||||
X(ecx),
|
||||
X(edx),
|
||||
X(ebx),
|
||||
X(esp), /* sp */
|
||||
X(ebp), /* fp */
|
||||
X(esi),
|
||||
X(edi),
|
||||
X(eip), /* pc */
|
||||
X(flags), /* ps */
|
||||
X(cs),
|
||||
X(ss),
|
||||
X(ds),
|
||||
X(es),
|
||||
X(ecode), /* Lynx doesn't give us either fs or gs, so */
|
||||
X(fault), /* we just substitute these two in the hopes
|
||||
that they are useful. */
|
||||
};
|
||||
#endif /* I386 */
|
||||
|
||||
#ifdef M68K
|
||||
/* Mappings from tm-m68k.h */
|
||||
|
||||
static int regmap[] =
|
||||
{
|
||||
X(regs[0]), /* d0 */
|
||||
X(regs[1]), /* d1 */
|
||||
X(regs[2]), /* d2 */
|
||||
X(regs[3]), /* d3 */
|
||||
X(regs[4]), /* d4 */
|
||||
X(regs[5]), /* d5 */
|
||||
X(regs[6]), /* d6 */
|
||||
X(regs[7]), /* d7 */
|
||||
X(regs[8]), /* a0 */
|
||||
X(regs[9]), /* a1 */
|
||||
X(regs[10]), /* a2 */
|
||||
X(regs[11]), /* a3 */
|
||||
X(regs[12]), /* a4 */
|
||||
X(regs[13]), /* a5 */
|
||||
X(regs[14]), /* fp */
|
||||
offsetof (st_t, usp) - offsetof (st_t, ec), /* sp */
|
||||
X(status), /* ps */
|
||||
X(pc),
|
||||
|
||||
X(fregs[0*3]), /* fp0 */
|
||||
X(fregs[1*3]), /* fp1 */
|
||||
X(fregs[2*3]), /* fp2 */
|
||||
X(fregs[3*3]), /* fp3 */
|
||||
X(fregs[4*3]), /* fp4 */
|
||||
X(fregs[5*3]), /* fp5 */
|
||||
X(fregs[6*3]), /* fp6 */
|
||||
X(fregs[7*3]), /* fp7 */
|
||||
|
||||
X(fcregs[0]), /* fpcontrol */
|
||||
X(fcregs[1]), /* fpstatus */
|
||||
X(fcregs[2]), /* fpiaddr */
|
||||
X(ssw), /* fpcode */
|
||||
X(fault), /* fpflags */
|
||||
};
|
||||
#endif /* M68K */
|
||||
|
||||
#ifdef SPARC
|
||||
/* Mappings from tm-sparc.h */
|
||||
|
||||
#define FX(ENTRY)(offsetof(struct fcontext, ENTRY))
|
||||
|
||||
static int regmap[] =
|
||||
{
|
||||
-1, /* g0 */
|
||||
X(g1),
|
||||
X(g2),
|
||||
X(g3),
|
||||
X(g4),
|
||||
-1, /* g5->g7 aren't saved by Lynx */
|
||||
-1,
|
||||
-1,
|
||||
|
||||
X(o[0]),
|
||||
X(o[1]),
|
||||
X(o[2]),
|
||||
X(o[3]),
|
||||
X(o[4]),
|
||||
X(o[5]),
|
||||
X(o[6]), /* sp */
|
||||
X(o[7]), /* ra */
|
||||
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, /* l0 -> l7 */
|
||||
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, /* i0 -> i7 */
|
||||
|
||||
FX(f.fregs[0]), /* f0 */
|
||||
FX(f.fregs[1]),
|
||||
FX(f.fregs[2]),
|
||||
FX(f.fregs[3]),
|
||||
FX(f.fregs[4]),
|
||||
FX(f.fregs[5]),
|
||||
FX(f.fregs[6]),
|
||||
FX(f.fregs[7]),
|
||||
FX(f.fregs[8]),
|
||||
FX(f.fregs[9]),
|
||||
FX(f.fregs[10]),
|
||||
FX(f.fregs[11]),
|
||||
FX(f.fregs[12]),
|
||||
FX(f.fregs[13]),
|
||||
FX(f.fregs[14]),
|
||||
FX(f.fregs[15]),
|
||||
FX(f.fregs[16]),
|
||||
FX(f.fregs[17]),
|
||||
FX(f.fregs[18]),
|
||||
FX(f.fregs[19]),
|
||||
FX(f.fregs[20]),
|
||||
FX(f.fregs[21]),
|
||||
FX(f.fregs[22]),
|
||||
FX(f.fregs[23]),
|
||||
FX(f.fregs[24]),
|
||||
FX(f.fregs[25]),
|
||||
FX(f.fregs[26]),
|
||||
FX(f.fregs[27]),
|
||||
FX(f.fregs[28]),
|
||||
FX(f.fregs[29]),
|
||||
FX(f.fregs[30]),
|
||||
FX(f.fregs[31]),
|
||||
|
||||
X(y),
|
||||
X(psr),
|
||||
X(wim),
|
||||
X(tbr),
|
||||
X(pc),
|
||||
X(npc),
|
||||
FX(fsr), /* fpsr */
|
||||
-1, /* cpsr */
|
||||
};
|
||||
#endif /* SPARC */
|
||||
|
||||
#ifdef rs6000
|
||||
|
||||
static int regmap[] =
|
||||
{
|
||||
X(iregs[0]), /* r0 */
|
||||
X(iregs[1]),
|
||||
X(iregs[2]),
|
||||
X(iregs[3]),
|
||||
X(iregs[4]),
|
||||
X(iregs[5]),
|
||||
X(iregs[6]),
|
||||
X(iregs[7]),
|
||||
X(iregs[8]),
|
||||
X(iregs[9]),
|
||||
X(iregs[10]),
|
||||
X(iregs[11]),
|
||||
X(iregs[12]),
|
||||
X(iregs[13]),
|
||||
X(iregs[14]),
|
||||
X(iregs[15]),
|
||||
X(iregs[16]),
|
||||
X(iregs[17]),
|
||||
X(iregs[18]),
|
||||
X(iregs[19]),
|
||||
X(iregs[20]),
|
||||
X(iregs[21]),
|
||||
X(iregs[22]),
|
||||
X(iregs[23]),
|
||||
X(iregs[24]),
|
||||
X(iregs[25]),
|
||||
X(iregs[26]),
|
||||
X(iregs[27]),
|
||||
X(iregs[28]),
|
||||
X(iregs[29]),
|
||||
X(iregs[30]),
|
||||
X(iregs[31]),
|
||||
|
||||
X(fregs[0]), /* f0 */
|
||||
X(fregs[1]),
|
||||
X(fregs[2]),
|
||||
X(fregs[3]),
|
||||
X(fregs[4]),
|
||||
X(fregs[5]),
|
||||
X(fregs[6]),
|
||||
X(fregs[7]),
|
||||
X(fregs[8]),
|
||||
X(fregs[9]),
|
||||
X(fregs[10]),
|
||||
X(fregs[11]),
|
||||
X(fregs[12]),
|
||||
X(fregs[13]),
|
||||
X(fregs[14]),
|
||||
X(fregs[15]),
|
||||
X(fregs[16]),
|
||||
X(fregs[17]),
|
||||
X(fregs[18]),
|
||||
X(fregs[19]),
|
||||
X(fregs[20]),
|
||||
X(fregs[21]),
|
||||
X(fregs[22]),
|
||||
X(fregs[23]),
|
||||
X(fregs[24]),
|
||||
X(fregs[25]),
|
||||
X(fregs[26]),
|
||||
X(fregs[27]),
|
||||
X(fregs[28]),
|
||||
X(fregs[29]),
|
||||
X(fregs[30]),
|
||||
X(fregs[31]),
|
||||
|
||||
X(srr0), /* IAR (PC) */
|
||||
X(srr1), /* MSR (PS) */
|
||||
X(cr), /* CR */
|
||||
X(lr), /* LR */
|
||||
X(ctr), /* CTR */
|
||||
X(xer), /* XER */
|
||||
X(mq) /* MQ */
|
||||
};
|
||||
|
||||
#endif /* rs6000 */
|
||||
|
||||
#ifdef SPARC
|
||||
|
||||
/* This routine handles some oddball cases for Sparc registers and LynxOS.
|
||||
In partucular, it causes refs to G0, g5->7, and all fp regs to return zero.
|
||||
It also handles knows where to find the I & L regs on the stack. */
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
int whatregs = 0;
|
||||
|
||||
#define WHATREGS_FLOAT 1
|
||||
#define WHATREGS_GEN 2
|
||||
#define WHATREGS_STACK 4
|
||||
|
||||
if (regno == -1)
|
||||
whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK;
|
||||
else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
|
||||
whatregs = WHATREGS_STACK;
|
||||
else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
|
||||
whatregs = WHATREGS_FLOAT;
|
||||
else
|
||||
whatregs = WHATREGS_GEN;
|
||||
|
||||
if (whatregs & WHATREGS_GEN)
|
||||
{
|
||||
struct econtext ec; /* general regs */
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
errno = 0;
|
||||
retval = ptrace (PTRACE_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &ec,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_GETREGS)");
|
||||
|
||||
memset (buf, 0, REGISTER_RAW_SIZE (G0_REGNUM));
|
||||
supply_register (G0_REGNUM, buf);
|
||||
supply_register (TBR_REGNUM, (char *)&ec.tbr);
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (G1_REGNUM)], &ec.g1,
|
||||
4 * REGISTER_RAW_SIZE (G1_REGNUM));
|
||||
for (i = G1_REGNUM; i <= G1_REGNUM + 3; i++)
|
||||
register_valid[i] = 1;
|
||||
|
||||
supply_register (PS_REGNUM, (char *)&ec.psr);
|
||||
supply_register (Y_REGNUM, (char *)&ec.y);
|
||||
supply_register (PC_REGNUM, (char *)&ec.pc);
|
||||
supply_register (NPC_REGNUM, (char *)&ec.npc);
|
||||
supply_register (WIM_REGNUM, (char *)&ec.wim);
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (O0_REGNUM)], ec.o,
|
||||
8 * REGISTER_RAW_SIZE (O0_REGNUM));
|
||||
for (i = O0_REGNUM; i <= O0_REGNUM + 7; i++)
|
||||
register_valid[i] = 1;
|
||||
}
|
||||
|
||||
if (whatregs & WHATREGS_STACK)
|
||||
{
|
||||
CORE_ADDR sp;
|
||||
int i;
|
||||
|
||||
sp = read_register (SP_REGNUM);
|
||||
|
||||
target_xfer_memory (sp + FRAME_SAVED_I0,
|
||||
®isters[REGISTER_BYTE(I0_REGNUM)],
|
||||
8 * REGISTER_RAW_SIZE (I0_REGNUM), 0);
|
||||
for (i = I0_REGNUM; i <= I7_REGNUM; i++)
|
||||
register_valid[i] = 1;
|
||||
|
||||
target_xfer_memory (sp + FRAME_SAVED_L0,
|
||||
®isters[REGISTER_BYTE(L0_REGNUM)],
|
||||
8 * REGISTER_RAW_SIZE (L0_REGNUM), 0);
|
||||
for (i = L0_REGNUM; i <= L0_REGNUM + 7; i++)
|
||||
register_valid[i] = 1;
|
||||
}
|
||||
|
||||
if (whatregs & WHATREGS_FLOAT)
|
||||
{
|
||||
struct fcontext fc; /* fp regs */
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
errno = 0;
|
||||
retval = ptrace (PTRACE_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_GETFPREGS)");
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], fc.f.fregs,
|
||||
32 * REGISTER_RAW_SIZE (FP0_REGNUM));
|
||||
for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
|
||||
register_valid[i] = 1;
|
||||
|
||||
supply_register (FPS_REGNUM, (char *)&fc.fsr);
|
||||
}
|
||||
}
|
||||
|
||||
/* This routine handles storing of the I & L regs for the Sparc. The trick
|
||||
here is that they actually live on the stack. The really tricky part is
|
||||
that when changing the stack pointer, the I & L regs must be written to
|
||||
where the new SP points, otherwise the regs will be incorrect when the
|
||||
process is started up again. We assume that the I & L regs are valid at
|
||||
this point. */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
int whatregs = 0;
|
||||
|
||||
if (regno == -1)
|
||||
whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK;
|
||||
else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
|
||||
whatregs = WHATREGS_STACK;
|
||||
else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
|
||||
whatregs = WHATREGS_FLOAT;
|
||||
else if (regno == SP_REGNUM)
|
||||
whatregs = WHATREGS_STACK | WHATREGS_GEN;
|
||||
else
|
||||
whatregs = WHATREGS_GEN;
|
||||
|
||||
if (whatregs & WHATREGS_GEN)
|
||||
{
|
||||
struct econtext ec; /* general regs */
|
||||
int retval;
|
||||
|
||||
ec.tbr = read_register (TBR_REGNUM);
|
||||
memcpy (&ec.g1, ®isters[REGISTER_BYTE (G1_REGNUM)],
|
||||
4 * REGISTER_RAW_SIZE (G1_REGNUM));
|
||||
|
||||
ec.psr = read_register (PS_REGNUM);
|
||||
ec.y = read_register (Y_REGNUM);
|
||||
ec.pc = read_register (PC_REGNUM);
|
||||
ec.npc = read_register (NPC_REGNUM);
|
||||
ec.wim = read_register (WIM_REGNUM);
|
||||
|
||||
memcpy (ec.o, ®isters[REGISTER_BYTE (O0_REGNUM)],
|
||||
8 * REGISTER_RAW_SIZE (O0_REGNUM));
|
||||
|
||||
errno = 0;
|
||||
retval = ptrace (PTRACE_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) &ec,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_SETREGS)");
|
||||
}
|
||||
|
||||
if (whatregs & WHATREGS_STACK)
|
||||
{
|
||||
int regoffset;
|
||||
CORE_ADDR sp;
|
||||
|
||||
sp = read_register (SP_REGNUM);
|
||||
|
||||
if (regno == -1 || regno == SP_REGNUM)
|
||||
{
|
||||
if (!register_valid[L0_REGNUM+5])
|
||||
abort();
|
||||
target_xfer_memory (sp + FRAME_SAVED_I0,
|
||||
®isters[REGISTER_BYTE (I0_REGNUM)],
|
||||
8 * REGISTER_RAW_SIZE (I0_REGNUM), 1);
|
||||
|
||||
target_xfer_memory (sp + FRAME_SAVED_L0,
|
||||
®isters[REGISTER_BYTE (L0_REGNUM)],
|
||||
8 * REGISTER_RAW_SIZE (L0_REGNUM), 1);
|
||||
}
|
||||
else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
|
||||
{
|
||||
if (!register_valid[regno])
|
||||
abort();
|
||||
if (regno >= L0_REGNUM && regno <= L0_REGNUM + 7)
|
||||
regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM)
|
||||
+ FRAME_SAVED_L0;
|
||||
else
|
||||
regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (I0_REGNUM)
|
||||
+ FRAME_SAVED_I0;
|
||||
target_xfer_memory (sp + regoffset, ®isters[REGISTER_BYTE (regno)],
|
||||
REGISTER_RAW_SIZE (regno), 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (whatregs & WHATREGS_FLOAT)
|
||||
{
|
||||
struct fcontext fc; /* fp regs */
|
||||
int retval;
|
||||
|
||||
/* We read fcontext first so that we can get good values for fq_t... */
|
||||
errno = 0;
|
||||
retval = ptrace (PTRACE_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_GETFPREGS)");
|
||||
|
||||
memcpy (fc.f.fregs, ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
32 * REGISTER_RAW_SIZE (FP0_REGNUM));
|
||||
|
||||
fc.fsr = read_register (FPS_REGNUM);
|
||||
|
||||
errno = 0;
|
||||
retval = ptrace (PTRACE_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) &fc,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_SETFPREGS)");
|
||||
}
|
||||
}
|
||||
#endif /* SPARC */
|
||||
|
||||
#if defined (I386) || defined (M68K) || defined (rs6000)
|
||||
|
||||
/* Return the offset relative to the start of the per-thread data to the
|
||||
saved context block. */
|
||||
|
||||
static unsigned long
|
||||
registers_addr(pid)
|
||||
int pid;
|
||||
{
|
||||
CORE_ADDR stblock;
|
||||
int ecpoff = offsetof(st_t, ecp);
|
||||
CORE_ADDR ecp;
|
||||
|
||||
errno = 0;
|
||||
stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, pid, (PTRACE_ARG3_TYPE)0,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_THREADUSER)");
|
||||
|
||||
ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, pid, (PTRACE_ARG3_TYPE)ecpoff,
|
||||
0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_PEEKTHREAD)");
|
||||
|
||||
return ecp - stblock;
|
||||
}
|
||||
|
||||
/* Fetch one or more registers from the inferior. REGNO == -1 to get
|
||||
them all. We actually fetch more than requested, when convenient,
|
||||
marking them as valid so we won't fetch them again. */
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
int reglo, reghi;
|
||||
int i;
|
||||
unsigned long ecp;
|
||||
|
||||
if (regno == -1)
|
||||
{
|
||||
reglo = 0;
|
||||
reghi = NUM_REGS - 1;
|
||||
}
|
||||
else
|
||||
reglo = reghi = regno;
|
||||
|
||||
ecp = registers_addr (inferior_pid);
|
||||
|
||||
for (regno = reglo; regno <= reghi; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int ptrace_fun = PTRACE_PEEKTHREAD;
|
||||
|
||||
#ifdef M68K
|
||||
ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
errno = 0;
|
||||
reg = ptrace (ptrace_fun, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), 0);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_PEEKUSP)");
|
||||
|
||||
*(int *)&buf[i] = reg;
|
||||
}
|
||||
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). */
|
||||
|
||||
/* Registers we shouldn't try to store. */
|
||||
#if !defined (CANNOT_STORE_REGISTER)
|
||||
#define CANNOT_STORE_REGISTER(regno) 0
|
||||
#endif
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
int reglo, reghi;
|
||||
int i;
|
||||
unsigned long ecp;
|
||||
|
||||
if (regno == -1)
|
||||
{
|
||||
reglo = 0;
|
||||
reghi = NUM_REGS - 1;
|
||||
}
|
||||
else
|
||||
reglo = reghi = regno;
|
||||
|
||||
ecp = registers_addr (inferior_pid);
|
||||
|
||||
for (regno = reglo; regno <= reghi; regno++)
|
||||
{
|
||||
int ptrace_fun = PTRACE_POKEUSER;
|
||||
|
||||
if (CANNOT_STORE_REGISTER (regno))
|
||||
continue;
|
||||
|
||||
#ifdef M68K
|
||||
ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = *(unsigned int *)®isters[REGISTER_BYTE (regno) + i];
|
||||
|
||||
errno = 0;
|
||||
ptrace (ptrace_fun, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), reg);
|
||||
if (errno)
|
||||
perror_with_name ("ptrace(PTRACE_POKEUSP)");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined (I386) || defined (M68K) || defined (rs6000) */
|
||||
|
||||
/* Wait for child to do something. Return pid of child, or -1 in case
|
||||
of error; store status through argument pointer OURSTATUS. */
|
||||
|
||||
int
|
||||
child_wait (pid, ourstatus)
|
||||
int pid;
|
||||
struct target_waitstatus *ourstatus;
|
||||
{
|
||||
int save_errno;
|
||||
int thread;
|
||||
union wait status;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int sig;
|
||||
|
||||
set_sigint_trap(); /* Causes SIGINT to be passed on to the
|
||||
attached process. */
|
||||
pid = wait (&status);
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
clear_sigint_trap();
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
if (save_errno == EINTR)
|
||||
continue;
|
||||
fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
|
||||
safe_strerror (save_errno));
|
||||
/* Claim it exited with unknown signal. */
|
||||
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
|
||||
ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid != PIDGET (inferior_pid)) /* Some other process?!? */
|
||||
continue;
|
||||
|
||||
thread = status.w_tid; /* Get thread id from status */
|
||||
|
||||
/* Initial thread value can only be acquired via wait, so we have to
|
||||
resort to this hack. */
|
||||
|
||||
if (TIDGET (inferior_pid) == 0 && thread != 0)
|
||||
{
|
||||
inferior_pid = BUILDPID (inferior_pid, thread);
|
||||
add_thread (inferior_pid);
|
||||
}
|
||||
|
||||
pid = BUILDPID (pid, thread);
|
||||
|
||||
/* We've become a single threaded process again. */
|
||||
if (thread == 0)
|
||||
inferior_pid = pid;
|
||||
|
||||
/* Check for thread creation. */
|
||||
if (WIFSTOPPED(status)
|
||||
&& WSTOPSIG(status) == SIGTRAP
|
||||
&& !in_thread_list (pid))
|
||||
{
|
||||
int realsig;
|
||||
|
||||
realsig = ptrace (PTRACE_GETTRACESIG, pid, (PTRACE_ARG3_TYPE)0, 0);
|
||||
|
||||
if (realsig == SIGNEWTHREAD)
|
||||
{
|
||||
/* It's a new thread notification. Nothing to do here since
|
||||
the machine independent code in wait_for_inferior will
|
||||
add the thread to the thread list and restart the thread
|
||||
when pid != inferior_pid and pid is not in the thread
|
||||
list. We don't even want to much with realsig -- the
|
||||
code in wait_for_inferior expects SIGTRAP. */
|
||||
;
|
||||
}
|
||||
else
|
||||
error ("Signal for unknown thread was not SIGNEWTHREAD");
|
||||
}
|
||||
|
||||
/* Check for thread termination. */
|
||||
else if (WIFSTOPPED(status)
|
||||
&& WSTOPSIG(status) == SIGTRAP
|
||||
&& in_thread_list (pid))
|
||||
{
|
||||
int realsig;
|
||||
|
||||
realsig = ptrace (PTRACE_GETTRACESIG, pid, (PTRACE_ARG3_TYPE)0, 0);
|
||||
|
||||
if (realsig == SIGTHREADEXIT)
|
||||
{
|
||||
ptrace (PTRACE_CONT, PIDGET (pid), (PTRACE_ARG3_TYPE)0, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SPARC
|
||||
/* SPARC Lynx uses an byte reversed wait status; we must use the
|
||||
host macros to access it. These lines just a copy of
|
||||
store_waitstatus. We can't use CHILD_SPECIAL_WAITSTATUS
|
||||
because target.c can't include the Lynx <sys/wait.h>. */
|
||||
if (WIFEXITED (status))
|
||||
{
|
||||
ourstatus->kind = TARGET_WAITKIND_EXITED;
|
||||
ourstatus->value.integer = WEXITSTATUS (status);
|
||||
}
|
||||
else if (!WIFSTOPPED (status))
|
||||
{
|
||||
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
|
||||
ourstatus->value.sig =
|
||||
target_signal_from_host (WTERMSIG (status));
|
||||
}
|
||||
else
|
||||
{
|
||||
ourstatus->kind = TARGET_WAITKIND_STOPPED;
|
||||
ourstatus->value.sig =
|
||||
target_signal_from_host (WSTOPSIG (status));
|
||||
}
|
||||
#else
|
||||
store_waitstatus (ourstatus, status.w_status);
|
||||
#endif
|
||||
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if the given thread is still alive. */
|
||||
int
|
||||
child_thread_alive (pid)
|
||||
int pid;
|
||||
{
|
||||
/* Arggh. Apparently pthread_kill only works for threads within
|
||||
the process that calls pthread_kill.
|
||||
|
||||
We want to avoid the lynx signal extensions as they simply don't
|
||||
map well to the generic gdb interface we want to keep.
|
||||
|
||||
All we want to do is determine if a particular thread is alive;
|
||||
it appears as if we can just make a harmless thread specific
|
||||
ptrace call to do that. */
|
||||
return (ptrace (PTRACE_THREADUSER, pid, 0, 0) != -1);
|
||||
}
|
||||
|
||||
/* Resume execution of the inferior process.
|
||||
If STEP is nonzero, single-step it.
|
||||
If SIGNAL is nonzero, give it that signal. */
|
||||
|
||||
void
|
||||
child_resume (pid, step, signal)
|
||||
int pid;
|
||||
int step;
|
||||
enum target_signal signal;
|
||||
{
|
||||
int func;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* If pid == -1, then we want to step/continue all threads, else
|
||||
we only want to step/continue a single thread. */
|
||||
if (pid == -1)
|
||||
{
|
||||
pid = inferior_pid;
|
||||
func = step ? PTRACE_SINGLESTEP : PTRACE_CONT;
|
||||
}
|
||||
else
|
||||
func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT_ONE;
|
||||
|
||||
|
||||
/* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
|
||||
it was. (If GDB wanted it to start some other way, we have already
|
||||
written a new PC value to the child.)
|
||||
|
||||
If this system does not support PT_STEP, a higher level function will
|
||||
have called single_step() to transmute the step request into a
|
||||
continue request (by setting breakpoints on all possible successor
|
||||
instructions), so we don't have to worry about that here. */
|
||||
|
||||
ptrace (func, pid, (PTRACE_ARG3_TYPE) 1, target_signal_to_host (signal));
|
||||
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
|
||||
/* Convert a Lynx process ID to a string. Returns the string in a static
|
||||
buffer. */
|
||||
|
||||
char *
|
||||
lynx_pid_to_str (pid)
|
||||
int pid;
|
||||
{
|
||||
static char buf[40];
|
||||
|
||||
sprintf (buf, "process %d thread %d", PIDGET (pid), TIDGET (pid));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Extract the register values out of the core file and store
|
||||
them where `read_register' will find them.
|
||||
|
||||
CORE_REG_SECT points to the register values themselves, read into memory.
|
||||
CORE_REG_SIZE is the size of that area.
|
||||
WHICH says which set of registers we are handling (0 = int, 2 = float
|
||||
on machines where they are discontiguous).
|
||||
REG_ADDR is the offset from u.u_ar0 to the register values relative to
|
||||
core_reg_sect. This is used with old-fashioned core files to
|
||||
locate the registers in a large upage-plus-stack ".reg" section.
|
||||
Original upage address X is at location core_reg_sect+x+reg_addr.
|
||||
*/
|
||||
|
||||
static void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned reg_addr;
|
||||
{
|
||||
struct st_entry s;
|
||||
unsigned int regno;
|
||||
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
if (regmap[regno] != -1)
|
||||
supply_register (regno, core_reg_sect + offsetof (st_t, ec)
|
||||
+ regmap[regno]);
|
||||
|
||||
#ifdef SPARC
|
||||
/* Fetching this register causes all of the I & L regs to be read from the
|
||||
stack and validated. */
|
||||
|
||||
fetch_inferior_registers (I0_REGNUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Register that we are able to handle lynx core file formats.
|
||||
FIXME: is this really bfd_target_unknown_flavour? */
|
||||
|
||||
static struct core_fns lynx_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour,
|
||||
fetch_core_registers,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_lynx ()
|
||||
{
|
||||
add_core_fns (&lynx_core_fns);
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,514 +0,0 @@
|
|||
/* Target dependent code for the Motorola 68000 series.
|
||||
Copyright (C) 1990, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "symtab.h"
|
||||
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
void
|
||||
m68k_push_dummy_frame ()
|
||||
{
|
||||
register CORE_ADDR sp = read_register (SP_REGNUM);
|
||||
register int regnum;
|
||||
char raw_buffer[12];
|
||||
|
||||
sp = push_word (sp, read_register (PC_REGNUM));
|
||||
sp = push_word (sp, read_register (FP_REGNUM));
|
||||
write_register (FP_REGNUM, sp);
|
||||
|
||||
/* Always save the floating-point registers, whether they exist on
|
||||
this target or not. */
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--)
|
||||
{
|
||||
read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12);
|
||||
sp = push_bytes (sp, raw_buffer, 12);
|
||||
}
|
||||
|
||||
for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--)
|
||||
{
|
||||
sp = push_word (sp, read_register (regnum));
|
||||
}
|
||||
sp = push_word (sp, read_register (PS_REGNUM));
|
||||
write_register (SP_REGNUM, sp);
|
||||
}
|
||||
|
||||
/* Discard from the stack the innermost frame,
|
||||
restoring all saved registers. */
|
||||
|
||||
void
|
||||
m68k_pop_frame ()
|
||||
{
|
||||
register struct frame_info *frame = get_current_frame ();
|
||||
register CORE_ADDR fp;
|
||||
register int regnum;
|
||||
struct frame_saved_regs fsr;
|
||||
struct frame_info *fi;
|
||||
char raw_buffer[12];
|
||||
|
||||
fp = FRAME_FP (frame);
|
||||
get_frame_saved_regs (frame, &fsr);
|
||||
for (regnum = FP0_REGNUM + 7 ; regnum >= FP0_REGNUM ; regnum--)
|
||||
{
|
||||
if (fsr.regs[regnum])
|
||||
{
|
||||
read_memory (fsr.regs[regnum], raw_buffer, 12);
|
||||
write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12);
|
||||
}
|
||||
}
|
||||
for (regnum = FP_REGNUM - 1 ; regnum >= 0 ; regnum--)
|
||||
{
|
||||
if (fsr.regs[regnum])
|
||||
{
|
||||
write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
|
||||
}
|
||||
}
|
||||
if (fsr.regs[PS_REGNUM])
|
||||
{
|
||||
write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4));
|
||||
}
|
||||
write_register (FP_REGNUM, read_memory_integer (fp, 4));
|
||||
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
|
||||
write_register (SP_REGNUM, fp + 8);
|
||||
flush_cached_frames ();
|
||||
}
|
||||
|
||||
|
||||
/* Given an ip value corresponding to the start of a function,
|
||||
return the ip of the first instruction after the function
|
||||
prologue. This is the generic m68k support. Machines which
|
||||
require something different can override the SKIP_PROLOGUE
|
||||
macro to point elsewhere.
|
||||
|
||||
Some instructions which typically may appear in a function
|
||||
prologue include:
|
||||
|
||||
A link instruction, word form:
|
||||
|
||||
link.w %a6,&0 4e56 XXXX
|
||||
|
||||
A link instruction, long form:
|
||||
|
||||
link.l %fp,&F%1 480e XXXX XXXX
|
||||
|
||||
A movm instruction to preserve integer regs:
|
||||
|
||||
movm.l &M%1,(4,%sp) 48ef XXXX XXXX
|
||||
|
||||
A fmovm instruction to preserve float regs:
|
||||
|
||||
fmovm &FPM%1,(FPO%1,%sp) f237 XXXX XXXX XXXX XXXX
|
||||
|
||||
Some profiling setup code (FIXME, not recognized yet):
|
||||
|
||||
lea.l (.L3,%pc),%a1 43fb XXXX XXXX XXXX
|
||||
bsr _mcount 61ff XXXX XXXX
|
||||
|
||||
*/
|
||||
|
||||
#define P_LINK_L 0x480e
|
||||
#define P_LINK_W 0x4e56
|
||||
#define P_MOV_L 0x207c
|
||||
#define P_JSR 0x4eb9
|
||||
#define P_BSR 0x61ff
|
||||
#define P_LEA_L 0x43fb
|
||||
#define P_MOVM_L 0x48ef
|
||||
#define P_FMOVM 0xf237
|
||||
#define P_TRAP 0x4e40
|
||||
|
||||
CORE_ADDR
|
||||
m68k_skip_prologue (ip)
|
||||
CORE_ADDR ip;
|
||||
{
|
||||
register CORE_ADDR limit;
|
||||
struct symtab_and_line sal;
|
||||
register int op;
|
||||
|
||||
/* Find out if there is a known limit for the extent of the prologue.
|
||||
If so, ensure we don't go past it. If not, assume "infinity". */
|
||||
|
||||
sal = find_pc_line (ip, 0);
|
||||
limit = (sal.end) ? sal.end : (CORE_ADDR) ~0;
|
||||
|
||||
while (ip < limit)
|
||||
{
|
||||
op = read_memory_integer (ip, 2);
|
||||
op &= 0xFFFF;
|
||||
|
||||
if (op == P_LINK_W)
|
||||
{
|
||||
ip += 4; /* Skip link.w */
|
||||
}
|
||||
else if (op == 0x4856)
|
||||
ip += 2; /* Skip pea %fp */
|
||||
else if (op == 0x2c4f)
|
||||
ip += 2; /* Skip move.l %sp, %fp */
|
||||
else if (op == P_LINK_L)
|
||||
{
|
||||
ip += 6; /* Skip link.l */
|
||||
}
|
||||
else if (op == P_MOVM_L)
|
||||
{
|
||||
ip += 6; /* Skip movm.l */
|
||||
}
|
||||
else if (op == P_FMOVM)
|
||||
{
|
||||
ip += 10; /* Skip fmovm */
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* Found unknown code, bail out. */
|
||||
}
|
||||
}
|
||||
return (ip);
|
||||
}
|
||||
|
||||
void
|
||||
m68k_find_saved_regs (frame_info, saved_regs)
|
||||
struct frame_info *frame_info;
|
||||
struct frame_saved_regs *saved_regs;
|
||||
{
|
||||
register int regnum;
|
||||
register int regmask;
|
||||
register CORE_ADDR next_addr;
|
||||
register CORE_ADDR pc;
|
||||
|
||||
/* First possible address for a pc in a call dummy for this frame. */
|
||||
CORE_ADDR possible_call_dummy_start =
|
||||
(frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 - 8*12;
|
||||
|
||||
int nextinsn;
|
||||
memset (saved_regs, 0, sizeof (*saved_regs));
|
||||
if ((frame_info)->pc >= possible_call_dummy_start
|
||||
&& (frame_info)->pc <= (frame_info)->frame)
|
||||
{
|
||||
|
||||
/* It is a call dummy. We could just stop now, since we know
|
||||
what the call dummy saves and where. But this code proceeds
|
||||
to parse the "prologue" which is part of the call dummy.
|
||||
This is needlessly complex and confusing. FIXME. */
|
||||
|
||||
next_addr = (frame_info)->frame;
|
||||
pc = possible_call_dummy_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = get_pc_function_start ((frame_info)->pc);
|
||||
|
||||
if (0x4856 == read_memory_integer (pc, 2)
|
||||
&& 0x2c4f == read_memory_integer (pc + 2, 2))
|
||||
{
|
||||
/*
|
||||
pea %fp
|
||||
move.l %sp, %fp */
|
||||
|
||||
pc += 4;
|
||||
next_addr = frame_info->frame;
|
||||
}
|
||||
else if (044016 == read_memory_integer (pc, 2))
|
||||
/* link.l %fp */
|
||||
/* Find the address above the saved
|
||||
regs using the amount of storage from the link instruction. */
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 4), pc+=4;
|
||||
else if (047126 == read_memory_integer (pc, 2))
|
||||
/* link.w %fp */
|
||||
/* Find the address above the saved
|
||||
regs using the amount of storage from the link instruction. */
|
||||
next_addr = (frame_info)->frame + read_memory_integer (pc += 2, 2), pc+=2;
|
||||
else goto lose;
|
||||
|
||||
/* If have an addal #-n, sp next, adjust next_addr. */
|
||||
if ((0177777 & read_memory_integer (pc, 2)) == 0157774)
|
||||
next_addr += read_memory_integer (pc += 2, 4), pc += 4;
|
||||
}
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
|
||||
/* Here can come an fmovem. Check for it. */
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf227 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xe000)
|
||||
{ pc += 4; /* Regmask's low bit is for register fp7, the first pushed */
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
saved_regs->regs[regnum] = (next_addr -= 12);
|
||||
regmask = read_memory_integer (pc + 2, 2); }
|
||||
|
||||
/* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */
|
||||
if (0044327 == read_memory_integer (pc, 2))
|
||||
{ pc += 4; /* Regmask's low bit is for register 0, the first written */
|
||||
for (regnum = 0; regnum < 16; regnum++, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
saved_regs->regs[regnum] = (next_addr += 4) - 4; }
|
||||
else if (0044347 == read_memory_integer (pc, 2))
|
||||
{
|
||||
pc += 4; /* Regmask's low bit is for register 15, the first pushed */
|
||||
for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
saved_regs->regs[regnum] = (next_addr -= 4);
|
||||
}
|
||||
else if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2)))
|
||||
{
|
||||
regnum = 0xf & read_memory_integer (pc, 2); pc += 2;
|
||||
saved_regs->regs[regnum] = (next_addr -= 4);
|
||||
/* gcc, at least, may use a pair of movel instructions when saving
|
||||
exactly 2 registers. */
|
||||
if (0x2f00 == (0xfff0 & read_memory_integer (pc, 2)))
|
||||
{
|
||||
regnum = 0xf & read_memory_integer (pc, 2);
|
||||
pc += 2;
|
||||
saved_regs->regs[regnum] = (next_addr -= 4);
|
||||
}
|
||||
}
|
||||
|
||||
/* fmovemx to index of sp may follow. */
|
||||
regmask = read_memory_integer (pc + 2, 2);
|
||||
nextinsn = 0xffff & read_memory_integer (pc, 2);
|
||||
if (0xf236 == nextinsn
|
||||
&& (regmask & 0xff00) == 0xf000)
|
||||
{ pc += 10; /* Regmask's low bit is for register fp0, the first written */
|
||||
for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1)
|
||||
if (regmask & 1)
|
||||
saved_regs->regs[regnum] = (next_addr += 12) - 12;
|
||||
regmask = read_memory_integer (pc + 2, 2); }
|
||||
|
||||
/* clrw -(sp); movw ccr,-(sp) may follow. */
|
||||
if (0x426742e7 == read_memory_integer (pc, 4))
|
||||
saved_regs->regs[PS_REGNUM] = (next_addr -= 4);
|
||||
lose: ;
|
||||
saved_regs->regs[SP_REGNUM] = (frame_info)->frame + 8;
|
||||
saved_regs->regs[FP_REGNUM] = (frame_info)->frame;
|
||||
saved_regs->regs[PC_REGNUM] = (frame_info)->frame + 4;
|
||||
#ifdef SIG_SP_FP_OFFSET
|
||||
/* Adjust saved SP_REGNUM for fake _sigtramp frames. */
|
||||
if (frame_info->signal_handler_caller && frame_info->next)
|
||||
saved_regs->regs[SP_REGNUM] = frame_info->next->frame + SIG_SP_FP_OFFSET;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_PROC_FS /* Target dependent support for /proc */
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* The /proc interface divides the target machine's register set up into
|
||||
two different sets, the general register set (gregset) and the floating
|
||||
point register set (fpregset). For each set, there is an ioctl to get
|
||||
the current register set and another ioctl to set the current values.
|
||||
|
||||
The actual structure passed through the ioctl interface is, of course,
|
||||
naturally machine dependent, and is different for each set of registers.
|
||||
For the m68k for example, the general register set is typically defined
|
||||
by:
|
||||
|
||||
typedef int gregset_t[18];
|
||||
|
||||
#define R_D0 0
|
||||
...
|
||||
#define R_PS 17
|
||||
|
||||
and the floating point set by:
|
||||
|
||||
typedef struct fpregset {
|
||||
int f_pcr;
|
||||
int f_psr;
|
||||
int f_fpiaddr;
|
||||
int f_fpregs[8][3]; (8 regs, 96 bits each)
|
||||
} fpregset_t;
|
||||
|
||||
These routines provide the packing and unpacking of gregset_t and
|
||||
fpregset_t formatted data.
|
||||
|
||||
*/
|
||||
|
||||
/* Atari SVR4 has R_SR but not R_PS */
|
||||
|
||||
#if !defined (R_PS) && defined (R_SR)
|
||||
#define R_PS R_SR
|
||||
#endif
|
||||
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
|
||||
for (regi = 0 ; regi < R_PC ; regi++)
|
||||
{
|
||||
supply_register (regi, (char *) (regp + regi));
|
||||
}
|
||||
supply_register (PS_REGNUM, (char *) (regp + R_PS));
|
||||
supply_register (PC_REGNUM, (char *) (regp + R_PC));
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
extern char registers[];
|
||||
|
||||
for (regi = 0 ; regi < R_PC ; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
*(regp + regi) = *(int *) ®isters[REGISTER_BYTE (regi)];
|
||||
}
|
||||
}
|
||||
if ((regno == -1) || (regno == PS_REGNUM))
|
||||
{
|
||||
*(regp + R_PS) = *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)];
|
||||
}
|
||||
if ((regno == -1) || (regno == PC_REGNUM))
|
||||
{
|
||||
*(regp + R_PC) = *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)];
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (FP0_REGNUM)
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), unpack the register contents and supply them as gdb's
|
||||
idea of the current floating point register values. */
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
register int regi;
|
||||
char *from;
|
||||
|
||||
for (regi = FP0_REGNUM ; regi < FPC_REGNUM ; regi++)
|
||||
{
|
||||
from = (char *) &(fpregsetp -> f_fpregs[regi-FP0_REGNUM][0]);
|
||||
supply_register (regi, from);
|
||||
}
|
||||
supply_register (FPC_REGNUM, (char *) &(fpregsetp -> f_pcr));
|
||||
supply_register (FPS_REGNUM, (char *) &(fpregsetp -> f_psr));
|
||||
supply_register (FPI_REGNUM, (char *) &(fpregsetp -> f_fpiaddr));
|
||||
}
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), update the register specified by REGNO from gdb's idea
|
||||
of the current floating point register set. If REGNO is -1, update
|
||||
them all. */
|
||||
|
||||
void
|
||||
fill_fpregset (fpregsetp, regno)
|
||||
fpregset_t *fpregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
char *to;
|
||||
char *from;
|
||||
extern char registers[];
|
||||
|
||||
for (regi = FP0_REGNUM ; regi < FPC_REGNUM ; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
from = (char *) ®isters[REGISTER_BYTE (regi)];
|
||||
to = (char *) &(fpregsetp -> f_fpregs[regi-FP0_REGNUM][0]);
|
||||
memcpy (to, from, REGISTER_RAW_SIZE (regi));
|
||||
}
|
||||
}
|
||||
if ((regno == -1) || (regno == FPC_REGNUM))
|
||||
{
|
||||
fpregsetp -> f_pcr = *(int *) ®isters[REGISTER_BYTE (FPC_REGNUM)];
|
||||
}
|
||||
if ((regno == -1) || (regno == FPS_REGNUM))
|
||||
{
|
||||
fpregsetp -> f_psr = *(int *) ®isters[REGISTER_BYTE (FPS_REGNUM)];
|
||||
}
|
||||
if ((regno == -1) || (regno == FPI_REGNUM))
|
||||
{
|
||||
fpregsetp -> f_fpiaddr = *(int *) ®isters[REGISTER_BYTE (FPI_REGNUM)];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined (FP0_REGNUM) */
|
||||
|
||||
#endif /* USE_PROC_FS */
|
||||
|
||||
#ifdef GET_LONGJMP_TARGET
|
||||
/* Figure out where the longjmp will land. Slurp the args out of the stack.
|
||||
We expect the first arg to be a pointer to the jmp_buf structure from which
|
||||
we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
|
||||
This routine returns true on success. */
|
||||
|
||||
int
|
||||
get_longjmp_target(pc)
|
||||
CORE_ADDR *pc;
|
||||
{
|
||||
char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
|
||||
CORE_ADDR sp, jb_addr;
|
||||
|
||||
sp = read_register(SP_REGNUM);
|
||||
|
||||
if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
|
||||
buf,
|
||||
TARGET_PTR_BIT / TARGET_CHAR_BIT))
|
||||
return 0;
|
||||
|
||||
jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
|
||||
|
||||
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
|
||||
TARGET_PTR_BIT / TARGET_CHAR_BIT))
|
||||
return 0;
|
||||
|
||||
*pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* GET_LONGJMP_TARGET */
|
||||
|
||||
/* Immediately after a function call, return the saved pc before the frame
|
||||
is setup. For sun3's, we check for the common case of being inside of a
|
||||
system call, and if so, we know that Sun pushes the call # on the stack
|
||||
prior to doing the trap. */
|
||||
|
||||
CORE_ADDR
|
||||
m68k_saved_pc_after_call(frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
#ifdef SYSCALL_TRAP
|
||||
int op;
|
||||
|
||||
op = read_memory_integer (frame->pc - SYSCALL_TRAP_OFFSET, 2);
|
||||
|
||||
if (op == SYSCALL_TRAP)
|
||||
return read_memory_integer (read_register (SP_REGNUM) + 4, 4);
|
||||
else
|
||||
#endif /* SYSCALL_TRAP */
|
||||
return read_memory_integer (read_register (SP_REGNUM), 4);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_m68k_tdep ()
|
||||
{
|
||||
tm_print_insn = print_insn_m68k;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/* Native-dependent code for Motorola m68k's running NetBSD, for GDB.
|
||||
Copyright 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/frame.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
|
||||
void
|
||||
fetch_inferior_registers(regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
struct fpreg inferior_fp_registers;
|
||||
|
||||
ptrace (PT_GETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
memcpy (®isters[REGISTER_BYTE (0)], &inferior_registers,
|
||||
sizeof(inferior_registers));
|
||||
|
||||
ptrace (PT_GETFPREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
|
||||
sizeof(inferior_fp_registers));
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
void
|
||||
store_inferior_registers(regno)
|
||||
int regno;
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
struct fpreg inferior_fp_registers;
|
||||
|
||||
memcpy (&inferior_registers, ®isters[REGISTER_BYTE (0)],
|
||||
sizeof(inferior_registers));
|
||||
ptrace (PT_SETREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_registers, 0);
|
||||
|
||||
memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
sizeof(inferior_fp_registers));
|
||||
ptrace (PT_SETFPREGS, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
|
||||
}
|
||||
|
||||
struct md_core {
|
||||
struct reg intreg;
|
||||
struct fpreg freg;
|
||||
};
|
||||
|
||||
void
|
||||
fetch_core_registers (core_reg_sect, core_reg_size, which, ignore)
|
||||
char *core_reg_sect;
|
||||
unsigned core_reg_size;
|
||||
int which;
|
||||
unsigned int ignore;
|
||||
{
|
||||
struct md_core *core_reg = (struct md_core *)core_reg_sect;
|
||||
|
||||
/* Integer registers */
|
||||
memcpy(®isters[REGISTER_BYTE (0)],
|
||||
&core_reg->intreg, sizeof(struct reg));
|
||||
/* Floating point registers */
|
||||
memcpy(®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
&core_reg->freg, sizeof(struct fpreg));
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
/* Native-dependent Motorola 88xxx support for GDB, the GNU Debugger.
|
||||
Copyright 1988, 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include "gdbcore.h"
|
||||
#include <sys/user.h>
|
||||
|
||||
#ifndef USER /* added to support BCS ptrace_user */
|
||||
#define USER ptrace_user
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#include "symtab.h"
|
||||
#include "setjmp.h"
|
||||
#include "value.h"
|
||||
|
||||
#ifdef DELTA88
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
/* define offsets to the pc instruction offsets in ptrace_user struct */
|
||||
#define SXIP_OFFSET ((char *)&u.pt_sigframe.sig_sxip - (char *)&u)
|
||||
#define SNIP_OFFSET ((char *)&u.pt_sigframe.sig_snip - (char *)&u)
|
||||
#define SFIP_OFFSET ((char *)&u.pt_sigframe.sig_sfip - (char *)&u)
|
||||
#else
|
||||
/* define offsets to the pc instruction offsets in ptrace_user struct */
|
||||
#define SXIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_sxip - (char *)&u)
|
||||
#define SNIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_snip - (char *)&u)
|
||||
#define SFIP_OFFSET ((char *)&u.pt_sigframe.dg_sigframe.sc_sfip - (char *)&u)
|
||||
#endif
|
||||
|
||||
extern int have_symbol_file_p();
|
||||
|
||||
extern jmp_buf stack_jmp;
|
||||
|
||||
extern int errno;
|
||||
extern char registers[REGISTER_BYTES];
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno; /* Original value discarded */
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
register int i;
|
||||
|
||||
struct USER u;
|
||||
unsigned int offset;
|
||||
|
||||
offset = (char *) &u.pt_r0 - (char *) &u;
|
||||
regaddr = offset; /* byte offset to r0;*/
|
||||
|
||||
/* offset = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) offset, 0) - KERNEL_U_ADDR; */
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
/*regaddr = register_addr (regno, offset);*/
|
||||
/* 88k enhancement */
|
||||
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
|
||||
{
|
||||
*(int *) &buf[i] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
regaddr += sizeof (int);
|
||||
}
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
/* now load up registers 36 - 38; special pc registers */
|
||||
*(int *) &buf[0] = ptrace (3,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET ,0);
|
||||
supply_register (SXIP_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET,0);
|
||||
supply_register (SNIP_REGNUM, buf);
|
||||
*(int *) &buf[0] = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET,0);
|
||||
supply_register (SFIP_REGNUM, 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). */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
struct USER u;
|
||||
|
||||
unsigned int offset = (char *) &u.pt_r0 - (char *) &u;
|
||||
|
||||
regaddr = offset;
|
||||
|
||||
/* Don't try to deal with EXIP_REGNUM or ENIP_REGNUM, because I think either
|
||||
svr3 doesn't run on an 88110, or the kernel isolates the different (not
|
||||
completely sure this is true, but seems to be. */
|
||||
if (regno >= 0)
|
||||
{
|
||||
/* regaddr = register_addr (regno, offset); */
|
||||
if (regno < PC_REGNUM)
|
||||
{
|
||||
regaddr = offset + regno * sizeof (int);
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
else if (regno == SXIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET, read_register(regno));
|
||||
else if (regno == SNIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET, read_register(regno));
|
||||
else if (regno == SFIP_REGNUM)
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET, read_register(regno));
|
||||
else
|
||||
printf_unfiltered ("Bad register number for store_inferior routine\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regno = 0; regno < PC_REGNUM; regno++)
|
||||
{
|
||||
/* regaddr = register_addr (regno, offset); */
|
||||
errno = 0;
|
||||
regaddr = offset + regno * sizeof (int);
|
||||
ptrace (6, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SXIP_OFFSET,read_register(SXIP_REGNUM));
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SNIP_OFFSET,read_register(SNIP_REGNUM));
|
||||
ptrace (6,inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) SFIP_OFFSET,read_register(SFIP_REGNUM));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* blockend is the address of the end of the user structure */
|
||||
m88k_register_u_addr (blockend, regnum)
|
||||
{
|
||||
struct USER u;
|
||||
int ustart = blockend - sizeof (struct USER);
|
||||
switch (regnum)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
return (ustart + ((int) &u.pt_r0 - (int) &u) + REGISTER_SIZE * regnum);
|
||||
case PSR_REGNUM: return (ustart + ((int) &u.pt_psr - (int) &u));
|
||||
case FPSR_REGNUM: return (ustart + ((int) &u.pt_fpsr - (int) &u));
|
||||
case FPCR_REGNUM: return (ustart + ((int) &u.pt_fpcr - (int) &u));
|
||||
case SXIP_REGNUM: return (ustart + SXIP_OFFSET);
|
||||
case SNIP_REGNUM: return (ustart + SNIP_OFFSET);
|
||||
case SFIP_REGNUM: return (ustart + SFIP_OFFSET);
|
||||
default:
|
||||
if (regnum < NUM_REGS)
|
||||
/* The register is one of those which is not defined...
|
||||
give it zero */
|
||||
return (ustart + ((int) &u.pt_r0 - (int) &u));
|
||||
else
|
||||
return (blockend + REGISTER_SIZE * regnum);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_PROC_FS
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
register int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
|
||||
for (regi=0; regi <= SP_REGNUM; regi++)
|
||||
supply_register (regi, (char *) (regp + regi));
|
||||
|
||||
supply_register (SXIP_REGNUM, (char *) (regp + R_XIP));
|
||||
supply_register (SNIP_REGNUM, (char *) (regp + R_NIP));
|
||||
supply_register (SFIP_REGNUM, (char *) (regp + R_FIP));
|
||||
supply_register (PSR_REGNUM, (char *) (regp + R_PSR));
|
||||
supply_register (FPSR_REGNUM, (char *) (regp + R_FPSR));
|
||||
supply_register (FPCR_REGNUM, (char *) (regp + R_FPCR));
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
extern char registers[];
|
||||
|
||||
for (regi = 0 ; regi <= R_R31 ; regi++)
|
||||
if ((regno == -1) || (regno == regi))
|
||||
*(regp + regi) = *(int *) ®isters[REGISTER_BYTE(regi)];
|
||||
|
||||
if ((regno == -1) || (regno == SXIP_REGNUM))
|
||||
*(regp + R_XIP) = *(int *) ®isters[REGISTER_BYTE(SXIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == SNIP_REGNUM))
|
||||
*(regp + R_NIP) = *(int *) ®isters[REGISTER_BYTE(SNIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == SFIP_REGNUM))
|
||||
*(regp + R_FIP) = *(int *) ®isters[REGISTER_BYTE(SFIP_REGNUM)];
|
||||
if ((regno == -1) || (regno == PSR_REGNUM))
|
||||
*(regp + R_PSR) = *(int *) ®isters[REGISTER_BYTE(PSR_REGNUM)];
|
||||
if ((regno == -1) || (regno == FPSR_REGNUM))
|
||||
*(regp + R_FPSR) = *(int *) ®isters[REGISTER_BYTE(FPSR_REGNUM)];
|
||||
if ((regno == -1) || (regno == FPCR_REGNUM))
|
||||
*(regp + R_FPCR) = *(int *) ®isters[REGISTER_BYTE(FPCR_REGNUM)];
|
||||
}
|
||||
|
||||
#endif /* USE_PROC_FS */
|
|
@ -1,616 +0,0 @@
|
|||
/* Target-machine dependent code for Motorola 88000 series, for GDB.
|
||||
Copyright 1988, 1990, 1991, 1994, 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "value.h"
|
||||
#include "gdbcore.h"
|
||||
#include "symtab.h"
|
||||
#include "setjmp.h"
|
||||
#include "value.h"
|
||||
|
||||
/* Size of an instruction */
|
||||
#define BYTES_PER_88K_INSN 4
|
||||
|
||||
void frame_find_saved_regs ();
|
||||
|
||||
/* Is this target an m88110? Otherwise assume m88100. This has
|
||||
relevance for the ways in which we screw with instruction pointers. */
|
||||
|
||||
int target_is_m88110 = 0;
|
||||
|
||||
/* Given a GDB frame, determine the address of the calling function's frame.
|
||||
This will be used to create a new GDB frame struct, and then
|
||||
INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
|
||||
|
||||
For us, the frame address is its stack pointer value, so we look up
|
||||
the function prologue to determine the caller's sp value, and return it. */
|
||||
|
||||
CORE_ADDR
|
||||
frame_chain (thisframe)
|
||||
struct frame_info *thisframe;
|
||||
{
|
||||
|
||||
frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0);
|
||||
/* NOTE: this depends on frame_find_saved_regs returning the VALUE, not
|
||||
the ADDRESS, of SP_REGNUM. It also depends on the cache of
|
||||
frame_find_saved_regs results. */
|
||||
if (thisframe->fsr->regs[SP_REGNUM])
|
||||
return thisframe->fsr->regs[SP_REGNUM];
|
||||
else
|
||||
return thisframe->frame; /* Leaf fn -- next frame up has same SP. */
|
||||
}
|
||||
|
||||
int
|
||||
frameless_function_invocation (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
|
||||
frame_find_saved_regs (frame, (struct frame_saved_regs *) 0);
|
||||
/* NOTE: this depends on frame_find_saved_regs returning the VALUE, not
|
||||
the ADDRESS, of SP_REGNUM. It also depends on the cache of
|
||||
frame_find_saved_regs results. */
|
||||
if (frame->fsr->regs[SP_REGNUM])
|
||||
return 0; /* Frameful -- return addr saved somewhere */
|
||||
else
|
||||
return 1; /* Frameless -- no saved return address */
|
||||
}
|
||||
|
||||
void
|
||||
init_extra_frame_info (fromleaf, frame)
|
||||
int fromleaf;
|
||||
struct frame_info *frame;
|
||||
{
|
||||
frame->fsr = 0; /* Not yet allocated */
|
||||
frame->args_pointer = 0; /* Unknown */
|
||||
frame->locals_pointer = 0; /* Unknown */
|
||||
}
|
||||
|
||||
/* Examine an m88k function prologue, recording the addresses at which
|
||||
registers are saved explicitly by the prologue code, and returning
|
||||
the address of the first instruction after the prologue (but not
|
||||
after the instruction at address LIMIT, as explained below).
|
||||
|
||||
LIMIT places an upper bound on addresses of the instructions to be
|
||||
examined. If the prologue code scan reaches LIMIT, the scan is
|
||||
aborted and LIMIT is returned. This is used, when examining the
|
||||
prologue for the current frame, to keep examine_prologue () from
|
||||
claiming that a given register has been saved when in fact the
|
||||
instruction that saves it has not yet been executed. LIMIT is used
|
||||
at other times to stop the scan when we hit code after the true
|
||||
function prologue (e.g. for the first source line) which might
|
||||
otherwise be mistaken for function prologue.
|
||||
|
||||
The format of the function prologue matched by this routine is
|
||||
derived from examination of the source to gcc 1.95, particularly
|
||||
the routine output_prologue () in config/out-m88k.c.
|
||||
|
||||
subu r31,r31,n # stack pointer update
|
||||
|
||||
(st rn,r31,offset)? # save incoming regs
|
||||
(st.d rn,r31,offset)?
|
||||
|
||||
(addu r30,r31,n)? # frame pointer update
|
||||
|
||||
(pic sequence)? # PIC code prologue
|
||||
|
||||
(or rn,rm,0)? # Move parameters to other regs
|
||||
*/
|
||||
|
||||
/* Macros for extracting fields from instructions. */
|
||||
|
||||
#define BITMASK(pos, width) (((0x1 << (width)) - 1) << (pos))
|
||||
#define EXTRACT_FIELD(val, pos, width) ((val) >> (pos) & BITMASK (0, width))
|
||||
#define SUBU_OFFSET(x) ((unsigned)(x & 0xFFFF))
|
||||
#define ST_OFFSET(x) ((unsigned)((x) & 0xFFFF))
|
||||
#define ST_SRC(x) EXTRACT_FIELD ((x), 21, 5)
|
||||
#define ADDU_OFFSET(x) ((unsigned)(x & 0xFFFF))
|
||||
|
||||
/*
|
||||
* prologue_insn_tbl is a table of instructions which may comprise a
|
||||
* function prologue. Associated with each table entry (corresponding
|
||||
* to a single instruction or group of instructions), is an action.
|
||||
* This action is used by examine_prologue (below) to determine
|
||||
* the state of certain machine registers and where the stack frame lives.
|
||||
*/
|
||||
|
||||
enum prologue_insn_action {
|
||||
PIA_SKIP, /* don't care what the instruction does */
|
||||
PIA_NOTE_ST, /* note register stored and where */
|
||||
PIA_NOTE_STD, /* note pair of registers stored and where */
|
||||
PIA_NOTE_SP_ADJUSTMENT, /* note stack pointer adjustment */
|
||||
PIA_NOTE_FP_ASSIGNMENT, /* note frame pointer assignment */
|
||||
PIA_NOTE_PROLOGUE_END, /* no more prologue */
|
||||
};
|
||||
|
||||
struct prologue_insns {
|
||||
unsigned long insn;
|
||||
unsigned long mask;
|
||||
enum prologue_insn_action action;
|
||||
};
|
||||
|
||||
struct prologue_insns prologue_insn_tbl[] = {
|
||||
/* Various register move instructions */
|
||||
{ 0x58000000, 0xf800ffff, PIA_SKIP }, /* or/or.u with immed of 0 */
|
||||
{ 0xf4005800, 0xfc1fffe0, PIA_SKIP }, /* or rd, r0, rs */
|
||||
{ 0xf4005800, 0xfc00ffff, PIA_SKIP }, /* or rd, rs, r0 */
|
||||
|
||||
/* Stack pointer setup: "subu sp, sp, n" where n is a multiple of 8 */
|
||||
{ 0x67ff0000, 0xffff0007, PIA_NOTE_SP_ADJUSTMENT },
|
||||
|
||||
/* Frame pointer assignment: "addu r30, r31, n" */
|
||||
{ 0x63df0000, 0xffff0000, PIA_NOTE_FP_ASSIGNMENT },
|
||||
|
||||
/* Store to stack instructions; either "st rx, sp, n" or "st.d rx, sp, n" */
|
||||
{ 0x241f0000, 0xfc1f0000, PIA_NOTE_ST }, /* st rx, sp, n */
|
||||
{ 0x201f0000, 0xfc1f0000, PIA_NOTE_STD }, /* st.d rs, sp, n */
|
||||
|
||||
/* Instructions needed for setting up r25 for pic code. */
|
||||
{ 0x5f200000, 0xffff0000, PIA_SKIP }, /* or.u r25, r0, offset_high */
|
||||
{ 0xcc000002, 0xffffffff, PIA_SKIP }, /* bsr.n Lab */
|
||||
{ 0x5b390000, 0xffff0000, PIA_SKIP }, /* or r25, r25, offset_low */
|
||||
{ 0xf7396001, 0xffffffff, PIA_SKIP }, /* Lab: addu r25, r25, r1 */
|
||||
|
||||
/* Various branch or jump instructions which have a delay slot -- these
|
||||
do not form part of the prologue, but the instruction in the delay
|
||||
slot might be a store instruction which should be noted. */
|
||||
{ 0xc4000000, 0xe4000000, PIA_NOTE_PROLOGUE_END },
|
||||
/* br.n, bsr.n, bb0.n, or bb1.n */
|
||||
{ 0xec000000, 0xfc000000, PIA_NOTE_PROLOGUE_END }, /* bcnd.n */
|
||||
{ 0xf400c400, 0xfffff7e0, PIA_NOTE_PROLOGUE_END } /* jmp.n or jsr.n */
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or
|
||||
is not the address of a valid instruction, the address of the next
|
||||
instruction beyond ADDR otherwise. *PWORD1 receives the first word
|
||||
of the instruction. */
|
||||
|
||||
#define NEXT_PROLOGUE_INSN(addr, lim, pword1) \
|
||||
(((addr) < (lim)) ? next_insn (addr, pword1) : 0)
|
||||
|
||||
/* Read the m88k instruction at 'memaddr' and return the address of
|
||||
the next instruction after that, or 0 if 'memaddr' is not the
|
||||
address of a valid instruction. The instruction
|
||||
is stored at 'pword1'. */
|
||||
|
||||
CORE_ADDR
|
||||
next_insn (memaddr, pword1)
|
||||
unsigned long *pword1;
|
||||
CORE_ADDR memaddr;
|
||||
{
|
||||
*pword1 = read_memory_integer (memaddr, BYTES_PER_88K_INSN);
|
||||
return memaddr + BYTES_PER_88K_INSN;
|
||||
}
|
||||
|
||||
/* Read a register from frames called by us (or from the hardware regs). */
|
||||
|
||||
static int
|
||||
read_next_frame_reg(frame, regno)
|
||||
struct frame_info *frame;
|
||||
int regno;
|
||||
{
|
||||
for (; frame; frame = frame->next) {
|
||||
if (regno == SP_REGNUM)
|
||||
return FRAME_FP (frame);
|
||||
else if (frame->fsr->regs[regno])
|
||||
return read_memory_integer(frame->fsr->regs[regno], 4);
|
||||
}
|
||||
return read_register(regno);
|
||||
}
|
||||
|
||||
/* Examine the prologue of a function. `ip' points to the first instruction.
|
||||
`limit' is the limit of the prologue (e.g. the addr of the first
|
||||
linenumber, or perhaps the program counter if we're stepping through).
|
||||
`frame_sp' is the stack pointer value in use in this frame.
|
||||
`fsr' is a pointer to a frame_saved_regs structure into which we put
|
||||
info about the registers saved by this frame.
|
||||
`fi' is a struct frame_info pointer; we fill in various fields in it
|
||||
to reflect the offsets of the arg pointer and the locals pointer. */
|
||||
|
||||
static CORE_ADDR
|
||||
examine_prologue (ip, limit, frame_sp, fsr, fi)
|
||||
register CORE_ADDR ip;
|
||||
register CORE_ADDR limit;
|
||||
CORE_ADDR frame_sp;
|
||||
struct frame_saved_regs *fsr;
|
||||
struct frame_info *fi;
|
||||
{
|
||||
register CORE_ADDR next_ip;
|
||||
register int src;
|
||||
unsigned int insn;
|
||||
int size, offset;
|
||||
char must_adjust[32]; /* If set, must adjust offsets in fsr */
|
||||
int sp_offset = -1; /* -1 means not set (valid must be mult of 8) */
|
||||
int fp_offset = -1; /* -1 means not set */
|
||||
CORE_ADDR frame_fp;
|
||||
CORE_ADDR prologue_end = 0;
|
||||
|
||||
memset (must_adjust, '\0', sizeof (must_adjust));
|
||||
next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn);
|
||||
|
||||
while (next_ip)
|
||||
{
|
||||
struct prologue_insns *pip;
|
||||
|
||||
for (pip=prologue_insn_tbl; (insn & pip->mask) != pip->insn; )
|
||||
if (++pip >= prologue_insn_tbl + sizeof prologue_insn_tbl)
|
||||
goto end_of_prologue_found; /* not a prologue insn */
|
||||
|
||||
switch (pip->action)
|
||||
{
|
||||
case PIA_NOTE_ST:
|
||||
case PIA_NOTE_STD:
|
||||
if (sp_offset != -1) {
|
||||
src = ST_SRC (insn);
|
||||
offset = ST_OFFSET (insn);
|
||||
must_adjust[src] = 1;
|
||||
fsr->regs[src++] = offset; /* Will be adjusted later */
|
||||
if (pip->action == PIA_NOTE_STD && src < 32)
|
||||
{
|
||||
offset += 4;
|
||||
must_adjust[src] = 1;
|
||||
fsr->regs[src++] = offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
goto end_of_prologue_found;
|
||||
break;
|
||||
case PIA_NOTE_SP_ADJUSTMENT:
|
||||
if (sp_offset == -1)
|
||||
sp_offset = -SUBU_OFFSET (insn);
|
||||
else
|
||||
goto end_of_prologue_found;
|
||||
break;
|
||||
case PIA_NOTE_FP_ASSIGNMENT:
|
||||
if (fp_offset == -1)
|
||||
fp_offset = ADDU_OFFSET (insn);
|
||||
else
|
||||
goto end_of_prologue_found;
|
||||
break;
|
||||
case PIA_NOTE_PROLOGUE_END:
|
||||
if (!prologue_end)
|
||||
prologue_end = ip;
|
||||
break;
|
||||
case PIA_SKIP:
|
||||
default :
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
ip = next_ip;
|
||||
next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn);
|
||||
}
|
||||
|
||||
end_of_prologue_found:
|
||||
|
||||
if (prologue_end)
|
||||
ip = prologue_end;
|
||||
|
||||
/* We're done with the prologue. If we don't care about the stack
|
||||
frame itself, just return. (Note that fsr->regs has been trashed,
|
||||
but the one caller who calls with fi==0 passes a dummy there.) */
|
||||
|
||||
if (fi == 0)
|
||||
return ip;
|
||||
|
||||
/*
|
||||
OK, now we have:
|
||||
|
||||
sp_offset original (before any alloca calls) displacement of SP
|
||||
(will be negative).
|
||||
|
||||
fp_offset displacement from original SP to the FP for this frame
|
||||
or -1.
|
||||
|
||||
fsr->regs[0..31] displacement from original SP to the stack
|
||||
location where reg[0..31] is stored.
|
||||
|
||||
must_adjust[0..31] set if corresponding offset was set.
|
||||
|
||||
If alloca has been called between the function prologue and the current
|
||||
IP, then the current SP (frame_sp) will not be the original SP as set by
|
||||
the function prologue. If the current SP is not the original SP, then the
|
||||
compiler will have allocated an FP for this frame, fp_offset will be set,
|
||||
and we can use it to calculate the original SP.
|
||||
|
||||
Then, we figure out where the arguments and locals are, and relocate the
|
||||
offsets in fsr->regs to absolute addresses. */
|
||||
|
||||
if (fp_offset != -1) {
|
||||
/* We have a frame pointer, so get it, and base our calc's on it. */
|
||||
frame_fp = (CORE_ADDR) read_next_frame_reg (fi->next, ACTUAL_FP_REGNUM);
|
||||
frame_sp = frame_fp - fp_offset;
|
||||
} else {
|
||||
/* We have no frame pointer, therefore frame_sp is still the same value
|
||||
as set by prologue. But where is the frame itself? */
|
||||
if (must_adjust[SRP_REGNUM]) {
|
||||
/* Function header saved SRP (r1), the return address. Frame starts
|
||||
4 bytes down from where it was saved. */
|
||||
frame_fp = frame_sp + fsr->regs[SRP_REGNUM] - 4;
|
||||
fi->locals_pointer = frame_fp;
|
||||
} else {
|
||||
/* Function header didn't save SRP (r1), so we are in a leaf fn or
|
||||
are otherwise confused. */
|
||||
frame_fp = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The locals are relative to the FP (whether it exists as an allocated
|
||||
register, or just as an assumed offset from the SP) */
|
||||
fi->locals_pointer = frame_fp;
|
||||
|
||||
/* The arguments are just above the SP as it was before we adjusted it
|
||||
on entry. */
|
||||
fi->args_pointer = frame_sp - sp_offset;
|
||||
|
||||
/* Now that we know the SP value used by the prologue, we know where
|
||||
it saved all the registers. */
|
||||
for (src = 0; src < 32; src++)
|
||||
if (must_adjust[src])
|
||||
fsr->regs[src] += frame_sp;
|
||||
|
||||
/* The saved value of the SP is always known. */
|
||||
/* (we hope...) */
|
||||
if (fsr->regs[SP_REGNUM] != 0
|
||||
&& fsr->regs[SP_REGNUM] != frame_sp - sp_offset)
|
||||
fprintf_unfiltered(gdb_stderr, "Bad saved SP value %x != %x, offset %x!\n",
|
||||
fsr->regs[SP_REGNUM],
|
||||
frame_sp - sp_offset, sp_offset);
|
||||
|
||||
fsr->regs[SP_REGNUM] = frame_sp - sp_offset;
|
||||
|
||||
return (ip);
|
||||
}
|
||||
|
||||
/* Given an ip value corresponding to the start of a function,
|
||||
return the ip of the first instruction after the function
|
||||
prologue. */
|
||||
|
||||
CORE_ADDR
|
||||
skip_prologue (ip)
|
||||
CORE_ADDR (ip);
|
||||
{
|
||||
struct frame_saved_regs saved_regs_dummy;
|
||||
struct symtab_and_line sal;
|
||||
CORE_ADDR limit;
|
||||
|
||||
sal = find_pc_line (ip, 0);
|
||||
limit = (sal.end) ? sal.end : 0xffffffff;
|
||||
|
||||
return (examine_prologue (ip, limit, (CORE_ADDR) 0, &saved_regs_dummy,
|
||||
(struct frame_info *)0 ));
|
||||
}
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame.
|
||||
|
||||
We cache the result of doing this in the frame_cache_obstack, since
|
||||
it is fairly expensive. */
|
||||
|
||||
void
|
||||
frame_find_saved_regs (fi, fsr)
|
||||
struct frame_info *fi;
|
||||
struct frame_saved_regs *fsr;
|
||||
{
|
||||
register struct frame_saved_regs *cache_fsr;
|
||||
extern struct obstack frame_cache_obstack;
|
||||
CORE_ADDR ip;
|
||||
struct symtab_and_line sal;
|
||||
CORE_ADDR limit;
|
||||
|
||||
if (!fi->fsr)
|
||||
{
|
||||
cache_fsr = (struct frame_saved_regs *)
|
||||
obstack_alloc (&frame_cache_obstack,
|
||||
sizeof (struct frame_saved_regs));
|
||||
memset (cache_fsr, '\0', sizeof (struct frame_saved_regs));
|
||||
fi->fsr = cache_fsr;
|
||||
|
||||
/* Find the start and end of the function prologue. If the PC
|
||||
is in the function prologue, we only consider the part that
|
||||
has executed already. In the case where the PC is not in
|
||||
the function prologue, we set limit to two instructions beyond
|
||||
where the prologue ends in case if any of the prologue instructions
|
||||
were moved into a delay slot of a branch instruction. */
|
||||
|
||||
ip = get_pc_function_start (fi->pc);
|
||||
sal = find_pc_line (ip, 0);
|
||||
limit = (sal.end && sal.end < fi->pc) ? sal.end + 2 * BYTES_PER_88K_INSN
|
||||
: fi->pc;
|
||||
|
||||
/* This will fill in fields in *fi as well as in cache_fsr. */
|
||||
#ifdef SIGTRAMP_FRAME_FIXUP
|
||||
if (fi->signal_handler_caller)
|
||||
SIGTRAMP_FRAME_FIXUP(fi->frame);
|
||||
#endif
|
||||
examine_prologue (ip, limit, fi->frame, cache_fsr, fi);
|
||||
#ifdef SIGTRAMP_SP_FIXUP
|
||||
if (fi->signal_handler_caller && fi->fsr->regs[SP_REGNUM])
|
||||
SIGTRAMP_SP_FIXUP(fi->fsr->regs[SP_REGNUM]);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fsr)
|
||||
*fsr = *fi->fsr;
|
||||
}
|
||||
|
||||
/* Return the address of the locals block for the frame
|
||||
described by FI. Returns 0 if the address is unknown.
|
||||
NOTE! Frame locals are referred to by negative offsets from the
|
||||
argument pointer, so this is the same as frame_args_address(). */
|
||||
|
||||
CORE_ADDR
|
||||
frame_locals_address (fi)
|
||||
struct frame_info *fi;
|
||||
{
|
||||
struct frame_saved_regs fsr;
|
||||
|
||||
if (fi->args_pointer) /* Cached value is likely there. */
|
||||
return fi->args_pointer;
|
||||
|
||||
/* Nope, generate it. */
|
||||
|
||||
get_frame_saved_regs (fi, &fsr);
|
||||
|
||||
return fi->args_pointer;
|
||||
}
|
||||
|
||||
/* Return the address of the argument block for the frame
|
||||
described by FI. Returns 0 if the address is unknown. */
|
||||
|
||||
CORE_ADDR
|
||||
frame_args_address (fi)
|
||||
struct frame_info *fi;
|
||||
{
|
||||
struct frame_saved_regs fsr;
|
||||
|
||||
if (fi->args_pointer) /* Cached value is likely there. */
|
||||
return fi->args_pointer;
|
||||
|
||||
/* Nope, generate it. */
|
||||
|
||||
get_frame_saved_regs (fi, &fsr);
|
||||
|
||||
return fi->args_pointer;
|
||||
}
|
||||
|
||||
/* Return the saved PC from this frame.
|
||||
|
||||
If the frame has a memory copy of SRP_REGNUM, use that. If not,
|
||||
just use the register SRP_REGNUM itself. */
|
||||
|
||||
CORE_ADDR
|
||||
frame_saved_pc (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
return read_next_frame_reg(frame, SRP_REGNUM);
|
||||
}
|
||||
|
||||
|
||||
#define DUMMY_FRAME_SIZE 192
|
||||
|
||||
static void
|
||||
write_word (sp, word)
|
||||
CORE_ADDR sp;
|
||||
unsigned LONGEST word;
|
||||
{
|
||||
register int len = REGISTER_SIZE;
|
||||
char buffer[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
store_unsigned_integer (buffer, len, word);
|
||||
write_memory (sp, buffer, len);
|
||||
}
|
||||
|
||||
void
|
||||
m88k_push_dummy_frame()
|
||||
{
|
||||
register CORE_ADDR sp = read_register (SP_REGNUM);
|
||||
register int rn;
|
||||
int offset;
|
||||
|
||||
sp -= DUMMY_FRAME_SIZE; /* allocate a bunch of space */
|
||||
|
||||
for (rn = 0, offset = 0; rn <= SP_REGNUM; rn++, offset+=4)
|
||||
write_word (sp+offset, read_register(rn));
|
||||
|
||||
write_word (sp+offset, read_register (SXIP_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_word (sp+offset, read_register (SNIP_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_word (sp+offset, read_register (SFIP_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_word (sp+offset, read_register (PSR_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_word (sp+offset, read_register (FPSR_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_word (sp+offset, read_register (FPCR_REGNUM));
|
||||
offset += 4;
|
||||
|
||||
write_register (SP_REGNUM, sp);
|
||||
write_register (ACTUAL_FP_REGNUM, sp);
|
||||
}
|
||||
|
||||
void
|
||||
pop_frame ()
|
||||
{
|
||||
register struct frame_info *frame = get_current_frame ();
|
||||
register CORE_ADDR fp;
|
||||
register int regnum;
|
||||
struct frame_saved_regs fsr;
|
||||
|
||||
fp = FRAME_FP (frame);
|
||||
get_frame_saved_regs (frame, &fsr);
|
||||
|
||||
if (PC_IN_CALL_DUMMY (read_pc (), read_register (SP_REGNUM), FRAME_FP (fi)))
|
||||
{
|
||||
/* FIXME: I think get_frame_saved_regs should be handling this so
|
||||
that we can deal with the saved registers properly (e.g. frame
|
||||
1 is a call dummy, the user types "frame 2" and then "print $ps"). */
|
||||
register CORE_ADDR sp = read_register (ACTUAL_FP_REGNUM);
|
||||
int offset;
|
||||
|
||||
for (regnum = 0, offset = 0; regnum <= SP_REGNUM; regnum++, offset+=4)
|
||||
(void) write_register (regnum, read_memory_integer (sp+offset, 4));
|
||||
|
||||
write_register (SXIP_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
write_register (SNIP_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
write_register (SFIP_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
write_register (PSR_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
write_register (FPSR_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
write_register (FPCR_REGNUM, read_memory_integer (sp+offset, 4));
|
||||
offset += 4;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regnum = FP_REGNUM ; regnum > 0 ; regnum--)
|
||||
if (fsr.regs[regnum])
|
||||
write_register (regnum,
|
||||
read_memory_integer (fsr.regs[regnum], 4));
|
||||
write_pc (frame_saved_pc (frame));
|
||||
}
|
||||
reinit_frame_cache ();
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_m88k_tdep ()
|
||||
{
|
||||
tm_print_insn = print_insn_m88k;
|
||||
}
|
|
@ -1,562 +0,0 @@
|
|||
/* Definitions and macros for support of AMD's remote debugger, MiniMON.
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/*
|
||||
* Some basic types. FIXME, this should be done by declaring bitfield
|
||||
* sizes in the structs. We can't portably depend on a "long int" being
|
||||
* 32 bits, etc.
|
||||
*/
|
||||
typedef long int INT32; /* 32 bit integer */
|
||||
typedef unsigned long int UINT32; /* 32 bit integer (unsigned) */
|
||||
typedef unsigned long int ADDR32; /* 32 bit address */
|
||||
typedef unsigned long int INST32; /* 32 bit instruction */
|
||||
typedef long int BOOLEAN; /* Boolean value (32 bit) */
|
||||
typedef unsigned char BYTE; /* byte (8 bit) */
|
||||
typedef short int INT16; /* 16 bit integer */
|
||||
typedef unsigned short int UINT16; /* 16 bit integer (unsigned) */
|
||||
|
||||
/****************************************************************************/
|
||||
/************************* Message Information ******************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Error codes
|
||||
*/
|
||||
|
||||
/* General errors */
|
||||
#define EMUSAGE 1 /* Bad args / flags */
|
||||
#define EMFAIL 2 /* Unrecoverable error */
|
||||
#define EMBADADDR 3 /* Illegal address */
|
||||
#define EMBADREG 4 /* Illegal register */
|
||||
#define EMSYNTAX 5 /* Illegal command syntax */
|
||||
#define EMACCESS 6 /* Could not access memory */
|
||||
#define EMALLOC 7 /* Could not allocate memory */
|
||||
#define EMTARGET 8 /* Unknown target type */
|
||||
#define EMHINIT 9 /* Could not initialize host */
|
||||
#define EMCOMM 10 /* Could not open communication channel */
|
||||
|
||||
/* Message errors */
|
||||
#define EMBADMSG 11 /* Unknown message type */
|
||||
#define EMMSG2BIG 12 /* Message to large for buffer */
|
||||
#define EMNOSEND 13 /* Could not send message */
|
||||
#define EMNORECV 14 /* Could not receive message */
|
||||
|
||||
#define EMRESET 15 /* Could not RESET target */
|
||||
#define EMCONFIG 16 /* Could not get target CONFIG */
|
||||
#define EMSTATUS 17 /* Could not get target STATUS */
|
||||
#define EMREAD 18 /* Could not READ target memory */
|
||||
#define EMWRITE 19 /* Could not WRITE target memory */
|
||||
#define EMBKPTSET 20 /* Could not set breakpoint */
|
||||
#define EMBKPTRM 21 /* Could not remove breakpoint */
|
||||
#define EMBKPTSTAT 22 /* Could not get breakpoint status */
|
||||
#define EMBKPTNONE 23 /* All breakpoints in use */
|
||||
#define EMBKPTUSED 24 /* Breakpoints already in use */
|
||||
#define EMCOPY 25 /* Could not COPY target memory */
|
||||
#define EMFILL 26 /* Could not FILL target memory */
|
||||
#define EMINIT 27 /* Could not initialize target memory */
|
||||
#define EMGO 28 /* Could not start execution */
|
||||
#define EMSTEP 29 /* Could not single step */
|
||||
#define EMBREAK 30 /* Could not BREAK */
|
||||
#define EMHIF 31 /* Could not perform HIF service */
|
||||
#define EMCHANNEL0 32 /* Could not read CHANNEL0 */
|
||||
#define EMCHANNEL1 33 /* Could not write CHANNEL1 */
|
||||
|
||||
/* COFF file loader errors */
|
||||
#define EMOPEN 34 /* Could not open COFF file */
|
||||
#define EMHDR 35 /* Could not read COFF header */
|
||||
#define EMMAGIC 36 /* Bad magic number */
|
||||
#define EMAOUT 37 /* Could not read COFF a.out header */
|
||||
#define EMSCNHDR 38 /* Could not read COFF section header */
|
||||
#define EMSCN 39 /* Could not read COFF section */
|
||||
#define EMCLOSE 40 /* Could not close COFF file */
|
||||
|
||||
/* Log file errors */
|
||||
#define EMLOGOPEN 41 /* Could not open log file */
|
||||
#define EMLOGREAD 42 /* Could not read log file */
|
||||
#define EMLOGWRITE 43 /* Could not write to log file */
|
||||
#define EMLOGCLOSE 44 /* Could not close log file */
|
||||
|
||||
/* Command file errors */
|
||||
#define EMCMDOPEN 45 /* Could not open command file */
|
||||
#define EMCMDREAD 46 /* Could not read command file */
|
||||
#define EMCMDWRITE 47 /* Could not write to command file */
|
||||
#define EMCMDCLOSE 48 /* Could not close comand file */
|
||||
|
||||
#define EMTIMEOUT 49 /* Host timed out waiting for a message */
|
||||
#define EMCOMMTYPE 50 /* A '-t' flag must be specified */
|
||||
#define EMCOMMERR 51 /* Communication error */
|
||||
#define EMBAUD 52 /* Invalid baud rate specified */
|
||||
/*
|
||||
* Memory Spaces
|
||||
*/
|
||||
#define LOCAL_REG 0 /* Local processor register */
|
||||
#define GLOBAL_REG 1 /* Global processor register */
|
||||
#define SPECIAL_REG 2 /* Special processor register */
|
||||
#define TLB_REG 3 /* Translation Lookaside Buffer */
|
||||
#define COPROC_REG 4 /* Coprocessor register */
|
||||
#define I_MEM 5 /* Instruction Memory */
|
||||
#define D_MEM 6 /* Data Memory */
|
||||
#define I_ROM 7 /* Instruction ROM */
|
||||
#define D_ROM 8 /* Data ROM */
|
||||
#define I_O 9 /* Input/Output */
|
||||
#define I_CACHE 10 /* Instruction Cache */
|
||||
#define D_CACHE 11 /* Data Cache */
|
||||
|
||||
/* To supress warnings for zero length array definitions */
|
||||
#define DUMMY 1
|
||||
|
||||
/*
|
||||
** Host to target definitions
|
||||
*/
|
||||
|
||||
#define RESET 0
|
||||
#define CONFIG_REQ 1
|
||||
#define STATUS_REQ 2
|
||||
#define READ_REQ 3
|
||||
#define WRITE_REQ 4
|
||||
#define BKPT_SET 5
|
||||
#define BKPT_RM 6
|
||||
#define BKPT_STAT 7
|
||||
#define COPY 8
|
||||
#define FILL 9
|
||||
#define INIT 10
|
||||
#define GO 11
|
||||
#define STEP 12
|
||||
#define BREAK 13
|
||||
|
||||
#define HIF_CALL_RTN 64
|
||||
#define CHANNEL0 65
|
||||
#define CHANNEL1_ACK 66
|
||||
|
||||
|
||||
/*
|
||||
** Target to host definitions
|
||||
*/
|
||||
|
||||
#define RESET_ACK 32
|
||||
#define CONFIG 33
|
||||
#define STATUS 34
|
||||
#define READ_ACK 35
|
||||
#define WRITE_ACK 36
|
||||
#define BKPT_SET_ACK 37
|
||||
#define BKPT_RM_ACK 38
|
||||
#define BKPT_STAT_ACK 39
|
||||
#define COPY_ACK 40
|
||||
#define FILL_ACK 41
|
||||
#define INIT_ACK 42
|
||||
#define HALT 43
|
||||
|
||||
#define ERROR 63
|
||||
|
||||
#define HIF_CALL 96
|
||||
#define CHANNEL0_ACK 97
|
||||
#define CHANNEL1 98
|
||||
|
||||
|
||||
/* A "generic" message */
|
||||
struct generic_msg_t {
|
||||
INT32 code; /* generic */
|
||||
INT32 length;
|
||||
BYTE byte[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
/* A "generic" message (with an INT32 array) */
|
||||
struct generic_int32_msg_t {
|
||||
INT32 code; /* generic */
|
||||
INT32 length;
|
||||
INT32 int32[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Host to target messages
|
||||
*/
|
||||
|
||||
struct reset_msg_t {
|
||||
INT32 code; /* 0 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct config_req_msg_t {
|
||||
INT32 code; /* 1 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct status_req_msg_t {
|
||||
INT32 code; /* 2 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct read_req_msg_t {
|
||||
INT32 code; /* 3 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
};
|
||||
|
||||
|
||||
struct write_req_msg_t {
|
||||
INT32 code; /* 4 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
BYTE data[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
struct write_r_msg_t {
|
||||
INT32 code; /* 4 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
INT32 data[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_set_msg_t {
|
||||
INT32 code; /* 5 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 bkpt_addr;
|
||||
INT32 pass_count;
|
||||
INT32 bkpt_type;
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_rm_msg_t {
|
||||
INT32 code; /* 6 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 bkpt_addr;
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_stat_msg_t {
|
||||
INT32 code; /* 7 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 bkpt_addr;
|
||||
};
|
||||
|
||||
|
||||
struct copy_msg_t {
|
||||
INT32 code; /* 8 */
|
||||
INT32 length;
|
||||
INT32 source_space;
|
||||
ADDR32 source_addr;
|
||||
INT32 dest_space;
|
||||
ADDR32 dest_addr;
|
||||
INT32 byte_count;
|
||||
};
|
||||
|
||||
|
||||
struct fill_msg_t {
|
||||
INT32 code; /* 9 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 start_addr;
|
||||
INT32 fill_count;
|
||||
INT32 byte_count;
|
||||
BYTE fill_data[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
struct init_msg_t {
|
||||
INT32 code; /* 10 */
|
||||
INT32 length;
|
||||
ADDR32 text_start;
|
||||
ADDR32 text_end;
|
||||
ADDR32 data_start;
|
||||
ADDR32 data_end;
|
||||
ADDR32 entry_point;
|
||||
INT32 mem_stack_size;
|
||||
INT32 reg_stack_size;
|
||||
ADDR32 arg_start;
|
||||
INT32 os_control;
|
||||
};
|
||||
|
||||
|
||||
struct go_msg_t {
|
||||
INT32 code; /* 11 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct step_msg_t {
|
||||
INT32 code; /* 12 */
|
||||
INT32 length;
|
||||
INT32 count;
|
||||
};
|
||||
|
||||
|
||||
struct break_msg_t {
|
||||
INT32 code; /* 13 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct hif_call_rtn_msg_t {
|
||||
INT32 code; /* 64 */
|
||||
INT32 length;
|
||||
INT32 service_number;
|
||||
INT32 gr121;
|
||||
INT32 gr96;
|
||||
INT32 gr97;
|
||||
};
|
||||
|
||||
|
||||
struct channel0_msg_t {
|
||||
INT32 code; /* 65 */
|
||||
INT32 length;
|
||||
BYTE data;
|
||||
};
|
||||
|
||||
|
||||
struct channel1_ack_msg_t {
|
||||
INT32 code; /* 66 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Target to host messages
|
||||
*/
|
||||
|
||||
|
||||
struct reset_ack_msg_t {
|
||||
INT32 code; /* 32 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct config_msg_t {
|
||||
INT32 code; /* 33 */
|
||||
INT32 length;
|
||||
INT32 processor_id;
|
||||
INT32 version;
|
||||
ADDR32 I_mem_start;
|
||||
INT32 I_mem_size;
|
||||
ADDR32 D_mem_start;
|
||||
INT32 D_mem_size;
|
||||
ADDR32 ROM_start;
|
||||
INT32 ROM_size;
|
||||
INT32 max_msg_size;
|
||||
INT32 max_bkpts;
|
||||
INT32 coprocessor;
|
||||
INT32 reserved;
|
||||
};
|
||||
|
||||
|
||||
struct status_msg_t {
|
||||
INT32 code; /* 34 */
|
||||
INT32 length;
|
||||
INT32 msgs_sent;
|
||||
INT32 msgs_received;
|
||||
INT32 errors;
|
||||
INT32 bkpts_hit;
|
||||
INT32 bkpts_free;
|
||||
INT32 traps;
|
||||
INT32 fills;
|
||||
INT32 spills;
|
||||
INT32 cycles;
|
||||
INT32 reserved;
|
||||
};
|
||||
|
||||
|
||||
struct read_ack_msg_t {
|
||||
INT32 code; /* 35 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
BYTE data[DUMMY];
|
||||
};
|
||||
|
||||
struct read_r_ack_msg_t {
|
||||
INT32 code; /* 35 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
INT32 data[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
struct write_ack_msg_t {
|
||||
INT32 code; /* 36 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 byte_count;
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_set_ack_msg_t {
|
||||
INT32 code; /* 37 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 pass_count;
|
||||
INT32 bkpt_type;
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_rm_ack_msg_t {
|
||||
INT32 code; /* 38 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
};
|
||||
|
||||
|
||||
struct bkpt_stat_ack_msg_t {
|
||||
INT32 code; /* 39 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
INT32 pass_count;
|
||||
INT32 bkpt_type;
|
||||
};
|
||||
|
||||
|
||||
struct copy_ack_msg_t {
|
||||
INT32 code; /* 40 */
|
||||
INT32 length;
|
||||
INT32 source_space;
|
||||
ADDR32 source_addr;
|
||||
INT32 dest_space;
|
||||
ADDR32 dest_addr;
|
||||
INT32 byte_count;
|
||||
};
|
||||
|
||||
|
||||
struct fill_ack_msg_t {
|
||||
INT32 code; /* 41 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 start_addr;
|
||||
INT32 fill_count;
|
||||
INT32 byte_count;
|
||||
};
|
||||
|
||||
|
||||
struct init_ack_msg_t {
|
||||
INT32 code; /* 42 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct halt_msg_t {
|
||||
INT32 code; /* 43 */
|
||||
INT32 length;
|
||||
INT32 memory_space;
|
||||
ADDR32 pc0;
|
||||
ADDR32 pc1;
|
||||
INT32 trap_number;
|
||||
};
|
||||
|
||||
|
||||
struct error_msg_t {
|
||||
INT32 code; /* 63 */
|
||||
INT32 length;
|
||||
INT32 error_code;
|
||||
INT32 memory_space;
|
||||
ADDR32 address;
|
||||
};
|
||||
|
||||
|
||||
struct hif_call_msg_t {
|
||||
INT32 code; /* 96 */
|
||||
INT32 length;
|
||||
INT32 service_number;
|
||||
INT32 lr2;
|
||||
INT32 lr3;
|
||||
INT32 lr4;
|
||||
};
|
||||
|
||||
|
||||
struct channel0_ack_msg_t {
|
||||
INT32 code; /* 97 */
|
||||
INT32 length;
|
||||
};
|
||||
|
||||
|
||||
struct channel1_msg_t {
|
||||
INT32 code; /* 98 */
|
||||
INT32 length;
|
||||
BYTE data[DUMMY];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Union all of the message types together
|
||||
*/
|
||||
|
||||
union msg_t {
|
||||
struct generic_msg_t generic_msg;
|
||||
struct generic_int32_msg_t generic_int32_msg;
|
||||
|
||||
struct reset_msg_t reset_msg;
|
||||
struct config_req_msg_t config_req_msg;
|
||||
struct status_req_msg_t status_req_msg;
|
||||
struct read_req_msg_t read_req_msg;
|
||||
struct write_req_msg_t write_req_msg;
|
||||
struct write_r_msg_t write_r_msg;
|
||||
struct bkpt_set_msg_t bkpt_set_msg;
|
||||
struct bkpt_rm_msg_t bkpt_rm_msg;
|
||||
struct bkpt_stat_msg_t bkpt_stat_msg;
|
||||
struct copy_msg_t copy_msg;
|
||||
struct fill_msg_t fill_msg;
|
||||
struct init_msg_t init_msg;
|
||||
struct go_msg_t go_msg;
|
||||
struct step_msg_t step_msg;
|
||||
struct break_msg_t break_msg;
|
||||
|
||||
struct hif_call_rtn_msg_t hif_call_rtn_msg;
|
||||
struct channel0_msg_t channel0_msg;
|
||||
struct channel1_ack_msg_t channel1_ack_msg;
|
||||
|
||||
struct reset_ack_msg_t reset_ack_msg;
|
||||
struct config_msg_t config_msg;
|
||||
struct status_msg_t status_msg;
|
||||
struct read_ack_msg_t read_ack_msg;
|
||||
struct read_r_ack_msg_t read_r_ack_msg;
|
||||
struct write_ack_msg_t write_ack_msg;
|
||||
struct bkpt_set_ack_msg_t bkpt_set_ack_msg;
|
||||
struct bkpt_rm_ack_msg_t bkpt_rm_ack_msg;
|
||||
struct bkpt_stat_ack_msg_t bkpt_stat_ack_msg;
|
||||
struct copy_ack_msg_t copy_ack_msg;
|
||||
struct fill_ack_msg_t fill_ack_msg;
|
||||
struct init_ack_msg_t init_ack_msg;
|
||||
struct halt_msg_t halt_msg;
|
||||
|
||||
struct error_msg_t error_msg;
|
||||
|
||||
struct hif_call_msg_t hif_call_msg;
|
||||
struct channel0_ack_msg_t channel0_ack_msg;
|
||||
struct channel1_msg_t channel1_msg;
|
||||
};
|
|
@ -1,270 +0,0 @@
|
|||
/* Remote target glue for the Intel 960 ROM monitor.
|
||||
Copyright 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
#include "srec.h"
|
||||
#include "xmodem.h"
|
||||
|
||||
#if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
|
||||
#define HAVE_SGTTY
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SGTTY
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* Needed by file.h on Sys V */
|
||||
#include <sys/file.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define USE_GENERIC_LOAD
|
||||
|
||||
int quiet = 0; /* 1 => stifle unnecessary messages */
|
||||
serial_t mon960_serial;
|
||||
char *mon960_ttyname; /* name of tty to talk to mon960 on, or null */
|
||||
static struct monitor_ops mon960_cmds;
|
||||
|
||||
#ifdef USE_GENERIC_LOAD
|
||||
extern void generic_load PARAMS ((char* filename, int from_tty));
|
||||
#endif
|
||||
static void mon960_open PARAMS ((char *args, int from_tty));
|
||||
|
||||
#ifdef USE_GENERIC_LOAD
|
||||
static void
|
||||
mon960_load_gen (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
extern int inferior_pid;
|
||||
generic_load (filename, from_tty);
|
||||
/* Finally, make the PC point at the start address */
|
||||
if (exec_bfd)
|
||||
write_pc (bfd_get_start_address (exec_bfd));
|
||||
|
||||
inferior_pid = 0; /* No process now */
|
||||
}
|
||||
|
||||
#else
|
||||
static void
|
||||
mon960_load (desc, file, hashmark)
|
||||
serial_t desc;
|
||||
char *file;
|
||||
int hashmark;
|
||||
{
|
||||
bfd *abfd;
|
||||
asection *s;
|
||||
char *buffer;
|
||||
int i;
|
||||
|
||||
buffer = alloca (XMODEM_PACKETSIZE);
|
||||
abfd = bfd_openr (file, 0);
|
||||
if (!abfd)
|
||||
{
|
||||
printf_filtered ("Unable to open file %s\n", file);
|
||||
return;
|
||||
}
|
||||
if (bfd_check_format (abfd, bfd_object) == 0)
|
||||
{
|
||||
printf_filtered ("File is not an object file\n");
|
||||
return;
|
||||
}
|
||||
for (s = abfd->sections; s; s = s->next)
|
||||
if (s->flags & SEC_LOAD)
|
||||
{
|
||||
bfd_size_type section_size;
|
||||
printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma,
|
||||
s->vma + s->_raw_size);
|
||||
gdb_flush (gdb_stdout);
|
||||
monitor_printf (mon960_cmds.load, s->vma);
|
||||
if (mon960_cmds.loadresp)
|
||||
monitor_expect (mon960_cmds.loadresp, NULL, 0);
|
||||
xmodem_init_xfer (desc);
|
||||
section_size = bfd_section_size (abfd, s);
|
||||
for (i = 0; i < section_size; i += XMODEM_DATASIZE)
|
||||
{
|
||||
int numbytes;
|
||||
numbytes = min (XMODEM_DATASIZE, section_size - i);
|
||||
bfd_get_section_contents (abfd, s, buffer + XMODEM_DATAOFFSET, i,
|
||||
numbytes);
|
||||
xmodem_send_packet (desc, buffer, numbytes, hashmark);
|
||||
if (hashmark)
|
||||
{
|
||||
putchar_unfiltered ('#');
|
||||
gdb_flush (gdb_stdout);
|
||||
}
|
||||
} /* Per-packet (or S-record) loop */
|
||||
xmodem_finish_xfer (desc);
|
||||
monitor_expect_prompt (NULL, 0);
|
||||
putchar_unfiltered ('\n');
|
||||
} /* Loadable sections */
|
||||
if (hashmark)
|
||||
putchar_unfiltered ('\n');
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This array of registers need to match the indexes used by GDB.
|
||||
This exists because the various ROM monitors use different strings
|
||||
than does GDB, and don't necessarily support all the registers
|
||||
either. So, typing "info reg sp" becomes a "r30". */
|
||||
|
||||
/* these correspond to the offsets from tm-* files from config directories */
|
||||
/* g0-g14, fp, pfp, sp, rip,r3-15, pc, ac, tc, fp0-3 */
|
||||
/* NOTE: "ip" is documented as "ir" in the Mon960 UG. */
|
||||
/* NOTE: "ir" can't be accessed... but there's an ip and rip. */
|
||||
static char *mon960_regnames[NUM_REGS] = {
|
||||
/* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7", \
|
||||
/* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",\
|
||||
/* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", \
|
||||
/* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp", \
|
||||
/* 32 */ "pc", "ac", "tc", "ip", "fp0", "fp1", "fp2", "fp3",\
|
||||
};
|
||||
|
||||
/* Define the monitor command strings. Since these are passed directly
|
||||
through to a printf style function, we may include formatting
|
||||
strings. We also need a CR or LF on the end. */
|
||||
|
||||
static struct target_ops mon960_ops;
|
||||
|
||||
/* need to pause the monitor for timing reasons, so slow it down */
|
||||
static char *mon960_inits[] = {"\n\r\r\r\r\r\r\r\r\r\r\r\r\r\r\n\r\n\r\n", NULL}; /* Exits sub-command mode & download cmds */
|
||||
|
||||
static struct monitor_ops mon960_cmds =
|
||||
{
|
||||
MO_CLR_BREAK_USES_ADDR
|
||||
| MO_NO_ECHO_ON_OPEN
|
||||
| MO_SEND_BREAK_ON_STOP
|
||||
| MO_GETMEM_READ_SINGLE, /* flags */
|
||||
mon960_inits, /* Init strings */
|
||||
"go\n\r", /* continue command */
|
||||
"st\n\r", /* single step */
|
||||
"\n\r", /* break interrupts the program */
|
||||
NULL, /* set a breakpoint */
|
||||
/* can't use "br" because only 2 hw bps are supported */
|
||||
NULL, /* clear a breakpoint - "de" is for hw bps */
|
||||
NULL, /* clear all breakpoints */
|
||||
NULL, /* fill (start end val) */
|
||||
/* can't use "fi" because it takes words, not bytes */
|
||||
{
|
||||
/* can't use "mb", "md" or "mo" because they require interaction */
|
||||
NULL, /* setmem.cmdb (addr, value) */
|
||||
"md %x %x\n\r", /* setmem.cmdw (addr, value) */
|
||||
NULL, /* setmem.cmdl (addr, value) */
|
||||
NULL, /* setmem.cmdll (addr, value) */
|
||||
NULL, /* setmem.resp_delim */
|
||||
NULL, /* setmem.term */
|
||||
NULL, /* setmem.term_cmd */
|
||||
},
|
||||
{
|
||||
/* since the parsing of multiple bytes is difficult due to
|
||||
interspersed addresses, we'll only read 1 value at a time,
|
||||
even tho these can handle a count */
|
||||
"db %x\n\r", /* getmem.cmdb (addr, #bytes) */
|
||||
"ds %x\n\r", /* getmem.cmdw (addr, #swords) */
|
||||
"di %x\n\r", /* getmem.cmdl (addr, #words) */
|
||||
"dd %x\n\r", /* getmem.cmdll (addr, #dwords) */
|
||||
" : ", /* getmem.resp_delim */
|
||||
NULL, /* getmem.term */
|
||||
NULL, /* getmem.term_cmd */
|
||||
},
|
||||
{
|
||||
"md %s %x\n\r", /* setreg.cmd (name, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"di %s\n\r", /* getreg.cmd (name) */
|
||||
" : ", /* getreg.resp_delim */
|
||||
NULL, /* getreg.term */
|
||||
NULL, /* getreg.term_cmd */
|
||||
},
|
||||
"re\n\r", /* dump_registers */
|
||||
"\\(\\w+\\)=\\([0-9a-fA-F]+\\)", /* register_pattern */
|
||||
NULL, /* supply_register */
|
||||
#ifdef USE_GENERIC_LOAD
|
||||
NULL, /* load_routine (defaults to SRECs) */
|
||||
NULL, /* download command */
|
||||
NULL, /* load response */
|
||||
#else
|
||||
mon960_load, /* load_routine (defaults to SRECs) */
|
||||
"do\n\r", /* download command */
|
||||
"Downloading\n\r", /* load response */
|
||||
#endif
|
||||
"=>", /* monitor command prompt */
|
||||
"\n\r", /* end-of-command delimitor */
|
||||
NULL, /* optional command terminator */
|
||||
&mon960_ops, /* target operations */
|
||||
SERIAL_1_STOPBITS, /* number of stop bits */
|
||||
mon960_regnames, /* registers names */
|
||||
MONITOR_OPS_MAGIC /* magic */
|
||||
};
|
||||
|
||||
/* invoked from monitor.c - opens the serial port */
|
||||
static void
|
||||
mon960_open (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
char *serial_port_name = args;
|
||||
if (args)
|
||||
{
|
||||
char *cursor = serial_port_name = strsave (args);
|
||||
|
||||
while (*cursor && *cursor != ' ')
|
||||
cursor++;
|
||||
|
||||
if (*cursor)
|
||||
*cursor++ = 0;
|
||||
|
||||
while (*cursor == ' ')
|
||||
cursor++;
|
||||
|
||||
}
|
||||
monitor_open (serial_port_name, &mon960_cmds, from_tty);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_initialize_mon960 ()
|
||||
{
|
||||
init_monitor_ops (&mon960_ops);
|
||||
|
||||
mon960_ops.to_shortname = "mon960"; /* for the target command */
|
||||
mon960_ops.to_longname = "Intel 960 rom monitor";
|
||||
#ifdef USE_GENERIC_LOAD
|
||||
mon960_ops.to_load = mon960_load_gen; /* FIXME - should go back and try "do" */
|
||||
#endif
|
||||
/* use SW breaks; target only supports 2 HW breakpoints */
|
||||
mon960_ops.to_insert_breakpoint = memory_insert_breakpoint;
|
||||
mon960_ops.to_remove_breakpoint = memory_remove_breakpoint;
|
||||
|
||||
mon960_ops.to_doc =
|
||||
"Debug on an Intel 960 eval board running the Mon960 rom monitor.\n"
|
||||
"Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
|
||||
mon960_ops.to_open = mon960_open;
|
||||
add_target (&mon960_ops);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,177 +0,0 @@
|
|||
/* Remote debugging interface ROM monitors.
|
||||
* Copyright 1990, 1991, 1992, 1996 Free Software Foundation, Inc.
|
||||
* Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
|
||||
*
|
||||
* This file is part of GDB.
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
/* This structure describes the strings necessary to give small command
|
||||
sequences to the monitor, and parse the response.
|
||||
|
||||
CMD is the actual command typed at the monitor. Usually this has embedded
|
||||
sequences ala printf, which are substituted with the arguments appropriate
|
||||
to that type of command. Ie: to examine a register, we substitute the
|
||||
register name for the first arg. To modify memory, we substitute the memory
|
||||
location and the new contents for the first and second args, etc...
|
||||
|
||||
RESP_DELIM used to home in on the response string, and is used to
|
||||
disambiguate the answer within the pile of text returned by the monitor.
|
||||
This should be a unique string that immediately precedes the answer. Ie: if
|
||||
your monitor prints out `PC: 00000001= ' in response to asking for the PC,
|
||||
you should use `: ' as the RESP_DELIM. RESP_DELIM may be NULL if the res-
|
||||
ponse is going to be ignored, or has no particular leading text.
|
||||
|
||||
TERM is the string that the monitor outputs to indicate that it is idle, and
|
||||
waiting for input. This is usually a prompt of some sort. In the previous
|
||||
example, it would be `= '. It is important that TERM really means that the
|
||||
monitor is idle, otherwise GDB may try to type at it when it isn't ready for
|
||||
input. This is a problem because many monitors cannot deal with type-ahead.
|
||||
TERM may be NULL if the normal prompt is output.
|
||||
|
||||
TERM_CMD is used to quit out of the subcommand mode and get back to the main
|
||||
prompt. TERM_CMD may be NULL if it isn't necessary. It will also be
|
||||
ignored if TERM is NULL.
|
||||
*/
|
||||
|
||||
struct memrw_cmd
|
||||
{
|
||||
char *cmdb; /* Command to send for byte read/write */
|
||||
char *cmdw; /* Command for word (16 bit) read/write */
|
||||
char *cmdl; /* Command for long (32 bit) read/write */
|
||||
char *cmdll; /* Command for long long (64 bit) read/write */
|
||||
char *resp_delim; /* String just prior to the desired value */
|
||||
char *term; /* Terminating string to search for */
|
||||
char *term_cmd; /* String to get out of sub-mode (if necessary) */
|
||||
};
|
||||
|
||||
struct regrw_cmd
|
||||
{
|
||||
char *cmd; /* Command to send for reg read/write */
|
||||
char *resp_delim; /* String (actually a regexp if getmem) just
|
||||
prior to the desired value */
|
||||
char *term; /* Terminating string to search for */
|
||||
char *term_cmd; /* String to get out of sub-mode (if necessary) */
|
||||
};
|
||||
|
||||
struct monitor_ops
|
||||
{
|
||||
int flags; /* See below */
|
||||
char **init; /* List of init commands. NULL terminated. */
|
||||
char *cont; /* continue command */
|
||||
char *step; /* single step */
|
||||
char *stop; /* Interrupt program string */
|
||||
char *set_break; /* set a breakpoint */
|
||||
char *clr_break; /* clear a breakpoint */
|
||||
char *clr_all_break; /* Clear all breakpoints */
|
||||
char *fill; /* Memory fill cmd (addr len val) */
|
||||
struct memrw_cmd setmem; /* set memory to a value */
|
||||
struct memrw_cmd getmem; /* display memory */
|
||||
struct regrw_cmd setreg; /* set a register */
|
||||
struct regrw_cmd getreg; /* get a register */
|
||||
/* Some commands can dump a bunch of registers
|
||||
at once. This comes as a set of REG=VAL
|
||||
pairs. This should be called for each pair
|
||||
of registers that we can parse to supply
|
||||
GDB with the value of a register. */
|
||||
char *dump_registers; /* Command to dump all regs at once */
|
||||
char *register_pattern; /* Pattern that picks out register from reg dump */
|
||||
void (*supply_register) PARAMS ((char *name, int namelen, char *val, int vallen));
|
||||
void (*load_routine) PARAMS ((serial_t desc, char *file, int hashmark)); /* Download routine */
|
||||
char *load; /* load command */
|
||||
char *loadresp; /* Response to load command */
|
||||
char *prompt; /* monitor command prompt */
|
||||
char *line_term; /* end-of-command delimitor */
|
||||
char *cmd_end; /* optional command terminator */
|
||||
struct target_ops *target; /* target operations */
|
||||
int stopbits; /* number of stop bits */
|
||||
char **regnames; /* array of register names in ascii */
|
||||
int magic; /* Check value */
|
||||
};
|
||||
|
||||
#define MONITOR_OPS_MAGIC 600925
|
||||
|
||||
/* Flag defintions */
|
||||
|
||||
#define MO_CLR_BREAK_USES_ADDR 0x1 /* If set, then clear breakpoint command
|
||||
uses address, otherwise it uses an index
|
||||
returned by the monitor. */
|
||||
#define MO_FILL_USES_ADDR 0x2 /* If set, then memory fill command uses
|
||||
STARTADDR, ENDADDR+1, VALUE as args, else it
|
||||
uses STARTADDR, LENGTH, VALUE as args. */
|
||||
#define MO_NEED_REGDUMP_AFTER_CONT 0x4 /* If set, then monitor doesn't auto-
|
||||
matically supply register dump when
|
||||
coming back after a continue. */
|
||||
#define MO_GETMEM_NEEDS_RANGE 0x8 /* getmem needs start addr and end addr */
|
||||
#define MO_GETMEM_READ_SINGLE 0x10 /* getmem can only read one loc at a time */
|
||||
#define MO_HANDLE_NL 0x20 /* handle \r\n combinations */
|
||||
|
||||
#define MO_NO_ECHO_ON_OPEN 0x40 /* don't expect echos in monitor_open */
|
||||
|
||||
#define MO_SEND_BREAK_ON_STOP 0x80 /* If set, send break to stop monitor */
|
||||
|
||||
extern struct monitor_ops *current_monitor;
|
||||
|
||||
#define LOADTYPES (current_monitor->loadtypes)
|
||||
#define LOADPROTOS (current_monitor->loadprotos)
|
||||
#define INIT_CMD (current_monitor->init)
|
||||
#define CONT_CMD (current_monitor->cont)
|
||||
#define STEP_CMD (current_monitor->step)
|
||||
#define SET_BREAK_CMD (current_monitor->set_break)
|
||||
#define CLR_BREAK_CMD (current_monitor->clr_break)
|
||||
#define SET_MEM (current_monitor->setmem)
|
||||
#define GET_MEM (current_monitor->getmem)
|
||||
#define LOAD_CMD (current_monitor->load)
|
||||
#define GET_REG (current_monitor->regget)
|
||||
#define SET_REG (current_monitor->regset)
|
||||
#define CMD_END (current_monitor->cmd_end)
|
||||
#define CMD_DELIM (current_monitor->cmd_delim)
|
||||
#define PROMPT (current_monitor->prompt)
|
||||
#define TARGET_OPS (current_monitor->target)
|
||||
#define TARGET_NAME (current_monitor->target->to_shortname)
|
||||
#define BAUDRATES (current_monitor->baudrates)
|
||||
#define STOPBITS (current_monitor->stopbits)
|
||||
#define REGNAMES(x) (current_monitor->regnames[x])
|
||||
#define ROMCMD(x) (x.cmd)
|
||||
#define ROMDELIM(x) (x.delim)
|
||||
#define ROMRES(x) (x.result)
|
||||
|
||||
#define push_monitor(x) current_monitor = x;
|
||||
|
||||
#define SREC_SIZE 160
|
||||
|
||||
/*
|
||||
* FIXME: These are to temporarily maintain compatability with the
|
||||
* old monitor structure till remote-mon.c is fixed to work
|
||||
* like the *-rom.c files.
|
||||
*/
|
||||
#define MEM_PROMPT (current_monitor->loadtypes)
|
||||
#define MEM_SET_CMD (current_monitor->setmem)
|
||||
#define MEM_DIS_CMD (current_monitor->getmem)
|
||||
#define REG_DELIM (current_monitor->regset.delim)
|
||||
|
||||
extern void monitor_open PARAMS ((char *args, struct monitor_ops *ops, int from_tty));
|
||||
extern void monitor_close PARAMS ((int quitting));
|
||||
extern char *monitor_supply_register PARAMS ((int regno, char *valstr));
|
||||
extern int monitor_expect PARAMS ((char *prompt, char *buf, int buflen));
|
||||
extern int monitor_expect_prompt PARAMS ((char *buf, int buflen));
|
||||
extern void monitor_printf PARAMS ((char *, ...))
|
||||
ATTR_FORMAT(printf, 1, 2);
|
||||
extern void monitor_printf_noecho PARAMS ((char *, ...))
|
||||
ATTR_FORMAT(printf, 1, 2);
|
||||
extern void init_monitor_ops PARAMS ((struct target_ops *));
|
|
@ -1,82 +0,0 @@
|
|||
# Configuration fragment for GDB.
|
||||
|
||||
If "{host_canonical}" =~ /m68k-apple-mpw/
|
||||
forward-include "{srcdir}"config:m68k:xm-mpw.h xm.h
|
||||
Set siow_lib '"{Libraries}"SIOW.o'
|
||||
|
||||
Else If "{host_canonical}" =~ /powerpc-apple-mpw/
|
||||
forward-include "{srcdir}"config:powerpc:xm-mpw.h xm.h
|
||||
Set siow_lib '"{PPCLibraries}"PPCSIOW.o'
|
||||
|
||||
End If
|
||||
|
||||
Set xdepfiles '"{o}"mac-xdep.c.o'
|
||||
|
||||
Set enable_cflags ""
|
||||
|
||||
# Make a copy of this file and give it a different name, so it
|
||||
# won't be confused with GDB's serial.h.
|
||||
|
||||
Duplicate -y "{CIncludes}"Serial.h MacSerial.h
|
||||
|
||||
Echo "/* dummy */" >termio.h
|
||||
|
||||
If "{target_canonical}" =~ /m68k-apple-macos/
|
||||
forward-include "{srcdir}"config:m68k:tm-mac.h tm.h
|
||||
forward-include "{srcdir}"config:m68k:tm-m68k.h 'm68k/tm-m68k.h'
|
||||
Set tdepfiles '"{o}"m68k-tdep.c.o'
|
||||
|
||||
Else If "{target_canonical}" =~ /powerpc-apple-macos/
|
||||
forward-include "{srcdir}"config:powerpc:tm-macos.h tm.h
|
||||
forward-include "{srcdir}"config:rs6000:tm-rs6000.h 'rs6000/tm-rs6000.h'
|
||||
Set tdepfiles '"{o}"rs6000-tdep.c.o "{o}"xcoffread.c.o'
|
||||
|
||||
Else If "{target_canonical}" =~ /i386-unknown-go32/
|
||||
forward-include "{srcdir}"config:i386:tm-i386v.h tm.h
|
||||
Set tdepfiles '"{o}"i386-tdep.c.o'
|
||||
|
||||
Else If "{target_canonical}" =~ /mips-idt-ecoff/
|
||||
forward-include "{srcdir}"config:mips:tm-embed.h tm.h
|
||||
forward-include "{srcdir}"config:mips:tm-bigmips.h 'mips/tm-bigmips.h'
|
||||
forward-include "{srcdir}"config:mips:tm-mips.h 'mips/tm-mips.h'
|
||||
Set tdepfiles '"{o}"mips-tdep.c.o "{o}"remote-mips.c.o'
|
||||
|
||||
|
||||
Else If "{target_canonical}" =~ /sh-hitachi-hms/
|
||||
forward-include "{srcdir}"config:sh:tm-sh.h tm.h
|
||||
Set tdepfiles '"{o}"sh-tdep.c.o'
|
||||
|
||||
End If
|
||||
|
||||
If "{target_canonical}" =~ /m68k-apple-macos/
|
||||
forward-include "{srcdir}"config:m68k:nm-macos.h nm.h
|
||||
Set natdepfiles '"{o}"mac-nat.c.o'
|
||||
|
||||
Else If "{target_canonical}" =~ /powerpc-apple-macos/
|
||||
forward-include "{srcdir}"config:powerpc:nm-macos.h nm.h
|
||||
Set natdepfiles '"{o}"mac-nat.c.o'
|
||||
|
||||
Else
|
||||
forward-include "{srcdir}"config:nm-empty.h nm.h
|
||||
Set natdepfiles ' '
|
||||
|
||||
End If
|
||||
|
||||
Echo '# From mpw-config.in' > "{o}"mk.tmp
|
||||
Echo "TDEPFILES = " {tdepfiles} >> "{o}"mk.tmp
|
||||
Echo "XDEPFILES = " {xdepfiles} >> "{o}"mk.tmp
|
||||
Echo "NATDEPFILES = " {natdepfiles} >> "{o}"mk.tmp
|
||||
Echo "XM_ADD_FILES = " >> "{o}"mk.tmp
|
||||
Echo "TM_ADD_FILES = " >> "{o}"mk.tmp
|
||||
Echo "NAT_ADD_FILES = " >> "{o}"mk.tmp
|
||||
Echo "XM_CDEPS = " >> "{o}"mk.tmp
|
||||
Echo "TM_CDEPS = " >> "{o}"mk.tmp
|
||||
Echo "NAT_CDEPS = " >> "{o}"mk.tmp
|
||||
Echo "SIOW_LIB = " {siow_lib} >> "{o}"mk.tmp
|
||||
Echo "ENABLE_CFLAGS = " {enable_cflags} >> "{o}"mk.tmp
|
||||
Echo '# End from mpw-config.in' >> "{o}"mk.tmp
|
||||
|
||||
Echo '/* config.h. Generated by mpw-configure. */' > "{o}"config.new
|
||||
Echo '#include "mpw.h"' >> "{o}"config.new
|
||||
|
||||
MoveIfChange "{o}"config.new "{o}"config.h
|
|
@ -1,167 +0,0 @@
|
|||
# Sed commands that finish translating the GDB Unix Makefile to MPW syntax.
|
||||
|
||||
/^host_alias =/s/^/#/
|
||||
/^target_alias =/s/^/#/
|
||||
|
||||
/^host_makefile_frag@$/d
|
||||
/^target_makefile_frag@$/d
|
||||
|
||||
/@ENABLE_CFLAGS@/s/@ENABLE_CFLAGS@/{ENABLE_CFLAGS}/g
|
||||
/^ENABLE_CFLAGS=/s/^/#/
|
||||
|
||||
# Edit all the symbolic definitions pointing to various libraries and such.
|
||||
|
||||
/^INCLUDE_DIR = /s/"{srcdir}":include/"{topsrcdir}"include:/
|
||||
|
||||
/^MMALLOC_DIR = /s/::mmalloc/mmalloc:/
|
||||
/^MMALLOC_SRC = /s/"{srcdir}"/"{topsrcdir}"/
|
||||
/^MMALLOC =/s/=.*$/=/
|
||||
/#MMALLOC_DISABLE/s/^#//
|
||||
|
||||
/^BFD_DIR = /s/::bfd/bfd:/
|
||||
/^BFD = /s/{BFD_DIR}:libbfd/{BFD_DIR}libbfd/
|
||||
/^BFD_SRC = /s/"{srcdir}"/"{topsrcdir}"/
|
||||
|
||||
/^READLINE_DIR = /s/::readline/readline:/
|
||||
/^READLINE =/s/=.*$/=/
|
||||
/^READLINE_SRC = /s/"{srcdir}"/"{topsrcdir}"/
|
||||
|
||||
/^INCLUDE_CFLAGS = /s/$/ -i "{topsrcdir}"include:mpw: -i ::extra-include:/
|
||||
|
||||
/^SER_HARDWIRE =/s/ser-unix/ser-mac/
|
||||
|
||||
/^TERMCAP =/s/ =.*$/ =/
|
||||
|
||||
/@DEFS@/s/@DEFS@//g
|
||||
|
||||
/@YACC@/s/@YACC@/byacc/g
|
||||
|
||||
/@ENABLE_OBS@/s/@ENABLE_OBS@//g
|
||||
|
||||
/@ENABLE_CLIBS@/s/@ENABLE_CLIBS@//g
|
||||
|
||||
/@LIBS@/s/@LIBS@//g
|
||||
|
||||
/INCLUDE_DIR/s/"{s}"{INCLUDE_DIR}/{INCLUDE_DIR}/g
|
||||
/INCLUDE_DIR/s/{INCLUDE_DIR}:/{INCLUDE_DIR}/g
|
||||
/INCLUDE_DIR/s/"{INCLUDE_DIR}":/"{INCLUDE_DIR}"/g
|
||||
|
||||
/{BFD_DIR}/s/"{BFD_DIR}":/"{BFD_DIR}"/g
|
||||
/{BFD_DIR}/s/\([ ]\){BFD_DIR}/\1::{BFD_DIR}/g
|
||||
/{BFD_DIR}/s/\([ ]\)"{BFD_DIR}"/\1::"{BFD_DIR}"/g
|
||||
|
||||
/{BFD_SRC}/s/"{s}"{BFD_SRC}/{BFD_SRC}/g
|
||||
/{BFD_SRC}/s/{BFD_SRC}:/{BFD_SRC}/g
|
||||
|
||||
/{READLINE_SRC}/s/"{s}"{READLINE_SRC}/{READLINE_SRC}/g
|
||||
|
||||
/^readline_headers =/,/^$/c\
|
||||
readline_headers =\
|
||||
|
||||
|
||||
/{MMALLOC_CHECK}/s/{MMALLOC_CHECK}//g
|
||||
|
||||
# This isn't really useful, and seems to cause nonsensical complaints.
|
||||
/{ALLDEPFILES}/s/{ALLDEPFILES}//g
|
||||
|
||||
/^copying.c \\Option-f /,/^$/d
|
||||
|
||||
# Fix the syntax of bits of C code that go into version.c.
|
||||
/char /s/'char .Option-x/'char */
|
||||
|
||||
/version/s/"{s}"version\.c/"{o}"version.c/g
|
||||
/version/s/^version\.c/"{o}"version.c/
|
||||
/config/s/"{s}"config\.h/"{o}"config.h/g
|
||||
/config/s/^config\.h/"{o}"config.h/
|
||||
/xm/s/"{s}"xm\.h/"{o}"xm.h/g
|
||||
/xm/s/^xm\.h/"{o}"xm.h/
|
||||
/tm/s/"{s}"tm\.h/"{o}"tm.h/g
|
||||
/tm/s/^tm\.h/"{o}"tm.h/
|
||||
/nm/s/"{s}"nm\.h/"{o}"nm.h/g
|
||||
/nm/s/^nm\.h/"{o}"nm.h/
|
||||
|
||||
/exp.tab.c/s/"{s}"\([a-z0-9]*\)-exp\.tab\.c/"{o}"\1-exp.tab.c/g
|
||||
/exp.tab.c/s/^\([a-z0-9]*\)-exp\.tab\.c/"{o}"\1-exp.tab.c/
|
||||
|
||||
/y.tab/s/"{s}"y.tab\.c/"{o}"y.tab.c/g
|
||||
/y.tab/s/^y.tab\.c/"{o}"y.tab.c/
|
||||
|
||||
/init/s/"{s}"init\.c-tmp/"{o}"init.c-tmp/g
|
||||
/init/s/^init\.c-tmp/"{o}"init.c-tmp/
|
||||
/init/s/"{s}"init\.c/"{o}"init.c/g
|
||||
/init/s/^init\.c/"{o}"init.c/
|
||||
|
||||
/"{o}"version.c \\Option-f Makefile/,/^$/c\
|
||||
"{o}"version.c \\Option-f Makefile\
|
||||
echo -n 'char *version = "' >"{o}"version.c\
|
||||
echo -n "{VERSION}" >>"{o}"version.c\
|
||||
echo '";' >>"{o}"version.c\
|
||||
echo -n 'char *host_name = "' >>"{o}"version.c\
|
||||
echo -n "{host_alias}" >>"{o}"version.c\
|
||||
echo '";' >>"{o}"version.c\
|
||||
echo -n 'char *target_name = "' >>"{o}"version.c\
|
||||
echo -n "{target_alias}" >>"{o}"version.c\
|
||||
echo '";' >>"{o}"version.c\
|
||||
|
||||
|
||||
# Open-brace in a command causes much confusion; replace with the
|
||||
# result from a script.
|
||||
/initialize_all_files ()/c\
|
||||
Echo -n 'void initialize_all_files () ' >> "{o}"init.c-tmp\
|
||||
open-brace >> "{o}"init.c-tmp
|
||||
|
||||
# Replace the whole sed bit for init.c; it's simpler that way...
|
||||
/filename=`echo $i | sed/,/esac/c\
|
||||
set filename "`Echo {i} | sed \\Option-d\
|
||||
-e '/^Onindy.c.o/d' \\Option-d\
|
||||
-e '/^nindy.c.o/d' \\Option-d\
|
||||
-e '/ttyflush.c.o/d' \\Option-d\
|
||||
-e '/xdr_ld.c.o/d' \\Option-d\
|
||||
-e '/xdr_ptrace.c.o/d' \\Option-d\
|
||||
-e '/xdr_rdb.c.o/d' \\Option-d\
|
||||
-e '/udr.c.o/d' \\Option-d\
|
||||
-e '/udip2soc.c.o/d' \\Option-d\
|
||||
-e '/udi2go32.c.o/d' \\Option-d\
|
||||
-e '/version.c.o/d' \\Option-d\
|
||||
-e '/[a-z0-9A-Z_]*-exp.tab.c.o/d' \\Option-d\
|
||||
-e 's/\\.c\\.o/.c/' \\Option-d\
|
||||
-e 's/^://'`"\
|
||||
If "{filename}" != ""\
|
||||
sed <"{s}""{filename}" >>"{o}"init.c-tmp -n \\Option-d\
|
||||
-e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\\([a-z_0-9A-Z]*\\).*/ {extern void \\1 (); \\1 ();}/p'\
|
||||
End If
|
||||
|
||||
# Fix the main compile/link command.
|
||||
/{CC_LD} {INTERNAL_LDFLAGS} -o gdb/,/"{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {LOADLIBES}/c\
|
||||
{CC_LD} {INTERNAL_LDFLAGS} -o gdb{PROG_EXT} "{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {LOADLIBES} {EXTRALIBS}\
|
||||
{MAKEPEF} gdb{PROG_EXT} -o gdb {MAKEPEF_TOOL_FLAGS} {MAKEPEF_FLAGS}\
|
||||
{REZ} "{s}"mac-gdb.r -o gdb -append -d PROG_NAME='"'gdb'"' -d VERSION_STRING='"'{version}'"'\
|
||||
|
||||
/^install \\Option-f /,/^$/c\
|
||||
install \\Option-f all install-only\
|
||||
\
|
||||
install-only \\Option-f \
|
||||
Duplicate -y gdb "{bindir}"gdb\
|
||||
If "`Exists SiowGDB`" != ""\
|
||||
Duplicate -y SiowGDB "{bindir}"SiowGDB\
|
||||
End If\
|
||||
|
||||
|
||||
# Don't do any recursive subdir stuff.
|
||||
/ subdir_do/s/{MAKE}/null-command/
|
||||
|
||||
# Edit out actions that only confuse MPW Make.
|
||||
/^config.status \\Option-f/,/^$/d
|
||||
/^Makefile \\Option-f/,/^$/d
|
||||
|
||||
/^"{o}"config.h \\Option-f/s/^/#/
|
||||
|
||||
# Add an action to build SIOWgdb.
|
||||
$a\
|
||||
SIOWgdb \\Option-f {OBS} {TSOBS} {ADD_DEPS} {CDEPS} "{o}"init.c.o\
|
||||
Delete -i -y SIOWgdb\
|
||||
{CC_LD} {INTERNAL_LDFLAGS} -t 'APPL' -c 'gdb ' -o SIOWgdb{PROG_EXT} "{o}"init.c.o {OBS} {TSOBS} {ADD_FILES} {CLIBS} {SIOW_LIB} {LOADLIBES} {EXTRALIBS}\
|
||||
{MAKEPEF} SIOWgdb{PROG_EXT} -o SIOWgdb -ft 'APPL' -fc 'gdb ' {MAKEPEF_FLAGS} \
|
||||
{REZ} -o SIOWgdb "{RIncludes}"siow.r -append -d __kPrefSize=5000 -d __kMinSize=2000 -d APPNAME='"'SIOWgdb'"' \
|
||||
{REZ} "{s}"mac-gdb.r -o SIOWgdb -append -d VERSION_STRING='"'{version}'"'\
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* Bad implement execle(3). It's depend for "/bin/cc".
|
||||
|
||||
main()
|
||||
{
|
||||
printf("execle:\n");
|
||||
execle(FILE, ARGS, envp);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
GCC:
|
||||
link a6,#0
|
||||
pea LC5 ; call printf
|
||||
jbsr _printf
|
||||
; ; (not popd stack)
|
||||
pea _envp ; call execle
|
||||
clrl sp@-
|
||||
pea LC4
|
||||
pea LC4
|
||||
pea LC4
|
||||
pea LC3
|
||||
pea LC6
|
||||
jbsr _execle
|
||||
addw #32,sp ; delayed pop !!
|
||||
|
||||
/bin/cc:
|
||||
link.l fp,#L23
|
||||
movem.l #L24,(sp)
|
||||
pea L26 ; call printf
|
||||
jbsr _printf
|
||||
addq.l #4,sp ; <--- popd stack !!
|
||||
pea _envp ; call execle
|
||||
clr.l -(sp)
|
||||
pea L32
|
||||
|
||||
*/
|
||||
|
||||
execle(name, args)
|
||||
char *name, *args;
|
||||
{
|
||||
register char **env = &args;
|
||||
while (*env++)
|
||||
;
|
||||
execve(name, (char **)&args, (char **)*env);
|
||||
}
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
/* Target-machine dependent code for the NINDY monitor running on the Intel 960
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
Contributed by Intel Corporation.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Miscellaneous NINDY-dependent routines.
|
||||
Some replace macros normally defined in "tm.h". */
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
|
||||
/* 'start_frame' is a variable in the NINDY runtime startup routine
|
||||
that contains the frame pointer of the 'start' routine (the routine
|
||||
that calls 'main'). By reading its contents out of remote memory,
|
||||
we can tell where the frame chain ends: backtraces should halt before
|
||||
they display this frame. */
|
||||
|
||||
int
|
||||
nindy_frame_chain_valid (chain, curframe)
|
||||
unsigned int chain;
|
||||
struct frame_info *curframe;
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct minimal_symbol *msymbol;
|
||||
|
||||
/* crtnindy.o is an assembler module that is assumed to be linked
|
||||
* first in an i80960 executable. It contains the true entry point;
|
||||
* it performs startup up initialization and then calls 'main'.
|
||||
*
|
||||
* 'sf' is the name of a variable in crtnindy.o that is set
|
||||
* during startup to the address of the first frame.
|
||||
*
|
||||
* 'a' is the address of that variable in 80960 memory.
|
||||
*/
|
||||
static char sf[] = "start_frame";
|
||||
CORE_ADDR a;
|
||||
|
||||
|
||||
chain &= ~0x3f; /* Zero low 6 bits because previous frame pointers
|
||||
contain return status info in them. */
|
||||
if ( chain == 0 ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
sym = lookup_symbol(sf, 0, VAR_NAMESPACE, (int *)NULL,
|
||||
(struct symtab **)NULL);
|
||||
if ( sym != 0 ){
|
||||
a = SYMBOL_VALUE (sym);
|
||||
} else {
|
||||
msymbol = lookup_minimal_symbol (sf, NULL, NULL);
|
||||
if (msymbol == NULL)
|
||||
return 0;
|
||||
a = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
}
|
||||
|
||||
return ( chain != read_memory_integer(a,4) );
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/* Print NS 32000 instructions for GDB, the GNU debugger.
|
||||
Copyright 1986, 1988, 1991, 1992, 1994, 1995
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
void
|
||||
_initialize_ns32k_tdep ()
|
||||
{
|
||||
tm_print_insn = print_insn_ns32k;
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
/* Low level interface to ns532 running mach 3.0.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mach.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/exception.h>
|
||||
#include <mach_error.h>
|
||||
|
||||
#define private static
|
||||
|
||||
|
||||
/* Find offsets to thread states at compile time.
|
||||
* If your compiler does not grok this, calculate offsets
|
||||
* offsets yourself and use them (or get a compatible compiler :-)
|
||||
*/
|
||||
|
||||
#define REG_N_OFFSET(reg) (int)(&((struct ns532_combined_state *)0)->ts.reg)
|
||||
#define REG_F_OFFSET(reg) (int)(&((struct ns532_combined_state *)0)->fs.reg)
|
||||
|
||||
/* at reg_offset[i] is the offset to the ns532_combined_state
|
||||
* location where the gdb registers[i] is stored.
|
||||
*/
|
||||
|
||||
static int reg_offset[] =
|
||||
{
|
||||
REG_N_OFFSET(r0), REG_N_OFFSET(r1), REG_N_OFFSET(r2), REG_N_OFFSET(r3),
|
||||
REG_N_OFFSET(r4), REG_N_OFFSET(r5), REG_N_OFFSET(r6), REG_N_OFFSET(r7),
|
||||
REG_F_OFFSET(l0a), REG_F_OFFSET(l1a),REG_F_OFFSET(l2a),REG_F_OFFSET(l3a),
|
||||
REG_F_OFFSET(l4a), REG_F_OFFSET(l5a),REG_F_OFFSET(l6a),REG_F_OFFSET(l7a),
|
||||
REG_N_OFFSET(sp), REG_N_OFFSET(fp), REG_N_OFFSET(pc), REG_N_OFFSET(psr),
|
||||
REG_F_OFFSET(fsr),
|
||||
REG_F_OFFSET(l0a), REG_F_OFFSET(l2a),REG_F_OFFSET(l4a),REG_F_OFFSET(l6a)
|
||||
/* @@@ 532 has more double length floating point regs, not accessed currently */
|
||||
};
|
||||
|
||||
/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
|
||||
* Caller knows that the regs handled in one transaction are of same size.
|
||||
*/
|
||||
#define FETCH_REGS(state, regnum, count) \
|
||||
memcpy (®isters[REGISTER_BYTE (regnum)], \
|
||||
(char *)state+reg_offset[ regnum ], \
|
||||
count*REGISTER_SIZE)
|
||||
|
||||
/* Store COUNT contiguous registers to thread STATE starting from REGNUM */
|
||||
#define STORE_REGS(state, regnum, count) \
|
||||
memcpy ((char *)state+reg_offset[ regnum ], \
|
||||
®isters[REGISTER_BYTE (regnum)], \
|
||||
count*REGISTER_SIZE)
|
||||
|
||||
/*
|
||||
* Fetch inferiors registers for gdb.
|
||||
* REGNO specifies which (as gdb views it) register, -1 for all.
|
||||
*/
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
kern_return_t ret;
|
||||
thread_state_data_t state;
|
||||
unsigned int stateCnt = NS532_COMBINED_STATE_COUNT;
|
||||
int index;
|
||||
|
||||
if (! MACH_PORT_VALID (current_thread))
|
||||
error ("fetch inferior registers: Invalid thread");
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 1);
|
||||
|
||||
ret = thread_get_state (current_thread,
|
||||
NS532_COMBINED_STATE,
|
||||
state,
|
||||
&stateCnt);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
message ("fetch_inferior_registers: %s ",
|
||||
mach_error_string (ret));
|
||||
#if 0
|
||||
/* It may be more effective to store validate all of them,
|
||||
* since we fetched them all anyway
|
||||
*/
|
||||
else if (regno != -1)
|
||||
supply_register (regno, (char *)state+reg_offset[regno]);
|
||||
#endif
|
||||
else
|
||||
{
|
||||
for (index = 0; index < NUM_REGS; index++)
|
||||
supply_register (index, (char *)state+reg_offset[index]);
|
||||
}
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
}
|
||||
|
||||
/* Store our register values back into the inferior.
|
||||
* If REGNO is -1, do this for all registers.
|
||||
* Otherwise, REGNO specifies which register
|
||||
*
|
||||
* On mach3 all registers are always saved in one call.
|
||||
*/
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
kern_return_t ret;
|
||||
thread_state_data_t state;
|
||||
unsigned int stateCnt = NS532_COMBINED_STATE_COUNT;
|
||||
register int index;
|
||||
|
||||
if (! MACH_PORT_VALID (current_thread))
|
||||
error ("store inferior registers: Invalid thread");
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 1);
|
||||
|
||||
/* Fetch the state of the current thread */
|
||||
ret = thread_get_state (current_thread,
|
||||
NS532_COMBINED_STATE,
|
||||
state,
|
||||
&stateCnt);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
{
|
||||
message ("store_inferior_registers (get): %s",
|
||||
mach_error_string (ret));
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* move gdb's registers to thread's state
|
||||
*
|
||||
* Since we save all registers anyway, save the ones
|
||||
* that gdb thinks are valid (e.g. ignore the regno
|
||||
* parameter)
|
||||
*/
|
||||
#if 0
|
||||
if (regno != -1)
|
||||
STORE_REGS (state, regno, 1);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (index = 0; index < NUM_REGS; index++)
|
||||
STORE_REGS (state, index, 1);
|
||||
}
|
||||
|
||||
/* Write gdb's current view of register to the thread
|
||||
*/
|
||||
ret = thread_set_state (current_thread,
|
||||
NS532_COMBINED_STATE,
|
||||
state,
|
||||
NS532_COMBINED_STATE_COUNT);
|
||||
|
||||
if (ret != KERN_SUCCESS)
|
||||
message ("store_inferior_registers (set): %s",
|
||||
mach_error_string (ret));
|
||||
|
||||
if (must_suspend_thread)
|
||||
setup_thread (current_thread, 0);
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
/* Remote target glue for the Oki op50n based eval board.
|
||||
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
|
||||
static void op50n_open PARAMS ((char *args, int from_tty));
|
||||
|
||||
/*
|
||||
* this array of registers need to match the indexes used by GDB. The
|
||||
* whole reason this exists is cause the various ROM monitors use
|
||||
* different strings than GDB does, and doesn't support all the
|
||||
* registers either. So, typing "info reg sp" becomes a "r30".
|
||||
*/
|
||||
|
||||
static char *op50n_regnames[NUM_REGS] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||||
"cr11", "p", NULL, NULL, NULL, "cr15", "cr19", "cr20",
|
||||
"cr21", "cr22", NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, "cr0", "cr8", "cr9", "cr10","cr12",
|
||||
"cr13", "cr24", "cr25", "cr26",
|
||||
};
|
||||
|
||||
/*
|
||||
* Define the monitor command strings. Since these are passed directly
|
||||
* through to a printf style function, we need can include formatting
|
||||
* strings. We also need a CR or LF on the end.
|
||||
*/
|
||||
|
||||
static struct target_ops op50n_ops;
|
||||
|
||||
static char *op50n_inits[] = {".\r", NULL};
|
||||
|
||||
static struct monitor_ops op50n_cmds =
|
||||
{
|
||||
MO_CLR_BREAK_USES_ADDR /*| MO_GETMEM_READ_SINGLE*/, /* flags */
|
||||
op50n_inits, /* Init strings */
|
||||
"g\r", /* continue command */
|
||||
"t\r", /* single step */
|
||||
"\003.\r", /* Interrupt char */
|
||||
"b %x\r", /* set a breakpoint */
|
||||
"b %x,0\r", /* clear breakpoint at addr */
|
||||
"bx\r", /* clear all breakpoints */
|
||||
"fx %x s%x %x\r", /* memory fill cmd (addr, len, val) */
|
||||
{
|
||||
"sx %x %x\r", /* setmem.cmdb (addr, value) */
|
||||
"sh %x %x\r", /* setmem.cmdw (addr, value) */
|
||||
"s %x %x\r", /* setmem.cmdl (addr, value) */
|
||||
NULL, /* setmem.cmdll (addr, value) */
|
||||
NULL, /* setmem.resp_delim */
|
||||
NULL, /* setmem.term */
|
||||
NULL, /* setmem.term_cmd */
|
||||
},
|
||||
#if 0
|
||||
{
|
||||
"sx %x\r", /* getmem.cmdb (addr, len) */
|
||||
"sh %x\r", /* getmem.cmdw (addr, len) */
|
||||
"s %x\r", /* getmem.cmdl (addr, len) */
|
||||
NULL, /* getmem.cmdll (addr, len) */
|
||||
" : ", /* getmem.resp_delim */
|
||||
" ", /* getmem.term */
|
||||
".\r", /* getmem.term_cmd */
|
||||
},
|
||||
#else
|
||||
{
|
||||
"dx %x s%x\r", /* getmem.cmdb (addr, len) */
|
||||
NULL, /* getmem.cmdw (addr, len) */
|
||||
NULL, /* getmem.cmdl (addr, len) */
|
||||
NULL, /* getmem.cmdll (addr, len) */
|
||||
" : ", /* getmem.resp_delim */
|
||||
NULL, /* getmem.term */
|
||||
NULL, /* getmem.term_cmd */
|
||||
},
|
||||
#endif
|
||||
{
|
||||
"x %s %x\r", /* setreg.cmd (name, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL, /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"x %s\r", /* getreg.cmd (name) */
|
||||
"=", /* getreg.resp_delim */
|
||||
" ", /* getreg.term */
|
||||
".\r", /* getreg.term_cmd */
|
||||
},
|
||||
NULL, /* dump_registers */
|
||||
NULL, /* register_pattern */
|
||||
NULL, /* supply_register */
|
||||
NULL, /* load routine */
|
||||
"r 0\r", /* download command */
|
||||
NULL, /* load response */
|
||||
"\n#", /* monitor command prompt */
|
||||
"\r", /* end-of-command delimitor */
|
||||
NULL, /* optional command terminator */
|
||||
&op50n_ops, /* target operations */
|
||||
SERIAL_1_STOPBITS, /* number of stop bits */
|
||||
op50n_regnames, /* register names */
|
||||
MONITOR_OPS_MAGIC /* magic */
|
||||
};
|
||||
|
||||
static void
|
||||
op50n_open (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
monitor_open (args, &op50n_cmds, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_op50n ()
|
||||
{
|
||||
init_monitor_ops (&op50n_ops);
|
||||
|
||||
op50n_ops.to_shortname = "op50n";
|
||||
op50n_ops.to_longname = "Oki's debug monitor for the Op50n Eval board";
|
||||
op50n_ops.to_doc = "Debug on a Oki OP50N eval board.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
op50n_ops.to_open = op50n_open;
|
||||
|
||||
add_target (&op50n_ops);
|
||||
}
|
|
@ -1,955 +0,0 @@
|
|||
/* Handle OSF/1 shared libraries for GDB, the GNU Debugger.
|
||||
Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* FIXME: Most of this code could be merged with solib.c by using
|
||||
next_link_map_member and xfer_link_map_member in solib.c. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "gdb_string.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "symtab.h"
|
||||
#include "bfd.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "target.h"
|
||||
#include "frame.h"
|
||||
#include "gnu-regex.h"
|
||||
#include "inferior.h"
|
||||
#include "language.h"
|
||||
#include "gdbcmd.h"
|
||||
|
||||
#define MAX_PATH_SIZE 1024 /* FIXME: Should be dynamic */
|
||||
|
||||
/* When handling shared libraries, GDB has to find out the pathnames
|
||||
of all shared libraries that are currently loaded (to read in their
|
||||
symbols) and where the shared libraries are loaded in memory
|
||||
(to relocate them properly from their prelinked addresses to the
|
||||
current load address).
|
||||
|
||||
Under OSF/1 there are two possibilities to get at this information:
|
||||
1) Peek around in the runtime loader structures.
|
||||
These are not documented, and they are not defined in the system
|
||||
header files. The definitions below were obtained by experimentation,
|
||||
but they seem stable enough.
|
||||
2) Use the undocumented libxproc.a library, which contains the
|
||||
equivalent ldr_* routines.
|
||||
This approach is somewhat cleaner, but it requires that the GDB
|
||||
executable is dynamically linked. In addition it requires a
|
||||
NAT_CLIBS= -lxproc -Wl,-expect_unresolved,ldr_process_context
|
||||
linker specification for GDB and all applications that are using
|
||||
libgdb.
|
||||
We will use the peeking approach until it becomes unwieldy. */
|
||||
|
||||
#ifndef USE_LDR_ROUTINES
|
||||
|
||||
/* Definition of runtime loader structures, found by experimentation. */
|
||||
#define RLD_CONTEXT_ADDRESS 0x3ffc0000000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CORE_ADDR next;
|
||||
CORE_ADDR previous;
|
||||
CORE_ADDR unknown1;
|
||||
char *module_name;
|
||||
CORE_ADDR modinfo_addr;
|
||||
long module_id;
|
||||
CORE_ADDR unknown2;
|
||||
CORE_ADDR unknown3;
|
||||
long region_count;
|
||||
CORE_ADDR regioninfo_addr;
|
||||
} ldr_module_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long unknown1;
|
||||
CORE_ADDR regionname_addr;
|
||||
long protection;
|
||||
CORE_ADDR vaddr;
|
||||
CORE_ADDR mapaddr;
|
||||
long size;
|
||||
long unknown2[5];
|
||||
} ldr_region_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CORE_ADDR unknown1;
|
||||
CORE_ADDR unknown2;
|
||||
CORE_ADDR head;
|
||||
CORE_ADDR tail;
|
||||
} ldr_context_t;
|
||||
|
||||
static ldr_context_t ldr_context;
|
||||
|
||||
#else
|
||||
|
||||
#include <loader.h>
|
||||
static ldr_process_t fake_ldr_process;
|
||||
|
||||
/* Called by ldr_* routines to read memory from the current target. */
|
||||
|
||||
static int ldr_read_memory PARAMS ((CORE_ADDR, char *, int, int));
|
||||
|
||||
static int
|
||||
ldr_read_memory (memaddr, myaddr, len, readstring)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int readstring;
|
||||
{
|
||||
int result;
|
||||
char *buffer;
|
||||
|
||||
if (readstring)
|
||||
{
|
||||
target_read_string (memaddr, &buffer, len, &result);
|
||||
if (result == 0)
|
||||
strcpy (myaddr, buffer);
|
||||
free (buffer);
|
||||
}
|
||||
else
|
||||
result = target_read_memory (memaddr, myaddr, len);
|
||||
|
||||
if (result != 0)
|
||||
result = -result;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Define our own link_map structure.
|
||||
This will help to share code with solib.c. */
|
||||
|
||||
struct link_map {
|
||||
CORE_ADDR l_offset; /* prelink to load address offset */
|
||||
char *l_name; /* full name of loaded object */
|
||||
ldr_module_info_t module_info; /* corresponding module info */
|
||||
};
|
||||
|
||||
#define LM_OFFSET(so) ((so) -> lm.l_offset)
|
||||
#define LM_NAME(so) ((so) -> lm.l_name)
|
||||
|
||||
struct so_list {
|
||||
struct so_list *next; /* next structure in linked list */
|
||||
struct link_map lm; /* copy of link map from inferior */
|
||||
struct link_map *lmaddr; /* addr in inferior lm was read from */
|
||||
CORE_ADDR lmend; /* upper addr bound of mapped object */
|
||||
char so_name[MAX_PATH_SIZE]; /* shared object lib name (FIXME) */
|
||||
char symbols_loaded; /* flag: symbols read in yet? */
|
||||
char from_tty; /* flag: print msgs? */
|
||||
struct objfile *objfile; /* objfile for loaded lib */
|
||||
struct section_table *sections;
|
||||
struct section_table *sections_end;
|
||||
struct section_table *textsection;
|
||||
bfd *abfd;
|
||||
};
|
||||
|
||||
static struct so_list *so_list_head; /* List of known shared objects */
|
||||
|
||||
extern int
|
||||
fdmatch PARAMS ((int, int)); /* In libiberty */
|
||||
|
||||
/* Local function prototypes */
|
||||
|
||||
static void
|
||||
sharedlibrary_command PARAMS ((char *, int));
|
||||
|
||||
static void
|
||||
info_sharedlibrary_command PARAMS ((char *, int));
|
||||
|
||||
static int
|
||||
symbol_add_stub PARAMS ((char *));
|
||||
|
||||
static struct so_list *
|
||||
find_solib PARAMS ((struct so_list *));
|
||||
|
||||
static struct link_map *
|
||||
first_link_map_member PARAMS ((void));
|
||||
|
||||
static struct link_map *
|
||||
next_link_map_member PARAMS ((struct so_list *));
|
||||
|
||||
static void
|
||||
xfer_link_map_member PARAMS ((struct so_list *, struct link_map *));
|
||||
|
||||
static void
|
||||
solib_map_sections PARAMS ((struct so_list *));
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
solib_map_sections -- open bfd and build sections for shared lib
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
static void solib_map_sections (struct so_list *so)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Given a pointer to one of the shared objects in our list
|
||||
of mapped objects, use the recorded name to open a bfd
|
||||
descriptor for the object, build a section table, and then
|
||||
relocate all the section addresses by the base address at
|
||||
which the shared object was mapped.
|
||||
|
||||
FIXMES
|
||||
|
||||
In most (all?) cases the shared object file name recorded in the
|
||||
dynamic linkage tables will be a fully qualified pathname. For
|
||||
cases where it isn't, do we really mimic the systems search
|
||||
mechanism correctly in the below code (particularly the tilde
|
||||
expansion stuff?).
|
||||
*/
|
||||
|
||||
static void
|
||||
solib_map_sections (so)
|
||||
struct so_list *so;
|
||||
{
|
||||
char *filename;
|
||||
char *scratch_pathname;
|
||||
int scratch_chan;
|
||||
struct section_table *p;
|
||||
struct cleanup *old_chain;
|
||||
bfd *abfd;
|
||||
|
||||
filename = tilde_expand (so -> so_name);
|
||||
old_chain = make_cleanup (free, filename);
|
||||
|
||||
scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
|
||||
&scratch_pathname);
|
||||
if (scratch_chan < 0)
|
||||
{
|
||||
scratch_chan = openp (getenv ("LD_LIBRARY_PATH"), 1, filename,
|
||||
O_RDONLY, 0, &scratch_pathname);
|
||||
}
|
||||
if (scratch_chan < 0)
|
||||
{
|
||||
perror_with_name (filename);
|
||||
}
|
||||
/* Leave scratch_pathname allocated. bfd->name will point to it. */
|
||||
|
||||
abfd = bfd_fdopenr (scratch_pathname, gnutarget, scratch_chan);
|
||||
if (!abfd)
|
||||
{
|
||||
close (scratch_chan);
|
||||
error ("Could not open `%s' as an executable file: %s",
|
||||
scratch_pathname, bfd_errmsg (bfd_get_error ()));
|
||||
}
|
||||
/* Leave bfd open, core_xfer_memory and "info files" need it. */
|
||||
so -> abfd = abfd;
|
||||
abfd -> cacheable = true;
|
||||
|
||||
if (!bfd_check_format (abfd, bfd_object))
|
||||
{
|
||||
error ("\"%s\": not in executable format: %s.",
|
||||
scratch_pathname, bfd_errmsg (bfd_get_error ()));
|
||||
}
|
||||
if (build_section_table (abfd, &so -> sections, &so -> sections_end))
|
||||
{
|
||||
error ("Can't find the file sections in `%s': %s",
|
||||
bfd_get_filename (exec_bfd), bfd_errmsg (bfd_get_error ()));
|
||||
}
|
||||
|
||||
for (p = so -> sections; p < so -> sections_end; p++)
|
||||
{
|
||||
/* Relocate the section binding addresses as recorded in the shared
|
||||
object's file by the offset to get the address to which the
|
||||
object was actually mapped. */
|
||||
p -> addr += LM_OFFSET (so);
|
||||
p -> endaddr += LM_OFFSET (so);
|
||||
so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend);
|
||||
if (STREQ (p -> the_bfd_section -> name, ".text"))
|
||||
{
|
||||
so -> textsection = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the file names, close the file now. */
|
||||
do_cleanups (old_chain);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
first_link_map_member -- locate first member in dynamic linker's map
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
static struct link_map *first_link_map_member (void)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Read in a copy of the first member in the inferior's dynamic
|
||||
link map from the inferior's dynamic linker structures, and return
|
||||
a pointer to the copy in our address space.
|
||||
*/
|
||||
|
||||
static struct link_map *
|
||||
first_link_map_member ()
|
||||
{
|
||||
struct link_map *lm = NULL;
|
||||
static struct link_map first_lm;
|
||||
|
||||
#ifdef USE_LDR_ROUTINES
|
||||
ldr_module_t mod_id = LDR_NULL_MODULE;
|
||||
size_t retsize;
|
||||
|
||||
fake_ldr_process = ldr_core_process ();
|
||||
ldr_set_core_reader (ldr_read_memory);
|
||||
ldr_xdetach (fake_ldr_process);
|
||||
if (ldr_xattach (fake_ldr_process) != 0
|
||||
|| ldr_next_module(fake_ldr_process, &mod_id) != 0
|
||||
|| mod_id == LDR_NULL_MODULE
|
||||
|| ldr_inq_module(fake_ldr_process, mod_id,
|
||||
&first_lm.module_info, sizeof(ldr_module_info_t),
|
||||
&retsize) != 0)
|
||||
return lm;
|
||||
#else
|
||||
CORE_ADDR ldr_context_addr;
|
||||
|
||||
if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS,
|
||||
(char *) &ldr_context_addr,
|
||||
sizeof (CORE_ADDR)) != 0
|
||||
|| target_read_memory (ldr_context_addr,
|
||||
(char *) &ldr_context,
|
||||
sizeof (ldr_context_t)) != 0
|
||||
|| target_read_memory ((CORE_ADDR) ldr_context.head,
|
||||
(char *) &first_lm.module_info,
|
||||
sizeof (ldr_module_info_t)) != 0)
|
||||
return lm;
|
||||
#endif
|
||||
|
||||
lm = &first_lm;
|
||||
|
||||
/* The first entry is for the main program and should be skipped. */
|
||||
lm->l_name = NULL;
|
||||
|
||||
return lm;
|
||||
}
|
||||
|
||||
static struct link_map *
|
||||
next_link_map_member (so_list_ptr)
|
||||
struct so_list *so_list_ptr;
|
||||
{
|
||||
struct link_map *lm = NULL;
|
||||
static struct link_map next_lm;
|
||||
#ifdef USE_LDR_ROUTINES
|
||||
ldr_module_t mod_id = so_list_ptr->lm.module_info.lmi_modid;
|
||||
size_t retsize;
|
||||
|
||||
if (ldr_next_module(fake_ldr_process, &mod_id) != 0
|
||||
|| mod_id == LDR_NULL_MODULE
|
||||
|| ldr_inq_module(fake_ldr_process, mod_id,
|
||||
&next_lm.module_info, sizeof(ldr_module_info_t),
|
||||
&retsize) != 0)
|
||||
return lm;
|
||||
|
||||
lm = &next_lm;
|
||||
lm->l_name = lm->module_info.lmi_name;
|
||||
#else
|
||||
CORE_ADDR ldr_context_addr;
|
||||
|
||||
/* Reread context in case ldr_context.tail was updated. */
|
||||
|
||||
if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS,
|
||||
(char *) &ldr_context_addr,
|
||||
sizeof (CORE_ADDR)) != 0
|
||||
|| target_read_memory (ldr_context_addr,
|
||||
(char *) &ldr_context,
|
||||
sizeof (ldr_context_t)) != 0
|
||||
|| so_list_ptr->lm.module_info.modinfo_addr == ldr_context.tail
|
||||
|| target_read_memory (so_list_ptr->lm.module_info.next,
|
||||
(char *) &next_lm.module_info,
|
||||
sizeof (ldr_module_info_t)) != 0)
|
||||
return lm;
|
||||
|
||||
lm = &next_lm;
|
||||
lm->l_name = lm->module_info.module_name;
|
||||
#endif
|
||||
return lm;
|
||||
}
|
||||
|
||||
static void
|
||||
xfer_link_map_member (so_list_ptr, lm)
|
||||
struct so_list *so_list_ptr;
|
||||
struct link_map *lm;
|
||||
{
|
||||
int i;
|
||||
so_list_ptr->lm = *lm;
|
||||
|
||||
/* OSF/1 shared libraries are pre-linked to particular addresses,
|
||||
but the runtime loader may have to relocate them if the
|
||||
address ranges of the libraries used by the target executable clash,
|
||||
or if the target executable is linked with the -taso option.
|
||||
The offset is the difference between the address where the shared
|
||||
library is mapped and the pre-linked address of the shared library.
|
||||
|
||||
FIXME: GDB is currently unable to relocate the shared library
|
||||
sections by different offsets. If sections are relocated by
|
||||
different offsets, put out a warning and use the offset of the
|
||||
first section for all remaining sections. */
|
||||
LM_OFFSET (so_list_ptr) = 0;
|
||||
|
||||
/* There is one entry that has no name (for the inferior executable)
|
||||
since it is not a shared object. */
|
||||
if (LM_NAME (so_list_ptr) != 0)
|
||||
{
|
||||
|
||||
#ifdef USE_LDR_ROUTINES
|
||||
int len = strlen (LM_NAME (so_list_ptr) + 1);
|
||||
|
||||
if (len > MAX_PATH_SIZE)
|
||||
len = MAX_PATH_SIZE;
|
||||
strncpy (so_list_ptr->so_name, LM_NAME (so_list_ptr), MAX_PATH_SIZE);
|
||||
so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0';
|
||||
|
||||
for (i = 0; i < lm->module_info.lmi_nregion; i++)
|
||||
{
|
||||
ldr_region_info_t region_info;
|
||||
size_t retsize;
|
||||
CORE_ADDR region_offset;
|
||||
|
||||
if (ldr_inq_region (fake_ldr_process, lm->module_info.lmi_modid,
|
||||
i, ®ion_info, sizeof (region_info),
|
||||
&retsize) != 0)
|
||||
break;
|
||||
region_offset = (CORE_ADDR) region_info.lri_mapaddr
|
||||
- (CORE_ADDR) region_info.lri_vaddr;
|
||||
if (i == 0)
|
||||
LM_OFFSET (so_list_ptr) = region_offset;
|
||||
else if (LM_OFFSET (so_list_ptr) != region_offset)
|
||||
warning ("cannot handle shared library relocation for %s (%s)",
|
||||
so_list_ptr->so_name, region_info.lri_name);
|
||||
}
|
||||
#else
|
||||
int errcode;
|
||||
char *buffer;
|
||||
target_read_string ((CORE_ADDR) LM_NAME (so_list_ptr), &buffer,
|
||||
MAX_PATH_SIZE - 1, &errcode);
|
||||
if (errcode != 0)
|
||||
error ("xfer_link_map_member: Can't read pathname for load map: %s\n",
|
||||
safe_strerror (errcode));
|
||||
strncpy (so_list_ptr->so_name, buffer, MAX_PATH_SIZE - 1);
|
||||
free (buffer);
|
||||
so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0';
|
||||
|
||||
for (i = 0; i < lm->module_info.region_count; i++)
|
||||
{
|
||||
ldr_region_info_t region_info;
|
||||
CORE_ADDR region_offset;
|
||||
|
||||
if (target_read_memory (lm->module_info.regioninfo_addr
|
||||
+ i * sizeof (region_info),
|
||||
(char *) ®ion_info,
|
||||
sizeof (region_info)) != 0)
|
||||
break;
|
||||
region_offset = region_info.mapaddr - region_info.vaddr;
|
||||
if (i == 0)
|
||||
LM_OFFSET (so_list_ptr) = region_offset;
|
||||
else if (LM_OFFSET (so_list_ptr) != region_offset)
|
||||
{
|
||||
char *region_name;
|
||||
target_read_string (region_info.regionname_addr, &buffer,
|
||||
MAX_PATH_SIZE - 1, &errcode);
|
||||
if (errcode == 0)
|
||||
region_name = buffer;
|
||||
else
|
||||
region_name = "??";
|
||||
warning ("cannot handle shared library relocation for %s (%s)",
|
||||
so_list_ptr->so_name, region_name);
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
solib_map_sections (so_list_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
find_solib -- step through list of shared objects
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
struct so_list *find_solib (struct so_list *so_list_ptr)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This module contains the routine which finds the names of any
|
||||
loaded "images" in the current process. The argument in must be
|
||||
NULL on the first call, and then the returned value must be passed
|
||||
in on subsequent calls. This provides the capability to "step" down
|
||||
the list of loaded objects. On the last object, a NULL value is
|
||||
returned.
|
||||
|
||||
The arg and return value are "struct link_map" pointers, as defined
|
||||
in <link.h>.
|
||||
*/
|
||||
|
||||
static struct so_list *
|
||||
find_solib (so_list_ptr)
|
||||
struct so_list *so_list_ptr; /* Last lm or NULL for first one */
|
||||
{
|
||||
struct so_list *so_list_next = NULL;
|
||||
struct link_map *lm = NULL;
|
||||
struct so_list *new;
|
||||
|
||||
if (so_list_ptr == NULL)
|
||||
{
|
||||
/* We are setting up for a new scan through the loaded images. */
|
||||
if ((so_list_next = so_list_head) == NULL)
|
||||
{
|
||||
/* Find the first link map list member. */
|
||||
lm = first_link_map_member ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have been called before, and are in the process of walking
|
||||
the shared library list. Advance to the next shared object. */
|
||||
lm = next_link_map_member (so_list_ptr);
|
||||
so_list_next = so_list_ptr -> next;
|
||||
}
|
||||
if ((so_list_next == NULL) && (lm != NULL))
|
||||
{
|
||||
/* Get next link map structure from inferior image and build a local
|
||||
abbreviated load_map structure */
|
||||
new = (struct so_list *) xmalloc (sizeof (struct so_list));
|
||||
memset ((char *) new, 0, sizeof (struct so_list));
|
||||
new -> lmaddr = lm;
|
||||
/* Add the new node as the next node in the list, or as the root
|
||||
node if this is the first one. */
|
||||
if (so_list_ptr != NULL)
|
||||
{
|
||||
so_list_ptr -> next = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
so_list_head = new;
|
||||
}
|
||||
so_list_next = new;
|
||||
xfer_link_map_member (new, lm);
|
||||
}
|
||||
return (so_list_next);
|
||||
}
|
||||
|
||||
/* A small stub to get us past the arg-passing pinhole of catch_errors. */
|
||||
|
||||
static int
|
||||
symbol_add_stub (arg)
|
||||
char *arg;
|
||||
{
|
||||
register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
|
||||
|
||||
so -> objfile = symbol_file_add (so -> so_name, so -> from_tty,
|
||||
so -> textsection -> addr,
|
||||
0, 0, 0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
solib_add -- add a shared library file to the symtab and section list
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void solib_add (char *arg_string, int from_tty,
|
||||
struct target_ops *target)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
solib_add (arg_string, from_tty, target)
|
||||
char *arg_string;
|
||||
int from_tty;
|
||||
struct target_ops *target;
|
||||
{
|
||||
register struct so_list *so = NULL; /* link map state variable */
|
||||
|
||||
/* Last shared library that we read. */
|
||||
struct so_list *so_last = NULL;
|
||||
|
||||
char *re_err;
|
||||
int count;
|
||||
int old;
|
||||
|
||||
if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
|
||||
{
|
||||
error ("Invalid regexp: %s", re_err);
|
||||
}
|
||||
|
||||
|
||||
/* Add the shared library sections to the section table of the
|
||||
specified target, if any. */
|
||||
if (target)
|
||||
{
|
||||
/* Count how many new section_table entries there are. */
|
||||
so = NULL;
|
||||
count = 0;
|
||||
while ((so = find_solib (so)) != NULL)
|
||||
{
|
||||
if (so -> so_name[0])
|
||||
{
|
||||
count += so -> sections_end - so -> sections;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
int update_coreops;
|
||||
|
||||
/* We must update the to_sections field in the core_ops structure
|
||||
here, otherwise we dereference a potential dangling pointer
|
||||
for each call to target_read/write_memory within this routine. */
|
||||
update_coreops = core_ops.to_sections == target->to_sections;
|
||||
|
||||
/* Reallocate the target's section table including the new size. */
|
||||
if (target -> to_sections)
|
||||
{
|
||||
old = target -> to_sections_end - target -> to_sections;
|
||||
target -> to_sections = (struct section_table *)
|
||||
xrealloc ((char *)target -> to_sections,
|
||||
(sizeof (struct section_table)) * (count + old));
|
||||
}
|
||||
else
|
||||
{
|
||||
old = 0;
|
||||
target -> to_sections = (struct section_table *)
|
||||
xmalloc ((sizeof (struct section_table)) * count);
|
||||
}
|
||||
target -> to_sections_end = target -> to_sections + (count + old);
|
||||
|
||||
/* Update the to_sections field in the core_ops structure
|
||||
if needed. */
|
||||
if (update_coreops)
|
||||
{
|
||||
core_ops.to_sections = target->to_sections;
|
||||
core_ops.to_sections_end = target->to_sections_end;
|
||||
}
|
||||
|
||||
/* Add these section table entries to the target's table. */
|
||||
while ((so = find_solib (so)) != NULL)
|
||||
{
|
||||
if (so -> so_name[0])
|
||||
{
|
||||
count = so -> sections_end - so -> sections;
|
||||
memcpy ((char *) (target -> to_sections + old),
|
||||
so -> sections,
|
||||
(sizeof (struct section_table)) * count);
|
||||
old += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now add the symbol files. */
|
||||
so = NULL;
|
||||
while ((so = find_solib (so)) != NULL)
|
||||
{
|
||||
if (so -> so_name[0] && re_exec (so -> so_name))
|
||||
{
|
||||
so -> from_tty = from_tty;
|
||||
if (so -> symbols_loaded)
|
||||
{
|
||||
if (from_tty)
|
||||
{
|
||||
printf_unfiltered ("Symbols already loaded for %s\n", so -> so_name);
|
||||
}
|
||||
}
|
||||
else if (catch_errors
|
||||
(symbol_add_stub, (char *) so,
|
||||
"Error while reading shared library symbols:\n",
|
||||
RETURN_MASK_ALL))
|
||||
{
|
||||
so_last = so;
|
||||
so -> symbols_loaded = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Getting new symbols may change our opinion about what is
|
||||
frameless. */
|
||||
if (so_last)
|
||||
reinit_frame_cache ();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
info_sharedlibrary_command -- code for "info sharedlibrary"
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
static void info_sharedlibrary_command ()
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Walk through the shared library list and print information
|
||||
about each attached library.
|
||||
*/
|
||||
|
||||
static void
|
||||
info_sharedlibrary_command (ignore, from_tty)
|
||||
char *ignore;
|
||||
int from_tty;
|
||||
{
|
||||
register struct so_list *so = NULL; /* link map state variable */
|
||||
int header_done = 0;
|
||||
|
||||
if (exec_bfd == NULL)
|
||||
{
|
||||
printf_unfiltered ("No exec file.\n");
|
||||
return;
|
||||
}
|
||||
while ((so = find_solib (so)) != NULL)
|
||||
{
|
||||
if (so -> so_name[0])
|
||||
{
|
||||
unsigned long txt_start = 0;
|
||||
unsigned long txt_end = 0;
|
||||
|
||||
if (!header_done)
|
||||
{
|
||||
printf_unfiltered("%-20s%-20s%-12s%s\n", "From", "To", "Syms Read",
|
||||
"Shared Object Library");
|
||||
header_done++;
|
||||
}
|
||||
if (so -> textsection)
|
||||
{
|
||||
txt_start = (unsigned long) so -> textsection -> addr;
|
||||
txt_end = (unsigned long) so -> textsection -> endaddr;
|
||||
}
|
||||
printf_unfiltered ("%-20s", local_hex_string_custom (txt_start, "08l"));
|
||||
printf_unfiltered ("%-20s", local_hex_string_custom (txt_end, "08l"));
|
||||
printf_unfiltered ("%-12s", so -> symbols_loaded ? "Yes" : "No");
|
||||
printf_unfiltered ("%s\n", so -> so_name);
|
||||
}
|
||||
}
|
||||
if (so_list_head == NULL)
|
||||
{
|
||||
printf_unfiltered ("No shared libraries loaded at this time.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
solib_address -- check to see if an address is in a shared lib
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
char *solib_address (CORE_ADDR address)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Provides a hook for other gdb routines to discover whether or
|
||||
not a particular address is within the mapped address space of
|
||||
a shared library. Any address between the base mapping address
|
||||
and the first address beyond the end of the last mapping, is
|
||||
considered to be within the shared library address space, for
|
||||
our purposes.
|
||||
|
||||
For example, this routine is called at one point to disable
|
||||
breakpoints which are in shared libraries that are not currently
|
||||
mapped in.
|
||||
*/
|
||||
|
||||
char *
|
||||
solib_address (address)
|
||||
CORE_ADDR address;
|
||||
{
|
||||
register struct so_list *so = 0; /* link map state variable */
|
||||
|
||||
while ((so = find_solib (so)) != NULL)
|
||||
{
|
||||
if (so -> so_name[0] && so -> textsection)
|
||||
{
|
||||
if ((address >= (CORE_ADDR) so -> textsection -> addr) &&
|
||||
(address < (CORE_ADDR) so -> textsection -> endaddr))
|
||||
return (so->so_name);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Called by free_all_symtabs */
|
||||
|
||||
void
|
||||
clear_solib()
|
||||
{
|
||||
struct so_list *next;
|
||||
char *bfd_filename;
|
||||
|
||||
while (so_list_head)
|
||||
{
|
||||
if (so_list_head -> sections)
|
||||
{
|
||||
free ((PTR)so_list_head -> sections);
|
||||
}
|
||||
if (so_list_head -> abfd)
|
||||
{
|
||||
bfd_filename = bfd_get_filename (so_list_head -> abfd);
|
||||
if (!bfd_close (so_list_head -> abfd))
|
||||
warning ("cannot close \"%s\": %s",
|
||||
bfd_filename, bfd_errmsg (bfd_get_error ()));
|
||||
}
|
||||
else
|
||||
/* This happens for the executable on SVR4. */
|
||||
bfd_filename = NULL;
|
||||
|
||||
next = so_list_head -> next;
|
||||
if (bfd_filename)
|
||||
free ((PTR)bfd_filename);
|
||||
free ((PTR)so_list_head);
|
||||
so_list_head = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
GLOBAL FUNCTION
|
||||
|
||||
solib_create_inferior_hook -- shared library startup support
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void solib_create_inferior_hook()
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
When gdb starts up the inferior, it nurses it along (through the
|
||||
shell) until it is ready to execute it's first instruction. At this
|
||||
point, this function gets called via expansion of the macro
|
||||
SOLIB_CREATE_INFERIOR_HOOK.
|
||||
For a statically bound executable, this first instruction is the
|
||||
one at "_start", or a similar text label. No further processing is
|
||||
needed in that case.
|
||||
For a dynamically bound executable, this first instruction is somewhere
|
||||
in the rld, and the actual user executable is not yet mapped in.
|
||||
We continue the inferior again, rld then maps in the actual user
|
||||
executable and any needed shared libraries and then sends
|
||||
itself a SIGTRAP.
|
||||
At that point we discover the names of all shared libraries and
|
||||
read their symbols in.
|
||||
|
||||
FIXME
|
||||
|
||||
This code does not properly handle hitting breakpoints which the
|
||||
user might have set in the rld itself. Proper handling would have
|
||||
to check if the SIGTRAP happened due to a kill call.
|
||||
|
||||
Also, what if child has exit()ed? Must exit loop somehow.
|
||||
*/
|
||||
|
||||
void
|
||||
solib_create_inferior_hook()
|
||||
{
|
||||
|
||||
/* Nothing to do for statically bound executables. */
|
||||
|
||||
if (symfile_objfile == NULL
|
||||
|| symfile_objfile->obfd == NULL
|
||||
|| ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
|
||||
return;
|
||||
|
||||
/* Now run the target. It will eventually get a SIGTRAP, at
|
||||
which point all of the libraries will have been mapped in and we
|
||||
can go groveling around in the rld structures to find
|
||||
out what we need to know about them. */
|
||||
|
||||
clear_proceed_status ();
|
||||
stop_soon_quietly = 1;
|
||||
stop_signal = TARGET_SIGNAL_0;
|
||||
do
|
||||
{
|
||||
target_resume (-1, 0, stop_signal);
|
||||
wait_for_inferior ();
|
||||
}
|
||||
while (stop_signal != TARGET_SIGNAL_TRAP);
|
||||
|
||||
/* solib_add will call reinit_frame_cache.
|
||||
But we are stopped in the runtime loader and we do not have symbols
|
||||
for the runtime loader. So heuristic_proc_start will be called
|
||||
and will put out an annoying warning.
|
||||
Delaying the resetting of stop_soon_quietly until after symbol loading
|
||||
suppresses the warning. */
|
||||
if (auto_solib_add)
|
||||
solib_add ((char *) 0, 0, (struct target_ops *) 0);
|
||||
stop_soon_quietly = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
sharedlibrary_command -- handle command to explicitly add library
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
static void sharedlibrary_command (char *args, int from_tty)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
*/
|
||||
|
||||
static void
|
||||
sharedlibrary_command (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
dont_repeat ();
|
||||
solib_add (args, from_tty, (struct target_ops *) 0);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_solib()
|
||||
{
|
||||
add_com ("sharedlibrary", class_files, sharedlibrary_command,
|
||||
"Load shared object library symbols for files matching REGEXP.");
|
||||
add_info ("sharedlibrary", info_sharedlibrary_command,
|
||||
"Status of loaded shared object libraries.");
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("auto-solib-add", class_support, var_zinteger,
|
||||
(char *) &auto_solib_add,
|
||||
"Set autoloading of shared library symbols.\n\
|
||||
If nonzero, symbols from all shared object libraries will be loaded\n\
|
||||
automatically when the inferior begins execution or when the dynamic linker\n\
|
||||
informs gdb that a new library has been loaded. Otherwise, symbols\n\
|
||||
must be loaded manually, using `sharedlibrary'.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
/* Remote debugging interface for PPCbug (PowerPC) Rom monitor
|
||||
for GDB, the GNU debugger.
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
|
||||
Written by Stu Grossman of Cygnus Support
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
|
||||
static void ppcbug_open PARAMS ((char *args, int from_tty));
|
||||
|
||||
static void
|
||||
ppcbug_supply_register (regname, regnamelen, val, vallen)
|
||||
char *regname;
|
||||
int regnamelen;
|
||||
char *val;
|
||||
int vallen;
|
||||
{
|
||||
int regno = 0, base = 0;
|
||||
|
||||
if (regnamelen < 2 || regnamelen > 4)
|
||||
return;
|
||||
|
||||
switch (regname[0])
|
||||
{
|
||||
case 'R':
|
||||
if (regname[1] < '0' || regname[1] > '9')
|
||||
return;
|
||||
if (regnamelen == 2)
|
||||
regno = regname[1] - '0';
|
||||
else if (regnamelen == 3 && regname[2] >= '0' && regname[2] <= '9')
|
||||
regno = (regname[1] - '0') * 10 + (regname[2] - '0');
|
||||
else
|
||||
return;
|
||||
break;
|
||||
case 'F':
|
||||
if (regname[1] != 'R' || regname[2] < '0' || regname[2] > '9')
|
||||
return;
|
||||
if (regnamelen == 3)
|
||||
regno = 32 + regname[2] - '0';
|
||||
else if (regnamelen == 4 && regname[3] >= '0' && regname[3] <= '9')
|
||||
regno = 32 + (regname[2] - '0') * 10 + (regname[3] - '0');
|
||||
else
|
||||
return;
|
||||
break;
|
||||
case 'I':
|
||||
if (regnamelen != 2 || regname[1] != 'P')
|
||||
return;
|
||||
regno = 64;
|
||||
break;
|
||||
case 'M':
|
||||
if (regnamelen != 3 || regname[1] != 'S' || regname[2] != 'R')
|
||||
return;
|
||||
regno = 65;
|
||||
break;
|
||||
case 'C':
|
||||
if (regnamelen != 2 || regname[1] != 'R')
|
||||
return;
|
||||
regno = 66;
|
||||
break;
|
||||
case 'S':
|
||||
if (regnamelen != 4 || regname[1] != 'P' || regname[2] != 'R')
|
||||
return;
|
||||
else if (regname[3] == '8')
|
||||
regno = 67;
|
||||
else if (regname[3] == '9')
|
||||
regno = 68;
|
||||
else if (regname[3] == '1')
|
||||
regno = 69;
|
||||
else if (regname[3] == '0')
|
||||
regno = 70;
|
||||
else
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_supply_register (regno, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* This array of registers needs to match the indexes used by GDB. The
|
||||
* whole reason this exists is because the various ROM monitors use
|
||||
* different names than GDB does, and don't support all the
|
||||
* registers either. So, typing "info reg sp" becomes an "A7".
|
||||
*/
|
||||
|
||||
static char *ppcbug_regnames[NUM_REGS] =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
|
||||
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
|
||||
|
||||
"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
|
||||
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
|
||||
"fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
|
||||
"fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31",
|
||||
|
||||
/* pc ps cnd lr cnt xer mq */
|
||||
"ip", "msr", "cr", "spr8", "spr9", "spr1", "spr0"
|
||||
};
|
||||
|
||||
/*
|
||||
* Define the monitor command strings. Since these are passed directly
|
||||
* through to a printf style function, we need can include formatting
|
||||
* strings. We also need a CR or LF on the end.
|
||||
*/
|
||||
|
||||
static struct target_ops ppcbug_ops0;
|
||||
static struct target_ops ppcbug_ops1;
|
||||
|
||||
static char *ppcbug_inits[] = {"\r", NULL};
|
||||
|
||||
#define PPC_CMDS(LOAD_CMD, OPS) \
|
||||
{ \
|
||||
MO_CLR_BREAK_USES_ADDR | MO_HANDLE_NL, \
|
||||
ppcbug_inits, /* Init strings */ \
|
||||
"g\r", /* continue command */ \
|
||||
"t\r", /* single step */ \
|
||||
NULL, /* interrupt command */ \
|
||||
"br %x\r", /* set a breakpoint */ \
|
||||
"nobr %x\r", /* clear a breakpoint */ \
|
||||
"nobr\r", /* clear all breakpoints */ \
|
||||
"bf %x:%x %x;b\r", /* fill (start count val) */ \
|
||||
{ \
|
||||
"ms %x %02x\r", /* setmem.cmdb (addr, value) */ \
|
||||
"ms %x %04x\r", /* setmem.cmdw (addr, value) */ \
|
||||
"ms %x %08x\r", /* setmem.cmdl (addr, value) */ \
|
||||
NULL, /* setmem.cmdll (addr, value) */ \
|
||||
NULL, /* setreg.resp_delim */ \
|
||||
NULL, /* setreg.term */ \
|
||||
NULL, /* setreg.term_cmd */ \
|
||||
}, \
|
||||
{ \
|
||||
"md %x:%x;b\r", /* getmem.cmdb (addr, len) */ \
|
||||
"md %x:%x;b\r", /* getmem.cmdw (addr, len) */ \
|
||||
"md %x:%x;b\r", /* getmem.cmdl (addr, len) */ \
|
||||
NULL, /* getmem.cmdll (addr, len) */ \
|
||||
" ", /* getmem.resp_delim */ \
|
||||
NULL, /* getmem.term */ \
|
||||
NULL, /* getmem.term_cmd */ \
|
||||
}, \
|
||||
{ \
|
||||
"rs %s %x\r", /* setreg.cmd (name, value) */ \
|
||||
NULL, /* setreg.resp_delim */ \
|
||||
NULL, /* setreg.term */ \
|
||||
NULL /* setreg.term_cmd */ \
|
||||
}, \
|
||||
{ \
|
||||
"rs %s\r", /* getreg.cmd (name) */ \
|
||||
"=", /* getreg.resp_delim */ \
|
||||
NULL, /* getreg.term */ \
|
||||
NULL /* getreg.term_cmd */ \
|
||||
}, \
|
||||
"rd\r", /* dump_registers */ \
|
||||
"\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)", /* register_pattern */ \
|
||||
ppcbug_supply_register, /* supply_register */ \
|
||||
NULL, /* load_routine (defaults to SRECs) */ \
|
||||
LOAD_CMD, /* download command */ \
|
||||
NULL, /* load response */ \
|
||||
"PPC1-Bug>", /* monitor command prompt */ \
|
||||
"\r", /* end-of-line terminator */ \
|
||||
NULL, /* optional command terminator */ \
|
||||
&OPS, /* target operations */ \
|
||||
SERIAL_1_STOPBITS, /* number of stop bits */ \
|
||||
ppcbug_regnames, /* registers names */ \
|
||||
MONITOR_OPS_MAGIC /* magic */ \
|
||||
}
|
||||
|
||||
|
||||
static struct monitor_ops ppcbug_cmds0 = PPC_CMDS("lo 0\r", ppcbug_ops0);
|
||||
static struct monitor_ops ppcbug_cmds1 = PPC_CMDS("lo 1\r", ppcbug_ops1);
|
||||
|
||||
static void
|
||||
ppcbug_open0(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
monitor_open (args, &ppcbug_cmds0, from_tty);
|
||||
}
|
||||
|
||||
static void
|
||||
ppcbug_open1(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
monitor_open (args, &ppcbug_cmds1, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_ppcbug_rom ()
|
||||
{
|
||||
init_monitor_ops (&ppcbug_ops0);
|
||||
|
||||
ppcbug_ops0.to_shortname = "ppcbug";
|
||||
ppcbug_ops0.to_longname = "PowerPC PPCBug monitor on port 0";
|
||||
ppcbug_ops0.to_doc = "Debug via the PowerPC PPCBug monitor using port 0.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
ppcbug_ops0.to_open = ppcbug_open0;
|
||||
|
||||
add_target (&ppcbug_ops0);
|
||||
|
||||
init_monitor_ops (&ppcbug_ops1);
|
||||
|
||||
ppcbug_ops1.to_shortname = "ppcbug1";
|
||||
ppcbug_ops1.to_longname = "PowerPC PPCBug monitor on port 1";
|
||||
ppcbug_ops1.to_doc = "Debug via the PowerPC PPCBug monitor using port 1.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
ppcbug_ops1.to_open = ppcbug_open1;
|
||||
|
||||
add_target (&ppcbug_ops1);
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,209 +0,0 @@
|
|||
/* Native-dependent code for ptx 4.0
|
||||
Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include <sys/procfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Given a pointer to a general register set in /proc format (gregset_t *),
|
||||
unpack the register contents and supply them as gdb's idea of the current
|
||||
register values. */
|
||||
|
||||
void
|
||||
supply_gregset (gregsetp)
|
||||
gregset_t *gregsetp;
|
||||
{
|
||||
supply_register(EAX_REGNUM, (char *)&(*gregsetp)[EAX]);
|
||||
supply_register(EDX_REGNUM, (char *)&(*gregsetp)[EDX]);
|
||||
supply_register(ECX_REGNUM, (char *)&(*gregsetp)[ECX]);
|
||||
supply_register(EBX_REGNUM, (char *)&(*gregsetp)[EBX]);
|
||||
supply_register(ESI_REGNUM, (char *)&(*gregsetp)[ESI]);
|
||||
supply_register(EDI_REGNUM, (char *)&(*gregsetp)[EDI]);
|
||||
supply_register(ESP_REGNUM, (char *)&(*gregsetp)[UESP]);
|
||||
supply_register(EBP_REGNUM, (char *)&(*gregsetp)[EBP]);
|
||||
supply_register(EIP_REGNUM, (char *)&(*gregsetp)[EIP]);
|
||||
supply_register(EFLAGS_REGNUM, (char *)&(*gregsetp)[EFL]);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregsetp, regno)
|
||||
gregset_t *gregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
extern char registers[];
|
||||
|
||||
for (regi = 0 ; regi < NUM_REGS ; regi++)
|
||||
{
|
||||
if ((regno == -1) || (regno == regi))
|
||||
{
|
||||
(*gregsetp)[regi] = *(greg_t *)®isters[REGISTER_BYTE (regi)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (FP0_REGNUM)
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), unpack the register contents and supply them as gdb's
|
||||
idea of the current floating point register values. */
|
||||
|
||||
void
|
||||
supply_fpregset (fpregsetp)
|
||||
fpregset_t *fpregsetp;
|
||||
{
|
||||
supply_fpu_registers((struct fpusave *)&fpregsetp->fp_reg_set);
|
||||
supply_fpa_registers((struct fpasave *)&fpregsetp->f_wregs);
|
||||
}
|
||||
|
||||
/* Given a pointer to a floating point register set in /proc format
|
||||
(fpregset_t *), update the register specified by REGNO from gdb's idea
|
||||
of the current floating point register set. If REGNO is -1, update
|
||||
them all. */
|
||||
|
||||
void
|
||||
fill_fpregset (fpregsetp, regno)
|
||||
fpregset_t *fpregsetp;
|
||||
int regno;
|
||||
{
|
||||
int regi;
|
||||
char *to;
|
||||
char *from;
|
||||
extern char registers[];
|
||||
|
||||
/* FIXME: see m68k-tdep.c for an example, for the m68k. */
|
||||
}
|
||||
|
||||
#endif /* defined (FP0_REGNUM) */
|
||||
|
||||
/*
|
||||
* This doesn't quite do the same thing as the procfs.c version, but give
|
||||
* it the same name so we don't have to put an ifdef in solib.c.
|
||||
*/
|
||||
/* this could use elf_interpreter() from elfread.c */
|
||||
int
|
||||
proc_iterate_over_mappings(func)
|
||||
int (*func) PARAMS ((int, CORE_ADDR));
|
||||
{
|
||||
vaddr_t curseg, memptr;
|
||||
pt_vseg_t pv;
|
||||
int rv, cmperr;
|
||||
sec_ptr interp_sec;
|
||||
char *interp_content;
|
||||
int interp_fd, funcstat;
|
||||
unsigned int size;
|
||||
char buf1[NBPG], buf2[NBPG];
|
||||
|
||||
/*
|
||||
* The following is really vile. We can get the name of the
|
||||
* shared library from the exec_bfd, and we can get a list of
|
||||
* each virtual memory segment, but there is no simple way to
|
||||
* find the mapped segment from the shared library (ala
|
||||
* procfs's PIOCOPENMEM). As a pretty nasty kludge, we
|
||||
* compare the virtual memory segment to the contents of the
|
||||
* .interp file. If they match, we assume that we've got the
|
||||
* right one.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: for attach, use XPT_OPENT to get the executable, in
|
||||
* case we're attached without knowning the executable's
|
||||
* filename.
|
||||
*/
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
printf("proc_iter\n");
|
||||
#endif
|
||||
interp_sec = bfd_get_section_by_name(exec_bfd, ".interp");
|
||||
if (!interp_sec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = bfd_section_size(exec_bfd, interp_sec);
|
||||
interp_content = alloca(size);
|
||||
if (0 == bfd_get_section_contents(exec_bfd, interp_sec,
|
||||
interp_content, (file_ptr)0, size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
printf("proc_iter: \"%s\"\n", interp_content);
|
||||
#endif
|
||||
interp_fd = open(interp_content, O_RDONLY, 0);
|
||||
if (-1 == interp_fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
curseg = 0;
|
||||
while (1) {
|
||||
rv = ptrace(PT_NEXT_VSEG, inferior_pid, &pv, curseg);
|
||||
#ifdef VERBOSE_DEBUG
|
||||
printf("PT_NEXT_VSEG: rv %d errno %d\n", rv, errno);
|
||||
#endif
|
||||
if (-1 == rv)
|
||||
break;
|
||||
if (0 == rv)
|
||||
break;
|
||||
#ifdef VERBOSE_DEBUG
|
||||
printf("pv.pv_start 0x%x pv_size 0x%x pv_prot 0x%x\n",
|
||||
pv.pv_start, pv.pv_size, pv.pv_prot);
|
||||
#endif
|
||||
curseg = pv.pv_start + pv.pv_size;
|
||||
|
||||
rv = lseek(interp_fd, 0, SEEK_SET);
|
||||
if (-1 == rv) {
|
||||
perror("lseek");
|
||||
close(interp_fd);
|
||||
return 0;
|
||||
}
|
||||
for (memptr = pv.pv_start; memptr < pv.pv_start + pv.pv_size;
|
||||
memptr += NBPG) {
|
||||
#ifdef VERBOSE_DEBUG
|
||||
printf("memptr 0x%x\n", memptr);
|
||||
#endif
|
||||
rv = read(interp_fd, buf1, NBPG);
|
||||
if (-1 == rv) {
|
||||
perror("read");
|
||||
close(interp_fd);
|
||||
return 0;
|
||||
}
|
||||
rv = ptrace(PT_RDATA_PAGE, inferior_pid, buf2,
|
||||
memptr);
|
||||
if (-1 == rv) {
|
||||
perror("ptrace");
|
||||
close(interp_fd);
|
||||
return 0;
|
||||
}
|
||||
cmperr = memcmp(buf1, buf2, NBPG);
|
||||
if (cmperr)
|
||||
break;
|
||||
}
|
||||
if (0 == cmperr) {
|
||||
/* this is it */
|
||||
funcstat = (*func)(interp_fd, pv.pv_start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(interp_fd);
|
||||
return 0;
|
||||
}
|
|
@ -1,452 +0,0 @@
|
|||
/* Pyramid target-dependent code for GDB.
|
||||
Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/*** Prettier register printing. ***/
|
||||
|
||||
/* Print registers in the same format as pyramid's dbx, adb, sdb. */
|
||||
pyr_print_registers(reg_buf, regnum)
|
||||
long *reg_buf[];
|
||||
{
|
||||
register int regno;
|
||||
int usp, ksp;
|
||||
struct user u;
|
||||
|
||||
for (regno = 0; regno < 16; regno++) {
|
||||
printf_unfiltered/*_filtered*/ ("%6.6s: %8x %6.6s: %8x %6s: %8x %6s: %8x\n",
|
||||
reg_names[regno], reg_buf[regno],
|
||||
reg_names[regno+16], reg_buf[regno+16],
|
||||
reg_names[regno+32], reg_buf[regno+32],
|
||||
reg_names[regno+48], reg_buf[regno+48]);
|
||||
}
|
||||
usp = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) ((char *)&u.u_pcb.pcb_usp) -
|
||||
((char *)&u), 0);
|
||||
ksp = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) ((char *)&u.u_pcb.pcb_ksp) -
|
||||
((char *)&u), 0);
|
||||
printf_unfiltered/*_filtered*/ ("\n%6.6s: %8x %6.6s: %8x (%08x) %6.6s %8x\n",
|
||||
reg_names[CSP_REGNUM],reg_buf[CSP_REGNUM],
|
||||
reg_names[KSP_REGNUM], reg_buf[KSP_REGNUM], ksp,
|
||||
"usp", usp);
|
||||
}
|
||||
|
||||
/* Print the register regnum, or all registers if regnum is -1.
|
||||
fpregs is currently ignored. */
|
||||
|
||||
pyr_do_registers_info (regnum, fpregs)
|
||||
int regnum;
|
||||
int fpregs;
|
||||
{
|
||||
/* On a pyr, we know a virtual register can always fit in an long.
|
||||
Here (and elsewhere) we take advantage of that. Yuk. */
|
||||
long raw_regs[MAX_REGISTER_RAW_SIZE*NUM_REGS];
|
||||
register int i;
|
||||
|
||||
for (i = 0 ; i < 64 ; i++) {
|
||||
read_relative_register_raw_bytes(i, raw_regs+i);
|
||||
}
|
||||
if (regnum == -1)
|
||||
pyr_print_registers (raw_regs, regnum);
|
||||
else
|
||||
for (i = 0; i < NUM_REGS; i++)
|
||||
if (i == regnum) {
|
||||
long val = raw_regs[i];
|
||||
|
||||
fputs_filtered (reg_names[i], stdout);
|
||||
printf_filtered(":");
|
||||
print_spaces_filtered (6 - strlen (reg_names[i]), stdout);
|
||||
if (val == 0)
|
||||
printf_filtered ("0");
|
||||
else
|
||||
printf_filtered ("%s %d", local_hex_string_custom(val,"08"), val);
|
||||
printf_filtered("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*** Debugging editions of various macros from m-pyr.h ****/
|
||||
|
||||
CORE_ADDR frame_locals_address (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
register int addr = find_saved_register (frame,CFP_REGNUM);
|
||||
register int result = read_memory_integer (addr, 4);
|
||||
#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING
|
||||
fprintf_unfiltered (stderr,
|
||||
"\t[[..frame_locals:%8x, %s= %x @%x fcfp= %x foo= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n",
|
||||
frame->frame,
|
||||
reg_names[CFP_REGNUM],
|
||||
result, addr,
|
||||
frame->frame_cfp, (CFP_REGNUM),
|
||||
|
||||
|
||||
read_register(13), read_register(29), read_register(61),
|
||||
find_saved_register(frame, 61));
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
|
||||
/* FIXME: I thought read_register (CFP_REGNUM) should be the right answer;
|
||||
or at least CFP_REGNUM relative to FRAME (ie, result).
|
||||
There seems to be a bug in the way the innermost frame is set up. */
|
||||
|
||||
return ((frame->next) ? result: frame->frame_cfp);
|
||||
}
|
||||
|
||||
CORE_ADDR frame_args_addr (frame)
|
||||
struct frame_info *frame;
|
||||
{
|
||||
register int addr = find_saved_register (frame,CFP_REGNUM);
|
||||
register int result = read_memory_integer (addr, 4);
|
||||
|
||||
#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING
|
||||
fprintf_unfiltered (stderr,
|
||||
"\t[[..frame_args:%8x, %s= %x @%x fcfp= %x r_r= %x\n\t gr13=%x pr13=%x tr13=%x @%x]]\n",
|
||||
frame->frame,
|
||||
reg_names[CFP_REGNUM],
|
||||
result, addr,
|
||||
frame->frame_cfp, read_register(CFP_REGNUM),
|
||||
|
||||
read_register(13), read_register(29), read_register(61),
|
||||
find_saved_register(frame, 61));
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
|
||||
/* FIXME: I thought read_register (CFP_REGNUM) should be the right answer;
|
||||
or at least CFP_REGNUM relative to FRAME (ie, result).
|
||||
There seems to be a bug in the way the innermost frame is set up. */
|
||||
return ((frame->next) ? result: frame->frame_cfp);
|
||||
}
|
||||
|
||||
#include "symtab.h"
|
||||
#include "opcode/pyr.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
|
||||
/* A couple of functions used for debugging frame-handling on
|
||||
Pyramids. (The Pyramid-dependent handling of register values for
|
||||
windowed registers is known to be buggy.)
|
||||
|
||||
When debugging, these functions can supplant the normal definitions of some
|
||||
of the macros in tm-pyramid.h The quantity of information produced
|
||||
when these functions are used makes the gdb unusable as a
|
||||
debugger for user programs. */
|
||||
|
||||
extern unsigned pyr_saved_pc(), pyr_frame_chain();
|
||||
|
||||
CORE_ADDR pyr_frame_chain(frame)
|
||||
CORE_ADDR frame;
|
||||
{
|
||||
int foo=frame - CONTROL_STACK_FRAME_SIZE;
|
||||
/* printf_unfiltered ("...following chain from %x: got %x\n", frame, foo);*/
|
||||
return foo;
|
||||
}
|
||||
|
||||
CORE_ADDR pyr_saved_pc(frame)
|
||||
CORE_ADDR frame;
|
||||
{
|
||||
int foo=0;
|
||||
foo = read_memory_integer (((CORE_ADDR)(frame))+60, 4);
|
||||
printf_unfiltered ("..reading pc from frame 0x%0x+%d regs: got %0x\n",
|
||||
frame, 60/4, foo);
|
||||
return foo;
|
||||
}
|
||||
|
||||
/* Pyramid instructions are never longer than this many bytes. */
|
||||
#define MAXLEN 24
|
||||
|
||||
/* Number of elements in the opcode table. */
|
||||
/*const*/ static int nopcodes = (sizeof (pyr_opcodes) / sizeof( pyr_opcodes[0]));
|
||||
#define NOPCODES (nopcodes)
|
||||
|
||||
/* Let's be byte-independent so we can use this as a cross-assembler. */
|
||||
|
||||
#define NEXTLONG(p) \
|
||||
(p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
|
||||
|
||||
/* Print one instruction at address MEMADDR in debugged memory,
|
||||
on STREAM. Returns length of the instruction, in bytes. */
|
||||
|
||||
int
|
||||
pyr_print_insn (memaddr, stream)
|
||||
CORE_ADDR memaddr;
|
||||
FILE *stream;
|
||||
{
|
||||
unsigned char buffer[MAXLEN];
|
||||
register int i, nargs, insn_size =4;
|
||||
register unsigned char *p;
|
||||
register char *d;
|
||||
register int insn_opcode, operand_mode;
|
||||
register int index_multiplier, index_reg_regno, op_1_regno, op_2_regno ;
|
||||
long insn; /* first word of the insn, not broken down. */
|
||||
pyr_insn_format insn_decode; /* the same, broken out into op{code,erands} */
|
||||
long extra_1, extra_2;
|
||||
|
||||
read_memory (memaddr, buffer, MAXLEN);
|
||||
insn_decode = *((pyr_insn_format *) buffer);
|
||||
insn = * ((int *) buffer);
|
||||
insn_opcode = insn_decode.operator;
|
||||
operand_mode = insn_decode.mode;
|
||||
index_multiplier = insn_decode.index_scale;
|
||||
index_reg_regno = insn_decode.index_reg;
|
||||
op_1_regno = insn_decode.operand_1;
|
||||
op_2_regno = insn_decode.operand_2;
|
||||
|
||||
|
||||
if (*((int *)buffer) == 0x0) {
|
||||
/* "halt" looks just like an invalid "jump" to the insn decoder,
|
||||
so is dealt with as a special case */
|
||||
fprintf_unfiltered (stream, "halt");
|
||||
return (4);
|
||||
}
|
||||
|
||||
for (i = 0; i < NOPCODES; i++)
|
||||
if (pyr_opcodes[i].datum.code == insn_opcode)
|
||||
break;
|
||||
|
||||
if (i == NOPCODES)
|
||||
/* FIXME: Handle unrecognised instructions better. */
|
||||
fprintf_unfiltered (stream, "???\t#%08x\t(op=%x mode =%x)",
|
||||
insn, insn_decode.operator, insn_decode.mode);
|
||||
else
|
||||
{
|
||||
/* Print the mnemonic for the instruction. Pyramid insn operands
|
||||
are so regular that we can deal with almost all of them
|
||||
separately.
|
||||
Unconditional branches are an exception: they are encoded as
|
||||
conditional branches (branch if false condition, I think)
|
||||
with no condition specified. The average user will not be
|
||||
aware of this. To maintain their illusion that an
|
||||
unconditional branch insn exists, we will have to FIXME to
|
||||
treat the insn mnemnonic of all branch instructions here as a
|
||||
special case: check the operands of branch insn and print an
|
||||
appropriate mnemonic. */
|
||||
|
||||
fprintf_unfiltered (stream, "%s\t", pyr_opcodes[i].name);
|
||||
|
||||
/* Print the operands of the insn (as specified in
|
||||
insn.operand_mode).
|
||||
Branch operands of branches are a special case: they are a word
|
||||
offset, not a byte offset. */
|
||||
|
||||
if (insn_decode.operator == 0x01 || insn_decode.operator == 0x02) {
|
||||
register int bit_codes=(insn >> 16)&0xf;
|
||||
register int i;
|
||||
register int displacement = (insn & 0x0000ffff) << 2;
|
||||
|
||||
static char cc_bit_names[] = "cvzn"; /* z,n,c,v: strange order? */
|
||||
|
||||
/* Is bfc and no bits specified an unconditional branch?*/
|
||||
for (i=0;i<4;i++) {
|
||||
if ((bit_codes) & 0x1)
|
||||
fputc_unfiltered (cc_bit_names[i], stream);
|
||||
bit_codes >>= 1;
|
||||
}
|
||||
|
||||
fprintf_unfiltered (stream, ",%0x",
|
||||
displacement + memaddr);
|
||||
return (insn_size);
|
||||
}
|
||||
|
||||
switch (operand_mode) {
|
||||
case 0:
|
||||
fprintf_unfiltered (stream, "%s,%s",
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
fprintf_unfiltered (stream, " 0x%0x,%s",
|
||||
op_1_regno,
|
||||
reg_names [op_2_regno]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream, " $0x%0x,%s",
|
||||
extra_1,
|
||||
reg_names [op_2_regno]);
|
||||
break;
|
||||
case 3:
|
||||
fprintf_unfiltered (stream, " (%s),%s",
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno]);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream, " 0x%0x(%s),%s",
|
||||
extra_1,
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno]);
|
||||
break;
|
||||
|
||||
/* S1 destination mode */
|
||||
case 5:
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? "%s,(%s)[%s*%1d]" : "%s,(%s)"),
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]"
|
||||
: " $%#0x,(%s)"),
|
||||
op_1_regno,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]"
|
||||
: " $%#0x,(%s)"),
|
||||
extra_1,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? " (%s),(%s)[%s*%1d]" : " (%s),(%s)"),
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno)
|
||||
? "%#0x(%s),(%s)[%s*%1d]"
|
||||
: "%#0x(%s),(%s)"),
|
||||
extra_1,
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
/* S2 destination mode */
|
||||
case 10:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? "%s,%#0x(%s)[%s*%1d]" : "%s,%#0x(%s)"),
|
||||
reg_names [op_1_regno],
|
||||
extra_1,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
case 11:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ?
|
||||
" $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"),
|
||||
op_1_regno,
|
||||
extra_1,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
case 12:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
read_memory (memaddr+8, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_2 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ?
|
||||
" $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"),
|
||||
extra_1,
|
||||
extra_2,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno)
|
||||
? " (%s),%#0x(%s)[%s*%1d]"
|
||||
: " (%s),%#0x(%s)"),
|
||||
reg_names [op_1_regno],
|
||||
extra_1,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
case 14:
|
||||
read_memory (memaddr+4, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_1 = * ((int *) buffer);
|
||||
read_memory (memaddr+8, buffer, MAXLEN);
|
||||
insn_size += 4;
|
||||
extra_2 = * ((int *) buffer);
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? "%#0x(%s),%#0x(%s)[%s*%1d]"
|
||||
: "%#0x(%s),%#0x(%s) "),
|
||||
extra_1,
|
||||
reg_names [op_1_regno],
|
||||
extra_2,
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf_unfiltered (stream,
|
||||
((index_reg_regno) ? "%s,%s [%s*%1d]" : "%s,%s"),
|
||||
reg_names [op_1_regno],
|
||||
reg_names [op_2_regno],
|
||||
reg_names [index_reg_regno],
|
||||
index_multiplier);
|
||||
fprintf_unfiltered (stream,
|
||||
"\t\t# unknown mode in %08x",
|
||||
insn);
|
||||
break;
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
{
|
||||
return insn_size;
|
||||
}
|
||||
abort ();
|
||||
}
|
|
@ -1,370 +0,0 @@
|
|||
/* Low level Pyramid interface to ptrace, for GDB when running under Unix.
|
||||
Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
/* #include <fcntl.h> Can we live without this? */
|
||||
|
||||
#include "gdbcore.h"
|
||||
#include <sys/user.h> /* After a.out.h */
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
|
||||
void
|
||||
fetch_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register int datum;
|
||||
register unsigned int regaddr;
|
||||
int reg_buf[NUM_REGS+1];
|
||||
struct user u;
|
||||
register int skipped_frames = 0;
|
||||
|
||||
registers_fetched ();
|
||||
|
||||
for (regno = 0; regno < 64; regno++) {
|
||||
reg_buf[regno] = ptrace (3, inferior_pid, (PTRACE_ARG3_TYPE) regno, 0);
|
||||
|
||||
#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING)
|
||||
printf_unfiltered ("Fetching register %s, got %0x\n",
|
||||
reg_names[regno],
|
||||
reg_buf[regno]);
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
|
||||
if (reg_buf[regno] == -1 && errno == EIO) {
|
||||
printf_unfiltered("fetch_interior_registers: fetching register %s\n",
|
||||
reg_names[regno]);
|
||||
errno = 0;
|
||||
}
|
||||
supply_register (regno, reg_buf+regno);
|
||||
}
|
||||
/* that leaves regs 64, 65, and 66 */
|
||||
datum = ptrace (3, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (((char *)&u.u_pcb.pcb_csp) -
|
||||
((char *)&u)), 0);
|
||||
|
||||
|
||||
|
||||
/* FIXME: Find the Current Frame Pointer (CFP). CFP is a global
|
||||
register (ie, NOT windowed), that gets saved in a frame iff
|
||||
the code for that frame has a prologue (ie, "adsf N"). If
|
||||
there is a prologue, the adsf insn saves the old cfp in
|
||||
pr13, cfp is set to sp, and N bytes of locals are allocated
|
||||
(sp is decremented by n).
|
||||
This makes finding CFP hard. I guess the right way to do it
|
||||
is:
|
||||
- If this is the innermost frame, believe ptrace() or
|
||||
the core area.
|
||||
- Otherwise:
|
||||
Find the first insn of the current frame.
|
||||
- find the saved pc;
|
||||
- find the call insn that saved it;
|
||||
- figure out where the call is to;
|
||||
- if the first insn is an adsf, we got a frame
|
||||
pointer. */
|
||||
|
||||
|
||||
/* Normal processors have separate stack pointers for user and
|
||||
kernel mode. Getting the last user mode frame on such
|
||||
machines is easy: the kernel context of the ptrace()'d
|
||||
process is on the kernel stack, and the USP points to what
|
||||
we want. But Pyramids only have a single cfp for both user and
|
||||
kernel mode. And processes being ptrace()'d have some
|
||||
kernel-context control frames on their stack.
|
||||
To avoid tracing back into the kernel context of an inferior,
|
||||
we skip 0 or more contiguous control frames where the pc is
|
||||
in the kernel. */
|
||||
|
||||
while (1) {
|
||||
register int inferior_saved_pc;
|
||||
inferior_saved_pc = ptrace (1, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) (datum+((32+15)*4)), 0);
|
||||
if (inferior_saved_pc > 0) break;
|
||||
#if defined(PYRAMID_CONTROL_FRAME_DEBUGGING)
|
||||
printf_unfiltered("skipping kernel frame %08x, pc=%08x\n", datum,
|
||||
inferior_saved_pc);
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
skipped_frames++;
|
||||
datum -= CONTROL_STACK_FRAME_SIZE;
|
||||
}
|
||||
|
||||
reg_buf[CSP_REGNUM] = datum;
|
||||
supply_register(CSP_REGNUM, reg_buf+CSP_REGNUM);
|
||||
#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING
|
||||
if (skipped_frames) {
|
||||
fprintf_unfiltered (stderr,
|
||||
"skipped %d frames from %x to %x; cfp was %x, now %x\n",
|
||||
skipped_frames, reg_buf[CSP_REGNUM]);
|
||||
}
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
}
|
||||
|
||||
/* 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). */
|
||||
|
||||
void
|
||||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
register unsigned int regaddr;
|
||||
char buf[80];
|
||||
|
||||
if (regno >= 0)
|
||||
{
|
||||
if ((0 <= regno) && (regno < 64)) {
|
||||
/*regaddr = register_addr (regno, offset);*/
|
||||
regaddr = regno;
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
|
||||
read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
/*regaddr = register_addr (regno, offset);*/
|
||||
regaddr = regno;
|
||||
errno = 0;
|
||||
ptrace (6, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
|
||||
read_register (regno));
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing all regs, number %d", regno);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*** Extensions to core and dump files, for GDB. */
|
||||
|
||||
extern unsigned int last_frame_offset;
|
||||
|
||||
#ifdef PYRAMID_CORE
|
||||
|
||||
/* Can't make definitions here static, since corefile.c needs them
|
||||
to do bounds checking on the core-file areas. O well. */
|
||||
|
||||
/* have two stacks: one for data, one for register windows. */
|
||||
extern CORE_ADDR reg_stack_start;
|
||||
extern CORE_ADDR reg_stack_end;
|
||||
|
||||
/* need this so we can find the global registers: they never get saved. */
|
||||
CORE_ADDR global_reg_offset;
|
||||
static CORE_ADDR last_frame_address;
|
||||
CORE_ADDR last_frame_offset;
|
||||
|
||||
|
||||
/* Address in core file of start of register window stack area.
|
||||
Don't know if is this any of meaningful, useful or necessary. */
|
||||
extern int reg_stack_offset;
|
||||
|
||||
#endif /* PYRAMID_CORE */
|
||||
|
||||
|
||||
/* Work with core dump and executable files, for GDB.
|
||||
This code would be in corefile.c if it weren't machine-dependent. */
|
||||
|
||||
void
|
||||
core_file_command (filename, from_tty)
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
int val;
|
||||
extern char registers[];
|
||||
|
||||
/* Discard all vestiges of any previous core file
|
||||
and mark data and stack spaces as empty. */
|
||||
|
||||
if (corefile)
|
||||
free (corefile);
|
||||
corefile = 0;
|
||||
|
||||
if (corechan >= 0)
|
||||
close (corechan);
|
||||
corechan = -1;
|
||||
|
||||
data_start = 0;
|
||||
data_end = 0;
|
||||
stack_start = STACK_END_ADDR;
|
||||
stack_end = STACK_END_ADDR;
|
||||
|
||||
#ifdef PYRAMID_CORE
|
||||
reg_stack_start = CONTROL_STACK_ADDR;
|
||||
reg_stack_end = CONTROL_STACK_ADDR; /* this isn't strictly true...*/
|
||||
#endif /* PYRAMID_CORE */
|
||||
|
||||
/* Now, if a new core file was specified, open it and digest it. */
|
||||
|
||||
if (filename)
|
||||
{
|
||||
filename = tilde_expand (filename);
|
||||
make_cleanup (free, filename);
|
||||
|
||||
if (have_inferior_p ())
|
||||
error ("To look at a core file, you must kill the program with \"kill\".");
|
||||
corechan = open (filename, O_RDONLY, 0);
|
||||
if (corechan < 0)
|
||||
perror_with_name (filename);
|
||||
/* 4.2-style (and perhaps also sysV-style) core dump file. */
|
||||
{
|
||||
struct user u;
|
||||
|
||||
unsigned int reg_offset;
|
||||
|
||||
val = myread (corechan, &u, sizeof u);
|
||||
if (val < 0)
|
||||
perror_with_name ("Not a core file: reading upage");
|
||||
if (val != sizeof u)
|
||||
error ("Not a core file: could only read %d bytes", val);
|
||||
data_start = exec_data_start;
|
||||
|
||||
data_end = data_start + NBPG * u.u_dsize;
|
||||
data_offset = NBPG * UPAGES;
|
||||
stack_offset = NBPG * (UPAGES + u.u_dsize);
|
||||
|
||||
/* find registers in core file */
|
||||
#ifdef PYRAMID_PTRACE
|
||||
stack_start = stack_end - NBPG * u.u_ussize;
|
||||
reg_stack_offset = stack_offset + (NBPG *u.u_ussize);
|
||||
reg_stack_end = reg_stack_start + NBPG * u.u_cssize;
|
||||
|
||||
last_frame_address = ((int) u.u_pcb.pcb_csp);
|
||||
last_frame_offset = reg_stack_offset + last_frame_address
|
||||
- CONTROL_STACK_ADDR ;
|
||||
global_reg_offset = (char *)&u - (char *)&u.u_pcb.pcb_gr0 ;
|
||||
|
||||
/* skip any control-stack frames that were executed in the
|
||||
kernel. */
|
||||
|
||||
while (1) {
|
||||
char buf[4];
|
||||
val = lseek (corechan, last_frame_offset+(47*4), 0);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
val = myread (corechan, buf, sizeof buf);
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
|
||||
if (*(int *)buf >= 0)
|
||||
break;
|
||||
printf_unfiltered ("skipping frame %s\n", local_hex_string (last_frame_address));
|
||||
last_frame_offset -= CONTROL_STACK_FRAME_SIZE;
|
||||
last_frame_address -= CONTROL_STACK_FRAME_SIZE;
|
||||
}
|
||||
reg_offset = last_frame_offset;
|
||||
|
||||
#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING)
|
||||
printf_unfiltered ("Control stack pointer = %s\n",
|
||||
local_hex_string (u.u_pcb.pcb_csp));
|
||||
printf_unfiltered ("offset to control stack %d outermost frame %d (%s)\n",
|
||||
reg_stack_offset, reg_offset, local_hex_string (last_frame_address));
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
|
||||
#else /* not PYRAMID_CORE */
|
||||
stack_start = stack_end - NBPG * u.u_ssize;
|
||||
reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
|
||||
#endif /* not PYRAMID_CORE */
|
||||
|
||||
#ifdef __not_on_pyr_yet
|
||||
/* 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;
|
||||
#endif
|
||||
|
||||
/* 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. */
|
||||
|
||||
{
|
||||
register int regno;
|
||||
|
||||
for (regno = 0; regno < 64; regno++)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
val = lseek (corechan, register_addr (regno, reg_offset), 0);
|
||||
if (val < 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);
|
||||
}
|
||||
|
||||
if (val < 0)
|
||||
perror_with_name (filename);
|
||||
#ifdef PYRAMID_CONTROL_FRAME_DEBUGGING
|
||||
printf_unfiltered ("[reg %s(%d), offset in file %s=0x%0x, addr =0x%0x, =%0x]\n",
|
||||
reg_names[regno], regno, filename,
|
||||
register_addr(regno, reg_offset),
|
||||
regno * 4 + last_frame_address,
|
||||
*((int *)buf));
|
||||
#endif /* PYRAMID_CONTROL_FRAME_DEBUGGING */
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
corefile = savestring (filename, strlen (filename));
|
||||
else
|
||||
{
|
||||
corefile = concat (current_directory, "/", filename, NULL);
|
||||
}
|
||||
|
||||
#if 1 || defined(PYRAMID_CONTROL_FRAME_DEBUGGING)
|
||||
printf_unfiltered ("Providing CSP (%s) as nominal address of current frame.\n",
|
||||
local_hex_string(last_frame_address));
|
||||
#endif PYRAMID_CONTROL_FRAME_DEBUGGING
|
||||
/* FIXME: Which of the following is correct? */
|
||||
#if 0
|
||||
set_current_frame ( create_new_frame (read_register (FP_REGNUM),
|
||||
read_pc ()));
|
||||
#else
|
||||
set_current_frame ( create_new_frame (last_frame_address,
|
||||
read_pc ()));
|
||||
#endif
|
||||
|
||||
select_frame (get_current_frame (), 0);
|
||||
validate_files ();
|
||||
}
|
||||
else if (from_tty)
|
||||
printf_unfiltered ("No core file now.\n");
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,174 +0,0 @@
|
|||
/* Remote debugging interface for EST-300 ICE, for GDB
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
Contributed by Cygnus Support.
|
||||
|
||||
Written by Steve Chamberlain for Cygnus Support.
|
||||
Re-written by Stu Grossman of Cygnus Support
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
|
||||
static void est_open PARAMS ((char *args, int from_tty));
|
||||
|
||||
static void
|
||||
est_supply_register (regname, regnamelen, val, vallen)
|
||||
char *regname;
|
||||
int regnamelen;
|
||||
char *val;
|
||||
int vallen;
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (regnamelen != 2)
|
||||
return;
|
||||
|
||||
switch (regname[0])
|
||||
{
|
||||
case 'S':
|
||||
if (regname[1] != 'R')
|
||||
return;
|
||||
regno = PS_REGNUM;
|
||||
break;
|
||||
case 'P':
|
||||
if (regname[1] != 'C')
|
||||
return;
|
||||
regno = PC_REGNUM;
|
||||
break;
|
||||
case 'D':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + D0_REGNUM;
|
||||
break;
|
||||
case 'A':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + A0_REGNUM;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_supply_register (regno, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* This array of registers needs to match the indexes used by GDB. The
|
||||
* whole reason this exists is because the various ROM monitors use
|
||||
* different names than GDB does, and don't support all the
|
||||
* registers either. So, typing "info reg sp" becomes a "r30".
|
||||
*/
|
||||
|
||||
static char *est_regnames[NUM_REGS] =
|
||||
{
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
||||
"SR", "PC",
|
||||
};
|
||||
|
||||
/*
|
||||
* Define the monitor command strings. Since these are passed directly
|
||||
* through to a printf style function, we need can include formatting
|
||||
* strings. We also need a CR or LF on the end.
|
||||
*/
|
||||
|
||||
static struct target_ops est_ops;
|
||||
|
||||
static char *est_inits[] = {"he\r", /* Resets the prompt, and clears repeated cmds */
|
||||
NULL};
|
||||
|
||||
static struct monitor_ops est_cmds =
|
||||
{
|
||||
MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_NEED_REGDUMP_AFTER_CONT,
|
||||
est_inits, /* Init strings */
|
||||
"go\r", /* continue command */
|
||||
"sidr\r", /* single step */
|
||||
"\003", /* ^C interrupts the program */
|
||||
"sb %x\r", /* set a breakpoint */
|
||||
"rb %x\r", /* clear a breakpoint */
|
||||
"rb\r", /* clear all breakpoints */
|
||||
"bfb %x %x %x\r", /* fill (start end val) */
|
||||
{
|
||||
"smb %x %x\r", /* setmem.cmdb (addr, value) */
|
||||
"smw %x %x\r", /* setmem.cmdw (addr, value) */
|
||||
"sml %x %x\r", /* setmem.cmdl (addr, value) */
|
||||
NULL, /* setmem.cmdll (addr, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL, /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"dmb %x %x\r", /* getmem.cmdb (addr, len) */
|
||||
"dmw %x %x\r", /* getmem.cmdw (addr, len) */
|
||||
"dml %x %x\r", /* getmem.cmdl (addr, len) */
|
||||
NULL, /* getmem.cmdll (addr, len) */
|
||||
": ", /* getmem.resp_delim */
|
||||
NULL, /* getmem.term */
|
||||
NULL, /* getmem.term_cmd */
|
||||
},
|
||||
{
|
||||
"sr %s %x\r", /* setreg.cmd (name, value) */
|
||||
NULL, /* setreg.resp_delim */
|
||||
NULL, /* setreg.term */
|
||||
NULL /* setreg.term_cmd */
|
||||
},
|
||||
{
|
||||
"dr %s\r", /* getreg.cmd (name) */
|
||||
" = ", /* getreg.resp_delim */
|
||||
NULL, /* getreg.term */
|
||||
NULL /* getreg.term_cmd */
|
||||
},
|
||||
"dr\r", /* dump_registers */
|
||||
"\\(\\w+\\) = \\([0-9a-fA-F]+\\)", /* register_pattern */
|
||||
est_supply_register, /* supply_register */
|
||||
NULL, /* load_routine (defaults to SRECs) */
|
||||
"dl\r", /* download command */
|
||||
"+", /* load response */
|
||||
">BKM>", /* monitor command prompt */
|
||||
"\r", /* end-of-line terminator */
|
||||
NULL, /* optional command terminator */
|
||||
&est_ops, /* target operations */
|
||||
SERIAL_1_STOPBITS, /* number of stop bits */
|
||||
est_regnames, /* registers names */
|
||||
MONITOR_OPS_MAGIC /* magic */
|
||||
};
|
||||
|
||||
static void
|
||||
est_open(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
monitor_open (args, &est_cmds, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_est ()
|
||||
{
|
||||
init_monitor_ops (&est_ops);
|
||||
|
||||
est_ops.to_shortname = "est";
|
||||
est_ops.to_longname = "EST background debug monitor";
|
||||
est_ops.to_doc = "Debug via the EST BDM.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
est_ops.to_open = est_open;
|
||||
|
||||
add_target (&est_ops);
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,820 +0,0 @@
|
|||
/* Memory-access and commands for remote NINDY process, for GDB.
|
||||
Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
Contributed by Intel Corporation. Modified from remote.c by Chris Benenati.
|
||||
|
||||
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY. No author or distributor accepts responsibility to anyone
|
||||
for the consequences of using it or for whether it serves any
|
||||
particular purpose or works at all, unless he says so in writing.
|
||||
Refer to the GDB General Public License for full details.
|
||||
|
||||
Everyone is granted permission to copy, modify and redistribute GDB,
|
||||
but only under the conditions described in the GDB General Public
|
||||
License. A copy of this license is supposed to have been given to you
|
||||
along with GDB so you can know your rights and responsibilities. It
|
||||
should be in a file named COPYING. Among other things, the copyright
|
||||
notice and this notice must be preserved on all copies.
|
||||
|
||||
In other words, go ahead and share GDB, but don't try to stop
|
||||
anyone else from sharing it farther. Help stamp out software hoarding!
|
||||
*/
|
||||
|
||||
/*
|
||||
Except for the data cache routines, this file bears little resemblence
|
||||
to remote.c. A new (although similar) protocol has been specified, and
|
||||
portions of the code are entirely dependent on having an i80960 with a
|
||||
NINDY ROM monitor at the other end of the line.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* REMOTE COMMUNICATION PROTOCOL BETWEEN GDB960 AND THE NINDY ROM MONITOR.
|
||||
*
|
||||
*
|
||||
* MODES OF OPERATION
|
||||
* ----- -- ---------
|
||||
*
|
||||
* As far as NINDY is concerned, GDB is always in one of two modes: command
|
||||
* mode or passthrough mode.
|
||||
*
|
||||
* In command mode (the default) pre-defined packets containing requests
|
||||
* are sent by GDB to NINDY. NINDY never talks except in reponse to a request.
|
||||
*
|
||||
* Once the the user program is started, GDB enters passthrough mode, to give
|
||||
* the user program access to the terminal. GDB remains in this mode until
|
||||
* NINDY indicates that the program has stopped.
|
||||
*
|
||||
*
|
||||
* PASSTHROUGH MODE
|
||||
* ----------- ----
|
||||
*
|
||||
* GDB writes all input received from the keyboard directly to NINDY, and writes
|
||||
* all characters received from NINDY directly to the monitor.
|
||||
*
|
||||
* Keyboard input is neither buffered nor echoed to the monitor.
|
||||
*
|
||||
* GDB remains in passthrough mode until NINDY sends a single ^P character,
|
||||
* to indicate that the user process has stopped.
|
||||
*
|
||||
* Note:
|
||||
* GDB assumes NINDY performs a 'flushreg' when the user program stops.
|
||||
*
|
||||
*
|
||||
* COMMAND MODE
|
||||
* ------- ----
|
||||
*
|
||||
* All info (except for message ack and nak) is transferred between gdb
|
||||
* and the remote processor in messages of the following format:
|
||||
*
|
||||
* <info>#<checksum>
|
||||
*
|
||||
* where
|
||||
* # is a literal character
|
||||
*
|
||||
* <info> ASCII information; all numeric information is in the
|
||||
* form of hex digits ('0'-'9' and lowercase 'a'-'f').
|
||||
*
|
||||
* <checksum>
|
||||
* is a pair of ASCII hex digits representing an 8-bit
|
||||
* checksum formed by adding together each of the
|
||||
* characters in <info>.
|
||||
*
|
||||
* The receiver of a message always sends a single character to the sender
|
||||
* to indicate that the checksum was good ('+') or bad ('-'); the sender
|
||||
* re-transmits the entire message over until a '+' is received.
|
||||
*
|
||||
* In response to a command NINDY always sends back either data or
|
||||
* a result code of the form "Xnn", where "nn" are hex digits and "X00"
|
||||
* means no errors. (Exceptions: the "s" and "c" commands don't respond.)
|
||||
*
|
||||
* SEE THE HEADER OF THE FILE "gdb.c" IN THE NINDY MONITOR SOURCE CODE FOR A
|
||||
* FULL DESCRIPTION OF LEGAL COMMANDS.
|
||||
*
|
||||
* SEE THE FILE "stop.h" IN THE NINDY MONITOR SOURCE CODE FOR A LIST
|
||||
* OF STOP CODES.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "defs.h"
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "bfd.h"
|
||||
#include "symfile.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "floatformat.h"
|
||||
|
||||
#include "wait.h"
|
||||
#include <sys/file.h>
|
||||
#include <ctype.h>
|
||||
#include "serial.h"
|
||||
#include "nindy-share/env.h"
|
||||
#include "nindy-share/stop.h"
|
||||
|
||||
#include "dcache.h"
|
||||
#include "remote-utils.h"
|
||||
|
||||
static DCACHE *nindy_dcache;
|
||||
|
||||
extern int unlink();
|
||||
extern char *getenv();
|
||||
extern char *mktemp();
|
||||
|
||||
extern void generic_mourn_inferior ();
|
||||
|
||||
extern struct target_ops nindy_ops;
|
||||
extern GDB_FILE *instream;
|
||||
|
||||
extern char ninStopWhy ();
|
||||
extern int ninMemGet ();
|
||||
extern int ninMemPut ();
|
||||
|
||||
int nindy_initial_brk; /* nonzero if want to send an initial BREAK to nindy */
|
||||
int nindy_old_protocol; /* nonzero if want to use old protocol */
|
||||
char *nindy_ttyname; /* name of tty to talk to nindy on, or null */
|
||||
|
||||
#define DLE '\020' /* Character NINDY sends to indicate user program has
|
||||
* halted. */
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* From nindy-share/nindy.c. */
|
||||
extern serial_t nindy_serial;
|
||||
|
||||
static int have_regs = 0; /* 1 iff regs read since i960 last halted */
|
||||
static int regs_changed = 0; /* 1 iff regs were modified since last read */
|
||||
|
||||
extern char *exists();
|
||||
|
||||
static void
|
||||
nindy_fetch_registers PARAMS ((int));
|
||||
|
||||
static void
|
||||
nindy_store_registers PARAMS ((int));
|
||||
|
||||
static char *savename;
|
||||
|
||||
static void
|
||||
nindy_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
if (nindy_serial != NULL)
|
||||
SERIAL_CLOSE (nindy_serial);
|
||||
nindy_serial = NULL;
|
||||
|
||||
if (savename)
|
||||
free (savename);
|
||||
savename = 0;
|
||||
}
|
||||
|
||||
/* Open a connection to a remote debugger.
|
||||
FIXME, there should be "set" commands for the options that are
|
||||
now specified with gdb command-line options (old_protocol,
|
||||
and initial_brk). */
|
||||
void
|
||||
nindy_open (name, from_tty)
|
||||
char *name; /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */
|
||||
int from_tty;
|
||||
{
|
||||
char baudrate[1024];
|
||||
|
||||
if (!name)
|
||||
error_no_arg ("serial port device name");
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
nindy_close (0);
|
||||
|
||||
have_regs = regs_changed = 0;
|
||||
nindy_dcache = dcache_init(ninMemGet, ninMemPut);
|
||||
|
||||
/* Allow user to interrupt the following -- we could hang if there's
|
||||
no NINDY at the other end of the remote tty. */
|
||||
immediate_quit++;
|
||||
/* If baud_rate is -1, then ninConnect will not recognize the baud rate
|
||||
and will deal with the situation in a (more or less) reasonable
|
||||
fashion. */
|
||||
sprintf(baudrate, "%d", baud_rate);
|
||||
ninConnect(name, baudrate,
|
||||
nindy_initial_brk, !from_tty, nindy_old_protocol);
|
||||
immediate_quit--;
|
||||
|
||||
if (nindy_serial == NULL)
|
||||
{
|
||||
perror_with_name (name);
|
||||
}
|
||||
|
||||
savename = savestring (name, strlen (name));
|
||||
push_target (&nindy_ops);
|
||||
target_fetch_registers(-1);
|
||||
}
|
||||
|
||||
/* User-initiated quit of nindy operations. */
|
||||
|
||||
static void
|
||||
nindy_detach (name, from_tty)
|
||||
char *name;
|
||||
int from_tty;
|
||||
{
|
||||
if (name)
|
||||
error ("Too many arguments");
|
||||
pop_target ();
|
||||
}
|
||||
|
||||
static void
|
||||
nindy_files_info ()
|
||||
{
|
||||
/* FIXME: this lies about the baud rate if we autobauded. */
|
||||
printf_unfiltered("\tAttached to %s at %d bits per second%s%s.\n", savename,
|
||||
baud_rate,
|
||||
nindy_old_protocol? " in old protocol": "",
|
||||
nindy_initial_brk? " with initial break": "");
|
||||
}
|
||||
|
||||
/* Return the number of characters in the buffer before
|
||||
the first DLE character. */
|
||||
|
||||
static
|
||||
int
|
||||
non_dle( buf, n )
|
||||
char *buf; /* Character buffer; NOT '\0'-terminated */
|
||||
int n; /* Number of characters in buffer */
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < n; i++ ){
|
||||
if ( buf[i] == DLE ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Tell the remote machine to resume. */
|
||||
|
||||
void
|
||||
nindy_resume (pid, step, siggnal)
|
||||
int pid, step;
|
||||
enum target_signal siggnal;
|
||||
{
|
||||
if (siggnal != TARGET_SIGNAL_0 && siggnal != stop_signal)
|
||||
warning ("Can't send signals to remote NINDY targets.");
|
||||
|
||||
dcache_flush(nindy_dcache);
|
||||
if ( regs_changed )
|
||||
{
|
||||
nindy_store_registers (-1);
|
||||
regs_changed = 0;
|
||||
}
|
||||
have_regs = 0;
|
||||
ninGo( step );
|
||||
}
|
||||
|
||||
/* FIXME, we can probably use the normal terminal_inferior stuff here.
|
||||
We have to do terminal_inferior and then set up the passthrough
|
||||
settings initially. Thereafter, terminal_ours and terminal_inferior
|
||||
will automatically swap the settings around for us. */
|
||||
|
||||
struct clean_up_tty_args {
|
||||
serial_ttystate state;
|
||||
serial_t serial;
|
||||
};
|
||||
static struct clean_up_tty_args tty_args;
|
||||
|
||||
static void
|
||||
clean_up_tty (ptrarg)
|
||||
PTR ptrarg;
|
||||
{
|
||||
struct clean_up_tty_args *args = (struct clean_up_tty_args *) ptrarg;
|
||||
SERIAL_SET_TTY_STATE (args->serial, args->state);
|
||||
free (args->state);
|
||||
warning ("\n\nYou may need to reset the 80960 and/or reload your program.\n");
|
||||
}
|
||||
|
||||
/* Recover from ^Z or ^C while remote process is running */
|
||||
static void (*old_ctrlc)();
|
||||
#ifdef SIGTSTP
|
||||
static void (*old_ctrlz)();
|
||||
#endif
|
||||
|
||||
static void
|
||||
clean_up_int()
|
||||
{
|
||||
SERIAL_SET_TTY_STATE (tty_args.serial, tty_args.state);
|
||||
free (tty_args.state);
|
||||
|
||||
signal(SIGINT, old_ctrlc);
|
||||
#ifdef SIGTSTP
|
||||
signal(SIGTSTP, old_ctrlz);
|
||||
#endif
|
||||
error("\n\nYou may need to reset the 80960 and/or reload your program.\n");
|
||||
}
|
||||
|
||||
/* Wait until the remote machine stops. While waiting, operate in passthrough
|
||||
* mode; i.e., pass everything NINDY sends to gdb_stdout, and everything from
|
||||
* stdin to NINDY.
|
||||
*
|
||||
* Return to caller, storing status in 'status' just as `wait' would.
|
||||
*/
|
||||
|
||||
static int
|
||||
nindy_wait( pid, status )
|
||||
int pid;
|
||||
struct target_waitstatus *status;
|
||||
{
|
||||
fd_set fds;
|
||||
int c;
|
||||
char buf[2];
|
||||
int i, n;
|
||||
unsigned char stop_exit;
|
||||
unsigned char stop_code;
|
||||
struct cleanup *old_cleanups;
|
||||
long ip_value, fp_value, sp_value; /* Reg values from stop */
|
||||
|
||||
status->kind = TARGET_WAITKIND_EXITED;
|
||||
status->value.integer = 0;
|
||||
|
||||
/* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */
|
||||
|
||||
/* Save current tty attributes, and restore them when done. */
|
||||
tty_args.serial = SERIAL_FDOPEN (0);
|
||||
tty_args.state = SERIAL_GET_TTY_STATE (tty_args.serial);
|
||||
old_ctrlc = signal( SIGINT, clean_up_int );
|
||||
#ifdef SIGTSTP
|
||||
old_ctrlz = signal( SIGTSTP, clean_up_int );
|
||||
#endif
|
||||
|
||||
old_cleanups = make_cleanup (clean_up_tty, &tty_args);
|
||||
|
||||
/* Pass input from keyboard to NINDY as it arrives. NINDY will interpret
|
||||
<CR> and perform echo. */
|
||||
/* This used to set CBREAK and clear ECHO and CRMOD. I hope this is close
|
||||
enough. */
|
||||
SERIAL_RAW (tty_args.serial);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Input on remote */
|
||||
c = SERIAL_READCHAR (nindy_serial, -1);
|
||||
if (c == SERIAL_ERROR)
|
||||
{
|
||||
error ("Cannot read from serial line");
|
||||
}
|
||||
else if (c == 0x1b) /* ESC */
|
||||
{
|
||||
c = SERIAL_READCHAR (nindy_serial, -1);
|
||||
c &= ~0x40;
|
||||
}
|
||||
else if (c != 0x10) /* DLE */
|
||||
/* Write out any characters preceding DLE */
|
||||
{
|
||||
buf[0] = (char)c;
|
||||
write (1, buf, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
stop_exit = ninStopWhy(&stop_code,
|
||||
&ip_value, &fp_value, &sp_value);
|
||||
if (!stop_exit && (stop_code == STOP_SRQ))
|
||||
{
|
||||
immediate_quit++;
|
||||
ninSrq();
|
||||
immediate_quit--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get out of loop */
|
||||
supply_register (IP_REGNUM,
|
||||
(char *)&ip_value);
|
||||
supply_register (FP_REGNUM,
|
||||
(char *)&fp_value);
|
||||
supply_register (SP_REGNUM,
|
||||
(char *)&sp_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SERIAL_SET_TTY_STATE (tty_args.serial, tty_args.state);
|
||||
free (tty_args.state);
|
||||
discard_cleanups (old_cleanups);
|
||||
|
||||
if (stop_exit)
|
||||
{
|
||||
status->kind = TARGET_WAITKIND_EXITED;
|
||||
status->value.integer = stop_code;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nindy has some special stop code need to be handled */
|
||||
if (stop_code == STOP_GDB_BPT)
|
||||
stop_code = TRACE_STEP;
|
||||
status->kind = TARGET_WAITKIND_STOPPED;
|
||||
status->value.sig = i960_fault_to_signal (stop_code);
|
||||
}
|
||||
return inferior_pid;
|
||||
}
|
||||
|
||||
/* Read the remote registers into the block REGS. */
|
||||
|
||||
/* This is the block that ninRegsGet and ninRegsPut handles. */
|
||||
struct nindy_regs {
|
||||
char local_regs[16 * 4];
|
||||
char global_regs[16 * 4];
|
||||
char pcw_acw[2 * 4];
|
||||
char ip[4];
|
||||
char tcw[4];
|
||||
char fp_as_double[4 * 8];
|
||||
};
|
||||
|
||||
static void
|
||||
nindy_fetch_registers(regno)
|
||||
int regno;
|
||||
{
|
||||
struct nindy_regs nindy_regs;
|
||||
int regnum, inv;
|
||||
double dub;
|
||||
|
||||
immediate_quit++;
|
||||
ninRegsGet( (char *) &nindy_regs );
|
||||
immediate_quit--;
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4);
|
||||
memcpy (®isters[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4);
|
||||
memcpy (®isters[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4);
|
||||
memcpy (®isters[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4);
|
||||
memcpy (®isters[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4);
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
|
||||
dub = unpack_double (builtin_type_double,
|
||||
&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
|
||||
&inv);
|
||||
/* dub now in host byte order */
|
||||
floatformat_from_double (&floatformat_i960_ext, &dub,
|
||||
®isters[REGISTER_BYTE (regnum)]);
|
||||
}
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
static void
|
||||
nindy_prepare_to_store()
|
||||
{
|
||||
/* Fetch all regs if they aren't already here. */
|
||||
read_register_bytes (0, NULL, REGISTER_BYTES);
|
||||
}
|
||||
|
||||
static void
|
||||
nindy_store_registers(regno)
|
||||
int regno;
|
||||
{
|
||||
struct nindy_regs nindy_regs;
|
||||
int regnum;
|
||||
double dub;
|
||||
|
||||
memcpy (nindy_regs.local_regs, ®isters[REGISTER_BYTE (R0_REGNUM)], 16*4);
|
||||
memcpy (nindy_regs.global_regs, ®isters[REGISTER_BYTE (G0_REGNUM)], 16*4);
|
||||
memcpy (nindy_regs.pcw_acw, ®isters[REGISTER_BYTE (PCW_REGNUM)], 2*4);
|
||||
memcpy (nindy_regs.ip, ®isters[REGISTER_BYTE (IP_REGNUM)], 1*4);
|
||||
memcpy (nindy_regs.tcw, ®isters[REGISTER_BYTE (TCW_REGNUM)], 1*4);
|
||||
for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++)
|
||||
{
|
||||
floatformat_to_double (&floatformat_i960_ext,
|
||||
®isters[REGISTER_BYTE (regnum)], &dub);
|
||||
store_floating (&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
|
||||
REGISTER_VIRTUAL_SIZE (regnum),
|
||||
dub);
|
||||
}
|
||||
|
||||
immediate_quit++;
|
||||
ninRegsPut( (char *) &nindy_regs );
|
||||
immediate_quit--;
|
||||
}
|
||||
|
||||
/* Read a word from remote address ADDR and return it.
|
||||
* This goes through the data cache.
|
||||
*/
|
||||
int
|
||||
nindy_fetch_word (addr)
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
return dcache_fetch (nindy_dcache, addr);
|
||||
}
|
||||
|
||||
/* Write a word WORD into remote address ADDR.
|
||||
This goes through the data cache. */
|
||||
|
||||
void
|
||||
nindy_store_word (addr, word)
|
||||
CORE_ADDR addr;
|
||||
int word;
|
||||
{
|
||||
dcache_poke (nindy_dcache, addr, word);
|
||||
}
|
||||
|
||||
/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR. Copy to inferior if
|
||||
WRITE is nonzero. Returns the length copied.
|
||||
|
||||
This is stolen almost directly from infptrace.c's child_xfer_memory,
|
||||
which also deals with a word-oriented memory interface. Sometime,
|
||||
FIXME, rewrite this to not use the word-oriented routines. */
|
||||
|
||||
int
|
||||
nindy_xfer_inferior_memory(memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target; /* ignored */
|
||||
{
|
||||
register int i;
|
||||
/* 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) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
|
||||
if (write)
|
||||
{
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (addr != memaddr || len < (int)sizeof (int)) {
|
||||
/* Need part of initial word -- fetch it. */
|
||||
buffer[0] = nindy_fetch_word (addr);
|
||||
}
|
||||
|
||||
if (count > 1) /* FIXME, avoid if even boundary */
|
||||
{
|
||||
buffer[count - 1]
|
||||
= nindy_fetch_word (addr + (count - 1) * sizeof (int));
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
nindy_store_word (addr, buffer[i]);
|
||||
if (errno)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
buffer[i] = nindy_fetch_word (addr);
|
||||
if (errno)
|
||||
return 0;
|
||||
QUIT;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
nindy_create_inferior (execfile, args, env)
|
||||
char *execfile;
|
||||
char *args;
|
||||
char **env;
|
||||
{
|
||||
int entry_pt;
|
||||
int pid;
|
||||
|
||||
if (args && *args)
|
||||
error ("Can't pass arguments to remote NINDY process");
|
||||
|
||||
if (execfile == 0 || exec_bfd == 0)
|
||||
error ("No exec file specified");
|
||||
|
||||
entry_pt = (int) bfd_get_start_address (exec_bfd);
|
||||
|
||||
pid = 42;
|
||||
|
||||
/* The "process" (board) is already stopped awaiting our commands, and
|
||||
the program is already downloaded. We just set its PC and go. */
|
||||
|
||||
inferior_pid = pid; /* Needed for wait_for_inferior below */
|
||||
|
||||
clear_proceed_status ();
|
||||
|
||||
/* Tell wait_for_inferior that we've started a new process. */
|
||||
init_wait_for_inferior ();
|
||||
|
||||
/* Set up the "saved terminal modes" of the inferior
|
||||
based on what modes we are starting it with. */
|
||||
target_terminal_init ();
|
||||
|
||||
/* Install inferior's terminal modes. */
|
||||
target_terminal_inferior ();
|
||||
|
||||
/* insert_step_breakpoint (); FIXME, do we need this? */
|
||||
/* Let 'er rip... */
|
||||
proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_command(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
if (nindy_serial == NULL)
|
||||
{
|
||||
error( "No target system to reset -- use 'target nindy' command.");
|
||||
}
|
||||
if ( query("Really reset the target system?",0,0) )
|
||||
{
|
||||
SERIAL_SEND_BREAK (nindy_serial);
|
||||
tty_flush (nindy_serial);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nindy_kill (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
return; /* Ignore attempts to kill target system */
|
||||
}
|
||||
|
||||
/* Clean up when a program exits.
|
||||
|
||||
The program actually lives on in the remote processor's RAM, and may be
|
||||
run again without a download. Don't leave it full of breakpoint
|
||||
instructions. */
|
||||
|
||||
void
|
||||
nindy_mourn_inferior ()
|
||||
{
|
||||
remove_breakpoints ();
|
||||
unpush_target (&nindy_ops);
|
||||
generic_mourn_inferior (); /* Do all the proper things now */
|
||||
}
|
||||
|
||||
/* Pass the args the way catch_errors wants them. */
|
||||
static int
|
||||
nindy_open_stub (arg)
|
||||
char *arg;
|
||||
{
|
||||
nindy_open (arg, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
nindy_load( filename, from_tty )
|
||||
char *filename;
|
||||
int from_tty;
|
||||
{
|
||||
asection *s;
|
||||
/* Can't do unix style forking on a VMS system, so we'll use bfd to do
|
||||
all the work for us
|
||||
*/
|
||||
|
||||
bfd *file = bfd_openr(filename,0);
|
||||
if (!file)
|
||||
{
|
||||
perror_with_name(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bfd_check_format(file, bfd_object))
|
||||
{
|
||||
error("can't prove it's an object file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for ( s = file->sections; s; s=s->next)
|
||||
{
|
||||
if (s->flags & SEC_LOAD)
|
||||
{
|
||||
char *buffer = xmalloc(s->_raw_size);
|
||||
bfd_get_section_contents(file, s, buffer, 0, s->_raw_size);
|
||||
printf("Loading section %s, size %x vma %x\n",
|
||||
s->name,
|
||||
s->_raw_size,
|
||||
s->vma);
|
||||
ninMemPut(s->vma, buffer, s->_raw_size);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
bfd_close(file);
|
||||
}
|
||||
|
||||
static int
|
||||
load_stub (arg)
|
||||
char *arg;
|
||||
{
|
||||
target_load (arg, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This routine is run as a hook, just before the main command loop is
|
||||
entered. If gdb is configured for the i960, but has not had its
|
||||
nindy target specified yet, this will loop prompting the user to do so.
|
||||
|
||||
Unlike the loop provided by Intel, we actually let the user get out
|
||||
of this with a RETURN. This is useful when e.g. simply examining
|
||||
an i960 object file on the host system. */
|
||||
|
||||
void
|
||||
nindy_before_main_loop ()
|
||||
{
|
||||
char ttyname[100];
|
||||
char *p, *p2;
|
||||
|
||||
while (target_stack->target_ops != &nindy_ops) /* What is this crap??? */
|
||||
{ /* remote tty not specified yet */
|
||||
if ( instream == stdin ){
|
||||
printf_unfiltered("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: ");
|
||||
gdb_flush( gdb_stdout );
|
||||
}
|
||||
fgets( ttyname, sizeof(ttyname)-1, stdin );
|
||||
|
||||
/* Strip leading and trailing whitespace */
|
||||
for ( p = ttyname; isspace(*p); p++ ){
|
||||
;
|
||||
}
|
||||
if ( *p == '\0' ){
|
||||
return; /* User just hit spaces or return, wants out */
|
||||
}
|
||||
for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){
|
||||
;
|
||||
}
|
||||
*p2= '\0';
|
||||
if ( STREQ("quit",p) ){
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (catch_errors (nindy_open_stub, p, "", RETURN_MASK_ALL))
|
||||
{
|
||||
/* Now that we have a tty open for talking to the remote machine,
|
||||
download the executable file if one was specified. */
|
||||
if (exec_bfd)
|
||||
{
|
||||
catch_errors (load_stub, bfd_get_filename (exec_bfd), "",
|
||||
RETURN_MASK_ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the target subroutine names */
|
||||
|
||||
struct target_ops nindy_ops = {
|
||||
"nindy", "Remote serial target in i960 NINDY-specific protocol",
|
||||
"Use a remote i960 system running NINDY connected by a serial line.\n\
|
||||
Specify the name of the device the serial line is connected to.\n\
|
||||
The speed (baud rate), whether to use the old NINDY protocol,\n\
|
||||
and whether to send a break on startup, are controlled by options\n\
|
||||
specified when you started GDB.",
|
||||
nindy_open, nindy_close,
|
||||
0,
|
||||
nindy_detach,
|
||||
nindy_resume,
|
||||
nindy_wait,
|
||||
nindy_fetch_registers, nindy_store_registers,
|
||||
nindy_prepare_to_store,
|
||||
nindy_xfer_inferior_memory, nindy_files_info,
|
||||
memory_insert_breakpoint,
|
||||
memory_remove_breakpoint,
|
||||
0, 0, 0, 0, 0, /* Terminal crud */
|
||||
nindy_kill,
|
||||
nindy_load,
|
||||
0, /* lookup_symbol */
|
||||
nindy_create_inferior,
|
||||
nindy_mourn_inferior,
|
||||
0, /* can_run */
|
||||
0, /* notice_signals */
|
||||
0, /* to_thread_alive */
|
||||
0, /* to_stop */
|
||||
process_stratum, 0, /* next */
|
||||
1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
|
||||
0, 0, /* Section pointers */
|
||||
OPS_MAGIC, /* Always the last thing */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_nindy ()
|
||||
{
|
||||
add_target (&nindy_ops);
|
||||
add_com ("reset", class_obscure, reset_command,
|
||||
"Send a 'break' to the remote target system.\n\
|
||||
Only useful if the target has been equipped with a circuit\n\
|
||||
to perform a hard reset when a break is detected.");
|
||||
}
|
|
@ -1,332 +0,0 @@
|
|||
/* Remote debugging with the XLNT Designs, Inc (XDI) NetROM.
|
||||
Copyright 1990, 1991, 1992, 1995 Free Software Foundation, Inc.
|
||||
Contributed by:
|
||||
Roger Moyers
|
||||
XLNT Designs, Inc.
|
||||
15050 Avenue of Science, Suite 106
|
||||
San Diego, CA 92128
|
||||
(619)487-9320
|
||||
roger@xlnt.com
|
||||
Adapted from work done at Cygnus Support in remote-nindy.c,
|
||||
later merged in by Stan Shebs at Cygnus.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "serial.h"
|
||||
#include "target.h"
|
||||
|
||||
/* Default ports used to talk with the NetROM. */
|
||||
|
||||
#define DEFAULT_NETROM_LOAD_PORT 1236
|
||||
#define DEFAULT_NETROM_CONTROL_PORT 1237
|
||||
|
||||
static void nrom_close PARAMS ((int quitting));
|
||||
|
||||
/* New commands. */
|
||||
|
||||
static void nrom_passthru PARAMS ((char *, int));
|
||||
|
||||
/* We talk to the NetROM over these sockets. */
|
||||
|
||||
static serial_t load_desc = NULL;
|
||||
static serial_t ctrl_desc = NULL;
|
||||
|
||||
static int load_port = DEFAULT_NETROM_LOAD_PORT;
|
||||
static int control_port = DEFAULT_NETROM_CONTROL_PORT;
|
||||
|
||||
static char nrom_hostname[100];
|
||||
|
||||
/* Forward data declaration. */
|
||||
|
||||
extern struct target_ops nrom_ops;
|
||||
|
||||
/* Scan input from the remote system, until STRING is found. Print chars that
|
||||
don't match. */
|
||||
|
||||
static int
|
||||
expect (string)
|
||||
char *string;
|
||||
{
|
||||
char *p = string;
|
||||
int c;
|
||||
|
||||
immediate_quit = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
c = SERIAL_READCHAR (ctrl_desc, 5);
|
||||
|
||||
if (c == *p++)
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
immediate_quit = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc_unfiltered (c, gdb_stdout);
|
||||
p = string;
|
||||
if (c == *p)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nrom_kill ()
|
||||
{
|
||||
nrom_close (0);
|
||||
}
|
||||
|
||||
static serial_t
|
||||
open_socket (name, port)
|
||||
char *name;
|
||||
int port;
|
||||
{
|
||||
char sockname[100];
|
||||
serial_t desc;
|
||||
|
||||
sprintf (sockname, "%s:%d", name, port);
|
||||
desc = SERIAL_OPEN (sockname);
|
||||
if (!desc)
|
||||
perror_with_name (sockname);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void
|
||||
load_cleanup ()
|
||||
{
|
||||
SERIAL_CLOSE (load_desc);
|
||||
load_desc = NULL;
|
||||
}
|
||||
|
||||
/* Download a file specified in ARGS to the netROM. */
|
||||
|
||||
static void
|
||||
nrom_load (args, fromtty)
|
||||
char *args;
|
||||
int fromtty;
|
||||
{
|
||||
int fd, rd_amt, fsize;
|
||||
bfd *pbfd;
|
||||
asection *section;
|
||||
char *downloadstring = "download 0\n";
|
||||
struct cleanup *old_chain;
|
||||
|
||||
/* Tell the netrom to get ready to download. */
|
||||
if (SERIAL_WRITE (ctrl_desc, downloadstring, strlen (downloadstring)))
|
||||
error ("nrom_load: control_send() of `%s' failed", downloadstring);
|
||||
|
||||
expect ("Waiting for a connection...\n");
|
||||
|
||||
load_desc = open_socket (nrom_hostname, load_port);
|
||||
|
||||
old_chain = make_cleanup (load_cleanup, 0);
|
||||
|
||||
pbfd = bfd_openr (args, 0);
|
||||
|
||||
if (pbfd)
|
||||
{
|
||||
make_cleanup (bfd_close, pbfd);
|
||||
|
||||
if (!bfd_check_format (pbfd, bfd_object))
|
||||
error ("\"%s\": not in executable format: %s",
|
||||
args, bfd_errmsg (bfd_get_error ()));
|
||||
|
||||
for (section = pbfd->sections; section; section = section->next)
|
||||
{
|
||||
if (bfd_get_section_flags (pbfd, section) & SEC_ALLOC)
|
||||
{
|
||||
bfd_vma section_address;
|
||||
unsigned long section_size;
|
||||
const char *section_name;
|
||||
|
||||
section_name = bfd_get_section_name (pbfd, section);
|
||||
section_address = bfd_get_section_vma (pbfd, section);
|
||||
section_size = bfd_section_size (pbfd, section);
|
||||
|
||||
if (bfd_get_section_flags (pbfd, section) & SEC_LOAD)
|
||||
{
|
||||
file_ptr fptr;
|
||||
|
||||
printf_filtered ("[Loading section %s at %x (%d bytes)]\n",
|
||||
section_name, section_address,
|
||||
section_size);
|
||||
|
||||
fptr = 0;
|
||||
|
||||
while (section_size > 0)
|
||||
{
|
||||
char buffer[1024];
|
||||
int count;
|
||||
|
||||
count = min (section_size, 1024);
|
||||
|
||||
bfd_get_section_contents (pbfd, section, buffer, fptr,
|
||||
count);
|
||||
|
||||
SERIAL_WRITE (load_desc, buffer, count);
|
||||
section_address += count;
|
||||
fptr += count;
|
||||
section_size -= count;
|
||||
}
|
||||
}
|
||||
else /* BSS and such */
|
||||
{
|
||||
printf_filtered ("[section %s: not loading]\n",
|
||||
section_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
error ("\"%s\": Could not open", args);
|
||||
|
||||
do_cleanups (old_chain);
|
||||
}
|
||||
|
||||
/* Open a connection to the remote NetROM devices. */
|
||||
|
||||
static void
|
||||
nrom_open (name, from_tty)
|
||||
char *name;
|
||||
int from_tty;
|
||||
{
|
||||
int errn;
|
||||
|
||||
if (!name || strchr (name, '/') || strchr (name, ':'))
|
||||
error (
|
||||
"To open a NetROM connection, you must specify the hostname\n\
|
||||
or IP address of the NetROM device you wish to use.");
|
||||
|
||||
strcpy (nrom_hostname, name);
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
unpush_target (&nrom_ops);
|
||||
|
||||
ctrl_desc = open_socket (nrom_hostname, control_port);
|
||||
|
||||
push_target (&nrom_ops);
|
||||
|
||||
if (from_tty)
|
||||
printf_filtered ("Connected to NetROM device \"%s\"\n", nrom_hostname);
|
||||
}
|
||||
|
||||
/* Close out all files and local state before this target loses control. */
|
||||
|
||||
static void
|
||||
nrom_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
if (load_desc)
|
||||
SERIAL_CLOSE (load_desc);
|
||||
if (ctrl_desc)
|
||||
SERIAL_CLOSE (ctrl_desc);
|
||||
}
|
||||
|
||||
/* Pass arguments directly to the NetROM. */
|
||||
|
||||
static void
|
||||
nrom_passthru (args, fromtty)
|
||||
char *args;
|
||||
int fromtty;
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
sprintf (buf, "%s\n", args);
|
||||
if (SERIAL_WRITE (ctrl_desc, buf, strlen (buf)))
|
||||
error ("nrom_reset: control_send() of `%s'failed", args);
|
||||
}
|
||||
|
||||
static void
|
||||
nrom_mourn()
|
||||
{
|
||||
unpush_target (&nrom_ops);
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
||||
/* Define the target vector. */
|
||||
|
||||
struct target_ops nrom_ops = {
|
||||
"nrom", /* to_shortname */
|
||||
"Remote XDI `NetROM' target", /* to_longname */
|
||||
"Remote debug using a NetROM over Ethernet", /* to_doc */
|
||||
nrom_open, /* to_open */
|
||||
nrom_close, /* to_close */
|
||||
NULL, /* to_attach */
|
||||
NULL, /* to_detach */
|
||||
NULL, /* to_resume */
|
||||
NULL, /* to_wait */
|
||||
NULL, /* to_fetch_registers */
|
||||
NULL, /* to_store_registers */
|
||||
NULL, /* to_prepare_to_store */
|
||||
NULL, /* to_xfer_memory */
|
||||
NULL, /* to_files_info */
|
||||
NULL, /* to_insert_breakpoint */
|
||||
NULL, /* to_remove_breakpoint */
|
||||
NULL, /* to_terminal_init */
|
||||
NULL, /* to_terminal_inferior */
|
||||
NULL, /* to_terminal_ours_for_output */
|
||||
NULL, /* to_terminal_ours */
|
||||
NULL, /* to_terminal_info */
|
||||
nrom_kill, /* to_kill */
|
||||
nrom_load, /* to_load */
|
||||
NULL, /* to_lookup_symbol */
|
||||
NULL, /* to_create_inferior */
|
||||
nrom_mourn, /* to_mourn_inferior */
|
||||
NULL, /* to_can_run */
|
||||
0, /* to_notice_signals */
|
||||
0, /* to_thread_alive */
|
||||
0, /* to_stop */
|
||||
download_stratum, /* to_stratum */
|
||||
NULL, /* to_next */
|
||||
1, /* to_has_all_memory */
|
||||
1, /* to_has_memory */
|
||||
1, /* to_has_stack */
|
||||
1, /* to_has_registers */
|
||||
0, /* to_has_execution */
|
||||
NULL, /* sections */
|
||||
NULL, /* sections_end */
|
||||
OPS_MAGIC /* to_magic */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_remote_nrom ()
|
||||
{
|
||||
add_target (&nrom_ops);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("nrom_load_port", no_class, var_zinteger, (char *)&load_port,
|
||||
"Set the port to use for NetROM downloads\n", &setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("nrom_control_port", no_class, var_zinteger, (char *)&control_port,
|
||||
"Set the port to use for NetROM debugger services\n", &setlist),
|
||||
&showlist);
|
||||
|
||||
add_cmd ("nrom", no_class, nrom_passthru,
|
||||
"Pass arguments as command to NetROM",
|
||||
&cmdlist);
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,468 +0,0 @@
|
|||
/* Generic remote debugging interface for simulators.
|
||||
Copyright 1993, 1994 Free Software Foundation, Inc.
|
||||
Contributed by Cygnus Support.
|
||||
Steve Chamberlain (sac@cygnus.com).
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "value.h"
|
||||
#include "gdb_string.h"
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <errno.h>
|
||||
#include "terminal.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "remote-sim.h"
|
||||
#include "remote-utils.h"
|
||||
#include "callback.h"
|
||||
|
||||
/* Naming convention:
|
||||
|
||||
sim_* are the interface to the simulator (see remote-sim.h).
|
||||
sim_callback_* are the stuff which the simulator can see inside GDB.
|
||||
gdbsim_* are stuff which is internal to gdb. */
|
||||
|
||||
/* Forward data declarations */
|
||||
extern struct target_ops gdbsim_ops;
|
||||
|
||||
static int program_loaded = 0;
|
||||
|
||||
static void
|
||||
dump_mem (buf, len)
|
||||
char *buf;
|
||||
int len;
|
||||
{
|
||||
if (len <= 8)
|
||||
{
|
||||
if (len == 8 || len == 4)
|
||||
{
|
||||
long l[2];
|
||||
memcpy (l, buf, len);
|
||||
printf_filtered ("\t0x%x", l[0]);
|
||||
printf_filtered (len == 8 ? " 0x%x\n" : "\n", l[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
printf_filtered ("\t");
|
||||
for (i = 0; i < len; i++)
|
||||
printf_filtered ("0x%x ", buf[i]);
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdbsim_fetch_register (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno == -1)
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
gdbsim_fetch_register (regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
|
||||
sim_fetch_register (regno, buf);
|
||||
supply_register (regno, buf);
|
||||
if (sr_get_debug ())
|
||||
{
|
||||
printf_filtered ("gdbsim_fetch_register: %d", regno);
|
||||
/* FIXME: We could print something more intelligible. */
|
||||
dump_mem (buf, REGISTER_RAW_SIZE (regno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gdbsim_store_register (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno == -1)
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
gdbsim_store_register (regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Until read_register() returns LONGEST, we have this. */
|
||||
char tmp[MAX_REGISTER_RAW_SIZE];
|
||||
read_register_gen (regno, tmp);
|
||||
sim_store_register (regno, tmp);
|
||||
if (sr_get_debug ())
|
||||
{
|
||||
printf_filtered ("gdbsim_store_register: %d", regno);
|
||||
/* FIXME: We could print something more intelligible. */
|
||||
dump_mem (tmp, REGISTER_RAW_SIZE (regno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Kill the running program. This may involve closing any open files
|
||||
and releasing other resources acquired by the simulated program. */
|
||||
|
||||
static void
|
||||
gdbsim_kill ()
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_kill\n");
|
||||
|
||||
sim_kill (); /* close fd's, remove mappings */
|
||||
inferior_pid = 0;
|
||||
}
|
||||
|
||||
/* Load an executable file into the target process. This is expected to
|
||||
not only bring new code into the target process, but also to update
|
||||
GDB's symbol tables to match. */
|
||||
|
||||
static void
|
||||
gdbsim_load (prog, fromtty)
|
||||
char *prog;
|
||||
int fromtty;
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_load: prog \"%s\"\n", prog);
|
||||
|
||||
inferior_pid = 0;
|
||||
|
||||
/* This must be done before calling gr_load_image. */
|
||||
program_loaded = 1;
|
||||
|
||||
if (sim_load (prog, fromtty) != 0)
|
||||
generic_load (prog, fromtty);
|
||||
}
|
||||
|
||||
|
||||
/* Start an inferior process and set inferior_pid to its pid.
|
||||
EXEC_FILE is the file to run.
|
||||
ALLARGS is a string containing the arguments to the program.
|
||||
ENV is the environment vector to pass. Errors reported with error().
|
||||
On VxWorks and various standalone systems, we ignore exec_file. */
|
||||
/* This is called not only when we first attach, but also when the
|
||||
user types "run" after having attached. */
|
||||
|
||||
static void
|
||||
gdbsim_create_inferior (exec_file, args, env)
|
||||
char *exec_file;
|
||||
char *args;
|
||||
char **env;
|
||||
{
|
||||
int len;
|
||||
char *arg_buf,**argv;
|
||||
CORE_ADDR entry_pt;
|
||||
|
||||
if (! program_loaded)
|
||||
error ("No program loaded.");
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_create_inferior: exec_file \"%s\", args \"%s\"\n",
|
||||
exec_file, args);
|
||||
|
||||
if (exec_file == 0 || exec_bfd == 0)
|
||||
error ("No exec file specified.");
|
||||
|
||||
entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
|
||||
|
||||
gdbsim_kill (NULL, NULL);
|
||||
remove_breakpoints ();
|
||||
init_wait_for_inferior ();
|
||||
|
||||
len = 5 + strlen (exec_file) + 1 + strlen (args) + 1 + /*slop*/ 10;
|
||||
arg_buf = (char *) alloca (len);
|
||||
arg_buf[0] = '\0';
|
||||
strcat (arg_buf, exec_file);
|
||||
strcat (arg_buf, " ");
|
||||
strcat (arg_buf, args);
|
||||
argv = buildargv (arg_buf);
|
||||
make_cleanup (freeargv, (char *) argv);
|
||||
sim_create_inferior (entry_pt, argv, env);
|
||||
|
||||
inferior_pid = 42;
|
||||
insert_breakpoints (); /* Needed to get correct instruction in cache */
|
||||
proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
|
||||
}
|
||||
|
||||
/* The open routine takes the rest of the parameters from the command,
|
||||
and (if successful) pushes a new target onto the stack.
|
||||
Targets should supply this routine, if only to provide an error message. */
|
||||
/* Called when selecting the simulator. EG: (gdb) target sim name. */
|
||||
|
||||
static void
|
||||
gdbsim_open (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_open: args \"%s\"\n", args ? args : "(null)");
|
||||
|
||||
sim_set_callbacks (&default_callback);
|
||||
default_callback.init (&default_callback);
|
||||
|
||||
sim_open (args);
|
||||
|
||||
push_target (&gdbsim_ops);
|
||||
target_fetch_registers (-1);
|
||||
printf_filtered ("Connected to the simulator.\n");
|
||||
}
|
||||
|
||||
/* Does whatever cleanup is required for a target that we are no longer
|
||||
going to be calling. Argument says whether we are quitting gdb and
|
||||
should not get hung in case of errors, or whether we want a clean
|
||||
termination even if it takes a while. This routine is automatically
|
||||
always called just before a routine is popped off the target stack.
|
||||
Closing file descriptors and freeing memory are typical things it should
|
||||
do. */
|
||||
/* Close out all files and local state before this target loses control. */
|
||||
|
||||
static void
|
||||
gdbsim_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_close: quitting %d\n", quitting);
|
||||
|
||||
program_loaded = 0;
|
||||
|
||||
sim_close (quitting);
|
||||
}
|
||||
|
||||
/* Takes a program previously attached to and detaches it.
|
||||
The program may resume execution (some targets do, some don't) and will
|
||||
no longer stop on signals, etc. We better not have left any breakpoints
|
||||
in the program or it'll die when it hits one. ARGS is arguments
|
||||
typed by the user (e.g. a signal to send the process). FROM_TTY
|
||||
says whether to be verbose or not. */
|
||||
/* Terminate the open connection to the remote debugger.
|
||||
Use this when you want to detach and do something else with your gdb. */
|
||||
|
||||
static void
|
||||
gdbsim_detach (args,from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_detach: args \"%s\"\n", args);
|
||||
|
||||
pop_target (); /* calls gdbsim_close to do the real work */
|
||||
if (from_tty)
|
||||
printf_filtered ("Ending simulator %s debugging\n", target_shortname);
|
||||
}
|
||||
|
||||
/* Resume execution of the target process. STEP says whether to single-step
|
||||
or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
|
||||
to the target, or zero for no signal. */
|
||||
|
||||
static void
|
||||
gdbsim_resume (pid, step, siggnal)
|
||||
int pid, step;
|
||||
enum target_signal siggnal;
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_resume: step %d, signal %d\n", step, siggnal);
|
||||
|
||||
sim_resume (step, target_signal_to_host (siggnal));
|
||||
}
|
||||
|
||||
/* Wait for inferior process to do something. Return pid of child,
|
||||
or -1 in case of error; store status through argument pointer STATUS,
|
||||
just as `wait' would. */
|
||||
|
||||
static int
|
||||
gdbsim_wait (pid, status)
|
||||
int pid;
|
||||
struct target_waitstatus *status;
|
||||
{
|
||||
int sigrc;
|
||||
enum sim_stop reason;
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_wait\n");
|
||||
|
||||
sim_stop_reason (&reason, &sigrc);
|
||||
switch (reason)
|
||||
{
|
||||
case sim_exited:
|
||||
status->kind = TARGET_WAITKIND_EXITED;
|
||||
status->value.integer = sigrc;
|
||||
break;
|
||||
case sim_stopped:
|
||||
status->kind = TARGET_WAITKIND_STOPPED;
|
||||
/* The signal in sigrc is a host signal. That probably
|
||||
should be fixed. */
|
||||
status->value.sig = target_signal_from_host (sigrc);
|
||||
break;
|
||||
case sim_signalled:
|
||||
status->kind = TARGET_WAITKIND_SIGNALLED;
|
||||
/* The signal in sigrc is a host signal. That probably
|
||||
should be fixed. */
|
||||
status->value.sig = target_signal_from_host (sigrc);
|
||||
break;
|
||||
}
|
||||
|
||||
return inferior_pid;
|
||||
}
|
||||
|
||||
/* Get ready to modify the registers array. On machines which store
|
||||
individual registers, this doesn't need to do anything. On machines
|
||||
which store all the registers in one fell swoop, this makes sure
|
||||
that registers contains all the registers from the program being
|
||||
debugged. */
|
||||
|
||||
static void
|
||||
gdbsim_prepare_to_store ()
|
||||
{
|
||||
/* Do nothing, since we can store individual regs */
|
||||
}
|
||||
|
||||
static int
|
||||
gdbsim_xfer_inferior_memory (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target; /* ignored */
|
||||
{
|
||||
if (! program_loaded)
|
||||
error ("No program loaded.");
|
||||
|
||||
if (sr_get_debug ())
|
||||
{
|
||||
printf_filtered ("gdbsim_xfer_inferior_memory: myaddr 0x%x, memaddr 0x%x, len %d, write %d\n",
|
||||
myaddr, memaddr, len, write);
|
||||
if (sr_get_debug () && write)
|
||||
dump_mem(myaddr, len);
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
len = sim_write (memaddr, myaddr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sim_read (memaddr, myaddr, len);
|
||||
if (sr_get_debug () && len > 0)
|
||||
dump_mem(myaddr, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
gdbsim_files_info (target)
|
||||
struct target_ops *target;
|
||||
{
|
||||
char *file = "nothing";
|
||||
|
||||
if (exec_bfd)
|
||||
file = bfd_get_filename (exec_bfd);
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_files_info: file \"%s\"\n", file);
|
||||
|
||||
if (exec_bfd)
|
||||
{
|
||||
printf_filtered ("\tAttached to %s running program %s\n",
|
||||
target_shortname, file);
|
||||
sim_info (0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the simulator's notion of what the break points are. */
|
||||
|
||||
static void
|
||||
gdbsim_mourn_inferior ()
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_mourn_inferior:\n");
|
||||
|
||||
remove_breakpoints ();
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
||||
/* Put a command string, in args, out to MONITOR. Output from MONITOR
|
||||
is placed on the users terminal until the prompt is seen. FIXME: We
|
||||
read the characters ourseleves here cause of a nasty echo. */
|
||||
|
||||
static void
|
||||
simulator_command (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
sim_do_command (args);
|
||||
}
|
||||
|
||||
/* Define the target subroutine names */
|
||||
|
||||
struct target_ops gdbsim_ops = {
|
||||
"sim", /* to_shortname */
|
||||
"simulator", /* to_longname */
|
||||
"Use the compiled-in simulator.", /* to_doc */
|
||||
gdbsim_open, /* to_open */
|
||||
gdbsim_close, /* to_close */
|
||||
NULL, /* to_attach */
|
||||
gdbsim_detach, /* to_detach */
|
||||
gdbsim_resume, /* to_resume */
|
||||
gdbsim_wait, /* to_wait */
|
||||
gdbsim_fetch_register, /* to_fetch_registers */
|
||||
gdbsim_store_register, /* to_store_registers */
|
||||
gdbsim_prepare_to_store, /* to_prepare_to_store */
|
||||
gdbsim_xfer_inferior_memory, /* to_xfer_memory */
|
||||
gdbsim_files_info, /* to_files_info */
|
||||
memory_insert_breakpoint, /* to_insert_breakpoint */
|
||||
memory_remove_breakpoint, /* to_remove_breakpoint */
|
||||
NULL, /* to_terminal_init */
|
||||
NULL, /* to_terminal_inferior */
|
||||
NULL, /* to_terminal_ours_for_output */
|
||||
NULL, /* to_terminal_ours */
|
||||
NULL, /* to_terminal_info */
|
||||
gdbsim_kill, /* to_kill */
|
||||
gdbsim_load, /* to_load */
|
||||
NULL, /* to_lookup_symbol */
|
||||
gdbsim_create_inferior, /* to_create_inferior */
|
||||
gdbsim_mourn_inferior, /* to_mourn_inferior */
|
||||
0, /* to_can_run */
|
||||
0, /* to_notice_signals */
|
||||
0, /* to_thread_alive */
|
||||
0, /* to_stop */
|
||||
process_stratum, /* to_stratum */
|
||||
NULL, /* to_next */
|
||||
1, /* to_has_all_memory */
|
||||
1, /* to_has_memory */
|
||||
1, /* to_has_stack */
|
||||
1, /* to_has_registers */
|
||||
1, /* to_has_execution */
|
||||
NULL, /* sections */
|
||||
NULL, /* sections_end */
|
||||
OPS_MAGIC, /* to_magic */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_remote_sim ()
|
||||
{
|
||||
add_target (&gdbsim_ops);
|
||||
|
||||
add_com ("sim <command>", class_obscure, simulator_command,
|
||||
"Send a command to the simulator.");
|
||||
}
|
|
@ -1,847 +0,0 @@
|
|||
/* Remote debugging interface for Tandem ST2000 phone switch, for GDB.
|
||||
Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This file was derived from remote-eb.c, which did a similar job, but for
|
||||
an AMD-29K running EBMON. That file was in turn derived from remote.c
|
||||
as mentioned in the following comment (left in for comic relief):
|
||||
|
||||
"This is like remote.c but is for an esoteric situation--
|
||||
having an a29k board in a PC hooked up to a unix machine with
|
||||
a serial line, and running ctty com1 on the PC, through which
|
||||
the unix machine can run ebmon. Not to mention that the PC
|
||||
has PC/NFS, so it can access the same executables that gdb can,
|
||||
over the net in real time."
|
||||
|
||||
In reality, this module talks to a debug monitor called 'STDEBUG', which
|
||||
runs in a phone switch. We communicate with STDEBUG via either a direct
|
||||
serial line, or a TCP (or possibly TELNET) stream to a terminal multiplexor,
|
||||
which in turn talks to the phone switch. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "wait.h"
|
||||
#ifdef ANSI_PROTOTYPES
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include "gdb_string.h"
|
||||
#include <sys/types.h>
|
||||
#include "serial.h"
|
||||
|
||||
extern struct target_ops st2000_ops; /* Forward declaration */
|
||||
|
||||
static void st2000_close();
|
||||
static void st2000_fetch_register();
|
||||
static void st2000_store_register();
|
||||
|
||||
#define LOG_FILE "st2000.log"
|
||||
#if defined (LOG_FILE)
|
||||
FILE *log_file;
|
||||
#endif
|
||||
|
||||
static int timeout = 24;
|
||||
|
||||
/* Descriptor for I/O to remote machine. Initialize it to -1 so that
|
||||
st2000_open knows that we don't have a file open when the program
|
||||
starts. */
|
||||
|
||||
static serial_t st2000_desc;
|
||||
|
||||
/* Send data to stdebug. Works just like printf. */
|
||||
|
||||
static void
|
||||
#ifdef ANSI_PROTOTYPES
|
||||
printf_stdebug(char *pattern, ...)
|
||||
#else
|
||||
printf_stdebug(va_alist)
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char buf[200];
|
||||
|
||||
#ifdef ANSI_PROTOTYPES
|
||||
va_start(args, pattern);
|
||||
#else
|
||||
char *pattern;
|
||||
va_start(args);
|
||||
pattern = va_arg(args, char *);
|
||||
#endif
|
||||
|
||||
vsprintf(buf, pattern, args);
|
||||
va_end(args);
|
||||
|
||||
if (SERIAL_WRITE(st2000_desc, buf, strlen(buf)))
|
||||
fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno));
|
||||
}
|
||||
|
||||
/* Read a character from the remote system, doing all the fancy timeout
|
||||
stuff. */
|
||||
|
||||
static int
|
||||
readchar(timeout)
|
||||
int timeout;
|
||||
{
|
||||
int c;
|
||||
|
||||
c = SERIAL_READCHAR(st2000_desc, timeout);
|
||||
|
||||
#ifdef LOG_FILE
|
||||
putc(c & 0x7f, log_file);
|
||||
#endif
|
||||
|
||||
if (c >= 0)
|
||||
return c & 0x7f;
|
||||
|
||||
if (c == SERIAL_TIMEOUT)
|
||||
{
|
||||
if (timeout == 0)
|
||||
return c; /* Polls shouldn't generate timeout errors */
|
||||
|
||||
error("Timeout reading from remote system.");
|
||||
}
|
||||
|
||||
perror_with_name("remote-st2000");
|
||||
}
|
||||
|
||||
/* Scan input from the remote system, until STRING is found. If DISCARD is
|
||||
non-zero, then discard non-matching input, else print it out.
|
||||
Let the user break out immediately. */
|
||||
static void
|
||||
expect(string, discard)
|
||||
char *string;
|
||||
int discard;
|
||||
{
|
||||
char *p = string;
|
||||
int c;
|
||||
|
||||
immediate_quit = 1;
|
||||
while (1)
|
||||
{
|
||||
c = readchar(timeout);
|
||||
if (c == *p++)
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
immediate_quit = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!discard)
|
||||
{
|
||||
fwrite(string, 1, (p - 1) - string, stdout);
|
||||
putchar((char)c);
|
||||
fflush(stdout);
|
||||
}
|
||||
p = string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep discarding input until we see the STDEBUG prompt.
|
||||
|
||||
The convention for dealing with the prompt is that you
|
||||
o give your command
|
||||
o *then* wait for the prompt.
|
||||
|
||||
Thus the last thing that a procedure does with the serial line
|
||||
will be an expect_prompt(). Exception: st2000_resume does not
|
||||
wait for the prompt, because the terminal is being handed over
|
||||
to the inferior. However, the next thing which happens after that
|
||||
is a st2000_wait which does wait for the prompt.
|
||||
Note that this includes abnormal exit, e.g. error(). This is
|
||||
necessary to prevent getting into states from which we can't
|
||||
recover. */
|
||||
static void
|
||||
expect_prompt(discard)
|
||||
int discard;
|
||||
{
|
||||
#if defined (LOG_FILE)
|
||||
/* This is a convenient place to do this. The idea is to do it often
|
||||
enough that we never lose much data if we terminate abnormally. */
|
||||
fflush(log_file);
|
||||
#endif
|
||||
expect ("dbug> ", discard);
|
||||
}
|
||||
|
||||
/* Get a hex digit from the remote system & return its value.
|
||||
If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
|
||||
static int
|
||||
get_hex_digit(ignore_space)
|
||||
int ignore_space;
|
||||
{
|
||||
int ch;
|
||||
while (1)
|
||||
{
|
||||
ch = readchar(timeout);
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch == ' ' && ignore_space)
|
||||
;
|
||||
else
|
||||
{
|
||||
expect_prompt(1);
|
||||
error("Invalid hex digit from remote system.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a byte from stdebug and put it in *BYT. Accept any number
|
||||
leading spaces. */
|
||||
static void
|
||||
get_hex_byte (byt)
|
||||
char *byt;
|
||||
{
|
||||
int val;
|
||||
|
||||
val = get_hex_digit (1) << 4;
|
||||
val |= get_hex_digit (0);
|
||||
*byt = val;
|
||||
}
|
||||
|
||||
/* Get N 32-bit words from remote, each preceded by a space,
|
||||
and put them in registers starting at REGNO. */
|
||||
static void
|
||||
get_hex_regs (n, regno)
|
||||
int n;
|
||||
int regno;
|
||||
{
|
||||
long val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
val = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
val = (val << 4) + get_hex_digit (j == 0);
|
||||
supply_register (regno++, (char *) &val);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called not only when we first attach, but also when the
|
||||
user types "run" after having attached. */
|
||||
static void
|
||||
st2000_create_inferior (execfile, args, env)
|
||||
char *execfile;
|
||||
char *args;
|
||||
char **env;
|
||||
{
|
||||
int entry_pt;
|
||||
|
||||
if (args && *args)
|
||||
error("Can't pass arguments to remote STDEBUG process");
|
||||
|
||||
if (execfile == 0 || exec_bfd == 0)
|
||||
error("No exec file specified");
|
||||
|
||||
entry_pt = (int) bfd_get_start_address (exec_bfd);
|
||||
|
||||
/* The "process" (board) is already stopped awaiting our commands, and
|
||||
the program is already downloaded. We just set its PC and go. */
|
||||
|
||||
clear_proceed_status ();
|
||||
|
||||
/* Tell wait_for_inferior that we've started a new process. */
|
||||
init_wait_for_inferior ();
|
||||
|
||||
/* Set up the "saved terminal modes" of the inferior
|
||||
based on what modes we are starting it with. */
|
||||
target_terminal_init ();
|
||||
|
||||
/* Install inferior's terminal modes. */
|
||||
target_terminal_inferior ();
|
||||
|
||||
/* insert_step_breakpoint (); FIXME, do we need this? */
|
||||
/* Let 'er rip... */
|
||||
proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
|
||||
}
|
||||
|
||||
/* Open a connection to a remote debugger.
|
||||
NAME is the filename used for communication. */
|
||||
|
||||
static int baudrate = 9600;
|
||||
static char dev_name[100];
|
||||
|
||||
static void
|
||||
st2000_open(args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
int n;
|
||||
char junk[100];
|
||||
|
||||
target_preopen(from_tty);
|
||||
|
||||
n = sscanf(args, " %s %d %s", dev_name, &baudrate, junk);
|
||||
|
||||
if (n != 2)
|
||||
error("Bad arguments. Usage: target st2000 <device> <speed>\n\
|
||||
or target st2000 <host> <port>\n");
|
||||
|
||||
st2000_close(0);
|
||||
|
||||
st2000_desc = SERIAL_OPEN(dev_name);
|
||||
|
||||
if (!st2000_desc)
|
||||
perror_with_name(dev_name);
|
||||
|
||||
SERIAL_SETBAUDRATE(st2000_desc, baudrate);
|
||||
|
||||
SERIAL_RAW(st2000_desc);
|
||||
|
||||
push_target(&st2000_ops);
|
||||
|
||||
#if defined (LOG_FILE)
|
||||
log_file = fopen (LOG_FILE, "w");
|
||||
if (log_file == NULL)
|
||||
perror_with_name (LOG_FILE);
|
||||
#endif
|
||||
|
||||
/* Hello? Are you there? */
|
||||
printf_stdebug("\003"); /* ^C wakes up dbug */
|
||||
|
||||
expect_prompt(1);
|
||||
|
||||
if (from_tty)
|
||||
printf("Remote %s connected to %s\n", target_shortname,
|
||||
dev_name);
|
||||
}
|
||||
|
||||
/* Close out all files and local state before this target loses control. */
|
||||
|
||||
static void
|
||||
st2000_close (quitting)
|
||||
int quitting;
|
||||
{
|
||||
SERIAL_CLOSE(st2000_desc);
|
||||
|
||||
#if defined (LOG_FILE)
|
||||
if (log_file) {
|
||||
if (ferror(log_file))
|
||||
fprintf(stderr, "Error writing log file.\n");
|
||||
if (fclose(log_file) != 0)
|
||||
fprintf(stderr, "Error closing log file.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Terminate the open connection to the remote debugger.
|
||||
Use this when you want to detach and do something else
|
||||
with your gdb. */
|
||||
static void
|
||||
st2000_detach (from_tty)
|
||||
int from_tty;
|
||||
{
|
||||
pop_target(); /* calls st2000_close to do the real work */
|
||||
if (from_tty)
|
||||
printf ("Ending remote %s debugging\n", target_shortname);
|
||||
}
|
||||
|
||||
/* Tell the remote machine to resume. */
|
||||
|
||||
static void
|
||||
st2000_resume (pid, step, sig)
|
||||
int pid, step;
|
||||
enum target_signal sig;
|
||||
{
|
||||
if (step)
|
||||
{
|
||||
printf_stdebug ("ST\r");
|
||||
/* Wait for the echo. */
|
||||
expect ("ST\r", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_stdebug ("GO\r");
|
||||
/* Swallow the echo. */
|
||||
expect ("GO\r", 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait until the remote machine stops, then return,
|
||||
storing status in STATUS just as `wait' would. */
|
||||
|
||||
static int
|
||||
st2000_wait (status)
|
||||
struct target_waitstatus *status;
|
||||
{
|
||||
int old_timeout = timeout;
|
||||
|
||||
status->kind = TARGET_WAITKIND_EXITED;
|
||||
status->value.integer = 0;
|
||||
|
||||
timeout = 0; /* Don't time out -- user program is running. */
|
||||
|
||||
expect_prompt(0); /* Wait for prompt, outputting extraneous text */
|
||||
|
||||
status->kind = TARGET_WAITKIND_STOPPED;
|
||||
status->value.sig = TARGET_SIGNAL_TRAP;
|
||||
|
||||
timeout = old_timeout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the name of register number REGNO in the form input and output by
|
||||
STDEBUG. Currently, REGISTER_NAMES just happens to contain exactly what
|
||||
STDEBUG wants. Lets take advantage of that just as long as possible! */
|
||||
|
||||
static char *
|
||||
get_reg_name (regno)
|
||||
int regno;
|
||||
{
|
||||
static char buf[50];
|
||||
const char *p;
|
||||
char *b;
|
||||
|
||||
b = buf;
|
||||
|
||||
for (p = reg_names[regno]; *p; p++)
|
||||
*b++ = toupper(*p);
|
||||
*b = '\000';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read the remote registers into the block REGS. */
|
||||
|
||||
static void
|
||||
st2000_fetch_registers ()
|
||||
{
|
||||
int regno;
|
||||
|
||||
/* Yeah yeah, I know this is horribly inefficient. But it isn't done
|
||||
very often... I'll clean it up later. */
|
||||
|
||||
for (regno = 0; regno <= PC_REGNUM; regno++)
|
||||
st2000_fetch_register(regno);
|
||||
}
|
||||
|
||||
/* Fetch register REGNO, or all registers if REGNO is -1.
|
||||
Returns errno value. */
|
||||
static void
|
||||
st2000_fetch_register (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno == -1)
|
||||
st2000_fetch_registers ();
|
||||
else
|
||||
{
|
||||
char *name = get_reg_name (regno);
|
||||
printf_stdebug ("DR %s\r", name);
|
||||
expect (name, 1);
|
||||
expect (" : ", 1);
|
||||
get_hex_regs (1, regno);
|
||||
expect_prompt (1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the remote registers from the contents of the block REGS. */
|
||||
|
||||
static void
|
||||
st2000_store_registers ()
|
||||
{
|
||||
int regno;
|
||||
|
||||
for (regno = 0; regno <= PC_REGNUM; regno++)
|
||||
st2000_store_register(regno);
|
||||
|
||||
registers_changed ();
|
||||
}
|
||||
|
||||
/* Store register REGNO, or all if REGNO == 0.
|
||||
Return errno value. */
|
||||
static void
|
||||
st2000_store_register (regno)
|
||||
int regno;
|
||||
{
|
||||
if (regno == -1)
|
||||
st2000_store_registers ();
|
||||
else
|
||||
{
|
||||
printf_stdebug ("PR %s %x\r", get_reg_name (regno),
|
||||
read_register (regno));
|
||||
|
||||
expect_prompt (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get ready to modify the registers array. On machines which store
|
||||
individual registers, this doesn't need to do anything. On machines
|
||||
which store all the registers in one fell swoop, this makes sure
|
||||
that registers contains all the registers from the program being
|
||||
debugged. */
|
||||
|
||||
static void
|
||||
st2000_prepare_to_store ()
|
||||
{
|
||||
/* Do nothing, since we can store individual regs */
|
||||
}
|
||||
|
||||
static void
|
||||
st2000_files_info ()
|
||||
{
|
||||
printf ("\tAttached to %s at %d baud.\n",
|
||||
dev_name, baudrate);
|
||||
}
|
||||
|
||||
/* Copy LEN bytes of data from debugger memory at MYADDR
|
||||
to inferior's memory at MEMADDR. Returns length moved. */
|
||||
static int
|
||||
st2000_write_inferior_memory (memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
unsigned char *myaddr;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
printf_stdebug ("PM.B %x %x\r", memaddr + i, myaddr[i]);
|
||||
expect_prompt (1);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Read LEN bytes from inferior memory at MEMADDR. Put the result
|
||||
at debugger address MYADDR. Returns length moved. */
|
||||
static int
|
||||
st2000_read_inferior_memory(memaddr, myaddr, len)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Number of bytes read so far. */
|
||||
int count;
|
||||
|
||||
/* Starting address of this pass. */
|
||||
unsigned long startaddr;
|
||||
|
||||
/* Number of bytes to read in this pass. */
|
||||
int len_this_pass;
|
||||
|
||||
/* Note that this code works correctly if startaddr is just less
|
||||
than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
|
||||
thing). That is, something like
|
||||
st2000_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
|
||||
works--it never adds len to memaddr and gets 0. */
|
||||
/* However, something like
|
||||
st2000_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
|
||||
doesn't need to work. Detect it and give up if there's an attempt
|
||||
to do that. */
|
||||
if (((memaddr - 1) + len) < memaddr) {
|
||||
errno = EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
startaddr = memaddr;
|
||||
count = 0;
|
||||
while (count < len)
|
||||
{
|
||||
len_this_pass = 16;
|
||||
if ((startaddr % 16) != 0)
|
||||
len_this_pass -= startaddr % 16;
|
||||
if (len_this_pass > (len - count))
|
||||
len_this_pass = (len - count);
|
||||
|
||||
printf_stdebug ("DI.L %x %x\r", startaddr, len_this_pass);
|
||||
expect (": ", 1);
|
||||
|
||||
for (i = 0; i < len_this_pass; i++)
|
||||
get_hex_byte (&myaddr[count++]);
|
||||
|
||||
expect_prompt (1);
|
||||
|
||||
startaddr += len_this_pass;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* FIXME-someday! Merge these two. */
|
||||
static int
|
||||
st2000_xfer_inferior_memory (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target; /* ignored */
|
||||
{
|
||||
if (write)
|
||||
return st2000_write_inferior_memory (memaddr, myaddr, len);
|
||||
else
|
||||
return st2000_read_inferior_memory (memaddr, myaddr, len);
|
||||
}
|
||||
|
||||
static void
|
||||
st2000_kill (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
return; /* Ignore attempts to kill target system */
|
||||
}
|
||||
|
||||
/* Clean up when a program exits.
|
||||
|
||||
The program actually lives on in the remote processor's RAM, and may be
|
||||
run again without a download. Don't leave it full of breakpoint
|
||||
instructions. */
|
||||
|
||||
static void
|
||||
st2000_mourn_inferior ()
|
||||
{
|
||||
remove_breakpoints ();
|
||||
unpush_target (&st2000_ops);
|
||||
generic_mourn_inferior (); /* Do all the proper things now */
|
||||
}
|
||||
|
||||
#define MAX_STDEBUG_BREAKPOINTS 16
|
||||
|
||||
extern int memory_breakpoint_size;
|
||||
static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] = {0};
|
||||
|
||||
static int
|
||||
st2000_insert_breakpoint (addr, shadow)
|
||||
CORE_ADDR addr;
|
||||
char *shadow;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++)
|
||||
if (breakaddr[i] == 0)
|
||||
{
|
||||
breakaddr[i] = addr;
|
||||
|
||||
st2000_read_inferior_memory(addr, shadow, memory_breakpoint_size);
|
||||
printf_stdebug("BR %x H\r", addr);
|
||||
expect_prompt(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Too many breakpoints (> 16) for STDBUG\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
st2000_remove_breakpoint (addr, shadow)
|
||||
CORE_ADDR addr;
|
||||
char *shadow;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_STDEBUG_BREAKPOINTS; i++)
|
||||
if (breakaddr[i] == addr)
|
||||
{
|
||||
breakaddr[i] = 0;
|
||||
|
||||
printf_stdebug("CB %d\r", i);
|
||||
expect_prompt(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Put a command string, in args, out to STDBUG. Output from STDBUG is placed
|
||||
on the users terminal until the prompt is seen. */
|
||||
|
||||
static void
|
||||
st2000_command (args, fromtty)
|
||||
char *args;
|
||||
int fromtty;
|
||||
{
|
||||
if (!st2000_desc)
|
||||
error("st2000 target not open.");
|
||||
|
||||
if (!args)
|
||||
error("Missing command.");
|
||||
|
||||
printf_stdebug("%s\r", args);
|
||||
expect_prompt(0);
|
||||
}
|
||||
|
||||
/* Connect the user directly to STDBUG. This command acts just like the
|
||||
'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
|
||||
|
||||
/*static struct ttystate ttystate;*/
|
||||
|
||||
static void
|
||||
cleanup_tty()
|
||||
{
|
||||
printf("\r\n[Exiting connect mode]\r\n");
|
||||
/* SERIAL_RESTORE(0, &ttystate);*/
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This all should now be in serial.c */
|
||||
|
||||
static void
|
||||
connect_command (args, fromtty)
|
||||
char *args;
|
||||
int fromtty;
|
||||
{
|
||||
fd_set readfds;
|
||||
int numfds;
|
||||
int c;
|
||||
char cur_esc = 0;
|
||||
|
||||
dont_repeat();
|
||||
|
||||
if (st2000_desc < 0)
|
||||
error("st2000 target not open.");
|
||||
|
||||
if (args)
|
||||
fprintf("This command takes no args. They have been ignored.\n");
|
||||
|
||||
printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
|
||||
|
||||
serial_raw(0, &ttystate);
|
||||
|
||||
make_cleanup(cleanup_tty, 0);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
|
||||
while (1)
|
||||
{
|
||||
do
|
||||
{
|
||||
FD_SET(0, &readfds);
|
||||
FD_SET(st2000_desc, &readfds);
|
||||
numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
|
||||
}
|
||||
while (numfds == 0);
|
||||
|
||||
if (numfds < 0)
|
||||
perror_with_name("select");
|
||||
|
||||
if (FD_ISSET(0, &readfds))
|
||||
{ /* tty input, send to stdebug */
|
||||
c = getchar();
|
||||
if (c < 0)
|
||||
perror_with_name("connect");
|
||||
|
||||
printf_stdebug("%c", c);
|
||||
switch (cur_esc)
|
||||
{
|
||||
case 0:
|
||||
if (c == '\r')
|
||||
cur_esc = c;
|
||||
break;
|
||||
case '\r':
|
||||
if (c == '~')
|
||||
cur_esc = c;
|
||||
else
|
||||
cur_esc = 0;
|
||||
break;
|
||||
case '~':
|
||||
if (c == '.' || c == '\004')
|
||||
return;
|
||||
else
|
||||
cur_esc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(st2000_desc, &readfds))
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
c = readchar(0);
|
||||
if (c < 0)
|
||||
break;
|
||||
putchar(c);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
/* Define the target subroutine names */
|
||||
|
||||
struct target_ops st2000_ops = {
|
||||
"st2000",
|
||||
"Remote serial Tandem ST2000 target",
|
||||
"Use a remote computer running STDEBUG connected by a serial line,\n\
|
||||
or a network connection.\n\
|
||||
Arguments are the name of the device for the serial line,\n\
|
||||
the speed to connect at in bits per second.",
|
||||
st2000_open,
|
||||
st2000_close,
|
||||
0,
|
||||
st2000_detach,
|
||||
st2000_resume,
|
||||
st2000_wait,
|
||||
st2000_fetch_register,
|
||||
st2000_store_register,
|
||||
st2000_prepare_to_store,
|
||||
st2000_xfer_inferior_memory,
|
||||
st2000_files_info,
|
||||
st2000_insert_breakpoint,
|
||||
st2000_remove_breakpoint, /* Breakpoints */
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, /* Terminal handling */
|
||||
st2000_kill,
|
||||
0, /* load */
|
||||
0, /* lookup_symbol */
|
||||
st2000_create_inferior,
|
||||
st2000_mourn_inferior,
|
||||
0, /* can_run */
|
||||
0, /* notice_signals */
|
||||
0, /* to_stop */
|
||||
process_stratum,
|
||||
0, /* next */
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, /* all mem, mem, stack, regs, exec */
|
||||
0,
|
||||
0, /* Section pointers */
|
||||
OPS_MAGIC, /* Always the last thing */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_remote_st2000 ()
|
||||
{
|
||||
add_target (&st2000_ops);
|
||||
add_com ("st2000 <command>", class_obscure, st2000_command,
|
||||
"Send a command to the STDBUG monitor.");
|
||||
add_com ("connect", class_obscure, connect_command,
|
||||
"Connect the terminal directly up to the STDBUG command monitor.\n\
|
||||
Use <CR>~. or <CR>~^D to break out.");
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,188 +0,0 @@
|
|||
/* Am29k-dependent portions of the RPC protocol
|
||||
used with a VxWorks target
|
||||
|
||||
Contributed by Wind River Systems.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#include "vx-share/regPacket.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h" /* for struct complaint */
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef _AIX /* IBM claims "void *malloc()" not char * */
|
||||
#define malloc bogon_malloc
|
||||
#endif
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
|
||||
#include <netdb.h>
|
||||
#include "vx-share/ptrace.h"
|
||||
#include "vx-share/xdr_ptrace.h"
|
||||
#include "vx-share/xdr_ld.h"
|
||||
#include "vx-share/xdr_rdb.h"
|
||||
#include "vx-share/dbgRpcLib.h"
|
||||
|
||||
/* get rid of value.h if possible */
|
||||
#include <value.h>
|
||||
#include <symtab.h>
|
||||
|
||||
/* Flag set if target has fpu */
|
||||
|
||||
extern int target_has_fp;
|
||||
|
||||
/* Generic register read/write routines in remote-vx.c. */
|
||||
|
||||
extern void net_read_registers ();
|
||||
extern void net_write_registers ();
|
||||
|
||||
/* Read a register or registers from the VxWorks target.
|
||||
REGNO is the register to read, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char am29k_greg_packet[AM29K_GREG_PLEN];
|
||||
char am29k_fpreg_packet[AM29K_FPREG_PLEN];
|
||||
|
||||
/* Get general-purpose registers. When copying values into
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
net_read_registers (am29k_greg_packet, AM29K_GREG_PLEN, PTRACE_GETREGS);
|
||||
|
||||
/* Now copy the register values into registers[].
|
||||
Note that this code depends on the ordering of the REGNUMs
|
||||
as defined in "tm-29k.h". */
|
||||
|
||||
bcopy (&am29k_greg_packet[AM29K_R_GR96],
|
||||
®isters[REGISTER_BYTE (GR96_REGNUM)], 160 * AM29K_GREG_SIZE);
|
||||
bcopy (&am29k_greg_packet[AM29K_R_VAB],
|
||||
®isters[REGISTER_BYTE (VAB_REGNUM)], 15 * AM29K_GREG_SIZE);
|
||||
registers[REGISTER_BYTE (INTE_REGNUM)] = am29k_greg_packet[AM29K_R_INTE];
|
||||
bcopy (&am29k_greg_packet[AM29K_R_RSP],
|
||||
®isters[REGISTER_BYTE (GR1_REGNUM)], 5 * AM29K_GREG_SIZE);
|
||||
|
||||
/* PAD For now, don't care about exop register */
|
||||
|
||||
memset (®isters[REGISTER_BYTE (EXO_REGNUM)], '\0', AM29K_GREG_SIZE);
|
||||
|
||||
/* If the target has floating point registers, fetch them.
|
||||
Otherwise, zero the floating point register values in
|
||||
registers[] for good measure, even though we might not
|
||||
need to. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
net_read_registers (am29k_fpreg_packet, AM29K_FPREG_PLEN,
|
||||
PTRACE_GETFPREGS);
|
||||
registers[REGISTER_BYTE (FPE_REGNUM)] = am29k_fpreg_packet[AM29K_R_FPE];
|
||||
registers[REGISTER_BYTE (FPS_REGNUM)] = am29k_fpreg_packet[AM29K_R_FPS];
|
||||
|
||||
/* PAD For now, don't care about registers (?) AI0 to q */
|
||||
|
||||
memset (®isters[REGISTER_BYTE (161)], '\0', 21 * AM29K_FPREG_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (®isters[REGISTER_BYTE (FPE_REGNUM)], '\0', AM29K_FPREG_SIZE);
|
||||
memset (®isters[REGISTER_BYTE (FPS_REGNUM)], '\0', AM29K_FPREG_SIZE);
|
||||
|
||||
/* PAD For now, don't care about registers (?) AI0 to q */
|
||||
|
||||
memset (®isters[REGISTER_BYTE (161)], '\0', 21 * AM29K_FPREG_SIZE);
|
||||
}
|
||||
|
||||
/* Mark the register cache valid. */
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
/* Store a register or registers into the VxWorks target.
|
||||
REGNO is the register to store, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_write_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char am29k_greg_packet[AM29K_GREG_PLEN];
|
||||
char am29k_fpreg_packet[AM29K_FPREG_PLEN];
|
||||
|
||||
/* Store general purpose registers. When copying values from
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
bcopy (®isters[REGISTER_BYTE (GR96_REGNUM)],
|
||||
&am29k_greg_packet[AM29K_R_GR96], 160 * AM29K_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (VAB_REGNUM)],
|
||||
&am29k_greg_packet[AM29K_R_VAB], 15 * AM29K_GREG_SIZE);
|
||||
am29k_greg_packet[AM29K_R_INTE] = registers[REGISTER_BYTE (INTE_REGNUM)];
|
||||
bcopy (®isters[REGISTER_BYTE (GR1_REGNUM)],
|
||||
&am29k_greg_packet[AM29K_R_RSP], 5 * AM29K_GREG_SIZE);
|
||||
|
||||
net_write_registers (am29k_greg_packet, AM29K_GREG_PLEN, PTRACE_SETREGS);
|
||||
|
||||
/* Store floating point registers if the target has them. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
am29k_fpreg_packet[AM29K_R_FPE] = registers[REGISTER_BYTE (FPE_REGNUM)];
|
||||
am29k_fpreg_packet[AM29K_R_FPS] = registers[REGISTER_BYTE (FPS_REGNUM)];
|
||||
|
||||
net_write_registers (am29k_fpreg_packet, AM29K_FPREG_PLEN,
|
||||
PTRACE_SETFPREGS);
|
||||
}
|
||||
}
|
||||
|
||||
/* VxWorks zeroes fp when the task is initialized; we use this
|
||||
to terminate the frame chain. Chain means here the nominal address of
|
||||
a frame, that is, the return address (lr0) address in the stack. To
|
||||
obtain the frame pointer (lr1) contents, we must add 4 bytes.
|
||||
Note : may be we should modify init_frame_info() to get the frame pointer
|
||||
and store it into the frame_info struct rather than reading its
|
||||
contents when FRAME_CHAIN_VALID is invoked. */
|
||||
|
||||
int
|
||||
get_fp_contents (chain, thisframe)
|
||||
CORE_ADDR chain;
|
||||
struct frame_info *thisframe; /* not used here */
|
||||
{
|
||||
int fp_contents;
|
||||
|
||||
read_memory ((CORE_ADDR)(chain + 4), (char *) &fp_contents, 4);
|
||||
return (fp_contents != 0);
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/* 68k-dependent portions of the RPC protocol
|
||||
used with a VxWorks target
|
||||
|
||||
Contributed by Wind River Systems.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#include "vx-share/regPacket.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h" /* for struct complaint */
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef _AIX /* IBM claims "void *malloc()" not char * */
|
||||
#define malloc bogon_malloc
|
||||
#endif
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
#ifdef _AIX
|
||||
#undef malloc
|
||||
#endif
|
||||
|
||||
#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
|
||||
#include <netdb.h>
|
||||
#include "vx-share/ptrace.h"
|
||||
#include "vx-share/xdr_ptrace.h"
|
||||
#include "vx-share/xdr_ld.h"
|
||||
#include "vx-share/xdr_rdb.h"
|
||||
#include "vx-share/dbgRpcLib.h"
|
||||
|
||||
/* get rid of value.h if possible */
|
||||
#include <value.h>
|
||||
#include <symtab.h>
|
||||
|
||||
/* Flag set if target has fpu */
|
||||
|
||||
extern int target_has_fp;
|
||||
|
||||
/* Generic register read/write routines in remote-vx.c. */
|
||||
|
||||
extern void net_read_registers ();
|
||||
extern void net_write_registers ();
|
||||
|
||||
/* Read a register or registers from the VxWorks target.
|
||||
REGNO is the register to read, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char mc68k_greg_packet[MC68K_GREG_PLEN];
|
||||
char mc68k_fpreg_packet[MC68K_FPREG_PLEN];
|
||||
|
||||
/* Get general-purpose registers. */
|
||||
|
||||
net_read_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_GETREGS);
|
||||
|
||||
bcopy (&mc68k_greg_packet[MC68K_R_D0], registers, 16 * MC68K_GREG_SIZE);
|
||||
bcopy (&mc68k_greg_packet[MC68K_R_SR], ®isters[REGISTER_BYTE (PS_REGNUM)],
|
||||
MC68K_GREG_SIZE);
|
||||
bcopy (&mc68k_greg_packet[MC68K_R_PC], ®isters[REGISTER_BYTE (PC_REGNUM)],
|
||||
MC68K_GREG_SIZE);
|
||||
|
||||
/* Get floating-point registers, if the target system has them.
|
||||
Otherwise, zero them. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
net_read_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN,
|
||||
PTRACE_GETFPREGS);
|
||||
|
||||
bcopy (&mc68k_fpreg_packet[MC68K_R_FP0],
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
MC68K_FPREG_SIZE * 8);
|
||||
bcopy (&mc68k_fpreg_packet[MC68K_R_FPCR],
|
||||
®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
bzero (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
MC68K_FPREG_SIZE * 8);
|
||||
bzero (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
|
||||
}
|
||||
|
||||
/* Mark the register cache valid. */
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
/* Store a register or registers into the VxWorks target.
|
||||
REGNO is the register to store, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_write_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char mc68k_greg_packet[MC68K_GREG_PLEN];
|
||||
char mc68k_fpreg_packet[MC68K_FPREG_PLEN];
|
||||
|
||||
/* Store general-purpose registers. */
|
||||
|
||||
bcopy (registers, &mc68k_greg_packet[MC68K_R_D0], 16 * MC68K_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (PS_REGNUM)],
|
||||
&mc68k_greg_packet[MC68K_R_SR], MC68K_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (PC_REGNUM)],
|
||||
&mc68k_greg_packet[MC68K_R_PC], MC68K_GREG_SIZE);
|
||||
|
||||
net_write_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_SETREGS);
|
||||
|
||||
/* Store floating point registers if the target has them. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
&mc68k_fpreg_packet[MC68K_R_FP0],
|
||||
MC68K_FPREG_SIZE * 8);
|
||||
bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||||
&mc68k_fpreg_packet[MC68K_R_FPCR],
|
||||
MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
|
||||
|
||||
net_write_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN,
|
||||
PTRACE_SETFPREGS);
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/* i80960-dependent portions of the RPC protocol
|
||||
used with a VxWorks target
|
||||
|
||||
Contributed by Wind River Systems.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#include "vx-share/regPacket.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h" /* for struct complaint */
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef _AIX /* IBM claims "void *malloc()" not char * */
|
||||
#define malloc bogon_malloc
|
||||
#endif
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
|
||||
#include <netdb.h>
|
||||
#include "vx-share/ptrace.h"
|
||||
#include "vx-share/xdr_ptrace.h"
|
||||
#include "vx-share/xdr_ld.h"
|
||||
#include "vx-share/xdr_rdb.h"
|
||||
#include "vx-share/dbgRpcLib.h"
|
||||
|
||||
/* get rid of value.h if possible */
|
||||
#include <value.h>
|
||||
#include <symtab.h>
|
||||
|
||||
/* Flag set if target has fpu */
|
||||
|
||||
extern int target_has_fp;
|
||||
|
||||
/* 960 floating point format descriptor, from "i960-tdep.c." */
|
||||
|
||||
extern struct ext_format ext_format_i960;
|
||||
|
||||
/* Generic register read/write routines in remote-vx.c. */
|
||||
|
||||
extern void net_read_registers ();
|
||||
extern void net_write_registers ();
|
||||
|
||||
/* Read a register or registers from the VxWorks target.
|
||||
REGNO is the register to read, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char i960_greg_packet[I960_GREG_PLEN];
|
||||
char i960_fpreg_packet[I960_FPREG_PLEN];
|
||||
|
||||
/* Get general-purpose registers. When copying values into
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
net_read_registers (i960_greg_packet, I960_GREG_PLEN, PTRACE_GETREGS);
|
||||
|
||||
bcopy (&i960_greg_packet[I960_R_R0],
|
||||
®isters[REGISTER_BYTE (R0_REGNUM)], 16 * I960_GREG_SIZE);
|
||||
bcopy (&i960_greg_packet[I960_R_G0],
|
||||
®isters[REGISTER_BYTE (G0_REGNUM)], 16 * I960_GREG_SIZE);
|
||||
bcopy (&i960_greg_packet[I960_R_PCW],
|
||||
®isters[REGISTER_BYTE (PCW_REGNUM)], sizeof (int));
|
||||
bcopy (&i960_greg_packet[I960_R_ACW],
|
||||
®isters[REGISTER_BYTE (ACW_REGNUM)], sizeof (int));
|
||||
bcopy (&i960_greg_packet[I960_R_TCW],
|
||||
®isters[REGISTER_BYTE (TCW_REGNUM)], sizeof (int));
|
||||
|
||||
/* If the target has floating point registers, fetch them.
|
||||
Otherwise, zero the floating point register values in
|
||||
registers[] for good measure, even though we might not
|
||||
need to. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
net_read_registers (i960_fpreg_packet, I960_FPREG_PLEN,
|
||||
PTRACE_GETFPREGS);
|
||||
bcopy (&i960_fpreg_packet[I960_R_FP0],
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
|
||||
}
|
||||
else
|
||||
bzero (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
|
||||
|
||||
/* Mark the register cache valid. */
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
/* Store a register or registers into the VxWorks target.
|
||||
REGNO is the register to store, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_write_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char i960_greg_packet[I960_GREG_PLEN];
|
||||
char i960_fpreg_packet[I960_FPREG_PLEN];
|
||||
|
||||
/* Store floating-point registers. When copying values from
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
bcopy (®isters[REGISTER_BYTE (R0_REGNUM)],
|
||||
&i960_greg_packet[I960_R_R0], 16 * I960_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (G0_REGNUM)],
|
||||
&i960_greg_packet[I960_R_G0], 16 * I960_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (PCW_REGNUM)],
|
||||
&i960_greg_packet[I960_R_PCW], sizeof (int));
|
||||
bcopy (®isters[REGISTER_BYTE (ACW_REGNUM)],
|
||||
&i960_greg_packet[I960_R_ACW], sizeof (int));
|
||||
bcopy (®isters[REGISTER_BYTE (TCW_REGNUM)],
|
||||
&i960_greg_packet[I960_R_TCW], sizeof (int));
|
||||
|
||||
net_write_registers (i960_greg_packet, I960_GREG_PLEN, PTRACE_SETREGS);
|
||||
|
||||
/* Store floating point registers if the target has them. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
&i960_fpreg_packet[I960_R_FP0],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 4);
|
||||
|
||||
net_write_registers (i960_fpreg_packet, I960_FPREG_PLEN,
|
||||
PTRACE_SETFPREGS);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
/* MIPS-dependent portions of the RPC protocol
|
||||
used with a VxWorks target
|
||||
|
||||
Contributed by Wind River Systems.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#include "vx-share/regPacket.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h" /* for struct complaint */
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
|
||||
#include <netdb.h>
|
||||
#include "vx-share/ptrace.h"
|
||||
#include "vx-share/xdr_ptrace.h"
|
||||
#include "vx-share/xdr_ld.h"
|
||||
#include "vx-share/xdr_rdb.h"
|
||||
#include "vx-share/dbgRpcLib.h"
|
||||
|
||||
/* get rid of value.h if possible */
|
||||
#include <value.h>
|
||||
#include <symtab.h>
|
||||
|
||||
/* Flag set if target has fpu */
|
||||
|
||||
extern int target_has_fp;
|
||||
|
||||
/* Generic register read/write routines in remote-vx.c. */
|
||||
|
||||
extern void net_read_registers ();
|
||||
extern void net_write_registers ();
|
||||
|
||||
/* Read a register or registers from the VxWorks target.
|
||||
REGNO is the register to read, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char mips_greg_packet[MIPS_GREG_PLEN];
|
||||
char mips_fpreg_packet[MIPS_FPREG_PLEN];
|
||||
|
||||
/* Get general-purpose registers. */
|
||||
|
||||
net_read_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_GETREGS);
|
||||
|
||||
/* this code copies the registers obtained by RPC
|
||||
stored in a structure(s) like this :
|
||||
|
||||
Register(s) Offset(s)
|
||||
gp 0-31 0x00
|
||||
hi 0x80
|
||||
lo 0x84
|
||||
sr 0x88
|
||||
pc 0x8c
|
||||
|
||||
into a stucture like this:
|
||||
|
||||
0x00 GP 0-31
|
||||
0x80 SR
|
||||
0x84 LO
|
||||
0x88 HI
|
||||
0x8C BAD --- Not available currently
|
||||
0x90 CAUSE --- Not available currently
|
||||
0x94 PC
|
||||
0x98 FP 0-31
|
||||
0x118 FCSR
|
||||
0x11C FIR --- Not available currently
|
||||
0x120 FP --- Not available currently
|
||||
|
||||
structure is 0x124 (292) bytes in length */
|
||||
|
||||
/* Copy the general registers. */
|
||||
|
||||
bcopy (&mips_greg_packet[MIPS_R_GP0], ®isters[0], 32 * MIPS_GREG_SIZE);
|
||||
|
||||
/* Copy SR, LO, HI, and PC. */
|
||||
|
||||
bcopy (&mips_greg_packet[MIPS_R_SR],
|
||||
®isters[REGISTER_BYTE (PS_REGNUM)], MIPS_GREG_SIZE);
|
||||
bcopy (&mips_greg_packet[MIPS_R_LO],
|
||||
®isters[REGISTER_BYTE (LO_REGNUM)], MIPS_GREG_SIZE);
|
||||
bcopy (&mips_greg_packet[MIPS_R_HI],
|
||||
®isters[REGISTER_BYTE (HI_REGNUM)], MIPS_GREG_SIZE);
|
||||
bcopy (&mips_greg_packet[MIPS_R_PC],
|
||||
®isters[REGISTER_BYTE (PC_REGNUM)], MIPS_GREG_SIZE);
|
||||
|
||||
/* If the target has floating point registers, fetch them.
|
||||
Otherwise, zero the floating point register values in
|
||||
registers[] for good measure, even though we might not
|
||||
need to. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
net_read_registers (mips_fpreg_packet, MIPS_FPREG_PLEN,
|
||||
PTRACE_GETFPREGS);
|
||||
|
||||
/* Copy the floating point registers. */
|
||||
|
||||
bcopy (&mips_fpreg_packet[MIPS_R_FP0],
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
|
||||
|
||||
/* Copy the floating point control/status register (fpcsr). */
|
||||
|
||||
bcopy (&mips_fpreg_packet[MIPS_R_FPCSR],
|
||||
®isters[REGISTER_BYTE (FCRCS_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FCRCS_REGNUM));
|
||||
}
|
||||
else
|
||||
{
|
||||
bzero ((char *) ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
|
||||
bzero ((char *) ®isters[REGISTER_BYTE (FCRCS_REGNUM)],
|
||||
REGISTER_RAW_SIZE (FCRCS_REGNUM));
|
||||
}
|
||||
|
||||
/* Mark the register cache valid. */
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
/* Store a register or registers into the VxWorks target.
|
||||
REGNO is the register to store, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
vx_write_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char mips_greg_packet[MIPS_GREG_PLEN];
|
||||
char mips_fpreg_packet[MIPS_FPREG_PLEN];
|
||||
|
||||
/* Store general registers. */
|
||||
|
||||
bcopy (®isters[0], &mips_greg_packet[MIPS_R_GP0], 32 * MIPS_GREG_SIZE);
|
||||
|
||||
/* Copy SR, LO, HI, and PC. */
|
||||
|
||||
bcopy (®isters[REGISTER_BYTE (PS_REGNUM)],
|
||||
&mips_greg_packet[MIPS_R_SR], MIPS_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (LO_REGNUM)],
|
||||
&mips_greg_packet[MIPS_R_LO], MIPS_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (HI_REGNUM)],
|
||||
&mips_greg_packet[MIPS_R_HI], MIPS_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (PC_REGNUM)],
|
||||
&mips_greg_packet[MIPS_R_PC], MIPS_GREG_SIZE);
|
||||
|
||||
net_write_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_SETREGS);
|
||||
|
||||
/* Store floating point registers if the target has them. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
/* Copy the floating point data registers. */
|
||||
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
&mips_fpreg_packet[MIPS_R_FP0],
|
||||
REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
|
||||
|
||||
/* Copy the floating point control/status register (fpcsr). */
|
||||
|
||||
bcopy (®isters[REGISTER_BYTE (FCRCS_REGNUM)],
|
||||
&mips_fpreg_packet[MIPS_R_FPCSR],
|
||||
REGISTER_RAW_SIZE (FCRCS_REGNUM));
|
||||
|
||||
net_write_registers (mips_fpreg_packet, MIPS_FPREG_PLEN,
|
||||
PTRACE_SETFPREGS);
|
||||
}
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
/* sparc-dependent portions of the RPC protocol
|
||||
used with a VxWorks target
|
||||
|
||||
Contributed by Wind River Systems.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#include "vx-share/regPacket.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "wait.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "command.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h" /* for struct complaint */
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef _AIX /* IBM claims "void *malloc()" not char * */
|
||||
#define malloc bogon_malloc
|
||||
#endif
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
|
||||
#include <netdb.h>
|
||||
#include "vx-share/ptrace.h"
|
||||
#include "vx-share/xdr_ptrace.h"
|
||||
#include "vx-share/xdr_ld.h"
|
||||
#include "vx-share/xdr_rdb.h"
|
||||
#include "vx-share/dbgRpcLib.h"
|
||||
|
||||
/* get rid of value.h if possible */
|
||||
#include <value.h>
|
||||
#include <symtab.h>
|
||||
|
||||
/* Flag set if target has fpu */
|
||||
|
||||
extern int target_has_fp;
|
||||
|
||||
/* sparc floating point format descriptor, from "sparc-tdep.c." */
|
||||
|
||||
extern struct ext_format ext_format_sparc;
|
||||
|
||||
/* Generic register read/write routines in remote-vx.c. */
|
||||
|
||||
extern void net_read_registers ();
|
||||
extern void net_write_registers ();
|
||||
|
||||
/* Read a register or registers from the VxWorks target.
|
||||
REGNO is the register to read, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_read_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char sparc_greg_packet[SPARC_GREG_PLEN];
|
||||
char sparc_fpreg_packet[SPARC_FPREG_PLEN];
|
||||
CORE_ADDR sp;
|
||||
|
||||
/* Get general-purpose registers. When copying values into
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
net_read_registers (sparc_greg_packet, SPARC_GREG_PLEN, PTRACE_GETREGS);
|
||||
|
||||
/* Now copy the register values into registers[].
|
||||
Note that this code depends on the ordering of the REGNUMs
|
||||
as defined in "tm-sparc.h". */
|
||||
|
||||
bcopy (&sparc_greg_packet[SPARC_R_G0],
|
||||
®isters[REGISTER_BYTE (G0_REGNUM)], 32 * SPARC_GREG_SIZE);
|
||||
bcopy (&sparc_greg_packet[SPARC_R_Y],
|
||||
®isters[REGISTER_BYTE (Y_REGNUM)], 6 * SPARC_GREG_SIZE);
|
||||
|
||||
/* Now write the local and in registers to the register window
|
||||
spill area in the frame. VxWorks does not do this for the
|
||||
active frame automatically; it greatly simplifies debugging
|
||||
(FRAME_FIND_SAVED_REGS, in particular, depends on this). */
|
||||
|
||||
sp = extract_address (®isters[REGISTER_BYTE (SP_REGNUM)],
|
||||
REGISTER_RAW_SIZE (CORE_ADDR));
|
||||
write_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)],
|
||||
16 * REGISTER_RAW_SIZE (L0_REGNUM));
|
||||
|
||||
/* If the target has floating point registers, fetch them.
|
||||
Otherwise, zero the floating point register values in
|
||||
registers[] for good measure, even though we might not
|
||||
need to. */
|
||||
|
||||
if (target_has_fp)
|
||||
{
|
||||
net_read_registers (sparc_fpreg_packet, SPARC_FPREG_PLEN,
|
||||
PTRACE_GETFPREGS);
|
||||
bcopy (&sparc_fpreg_packet[SPARC_R_FP0],
|
||||
®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * SPARC_FPREG_SIZE);
|
||||
bcopy (&sparc_fpreg_packet[SPARC_R_FSR],
|
||||
®isters[REGISTER_BYTE (FPS_REGNUM)], 1 * SPARC_FPREG_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
bzero (®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * SPARC_FPREG_SIZE);
|
||||
bzero (®isters[REGISTER_BYTE (FPS_REGNUM)], 1 * SPARC_FPREG_SIZE);
|
||||
}
|
||||
|
||||
/* Mark the register cache valid. */
|
||||
|
||||
registers_fetched ();
|
||||
}
|
||||
|
||||
/* Store a register or registers into the VxWorks target.
|
||||
REGNO is the register to store, or -1 for all; currently,
|
||||
it is ignored. FIXME look at regno to improve efficiency. */
|
||||
|
||||
void
|
||||
vx_write_register (regno)
|
||||
int regno;
|
||||
{
|
||||
char sparc_greg_packet[SPARC_GREG_PLEN];
|
||||
char sparc_fpreg_packet[SPARC_FPREG_PLEN];
|
||||
int in_gp_regs;
|
||||
int in_fp_regs;
|
||||
CORE_ADDR sp;
|
||||
|
||||
/* Store general purpose registers. When copying values from
|
||||
registers [], don't assume that a location in registers []
|
||||
is properly aligned for the target data type. */
|
||||
|
||||
in_gp_regs = 1;
|
||||
in_fp_regs = 1;
|
||||
if (regno >= 0)
|
||||
{
|
||||
if ((G0_REGNUM <= regno && regno <= I7_REGNUM)
|
||||
|| (Y_REGNUM <= regno && regno <= NPC_REGNUM))
|
||||
in_fp_regs = 0;
|
||||
else
|
||||
in_gp_regs = 0;
|
||||
}
|
||||
if (in_gp_regs)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (G0_REGNUM)],
|
||||
&sparc_greg_packet[SPARC_R_G0], 32 * SPARC_GREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (Y_REGNUM)],
|
||||
&sparc_greg_packet[SPARC_R_Y], 6 * SPARC_GREG_SIZE);
|
||||
|
||||
net_write_registers (sparc_greg_packet, SPARC_GREG_PLEN, PTRACE_SETREGS);
|
||||
|
||||
/* If this is a local or in register, or we're storing all
|
||||
registers, update the register window spill area. */
|
||||
|
||||
if (regno < 0 || (L0_REGNUM <= regno && regno <= I7_REGNUM))
|
||||
{
|
||||
sp = extract_address (®isters[REGISTER_BYTE (SP_REGNUM)],
|
||||
REGISTER_RAW_SIZE (CORE_ADDR));
|
||||
write_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)],
|
||||
16 * REGISTER_RAW_SIZE (L0_REGNUM));
|
||||
}
|
||||
}
|
||||
|
||||
/* Store floating point registers if the target has them. */
|
||||
|
||||
if (in_fp_regs && target_has_fp)
|
||||
{
|
||||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
&sparc_fpreg_packet[SPARC_R_FP0], 32 * SPARC_FPREG_SIZE);
|
||||
bcopy (®isters[REGISTER_BYTE (FPS_REGNUM)],
|
||||
&sparc_fpreg_packet[SPARC_R_FSR], 1 * SPARC_FPREG_SIZE);
|
||||
|
||||
net_write_registers (sparc_fpreg_packet, SPARC_FPREG_PLEN,
|
||||
PTRACE_SETFPREGS);
|
||||
}
|
||||
}
|
|
@ -1,420 +0,0 @@
|
|||
/* Remote serial interface using Hitachi E7000 PC ISA card in a PC
|
||||
|
||||
Copyright 1994 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef __GO32__
|
||||
#include "defs.h"
|
||||
#include "serial.h"
|
||||
#include <sys/dos.h>
|
||||
|
||||
|
||||
|
||||
static int e7000pc_open PARAMS ((serial_t scb, const char *name));
|
||||
static void e7000pc_raw PARAMS ((serial_t scb));
|
||||
static int e7000pc_readchar PARAMS ((serial_t scb, int timeout));
|
||||
static int e7000pc_setbaudrate PARAMS ((serial_t scb, int rate));
|
||||
static int e7000pc_write PARAMS ((serial_t scb, const char *str, int len));
|
||||
static void e7000pc_close PARAMS ((serial_t scb));
|
||||
static serial_ttystate e7000pc_get_tty_state PARAMS ((serial_t scb));
|
||||
static int e7000pc_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
|
||||
static char *aptr PARAMS ((short p));
|
||||
|
||||
static int dos_async_init PARAMS ((int port));
|
||||
static void dos_async_tx PARAMS ((const char c));
|
||||
static int dos_async_rx PARAMS (());
|
||||
|
||||
|
||||
|
||||
#define OFF_DPD 0x0000
|
||||
#define OFF_DDP 0x1000
|
||||
#define OFF_CPD 0x2000
|
||||
#define OFF_CDP 0x2400
|
||||
#define OFF_FA 0x3000
|
||||
#define OFF_FB 0x3002
|
||||
#define OFF_FC 0x3004
|
||||
#define OFF_IRQTOD 0x3008
|
||||
#define OFF_IRQTOP 0x300a
|
||||
#define OFF_READY 0x300c
|
||||
#define OFF_PON 0x300e
|
||||
|
||||
#define IDLE 0x0000
|
||||
#define CMD_CI 0x4349
|
||||
#define CMD_CO 0x434f
|
||||
#define CMD_LO 0x4c4f
|
||||
#define CMD_LS 0x4c53
|
||||
#define CMD_SV 0x5356
|
||||
#define CMD_SS 0x5353
|
||||
#define CMD_OK 0x4f4b
|
||||
#define CMD_ER 0x4552
|
||||
#define CMD_NF 0x4e46
|
||||
#define CMD_AB 0x4142
|
||||
#define CMD_ED 0x4544
|
||||
#define CMD_CE 0x4345
|
||||
|
||||
static unsigned long fa;
|
||||
static unsigned long irqtod;
|
||||
static unsigned long ready;
|
||||
static unsigned long fb;
|
||||
static unsigned long cpd ;
|
||||
static unsigned long cdp ;
|
||||
static unsigned long ready;
|
||||
static unsigned long pon;
|
||||
static unsigned long irqtop;
|
||||
static unsigned long board_at;
|
||||
|
||||
#define SET_BYTE(x,y) { char _buf = y;dosmemput(&_buf,1, x);}
|
||||
#define SET_WORD(x,y) { short _buf = y;dosmemput(&_buf,2, x);}
|
||||
#define GET_BYTE(x) ( dosmemget(x,1,&bb), bb)
|
||||
#define GET_WORD(x) ( dosmemget(x,2,&sb), sb)
|
||||
|
||||
static unsigned char bb;
|
||||
static unsigned short sb;
|
||||
|
||||
|
||||
static struct sw
|
||||
{
|
||||
int sw;
|
||||
int addr;
|
||||
} sigs[] = {
|
||||
{0x14, 0xd0000},
|
||||
{0x15, 0xd4000},
|
||||
{0x16, 0xd8000},
|
||||
{0x17, 0xdc000},
|
||||
0};
|
||||
|
||||
static int
|
||||
e7000pc_init ()
|
||||
{
|
||||
/* Look around in memory for the board's signature */
|
||||
|
||||
int try;
|
||||
|
||||
for (try = 0; sigs[try].sw; try++)
|
||||
|
||||
{
|
||||
int val;
|
||||
board_at = sigs[try].addr;
|
||||
fa = board_at + OFF_FA;
|
||||
fb = board_at + OFF_FB;
|
||||
cpd = board_at + OFF_CPD;
|
||||
cdp = board_at + OFF_CDP;
|
||||
ready =board_at + OFF_READY;
|
||||
pon = board_at + OFF_PON;
|
||||
irqtop = board_at + OFF_IRQTOP;
|
||||
irqtod = board_at + OFF_IRQTOD;
|
||||
|
||||
val = GET_WORD (ready);
|
||||
|
||||
if (val == (0xaaa0 | sigs[try].sw))
|
||||
{
|
||||
if (GET_BYTE (pon) & 0xf)
|
||||
{
|
||||
SET_BYTE(fa, 0);
|
||||
SET_BYTE (fb, 0);
|
||||
|
||||
SET_BYTE (irqtop, 1); /* Disable interrupts from e7000 */
|
||||
SET_WORD (ready, 1);
|
||||
printf_filtered ("\nConnected to the E7000PC at address 0x%x\n",
|
||||
sigs[try].addr);
|
||||
return 1;
|
||||
}
|
||||
error ("The E7000 PC board is working, but the E7000 is turned off.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error ("GDB cannot connect to the E7000 PC board, check that it is installed\n\
|
||||
and that the switch settings are correct. Some other DOS programs can \n\
|
||||
stop the board from working. Try starting from a very minimal boot, \n\
|
||||
perhaps you need to disable EMM386 over the region where the board has\n\
|
||||
its I/O space, remove other unneeded cards, etc etc\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int pbuf_size;
|
||||
static int pbuf_index;
|
||||
|
||||
static
|
||||
int
|
||||
e7000_get ()
|
||||
{
|
||||
static char pbuf[1000];
|
||||
char tmp[1000];
|
||||
int x;
|
||||
if (pbuf_index < pbuf_size)
|
||||
{
|
||||
x = pbuf[pbuf_index++];
|
||||
}
|
||||
else if ((GET_BYTE (fb) & 1))
|
||||
{
|
||||
int i;
|
||||
pbuf_size = GET_WORD(cdp + 2);
|
||||
|
||||
dosmemget (cdp + 8, pbuf_size + 1, tmp);
|
||||
|
||||
/* Tell the E7000 we've eaten */
|
||||
SET_BYTE(fb,0);
|
||||
/* Swap it around */
|
||||
for (i = 0; i < pbuf_size; i++)
|
||||
{
|
||||
pbuf[i] = tmp[i^1];
|
||||
}
|
||||
pbuf_index = 0;
|
||||
x = pbuf[pbuf_index++];
|
||||
}
|
||||
else
|
||||
{
|
||||
x = -1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static int
|
||||
dosasync_read (fd, buf, len, timeout)
|
||||
int fd;
|
||||
char *buf;
|
||||
int len;
|
||||
int timeout;
|
||||
|
||||
{
|
||||
long now;
|
||||
long then;
|
||||
int i = 0;
|
||||
int p;
|
||||
|
||||
/* Then look for some more if we're still hungry */
|
||||
time (&now);
|
||||
then = now + timeout;
|
||||
while (i < len)
|
||||
{
|
||||
int ch = e7000_get();
|
||||
|
||||
/* While there's room in the buffer, and we've already
|
||||
read the stuff in, suck it over */
|
||||
if (ch != -1)
|
||||
{
|
||||
buf[i++] = ch;
|
||||
while (i < len && pbuf_index < pbuf_size )
|
||||
{
|
||||
ch = e7000_get();
|
||||
if (ch == -1)
|
||||
break;
|
||||
buf[i++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
time (&now);
|
||||
|
||||
if (timeout == 0)
|
||||
return i;
|
||||
if (now >= then && timeout > 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dosasync_write (fd, buf, len)
|
||||
int fd;
|
||||
const char *buf;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
char dummy[1000];
|
||||
|
||||
|
||||
/* Construct copy locally */
|
||||
((short *)dummy)[0] = CMD_CI;
|
||||
((short *)dummy)[1] = len;
|
||||
((short *)dummy)[2] = 0;
|
||||
((short *)dummy)[3] = 0;
|
||||
for (i = 0; i < len ; i++)
|
||||
{
|
||||
dummy[8 + i ^ 1] = buf[i];
|
||||
}
|
||||
|
||||
/* Wait for the card to get ready */
|
||||
while ((GET_BYTE(fa) & 1) != 0)
|
||||
;
|
||||
|
||||
/* Blast onto the ISA card */
|
||||
dosmemput (dummy, 8 + len + 1, cpd);
|
||||
|
||||
SET_BYTE(fa, 1);
|
||||
SET_BYTE(irqtod, 1); /* Interrupt the E7000 */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_open (scb, name)
|
||||
serial_t scb;
|
||||
const char *name;
|
||||
{
|
||||
if (strncasecmp (name, "pc", 2) != 0)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
scb->fd = e7000pc_init ();
|
||||
|
||||
if (!scb->fd)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_noop (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
e7000pc_raw (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
/* Always in raw mode */
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_readchar (scb, timeout)
|
||||
serial_t scb;
|
||||
int timeout;
|
||||
{
|
||||
char buf;
|
||||
|
||||
top:
|
||||
|
||||
if (dosasync_read (scb->fd, &buf, 1, timeout))
|
||||
{
|
||||
if (buf == 0) goto top;
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return SERIAL_TIMEOUT;
|
||||
}
|
||||
|
||||
struct e7000pc_ttystate {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
/* e7000pc_{get set}_tty_state() are both dummys to fill out the function
|
||||
vector. Someday, they may do something real... */
|
||||
|
||||
static serial_ttystate
|
||||
e7000pc_get_tty_state (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
struct e7000pc_ttystate *state;
|
||||
|
||||
state = (struct e7000pc_ttystate *) xmalloc (sizeof *state);
|
||||
|
||||
return (serial_ttystate) state;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_set_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate new_ttystate;
|
||||
serial_ttystate old_ttystate;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
e7000pc_print_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
/* Nothing to print. */
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_setbaudrate (scb, rate)
|
||||
serial_t scb;
|
||||
int rate;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
e7000pc_write (scb, str, len)
|
||||
serial_t scb;
|
||||
const char *str;
|
||||
int len;
|
||||
{
|
||||
dosasync_write (scb->fd, str, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
e7000pc_close (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
}
|
||||
|
||||
static struct serial_ops e7000pc_ops =
|
||||
{
|
||||
"pc",
|
||||
0,
|
||||
e7000pc_open,
|
||||
e7000pc_close,
|
||||
e7000pc_readchar,
|
||||
e7000pc_write,
|
||||
e7000pc_noop, /* flush output */
|
||||
e7000pc_noop, /* flush input */
|
||||
e7000pc_noop, /* send break -- currently used only for nindy */
|
||||
e7000pc_raw,
|
||||
e7000pc_get_tty_state,
|
||||
e7000pc_set_tty_state,
|
||||
e7000pc_print_tty_state,
|
||||
e7000pc_noflush_set_tty_state,
|
||||
e7000pc_setbaudrate,
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_ser_e7000pc ()
|
||||
{
|
||||
serial_add_interface (&e7000pc_ops);
|
||||
}
|
||||
#else
|
||||
|
||||
void
|
||||
_initialize_ser_e7000pc ()
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
|
@ -1,957 +0,0 @@
|
|||
/* Remote serial interface for local (hardwired) serial ports for
|
||||
GO32. Copyright 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
|
||||
|
||||
This version uses DPMI interrupts to handle buffered i/o
|
||||
without the separate "asynctsr" program.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
/*
|
||||
* NS16550 UART registers
|
||||
*/
|
||||
|
||||
#define COM1ADDR 0x3f8
|
||||
#define COM2ADDR 0x2f8
|
||||
#define COM3ADDR 0x3e8
|
||||
#define COM4ADDR 0x3e0
|
||||
|
||||
#define com_data 0 /* data register (R/W) */
|
||||
#define com_dlbl 0 /* divisor latch low (W) */
|
||||
#define com_ier 1 /* interrupt enable (W) */
|
||||
#define com_dlbh 1 /* divisor latch high (W) */
|
||||
#define com_iir 2 /* interrupt identification (R) */
|
||||
#define com_fifo 2 /* FIFO control (W) */
|
||||
#define com_lctl 3 /* line control register (R/W) */
|
||||
#define com_cfcr 3 /* line control register (R/W) */
|
||||
#define com_mcr 4 /* modem control register (R/W) */
|
||||
#define com_lsr 5 /* line status register (R/W) */
|
||||
#define com_msr 6 /* modem status register (R/W) */
|
||||
|
||||
/*
|
||||
* Constants for computing 16 bit baud rate divisor (lower byte
|
||||
* in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal. Divisor is
|
||||
* 1.8432 MHz / (16 * X) for X bps. If the baud rate can't be set
|
||||
* to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
|
||||
*/
|
||||
#define COMTICK (1843200/16)
|
||||
#define SPEED_TOLERANCE 30 /* thousandths; real == desired +- 3.0% */
|
||||
|
||||
/* interrupt enable register */
|
||||
#define IER_ERXRDY 0x1 /* int on rx ready */
|
||||
#define IER_ETXRDY 0x2 /* int on tx ready */
|
||||
#define IER_ERLS 0x4 /* int on line status change */
|
||||
#define IER_EMSC 0x8 /* int on modem status change */
|
||||
|
||||
/* interrupt identification register */
|
||||
#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
|
||||
#define IIR_IMASK 0xf /* interrupt cause mask */
|
||||
#define IIR_NOPEND 0x1 /* nothing pending */
|
||||
#define IIR_RLS 0x6 /* receive line status */
|
||||
#define IIR_RXRDY 0x4 /* receive ready */
|
||||
#define IIR_RXTOUT 0xc /* receive timeout */
|
||||
#define IIR_TXRDY 0x2 /* transmit ready */
|
||||
#define IIR_MLSC 0x0 /* modem status */
|
||||
|
||||
|
||||
/* fifo control register */
|
||||
#define FIFO_ENABLE 0x01 /* enable fifo */
|
||||
#define FIFO_RCV_RST 0x02 /* reset receive fifo */
|
||||
#define FIFO_XMT_RST 0x04 /* reset transmit fifo */
|
||||
#define FIFO_DMA_MODE 0x08 /* enable dma mode */
|
||||
#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */
|
||||
#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */
|
||||
#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */
|
||||
#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */
|
||||
|
||||
/* character format control register */
|
||||
#define CFCR_DLAB 0x80 /* divisor latch */
|
||||
#define CFCR_SBREAK 0x40 /* send break */
|
||||
#define CFCR_PZERO 0x30 /* zero parity */
|
||||
#define CFCR_PONE 0x20 /* one parity */
|
||||
#define CFCR_PEVEN 0x10 /* even parity */
|
||||
#define CFCR_PODD 0x00 /* odd parity */
|
||||
#define CFCR_PENAB 0x08 /* parity enable */
|
||||
#define CFCR_STOPB 0x04 /* 2 stop bits */
|
||||
#define CFCR_8BITS 0x03 /* 8 data bits */
|
||||
#define CFCR_7BITS 0x02 /* 7 data bits */
|
||||
#define CFCR_6BITS 0x01 /* 6 data bits */
|
||||
#define CFCR_5BITS 0x00 /* 5 data bits */
|
||||
|
||||
/* modem control register */
|
||||
#define MCR_LOOPBACK 0x10 /* loopback */
|
||||
#define MCR_IENABLE 0x08 /* output 2 = int enable */
|
||||
#define MCR_DRS 0x04 /* output 1 = xxx */
|
||||
#define MCR_RTS 0x02 /* enable RTS */
|
||||
#define MCR_DTR 0x01 /* enable DTR */
|
||||
|
||||
/* line status register */
|
||||
#define LSR_RCV_FIFO 0x80 /* error in receive fifo */
|
||||
#define LSR_TSRE 0x40 /* transmitter empty */
|
||||
#define LSR_TXRDY 0x20 /* transmitter ready */
|
||||
#define LSR_BI 0x10 /* break detected */
|
||||
#define LSR_FE 0x08 /* framing error */
|
||||
#define LSR_PE 0x04 /* parity error */
|
||||
#define LSR_OE 0x02 /* overrun error */
|
||||
#define LSR_RXRDY 0x01 /* receiver ready */
|
||||
#define LSR_RCV_MASK 0x1f
|
||||
|
||||
/* modem status register */
|
||||
#define MSR_DCD 0x80
|
||||
#define MSR_RI 0x40
|
||||
#define MSR_DSR 0x20
|
||||
#define MSR_CTS 0x10
|
||||
#define MSR_DDCD 0x08
|
||||
#define MSR_TERI 0x04
|
||||
#define MSR_DDSR 0x02
|
||||
#define MSR_DCTS 0x01
|
||||
|
||||
#include <sys/dos.h>
|
||||
#include <sys/go32.h>
|
||||
#include <sys/dpmi.h>
|
||||
|
||||
/* DPMI Communication */
|
||||
static union REGS dpmi_regs;
|
||||
static struct SREGS dpmi_sregs;
|
||||
|
||||
/* 16550 rx fifo trigger point */
|
||||
#define FIFO_TRIGGER FIFO_TRIGGER_4
|
||||
|
||||
/* input buffer size */
|
||||
#define CBSIZE 4096
|
||||
|
||||
/* return raw 18Hz clock count */
|
||||
extern long rawclock (void);
|
||||
|
||||
#define RAWHZ 18
|
||||
|
||||
#ifdef DOS_STATS
|
||||
#define CNT_RX 16
|
||||
#define CNT_TX 17
|
||||
#define CNT_STRAY 18
|
||||
#define CNT_ORUN 19
|
||||
#define NCNT 20
|
||||
|
||||
static int intrcnt;
|
||||
static int cnts[NCNT];
|
||||
static char *cntnames[NCNT] = {
|
||||
/* h/w interrupt counts. */
|
||||
"mlsc", "nopend", "txrdy", "?3",
|
||||
"rxrdy", "?5", "rls", "?7",
|
||||
"?8", "?9", "?a", "?b",
|
||||
"rxtout", "?d", "?e", "?f",
|
||||
/* s/w counts. */
|
||||
"rxcnt", "txcnt", "stray", "swoflo"
|
||||
};
|
||||
|
||||
#define COUNT(x) cnts[x]++
|
||||
#else
|
||||
#define COUNT(x)
|
||||
#endif
|
||||
|
||||
/* Main interrupt controller port addresses. */
|
||||
#define ICU_BASE 0x20
|
||||
#define ICU_OCW2 (ICU_BASE + 0)
|
||||
#define ICU_MASK (ICU_BASE + 1)
|
||||
|
||||
/* Original interrupt controller mask register. */
|
||||
unsigned char icu_oldmask;
|
||||
|
||||
/* Maximum of 8 interrupts (we don't handle the slave icu yet). */
|
||||
#define NINTR 8
|
||||
|
||||
static struct intrupt
|
||||
{
|
||||
char inuse;
|
||||
struct dos_ttystate *port;
|
||||
_go32_dpmi_seginfo old_rmhandler;
|
||||
_go32_dpmi_seginfo old_pmhandler;
|
||||
_go32_dpmi_seginfo new_rmhandler;
|
||||
_go32_dpmi_seginfo new_pmhandler;
|
||||
_go32_dpmi_registers regs;
|
||||
} intrupts[NINTR];
|
||||
|
||||
|
||||
static struct dos_ttystate
|
||||
{
|
||||
int base;
|
||||
int irq;
|
||||
int refcnt;
|
||||
struct intrupt *intrupt;
|
||||
int fifo;
|
||||
int baudrate;
|
||||
unsigned char cbuf[CBSIZE];
|
||||
unsigned int first;
|
||||
unsigned int count;
|
||||
int txbusy;
|
||||
unsigned char old_mcr;
|
||||
int ferr;
|
||||
int perr;
|
||||
int oflo;
|
||||
int msr;
|
||||
} ports[4] = {
|
||||
{COM1ADDR, 4},
|
||||
{COM2ADDR, 3},
|
||||
{COM3ADDR, 4},
|
||||
{COM4ADDR, 3}
|
||||
};
|
||||
|
||||
static int dos_open PARAMS ((serial_t scb, const char *name));
|
||||
static void dos_raw PARAMS ((serial_t scb));
|
||||
static int dos_readchar PARAMS ((serial_t scb, int timeout));
|
||||
static int dos_setbaudrate PARAMS ((serial_t scb, int rate));
|
||||
static int dos_write PARAMS ((serial_t scb, const char *str, int len));
|
||||
static void dos_close PARAMS ((serial_t scb));
|
||||
static serial_ttystate dos_get_tty_state PARAMS ((serial_t scb));
|
||||
static int dos_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
|
||||
static int dos_baudconv PARAMS ((int rate));
|
||||
|
||||
#define inb(p,a) inportb((p)->base + (a))
|
||||
#define outb(p,a,v) outportb((p)->base + (a), (v))
|
||||
#define disable() asm volatile ("cli");
|
||||
#define enable() asm volatile ("sti");
|
||||
|
||||
|
||||
static int
|
||||
dos_getc (port)
|
||||
volatile struct dos_ttystate *port;
|
||||
{
|
||||
int c;
|
||||
|
||||
if (port->count == 0)
|
||||
return -1;
|
||||
|
||||
c = port->cbuf[port->first];
|
||||
disable ();
|
||||
port->first = (port->first + 1) & (CBSIZE - 1);
|
||||
port->count--;
|
||||
enable ();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dos_putc (c, port)
|
||||
int c;
|
||||
struct dos_ttystate *port;
|
||||
{
|
||||
if (port->count >= CBSIZE - 1)
|
||||
return -1;
|
||||
port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
|
||||
port->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
dos_comisr (irq)
|
||||
int irq;
|
||||
{
|
||||
struct dos_ttystate *port;
|
||||
unsigned char iir, lsr, c;
|
||||
|
||||
disable (); /* Paranoia */
|
||||
outportb (ICU_OCW2, 0x20); /* End-Of-Interrupt */
|
||||
#ifdef DOS_STATS
|
||||
++intrcnt;
|
||||
#endif
|
||||
|
||||
port = intrupts[irq].port;
|
||||
if (!port)
|
||||
{
|
||||
COUNT (CNT_STRAY);
|
||||
return; /* not open */
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
iir = inb (port, com_iir) & IIR_IMASK;
|
||||
switch (iir)
|
||||
{
|
||||
|
||||
case IIR_RLS:
|
||||
lsr = inb (port, com_lsr);
|
||||
goto rx;
|
||||
|
||||
case IIR_RXTOUT:
|
||||
case IIR_RXRDY:
|
||||
lsr = 0;
|
||||
|
||||
rx:
|
||||
do
|
||||
{
|
||||
c = inb (port, com_data);
|
||||
if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
|
||||
{
|
||||
if (lsr & (LSR_BI | LSR_FE))
|
||||
port->ferr++;
|
||||
else if (lsr & LSR_PE)
|
||||
port->perr++;
|
||||
if (lsr & LSR_OE)
|
||||
port->oflo++;
|
||||
}
|
||||
|
||||
if (dos_putc (c, port) < 0)
|
||||
{
|
||||
COUNT (CNT_ORUN);
|
||||
}
|
||||
else
|
||||
{
|
||||
COUNT (CNT_RX);
|
||||
}
|
||||
}
|
||||
while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
|
||||
break;
|
||||
|
||||
case IIR_MLSC:
|
||||
/* could be used to flowcontrol Tx */
|
||||
port->msr = inb (port, com_msr);
|
||||
break;
|
||||
|
||||
case IIR_TXRDY:
|
||||
port->txbusy = 0;
|
||||
break;
|
||||
|
||||
case IIR_NOPEND:
|
||||
/* no more pending interrupts, all done */
|
||||
return;
|
||||
|
||||
default:
|
||||
/* unexpected interrupt, ignore */
|
||||
break;
|
||||
}
|
||||
COUNT (iir);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
#define ISRNAME(x) dos_comisr##x
|
||||
#else
|
||||
#define ISRNAME(x) dos_comisr/**/x
|
||||
#endif
|
||||
#define ISR(x) static void ISRNAME(x)() {dos_comisr(x);}
|
||||
|
||||
ISR(0) ISR(1) ISR(2) ISR(3)
|
||||
ISR(4) ISR(5) ISR(6) ISR(7)
|
||||
|
||||
typedef void (*isr_t)();
|
||||
|
||||
static isr_t isrs[NINTR] = {
|
||||
ISRNAME(0), ISRNAME(1), ISRNAME(2), ISRNAME(3),
|
||||
ISRNAME(4), ISRNAME(5), ISRNAME(6), ISRNAME(7)
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct intrupt *
|
||||
dos_hookirq (irq)
|
||||
unsigned int irq;
|
||||
{
|
||||
struct intrupt *intr;
|
||||
unsigned int vec;
|
||||
isr_t isr;
|
||||
|
||||
if (irq >= NINTR)
|
||||
return 0;
|
||||
|
||||
intr = &intrupts[irq];
|
||||
if (intr->inuse)
|
||||
return 0;
|
||||
|
||||
vec = 0x08 + irq;
|
||||
isr = isrs[irq];
|
||||
|
||||
/* setup real mode handler */
|
||||
_go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
|
||||
|
||||
intr->new_rmhandler.pm_selector = _go32_my_cs();
|
||||
intr->new_rmhandler.pm_offset = (u_long)isr;
|
||||
if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
|
||||
&intr->regs))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setup protected mode handler */
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(vec, &intr->old_pmhandler);
|
||||
|
||||
intr->new_pmhandler.pm_selector = _go32_my_cs();
|
||||
intr->new_pmhandler.pm_offset = (u_long)isr;
|
||||
_go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
|
||||
|
||||
if (_go32_dpmi_set_protected_mode_interrupt_vector(vec, &intr->new_pmhandler))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setup interrupt controller mask */
|
||||
disable ();
|
||||
outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
|
||||
enable ();
|
||||
|
||||
intr->inuse = 1;
|
||||
return intr;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dos_unhookirq (intr)
|
||||
struct intrupt *intr;
|
||||
{
|
||||
unsigned int irq, vec;
|
||||
unsigned char mask;
|
||||
|
||||
irq = intr - intrupts;
|
||||
vec = 0x08 + irq;
|
||||
|
||||
/* restore old interrupt mask bit */
|
||||
mask = 1 << irq;
|
||||
disable ();
|
||||
outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
|
||||
enable ();
|
||||
|
||||
/* remove real mode handler */
|
||||
_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
|
||||
_go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
|
||||
|
||||
/* remove protected mode handler */
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
|
||||
_go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
|
||||
intr->inuse = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
dos_open (scb, name)
|
||||
serial_t scb;
|
||||
const char *name;
|
||||
{
|
||||
struct dos_ttystate *port;
|
||||
int fd, i;
|
||||
|
||||
if (strncasecmp (name, "/dev/", 5) == 0)
|
||||
name += 5;
|
||||
else if (strncasecmp (name, "\\dev\\", 5) == 0)
|
||||
name += 5;
|
||||
|
||||
if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (name[3] < '1' || name[3] > '4')
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = name[3] - '1';
|
||||
port = &ports[fd];
|
||||
if (port->refcnt++ > 0)
|
||||
{
|
||||
/* Device already opened another user. Just point at it. */
|
||||
scb->fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* force access to ID reg */
|
||||
outb(port, com_cfcr, 0);
|
||||
outb(port, com_iir, 0);
|
||||
for (i = 0; i < 17; i++) {
|
||||
if ((inb(port, com_iir) & 0x38) == 0)
|
||||
goto ok;
|
||||
(void) inb(port, com_data); /* clear recv */
|
||||
}
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
|
||||
ok:
|
||||
/* disable all interrupts in chip */
|
||||
outb(port, com_ier, 0);
|
||||
|
||||
/* tentatively enable 16550 fifo, and see if it responds */
|
||||
outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER);
|
||||
sleep(1);
|
||||
port->fifo = ((inb(port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
|
||||
|
||||
/* clear pending status reports. */
|
||||
(void) inb(port, com_lsr);
|
||||
(void) inb(port, com_msr);
|
||||
|
||||
/* enable external interrupt gate (to avoid floating IRQ) */
|
||||
outb(port, com_mcr, MCR_IENABLE);
|
||||
|
||||
/* hook up interrupt handler and initialise icu */
|
||||
port->intrupt = dos_hookirq (port->irq);
|
||||
if (!port->intrupt)
|
||||
{
|
||||
outb(port, com_mcr, 0);
|
||||
outb(port, com_fifo, 0);
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
disable ();
|
||||
|
||||
/* record port */
|
||||
port->intrupt->port = port;
|
||||
scb->fd = fd;
|
||||
|
||||
/* clear rx buffer, tx busy flag and overflow count */
|
||||
port->first = port->count = 0;
|
||||
port->txbusy = 0;
|
||||
port->oflo = 0;
|
||||
|
||||
/* set default baud rate and mode: 9600,8,n,1 */
|
||||
i = dos_baudconv (port->baudrate = 9600);
|
||||
outb(port, com_cfcr, CFCR_DLAB);
|
||||
outb(port, com_dlbl, i & 0xff);
|
||||
outb(port, com_dlbh, i >> 8);
|
||||
outb(port, com_cfcr, CFCR_8BITS);
|
||||
|
||||
/* enable all interrupts */
|
||||
outb(port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
|
||||
|
||||
/* enable DTR & RTS */
|
||||
outb(port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
|
||||
|
||||
enable ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dos_close (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
struct dos_ttystate *port;
|
||||
struct intrupt *intrupt;
|
||||
|
||||
if (!scb)
|
||||
return;
|
||||
|
||||
port = &ports[scb->fd];
|
||||
|
||||
if (port->refcnt-- > 1)
|
||||
return;
|
||||
|
||||
if (!(intrupt = port->intrupt))
|
||||
return;
|
||||
|
||||
/* disable interrupts, fifo, flow control */
|
||||
disable ();
|
||||
port->intrupt = 0;
|
||||
intrupt->port = 0;
|
||||
outb(port, com_fifo, 0);
|
||||
outb(port, com_ier, 0);
|
||||
enable ();
|
||||
|
||||
/* unhook handler, and disable interrupt gate */
|
||||
dos_unhookirq (intrupt);
|
||||
outb(port, com_mcr, 0);
|
||||
|
||||
/* Check for overflow errors */
|
||||
if (port->oflo)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stderr,
|
||||
"Serial input overruns occurred.\n");
|
||||
fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
|
||||
port->fifo ? "cannot" : "needs a 16550 to",
|
||||
port->baudrate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
dos_noop (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dos_raw (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
/* Always in raw mode */
|
||||
}
|
||||
|
||||
static int
|
||||
dos_readchar (scb, timeout)
|
||||
serial_t scb;
|
||||
int timeout;
|
||||
{
|
||||
struct dos_ttystate *port = &ports[scb->fd];
|
||||
long then;
|
||||
int c;
|
||||
|
||||
then = rawclock() + (timeout * RAWHZ);
|
||||
while ((c = dos_getc (port)) < 0)
|
||||
{
|
||||
if (timeout >= 0 && (rawclock () - then) >= 0)
|
||||
return SERIAL_TIMEOUT;
|
||||
notice_quit ();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static serial_ttystate
|
||||
dos_get_tty_state (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
struct dos_ttystate *port = &ports[scb->fd];
|
||||
struct dos_ttystate *state;
|
||||
|
||||
state = (struct dos_ttystate *) xmalloc (sizeof *state);
|
||||
*state = *port;
|
||||
return (serial_ttystate) state;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_set_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
struct dos_ttystate *state;
|
||||
|
||||
state = (struct dos_ttystate *) ttystate;
|
||||
dos_setbaudrate (scb, state->baudrate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate new_ttystate;
|
||||
serial_ttystate old_ttystate;
|
||||
{
|
||||
struct dos_ttystate *state;
|
||||
|
||||
state = (struct dos_ttystate *) new_ttystate;
|
||||
dos_setbaudrate (scb, state->baudrate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_flush_input (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
struct dos_ttystate *port = &ports[scb->fd];
|
||||
disable();
|
||||
port->first = port->count = 0;
|
||||
if (port->fifo)
|
||||
outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_TRIGGER);
|
||||
enable();
|
||||
}
|
||||
|
||||
static void
|
||||
dos_print_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
/* Nothing to print */
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_baudconv (rate)
|
||||
int rate;
|
||||
{
|
||||
long x, err;
|
||||
|
||||
if (rate <= 0)
|
||||
return -1;
|
||||
|
||||
#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* divide and round off */
|
||||
x = divrnd(COMTICK, rate);
|
||||
if (x <= 0)
|
||||
return -1;
|
||||
|
||||
err = divrnd(1000 * COMTICK, x * rate) - 1000;
|
||||
if (err < 0)
|
||||
err = -err;
|
||||
if (err > SPEED_TOLERANCE)
|
||||
return -1;
|
||||
#undef divrnd
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dos_setbaudrate (scb, rate)
|
||||
serial_t scb;
|
||||
int rate;
|
||||
{
|
||||
struct dos_ttystate *port = &ports[scb->fd];
|
||||
|
||||
if (port->baudrate != rate)
|
||||
{
|
||||
int x;
|
||||
unsigned char cfcr;
|
||||
|
||||
x = dos_baudconv (rate);
|
||||
if (x <= 0)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
disable ();
|
||||
cfcr = inb (port, com_cfcr);
|
||||
|
||||
outb(port, com_cfcr, CFCR_DLAB);
|
||||
outb(port, com_dlbl, x & 0xff);
|
||||
outb(port, com_dlbh, x >> 8);
|
||||
outb(port, com_cfcr, cfcr);
|
||||
port->baudrate = rate;
|
||||
enable ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_setstopbits (scb, num)
|
||||
serial_t scb;
|
||||
int num;
|
||||
{
|
||||
struct dos_ttystate *port = &ports[scb->fd];
|
||||
unsigned char cfcr;
|
||||
|
||||
disable ();
|
||||
cfcr = inb (port, com_cfcr);
|
||||
|
||||
switch (num)
|
||||
{
|
||||
case SERIAL_1_STOPBITS:
|
||||
outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
|
||||
break;
|
||||
case SERIAL_1_AND_A_HALF_STOPBITS:
|
||||
case SERIAL_2_STOPBITS:
|
||||
outb (port, com_cfcr, cfcr | CFCR_STOPB);
|
||||
break;
|
||||
default:
|
||||
enable ();
|
||||
return 1;
|
||||
}
|
||||
enable ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dos_write (scb, str, len)
|
||||
serial_t scb;
|
||||
const char *str;
|
||||
int len;
|
||||
{
|
||||
volatile struct dos_ttystate *port = &ports[scb->fd];
|
||||
int fifosize = port->fifo ? 16 : 1;
|
||||
long then;
|
||||
int cnt;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
/* send the data, fifosize bytes at a time */
|
||||
cnt = fifosize > len ? len : fifosize;
|
||||
port->txbusy = 1;
|
||||
outportsb (port->base + com_data, str, cnt);
|
||||
str += cnt;
|
||||
len -= cnt;
|
||||
#ifdef DOS_STATS
|
||||
cnts[CNT_TX] += cnt;
|
||||
#endif
|
||||
/* wait for transmission to complete (max 1 sec) */
|
||||
then = rawclock() + RAWHZ;
|
||||
while (port->txbusy)
|
||||
{
|
||||
if ((rawclock () - then) >= 0)
|
||||
{
|
||||
errno = EIO;
|
||||
return SERIAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dos_sendbreak (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
volatile struct dos_ttystate *port = &ports[scb->fd];
|
||||
unsigned char cfcr;
|
||||
long then;
|
||||
|
||||
cfcr = inb(port, com_cfcr);
|
||||
outb(port, com_cfcr, cfcr | CFCR_SBREAK);
|
||||
|
||||
/* 0.25 sec delay */
|
||||
then = rawclock () + RAWHZ / 4;
|
||||
while ((rawclock () - then) < 0)
|
||||
continue;
|
||||
|
||||
outb(port, com_cfcr, cfcr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct serial_ops dos_ops =
|
||||
{
|
||||
"hardwire",
|
||||
0,
|
||||
dos_open,
|
||||
dos_close,
|
||||
dos_readchar,
|
||||
dos_write,
|
||||
dos_noop, /* flush output */
|
||||
dos_flush_input,
|
||||
dos_sendbreak,
|
||||
dos_raw,
|
||||
dos_get_tty_state,
|
||||
dos_set_tty_state,
|
||||
dos_print_tty_state,
|
||||
dos_noflush_set_tty_state,
|
||||
dos_setbaudrate,
|
||||
dos_setstopbits,
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
dos_info (arg, from_tty)
|
||||
char *arg;
|
||||
int from_tty;
|
||||
{
|
||||
struct dos_ttystate *port;
|
||||
int i;
|
||||
|
||||
for (port = ports; port < &ports[4]; port++)
|
||||
{
|
||||
if (port->baudrate == 0)
|
||||
continue;
|
||||
printf_filtered ("Port:\tCOM%d (%sactive)\n", port - ports + 1,
|
||||
port->intrupt ? "" : "not ");
|
||||
printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
|
||||
printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
|
||||
printf_filtered ("Speed:\t%d baud\n", port->baudrate);
|
||||
printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
|
||||
port->ferr, port->perr, port->oflo);
|
||||
}
|
||||
|
||||
#ifdef DOS_STATS
|
||||
printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
|
||||
for (i = 0; i < NCNT; i++)
|
||||
if (cnts[i])
|
||||
printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_initialize_ser_dos ()
|
||||
{
|
||||
struct cmd_list_element *c;
|
||||
|
||||
serial_add_interface (&dos_ops);
|
||||
|
||||
/* Save original interrupt mask register. */
|
||||
icu_oldmask = inportb (ICU_MASK);
|
||||
|
||||
/* Mark fixed motherboard irqs as inuse. */
|
||||
intrupts[0].inuse = /* timer tick */
|
||||
intrupts[1].inuse = /* keyboard */
|
||||
intrupts[2].inuse = 1; /* slave icu */
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com1base", class_obscure, var_zinteger,
|
||||
(char *) &ports[0].base,
|
||||
"Set COM1 base i/o port address.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com1irq", class_obscure, var_zinteger,
|
||||
(char *) &ports[0].irq,
|
||||
"Set COM1 interrupt request.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com2base", class_obscure, var_zinteger,
|
||||
(char *) &ports[1].base,
|
||||
"Set COM2 base i/o port address.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com2irq", class_obscure, var_zinteger,
|
||||
(char *) &ports[1].irq,
|
||||
"Set COM2 interrupt request.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com3base", class_obscure, var_zinteger,
|
||||
(char *) &ports[2].base,
|
||||
"Set COM3 base i/o port address.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com3irq", class_obscure, var_zinteger,
|
||||
(char *) &ports[2].irq,
|
||||
"Set COM3 interrupt request.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com4base", class_obscure, var_zinteger,
|
||||
(char *) &ports[3].base,
|
||||
"Set COM4 base i/o port address.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_show_from_set (
|
||||
add_set_cmd ("com4irq", class_obscure, var_zinteger,
|
||||
(char *) &ports[3].irq,
|
||||
"Set COM4 interrupt request.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
add_info ("serial", dos_info,
|
||||
"Print DOS serial port status.");
|
||||
}
|
|
@ -1,361 +0,0 @@
|
|||
/* Remote serial interface for local (hardwired) serial ports for Macintosh.
|
||||
Copyright 1994 Free Software Foundation, Inc.
|
||||
Contributed by Cygnus Support. Written by Stan Shebs.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "serial.h"
|
||||
|
||||
#include <Types.h>
|
||||
#include <Devices.h>
|
||||
/* This is the regular Mac Serial.h, but copied to a different name
|
||||
so as not to get confused with the GDB serial.h above. */
|
||||
#include "MacSerial.h"
|
||||
|
||||
/* This is unused for now. We just return a placeholder. */
|
||||
|
||||
struct mac_ttystate
|
||||
{
|
||||
int bogus;
|
||||
};
|
||||
|
||||
static int mac_open PARAMS ((serial_t scb, const char *name));
|
||||
static void mac_raw PARAMS ((serial_t scb));
|
||||
static int mac_readchar PARAMS ((serial_t scb, int timeout));
|
||||
static int mac_setbaudrate PARAMS ((serial_t scb, int rate));
|
||||
static int mac_write PARAMS ((serial_t scb, const char *str, int len));
|
||||
static void mac_close PARAMS ((serial_t scb));
|
||||
static serial_ttystate mac_get_tty_state PARAMS ((serial_t scb));
|
||||
static int mac_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
|
||||
static char *aptr PARAMS ((short p));
|
||||
|
||||
short input_refnum;
|
||||
short output_refnum;
|
||||
|
||||
char *mac_input_buffer;
|
||||
char *mac_output_buffer;
|
||||
|
||||
static int
|
||||
mac_open (scb, name)
|
||||
serial_t scb;
|
||||
const char *name;
|
||||
{
|
||||
OSErr err;
|
||||
|
||||
/* Alloc buffer space first - that way any allocation failures are
|
||||
intercepted before the serial driver gets involved. */
|
||||
if (mac_input_buffer == NULL)
|
||||
mac_input_buffer = (char *) xmalloc (4096);
|
||||
/* Match on a name and open a port. */
|
||||
if (strcmp (name, "modem") == 0)
|
||||
{
|
||||
err = OpenDriver ("\p.AIn", &input_refnum);
|
||||
if (err != 0)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
err = OpenDriver ("\p.AOut", &output_refnum);
|
||||
if (err != 0)
|
||||
{
|
||||
CloseDriver (input_refnum);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
else if (strcmp (name, "printer") == 0)
|
||||
{
|
||||
err = OpenDriver ("\p.BIn", &input_refnum);
|
||||
if (err != 0)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
err = OpenDriver ("\p.BOut", &output_refnum);
|
||||
if (err != 0)
|
||||
{
|
||||
CloseDriver (input_refnum);
|
||||
return (-1);
|
||||
}
|
||||
/* fake */
|
||||
scb->fd = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
error ("You must specify a valid serial port name; your choices are `modem' or `printer'.");
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
/* We got something open. */
|
||||
if (1 /* using custom buffer */)
|
||||
SerSetBuf (input_refnum, mac_input_buffer, 4096);
|
||||
/* Set to a GDB-preferred state. */
|
||||
SerReset (input_refnum, stop10|noParity|data8|baud9600);
|
||||
SerReset (output_refnum, stop10|noParity|data8|baud9600);
|
||||
{
|
||||
CntrlParam cb;
|
||||
struct SerShk *handshake;
|
||||
|
||||
cb.ioCRefNum = output_refnum;
|
||||
cb.csCode = 14;
|
||||
handshake = (struct SerShk *) &cb.csParam[0];
|
||||
handshake->fXOn = 0;
|
||||
handshake->fCTS = 0;
|
||||
handshake->xOn = 0;
|
||||
handshake->xOff = 0;
|
||||
handshake->errs = 0;
|
||||
handshake->evts = 0;
|
||||
handshake->fInX = 0;
|
||||
handshake->fDTR = 0;
|
||||
err = PBControl ((ParmBlkPtr) &cb, 0);
|
||||
if (err < 0)
|
||||
return (-1);
|
||||
}
|
||||
/* fake */
|
||||
scb->fd = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mac_noop (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mac_raw (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
/* Always effectively in raw mode. */
|
||||
}
|
||||
|
||||
/* Read a character with user-specified timeout. TIMEOUT is number of seconds
|
||||
to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
|
||||
char if successful. Returns -2 if timeout expired, EOF if line dropped
|
||||
dead, or -3 for any other error (see errno in that case). */
|
||||
|
||||
static int
|
||||
mac_readchar (scb, timeout)
|
||||
serial_t scb;
|
||||
int timeout;
|
||||
{
|
||||
int status, n;
|
||||
/* time_t */ unsigned long start_time, now;
|
||||
OSErr err;
|
||||
CntrlParam cb;
|
||||
IOParam pb;
|
||||
|
||||
if (scb->bufcnt-- > 0)
|
||||
return *scb->bufp++;
|
||||
|
||||
time (&start_time);
|
||||
|
||||
while (1)
|
||||
{
|
||||
cb.ioCRefNum = input_refnum;
|
||||
cb.csCode = 2;
|
||||
err = PBStatus ((ParmBlkPtr) &cb, 0);
|
||||
if (err < 0)
|
||||
return SERIAL_ERROR;
|
||||
n = *((long *) &cb.csParam[0]);
|
||||
if (n > 0)
|
||||
{
|
||||
pb.ioRefNum = input_refnum;
|
||||
pb.ioBuffer = (Ptr) (scb->buf);
|
||||
pb.ioReqCount = (n > 64 ? 64 : n);
|
||||
err = PBRead ((ParmBlkPtr) &pb, 0);
|
||||
if (err < 0)
|
||||
return SERIAL_ERROR;
|
||||
scb->bufcnt = pb.ioReqCount;
|
||||
scb->bufcnt--;
|
||||
scb->bufp = scb->buf;
|
||||
return *scb->bufp++;
|
||||
}
|
||||
else if (timeout == 0)
|
||||
return SERIAL_TIMEOUT;
|
||||
else if (timeout == -1)
|
||||
;
|
||||
else
|
||||
{
|
||||
time (&now);
|
||||
if (now > start_time + timeout)
|
||||
return SERIAL_TIMEOUT;
|
||||
}
|
||||
PROGRESS (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* mac_{get set}_tty_state() are both dummys to fill out the function
|
||||
vector. Someday, they may do something real... */
|
||||
|
||||
static serial_ttystate
|
||||
mac_get_tty_state (scb)
|
||||
serial_t scb;
|
||||
{
|
||||
struct mac_ttystate *state;
|
||||
|
||||
state = (struct mac_ttystate *) xmalloc (sizeof *state);
|
||||
|
||||
return (serial_ttystate) state;
|
||||
}
|
||||
|
||||
static int
|
||||
mac_set_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mac_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate new_ttystate;
|
||||
serial_ttystate old_ttystate;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mac_print_tty_state (scb, ttystate)
|
||||
serial_t scb;
|
||||
serial_ttystate ttystate;
|
||||
{
|
||||
/* Nothing to print. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is a tricky formula to relate real baud rates
|
||||
to what the serial driver wants, we should use it. Until
|
||||
we get one, this table will have to do. */
|
||||
|
||||
static struct {
|
||||
int real_rate;
|
||||
int bits;
|
||||
} mac_baud_rate_table[] = {
|
||||
{ 57600, baud57600 },
|
||||
{ 38400, 1 },
|
||||
{ 19200, baud19200 },
|
||||
{ 9600, baud9600 },
|
||||
{ 7200, baud7200 },
|
||||
{ 4800, baud4800 },
|
||||
{ 3600, baud3600 },
|
||||
{ 2400, baud2400 },
|
||||
{ 1800, baud1800 },
|
||||
{ 1200, baud1200 },
|
||||
{ 600, baud600 },
|
||||
{ 300, baud300 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static int
|
||||
mac_set_baud_rate (scb, rate)
|
||||
serial_t scb;
|
||||
int rate;
|
||||
{
|
||||
int i, bits;
|
||||
|
||||
for (i = 0; mac_baud_rate_table[i].real_rate != 0; ++i)
|
||||
{
|
||||
if (mac_baud_rate_table[i].real_rate == rate)
|
||||
{
|
||||
bits = mac_baud_rate_table[i].bits;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SerReset (input_refnum, stop10|noParity|data8|bits);
|
||||
SerReset (output_refnum, stop10|noParity|data8|bits);
|
||||
}
|
||||
|
||||
static int
|
||||
mac_set_stop_bits (scb, num)
|
||||
serial_t scb;
|
||||
int num;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int first_mac_write = 0;
|
||||
|
||||
static int
|
||||
mac_write (scb, str, len)
|
||||
serial_t scb;
|
||||
const char *str;
|
||||
int len;
|
||||
{
|
||||
OSErr err;
|
||||
IOParam pb;
|
||||
|
||||
if (first_mac_write++ < 4)
|
||||
{
|
||||
sleep (1);
|
||||
}
|
||||
pb.ioRefNum = output_refnum;
|
||||
pb.ioBuffer = (Ptr) str;
|
||||
pb.ioReqCount = len;
|
||||
err = PBWrite ((ParmBlkPtr) &pb, 0);
|
||||
if (err < 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mac_close (serial_t scb)
|
||||
{
|
||||
if (input_refnum)
|
||||
{
|
||||
if (1 /* custom buffer */)
|
||||
SerSetBuf (input_refnum, mac_input_buffer, 0);
|
||||
CloseDriver (input_refnum);
|
||||
input_refnum = 0;
|
||||
}
|
||||
if (output_refnum)
|
||||
{
|
||||
if (0 /* custom buffer */)
|
||||
SetSetBuf (input_refnum, mac_output_buffer, 0);
|
||||
CloseDriver (output_refnum);
|
||||
output_refnum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct serial_ops mac_ops =
|
||||
{
|
||||
"hardwire",
|
||||
0,
|
||||
mac_open,
|
||||
mac_close,
|
||||
mac_readchar,
|
||||
mac_write,
|
||||
mac_noop, /* flush output */
|
||||
mac_noop, /* flush input */
|
||||
mac_noop, /* send break -- currently only for nindy */
|
||||
mac_raw,
|
||||
mac_get_tty_state,
|
||||
mac_set_tty_state,
|
||||
mac_print_tty_state,
|
||||
mac_noflush_set_tty_state,
|
||||
mac_set_baud_rate,
|
||||
mac_set_stop_bits,
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_ser_mac ()
|
||||
{
|
||||
serial_add_interface (&mac_ops);
|
||||
}
|
|
@ -1,470 +0,0 @@
|
|||
/* Read HP PA/Risc object files for GDB.
|
||||
Copyright 1991, 1992, 1996 Free Software Foundation, Inc.
|
||||
Written by Fred Fish at Cygnus Support.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "bfd.h"
|
||||
#include "som.h"
|
||||
#include "libhppa.h"
|
||||
#include <syms.h>
|
||||
#include "symtab.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "buildsym.h"
|
||||
#include "stabsread.h"
|
||||
#include "gdb-stabs.h"
|
||||
#include "complaints.h"
|
||||
#include "gdb_string.h"
|
||||
#include "demangle.h"
|
||||
#include <sys/file.h>
|
||||
|
||||
/* Various things we might complain about... */
|
||||
|
||||
static void
|
||||
som_symfile_init PARAMS ((struct objfile *));
|
||||
|
||||
static void
|
||||
som_new_init PARAMS ((struct objfile *));
|
||||
|
||||
static void
|
||||
som_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
|
||||
|
||||
static void
|
||||
som_symfile_finish PARAMS ((struct objfile *));
|
||||
|
||||
static void
|
||||
som_symtab_read PARAMS ((bfd *, struct objfile *,
|
||||
struct section_offsets *));
|
||||
|
||||
static struct section_offsets *
|
||||
som_symfile_offsets PARAMS ((struct objfile *, CORE_ADDR));
|
||||
|
||||
static void
|
||||
record_minimal_symbol PARAMS ((char *, CORE_ADDR,
|
||||
enum minimal_symbol_type,
|
||||
struct objfile *));
|
||||
|
||||
static void
|
||||
record_minimal_symbol (name, address, ms_type, objfile)
|
||||
char *name;
|
||||
CORE_ADDR address;
|
||||
enum minimal_symbol_type ms_type;
|
||||
struct objfile *objfile;
|
||||
{
|
||||
name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
|
||||
prim_record_minimal_symbol (name, address, ms_type, objfile);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
som_symtab_read -- read the symbol table of a SOM file
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
void som_symtab_read (bfd *abfd, struct objfile *objfile,
|
||||
struct section_offsets *section_offsets)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Given an open bfd, a base address to relocate symbols to, and a
|
||||
flag that specifies whether or not this bfd is for an executable
|
||||
or not (may be shared library for example), add all the global
|
||||
function and data symbols to the minimal symbol table.
|
||||
*/
|
||||
|
||||
static void
|
||||
som_symtab_read (abfd, objfile, section_offsets)
|
||||
bfd *abfd;
|
||||
struct objfile *objfile;
|
||||
struct section_offsets *section_offsets;
|
||||
{
|
||||
unsigned int number_of_symbols;
|
||||
int val, dynamic;
|
||||
char *stringtab;
|
||||
asection *shlib_info;
|
||||
struct symbol_dictionary_record *buf, *bufp, *endbufp;
|
||||
char *symname;
|
||||
CONST int symsize = sizeof (struct symbol_dictionary_record);
|
||||
CORE_ADDR text_offset, data_offset;
|
||||
|
||||
|
||||
text_offset = ANOFFSET (section_offsets, 0);
|
||||
data_offset = ANOFFSET (section_offsets, 1);
|
||||
|
||||
number_of_symbols = bfd_get_symcount (abfd);
|
||||
|
||||
buf = alloca (symsize * number_of_symbols);
|
||||
bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
|
||||
val = bfd_read (buf, symsize * number_of_symbols, 1, abfd);
|
||||
if (val != symsize * number_of_symbols)
|
||||
error ("Couldn't read symbol dictionary!");
|
||||
|
||||
stringtab = alloca (obj_som_stringtab_size (abfd));
|
||||
bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
|
||||
val = bfd_read (stringtab, obj_som_stringtab_size (abfd), 1, abfd);
|
||||
if (val != obj_som_stringtab_size (abfd))
|
||||
error ("Can't read in HP string table.");
|
||||
|
||||
/* We need to determine if objfile is a dynamic executable (so we
|
||||
can do the right thing for ST_ENTRY vs ST_CODE symbols).
|
||||
|
||||
There's nothing in the header which easily allows us to do
|
||||
this. The only reliable way I know of is to check for the
|
||||
existance of a $SHLIB_INFO$ section with a non-zero size. */
|
||||
shlib_info = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$");
|
||||
if (shlib_info)
|
||||
dynamic = (bfd_section_size (objfile->obfd, shlib_info) != 0);
|
||||
else
|
||||
dynamic = 0;
|
||||
|
||||
endbufp = buf + number_of_symbols;
|
||||
for (bufp = buf; bufp < endbufp; ++bufp)
|
||||
{
|
||||
enum minimal_symbol_type ms_type;
|
||||
|
||||
QUIT;
|
||||
|
||||
switch (bufp->symbol_scope)
|
||||
{
|
||||
case SS_UNIVERSAL:
|
||||
case SS_EXTERNAL:
|
||||
switch (bufp->symbol_type)
|
||||
{
|
||||
case ST_SYM_EXT:
|
||||
case ST_ARG_EXT:
|
||||
continue;
|
||||
|
||||
case ST_CODE:
|
||||
case ST_PRI_PROG:
|
||||
case ST_SEC_PROG:
|
||||
case ST_MILLICODE:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
ms_type = mst_text;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ST_ENTRY:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
/* For a dynamic executable, ST_ENTRY symbols are
|
||||
the stubs, while the ST_CODE symbol is the real
|
||||
function. */
|
||||
if (dynamic)
|
||||
ms_type = mst_solib_trampoline;
|
||||
else
|
||||
ms_type = mst_text;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ST_STUB:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
ms_type = mst_solib_trampoline;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ST_DATA:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
bufp->symbol_value += data_offset;
|
||||
ms_type = mst_data;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
/* SS_GLOBAL and SS_LOCAL are two names for the same thing (!). */
|
||||
case SS_GLOBAL:
|
||||
#endif
|
||||
case SS_LOCAL:
|
||||
switch (bufp->symbol_type)
|
||||
{
|
||||
case ST_SYM_EXT:
|
||||
case ST_ARG_EXT:
|
||||
continue;
|
||||
|
||||
case ST_CODE:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
ms_type = mst_file_text;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
|
||||
check_strange_names:
|
||||
/* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
|
||||
label prefixes for stabs, constant data, etc. So we need
|
||||
only filter out L$ symbols which are left in due to
|
||||
limitations in how GAS generates SOM relocations.
|
||||
|
||||
When linking in the HPUX C-library the HP linker has
|
||||
the nasty habit of placing section symbols from the literal
|
||||
subspaces in the middle of the program's text. Filter
|
||||
those out as best we can. Check for first and last character
|
||||
being '$'.
|
||||
|
||||
And finally, the newer HP compilers emit crud like $PIC_foo$N
|
||||
in some circumstance (PIC code I guess). It's also claimed
|
||||
that they emit D$ symbols too. What stupidity. */
|
||||
if ((symname[0] == 'L' && symname[1] == '$')
|
||||
|| (symname[0] == '$' && symname[strlen(symname) - 1] == '$')
|
||||
|| (symname[0] == 'D' && symname[1] == '$')
|
||||
|| (strncmp (symname, "$PIC", 4) == 0))
|
||||
continue;
|
||||
break;
|
||||
|
||||
case ST_PRI_PROG:
|
||||
case ST_SEC_PROG:
|
||||
case ST_MILLICODE:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
ms_type = mst_file_text;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ST_ENTRY:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
/* For a dynamic executable, ST_ENTRY symbols are
|
||||
the stubs, while the ST_CODE symbol is the real
|
||||
function. */
|
||||
if (dynamic)
|
||||
ms_type = mst_solib_trampoline;
|
||||
else
|
||||
ms_type = mst_file_text;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case ST_STUB:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
ms_type = mst_solib_trampoline;
|
||||
bufp->symbol_value += text_offset;
|
||||
#ifdef SMASH_TEXT_ADDRESS
|
||||
SMASH_TEXT_ADDRESS (bufp->symbol_value);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case ST_DATA:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
bufp->symbol_value += data_offset;
|
||||
ms_type = mst_file_data;
|
||||
goto check_strange_names;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
/* This can happen for common symbols when -E is passed to the
|
||||
final link. No idea _why_ that would make the linker force
|
||||
common symbols to have an SS_UNSAT scope, but it does. */
|
||||
case SS_UNSAT:
|
||||
switch (bufp->symbol_type)
|
||||
{
|
||||
case ST_STORAGE:
|
||||
symname = bufp->name.n_strx + stringtab;
|
||||
bufp->symbol_value += data_offset;
|
||||
ms_type = mst_data;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bufp->name.n_strx > obj_som_stringtab_size (abfd))
|
||||
error ("Invalid symbol data; bad HP string table offset: %d",
|
||||
bufp->name.n_strx);
|
||||
|
||||
record_minimal_symbol (symname,
|
||||
bufp->symbol_value, ms_type,
|
||||
objfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan and build partial symbols for a symbol file.
|
||||
We have been initialized by a call to som_symfile_init, which
|
||||
currently does nothing.
|
||||
|
||||
SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
|
||||
in each section. This is ignored, as it isn't needed for SOM.
|
||||
|
||||
MAINLINE is true if we are reading the main symbol
|
||||
table (as opposed to a shared lib or dynamically loaded file).
|
||||
|
||||
This function only does the minimum work necessary for letting the
|
||||
user "name" things symbolically; it does not read the entire symtab.
|
||||
Instead, it reads the external and static symbols and puts them in partial
|
||||
symbol tables. When more extensive information is requested of a
|
||||
file, the corresponding partial symbol table is mutated into a full
|
||||
fledged symbol table by going back and reading the symbols
|
||||
for real.
|
||||
|
||||
We look for sections with specific names, to tell us what debug
|
||||
format to look for: FIXME!!!
|
||||
|
||||
somstab_build_psymtabs() handles STABS symbols.
|
||||
|
||||
Note that SOM files have a "minimal" symbol table, which is vaguely
|
||||
reminiscent of a COFF symbol table, but has only the minimal information
|
||||
necessary for linking. We process this also, and use the information to
|
||||
build gdb's minimal symbol table. This gives us some minimal debugging
|
||||
capability even for files compiled without -g. */
|
||||
|
||||
static void
|
||||
som_symfile_read (objfile, section_offsets, mainline)
|
||||
struct objfile *objfile;
|
||||
struct section_offsets *section_offsets;
|
||||
int mainline;
|
||||
{
|
||||
bfd *abfd = objfile->obfd;
|
||||
struct cleanup *back_to;
|
||||
|
||||
init_minimal_symbol_collection ();
|
||||
back_to = make_cleanup (discard_minimal_symbols, 0);
|
||||
|
||||
/* Process the normal SOM symbol table first. */
|
||||
|
||||
som_symtab_read (abfd, objfile, section_offsets);
|
||||
|
||||
/* Now read information from the stabs debug sections. */
|
||||
stabsect_build_psymtabs (objfile, section_offsets, mainline,
|
||||
"$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$");
|
||||
|
||||
/* Now read the native debug information. */
|
||||
hpread_build_psymtabs (objfile, section_offsets, mainline);
|
||||
|
||||
/* Install any minimal symbols that have been collected as the current
|
||||
minimal symbols for this objfile. */
|
||||
install_minimal_symbols (objfile);
|
||||
|
||||
/* Force hppa-tdep.c to re-read the unwind descriptors. */
|
||||
objfile->obj_private = NULL;
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
/* Initialize anything that needs initializing when a completely new symbol
|
||||
file is specified (not just adding some symbols from another file, e.g. a
|
||||
shared library).
|
||||
|
||||
We reinitialize buildsym, since we may be reading stabs from a SOM file. */
|
||||
|
||||
static void
|
||||
som_new_init (ignore)
|
||||
struct objfile *ignore;
|
||||
{
|
||||
stabsread_new_init ();
|
||||
buildsym_new_init ();
|
||||
}
|
||||
|
||||
/* Perform any local cleanups required when we are done with a particular
|
||||
objfile. I.E, we are in the process of discarding all symbol information
|
||||
for an objfile, freeing up all memory held for it, and unlinking the
|
||||
objfile struct from the global list of known objfiles. */
|
||||
|
||||
static void
|
||||
som_symfile_finish (objfile)
|
||||
struct objfile *objfile;
|
||||
{
|
||||
if (objfile -> sym_stab_info != NULL)
|
||||
{
|
||||
mfree (objfile -> md, objfile -> sym_stab_info);
|
||||
}
|
||||
hpread_symfile_finish (objfile);
|
||||
}
|
||||
|
||||
/* SOM specific initialization routine for reading symbols. */
|
||||
|
||||
static void
|
||||
som_symfile_init (objfile)
|
||||
struct objfile *objfile;
|
||||
{
|
||||
/* SOM objects may be reordered, so set OBJF_REORDERED. If we
|
||||
find this causes a significant slowdown in gdb then we could
|
||||
set it in the debug symbol readers only when necessary. */
|
||||
objfile->flags |= OBJF_REORDERED;
|
||||
hpread_symfile_init (objfile);
|
||||
}
|
||||
|
||||
/* SOM specific parsing routine for section offsets.
|
||||
|
||||
Plain and simple for now. */
|
||||
|
||||
static struct section_offsets *
|
||||
som_symfile_offsets (objfile, addr)
|
||||
struct objfile *objfile;
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
struct section_offsets *section_offsets;
|
||||
int i;
|
||||
|
||||
objfile->num_sections = SECT_OFF_MAX;
|
||||
section_offsets = (struct section_offsets *)
|
||||
obstack_alloc (&objfile -> psymbol_obstack,
|
||||
sizeof (struct section_offsets)
|
||||
+ sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
|
||||
|
||||
/* First see if we're a shared library. If so, get the section
|
||||
offsets from the library, else get them from addr. */
|
||||
if (!som_solib_section_offsets (objfile, section_offsets))
|
||||
{
|
||||
for (i = 0; i < SECT_OFF_MAX; i++)
|
||||
ANOFFSET (section_offsets, i) = addr;
|
||||
}
|
||||
|
||||
return section_offsets;
|
||||
}
|
||||
|
||||
/* Register that we are able to handle SOM object file formats. */
|
||||
|
||||
static struct sym_fns som_sym_fns =
|
||||
{
|
||||
bfd_target_som_flavour,
|
||||
som_new_init, /* sym_new_init: init anything gbl to entire symtab */
|
||||
som_symfile_init, /* sym_init: read initial info, setup for sym_read() */
|
||||
som_symfile_read, /* sym_read: read a symbol file into symtab */
|
||||
som_symfile_finish, /* sym_finish: finished with file, cleanup */
|
||||
som_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
|
||||
NULL /* next: pointer to next struct sym_fns */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_somread ()
|
||||
{
|
||||
add_symtab_fns (&som_sym_fns);
|
||||
}
|
|
@ -1,820 +0,0 @@
|
|||
/* Handle HP SOM shared libraries for GDB, the GNU Debugger.
|
||||
Copyright 1993, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Written by the Center for Software Science at the Univerity of Utah
|
||||
and by Cygnus Support. */
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "frame.h"
|
||||
#include "bfd.h"
|
||||
#include "som.h"
|
||||
#include "libhppa.h"
|
||||
#include "gdbcore.h"
|
||||
#include "symtab.h"
|
||||
#include "breakpoint.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
#include "inferior.h"
|
||||
#include "gdb-stabs.h"
|
||||
#include "gdbcmd.h"
|
||||
|
||||
/* TODO:
|
||||
|
||||
* Most of this code should work for hp300 shared libraries. Does
|
||||
anyone care enough to weed out any SOM-isms.
|
||||
|
||||
* Support for hpux8 dynamic linker. */
|
||||
|
||||
/* The basic structure which describes a dynamically loaded object. This
|
||||
data structure is private to the dynamic linker and isn't found in
|
||||
any HPUX include file. */
|
||||
|
||||
struct som_solib_mapped_entry
|
||||
{
|
||||
/* The name of the library. */
|
||||
char *name;
|
||||
|
||||
/* Version of this structure (it is expected to change again in hpux10). */
|
||||
unsigned char struct_version;
|
||||
|
||||
/* Binding mode for this library. */
|
||||
unsigned char bind_mode;
|
||||
|
||||
/* Version of this library. */
|
||||
short library_version;
|
||||
|
||||
/* Start of text address, link-time text location, end of text address. */
|
||||
CORE_ADDR text_addr;
|
||||
CORE_ADDR text_link_addr;
|
||||
CORE_ADDR text_end;
|
||||
|
||||
/* Start of data, start of bss and end of data. */
|
||||
CORE_ADDR data_start;
|
||||
CORE_ADDR bss_start;
|
||||
CORE_ADDR data_end;
|
||||
|
||||
/* Value of linkage pointer (%r19). */
|
||||
CORE_ADDR got_value;
|
||||
|
||||
/* Next entry. */
|
||||
struct som_solib_mapped_entry *next;
|
||||
|
||||
/* There are other fields, but I don't have information as to what is
|
||||
contained in them. */
|
||||
};
|
||||
|
||||
/* A structure to keep track of all the known shared objects. */
|
||||
struct so_list
|
||||
{
|
||||
struct som_solib_mapped_entry som_solib;
|
||||
struct objfile *objfile;
|
||||
bfd *abfd;
|
||||
struct section_table *sections;
|
||||
struct section_table *sections_end;
|
||||
struct so_list *next;
|
||||
};
|
||||
|
||||
static struct so_list *so_list_head;
|
||||
|
||||
static void som_sharedlibrary_info_command PARAMS ((char *, int));
|
||||
|
||||
/* Add symbols from shared libraries into the symtab list. */
|
||||
|
||||
void
|
||||
som_solib_add (arg_string, from_tty, target)
|
||||
char *arg_string;
|
||||
int from_tty;
|
||||
struct target_ops *target;
|
||||
{
|
||||
struct minimal_symbol *msymbol;
|
||||
struct so_list *so_list_tail;
|
||||
CORE_ADDR addr;
|
||||
asection *shlib_info;
|
||||
int status;
|
||||
unsigned int dld_flags;
|
||||
char buf[4], *re_err;
|
||||
|
||||
/* First validate our arguments. */
|
||||
if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
|
||||
{
|
||||
error ("Invalid regexp: %s", re_err);
|
||||
}
|
||||
|
||||
/* If we're debugging a core file, or have attached to a running
|
||||
process, then som_solib_create_inferior_hook will not have been
|
||||
called.
|
||||
|
||||
We need to first determine if we're dealing with a dynamically
|
||||
linked executable. If not, then return without an error or warning.
|
||||
|
||||
We also need to examine __dld_flags to determine if the shared library
|
||||
list is valid and to determine if the libraries have been privately
|
||||
mapped. */
|
||||
if (symfile_objfile == NULL)
|
||||
return;
|
||||
|
||||
/* First see if the objfile was dynamically linked. */
|
||||
shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
|
||||
if (!shlib_info)
|
||||
return;
|
||||
|
||||
/* It's got a $SHLIB_INFO$ section, make sure it's not empty. */
|
||||
if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
|
||||
return;
|
||||
|
||||
msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
error ("Unable to find __dld_flags symbol in object file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
/* Read the current contents. */
|
||||
status = target_read_memory (addr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
error ("Unable to read __dld_flags\n");
|
||||
return;
|
||||
}
|
||||
dld_flags = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* __dld_list may not be valid. If it's not valid tell the user. */
|
||||
if ((dld_flags & 4) == 0)
|
||||
{
|
||||
error ("__dld_list is not valid according to __dld_flags.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the libraries were not mapped private, warn the user. */
|
||||
if ((dld_flags & 1) == 0)
|
||||
warning ("The shared libraries were not privately mapped; setting a\nbreakpoint in a shared library will not work until you rerun the program.\n");
|
||||
|
||||
msymbol = lookup_minimal_symbol ("__dld_list", NULL, NULL);
|
||||
if (!msymbol)
|
||||
{
|
||||
/* Older crt0.o files (hpux8) don't have __dld_list as a symbol,
|
||||
but the data is still available if you know where to look. */
|
||||
msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
|
||||
if (!msymbol)
|
||||
{
|
||||
error ("Unable to find dynamic library list.\n");
|
||||
return;
|
||||
}
|
||||
addr = SYMBOL_VALUE_ADDRESS (msymbol) - 8;
|
||||
}
|
||||
else
|
||||
addr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
|
||||
status = target_read_memory (addr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
error ("Unable to find dynamic library list.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* If addr is zero, then we're using an old dynamic loader which
|
||||
doesn't maintain __dld_list. We'll have to use a completely
|
||||
different approach to get shared library information. */
|
||||
if (addr == 0)
|
||||
goto old_dld;
|
||||
|
||||
/* Using the information in __dld_list is the preferred method
|
||||
to get at shared library information. It doesn't depend on
|
||||
any functions in /usr/lib/end.o and has a chance of working
|
||||
with hpux10 when it is released. */
|
||||
status = target_read_memory (addr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
error ("Unable to find dynamic library list.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* addr now holds the address of the first entry in the dynamic
|
||||
library list. */
|
||||
addr = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* Now that we have a pointer to the dynamic library list, walk
|
||||
through it and add the symbols for each library. */
|
||||
|
||||
so_list_tail = so_list_head;
|
||||
/* Find the end of the list of shared objects. */
|
||||
while (so_list_tail && so_list_tail->next)
|
||||
so_list_tail = so_list_tail->next;
|
||||
|
||||
while (1)
|
||||
{
|
||||
CORE_ADDR name_addr, text_addr;
|
||||
unsigned int name_len;
|
||||
char *name;
|
||||
struct so_list *new_so;
|
||||
struct so_list *so_list = so_list_head;
|
||||
struct section_table *p;
|
||||
struct stat statbuf;
|
||||
|
||||
if (addr == 0)
|
||||
break;
|
||||
|
||||
/* Get a pointer to the name of this library. */
|
||||
status = target_read_memory (addr, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
name_addr = extract_unsigned_integer (buf, 4);
|
||||
name_len = 0;
|
||||
while (1)
|
||||
{
|
||||
target_read_memory (name_addr + name_len, buf, 1);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
name_len++;
|
||||
if (*buf == '\0')
|
||||
break;
|
||||
}
|
||||
name = alloca (name_len);
|
||||
status = target_read_memory (name_addr, name, name_len);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
/* See if we've already loaded something with this name. */
|
||||
while (so_list)
|
||||
{
|
||||
if (!strcmp (so_list->som_solib.name, name))
|
||||
break;
|
||||
so_list = so_list->next;
|
||||
}
|
||||
|
||||
/* See if the file exists. If not, give a warning, but don't
|
||||
die. */
|
||||
status = stat (name, &statbuf);
|
||||
if (status == -1)
|
||||
{
|
||||
warning ("Can't find file %s referenced in dld_list.", name);
|
||||
|
||||
status = target_read_memory (addr + 36, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
addr = (CORE_ADDR) extract_unsigned_integer (buf, 4);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we've already loaded this one or it's the main program, skip it. */
|
||||
if (so_list || !strcmp (name, symfile_objfile->name))
|
||||
{
|
||||
status = target_read_memory (addr + 36, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
addr = (CORE_ADDR) extract_unsigned_integer (buf, 4);
|
||||
continue;
|
||||
}
|
||||
|
||||
name = obsavestring (name, name_len - 1,
|
||||
&symfile_objfile->symbol_obstack);
|
||||
|
||||
status = target_read_memory (addr + 8, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
text_addr = extract_unsigned_integer (buf, 4);
|
||||
|
||||
|
||||
new_so = (struct so_list *) xmalloc (sizeof (struct so_list));
|
||||
memset ((char *)new_so, 0, sizeof (struct so_list));
|
||||
if (so_list_head == NULL)
|
||||
{
|
||||
so_list_head = new_so;
|
||||
so_list_tail = new_so;
|
||||
}
|
||||
else
|
||||
{
|
||||
so_list_tail->next = new_so;
|
||||
so_list_tail = new_so;
|
||||
}
|
||||
|
||||
/* Fill in all the entries in GDB's shared library list. */
|
||||
new_so->som_solib.name = name;
|
||||
status = target_read_memory (addr + 4, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.struct_version = extract_unsigned_integer (buf + 3, 1);
|
||||
new_so->som_solib.bind_mode = extract_unsigned_integer (buf + 2, 1);
|
||||
new_so->som_solib.library_version = extract_unsigned_integer (buf, 2);
|
||||
new_so->som_solib.text_addr = text_addr;
|
||||
|
||||
status = target_read_memory (addr + 12, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.text_link_addr = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 16, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.text_end = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 20, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.data_start = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 24, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.bss_start = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 28, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.data_end = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 32, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.got_value = extract_unsigned_integer (buf, 4);
|
||||
|
||||
status = target_read_memory (addr + 36, buf, 4);
|
||||
if (status != 0)
|
||||
goto err;
|
||||
|
||||
new_so->som_solib.next = (void *)extract_unsigned_integer (buf, 4);
|
||||
addr = (CORE_ADDR)new_so->som_solib.next;
|
||||
|
||||
new_so->objfile = symbol_file_add (name, from_tty, text_addr, 0, 0, 0);
|
||||
new_so->abfd = new_so->objfile->obfd;
|
||||
|
||||
if (!bfd_check_format (new_so->abfd, bfd_object))
|
||||
{
|
||||
error ("\"%s\": not in executable format: %s.",
|
||||
name, bfd_errmsg (bfd_get_error ()));
|
||||
}
|
||||
|
||||
/* Now we need to build a section table for this library since
|
||||
we might be debugging a core file from a dynamically linked
|
||||
executable in which the libraries were not privately mapped. */
|
||||
if (build_section_table (new_so->abfd,
|
||||
&new_so->sections,
|
||||
&new_so->sections_end))
|
||||
{
|
||||
error ("Unable to build section table for shared library\n.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Relocate all the sections based on where they got loaded. */
|
||||
for (p = new_so->sections; p < new_so->sections_end; p++)
|
||||
{
|
||||
if (p->the_bfd_section->flags & SEC_CODE)
|
||||
{
|
||||
p->addr += text_addr - new_so->som_solib.text_link_addr;
|
||||
p->endaddr += text_addr - new_so->som_solib.text_link_addr;
|
||||
}
|
||||
else if (p->the_bfd_section->flags & SEC_DATA)
|
||||
{
|
||||
p->addr += new_so->som_solib.data_start;
|
||||
p->endaddr += new_so->som_solib.data_start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now see if we need to map in the text and data for this shared
|
||||
library (for example debugging a core file which does not use
|
||||
private shared libraries.).
|
||||
|
||||
Carefully peek at the first text address in the library. If the
|
||||
read succeeds, then the libraries were privately mapped and were
|
||||
included in the core dump file.
|
||||
|
||||
If the peek failed, then the libraries were not privately mapped
|
||||
and are not in the core file, we'll have to read them in ourselves. */
|
||||
status = target_read_memory (text_addr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
int old, new;
|
||||
int update_coreops;
|
||||
|
||||
/* We must update the to_sections field in the core_ops structure
|
||||
here, otherwise we dereference a potential dangling pointer
|
||||
for each call to target_read/write_memory within this routine. */
|
||||
update_coreops = core_ops.to_sections == target->to_sections;
|
||||
|
||||
new = new_so->sections_end - new_so->sections;
|
||||
/* Add sections from the shared library to the core target. */
|
||||
if (target->to_sections)
|
||||
{
|
||||
old = target->to_sections_end - target->to_sections;
|
||||
target->to_sections = (struct section_table *)
|
||||
xrealloc ((char *)target->to_sections,
|
||||
((sizeof (struct section_table)) * (old + new)));
|
||||
}
|
||||
else
|
||||
{
|
||||
old = 0;
|
||||
target->to_sections = (struct section_table *)
|
||||
xmalloc ((sizeof (struct section_table)) * new);
|
||||
}
|
||||
target->to_sections_end = (target->to_sections + old + new);
|
||||
|
||||
/* Update the to_sections field in the core_ops structure
|
||||
if needed. */
|
||||
if (update_coreops)
|
||||
{
|
||||
core_ops.to_sections = target->to_sections;
|
||||
core_ops.to_sections_end = target->to_sections_end;
|
||||
}
|
||||
|
||||
/* Copy over the old data before it gets clobbered. */
|
||||
memcpy ((char *)(target->to_sections + old),
|
||||
new_so->sections,
|
||||
((sizeof (struct section_table)) * new));
|
||||
}
|
||||
}
|
||||
|
||||
/* Getting new symbols may change our opinion about what is
|
||||
frameless. */
|
||||
reinit_frame_cache ();
|
||||
return;
|
||||
|
||||
old_dld:
|
||||
error ("Debugging dynamic executables loaded via the hpux8 dld.sl is not supported.\n");
|
||||
return;
|
||||
|
||||
err:
|
||||
error ("Error while reading dynamic library list.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* This hook gets called just before the first instruction in the
|
||||
inferior process is executed.
|
||||
|
||||
This is our opportunity to set magic flags in the inferior so
|
||||
that GDB can be notified when a shared library is mapped in and
|
||||
to tell the dynamic linker that a private copy of the library is
|
||||
needed (so GDB can set breakpoints in the library).
|
||||
|
||||
__dld_flags is the location of the magic flags; as of this implementation
|
||||
there are 3 flags of interest:
|
||||
|
||||
bit 0 when set indicates that private copies of the libraries are needed
|
||||
bit 1 when set indicates that the callback hook routine is valid
|
||||
bit 2 when set indicates that the dynamic linker should maintain the
|
||||
__dld_list structure when loading/unloading libraries.
|
||||
|
||||
Note that shared libraries are not mapped in at this time, so we have
|
||||
run the inferior until the libraries are mapped in. Typically this
|
||||
means running until the "_start" is called. */
|
||||
|
||||
void
|
||||
som_solib_create_inferior_hook()
|
||||
{
|
||||
struct minimal_symbol *msymbol;
|
||||
unsigned int dld_flags, status, have_endo;
|
||||
asection *shlib_info;
|
||||
char shadow_contents[BREAKPOINT_MAX], buf[4];
|
||||
struct objfile *objfile;
|
||||
CORE_ADDR anaddr;
|
||||
|
||||
/* First, remove all the solib event breakpoints. Their addresses
|
||||
may have changed since the last time we ran the program. */
|
||||
remove_solib_event_breakpoints ();
|
||||
|
||||
if (symfile_objfile == NULL)
|
||||
return;
|
||||
|
||||
/* First see if the objfile was dynamically linked. */
|
||||
shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
|
||||
if (!shlib_info)
|
||||
return;
|
||||
|
||||
/* It's got a $SHLIB_INFO$ section, make sure it's not empty. */
|
||||
if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
|
||||
return;
|
||||
|
||||
have_endo = 0;
|
||||
/* Slam the pid of the process into __d_pid; failing is only a warning! */
|
||||
msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
warning ("Unable to find __d_pid symbol in object file.");
|
||||
warning ("Suggest linking with /usr/lib/end.o.");
|
||||
warning ("GDB will be unable to track shl_load/shl_unload calls");
|
||||
goto keep_going;
|
||||
}
|
||||
|
||||
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
store_unsigned_integer (buf, 4, inferior_pid);
|
||||
status = target_write_memory (anaddr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
warning ("Unable to write __d_pid");
|
||||
warning ("Suggest linking with /usr/lib/end.o.");
|
||||
warning ("GDB will be unable to track shl_load/shl_unload calls");
|
||||
goto keep_going;
|
||||
}
|
||||
|
||||
/* Get the value of _DLD_HOOK (an export stub) and put it in __dld_hook;
|
||||
This will force the dynamic linker to call __d_trap when significant
|
||||
events occur. */
|
||||
msymbol = lookup_minimal_symbol ("_DLD_HOOK", NULL, symfile_objfile);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
warning ("Unable to find _DLD_HOOK symbol in object file.");
|
||||
warning ("Suggest linking with /usr/lib/end.o.");
|
||||
warning ("GDB will be unable to track shl_load/shl_unload calls");
|
||||
goto keep_going;
|
||||
}
|
||||
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
|
||||
/* Grrr, this might not be an export symbol! We have to find the
|
||||
export stub. */
|
||||
ALL_OBJFILES (objfile)
|
||||
{
|
||||
struct unwind_table_entry *u;
|
||||
extern struct unwind_table_entry *find_unwind_entry PARAMS ((CORE_ADDR pc));
|
||||
|
||||
/* What a crock. */
|
||||
msymbol = lookup_minimal_symbol_solib_trampoline (SYMBOL_NAME (msymbol),
|
||||
NULL, objfile);
|
||||
/* Found a symbol with the right name. */
|
||||
if (msymbol)
|
||||
{
|
||||
struct unwind_table_entry *u;
|
||||
/* It must be a shared library trampoline. */
|
||||
if (SYMBOL_TYPE (msymbol) != mst_solib_trampoline)
|
||||
continue;
|
||||
|
||||
/* It must also be an export stub. */
|
||||
u = find_unwind_entry (SYMBOL_VALUE (msymbol));
|
||||
if (!u || u->stub_type != EXPORT)
|
||||
continue;
|
||||
|
||||
/* OK. Looks like the correct import stub. */
|
||||
anaddr = SYMBOL_VALUE (msymbol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
store_unsigned_integer (buf, 4, anaddr);
|
||||
|
||||
msymbol = lookup_minimal_symbol ("__dld_hook", NULL, symfile_objfile);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
warning ("Unable to find __dld_hook symbol in object file.");
|
||||
warning ("Suggest linking with /usr/lib/end.o.");
|
||||
warning ("GDB will be unable to track shl_load/shl_unload calls");
|
||||
goto keep_going;
|
||||
}
|
||||
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
status = target_write_memory (anaddr, buf, 4);
|
||||
|
||||
/* Now set a shlib_event breakpoint at __d_trap so we can track
|
||||
significant shared library events. */
|
||||
msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
warning ("Unable to find __dld_d_trap symbol in object file.");
|
||||
warning ("Suggest linking with /usr/lib/end.o.");
|
||||
warning ("GDB will be unable to track shl_load/shl_unload calls");
|
||||
goto keep_going;
|
||||
}
|
||||
create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol));
|
||||
|
||||
/* We have all the support usually found in end.o, so we can track
|
||||
shl_load and shl_unload calls. */
|
||||
have_endo = 1;
|
||||
|
||||
keep_going:
|
||||
|
||||
/* Get the address of __dld_flags, if no such symbol exists, then we can
|
||||
not debug the shared code. */
|
||||
msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
error ("Unable to find __dld_flags symbol in object file.\n");
|
||||
goto keep_going;
|
||||
return;
|
||||
}
|
||||
|
||||
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
/* Read the current contents. */
|
||||
status = target_read_memory (anaddr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
error ("Unable to read __dld_flags\n");
|
||||
return;
|
||||
}
|
||||
dld_flags = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* Turn on the flags we care about. */
|
||||
dld_flags |= (0x5 | (have_endo << 1));
|
||||
store_unsigned_integer (buf, 4, dld_flags);
|
||||
status = target_write_memory (anaddr, buf, 4);
|
||||
if (status != 0)
|
||||
{
|
||||
error ("Unable to write __dld_flags\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now find the address of _start and set a breakpoint there.
|
||||
We still need this code for two reasons:
|
||||
|
||||
* Not all sites have /usr/lib/end.o, so it's not always
|
||||
possible to track the dynamic linker's events.
|
||||
|
||||
* At this time no events are triggered for shared libraries
|
||||
loaded at startup time (what a crock). */
|
||||
|
||||
msymbol = lookup_minimal_symbol ("_start", NULL, symfile_objfile);
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
error ("Unable to find _start symbol in object file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
|
||||
/* Make the breakpoint at "_start" a shared library event breakpoint. */
|
||||
create_solib_event_breakpoint (anaddr);
|
||||
|
||||
/* Wipe out all knowledge of old shared libraries since their
|
||||
mapping can change from one exec to another! */
|
||||
while (so_list_head)
|
||||
{
|
||||
struct so_list *temp;
|
||||
|
||||
free_objfile (so_list_head->objfile);
|
||||
temp = so_list_head;
|
||||
free (so_list_head);
|
||||
so_list_head = temp->next;
|
||||
}
|
||||
clear_symtab_users ();
|
||||
}
|
||||
|
||||
/* Return the GOT value for the shared library in which ADDR belongs. If
|
||||
ADDR isn't in any known shared library, return zero. */
|
||||
|
||||
CORE_ADDR
|
||||
som_solib_get_got_by_pc (addr)
|
||||
CORE_ADDR addr;
|
||||
{
|
||||
struct so_list *so_list = so_list_head;
|
||||
CORE_ADDR got_value = 0;
|
||||
|
||||
while (so_list)
|
||||
{
|
||||
if (so_list->som_solib.text_addr <= addr
|
||||
&& so_list->som_solib.text_end > addr)
|
||||
{
|
||||
got_value = so_list->som_solib.got_value;
|
||||
break;
|
||||
}
|
||||
so_list = so_list->next;
|
||||
}
|
||||
return got_value;
|
||||
}
|
||||
|
||||
int
|
||||
som_solib_section_offsets (objfile, offsets)
|
||||
struct objfile *objfile;
|
||||
struct section_offsets *offsets;
|
||||
{
|
||||
struct so_list *so_list = so_list_head;
|
||||
|
||||
while (so_list)
|
||||
{
|
||||
/* Oh what a pain! We need the offsets before so_list->objfile
|
||||
is valid. The BFDs will never match. Make a best guess. */
|
||||
if (strstr (objfile->name, so_list->som_solib.name))
|
||||
{
|
||||
asection *private_section;
|
||||
|
||||
/* The text offset is easy. */
|
||||
ANOFFSET (offsets, SECT_OFF_TEXT)
|
||||
= (so_list->som_solib.text_addr
|
||||
- so_list->som_solib.text_link_addr);
|
||||
ANOFFSET (offsets, SECT_OFF_RODATA)
|
||||
= ANOFFSET (offsets, SECT_OFF_TEXT);
|
||||
|
||||
/* We should look at presumed_dp in the SOM header, but
|
||||
that's not easily available. This should be OK though. */
|
||||
private_section = bfd_get_section_by_name (objfile->obfd,
|
||||
"$PRIVATE$");
|
||||
if (!private_section)
|
||||
{
|
||||
warning ("Unable to find $PRIVATE$ in shared library!");
|
||||
ANOFFSET (offsets, SECT_OFF_DATA) = 0;
|
||||
ANOFFSET (offsets, SECT_OFF_BSS) = 0;
|
||||
return 1;
|
||||
}
|
||||
ANOFFSET (offsets, SECT_OFF_DATA)
|
||||
= (so_list->som_solib.data_start - private_section->vma);
|
||||
ANOFFSET (offsets, SECT_OFF_BSS)
|
||||
= ANOFFSET (offsets, SECT_OFF_DATA);
|
||||
return 1;
|
||||
}
|
||||
so_list = so_list->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dump information about all the currently loaded shared libraries. */
|
||||
|
||||
static void
|
||||
som_sharedlibrary_info_command (ignore, from_tty)
|
||||
char *ignore;
|
||||
int from_tty;
|
||||
{
|
||||
struct so_list *so_list = so_list_head;
|
||||
|
||||
if (exec_bfd == NULL)
|
||||
{
|
||||
printf_unfiltered ("no exec file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (so_list == NULL)
|
||||
{
|
||||
printf_unfiltered ("No shared libraries loaded at this time.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf_unfiltered ("Shared Object Libraries\n");
|
||||
printf_unfiltered (" %-12s%-12s%-12s%-12s%-12s%-12s\n",
|
||||
" flags", " tstart", " tend", " dstart", " dend", " dlt");
|
||||
while (so_list)
|
||||
{
|
||||
unsigned int flags;
|
||||
|
||||
flags = so_list->som_solib.struct_version << 24;
|
||||
flags |= so_list->som_solib.bind_mode << 16;
|
||||
flags |= so_list->som_solib.library_version;
|
||||
printf_unfiltered ("%s\n", so_list->som_solib.name);
|
||||
printf_unfiltered (" %-12s", local_hex_string_custom (flags, "08l"));
|
||||
printf_unfiltered ("%-12s",
|
||||
local_hex_string_custom (so_list->som_solib.text_addr, "08l"));
|
||||
printf_unfiltered ("%-12s",
|
||||
local_hex_string_custom (so_list->som_solib.text_end, "08l"));
|
||||
printf_unfiltered ("%-12s",
|
||||
local_hex_string_custom (so_list->som_solib.data_start, "08l"));
|
||||
printf_unfiltered ("%-12s",
|
||||
local_hex_string_custom (so_list->som_solib.data_end, "08l"));
|
||||
printf_unfiltered ("%-12s\n",
|
||||
local_hex_string_custom (so_list->som_solib.got_value, "08l"));
|
||||
so_list = so_list->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
som_solib_sharedlibrary_command (args, from_tty)
|
||||
char *args;
|
||||
int from_tty;
|
||||
{
|
||||
dont_repeat ();
|
||||
som_solib_add (args, from_tty, (struct target_ops *) 0);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_som_solib ()
|
||||
{
|
||||
add_com ("sharedlibrary", class_files, som_solib_sharedlibrary_command,
|
||||
"Load shared object library symbols for files matching REGEXP.");
|
||||
add_info ("sharedlibrary", som_sharedlibrary_info_command,
|
||||
"Status of loaded shared object libraries.");
|
||||
add_show_from_set
|
||||
(add_set_cmd ("auto-solib-add", class_support, var_zinteger,
|
||||
(char *) &auto_solib_add,
|
||||
"Set autoloading of shared library symbols at startup.\n\
|
||||
If nonzero, symbols from all shared object libraries will be loaded\n\
|
||||
automatically when the inferior begins execution or when the dynamic linker\n\
|
||||
informs gdb that a new library has been loaded. Otherwise, symbols\n\
|
||||
must be loaded manually, using `sharedlibrary'.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/* HP SOM Shared library declarations for GDB, the GNU Debugger.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Written by the Center for Software Science at the Univerity of Utah
|
||||
and by Cygnus Support. */
|
||||
|
||||
#ifdef __STDC__ /* Forward decl's for prototypes */
|
||||
struct target_ops;
|
||||
struct objfile;
|
||||
struct section_offsets;
|
||||
#endif
|
||||
|
||||
/* Called to add symbols from a shared library to gdb's symbol table. */
|
||||
|
||||
#define SOLIB_ADD(filename, from_tty, targ) \
|
||||
som_solib_add (filename, from_tty, targ)
|
||||
|
||||
extern void
|
||||
som_solib_add PARAMS ((char *, int, struct target_ops *));
|
||||
|
||||
extern CORE_ADDR
|
||||
som_solib_get_got_by_pc PARAMS ((CORE_ADDR));
|
||||
|
||||
extern int
|
||||
som_solib_section_offsets PARAMS ((struct objfile *, struct section_offsets *));
|
||||
|
||||
/* Function to be called when the inferior starts up, to discover the names
|
||||
of shared libraries that are dynamically linked, the base addresses to
|
||||
which they are linked, and sufficient information to read in their symbols
|
||||
at a later time. */
|
||||
|
||||
#define SOLIB_CREATE_INFERIOR_HOOK(PID) som_solib_create_inferior_hook()
|
||||
|
||||
extern void
|
||||
som_solib_create_inferior_hook PARAMS((void));
|
|
@ -1,35 +0,0 @@
|
|||
/* S-record download support for GDB, the GNU debugger.
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
void load_srec PARAMS ((serial_t desc, const char *file, int maxrecsize,
|
||||
int flags, int hashmark));
|
||||
|
||||
/* S-record capability flags */
|
||||
|
||||
/* Which record types are supported */
|
||||
#define SREC_2_BYTE_ADDR 0x00000001
|
||||
#define SREC_3_BYTE_ADDR 0x00000002
|
||||
#define SREC_4_BYTE_ADDR 0x00000004
|
||||
#define SREC_TERM_SHIFT 3
|
||||
|
||||
#define SREC_ALL (SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR \
|
||||
| ((SREC_2_BYTE_ADDR | SREC_3_BYTE_ADDR | SREC_4_BYTE_ADDR) \
|
||||
<< SREC_TERM_SHIFT))
|
||||
|
||||
#define SREC_BINARY 0x00000040 /* Supports binary form of S-records */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue