This file has been removed from HEAD when it should (also) have been
removed from the vendor branch.
This commit is contained in:
parent
f0f8ce0889
commit
90184f6712
@ -1,167 +0,0 @@
|
||||
/* Remote debugging interface for ABug Rom monitor for GDB, the GNU debugger.
|
||||
Copyright 1995, 1996, 1998, 1999, 2000, 2001
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Written by Rob Savoye 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"
|
||||
#include "regcache.h"
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
static void abug_open (char *args, int from_tty);
|
||||
|
||||
static void
|
||||
abug_supply_register (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 *abug_regnames[NUM_REGS] =
|
||||
{
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
||||
"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 abug_ops;
|
||||
|
||||
static char *abug_inits[] =
|
||||
{"\r", NULL};
|
||||
|
||||
static struct monitor_ops abug_cmds;
|
||||
|
||||
static void
|
||||
init_abug_cmds (void)
|
||||
{
|
||||
abug_cmds.flags = MO_CLR_BREAK_USES_ADDR;
|
||||
abug_cmds.init = abug_inits; /* Init strings */
|
||||
abug_cmds.cont = "g\r"; /* continue command */
|
||||
abug_cmds.step = "t\r"; /* single step */
|
||||
abug_cmds.stop = NULL; /* interrupt command */
|
||||
abug_cmds.set_break = "br %x\r"; /* set a breakpoint */
|
||||
abug_cmds.clr_break = "nobr %x\r"; /* clear a breakpoint */
|
||||
abug_cmds.clr_all_break = "nobr\r"; /* clear all breakpoints */
|
||||
abug_cmds.fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
|
||||
abug_cmds.setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
|
||||
abug_cmds.setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
|
||||
abug_cmds.setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
|
||||
abug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
|
||||
abug_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
|
||||
abug_cmds.setmem.term = NULL; /* setreg.term */
|
||||
abug_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
|
||||
abug_cmds.getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
|
||||
abug_cmds.getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
|
||||
abug_cmds.getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
|
||||
abug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
|
||||
abug_cmds.getmem.resp_delim = " "; /* getmem.resp_delim */
|
||||
abug_cmds.getmem.term = NULL; /* getmem.term */
|
||||
abug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
|
||||
abug_cmds.setreg.cmd = "rm %s %x\r"; /* setreg.cmd (name, value) */
|
||||
abug_cmds.setreg.resp_delim = "="; /* setreg.resp_delim */
|
||||
abug_cmds.setreg.term = "? "; /* setreg.term */
|
||||
abug_cmds.setreg.term_cmd = ".\r"; /* setreg.term_cmd */
|
||||
abug_cmds.getreg.cmd = "rm %s\r"; /* getreg.cmd (name) */
|
||||
abug_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
|
||||
abug_cmds.getreg.term = "? "; /* getreg.term */
|
||||
abug_cmds.getreg.term_cmd = ".\r"; /* getreg.term_cmd */
|
||||
abug_cmds.dump_registers = "rd\r"; /* dump_registers */
|
||||
abug_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
|
||||
abug_cmds.supply_register = abug_supply_register; /* supply_register */
|
||||
abug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
|
||||
abug_cmds.load = "lo 0\r"; /* download command */
|
||||
abug_cmds.loadresp = "\n"; /* load response */
|
||||
abug_cmds.prompt = "135Bug>"; /* monitor command prompt */
|
||||
abug_cmds.line_term = "\r"; /* end-of-line terminator */
|
||||
abug_cmds.cmd_end = NULL; /* optional command terminator */
|
||||
abug_cmds.target = &abug_ops; /* target operations */
|
||||
abug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
|
||||
abug_cmds.regnames = abug_regnames; /* registers names */
|
||||
abug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
|
||||
};
|
||||
|
||||
static void
|
||||
abug_open (char *args, int from_tty)
|
||||
{
|
||||
monitor_open (args, &abug_cmds, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_abug_rom (void)
|
||||
{
|
||||
init_abug_cmds ();
|
||||
init_monitor_ops (&abug_ops);
|
||||
|
||||
abug_ops.to_shortname = "abug";
|
||||
abug_ops.to_longname = "ABug monitor";
|
||||
abug_ops.to_doc = "Debug via the ABug monitor.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
abug_ops.to_open = abug_open;
|
||||
|
||||
add_target (&abug_ops);
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
/* Define if compiling on Solaris 7. */
|
||||
#undef _MSE_INT_H
|
||||
|
||||
/* Define if your struct reg has r_fs. */
|
||||
#undef HAVE_STRUCT_REG_R_FS
|
||||
|
||||
/* Define if your struct reg has r_gs. */
|
||||
#undef HAVE_STRUCT_REG_R_GS
|
||||
|
||||
/* Define if pstatus_t type is available */
|
||||
#undef HAVE_PSTATUS_T
|
||||
|
||||
/* Define if prrun_t type is available */
|
||||
#undef HAVE_PRRUN_T
|
||||
|
||||
/* Define if fpregset_t type is available. */
|
||||
#undef HAVE_FPREGSET_T
|
||||
|
||||
/* Define if gregset_t type is available. */
|
||||
#undef HAVE_GREGSET_T
|
||||
|
||||
/* Define if <sys/procfs.h> has prgregset_t. */
|
||||
#undef HAVE_PRGREGSET_T
|
||||
|
||||
/* Define if <sys/procfs.h> has prfpregset_t. */
|
||||
#undef HAVE_PRFPREGSET_T
|
||||
|
||||
/* Define if <sys/procfs.h> has lwpid_t. */
|
||||
#undef HAVE_LWPID_T
|
||||
|
||||
/* Define if <sys/procfs.h> has psaddr_t. */
|
||||
#undef HAVE_PSADDR_T
|
||||
|
||||
/* Define if <sys/procfs.h> has prgregset32_t. */
|
||||
#undef HAVE_PRGREGSET32_T
|
||||
|
||||
/* Define if <sys/procfs.h> has prfpregset32_t. */
|
||||
#undef HAVE_PRFPREGSET32_T
|
||||
|
||||
/* Define if <sys/procfs.h> has prsysent_t */
|
||||
#undef HAVE_PRSYSENT_T
|
||||
|
||||
/* Define if <sys/procfs.h> has pr_sigset_t */
|
||||
#undef HAVE_PR_SIGSET_T
|
||||
|
||||
/* Define if <sys/procfs.h> has pr_sigaction64_t */
|
||||
#undef HAVE_PR_SIGACTION64_T
|
||||
|
||||
/* Define if <sys/procfs.h> has pr_siginfo64_t */
|
||||
#undef HAVE_PR_SIGINFO64_T
|
||||
|
||||
/* Define if <link.h> exists and defines struct link_map which has
|
||||
members with an ``l_'' prefix. (For Solaris, SVR4, and
|
||||
SVR4-like systems.) */
|
||||
#undef HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS
|
||||
|
||||
/* Define if <link.h> exists and defines struct link_map which has
|
||||
members with an ``lm_'' prefix. (For SunOS.) */
|
||||
#undef HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS
|
||||
|
||||
/* Define if <link.h> exists and defines a struct so_map which has
|
||||
members with an ``som_'' prefix. (Found on older *BSD systems.) */
|
||||
#undef HAVE_STRUCT_SO_MAP_WITH_SOM_MEMBERS
|
||||
|
||||
/* Define if <sys/link.h> has struct link_map32 */
|
||||
#undef HAVE_STRUCT_LINK_MAP32
|
||||
|
||||
/* Define if the prfpregset_t type is broken. */
|
||||
#undef PRFPREGSET_T_BROKEN
|
||||
|
||||
/* Define if you want to use new multi-fd /proc interface
|
||||
(replaces HAVE_MULTIPLE_PROC_FDS as well as other macros). */
|
||||
#undef NEW_PROC_API
|
||||
|
||||
/* Define if ioctl argument PIOCSET is available. */
|
||||
#undef HAVE_PROCFS_PIOCSET
|
||||
|
||||
/* Define if the `long long' type works. */
|
||||
#undef CC_HAS_LONG_LONG
|
||||
|
||||
/* Define if the "ll" format works to print long long ints. */
|
||||
#undef PRINTF_HAS_LONG_LONG
|
||||
|
||||
/* Define if the "%Lg" format works to print long doubles. */
|
||||
#undef PRINTF_HAS_LONG_DOUBLE
|
||||
|
||||
/* Define if the "%Lg" format works to scan long doubles. */
|
||||
#undef SCANF_HAS_LONG_DOUBLE
|
||||
|
||||
/* Define if using Solaris thread debugging. */
|
||||
#undef HAVE_THREAD_DB_LIB
|
||||
|
||||
/* Define on a GNU/Linux system to work around problems in sys/procfs.h. */
|
||||
#undef START_INFERIOR_TRAPS_EXPECTED
|
||||
#undef sys_quotactl
|
||||
|
||||
/* Define if you have HPUX threads */
|
||||
#undef HAVE_HPUX_THREAD_SUPPORT
|
||||
|
||||
/* Define if you want to use the memory mapped malloc package (mmalloc). */
|
||||
#undef USE_MMALLOC
|
||||
|
||||
/* Define if the runtime uses a routine from mmalloc before gdb has a chance
|
||||
to initialize mmalloc, and we want to force checking to be used anyway.
|
||||
This may cause spurious memory corruption messages if the runtime tries
|
||||
to explicitly deallocate that memory when gdb calls exit. */
|
||||
#undef MMCHECK_FORCE
|
||||
|
||||
/* Define to 1 if NLS is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
|
||||
#undef HAVE_CATGETS
|
||||
|
||||
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define as 1 if you have the stpcpy function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define if your locale.h file contains LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
|
||||
/* Define if you want to use the full-screen terminal user interface. */
|
||||
#undef TUI
|
||||
|
||||
/* Define if <proc_service.h> on solaris uses int instead of
|
||||
size_t, and assorted other type changes. */
|
||||
#undef PROC_SERVICE_IS_OLD
|
||||
|
||||
/* If you want to specify a default CPU variant, define this to be its
|
||||
name, as a C string. */
|
||||
#undef TARGET_CPU_DEFAULT
|
||||
|
||||
/* Define if the simulator is being linked in. */
|
||||
#undef WITH_SIM
|
||||
|
||||
/* Set to true if the save_state_t structure is present */
|
||||
#undef HAVE_STRUCT_SAVE_STATE_T
|
||||
|
||||
/* Set to true if the save_state_t structure has the ss_wide member */
|
||||
#undef HAVE_STRUCT_MEMBER_SS_WIDE
|
||||
|
||||
/* Define if <sys/ptrace.h> defines the PTRACE_GETREGS request. */
|
||||
#undef HAVE_PTRACE_GETREGS
|
||||
|
||||
/* Define if <sys/ptrace.h> defines the PTRACE_GETFPXREGS request. */
|
||||
#undef HAVE_PTRACE_GETFPXREGS
|
||||
|
||||
/* Define if <sys/ptrace.h> defines the PT_GETDBREGS request. */
|
||||
#undef HAVE_PT_GETDBREGS
|
||||
|
||||
/* Define if <sys/ptrace.h> defines the PT_GETXMMREGS request. */
|
||||
#undef HAVE_PT_GETXMMREGS
|
||||
|
||||
/* Define if gnu-regex.c included with GDB should be used. */
|
||||
#undef USE_INCLUDED_REGEX
|
||||
|
||||
/* BFD's default architecture. */
|
||||
#undef DEFAULT_BFD_ARCH
|
||||
|
||||
/* BFD's default target vector. */
|
||||
#undef DEFAULT_BFD_VEC
|
||||
|
||||
/* Multi-arch enabled. */
|
||||
#undef GDB_MULTI_ARCH
|
||||
|
||||
/* hostfile */
|
||||
#undef GDB_XM_FILE
|
||||
|
||||
/* targetfile */
|
||||
#undef GDB_TM_FILE
|
||||
|
||||
/* nativefile */
|
||||
#undef GDB_NM_FILE
|
@ -1,308 +0,0 @@
|
||||
/* Low level Alpha interface, for GDB when running native.
|
||||
Copyright 1993, 1995, 1996, 1998, 1999, 2000, 2001
|
||||
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 "regcache.h"
|
||||
#include <sys/ptrace.h>
|
||||
#ifdef __linux__
|
||||
#include <asm/reg.h>
|
||||
#include <alpha/ptrace.h>
|
||||
#else
|
||||
#include <alpha/coreregs.h>
|
||||
#endif
|
||||
#include <sys/user.h>
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
static void fetch_osf_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
static void fetch_elf_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
|
||||
/* 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 (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_osf_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR 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. OSF5 uses different names for the register
|
||||
enum list, need to handle two cases. The actual values are the
|
||||
same. */
|
||||
static int core_reg_mapping[NUM_REGS] =
|
||||
{
|
||||
#ifdef NCF_REGS
|
||||
#define EFL NCF_REGS
|
||||
CF_V0, CF_T0, CF_T1, CF_T2, CF_T3, CF_T4, CF_T5, CF_T6,
|
||||
CF_T7, CF_S0, CF_S1, CF_S2, CF_S3, CF_S4, CF_S5, CF_S6,
|
||||
CF_A0, CF_A1, CF_A2, CF_A3, CF_A4, CF_A5, CF_T8, CF_T9,
|
||||
CF_T10, CF_T11, CF_RA, CF_T12, CF_AT, CF_GP, CF_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,
|
||||
CF_PC, -1
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
};
|
||||
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.", REGISTER_NAME (bad_reg));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_elf_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
if (core_reg_size < 32 * 8)
|
||||
{
|
||||
error ("Core file register section too small (%u bytes).", core_reg_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (which == 2)
|
||||
{
|
||||
/* The FPU Registers. */
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)], core_reg_sect, 31 * 8);
|
||||
memset (®isters[REGISTER_BYTE (FP0_REGNUM + 31)], 0, 8);
|
||||
memset (®ister_valid[FP0_REGNUM], 1, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The General Registers. */
|
||||
memcpy (®isters[REGISTER_BYTE (V0_REGNUM)], core_reg_sect, 31 * 8);
|
||||
memcpy (®isters[REGISTER_BYTE (PC_REGNUM)], core_reg_sect + 31 * 8, 8);
|
||||
memset (®isters[REGISTER_BYTE (ZERO_REGNUM)], 0, 8);
|
||||
memset (®ister_valid[V0_REGNUM], 1, 32);
|
||||
register_valid[PC_REGNUM] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
||||
CORE_ADDR
|
||||
register_addr (int regno, CORE_ADDR blockend)
|
||||
{
|
||||
return REGISTER_PTRACE_ADDR (regno);
|
||||
}
|
||||
|
||||
int
|
||||
kernel_u_size (void)
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
#if defined(USE_PROC_FS) || defined(HAVE_GREGSET_T)
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (gdb_gregset_t *gregsetp)
|
||||
{
|
||||
register int regi;
|
||||
register long *regp = ALPHA_REGSET_BASE (gregsetp);
|
||||
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 (gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
int regi;
|
||||
register long *regp = ALPHA_REGSET_BASE (gregsetp);
|
||||
|
||||
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 (gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
register int regi;
|
||||
register long *regp = ALPHA_REGSET_BASE (fpregsetp);
|
||||
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
supply_register (regi + FP0_REGNUM, (char *) (regp + regi));
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
int regi;
|
||||
register long *regp = ALPHA_REGSET_BASE (fpregsetp);
|
||||
|
||||
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_osf_core_fns =
|
||||
{
|
||||
/* This really is bfd_target_unknown_flavour. */
|
||||
|
||||
bfd_target_unknown_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_osf_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
static struct core_fns alpha_elf_core_fns =
|
||||
{
|
||||
bfd_target_elf_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_elf_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_alpha (void)
|
||||
{
|
||||
add_core_fns (&alpha_osf_core_fns);
|
||||
add_core_fns (&alpha_elf_core_fns);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,134 +0,0 @@
|
||||
/* Handle COFF SVR3 shared libraries for GDB, the GNU Debugger.
|
||||
Copyright 1993, 1994, 1998, 1999, 2000 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"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.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, int readsyms)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
coff_solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
|
||||
{
|
||||
asection *libsect;
|
||||
|
||||
if (!readsyms)
|
||||
return;
|
||||
|
||||
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,
|
||||
NULL, /* no offsets */
|
||||
0, /* not mainline */
|
||||
OBJF_SHARED); /* flags */
|
||||
|
||||
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 (void)
|
||||
{
|
||||
coff_solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
/* COFF (SVR3) Shared library declarations for GDB, the GNU Debugger.
|
||||
Copyright 1992, 1993, 1998, 1999, 2000 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. */
|
||||
|
||||
/* Forward decl's for prototypes */
|
||||
struct target_ops;
|
||||
|
||||
/* 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 (void);
|
||||
#endif
|
||||
|
||||
/* Called to add symbols from a shared library to gdb's symbol table. */
|
||||
|
||||
#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
|
||||
coff_solib_add (filename, from_tty, targ, readsyms)
|
||||
|
||||
extern void coff_solib_add (char *, int, struct target_ops *, int);
|
||||
|
||||
/* 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 (void); /* solib.c */
|
||||
|
||||
/* Function to be called to remove the connection between debugger and
|
||||
dynamic linker that was established by SOLIB_CREATE_INFERIOR_HOOK.
|
||||
(This operation does not remove shared library information from
|
||||
the debugger, as CLEAR_SOLIB does.)
|
||||
|
||||
This functionality is presently not implemented for this target.
|
||||
*/
|
||||
#define SOLIB_REMOVE_INFERIOR_HOOK(PID) (0)
|
||||
|
||||
/* This function is called by the "catch load" command. It allows
|
||||
the debugger to be notified by the dynamic linker when a specified
|
||||
library file (or any library file, if filename is NULL) is loaded.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag,filename,cond_string) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
|
||||
/* This function is called by the "catch unload" command. It allows
|
||||
the debugger to be notified by the dynamic linker when a specified
|
||||
library file (or any library file, if filename is NULL) is unloaded.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename,cond_string) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
|
||||
/* This function returns TRUE if the dynamic linker has just reported
|
||||
a load of a library.
|
||||
|
||||
This function must be used only when the inferior has stopped in
|
||||
the dynamic linker hook, or undefined results are guaranteed.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
/*
|
||||
#define SOLIB_HAVE_LOAD_EVENT(pid) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
*/
|
||||
|
||||
#define SOLIB_HAVE_LOAD_EVENT(pid) \
|
||||
(0)
|
||||
|
||||
/* This function returns a pointer to the string representation of the
|
||||
pathname of the dynamically-linked library that has just been loaded.
|
||||
|
||||
This function must be used only when SOLIB_HAVE_LOAD_EVENT is TRUE,
|
||||
or undefined results are guaranteed.
|
||||
|
||||
This string's contents are only valid immediately after the inferior
|
||||
has stopped in the dynamic linker hook, and becomes invalid as soon
|
||||
as the inferior is continued. Clients should make a copy of this
|
||||
string if they wish to continue the inferior and then access the string.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
|
||||
/*
|
||||
#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
*/
|
||||
|
||||
#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
|
||||
(0)
|
||||
|
||||
/* This function returns TRUE if the dynamic linker has just reported
|
||||
an unload of a library.
|
||||
|
||||
This function must be used only when the inferior has stopped in
|
||||
the dynamic linker hook, or undefined results are guaranteed.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
/*
|
||||
#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
*/
|
||||
|
||||
#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
|
||||
(0)
|
||||
|
||||
/* This function returns a pointer to the string representation of the
|
||||
pathname of the dynamically-linked library that has just been unloaded.
|
||||
|
||||
This function must be used only when SOLIB_HAVE_UNLOAD_EVENT is TRUE,
|
||||
or undefined results are guaranteed.
|
||||
|
||||
This string's contents are only valid immediately after the inferior
|
||||
has stopped in the dynamic linker hook, and becomes invalid as soon
|
||||
as the inferior is continued. Clients should make a copy of this
|
||||
string if they wish to continue the inferior and then access the string.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
/*
|
||||
#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
*/
|
||||
|
||||
#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
|
||||
(0)
|
||||
|
||||
/* This function returns TRUE if pc is the address of an instruction that
|
||||
lies within the dynamic linker (such as the event hook, or the dld
|
||||
itself).
|
||||
|
||||
This function must be used only when a dynamic linker event has been
|
||||
caught, and the inferior is being stepped out of the hook, or undefined
|
||||
results are guaranteed.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
|
||||
/*
|
||||
#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
|
||||
error("catch of library loads/unloads not yet implemented on this platform")
|
||||
*/
|
||||
|
||||
#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
|
||||
(0)
|
||||
|
||||
/* This function must be called when the inferior is killed, and the program
|
||||
restarted. This is not the same as CLEAR_SOLIB, in that it doesn't discard
|
||||
any symbol tables.
|
||||
|
||||
Presently, this functionality is not implemented.
|
||||
*/
|
||||
#define SOLIB_RESTART() \
|
||||
(0)
|
||||
|
||||
/* 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 (CORE_ADDR); /* solib.c */
|
||||
#endif
|
@ -1,196 +0,0 @@
|
||||
/* Machine independent support for Solaris 2 core files for GDB.
|
||||
Copyright 1994, 1995, 1996, 1998, 1999, 2000, 2001
|
||||
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. */
|
||||
|
||||
/* for Sparc64 cross Sparc32 */
|
||||
#define _SYSCALL32
|
||||
#include "defs.h"
|
||||
|
||||
#if defined (__sparcv9)
|
||||
/* Fails to get included by the Solaris system header files. */
|
||||
# include <v9/sys/privregs.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/regset.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "gdb_string.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "command.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
|
||||
/* Fetch registers from core file data pointed to by CORE_REG_SECT. When
|
||||
WHICH is 0, the the general register set is fetched; when WHICH is
|
||||
2, the floating point registers are fetched. CORE_REG_SIZE is used
|
||||
to validate the size of the data pointed to by CORE_REG_SECT. REG_ADDR
|
||||
is unused. */
|
||||
|
||||
static void
|
||||
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
|
||||
CORE_ADDR reg_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (which == 0)
|
||||
{
|
||||
prgregset_t prgregset;
|
||||
|
||||
if (core_reg_size == sizeof (prgregset_t))
|
||||
{
|
||||
memcpy ((char *) &prgregset, core_reg_sect, sizeof (prgregset));
|
||||
supply_gregset (&prgregset);
|
||||
}
|
||||
#if defined (HAVE_PRGREGSET32_T)
|
||||
/* 32-bit corefile, 64-bit debugger. */
|
||||
else if (core_reg_size == sizeof (prgregset32_t))
|
||||
{
|
||||
prgreg32_t *core_gregs;
|
||||
|
||||
/* Can't use memcpy here, because the core file contains
|
||||
32-bit regs; supply_register expects 64-bit regs. */
|
||||
core_gregs = (prgreg32_t *) core_reg_sect;
|
||||
for (i = 0; i < NPRGREG; i++)
|
||||
prgregset[i] = core_gregs[i];
|
||||
|
||||
supply_gregset (&prgregset);
|
||||
}
|
||||
#endif /* HAVE_PRGREGSET32_T */
|
||||
else if (core_reg_size == sizeof (struct regs))
|
||||
{
|
||||
struct regs *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)
|
||||
{
|
||||
prfpregset_t prfpregset;
|
||||
|
||||
if (core_reg_size == sizeof (prfpregset_t))
|
||||
{
|
||||
memcpy ((char *) &prfpregset, core_reg_sect, sizeof (prfpregset));
|
||||
supply_fpregset (&prfpregset);
|
||||
}
|
||||
#if defined (HAVE_PRFPREGSET32_T)
|
||||
/* 32-bit corefile, 64-bit debugger. */
|
||||
else if (core_reg_size == sizeof (prfpregset32_t))
|
||||
{
|
||||
prfpregset32_t *core_fpregset;
|
||||
|
||||
/* Can't use memcpy here, because the core file contains
|
||||
32-bit regs; supply_fpregset expects 64-bit regs. */
|
||||
|
||||
core_fpregset = (prfpregset32_t *) core_reg_sect;
|
||||
for (i = 0; i < 16; i++)
|
||||
prfpregset.pr_fr.pr_dregs[i] = core_fpregset->pr_fr.pr_dregs[i];
|
||||
while (i < 32)
|
||||
prfpregset.pr_fr.pr_dregs[i++] = 0;
|
||||
|
||||
prfpregset.pr_fsr = core_fpregset->pr_fsr;
|
||||
prfpregset.pr_qcnt = core_fpregset->pr_qcnt;
|
||||
prfpregset.pr_q_entrysize = core_fpregset->pr_q_entrysize;
|
||||
prfpregset.pr_en = core_fpregset->pr_en;
|
||||
/* We will not use the pr_q array. */
|
||||
|
||||
supply_fpregset (&prfpregset);
|
||||
}
|
||||
#endif /* HAVE_PRFPREGSET32_T */
|
||||
else if (core_reg_size >= sizeof (struct fpu))
|
||||
{
|
||||
struct fpu *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, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_solaris (void)
|
||||
{
|
||||
add_core_fns (&solaris_core_fns);
|
||||
}
|
@ -1,601 +0,0 @@
|
||||
/* Target-dependent code for the Fujitsu FR30.
|
||||
Copyright 1999, 2000, 2001 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 "obstack.h"
|
||||
#include "target.h"
|
||||
#include "value.h"
|
||||
#include "bfd.h"
|
||||
#include "gdb_string.h"
|
||||
#include "gdbcore.h"
|
||||
#include "symfile.h"
|
||||
#include "regcache.h"
|
||||
|
||||
/* An expression that tells us whether the function invocation represented
|
||||
by FI does not have a frame on the stack associated with it. */
|
||||
int
|
||||
fr30_frameless_function_invocation (struct frame_info *fi)
|
||||
{
|
||||
int frameless;
|
||||
CORE_ADDR func_start, after_prologue;
|
||||
func_start = (get_pc_function_start ((fi)->pc) +
|
||||
FUNCTION_START_OFFSET);
|
||||
after_prologue = func_start;
|
||||
after_prologue = SKIP_PROLOGUE (after_prologue);
|
||||
frameless = (after_prologue == func_start);
|
||||
return frameless;
|
||||
}
|
||||
|
||||
/* Function: pop_frame
|
||||
This routine gets called when either the user uses the `return'
|
||||
command, or the call dummy breakpoint gets hit. */
|
||||
|
||||
void
|
||||
fr30_pop_frame (void)
|
||||
{
|
||||
struct frame_info *frame = get_current_frame ();
|
||||
int regnum;
|
||||
CORE_ADDR sp = read_register (SP_REGNUM);
|
||||
|
||||
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
|
||||
generic_pop_dummy_frame ();
|
||||
else
|
||||
{
|
||||
write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
|
||||
|
||||
for (regnum = 0; regnum < NUM_REGS; regnum++)
|
||||
if (frame->fsr.regs[regnum] != 0)
|
||||
{
|
||||
write_register (regnum,
|
||||
read_memory_unsigned_integer (frame->fsr.regs[regnum],
|
||||
REGISTER_RAW_SIZE (regnum)));
|
||||
}
|
||||
write_register (SP_REGNUM, sp + frame->framesize);
|
||||
}
|
||||
flush_cached_frames ();
|
||||
}
|
||||
|
||||
|
||||
/* Function: fr30_store_return_value
|
||||
Put a value where a caller expects to see it. Used by the 'return'
|
||||
command. */
|
||||
void
|
||||
fr30_store_return_value (struct type *type,
|
||||
char *valbuf)
|
||||
{
|
||||
/* Here's how the FR30 returns values (gleaned from gcc/config/
|
||||
fr30/fr30.h):
|
||||
|
||||
If the return value is 32 bits long or less, it goes in r4.
|
||||
|
||||
If the return value is 64 bits long or less, it goes in r4 (most
|
||||
significant word) and r5 (least significant word.
|
||||
|
||||
If the function returns a structure, of any size, the caller
|
||||
passes the function an invisible first argument where the callee
|
||||
should store the value. But GDB doesn't let you do that anyway.
|
||||
|
||||
If you're returning a value smaller than a word, it's not really
|
||||
necessary to zero the upper bytes of the register; the caller is
|
||||
supposed to ignore them. However, the FR30 typically keeps its
|
||||
values extended to the full register width, so we should emulate
|
||||
that. */
|
||||
|
||||
/* The FR30 is big-endian, so if we return a small value (like a
|
||||
short or a char), we need to position it correctly within the
|
||||
register. We round the size up to a register boundary, and then
|
||||
adjust the offset so as to place the value at the right end. */
|
||||
int value_size = TYPE_LENGTH (type);
|
||||
int returned_size = (value_size + FR30_REGSIZE - 1) & ~(FR30_REGSIZE - 1);
|
||||
int offset = (REGISTER_BYTE (RETVAL_REG)
|
||||
+ (returned_size - value_size));
|
||||
char *zeros = alloca (returned_size);
|
||||
memset (zeros, 0, returned_size);
|
||||
|
||||
write_register_bytes (REGISTER_BYTE (RETVAL_REG), zeros, returned_size);
|
||||
write_register_bytes (offset, valbuf, value_size);
|
||||
}
|
||||
|
||||
|
||||
/* Function: skip_prologue
|
||||
Return the address of the first code past the prologue of the function. */
|
||||
|
||||
CORE_ADDR
|
||||
fr30_skip_prologue (CORE_ADDR pc)
|
||||
{
|
||||
CORE_ADDR func_addr, func_end;
|
||||
|
||||
/* See what the symbol table says */
|
||||
|
||||
if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
|
||||
{
|
||||
struct symtab_and_line sal;
|
||||
|
||||
sal = find_pc_line (func_addr, 0);
|
||||
|
||||
if (sal.line != 0 && sal.end < func_end)
|
||||
{
|
||||
return sal.end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Either we didn't find the start of this function (nothing we can do),
|
||||
or there's no line info, or the line after the prologue is after
|
||||
the end of the function (there probably isn't a prologue). */
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
/* Function: push_arguments
|
||||
Setup arguments and RP for a call to the target. First four args
|
||||
go in FIRST_ARGREG -> LAST_ARGREG, subsequent args go on stack...
|
||||
Structs are passed by reference. XXX not right now Z.R.
|
||||
64 bit quantities (doubles and long longs) may be split between
|
||||
the regs and the stack.
|
||||
When calling a function that returns a struct, a pointer to the struct
|
||||
is passed in as a secret first argument (always in FIRST_ARGREG).
|
||||
|
||||
Stack space for the args has NOT been allocated: that job is up to us.
|
||||
*/
|
||||
|
||||
CORE_ADDR
|
||||
fr30_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
|
||||
int struct_return, CORE_ADDR struct_addr)
|
||||
{
|
||||
int argreg;
|
||||
int argnum;
|
||||
int stack_offset;
|
||||
struct stack_arg
|
||||
{
|
||||
char *val;
|
||||
int len;
|
||||
int offset;
|
||||
};
|
||||
struct stack_arg *stack_args =
|
||||
(struct stack_arg *) alloca (nargs * sizeof (struct stack_arg));
|
||||
int nstack_args = 0;
|
||||
|
||||
argreg = FIRST_ARGREG;
|
||||
|
||||
/* the struct_return pointer occupies the first parameter-passing reg */
|
||||
if (struct_return)
|
||||
write_register (argreg++, struct_addr);
|
||||
|
||||
stack_offset = 0;
|
||||
|
||||
/* Process args from left to right. Store as many as allowed in
|
||||
registers, save the rest to be pushed on the stack */
|
||||
for (argnum = 0; argnum < nargs; argnum++)
|
||||
{
|
||||
char *val;
|
||||
struct value *arg = args[argnum];
|
||||
struct type *arg_type = check_typedef (VALUE_TYPE (arg));
|
||||
struct type *target_type = TYPE_TARGET_TYPE (arg_type);
|
||||
int len = TYPE_LENGTH (arg_type);
|
||||
enum type_code typecode = TYPE_CODE (arg_type);
|
||||
CORE_ADDR regval;
|
||||
int newarg;
|
||||
|
||||
val = (char *) VALUE_CONTENTS (arg);
|
||||
|
||||
{
|
||||
/* Copy the argument to general registers or the stack in
|
||||
register-sized pieces. Large arguments are split between
|
||||
registers and stack. */
|
||||
while (len > 0)
|
||||
{
|
||||
if (argreg <= LAST_ARGREG)
|
||||
{
|
||||
int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE;
|
||||
regval = extract_address (val, partial_len);
|
||||
|
||||
/* It's a simple argument being passed in a general
|
||||
register. */
|
||||
write_register (argreg, regval);
|
||||
argreg++;
|
||||
len -= partial_len;
|
||||
val += partial_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* keep for later pushing */
|
||||
stack_args[nstack_args].val = val;
|
||||
stack_args[nstack_args++].len = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* now do the real stack pushing, process args right to left */
|
||||
while (nstack_args--)
|
||||
{
|
||||
sp -= stack_args[nstack_args].len;
|
||||
write_memory (sp, stack_args[nstack_args].val,
|
||||
stack_args[nstack_args].len);
|
||||
}
|
||||
|
||||
/* Return adjusted stack pointer. */
|
||||
return sp;
|
||||
}
|
||||
|
||||
void _initialize_fr30_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_fr30_tdep (void)
|
||||
{
|
||||
extern int print_insn_fr30 (bfd_vma, disassemble_info *);
|
||||
tm_print_insn = print_insn_fr30;
|
||||
}
|
||||
|
||||
/* Function: check_prologue_cache
|
||||
Check if prologue for this frame's PC has already been scanned.
|
||||
If it has, copy the relevant information about that prologue and
|
||||
return non-zero. Otherwise do not copy anything and return zero.
|
||||
|
||||
The information saved in the cache includes:
|
||||
* the frame register number;
|
||||
* the size of the stack frame;
|
||||
* the offsets of saved regs (relative to the old SP); and
|
||||
* the offset from the stack pointer to the frame pointer
|
||||
|
||||
The cache contains only one entry, since this is adequate
|
||||
for the typical sequence of prologue scan requests we get.
|
||||
When performing a backtrace, GDB will usually ask to scan
|
||||
the same function twice in a row (once to get the frame chain,
|
||||
and once to fill in the extra frame information).
|
||||
*/
|
||||
|
||||
static struct frame_info prologue_cache;
|
||||
|
||||
static int
|
||||
check_prologue_cache (struct frame_info *fi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fi->pc == prologue_cache.pc)
|
||||
{
|
||||
fi->framereg = prologue_cache.framereg;
|
||||
fi->framesize = prologue_cache.framesize;
|
||||
fi->frameoffset = prologue_cache.frameoffset;
|
||||
for (i = 0; i <= NUM_REGS; i++)
|
||||
fi->fsr.regs[i] = prologue_cache.fsr.regs[i];
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Function: save_prologue_cache
|
||||
Copy the prologue information from fi to the prologue cache.
|
||||
*/
|
||||
|
||||
static void
|
||||
save_prologue_cache (struct frame_info *fi)
|
||||
{
|
||||
int i;
|
||||
|
||||
prologue_cache.pc = fi->pc;
|
||||
prologue_cache.framereg = fi->framereg;
|
||||
prologue_cache.framesize = fi->framesize;
|
||||
prologue_cache.frameoffset = fi->frameoffset;
|
||||
|
||||
for (i = 0; i <= NUM_REGS; i++)
|
||||
{
|
||||
prologue_cache.fsr.regs[i] = fi->fsr.regs[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Function: scan_prologue
|
||||
Scan the prologue of the function that contains PC, and record what
|
||||
we find in PI. PI->fsr must be zeroed by the called. Returns the
|
||||
pc after the prologue. Note that the addresses saved in pi->fsr
|
||||
are actually just frame relative (negative offsets from the frame
|
||||
pointer). This is because we don't know the actual value of the
|
||||
frame pointer yet. In some circumstances, the frame pointer can't
|
||||
be determined till after we have scanned the prologue. */
|
||||
|
||||
static void
|
||||
fr30_scan_prologue (struct frame_info *fi)
|
||||
{
|
||||
int sp_offset, fp_offset;
|
||||
CORE_ADDR prologue_start, prologue_end, current_pc;
|
||||
|
||||
/* Check if this function is already in the cache of frame information. */
|
||||
if (check_prologue_cache (fi))
|
||||
return;
|
||||
|
||||
/* Assume there is no frame until proven otherwise. */
|
||||
fi->framereg = SP_REGNUM;
|
||||
fi->framesize = 0;
|
||||
fi->frameoffset = 0;
|
||||
|
||||
/* Find the function prologue. If we can't find the function in
|
||||
the symbol table, peek in the stack frame to find the PC. */
|
||||
if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end))
|
||||
{
|
||||
/* Assume the prologue is everything between the first instruction
|
||||
in the function and the first source line. */
|
||||
struct symtab_and_line sal = find_pc_line (prologue_start, 0);
|
||||
|
||||
if (sal.line == 0) /* no line info, use current PC */
|
||||
prologue_end = fi->pc;
|
||||
else if (sal.end < prologue_end) /* next line begins after fn end */
|
||||
prologue_end = sal.end; /* (probably means no prologue) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX Z.R. What now??? The following is entirely bogus */
|
||||
prologue_start = (read_memory_integer (fi->frame, 4) & 0x03fffffc) - 12;
|
||||
prologue_end = prologue_start + 40;
|
||||
}
|
||||
|
||||
/* Now search the prologue looking for instructions that set up the
|
||||
frame pointer, adjust the stack pointer, and save registers. */
|
||||
|
||||
sp_offset = fp_offset = 0;
|
||||
for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 2)
|
||||
{
|
||||
unsigned int insn;
|
||||
|
||||
insn = read_memory_unsigned_integer (current_pc, 2);
|
||||
|
||||
if ((insn & 0xfe00) == 0x8e00) /* stm0 or stm1 */
|
||||
{
|
||||
int reg, mask = insn & 0xff;
|
||||
|
||||
/* scan in one sweep - create virtual 16-bit mask from either insn's mask */
|
||||
if ((insn & 0x0100) == 0)
|
||||
{
|
||||
mask <<= 8; /* stm0 - move to upper byte in virtual mask */
|
||||
}
|
||||
|
||||
/* Calculate offsets of saved registers (to be turned later into addresses). */
|
||||
for (reg = R4_REGNUM; reg <= R11_REGNUM; reg++)
|
||||
if (mask & (1 << (15 - reg)))
|
||||
{
|
||||
sp_offset -= 4;
|
||||
fi->fsr.regs[reg] = sp_offset;
|
||||
}
|
||||
}
|
||||
else if ((insn & 0xfff0) == 0x1700) /* st rx,@-r15 */
|
||||
{
|
||||
int reg = insn & 0xf;
|
||||
|
||||
sp_offset -= 4;
|
||||
fi->fsr.regs[reg] = sp_offset;
|
||||
}
|
||||
else if ((insn & 0xff00) == 0x0f00) /* enter */
|
||||
{
|
||||
fp_offset = fi->fsr.regs[FP_REGNUM] = sp_offset - 4;
|
||||
sp_offset -= 4 * (insn & 0xff);
|
||||
fi->framereg = FP_REGNUM;
|
||||
}
|
||||
else if (insn == 0x1781) /* st rp,@-sp */
|
||||
{
|
||||
sp_offset -= 4;
|
||||
fi->fsr.regs[RP_REGNUM] = sp_offset;
|
||||
}
|
||||
else if (insn == 0x170e) /* st fp,@-sp */
|
||||
{
|
||||
sp_offset -= 4;
|
||||
fi->fsr.regs[FP_REGNUM] = sp_offset;
|
||||
}
|
||||
else if (insn == 0x8bfe) /* mov sp,fp */
|
||||
{
|
||||
fi->framereg = FP_REGNUM;
|
||||
}
|
||||
else if ((insn & 0xff00) == 0xa300) /* addsp xx */
|
||||
{
|
||||
sp_offset += 4 * (signed char) (insn & 0xff);
|
||||
}
|
||||
else if ((insn & 0xff0f) == 0x9b00 && /* ldi:20 xx,r0 */
|
||||
read_memory_unsigned_integer (current_pc + 4, 2)
|
||||
== 0xac0f) /* sub r0,sp */
|
||||
{
|
||||
/* large stack adjustment */
|
||||
sp_offset -= (((insn & 0xf0) << 12) | read_memory_unsigned_integer (current_pc + 2, 2));
|
||||
current_pc += 4;
|
||||
}
|
||||
else if (insn == 0x9f80 && /* ldi:32 xx,r0 */
|
||||
read_memory_unsigned_integer (current_pc + 6, 2)
|
||||
== 0xac0f) /* sub r0,sp */
|
||||
{
|
||||
/* large stack adjustment */
|
||||
sp_offset -=
|
||||
(read_memory_unsigned_integer (current_pc + 2, 2) << 16 |
|
||||
read_memory_unsigned_integer (current_pc + 4, 2));
|
||||
current_pc += 6;
|
||||
}
|
||||
}
|
||||
|
||||
/* The frame size is just the negative of the offset (from the original SP)
|
||||
of the last thing thing we pushed on the stack. The frame offset is
|
||||
[new FP] - [new SP]. */
|
||||
fi->framesize = -sp_offset;
|
||||
fi->frameoffset = fp_offset - sp_offset;
|
||||
|
||||
save_prologue_cache (fi);
|
||||
}
|
||||
|
||||
/* Function: init_extra_frame_info
|
||||
Setup the frame's frame pointer, pc, and frame addresses for saved
|
||||
registers. Most of the work is done in scan_prologue().
|
||||
|
||||
Note that when we are called for the last frame (currently active frame),
|
||||
that fi->pc and fi->frame will already be setup. However, fi->frame will
|
||||
be valid only if this routine uses FP. For previous frames, fi-frame will
|
||||
always be correct (since that is derived from fr30_frame_chain ()).
|
||||
|
||||
We can be called with the PC in the call dummy under two circumstances.
|
||||
First, during normal backtracing, second, while figuring out the frame
|
||||
pointer just prior to calling the target function (see run_stack_dummy). */
|
||||
|
||||
void
|
||||
fr30_init_extra_frame_info (struct frame_info *fi)
|
||||
{
|
||||
int reg;
|
||||
|
||||
if (fi->next)
|
||||
fi->pc = FRAME_SAVED_PC (fi->next);
|
||||
|
||||
memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs);
|
||||
|
||||
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
|
||||
{
|
||||
/* We need to setup fi->frame here because run_stack_dummy gets it wrong
|
||||
by assuming it's always FP. */
|
||||
fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
|
||||
fi->framesize = 0;
|
||||
fi->frameoffset = 0;
|
||||
return;
|
||||
}
|
||||
fr30_scan_prologue (fi);
|
||||
|
||||
if (!fi->next) /* this is the innermost frame? */
|
||||
fi->frame = read_register (fi->framereg);
|
||||
else
|
||||
/* not the innermost frame */
|
||||
/* If we have an FP, the callee saved it. */
|
||||
if (fi->framereg == FP_REGNUM)
|
||||
if (fi->next->fsr.regs[fi->framereg] != 0)
|
||||
fi->frame = read_memory_integer (fi->next->fsr.regs[fi->framereg], 4);
|
||||
|
||||
/* Calculate actual addresses of saved registers using offsets determined
|
||||
by fr30_scan_prologue. */
|
||||
for (reg = 0; reg < NUM_REGS; reg++)
|
||||
if (fi->fsr.regs[reg] != 0)
|
||||
{
|
||||
fi->fsr.regs[reg] += fi->frame + fi->framesize - fi->frameoffset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function: find_callers_reg
|
||||
Find REGNUM on the stack. Otherwise, it's in an active register.
|
||||
One thing we might want to do here is to check REGNUM against the
|
||||
clobber mask, and somehow flag it as invalid if it isn't saved on
|
||||
the stack somewhere. This would provide a graceful failure mode
|
||||
when trying to get the value of caller-saves registers for an inner
|
||||
frame. */
|
||||
|
||||
CORE_ADDR
|
||||
fr30_find_callers_reg (struct frame_info *fi, int regnum)
|
||||
{
|
||||
for (; fi; fi = fi->next)
|
||||
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
|
||||
return generic_read_register_dummy (fi->pc, fi->frame, regnum);
|
||||
else if (fi->fsr.regs[regnum] != 0)
|
||||
return read_memory_unsigned_integer (fi->fsr.regs[regnum],
|
||||
REGISTER_RAW_SIZE (regnum));
|
||||
|
||||
return read_register (regnum);
|
||||
}
|
||||
|
||||
|
||||
/* Function: frame_chain
|
||||
Figure out the frame prior to FI. Unfortunately, this involves
|
||||
scanning the prologue of the caller, which will also be done
|
||||
shortly by fr30_init_extra_frame_info. For the dummy frame, we
|
||||
just return the stack pointer that was in use at the time the
|
||||
function call was made. */
|
||||
|
||||
|
||||
CORE_ADDR
|
||||
fr30_frame_chain (struct frame_info *fi)
|
||||
{
|
||||
CORE_ADDR fn_start, callers_pc, fp;
|
||||
struct frame_info caller_fi;
|
||||
int framereg;
|
||||
|
||||
/* is this a dummy frame? */
|
||||
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
|
||||
return fi->frame; /* dummy frame same as caller's frame */
|
||||
|
||||
/* is caller-of-this a dummy frame? */
|
||||
callers_pc = FRAME_SAVED_PC (fi); /* find out who called us: */
|
||||
fp = fr30_find_callers_reg (fi, FP_REGNUM);
|
||||
if (PC_IN_CALL_DUMMY (callers_pc, fp, fp))
|
||||
return fp; /* dummy frame's frame may bear no relation to ours */
|
||||
|
||||
if (find_pc_partial_function (fi->pc, 0, &fn_start, 0))
|
||||
if (fn_start == entry_point_address ())
|
||||
return 0; /* in _start fn, don't chain further */
|
||||
|
||||
framereg = fi->framereg;
|
||||
|
||||
/* If the caller is the startup code, we're at the end of the chain. */
|
||||
if (find_pc_partial_function (callers_pc, 0, &fn_start, 0))
|
||||
if (fn_start == entry_point_address ())
|
||||
return 0;
|
||||
|
||||
memset (&caller_fi, 0, sizeof (caller_fi));
|
||||
caller_fi.pc = callers_pc;
|
||||
fr30_scan_prologue (&caller_fi);
|
||||
framereg = caller_fi.framereg;
|
||||
|
||||
/* If the caller used a frame register, return its value.
|
||||
Otherwise, return the caller's stack pointer. */
|
||||
if (framereg == FP_REGNUM)
|
||||
return fr30_find_callers_reg (fi, framereg);
|
||||
else
|
||||
return fi->frame + fi->framesize;
|
||||
}
|
||||
|
||||
/* Function: frame_saved_pc
|
||||
Find the caller of this frame. We do this by seeing if RP_REGNUM
|
||||
is saved in the stack anywhere, otherwise we get it from the
|
||||
registers. If the inner frame is a dummy frame, return its PC
|
||||
instead of RP, because that's where "caller" of the dummy-frame
|
||||
will be found. */
|
||||
|
||||
CORE_ADDR
|
||||
fr30_frame_saved_pc (struct frame_info *fi)
|
||||
{
|
||||
if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
|
||||
return generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
|
||||
else
|
||||
return fr30_find_callers_reg (fi, RP_REGNUM);
|
||||
}
|
||||
|
||||
/* Function: fix_call_dummy
|
||||
Pokes the callee function's address into the CALL_DUMMY assembly stub.
|
||||
Assumes that the CALL_DUMMY looks like this:
|
||||
jarl <offset24>, r31
|
||||
trap
|
||||
*/
|
||||
|
||||
int
|
||||
fr30_fix_call_dummy (char *dummy, CORE_ADDR sp, CORE_ADDR fun, int nargs,
|
||||
struct value **args, struct type *type, int gcc_p)
|
||||
{
|
||||
long offset24;
|
||||
|
||||
offset24 = (long) fun - (long) entry_point_address ();
|
||||
offset24 &= 0x3fffff;
|
||||
offset24 |= 0xff800000; /* jarl <offset24>, r31 */
|
||||
|
||||
store_unsigned_integer ((unsigned int *) &dummy[2], 2, offset24 & 0xffff);
|
||||
store_unsigned_integer ((unsigned int *) &dummy[0], 2, offset24 >> 16);
|
||||
return 0;
|
||||
}
|
@ -1,952 +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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
extern void putDebugChar(); /* write a single character */
|
||||
extern int getDebugChar(); /* read and return a single char */
|
||||
extern void exceptionHandler(); /* assign an exception handler */
|
||||
|
||||
/************************************************************************/
|
||||
/* 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 */
|
||||
|
||||
static const char hexchars[]="0123456789abcdef";
|
||||
|
||||
/* Number of registers. */
|
||||
#define NUMREGS 16
|
||||
|
||||
/* Number of bytes of registers. */
|
||||
#define NUMREGBYTES (NUMREGS * 4)
|
||||
|
||||
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[NUMREGS];
|
||||
|
||||
#define STACKSIZE 10000
|
||||
int remcomStack[STACKSIZE/sizeof(int)];
|
||||
static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
|
||||
|
||||
/*************************** 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);
|
||||
}
|
||||
|
||||
static char remcomInBuffer[BUFMAX];
|
||||
static char remcomOutBuffer[BUFMAX];
|
||||
|
||||
/* scan for the sequence $<data>#<checksum> */
|
||||
|
||||
unsigned char *
|
||||
getpacket (void)
|
||||
{
|
||||
unsigned char *buffer = &remcomInBuffer[0];
|
||||
unsigned char checksum;
|
||||
unsigned char xmitcsum;
|
||||
int count;
|
||||
char ch;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* wait around for the start character, ignore all other characters */
|
||||
while ((ch = getDebugChar ()) != '$')
|
||||
;
|
||||
|
||||
retry:
|
||||
checksum = 0;
|
||||
xmitcsum = -1;
|
||||
count = 0;
|
||||
|
||||
/* now, read until a # or end of buffer is found */
|
||||
while (count < BUFMAX)
|
||||
{
|
||||
ch = getDebugChar ();
|
||||
if (ch == '$')
|
||||
goto retry;
|
||||
if (ch == '#')
|
||||
break;
|
||||
checksum = checksum + ch;
|
||||
buffer[count] = ch;
|
||||
count = count + 1;
|
||||
}
|
||||
buffer[count] = 0;
|
||||
|
||||
if (ch == '#')
|
||||
{
|
||||
ch = getDebugChar ();
|
||||
xmitcsum = hex (ch) << 4;
|
||||
ch = getDebugChar ();
|
||||
xmitcsum += hex (ch);
|
||||
|
||||
if (checksum != xmitcsum)
|
||||
{
|
||||
if (remote_debug)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n",
|
||||
checksum, xmitcsum, buffer);
|
||||
}
|
||||
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]);
|
||||
|
||||
return &buffer[3];
|
||||
}
|
||||
|
||||
return &buffer[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* send the packet in buffer. */
|
||||
|
||||
void
|
||||
putpacket (unsigned char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
char ch;
|
||||
|
||||
/* $<packet info>#<checksum>. */
|
||||
do
|
||||
{
|
||||
putDebugChar ('$');
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
|
||||
while (ch = buffer[count])
|
||||
{
|
||||
putDebugChar (ch);
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
putDebugChar ('#');
|
||||
putDebugChar (hexchars[checksum >> 4]);
|
||||
putDebugChar (hexchars[checksum % 16]);
|
||||
|
||||
}
|
||||
while (getDebugChar () != '+');
|
||||
}
|
||||
|
||||
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 (void)
|
||||
{
|
||||
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 (char *addr)
|
||||
{
|
||||
return *addr;
|
||||
}
|
||||
|
||||
void
|
||||
set_char (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 (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, stepping;
|
||||
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);
|
||||
|
||||
ptr = remcomOutBuffer;
|
||||
|
||||
*ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
|
||||
*ptr++ = hexchars[sigval >> 4];
|
||||
*ptr++ = hexchars[sigval & 0xf];
|
||||
|
||||
*ptr++ = hexchars[ESP];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[EBP];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[PC];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr = '\0'
|
||||
|
||||
putpacket (remcomOutBuffer);
|
||||
|
||||
stepping = 0;
|
||||
|
||||
while (1 == 1)
|
||||
{
|
||||
remcomOutBuffer[0] = 0;
|
||||
ptr = getpacket ();
|
||||
|
||||
switch (*ptr++)
|
||||
{
|
||||
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 (ptr, (char *) registers, NUMREGBYTES, 0);
|
||||
strcpy (remcomOutBuffer, "OK");
|
||||
break;
|
||||
case 'P': /* set the value of a single CPU register - return OK */
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (hexToInt (&ptr, ®no) && *ptr++ == '=')
|
||||
if (regno >= 0 && regno < NUMREGS)
|
||||
{
|
||||
hex2mem (ptr, (char *) ®isters[regno], 4, 0);
|
||||
strcpy (remcomOutBuffer, "OK");
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy (remcomOutBuffer, "E01");
|
||||
break;
|
||||
}
|
||||
|
||||
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||||
case 'm':
|
||||
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
|
||||
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");
|
||||
}
|
||||
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 */
|
||||
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");
|
||||
}
|
||||
break;
|
||||
|
||||
/* cAA..AA Continue at address AA..AA(optional) */
|
||||
/* sAA..AA Step one instruction from AA..AA(optional) */
|
||||
case 's':
|
||||
stepping = 1;
|
||||
case 'c':
|
||||
/* try to read optional parameter, pc unchanged if no parm */
|
||||
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 (stepping)
|
||||
registers[PS] |= 0x100;
|
||||
|
||||
_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 (void)
|
||||
{
|
||||
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);
|
||||
|
||||
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 (void)
|
||||
{
|
||||
if (initialized)
|
||||
BREAKPOINT ();
|
||||
}
|
@ -1,377 +0,0 @@
|
||||
/* Intel 386 native support.
|
||||
Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
|
||||
2000, 2001 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"
|
||||
#include "regcache.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;
|
||||
|
||||
#ifdef HAVE_SYS_REG_H
|
||||
#include <sys/reg.h>
|
||||
#endif
|
||||
|
||||
#include "floatformat.h"
|
||||
|
||||
#include "target.h"
|
||||
|
||||
static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
|
||||
|
||||
/* 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 (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 (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 (void)
|
||||
{
|
||||
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 (! ptid_equal (inferior_ptid, null_ptid))
|
||||
{
|
||||
char buf[10];
|
||||
unsigned short status;
|
||||
|
||||
ptrace (PT_READ_FPR, PIDGET (inferior_ptid), 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 (! ptid_equal (inferior_ptid, null_ptid))
|
||||
{
|
||||
int offset;
|
||||
for (offset = 0; offset < sizeof (fps); offset += 10)
|
||||
{
|
||||
char buf[10];
|
||||
ptrace (PT_READ_FPR, PIDGET (inferior_ptid), 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 (int regno)
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
if (regno < FP0_REGNUM)
|
||||
*(int *) buf = ptrace (PT_READ_GPR, PIDGET (inferior_ptid),
|
||||
PT_REG (regmap[regno]), 0, 0);
|
||||
else
|
||||
ptrace (PT_READ_FPR, PIDGET (inferior_ptid), buf,
|
||||
(regno - FP0_REGNUM) * 10 + offsetof (struct env387, regs));
|
||||
supply_register (regno, buf);
|
||||
}
|
||||
|
||||
void
|
||||
fetch_inferior_registers (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 (int regno)
|
||||
{
|
||||
char buf[80];
|
||||
errno = 0;
|
||||
if (regno < FP0_REGNUM)
|
||||
ptrace (PT_WRITE_GPR, PIDGET (inferior_ptid), PT_REG (regmap[regno]),
|
||||
*(int *) ®isters[REGISTER_BYTE (regno)], 0);
|
||||
else
|
||||
ptrace (PT_WRITE_FPR, PIDGET (inferior_ptid),
|
||||
®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 (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,
|
||||
};
|
||||
|
||||
/* Provide registers to GDB from a core file.
|
||||
|
||||
CORE_REG_SECT points to an array of bytes, which were obtained from
|
||||
a core file which BFD thinks might contain register contents.
|
||||
CORE_REG_SIZE is its size.
|
||||
|
||||
WHICH says which register set corelow suspects this is:
|
||||
0 --- the general-purpose register set
|
||||
2 --- the floating-point register set
|
||||
|
||||
REG_ADDR isn't used. */
|
||||
|
||||
static void
|
||||
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
|
||||
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, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_i386aix (void)
|
||||
{
|
||||
add_core_fns (&i386aix_core_fns);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/* Target-dependent code for Intel 386 running LynxOS.
|
||||
Copyright 1993, 1996, 2000, 2001 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"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.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 (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,426 +0,0 @@
|
||||
/* Low level interface to I386 running mach 3.0.
|
||||
Copyright 1992, 1993, 1994, 1996, 2000, 2001
|
||||
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 "regcache.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 (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 (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)
|
||||
*/
|
||||
|
||||
CORE_ADDR
|
||||
register_addr (int regno, CORE_ADDR blockend)
|
||||
{
|
||||
CORE_ADDR 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 (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 (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 (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 (void)
|
||||
{
|
||||
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,172 +0,0 @@
|
||||
/* Native dependent code for Mach 386's for GDB, the GNU debugger.
|
||||
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1995, 1996, 1999, 2000,
|
||||
2001 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 "regcache.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>
|
||||
|
||||
static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
|
||||
void
|
||||
fetch_inferior_registers (int regno)
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_state inferior_fp_registers;
|
||||
|
||||
registers_fetched ();
|
||||
|
||||
ptrace (PTRACE_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) & inferior_registers);
|
||||
ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(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 (int regno)
|
||||
{
|
||||
struct regs inferior_registers;
|
||||
struct fp_state inferior_fp_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, PIDGET (inferior_ptid),
|
||||
(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, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) & inferior_registers);
|
||||
ptrace (PTRACE_POKEDATA, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) stack, 0xc589);
|
||||
ptrace (PTRACE_SINGLESTEP, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) stack, 0);
|
||||
wait (0);
|
||||
ptrace (PTRACE_POKEDATA, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) stack, stuff);
|
||||
inferior_registers.r_reg[EAX] = reg;
|
||||
}
|
||||
#endif
|
||||
ptrace (PTRACE_SETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) & inferior_registers);
|
||||
ptrace (PTRACE_SETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_ARG3_TYPE) & inferior_fp_registers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Provide registers to GDB from a core file.
|
||||
|
||||
CORE_REG_SECT points to an array of bytes, which were obtained from
|
||||
a core file which BFD thinks might contain register contents.
|
||||
CORE_REG_SIZE is its size.
|
||||
|
||||
WHICH says which register set corelow suspects this is:
|
||||
0 --- the general-purpose register set
|
||||
2 --- the floating-point register set
|
||||
|
||||
REG_ADDR isn't used. */
|
||||
|
||||
static void
|
||||
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
memcpy (registers, core_reg_sect, core_reg_size);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||||
core_reg_sect,
|
||||
core_reg_size); /* FIXME, probably bogus */
|
||||
#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, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_i386mach (void)
|
||||
{
|
||||
add_core_fns (&i386mach_core_fns);
|
||||
}
|
@ -1,289 +0,0 @@
|
||||
/* Intel 386 native support for SYSV systems (pre-SVR4).
|
||||
|
||||
Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
|
||||
1999, 2000, 2002 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_PTRACE_H
|
||||
#include <ptrace.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_PTRACE_H
|
||||
#include <sys/ptrace.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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>
|
||||
|
||||
|
||||
/* FIXME: 1998-10-21/jsm: The following used to be just "#include
|
||||
<sys/debugreg.h>", but the the Linux kernel (version 2.1.x) and
|
||||
glibc 2.0.x are not in sync; including <sys/debugreg.h> will result
|
||||
in an error. With luck, these losers will get their act together
|
||||
and we can trash this hack in the near future. */
|
||||
|
||||
#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
|
||||
#ifdef HAVE_ASM_DEBUGREG_H
|
||||
#include <asm/debugreg.h>
|
||||
#else
|
||||
#include <sys/debugreg.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/file.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#ifdef HAVE_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 (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 (void)
|
||||
{
|
||||
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 (int, CORE_ADDR, CORE_ADDR, int, int);
|
||||
|
||||
static int
|
||||
i386_insert_nonaligned_watchpoint (int, CORE_ADDR, CORE_ADDR, int, int);
|
||||
|
||||
/* Insert a watchpoint. */
|
||||
|
||||
int
|
||||
i386_insert_watchpoint (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 (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 : DR_RW_WRITE;
|
||||
|
||||
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 (int pid, CORE_ADDR waddr, CORE_ADDR addr,
|
||||
int len, int rw)
|
||||
{
|
||||
int align;
|
||||
int size;
|
||||
int rv;
|
||||
|
||||
static int size_try_array[4][4] =
|
||||
{
|
||||
{ 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 = size_try_array[len > 4 ? 3 : len - 1][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 (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 (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 */
|
@ -1,184 +0,0 @@
|
||||
/* Native-dependent code for SVR4 Unix running on i386's, for GDB.
|
||||
Copyright 1988, 1989, 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
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 "value.h"
|
||||
#include "inferior.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#ifdef HAVE_SYS_REG_H
|
||||
#include <sys/reg.h>
|
||||
#endif
|
||||
#include "i387-nat.h"
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_PROCFS_H
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.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,
|
||||
};
|
||||
|
||||
/* Prototypes for local functions */
|
||||
|
||||
void fill_gregset (gregset_t *, int);
|
||||
|
||||
void supply_gregset (gregset_t *);
|
||||
|
||||
void supply_fpregset (fpregset_t *);
|
||||
|
||||
void fill_fpregset (fpregset_t *, int);
|
||||
|
||||
|
||||
/* 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 (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 (gregset_t *gregsetp, int regno)
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
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 (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. */
|
||||
|
||||
/* FIXME: Assumes that fpregsetp contains an i387 FSAVE area. */
|
||||
#if !defined(FPREGSET_FSAVE_OFFSET)
|
||||
#define FPREGSET_FSAVE_OFFSET 0
|
||||
#endif
|
||||
|
||||
void
|
||||
supply_fpregset (fpregset_t *fpregsetp)
|
||||
{
|
||||
if (NUM_FREGS == 0)
|
||||
return;
|
||||
|
||||
i387_supply_fsave ((char *) fpregsetp + FPREGSET_FSAVE_OFFSET);
|
||||
}
|
||||
|
||||
/* 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 (fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
if (NUM_FREGS == 0)
|
||||
return;
|
||||
|
||||
i387_fill_fsave ((char *) fpregsetp + FPREGSET_FSAVE_OFFSET, regno);
|
||||
}
|
||||
|
||||
#endif /* defined (HAVE_FPREGSET_T) */
|
||||
|
||||
#endif /* HAVE_SYS_PROCFS_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,601 +0,0 @@
|
||||
/* Definitions and macros for support of AMD's remote debugger, MiniMON.
|
||||
Copyright 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;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,254 +0,0 @@
|
||||
/* Definitions for remote debugging interface for ROM monitors.
|
||||
Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MONITOR_H
|
||||
#define MONITOR_H
|
||||
|
||||
struct serial;
|
||||
|
||||
/* 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. If NULL, monitor implementation
|
||||
sets its own to_insert_breakpoint method. */
|
||||
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) (char *name, int namelen, char *val, int vallen);
|
||||
void (*load_routine) (struct serial *desc, char *file,
|
||||
int hashmark); /* Download routine */
|
||||
int (*dumpregs) (void); /* routine to dump all registers */
|
||||
int (*continue_hook) (void); /* Emit the continue command */
|
||||
int (*wait_filter) (char *buf, /* Maybe contains registers */
|
||||
int bufmax,
|
||||
int *response_length,
|
||||
struct target_waitstatus * status);
|
||||
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 num_breakpoints; /* If set_break != NULL, number of supported
|
||||
breakpoints */
|
||||
int magic; /* Check value */
|
||||
};
|
||||
|
||||
/* The monitor ops magic number, used to detect if an ops structure doesn't
|
||||
have the right number of entries filled in. */
|
||||
|
||||
#define MONITOR_OPS_MAGIC 600925
|
||||
|
||||
/* Flag definitions. */
|
||||
|
||||
/* If set, then clear breakpoint command uses address, otherwise it
|
||||
uses an index returned by the monitor. */
|
||||
|
||||
#define MO_CLR_BREAK_USES_ADDR 0x1
|
||||
|
||||
/* If set, then memory fill command uses STARTADDR, ENDADDR+1, VALUE
|
||||
as args, else it uses STARTADDR, LENGTH, VALUE as args. */
|
||||
|
||||
#define MO_FILL_USES_ADDR 0x2
|
||||
|
||||
/* If set, then monitor doesn't automatically supply register dump
|
||||
when coming back after a continue. */
|
||||
|
||||
#define MO_NEED_REGDUMP_AFTER_CONT 0x4
|
||||
|
||||
/* getmem needs start addr and end addr */
|
||||
|
||||
#define MO_GETMEM_NEEDS_RANGE 0x8
|
||||
|
||||
/* getmem can only read one loc at a time */
|
||||
|
||||
#define MO_GETMEM_READ_SINGLE 0x10
|
||||
|
||||
/* handle \r\n combinations */
|
||||
|
||||
#define MO_HANDLE_NL 0x20
|
||||
|
||||
/* don't expect echos in monitor_open */
|
||||
|
||||
#define MO_NO_ECHO_ON_OPEN 0x40
|
||||
|
||||
/* If set, send break to stop monitor */
|
||||
|
||||
#define MO_SEND_BREAK_ON_STOP 0x80
|
||||
|
||||
/* If set, target sends an ACK after each S-record */
|
||||
|
||||
#define MO_SREC_ACK 0x100
|
||||
|
||||
/* Allow 0x prefix on addresses retured from monitor */
|
||||
|
||||
#define MO_HEX_PREFIX 0x200
|
||||
|
||||
/* Some monitors require a different command when starting a program */
|
||||
|
||||
#define MO_RUN_FIRST_TIME 0x400
|
||||
|
||||
/* Don't expect echos when getting memory */
|
||||
|
||||
#define MO_NO_ECHO_ON_SETMEM 0x800
|
||||
|
||||
/* If set, then register store command expects value BEFORE regname */
|
||||
|
||||
#define MO_REGISTER_VALUE_FIRST 0x1000
|
||||
|
||||
/* If set, then the monitor displays registers as pairs. */
|
||||
|
||||
#define MO_32_REGS_PAIRED 0x2000
|
||||
|
||||
/* If set, then register setting happens interactively. */
|
||||
|
||||
#define MO_SETREG_INTERACTIVE 0x4000
|
||||
|
||||
/* If set, then memory setting happens interactively. */
|
||||
|
||||
#define MO_SETMEM_INTERACTIVE 0x8000
|
||||
|
||||
/* If set, then memory dumps are always on 16-byte boundaries, even
|
||||
when less is desired. */
|
||||
|
||||
#define MO_GETMEM_16_BOUNDARY 0x10000
|
||||
|
||||
/* If set, then the monitor numbers its breakpoints starting from 1. */
|
||||
|
||||
#define MO_CLR_BREAK_1_BASED 0x20000
|
||||
|
||||
/* If set, then the monitor acks srecords with a plus sign. */
|
||||
|
||||
#define MO_SREC_ACK_PLUS 0x40000
|
||||
|
||||
/* If set, then the monitor "acks" srecords with rotating lines. */
|
||||
|
||||
#define MO_SREC_ACK_ROTATE 0x80000
|
||||
|
||||
/* If set, then remove useless address bits from memory addresses. */
|
||||
|
||||
#define MO_ADDR_BITS_REMOVE 0x100000
|
||||
|
||||
/* If set, then display target program output if prefixed by ^O. */
|
||||
|
||||
#define MO_PRINT_PROGRAM_OUTPUT 0x200000
|
||||
|
||||
/* Some dump bytes commands align the first data with the preceeding
|
||||
16 byte boundary. Some print blanks and start at the exactly the
|
||||
requested boundary. */
|
||||
|
||||
#define MO_EXACT_DUMPADDR 0x400000
|
||||
|
||||
/* Rather entering and exiting the write memory dialog for each word byte,
|
||||
we can save time by transferring the whole block without exiting
|
||||
the memory editing mode. You only need to worry about this
|
||||
if you are doing memory downloading.
|
||||
This engages a new write function registered with dcache.
|
||||
*/
|
||||
#define MO_HAS_BLOCKWRITES 0x800000
|
||||
|
||||
#define SREC_SIZE 160
|
||||
|
||||
extern void monitor_open (char *args, struct monitor_ops *ops, int from_tty);
|
||||
extern void monitor_close (int quitting);
|
||||
extern char *monitor_supply_register (int regno, char *valstr);
|
||||
extern int monitor_expect (char *prompt, char *buf, int buflen);
|
||||
extern int monitor_expect_prompt (char *buf, int buflen);
|
||||
extern void monitor_printf (char *, ...) ATTR_FORMAT (printf, 1, 2);
|
||||
extern void
|
||||
monitor_printf_noecho (char *, ...)
|
||||
ATTR_FORMAT (printf, 1, 2);
|
||||
extern void monitor_write (char *buf, int buflen);
|
||||
extern int monitor_readchar (void);
|
||||
extern char *monitor_get_dev_name (void);
|
||||
extern void init_monitor_ops (struct target_ops *);
|
||||
extern int monitor_dump_reg_block (char *dump_cmd);
|
||||
|
||||
#endif
|
@ -1,938 +0,0 @@
|
||||
/* Handle OSF/1 shared libraries for GDB, the GNU Debugger.
|
||||
Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000
|
||||
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 "gdb_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 (CORE_ADDR, char *, int, int);
|
||||
|
||||
static int
|
||||
ldr_read_memory (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);
|
||||
xfree (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 (int, int); /* In libiberty */
|
||||
|
||||
/* Local function prototypes */
|
||||
|
||||
static void sharedlibrary_command (char *, int);
|
||||
|
||||
static void info_sharedlibrary_command (char *, int);
|
||||
|
||||
static int symbol_add_stub (char *);
|
||||
|
||||
static struct so_list *find_solib (struct so_list *);
|
||||
|
||||
static struct link_map *first_link_map_member (void);
|
||||
|
||||
static struct link_map *next_link_map_member (struct so_list *);
|
||||
|
||||
static void xfer_link_map_member (struct so_list *, struct link_map *);
|
||||
|
||||
static int solib_map_sections (char *);
|
||||
|
||||
/*
|
||||
|
||||
LOCAL FUNCTION
|
||||
|
||||
solib_map_sections -- open bfd and build sections for shared lib
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
static int 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 int
|
||||
solib_map_sections (char *arg)
|
||||
{
|
||||
struct so_list *so = (struct so_list *) arg; /* catch_errors bogon */
|
||||
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 (xfree, 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 = 1;
|
||||
|
||||
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);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
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 (void)
|
||||
{
|
||||
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 (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 (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);
|
||||
xfree (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);
|
||||
xfree (buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
catch_errors (solib_map_sections, (char *) so_list_ptr,
|
||||
"Error while mapping shared library sections:\n",
|
||||
RETURN_MASK_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
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 (struct so_list *so_list_ptr)
|
||||
{
|
||||
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 (char *arg)
|
||||
{
|
||||
register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
|
||||
CORE_ADDR text_addr = 0;
|
||||
struct section_addr_info section_addrs;
|
||||
|
||||
memset (§ion_addrs, 0, sizeof (section_addrs));
|
||||
if (so->textsection)
|
||||
text_addr = so->textsection->addr;
|
||||
else if (so->abfd != NULL)
|
||||
{
|
||||
asection *lowest_sect;
|
||||
|
||||
/* If we didn't find a mapped non zero sized .text section, set up
|
||||
text_addr so that the relocation in symbol_file_add does no harm. */
|
||||
|
||||
lowest_sect = bfd_get_section_by_name (so->abfd, ".text");
|
||||
if (lowest_sect == NULL)
|
||||
bfd_map_over_sections (so->abfd, find_lowest_section,
|
||||
(PTR) &lowest_sect);
|
||||
if (lowest_sect)
|
||||
text_addr = bfd_section_vma (so->abfd, lowest_sect) + LM_OFFSET (so);
|
||||
}
|
||||
|
||||
section_addrs.other[0].addr = text_addr;
|
||||
section_addrs.other[0].name = ".text";
|
||||
so->objfile = symbol_file_add (so->so_name, so->from_tty,
|
||||
§ion_addrs, 0, OBJF_SHARED);
|
||||
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, int readsyms)
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
|
||||
{
|
||||
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 (!readsyms)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
/* Add these section table entries to the target's table. */
|
||||
|
||||
old = target_resize_to_sections (target, count);
|
||||
|
||||
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 (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 executable 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 (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 (void)
|
||||
{
|
||||
struct so_list *next;
|
||||
char *bfd_filename;
|
||||
|
||||
disable_breakpoints_in_shlibs (1);
|
||||
|
||||
while (so_list_head)
|
||||
{
|
||||
if (so_list_head->sections)
|
||||
{
|
||||
xfree (so_list_head->sections);
|
||||
}
|
||||
if (so_list_head->abfd)
|
||||
{
|
||||
remove_target_sections (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)
|
||||
xfree (bfd_filename);
|
||||
xfree (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 (void)
|
||||
{
|
||||
|
||||
/* 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 (minus_one_ptid, 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. */
|
||||
solib_add ((char *) 0, 0, (struct target_ops *) 0, auto_solib_add);
|
||||
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 (char *args, int from_tty)
|
||||
{
|
||||
dont_repeat ();
|
||||
solib_add (args, from_tty, (struct target_ops *) 0, 1);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_solib (void)
|
||||
{
|
||||
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_boolean,
|
||||
(char *) &auto_solib_add,
|
||||
"Set autoloading of shared library symbols.\n\
|
||||
If \"on\", symbols from all shared object libraries will be loaded\n\
|
||||
automatically when the inferior begins execution, when the dynamic linker\n\
|
||||
informs gdb that a new library has been loaded, or when attaching to the\n\
|
||||
inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
/* Remote debugging interface for PPCbug (PowerPC) Rom monitor
|
||||
for GDB, the GNU debugger.
|
||||
Copyright 1995, 1998, 1999, 2000, 2001 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"
|
||||
#include "regcache.h"
|
||||
|
||||
static void
|
||||
ppcbug_supply_register (char *regname, int regnamelen, char *val, int vallen)
|
||||
{
|
||||
int regno = 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[] =
|
||||
{
|
||||
"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};
|
||||
|
||||
static void
|
||||
init_ppc_cmds (char *LOAD_CMD,
|
||||
struct monitor_ops *OPS,
|
||||
struct target_ops *targops)
|
||||
{
|
||||
OPS->flags = MO_CLR_BREAK_USES_ADDR | MO_HANDLE_NL;
|
||||
OPS->init = ppcbug_inits; /* Init strings */
|
||||
OPS->cont = "g\r"; /* continue command */
|
||||
OPS->step = "t\r"; /* single step */
|
||||
OPS->stop = NULL; /* interrupt command */
|
||||
OPS->set_break = "br %x\r"; /* set a breakpoint */
|
||||
OPS->clr_break = "nobr %x\r"; /* clear a breakpoint */
|
||||
OPS->clr_all_break = "nobr\r"; /* clear all breakpoints */
|
||||
OPS->fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
|
||||
OPS->setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
|
||||
OPS->setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
|
||||
OPS->setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
|
||||
OPS->setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
|
||||
OPS->setmem.resp_delim = NULL; /* setreg.resp_delim */
|
||||
OPS->setmem.term = NULL; /* setreg.term */
|
||||
OPS->setmem.term_cmd = NULL; /* setreg.term_cmd */
|
||||
OPS->getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
|
||||
OPS->getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
|
||||
OPS->getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
|
||||
OPS->getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
|
||||
OPS->getmem.resp_delim = " "; /* getmem.resp_delim */
|
||||
OPS->getmem.term = NULL; /* getmem.term */
|
||||
OPS->getmem.term_cmd = NULL; /* getmem.term_cmd */
|
||||
OPS->setreg.cmd = "rs %s %x\r"; /* setreg.cmd (name, value) */
|
||||
OPS->setreg.resp_delim = NULL; /* setreg.resp_delim */
|
||||
OPS->setreg.term = NULL; /* setreg.term */
|
||||
OPS->setreg.term_cmd = NULL; /* setreg.term_cmd */
|
||||
OPS->getreg.cmd = "rs %s\r"; /* getreg.cmd (name) */
|
||||
OPS->getreg.resp_delim = "="; /* getreg.resp_delim */
|
||||
OPS->getreg.term = NULL; /* getreg.term */
|
||||
OPS->getreg.term_cmd = NULL; /* getreg.term_cmd */
|
||||
OPS->register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
|
||||
OPS->supply_register = ppcbug_supply_register; /* supply_register */
|
||||
OPS->dump_registers = "rd\r"; /* dump all registers */
|
||||
OPS->load_routine = NULL; /* load_routine (defaults to SRECs) */
|
||||
OPS->load = LOAD_CMD; /* download command */
|
||||
OPS->loadresp = NULL; /* load response */
|
||||
OPS->prompt = "PPC1-Bug>"; /* monitor command prompt */
|
||||
OPS->line_term = "\r"; /* end-of-line terminator */
|
||||
OPS->cmd_end = NULL; /* optional command terminator */
|
||||
OPS->target = targops; /* target operations */
|
||||
OPS->stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
|
||||
OPS->regnames = ppcbug_regnames; /* registers names */
|
||||
OPS->magic = MONITOR_OPS_MAGIC; /* magic */
|
||||
}
|
||||
|
||||
|
||||
static struct monitor_ops ppcbug_cmds0;
|
||||
static struct monitor_ops ppcbug_cmds1;
|
||||
|
||||
static void
|
||||
ppcbug_open0 (char *args, int from_tty)
|
||||
{
|
||||
monitor_open (args, &ppcbug_cmds0, from_tty);
|
||||
}
|
||||
|
||||
static void
|
||||
ppcbug_open1 (char *args, int from_tty)
|
||||
{
|
||||
monitor_open (args, &ppcbug_cmds1, from_tty);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_ppcbug_rom (void)
|
||||
{
|
||||
init_ppc_cmds ("lo 0\r", &ppcbug_cmds0, &ppcbug_ops0);
|
||||
init_ppc_cmds ("lo 1\r", &ppcbug_cmds1, &ppcbug_ops1);
|
||||
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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,941 +0,0 @@
|
||||
/* Generic remote debugging interface for simulators.
|
||||
|
||||
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002 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 "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 "callback.h"
|
||||
#include "remote-sim.h"
|
||||
#include "remote-utils.h"
|
||||
#include "command.h"
|
||||
#include "regcache.h"
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
extern void _initialize_remote_sim (void);
|
||||
|
||||
extern int (*ui_loop_hook) (int signo);
|
||||
|
||||
static void dump_mem (char *buf, int len);
|
||||
|
||||
static void init_callbacks (void);
|
||||
|
||||
static void end_callbacks (void);
|
||||
|
||||
static int gdb_os_write_stdout (host_callback *, const char *, int);
|
||||
|
||||
static void gdb_os_flush_stdout (host_callback *);
|
||||
|
||||
static int gdb_os_write_stderr (host_callback *, const char *, int);
|
||||
|
||||
static void gdb_os_flush_stderr (host_callback *);
|
||||
|
||||
static int gdb_os_poll_quit (host_callback *);
|
||||
|
||||
/* printf_filtered is depreciated */
|
||||
static void gdb_os_printf_filtered (host_callback *, const char *, ...);
|
||||
|
||||
static void gdb_os_vprintf_filtered (host_callback *, const char *, va_list);
|
||||
|
||||
static void gdb_os_evprintf_filtered (host_callback *, const char *, va_list);
|
||||
|
||||
static void gdb_os_error (host_callback *, const char *, ...);
|
||||
|
||||
static void gdbsim_fetch_register (int regno);
|
||||
|
||||
static void gdbsim_store_register (int regno);
|
||||
|
||||
static void gdbsim_kill (void);
|
||||
|
||||
static void gdbsim_load (char *prog, int fromtty);
|
||||
|
||||
static void gdbsim_create_inferior (char *exec_file, char *args, char **env);
|
||||
|
||||
static void gdbsim_open (char *args, int from_tty);
|
||||
|
||||
static void gdbsim_close (int quitting);
|
||||
|
||||
static void gdbsim_detach (char *args, int from_tty);
|
||||
|
||||
static void gdbsim_resume (ptid_t ptid, int step, enum target_signal siggnal);
|
||||
|
||||
static ptid_t gdbsim_wait (ptid_t ptid, struct target_waitstatus *status);
|
||||
|
||||
static void gdbsim_prepare_to_store (void);
|
||||
|
||||
static int gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr,
|
||||
int len, int write,
|
||||
struct mem_attrib *attrib,
|
||||
struct target_ops *target);
|
||||
|
||||
static void gdbsim_files_info (struct target_ops *target);
|
||||
|
||||
static void gdbsim_mourn_inferior (void);
|
||||
|
||||
static void gdbsim_stop (void);
|
||||
|
||||
void simulator_command (char *args, int from_tty);
|
||||
|
||||
/* Naming convention:
|
||||
|
||||
sim_* are the interface to the simulator (see remote-sim.h).
|
||||
gdbsim_* are stuff which is internal to gdb. */
|
||||
|
||||
/* Forward data declarations */
|
||||
extern struct target_ops gdbsim_ops;
|
||||
|
||||
static int program_loaded = 0;
|
||||
|
||||
/* We must keep track of whether the simulator has been opened or not because
|
||||
GDB can call a target's close routine twice, but sim_close doesn't allow
|
||||
this. We also need to record the result of sim_open so we can pass it
|
||||
back to the other sim_foo routines. */
|
||||
static SIM_DESC gdbsim_desc = 0;
|
||||
|
||||
static void
|
||||
dump_mem (char *buf, int len)
|
||||
{
|
||||
if (len <= 8)
|
||||
{
|
||||
if (len == 8 || len == 4)
|
||||
{
|
||||
long l[2];
|
||||
memcpy (l, buf, len);
|
||||
printf_filtered ("\t0x%lx", l[0]);
|
||||
if (len == 8)
|
||||
printf_filtered (" 0x%lx", l[1]);
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
printf_filtered ("\t");
|
||||
for (i = 0; i < len; i++)
|
||||
printf_filtered ("0x%x ", buf[i]);
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static host_callback gdb_callback;
|
||||
static int callbacks_initialized = 0;
|
||||
|
||||
/* Initialize gdb_callback. */
|
||||
|
||||
static void
|
||||
init_callbacks (void)
|
||||
{
|
||||
if (!callbacks_initialized)
|
||||
{
|
||||
gdb_callback = default_callback;
|
||||
gdb_callback.init (&gdb_callback);
|
||||
gdb_callback.write_stdout = gdb_os_write_stdout;
|
||||
gdb_callback.flush_stdout = gdb_os_flush_stdout;
|
||||
gdb_callback.write_stderr = gdb_os_write_stderr;
|
||||
gdb_callback.flush_stderr = gdb_os_flush_stderr;
|
||||
gdb_callback.printf_filtered = gdb_os_printf_filtered;
|
||||
gdb_callback.vprintf_filtered = gdb_os_vprintf_filtered;
|
||||
gdb_callback.evprintf_filtered = gdb_os_evprintf_filtered;
|
||||
gdb_callback.error = gdb_os_error;
|
||||
gdb_callback.poll_quit = gdb_os_poll_quit;
|
||||
gdb_callback.magic = HOST_CALLBACK_MAGIC;
|
||||
callbacks_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release callbacks (free resources used by them). */
|
||||
|
||||
static void
|
||||
end_callbacks (void)
|
||||
{
|
||||
if (callbacks_initialized)
|
||||
{
|
||||
gdb_callback.shutdown (&gdb_callback);
|
||||
callbacks_initialized = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* GDB version of os_write_stdout callback. */
|
||||
|
||||
static int
|
||||
gdb_os_write_stdout (host_callback *p, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
char b[2];
|
||||
|
||||
ui_file_write (gdb_stdtarg, buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* GDB version of os_flush_stdout callback. */
|
||||
|
||||
static void
|
||||
gdb_os_flush_stdout (host_callback *p)
|
||||
{
|
||||
gdb_flush (gdb_stdtarg);
|
||||
}
|
||||
|
||||
/* GDB version of os_write_stderr callback. */
|
||||
|
||||
static int
|
||||
gdb_os_write_stderr (host_callback *p, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
char b[2];
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
b[0] = buf[i];
|
||||
b[1] = 0;
|
||||
fputs_unfiltered (b, gdb_stdtarg);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* GDB version of os_flush_stderr callback. */
|
||||
|
||||
static void
|
||||
gdb_os_flush_stderr (host_callback *p)
|
||||
{
|
||||
gdb_flush (gdb_stderr);
|
||||
}
|
||||
|
||||
/* GDB version of printf_filtered callback. */
|
||||
|
||||
static void
|
||||
gdb_os_printf_filtered (host_callback * p, const char *format,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
|
||||
vfprintf_filtered (gdb_stdout, format, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/* GDB version of error vprintf_filtered. */
|
||||
|
||||
static void
|
||||
gdb_os_vprintf_filtered (host_callback * p, const char *format, va_list ap)
|
||||
{
|
||||
vfprintf_filtered (gdb_stdout, format, ap);
|
||||
}
|
||||
|
||||
/* GDB version of error evprintf_filtered. */
|
||||
|
||||
static void
|
||||
gdb_os_evprintf_filtered (host_callback * p, const char *format, va_list ap)
|
||||
{
|
||||
vfprintf_filtered (gdb_stderr, format, ap);
|
||||
}
|
||||
|
||||
/* GDB version of error callback. */
|
||||
|
||||
static void
|
||||
gdb_os_error (host_callback * p, const char *format,...)
|
||||
{
|
||||
if (error_hook)
|
||||
(*error_hook) ();
|
||||
else
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
verror (format, args);
|
||||
va_end (args);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdbsim_fetch_register (int regno)
|
||||
{
|
||||
static int warn_user = 1;
|
||||
if (regno == -1)
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
gdbsim_fetch_register (regno);
|
||||
}
|
||||
else if (REGISTER_NAME (regno) != NULL
|
||||
&& *REGISTER_NAME (regno) != '\0')
|
||||
{
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int nr_bytes;
|
||||
if (REGISTER_SIM_REGNO (regno) >= 0)
|
||||
nr_bytes = sim_fetch_register (gdbsim_desc,
|
||||
REGISTER_SIM_REGNO (regno),
|
||||
buf, REGISTER_RAW_SIZE (regno));
|
||||
else
|
||||
nr_bytes = 0;
|
||||
if (nr_bytes == 0)
|
||||
/* register not applicable, supply zero's */
|
||||
memset (buf, 0, MAX_REGISTER_RAW_SIZE);
|
||||
else if (nr_bytes > 0 && nr_bytes != REGISTER_RAW_SIZE (regno)
|
||||
&& warn_user)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stderr,
|
||||
"Size of register %s (%d/%d) incorrect (%d instead of %d))",
|
||||
REGISTER_NAME (regno),
|
||||
regno, REGISTER_SIM_REGNO (regno),
|
||||
nr_bytes, REGISTER_RAW_SIZE (regno));
|
||||
warn_user = 0;
|
||||
}
|
||||
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 (int regno)
|
||||
{
|
||||
if (regno == -1)
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
gdbsim_store_register (regno);
|
||||
}
|
||||
else if (REGISTER_NAME (regno) != NULL
|
||||
&& *REGISTER_NAME (regno) != '\0'
|
||||
&& REGISTER_SIM_REGNO (regno) >= 0)
|
||||
{
|
||||
char tmp[MAX_REGISTER_RAW_SIZE];
|
||||
int nr_bytes;
|
||||
read_register_gen (regno, tmp);
|
||||
nr_bytes = sim_store_register (gdbsim_desc,
|
||||
REGISTER_SIM_REGNO (regno),
|
||||
tmp, REGISTER_RAW_SIZE (regno));
|
||||
if (nr_bytes > 0 && nr_bytes != REGISTER_RAW_SIZE (regno))
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"Register size different to expected");
|
||||
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 (void)
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_kill\n");
|
||||
|
||||
/* There is no need to `kill' running simulator - the simulator is
|
||||
not running */
|
||||
inferior_ptid = null_ptid;
|
||||
}
|
||||
|
||||
/* 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 (char *prog, int fromtty)
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_load: prog \"%s\"\n", prog);
|
||||
|
||||
inferior_ptid = null_ptid;
|
||||
|
||||
/* FIXME: We will print two messages on error.
|
||||
Need error to either not print anything if passed NULL or need
|
||||
another routine that doesn't take any arguments. */
|
||||
if (sim_load (gdbsim_desc, prog, NULL, fromtty) == SIM_RC_FAIL)
|
||||
error ("unable to load program");
|
||||
|
||||
/* FIXME: If a load command should reset the targets registers then
|
||||
a call to sim_create_inferior() should go here. */
|
||||
|
||||
program_loaded = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Start an inferior process and set inferior_ptid to its pid.
|
||||
EXEC_FILE is the file to run.
|
||||
ARGS 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 (char *exec_file, char *args, char **env)
|
||||
{
|
||||
int len;
|
||||
char *arg_buf, **argv;
|
||||
|
||||
if (exec_file == 0 || exec_bfd == 0)
|
||||
warning ("No executable file specified.");
|
||||
if (!program_loaded)
|
||||
warning ("No program loaded.");
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_create_inferior: exec_file \"%s\", args \"%s\"\n",
|
||||
(exec_file ? exec_file : "(NULL)"),
|
||||
args);
|
||||
|
||||
gdbsim_kill ();
|
||||
remove_breakpoints ();
|
||||
init_wait_for_inferior ();
|
||||
|
||||
if (exec_file != NULL)
|
||||
{
|
||||
len = 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 (argv);
|
||||
}
|
||||
else
|
||||
argv = NULL;
|
||||
sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
|
||||
|
||||
inferior_ptid = pid_to_ptid (42);
|
||||
insert_breakpoints (); /* Needed to get correct instruction in cache */
|
||||
|
||||
clear_proceed_status ();
|
||||
|
||||
/* NB: Entry point already set by sim_create_inferior. */
|
||||
proceed ((CORE_ADDR) -1, 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 (char *args, int from_tty)
|
||||
{
|
||||
int len;
|
||||
char *arg_buf;
|
||||
char **argv;
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_open: args \"%s\"\n", args ? args : "(null)");
|
||||
|
||||
/* Remove current simulator if one exists. Only do this if the simulator
|
||||
has been opened because sim_close requires it.
|
||||
This is important because the call to push_target below will cause
|
||||
sim_close to be called if the simulator is already open, but push_target
|
||||
is called after sim_open! We can't move the call to push_target before
|
||||
the call to sim_open because sim_open may invoke `error'. */
|
||||
if (gdbsim_desc != NULL)
|
||||
unpush_target (&gdbsim_ops);
|
||||
|
||||
len = (7 + 1 /* gdbsim */
|
||||
+ strlen (" -E little")
|
||||
+ strlen (" --architecture=xxxxxxxxxx")
|
||||
+ (args ? strlen (args) : 0)
|
||||
+ 50) /* slack */ ;
|
||||
arg_buf = (char *) alloca (len);
|
||||
strcpy (arg_buf, "gdbsim"); /* 7 */
|
||||
/* Specify the byte order for the target when it is both selectable
|
||||
and explicitly specified by the user (not auto detected). */
|
||||
if (!TARGET_BYTE_ORDER_AUTO)
|
||||
{
|
||||
switch (TARGET_BYTE_ORDER)
|
||||
{
|
||||
case BFD_ENDIAN_BIG:
|
||||
strcat (arg_buf, " -E big");
|
||||
break;
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
strcat (arg_buf, " -E little");
|
||||
break;
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"Value of TARGET_BYTE_ORDER unknown");
|
||||
}
|
||||
}
|
||||
/* Specify the architecture of the target when it has been
|
||||
explicitly specified */
|
||||
if (!TARGET_ARCHITECTURE_AUTO)
|
||||
{
|
||||
strcat (arg_buf, " --architecture=");
|
||||
strcat (arg_buf, TARGET_ARCHITECTURE->printable_name);
|
||||
}
|
||||
/* finally, any explicit args */
|
||||
if (args)
|
||||
{
|
||||
strcat (arg_buf, " "); /* 1 */
|
||||
strcat (arg_buf, args);
|
||||
}
|
||||
argv = buildargv (arg_buf);
|
||||
if (argv == NULL)
|
||||
error ("Insufficient memory available to allocate simulator arg list.");
|
||||
make_cleanup_freeargv (argv);
|
||||
|
||||
init_callbacks ();
|
||||
gdbsim_desc = sim_open (SIM_OPEN_DEBUG, &gdb_callback, exec_bfd, argv);
|
||||
|
||||
if (gdbsim_desc == 0)
|
||||
error ("unable to create simulator instance");
|
||||
|
||||
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 (int quitting)
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_close: quitting %d\n", quitting);
|
||||
|
||||
program_loaded = 0;
|
||||
|
||||
if (gdbsim_desc != NULL)
|
||||
{
|
||||
sim_close (gdbsim_desc, quitting);
|
||||
gdbsim_desc = NULL;
|
||||
}
|
||||
|
||||
end_callbacks ();
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
||||
/* 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 (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 enum target_signal resume_siggnal;
|
||||
static int resume_step;
|
||||
|
||||
static void
|
||||
gdbsim_resume (ptid_t ptid, int step, enum target_signal siggnal)
|
||||
{
|
||||
if (PIDGET (inferior_ptid) != 42)
|
||||
error ("The program is not being run.");
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_resume: step %d, signal %d\n", step, siggnal);
|
||||
|
||||
resume_siggnal = siggnal;
|
||||
resume_step = step;
|
||||
}
|
||||
|
||||
/* Notify the simulator of an asynchronous request to stop.
|
||||
|
||||
The simulator shall ensure that the stop request is eventually
|
||||
delivered to the simulator. If the call is made while the
|
||||
simulator is not running then the stop request is processed when
|
||||
the simulator is next resumed.
|
||||
|
||||
For simulators that do not support this operation, just abort */
|
||||
|
||||
static void
|
||||
gdbsim_stop (void)
|
||||
{
|
||||
if (!sim_stop (gdbsim_desc))
|
||||
{
|
||||
quit ();
|
||||
}
|
||||
}
|
||||
|
||||
/* GDB version of os_poll_quit callback.
|
||||
Taken from gdb/util.c - should be in a library */
|
||||
|
||||
static int
|
||||
gdb_os_poll_quit (host_callback *p)
|
||||
{
|
||||
if (ui_loop_hook != NULL)
|
||||
ui_loop_hook (0);
|
||||
|
||||
if (quit_flag) /* gdb's idea of quit */
|
||||
{
|
||||
quit_flag = 0; /* we've stolen it */
|
||||
return 1;
|
||||
}
|
||||
else if (immediate_quit)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 void
|
||||
gdbsim_cntrl_c (int signo)
|
||||
{
|
||||
gdbsim_stop ();
|
||||
}
|
||||
|
||||
static ptid_t
|
||||
gdbsim_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||
{
|
||||
static RETSIGTYPE (*prev_sigint) ();
|
||||
int sigrc = 0;
|
||||
enum sim_stop reason = sim_running;
|
||||
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_wait\n");
|
||||
|
||||
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
|
||||
{
|
||||
struct sigaction sa, osa;
|
||||
sa.sa_handler = gdbsim_cntrl_c;
|
||||
sigemptyset (&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction (SIGINT, &sa, &osa);
|
||||
prev_sigint = osa.sa_handler;
|
||||
}
|
||||
#else
|
||||
prev_sigint = signal (SIGINT, gdbsim_cntrl_c);
|
||||
#endif
|
||||
sim_resume (gdbsim_desc, resume_step,
|
||||
target_signal_to_host (resume_siggnal));
|
||||
signal (SIGINT, prev_sigint);
|
||||
resume_step = 0;
|
||||
|
||||
sim_stop_reason (gdbsim_desc, &reason, &sigrc);
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case sim_exited:
|
||||
status->kind = TARGET_WAITKIND_EXITED;
|
||||
status->value.integer = sigrc;
|
||||
break;
|
||||
case sim_stopped:
|
||||
switch (sigrc)
|
||||
{
|
||||
case SIGABRT:
|
||||
quit ();
|
||||
break;
|
||||
case SIGINT:
|
||||
case SIGTRAP:
|
||||
default:
|
||||
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;
|
||||
}
|
||||
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;
|
||||
case sim_running:
|
||||
case sim_polling:
|
||||
/* FIXME: Is this correct? */
|
||||
break;
|
||||
}
|
||||
|
||||
return inferior_ptid;
|
||||
}
|
||||
|
||||
/* 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 (void)
|
||||
{
|
||||
/* Do nothing, since we can store individual regs */
|
||||
}
|
||||
|
||||
/* Transfer LEN bytes between GDB address MYADDR and target address
|
||||
MEMADDR. If WRITE is non-zero, transfer them to the target,
|
||||
otherwise transfer them from the target. TARGET is unused.
|
||||
|
||||
Returns the number of bytes transferred. */
|
||||
|
||||
static int
|
||||
gdbsim_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
|
||||
int write, struct mem_attrib *attrib,
|
||||
struct target_ops *target)
|
||||
{
|
||||
if (!program_loaded)
|
||||
error ("No program loaded.");
|
||||
|
||||
if (sr_get_debug ())
|
||||
{
|
||||
/* FIXME: Send to something other than STDOUT? */
|
||||
printf_filtered ("gdbsim_xfer_inferior_memory: myaddr 0x");
|
||||
gdb_print_host_address (myaddr, gdb_stdout);
|
||||
printf_filtered (", memaddr 0x%s, len %d, write %d\n",
|
||||
paddr_nz (memaddr), len, write);
|
||||
if (sr_get_debug () && write)
|
||||
dump_mem (myaddr, len);
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
len = sim_write (gdbsim_desc, memaddr, myaddr, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sim_read (gdbsim_desc, memaddr, myaddr, len);
|
||||
if (sr_get_debug () && len > 0)
|
||||
dump_mem (myaddr, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
gdbsim_files_info (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 (gdbsim_desc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the simulator's notion of what the break points are. */
|
||||
|
||||
static void
|
||||
gdbsim_mourn_inferior (void)
|
||||
{
|
||||
if (sr_get_debug ())
|
||||
printf_filtered ("gdbsim_mourn_inferior:\n");
|
||||
|
||||
remove_breakpoints ();
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
||||
static int
|
||||
gdbsim_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
|
||||
{
|
||||
#ifdef SIM_HAS_BREAKPOINTS
|
||||
SIM_RC retcode;
|
||||
|
||||
retcode = sim_set_breakpoint (gdbsim_desc, addr);
|
||||
|
||||
switch (retcode)
|
||||
{
|
||||
case SIM_RC_OK:
|
||||
return 0;
|
||||
case SIM_RC_INSUFFICIENT_RESOURCES:
|
||||
return ENOMEM;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
#else
|
||||
return memory_insert_breakpoint (addr, contents_cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
gdbsim_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
|
||||
{
|
||||
#ifdef SIM_HAS_BREAKPOINTS
|
||||
SIM_RC retcode;
|
||||
|
||||
retcode = sim_clear_breakpoint (gdbsim_desc, addr);
|
||||
|
||||
switch (retcode)
|
||||
{
|
||||
case SIM_RC_OK:
|
||||
case SIM_RC_UNKNOWN_BREAKPOINT:
|
||||
return 0;
|
||||
case SIM_RC_INSUFFICIENT_RESOURCES:
|
||||
return ENOMEM;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
#else
|
||||
return memory_remove_breakpoint (addr, contents_cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pass the command argument through to the simulator verbatim. The
|
||||
simulator must do any command interpretation work. */
|
||||
|
||||
void
|
||||
simulator_command (char *args, int from_tty)
|
||||
{
|
||||
if (gdbsim_desc == NULL)
|
||||
{
|
||||
|
||||
/* PREVIOUSLY: The user may give a command before the simulator
|
||||
is opened. [...] (??? assuming of course one wishes to
|
||||
continue to allow commands to be sent to unopened simulators,
|
||||
which isn't entirely unreasonable). */
|
||||
|
||||
/* The simulator is a builtin abstraction of a remote target.
|
||||
Consistent with that model, access to the simulator, via sim
|
||||
commands, is restricted to the period when the channel to the
|
||||
simulator is open. */
|
||||
|
||||
error ("Not connected to the simulator target");
|
||||
}
|
||||
|
||||
sim_do_command (gdbsim_desc, args);
|
||||
|
||||
/* Invalidate the register cache, in case the simulator command does
|
||||
something funny. */
|
||||
registers_changed ();
|
||||
}
|
||||
|
||||
/* Define the target subroutine names */
|
||||
|
||||
struct target_ops gdbsim_ops;
|
||||
|
||||
static void
|
||||
init_gdbsim_ops (void)
|
||||
{
|
||||
gdbsim_ops.to_shortname = "sim";
|
||||
gdbsim_ops.to_longname = "simulator";
|
||||
gdbsim_ops.to_doc = "Use the compiled-in simulator.";
|
||||
gdbsim_ops.to_open = gdbsim_open;
|
||||
gdbsim_ops.to_close = gdbsim_close;
|
||||
gdbsim_ops.to_attach = NULL;
|
||||
gdbsim_ops.to_post_attach = NULL;
|
||||
gdbsim_ops.to_require_attach = NULL;
|
||||
gdbsim_ops.to_detach = gdbsim_detach;
|
||||
gdbsim_ops.to_require_detach = NULL;
|
||||
gdbsim_ops.to_resume = gdbsim_resume;
|
||||
gdbsim_ops.to_wait = gdbsim_wait;
|
||||
gdbsim_ops.to_post_wait = NULL;
|
||||
gdbsim_ops.to_fetch_registers = gdbsim_fetch_register;
|
||||
gdbsim_ops.to_store_registers = gdbsim_store_register;
|
||||
gdbsim_ops.to_prepare_to_store = gdbsim_prepare_to_store;
|
||||
gdbsim_ops.to_xfer_memory = gdbsim_xfer_inferior_memory;
|
||||
gdbsim_ops.to_files_info = gdbsim_files_info;
|
||||
gdbsim_ops.to_insert_breakpoint = gdbsim_insert_breakpoint;
|
||||
gdbsim_ops.to_remove_breakpoint = gdbsim_remove_breakpoint;
|
||||
gdbsim_ops.to_terminal_init = NULL;
|
||||
gdbsim_ops.to_terminal_inferior = NULL;
|
||||
gdbsim_ops.to_terminal_ours_for_output = NULL;
|
||||
gdbsim_ops.to_terminal_ours = NULL;
|
||||
gdbsim_ops.to_terminal_info = NULL;
|
||||
gdbsim_ops.to_kill = gdbsim_kill;
|
||||
gdbsim_ops.to_load = gdbsim_load;
|
||||
gdbsim_ops.to_lookup_symbol = NULL;
|
||||
gdbsim_ops.to_create_inferior = gdbsim_create_inferior;
|
||||
gdbsim_ops.to_post_startup_inferior = NULL;
|
||||
gdbsim_ops.to_acknowledge_created_inferior = NULL;
|
||||
gdbsim_ops.to_clone_and_follow_inferior = NULL;
|
||||
gdbsim_ops.to_post_follow_inferior_by_clone = NULL;
|
||||
gdbsim_ops.to_insert_fork_catchpoint = NULL;
|
||||
gdbsim_ops.to_remove_fork_catchpoint = NULL;
|
||||
gdbsim_ops.to_insert_vfork_catchpoint = NULL;
|
||||
gdbsim_ops.to_remove_vfork_catchpoint = NULL;
|
||||
gdbsim_ops.to_has_forked = NULL;
|
||||
gdbsim_ops.to_has_vforked = NULL;
|
||||
gdbsim_ops.to_can_follow_vfork_prior_to_exec = NULL;
|
||||
gdbsim_ops.to_post_follow_vfork = NULL;
|
||||
gdbsim_ops.to_insert_exec_catchpoint = NULL;
|
||||
gdbsim_ops.to_remove_exec_catchpoint = NULL;
|
||||
gdbsim_ops.to_has_execd = NULL;
|
||||
gdbsim_ops.to_reported_exec_events_per_exec_call = NULL;
|
||||
gdbsim_ops.to_has_exited = NULL;
|
||||
gdbsim_ops.to_mourn_inferior = gdbsim_mourn_inferior;
|
||||
gdbsim_ops.to_can_run = 0;
|
||||
gdbsim_ops.to_notice_signals = 0;
|
||||
gdbsim_ops.to_thread_alive = 0;
|
||||
gdbsim_ops.to_stop = gdbsim_stop;
|
||||
gdbsim_ops.to_pid_to_exec_file = NULL;
|
||||
gdbsim_ops.to_stratum = process_stratum;
|
||||
gdbsim_ops.DONT_USE = NULL;
|
||||
gdbsim_ops.to_has_all_memory = 1;
|
||||
gdbsim_ops.to_has_memory = 1;
|
||||
gdbsim_ops.to_has_stack = 1;
|
||||
gdbsim_ops.to_has_registers = 1;
|
||||
gdbsim_ops.to_has_execution = 1;
|
||||
gdbsim_ops.to_sections = NULL;
|
||||
gdbsim_ops.to_sections_end = NULL;
|
||||
gdbsim_ops.to_magic = OPS_MAGIC;
|
||||
|
||||
#ifdef TARGET_REDEFINE_DEFAULT_OPS
|
||||
TARGET_REDEFINE_DEFAULT_OPS (&gdbsim_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_remote_sim (void)
|
||||
{
|
||||
init_gdbsim_ops ();
|
||||
add_target (&gdbsim_ops);
|
||||
|
||||
add_com ("sim <command>", class_obscure, simulator_command,
|
||||
"Send a command to the simulator.");
|
||||
}
|
@ -1,837 +0,0 @@
|
||||
/* Remote debugging interface for Tandem ST2000 phone switch, for GDB.
|
||||
|
||||
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000,
|
||||
2001, 2002 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 "gdb_string.h"
|
||||
#include <sys/types.h>
|
||||
#include "serial.h"
|
||||
#include "regcache.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 struct serial *st2000_desc;
|
||||
|
||||
/* Send data to stdebug. Works just like printf. */
|
||||
|
||||
static void
|
||||
printf_stdebug (char *pattern,...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[200];
|
||||
|
||||
va_start (args, pattern);
|
||||
|
||||
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 (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 (char *string, int discard)
|
||||
{
|
||||
char *p = string;
|
||||
int c;
|
||||
|
||||
immediate_quit++;
|
||||
while (1)
|
||||
{
|
||||
c = readchar (timeout);
|
||||
if (c == *p++)
|
||||
{
|
||||
if (*p == '\0')
|
||||
{
|
||||
immediate_quit--;
|
||||
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 (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 (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 (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 (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 (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 executable 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 (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);
|
||||
|
||||
if (serial_setbaudrate (st2000_desc, baudrate))
|
||||
{
|
||||
serial_close (dev_name);
|
||||
perror_with_name (dev_name);
|
||||
}
|
||||
|
||||
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 (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 (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 (ptid_t ptid, int 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 ptid_t
|
||||
st2000_wait (ptid_t ptid, 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 inferior_ptid;
|
||||
}
|
||||
|
||||
/* 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 (int regno)
|
||||
{
|
||||
static char buf[50];
|
||||
const char *p;
|
||||
char *b;
|
||||
|
||||
b = buf;
|
||||
|
||||
for (p = REGISTER_NAME (regno); *p; p++)
|
||||
*b++ = toupper (*p);
|
||||
*b = '\000';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read the remote registers into the block REGS. */
|
||||
|
||||
static void
|
||||
st2000_fetch_registers (void)
|
||||
{
|
||||
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 (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 (void)
|
||||
{
|
||||
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 (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 (void)
|
||||
{
|
||||
/* Do nothing, since we can store individual regs */
|
||||
}
|
||||
|
||||
static void
|
||||
st2000_files_info (void)
|
||||
{
|
||||
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 (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 (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;
|
||||
}
|
||||
|
||||
/* Transfer LEN bytes between GDB address MYADDR and target address
|
||||
MEMADDR. If WRITE is non-zero, transfer them to the target,
|
||||
otherwise transfer them from the target. TARGET is unused.
|
||||
|
||||
Returns the number of bytes transferred. */
|
||||
|
||||
static int
|
||||
st2000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
|
||||
int write, struct mem_attrib *attrib,
|
||||
struct target_ops *target)
|
||||
{
|
||||
if (write)
|
||||
return st2000_write_inferior_memory (memaddr, myaddr, len);
|
||||
else
|
||||
return st2000_read_inferior_memory (memaddr, myaddr, len);
|
||||
}
|
||||
|
||||
static void
|
||||
st2000_kill (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 (void)
|
||||
{
|
||||
remove_breakpoints ();
|
||||
unpush_target (&st2000_ops);
|
||||
generic_mourn_inferior (); /* Do all the proper things now */
|
||||
}
|
||||
|
||||
#define MAX_STDEBUG_BREAKPOINTS 16
|
||||
|
||||
static CORE_ADDR breakaddr[MAX_STDEBUG_BREAKPOINTS] =
|
||||
{0};
|
||||
|
||||
static int
|
||||
st2000_insert_breakpoint (CORE_ADDR addr, char *shadow)
|
||||
{
|
||||
int i;
|
||||
CORE_ADDR bp_addr = addr;
|
||||
int bp_size = 0;
|
||||
|
||||
BREAKPOINT_FROM_PC (&bp_addr, &bp_size);
|
||||
|
||||
for (i = 0; i <= MAX_STDEBUG_BREAKPOINTS; i++)
|
||||
if (breakaddr[i] == 0)
|
||||
{
|
||||
breakaddr[i] = addr;
|
||||
|
||||
st2000_read_inferior_memory (bp_addr, shadow, bp_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 (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 (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 (void)
|
||||
{
|
||||
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 (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 (deprecated_serial_fd (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 (deprecated_serial_fd (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;
|
||||
|
||||
static void
|
||||
init_st2000_ops (void)
|
||||
{
|
||||
st2000_ops.to_shortname = "st2000";
|
||||
st2000_ops.to_longname = "Remote serial Tandem ST2000 target";
|
||||
st2000_ops.to_doc = "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_ops.to_open = st2000_open;
|
||||
st2000_ops.to_close = st2000_close;
|
||||
st2000_ops.to_attach = 0;
|
||||
st2000_run_ops.to_post_attach = NULL;
|
||||
st2000_ops.to_require_attach = NULL;
|
||||
st2000_ops.to_detach = st2000_detach;
|
||||
st2000_ops.to_require_detach = NULL;
|
||||
st2000_ops.to_resume = st2000_resume;
|
||||
st2000_ops.to_wait = st2000_wait;
|
||||
st2000_ops.to_post_wait = NULL;
|
||||
st2000_ops.to_fetch_registers = st2000_fetch_register;
|
||||
st2000_ops.to_store_registers = st2000_store_register;
|
||||
st2000_ops.to_prepare_to_store = st2000_prepare_to_store;
|
||||
st2000_ops.to_xfer_memory = st2000_xfer_inferior_memory;
|
||||
st2000_ops.to_files_info = st2000_files_info;
|
||||
st2000_ops.to_insert_breakpoint = st2000_insert_breakpoint;
|
||||
st2000_ops.to_remove_breakpoint = st2000_remove_breakpoint; /* Breakpoints */
|
||||
st2000_ops.to_terminal_init = 0;
|
||||
st2000_ops.to_terminal_inferior = 0;
|
||||
st2000_ops.to_terminal_ours_for_output = 0;
|
||||
st2000_ops.to_terminal_ours = 0;
|
||||
st2000_ops.to_terminal_info = 0; /* Terminal handling */
|
||||
st2000_ops.to_kill = st2000_kill;
|
||||
st2000_ops.to_load = 0; /* load */
|
||||
st2000_ops.to_lookup_symbol = 0; /* lookup_symbol */
|
||||
st2000_ops.to_create_inferior = st2000_create_inferior;
|
||||
st2000_ops.to_post_startup_inferior = NULL;
|
||||
st2000_ops.to_acknowledge_created_inferior = NULL;
|
||||
st2000_ops.to_clone_and_follow_inferior = NULL;
|
||||
st2000_ops.to_post_follow_inferior_by_clone = NULL;
|
||||
st2000_run_ops.to_insert_fork_catchpoint = NULL;
|
||||
st2000_run_ops.to_remove_fork_catchpoint = NULL;
|
||||
st2000_run_ops.to_insert_vfork_catchpoint = NULL;
|
||||
st2000_run_ops.to_remove_vfork_catchpoint = NULL;
|
||||
st2000_ops.to_has_forked = NULL;
|
||||
st2000_ops.to_has_vforked = NULL;
|
||||
st2000_run_ops.to_can_follow_vfork_prior_to_exec = NULL;
|
||||
st2000_ops.to_post_follow_vfork = NULL;
|
||||
st2000_run_ops.to_insert_exec_catchpoint = NULL;
|
||||
st2000_run_ops.to_remove_exec_catchpoint = NULL;
|
||||
st2000_run_ops.to_has_execd = NULL;
|
||||
st2000_run_ops.to_reported_exec_events_per_exec_call = NULL;
|
||||
st2000_run_ops.to_has_exited = NULL;
|
||||
st2000_ops.to_mourn_inferior = st2000_mourn_inferior;
|
||||
st2000_ops.to_can_run = 0; /* can_run */
|
||||
st2000_ops.to_notice_signals = 0; /* notice_signals */
|
||||
st2000_ops.to_thread_alive = 0; /* thread alive */
|
||||
st2000_ops.to_stop = 0; /* to_stop */
|
||||
st2000_ops.to_pid_to_exec_file = NULL;
|
||||
st2000_ops.to_stratum = process_stratum;
|
||||
st2000_ops.DONT_USE = 0; /* next */
|
||||
st2000_ops.to_has_all_memory = 1;
|
||||
st2000_ops.to_has_memory = 1;
|
||||
st2000_ops.to_has_stack = 1;
|
||||
st2000_ops.to_has_registers = 1;
|
||||
st2000_ops.to_has_execution = 1; /* all mem, mem, stack, regs, exec */
|
||||
st2000_ops.to_sections = 0;
|
||||
st2000_ops.to_sections_end = 0; /* Section pointers */
|
||||
st2000_ops.to_magic = OPS_MAGIC; /* Always the last thing */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_remote_st2000 (void)
|
||||
{
|
||||
init_st2000_ops ();
|
||||
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.");
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/* S-record download support for GDB, the GNU debugger.
|
||||
Copyright 1995, 1996, 2000 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 (struct serial *desc, const char *file, bfd_vma load_offset,
|
||||
int maxrecsize, int flags, int hashmark,
|
||||
int (*waitack) (void));
|
||||
|
||||
/* 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 */
|
@ -1,579 +0,0 @@
|
||||
/* Interface to bare machine for GDB running as kernel debugger.
|
||||
Copyright 1986, 1989, 1991, 1992, 1993, 1995, 1996, 2000, 2001
|
||||
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>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include "gdb_stat.h"
|
||||
|
||||
#if defined (SIGTSTP) && defined (SIGIO)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif /* SIGTSTP and SIGIO defined (must be 4.2) */
|
||||
|
||||
#include "defs.h"
|
||||
#include <signal.h>
|
||||
#include "symtab.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "gdb_wait.h"
|
||||
|
||||
|
||||
/* Random system calls, mostly no-ops to prevent link problems */
|
||||
|
||||
ioctl (int desc, int code, int arg)
|
||||
{
|
||||
}
|
||||
|
||||
int (*signal ()) ()
|
||||
{
|
||||
}
|
||||
|
||||
kill (void)
|
||||
{
|
||||
}
|
||||
|
||||
getpid (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sigsetmask (void)
|
||||
{
|
||||
}
|
||||
|
||||
chdir (void)
|
||||
{
|
||||
}
|
||||
|
||||
char *
|
||||
getcwd (char *buf, unsigned int len)
|
||||
{
|
||||
buf[0] = '/';
|
||||
buf[1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Used to check for existence of .gdbinit. Say no. */
|
||||
|
||||
access (void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
exit (void)
|
||||
{
|
||||
error ("Fatal error; restarting.");
|
||||
}
|
||||
|
||||
/* Reading "files". The contents of some files are written into kdb's
|
||||
data area before it is run. These files are used to contain the
|
||||
symbol table for kdb to load, and the source files (in case the
|
||||
kdb user wants to print them). The symbols are stored in a file
|
||||
named "kdb-symbols" in a.out format (except that all the text and
|
||||
data have been stripped to save room).
|
||||
|
||||
The files are stored in the following format:
|
||||
int number of bytes of data for this file, including these four.
|
||||
char[] name of the file, ending with a null.
|
||||
padding to multiple of 4 boundary.
|
||||
char[] file contents. The length can be deduced from what was
|
||||
specified before. There is no terminating null here.
|
||||
|
||||
If the int at the front is zero, it means there are no more files.
|
||||
|
||||
Opening a file in kdb returns a nonzero value to indicate success,
|
||||
but the value does not matter. Only one file can be open, and only
|
||||
for reading. All the primitives for input from the file know
|
||||
which file is open and ignore what is specified for the descriptor
|
||||
or for the stdio stream.
|
||||
|
||||
Input with fgetc can be done either on the file that is open
|
||||
or on stdin (which reads from the terminal through tty_input () */
|
||||
|
||||
/* Address of data for the files stored in format described above. */
|
||||
char *files_start;
|
||||
|
||||
/* The file stream currently open: */
|
||||
|
||||
char *sourcebeg; /* beginning of contents */
|
||||
int sourcesize; /* size of contents */
|
||||
char *sourceptr; /* current read pointer */
|
||||
int sourceleft; /* number of bytes to eof */
|
||||
|
||||
/* "descriptor" for the file now open.
|
||||
Incremented at each close.
|
||||
If specified descriptor does not match this,
|
||||
it means the program is trying to use a closed descriptor.
|
||||
We report an error for that. */
|
||||
|
||||
int sourcedesc;
|
||||
|
||||
open (char *filename, int modes)
|
||||
{
|
||||
register char *next;
|
||||
|
||||
if (modes)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sourceptr)
|
||||
{
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (next = files_start; *(int *) next; next += *(int *) next)
|
||||
{
|
||||
if (!strcmp (next + 4, filename))
|
||||
{
|
||||
sourcebeg = next + 4 + strlen (next + 4) + 1;
|
||||
sourcebeg = (char *) (((int) sourcebeg + 3) & (-4));
|
||||
sourceptr = sourcebeg;
|
||||
sourcesize = next + *(int *) next - sourceptr;
|
||||
sourceleft = sourcesize;
|
||||
return sourcedesc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
close (int desc)
|
||||
{
|
||||
sourceptr = 0;
|
||||
sourcedesc++;
|
||||
/* Don't let sourcedesc get big enough to be confused with stdin. */
|
||||
if (sourcedesc == 100)
|
||||
sourcedesc = 5;
|
||||
}
|
||||
|
||||
FILE *
|
||||
fopen (char *filename, char *modes)
|
||||
{
|
||||
return (FILE *) open (filename, *modes == 'w');
|
||||
}
|
||||
|
||||
FILE *
|
||||
fdopen (int desc)
|
||||
{
|
||||
return (FILE *) desc;
|
||||
}
|
||||
|
||||
fclose (int desc)
|
||||
{
|
||||
close (desc);
|
||||
}
|
||||
|
||||
fstat (int desc, struct stat *statbuf)
|
||||
{
|
||||
if (desc != sourcedesc)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
statbuf->st_size = sourcesize;
|
||||
}
|
||||
|
||||
myread (int desc, char *destptr, int size, char *filename)
|
||||
{
|
||||
int len = min (sourceleft, size);
|
||||
|
||||
if (desc != sourcedesc)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (destptr, sourceptr, len);
|
||||
sourceleft -= len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
fread (int bufp, int numelts, int eltsize, int stream)
|
||||
{
|
||||
register int elts = min (numelts, sourceleft / eltsize);
|
||||
register int len = elts * eltsize;
|
||||
|
||||
if (stream != sourcedesc)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy (bufp, sourceptr, len);
|
||||
sourceleft -= len;
|
||||
return elts;
|
||||
}
|
||||
|
||||
int
|
||||
fgetc (int desc)
|
||||
{
|
||||
|
||||
if (desc == (int) stdin)
|
||||
return tty_input ();
|
||||
|
||||
if (desc != sourcedesc)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sourceleft-- <= 0)
|
||||
return EOF;
|
||||
return *sourceptr++;
|
||||
}
|
||||
|
||||
lseek (int desc, int pos)
|
||||
{
|
||||
|
||||
if (desc != sourcedesc)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos < 0 || pos > sourcesize)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sourceptr = sourcebeg + pos;
|
||||
sourceleft = sourcesize - pos;
|
||||
}
|
||||
|
||||
/* Output in kdb can go only to the terminal, so the stream
|
||||
specified may be ignored. */
|
||||
|
||||
printf (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
display_string (buffer);
|
||||
}
|
||||
|
||||
fprintf (int ign, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
|
||||
int a8, int a9)
|
||||
{
|
||||
char buffer[1024];
|
||||
sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
display_string (buffer);
|
||||
}
|
||||
|
||||
fwrite (register char *buf, int numelts, int size, int stream)
|
||||
{
|
||||
register int i = numelts * size;
|
||||
while (i-- > 0)
|
||||
fputc (*buf++, stream);
|
||||
}
|
||||
|
||||
fputc (int c, int ign)
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
display_string (buf);
|
||||
}
|
||||
|
||||
/* sprintf refers to this, but loading this from the
|
||||
library would cause fflush to be loaded from it too.
|
||||
In fact there should be no need to call this (I hope). */
|
||||
|
||||
_flsbuf (void)
|
||||
{
|
||||
error ("_flsbuf was actually called.");
|
||||
}
|
||||
|
||||
fflush (int ign)
|
||||
{
|
||||
}
|
||||
|
||||
/* Entries into core and inflow, needed only to make things link ok. */
|
||||
|
||||
exec_file_command (void)
|
||||
{
|
||||
}
|
||||
|
||||
core_file_command (void)
|
||||
{
|
||||
}
|
||||
|
||||
char *
|
||||
get_exec_file (int err)
|
||||
{
|
||||
/* Makes one printout look reasonable; value does not matter otherwise. */
|
||||
return "run";
|
||||
}
|
||||
|
||||
/* Nonzero if there is a core file. */
|
||||
|
||||
have_core_file_p (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
kill_command (void)
|
||||
{
|
||||
inferior_ptid = null_ptid;
|
||||
}
|
||||
|
||||
terminal_inferior (void)
|
||||
{
|
||||
}
|
||||
|
||||
terminal_ours (void)
|
||||
{
|
||||
}
|
||||
|
||||
terminal_init_inferior (void)
|
||||
{
|
||||
}
|
||||
|
||||
write_inferior_register (void)
|
||||
{
|
||||
}
|
||||
|
||||
read_inferior_register (void)
|
||||
{
|
||||
}
|
||||
|
||||
read_memory (CORE_ADDR memaddr, char *myaddr, int len)
|
||||
{
|
||||
memcpy (myaddr, memaddr, len);
|
||||
}
|
||||
|
||||
/* Always return 0 indicating success. */
|
||||
|
||||
write_memory (CORE_ADDR memaddr, char *myaddr, int len)
|
||||
{
|
||||
memcpy (memaddr, myaddr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static REGISTER_TYPE saved_regs[NUM_REGS];
|
||||
|
||||
REGISTER_TYPE
|
||||
read_register (int regno)
|
||||
{
|
||||
if (regno < 0 || regno >= NUM_REGS)
|
||||
error ("Register number %d out of range.", regno);
|
||||
return saved_regs[regno];
|
||||
}
|
||||
|
||||
void
|
||||
write_register (int regno, REGISTER_TYPE value)
|
||||
{
|
||||
if (regno < 0 || regno >= NUM_REGS)
|
||||
error ("Register number %d out of range.", regno);
|
||||
saved_regs[regno] = value;
|
||||
}
|
||||
|
||||
/* System calls needed in relation to running the "inferior". */
|
||||
|
||||
vfork (void)
|
||||
{
|
||||
/* Just appear to "succeed". Say the inferior's pid is 1. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* These are called by code that normally runs in the inferior
|
||||
that has just been forked. That code never runs, when standalone,
|
||||
and these definitions are so it will link without errors. */
|
||||
|
||||
ptrace (void)
|
||||
{
|
||||
}
|
||||
|
||||
setpgrp (void)
|
||||
{
|
||||
}
|
||||
|
||||
execle (void)
|
||||
{
|
||||
}
|
||||
|
||||
_exit (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Malloc calls these. */
|
||||
|
||||
malloc_warning (char *str)
|
||||
{
|
||||
printf ("\n%s.\n\n", str);
|
||||
}
|
||||
|
||||
char *next_free;
|
||||
char *memory_limit;
|
||||
|
||||
char *
|
||||
sbrk (int amount)
|
||||
{
|
||||
if (next_free + amount > memory_limit)
|
||||
return (char *) -1;
|
||||
next_free += amount;
|
||||
return next_free - amount;
|
||||
}
|
||||
|
||||
/* Various ways malloc might ask where end of memory is. */
|
||||
|
||||
char *
|
||||
ulimit (void)
|
||||
{
|
||||
return memory_limit;
|
||||
}
|
||||
|
||||
int
|
||||
vlimit (void)
|
||||
{
|
||||
return memory_limit - next_free;
|
||||
}
|
||||
|
||||
getrlimit (struct rlimit *addr)
|
||||
{
|
||||
addr->rlim_cur = memory_limit - next_free;
|
||||
}
|
||||
|
||||
/* Context switching to and from program being debugged. */
|
||||
|
||||
/* GDB calls here to run the user program.
|
||||
The frame pointer for this function is saved in
|
||||
gdb_stack by save_frame_pointer; then we restore
|
||||
all of the user program's registers, including PC and PS. */
|
||||
|
||||
static int fault_code;
|
||||
static REGISTER_TYPE gdb_stack;
|
||||
|
||||
resume (void)
|
||||
{
|
||||
REGISTER_TYPE restore[NUM_REGS];
|
||||
|
||||
PUSH_FRAME_PTR;
|
||||
save_frame_pointer ();
|
||||
|
||||
memcpy (restore, saved_regs, sizeof restore);
|
||||
POP_REGISTERS;
|
||||
/* Control does not drop through here! */
|
||||
}
|
||||
|
||||
save_frame_pointer (CORE_ADDR val)
|
||||
{
|
||||
gdb_stack = val;
|
||||
}
|
||||
|
||||
/* Fault handlers call here, running in the user program stack.
|
||||
They must first push a fault code,
|
||||
old PC, old PS, and any other info about the fault.
|
||||
The exact format is machine-dependent and is known only
|
||||
in the definition of PUSH_REGISTERS. */
|
||||
|
||||
fault (void)
|
||||
{
|
||||
/* Transfer all registers and fault code to the stack
|
||||
in canonical order: registers in order of GDB register number,
|
||||
followed by fault code. */
|
||||
PUSH_REGISTERS;
|
||||
|
||||
/* Transfer them to saved_regs and fault_code. */
|
||||
save_registers ();
|
||||
|
||||
restore_gdb ();
|
||||
/* Control does not reach here */
|
||||
}
|
||||
|
||||
restore_gdb (void)
|
||||
{
|
||||
CORE_ADDR new_fp = gdb_stack;
|
||||
/* Switch to GDB's stack */
|
||||
POP_FRAME_PTR;
|
||||
/* Return from the function `resume'. */
|
||||
}
|
||||
|
||||
/* Assuming register contents and fault code have been pushed on the stack as
|
||||
arguments to this function, copy them into the standard place
|
||||
for the program's registers while GDB is running. */
|
||||
|
||||
save_registers (int firstreg)
|
||||
{
|
||||
memcpy (saved_regs, &firstreg, sizeof saved_regs);
|
||||
fault_code = (&firstreg)[NUM_REGS];
|
||||
}
|
||||
|
||||
/* Store into the structure such as `wait' would return
|
||||
the information on why the program faulted,
|
||||
converted into a machine-independent signal number. */
|
||||
|
||||
static int fault_table[] = FAULT_TABLE;
|
||||
|
||||
int
|
||||
wait (WAITTYPE *w)
|
||||
{
|
||||
WSETSTOP (*w, fault_table[fault_code / FAULT_CODE_UNITS]);
|
||||
return PIDGET (inferior_ptid);
|
||||
}
|
||||
|
||||
/* Allocate a big space in which files for kdb to read will be stored.
|
||||
Whatever is left is where malloc can allocate storage.
|
||||
|
||||
Initialize it, so that there will be space in the executable file
|
||||
for it. Then the files can be put into kdb by writing them into
|
||||
kdb's executable file. */
|
||||
|
||||
/* The default size is as much space as we expect to be available
|
||||
for kdb to use! */
|
||||
|
||||
#ifndef HEAP_SIZE
|
||||
#define HEAP_SIZE 400000
|
||||
#endif
|
||||
|
||||
char heap[HEAP_SIZE] =
|
||||
{0};
|
||||
|
||||
#ifndef STACK_SIZE
|
||||
#define STACK_SIZE 100000
|
||||
#endif
|
||||
|
||||
int kdb_stack_beg[STACK_SIZE / sizeof (int)];
|
||||
int kdb_stack_end;
|
||||
|
||||
_initialize_standalone (void)
|
||||
{
|
||||
register char *next;
|
||||
|
||||
/* Find start of data on files. */
|
||||
|
||||
files_start = heap;
|
||||
|
||||
/* Find the end of the data on files. */
|
||||
|
||||
for (next = files_start; *(int *) next; next += *(int *) next)
|
||||
{
|
||||
}
|
||||
|
||||
/* That is where free storage starts for sbrk to give out. */
|
||||
next_free = next;
|
||||
|
||||
memory_limit = heap + sizeof heap;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,196 +0,0 @@
|
||||
/* Shared library support for RS/6000 (xcoff) object files, for GDB.
|
||||
Copyright 1991, 1992, 1995, 1996, 1999, 2000, 2001
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by IBM 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. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "bfd.h"
|
||||
#include "xcoffsolib.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "symfile.h"
|
||||
#include "frame.h"
|
||||
#include "gdb_regex.h"
|
||||
|
||||
|
||||
/* If ADDR lies in a shared library, return its name.
|
||||
Note that returned name points to static data whose content is overwritten
|
||||
by each call. */
|
||||
|
||||
char *
|
||||
xcoff_solib_address (CORE_ADDR addr)
|
||||
{
|
||||
static char *buffer = NULL;
|
||||
struct vmap *vp = vmap;
|
||||
|
||||
/* The first vmap entry is for the exec file. */
|
||||
|
||||
if (vp == NULL)
|
||||
return NULL;
|
||||
for (vp = vp->nxt; vp; vp = vp->nxt)
|
||||
if (vp->tstart <= addr && addr < vp->tend)
|
||||
{
|
||||
xfree (buffer);
|
||||
xasprintf (&buffer, "%s%s%s%s",
|
||||
vp->name,
|
||||
*vp->member ? "(" : "",
|
||||
vp->member,
|
||||
*vp->member ? ")" : "");
|
||||
return buffer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void solib_info (char *, int);
|
||||
static void sharedlibrary_command (char *pattern, int from_tty);
|
||||
|
||||
static void
|
||||
solib_info (char *args, int from_tty)
|
||||
{
|
||||
struct vmap *vp = vmap;
|
||||
|
||||
/* Check for new shared libraries loaded with load (). */
|
||||
if (! ptid_equal (inferior_ptid, null_ptid))
|
||||
xcoff_relocate_symtab (PIDGET (inferior_ptid));
|
||||
|
||||
if (vp == NULL || vp->nxt == NULL)
|
||||
{
|
||||
printf_unfiltered ("No shared libraries loaded at this time.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip over the first vmap, it is the main program, always loaded. */
|
||||
vp = vp->nxt;
|
||||
|
||||
printf_unfiltered ("\
|
||||
Text Range Data Range Syms Shared Object Library\n");
|
||||
|
||||
for (; vp != NULL; vp = vp->nxt)
|
||||
{
|
||||
printf_unfiltered ("0x%s-0x%s 0x%s-0x%s %s %s%s%s%s\n",
|
||||
paddr (vp->tstart),paddr (vp->tend),
|
||||
paddr (vp->dstart), paddr (vp->dend),
|
||||
vp->loaded ? "Yes" : "No ",
|
||||
vp->name,
|
||||
*vp->member ? "(" : "",
|
||||
vp->member,
|
||||
*vp->member ? ")" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sharedlibrary_command (char *pattern, int from_tty)
|
||||
{
|
||||
dont_repeat ();
|
||||
|
||||
/* Check for new shared libraries loaded with load (). */
|
||||
if (! ptid_equal (inferior_ptid, null_ptid))
|
||||
xcoff_relocate_symtab (PIDGET (inferior_ptid));
|
||||
|
||||
if (pattern)
|
||||
{
|
||||
char *re_err = re_comp (pattern);
|
||||
|
||||
if (re_err)
|
||||
error ("Invalid regexp: %s", re_err);
|
||||
}
|
||||
|
||||
/* Walk the list of currently loaded shared libraries, and read
|
||||
symbols for any that match the pattern --- or any whose symbols
|
||||
aren't already loaded, if no pattern was given. */
|
||||
{
|
||||
int any_matches = 0;
|
||||
int loaded_any_symbols = 0;
|
||||
struct vmap *vp = vmap;
|
||||
|
||||
if (!vp)
|
||||
return;
|
||||
|
||||
/* skip over the first vmap, it is the main program, always loaded. */
|
||||
for (vp = vp->nxt; vp; vp = vp->nxt)
|
||||
if (! pattern
|
||||
|| re_exec (vp->name)
|
||||
|| (*vp->member && re_exec (vp->member)))
|
||||
{
|
||||
any_matches = 1;
|
||||
|
||||
if (vp->loaded)
|
||||
{
|
||||
if (from_tty)
|
||||
printf_unfiltered ("Symbols already loaded for %s\n",
|
||||
vp->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vmap_add_symbols (vp))
|
||||
loaded_any_symbols = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (from_tty && pattern && ! any_matches)
|
||||
printf_unfiltered
|
||||
("No loaded shared libraries match the pattern `%s'.\n", pattern);
|
||||
|
||||
if (loaded_any_symbols)
|
||||
{
|
||||
/* Getting new symbols may change our opinion about what is
|
||||
frameless. */
|
||||
reinit_frame_cache ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* LOCAL FUNCTION
|
||||
|
||||
no_shared_libraries -- handle command to explicitly discard symbols
|
||||
from shared libraries.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Implements the command "nosharedlibrary", which discards symbols
|
||||
that have been auto-loaded from shared libraries. Symbols from
|
||||
shared libraries that were added by explicit request of the user
|
||||
are not discarded. Also called from remote.c. */
|
||||
|
||||
void
|
||||
no_shared_libraries (char *ignored, int from_tty)
|
||||
{
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_xcoffsolib (void)
|
||||
{
|
||||
add_com ("sharedlibrary", class_files, sharedlibrary_command,
|
||||
"Load shared object library symbols for files matching REGEXP.");
|
||||
add_info ("sharedlibrary", solib_info,
|
||||
"Status of loaded shared object libraries");
|
||||
|
||||
add_show_from_set
|
||||
(add_set_cmd ("auto-solib-add", class_support, var_boolean,
|
||||
(char *) &auto_solib_add,
|
||||
"Set autoloading of shared library symbols.\n\
|
||||
If \"on\", symbols from all shared object libraries will be loaded\n\
|
||||
automatically when the inferior begins execution, when the dynamic linker\n\
|
||||
informs gdb that a new library has been loaded, or when attaching to the\n\
|
||||
inferior. Otherwise, symbols must be loaded manually, using `sharedlibrary'.",
|
||||
&setlist),
|
||||
&showlist);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user