diff options
author | marcel <marcel@FreeBSD.org> | 2004-06-19 03:39:16 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2004-06-19 03:39:16 +0000 |
commit | ba7e012f7af0a56947dc4a72182dc5e77419e817 (patch) | |
tree | c837b4af2c91e137b130c7d4fd2695d542f27c3b | |
parent | 88f121ea812f30a7b6c132b492f208564521e407 (diff) | |
download | FreeBSD-src-ba7e012f7af0a56947dc4a72182dc5e77419e817.zip FreeBSD-src-ba7e012f7af0a56947dc4a72182dc5e77419e817.tar.gz |
This file has been removed from HEAD when it should (also) have been
removed from the vendor branch.
30 files changed, 0 insertions, 32873 deletions
diff --git a/contrib/gdb/gdb/abug-rom.c b/contrib/gdb/gdb/abug-rom.c deleted file mode 100644 index b4c44a9..0000000 --- a/contrib/gdb/gdb/abug-rom.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/acconfig.h b/contrib/gdb/gdb/acconfig.h deleted file mode 100644 index 664bbcf..0000000 --- a/contrib/gdb/gdb/acconfig.h +++ /dev/null @@ -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 diff --git a/contrib/gdb/gdb/alpha-nat.c b/contrib/gdb/gdb/alpha-nat.c deleted file mode 100644 index f7e565b..0000000 --- a/contrib/gdb/gdb/alpha-nat.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/arm-tdep.c b/contrib/gdb/gdb/arm-tdep.c deleted file mode 100644 index b164f8e..0000000 --- a/contrib/gdb/gdb/arm-tdep.c +++ /dev/null @@ -1,3146 +0,0 @@ -/* Common target dependent code for GDB on ARM systems. - Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000, - 2001, 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 <ctype.h> /* XXX for isupper () */ - -#include "defs.h" -#include "frame.h" -#include "inferior.h" -#include "gdbcmd.h" -#include "gdbcore.h" -#include "symfile.h" -#include "gdb_string.h" -#include "dis-asm.h" /* For register flavors. */ -#include "regcache.h" -#include "doublest.h" -#include "value.h" -#include "arch-utils.h" -#include "solib-svr4.h" - -#include "arm-tdep.h" - -#include "elf-bfd.h" -#include "coff/internal.h" -#include "elf/arm.h" - -/* Each OS has a different mechanism for accessing the various - registers stored in the sigcontext structure. - - SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or - function pointer) which may be used to determine the addresses - of the various saved registers in the sigcontext structure. - - For the ARM target, there are three parameters to this function. - The first is the pc value of the frame under consideration, the - second the stack pointer of this frame, and the last is the - register number to fetch. - - If the tm.h file does not define this macro, then it's assumed that - no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to - be 0. - - When it comes time to multi-arching this code, see the identically - named machinery in ia64-tdep.c for an example of how it could be - done. It should not be necessary to modify the code below where - this macro is used. */ - -#ifdef SIGCONTEXT_REGISTER_ADDRESS -#ifndef SIGCONTEXT_REGISTER_ADDRESS_P -#define SIGCONTEXT_REGISTER_ADDRESS_P() 1 -#endif -#else -#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0 -#define SIGCONTEXT_REGISTER_ADDRESS_P() 0 -#endif - -/* Macros for setting and testing a bit in a minimal symbol that marks - it as Thumb function. The MSB of the minimal symbol's "info" field - is used for this purpose. This field is already being used to store - the symbol size, so the assumption is that the symbol size cannot - exceed 2^31. - - MSYMBOL_SET_SPECIAL Actually sets the "special" bit. - MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. - MSYMBOL_SIZE Returns the size of the minimal symbol, - i.e. the "info" field with the "special" bit - masked out. */ - -#define MSYMBOL_SET_SPECIAL(msym) \ - MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) \ - | 0x80000000) - -#define MSYMBOL_IS_SPECIAL(msym) \ - (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0) - -#define MSYMBOL_SIZE(msym) \ - ((long) MSYMBOL_INFO (msym) & 0x7fffffff) - -/* This table matches the indicees assigned to enum arm_abi. Keep - them in sync. */ - -static const char * const arm_abi_names[] = -{ - "<unknown>", - "ARM EABI (version 1)", - "ARM EABI (version 2)", - "GNU/Linux", - "NetBSD (a.out)", - "NetBSD (ELF)", - "APCS", - "FreeBSD", - "Windows CE", - NULL -}; - -/* Number of different reg name sets (options). */ -static int num_flavor_options; - -/* We have more registers than the disassembler as gdb can print the value - of special registers as well. - The general register names are overwritten by whatever is being used by - the disassembler at the moment. We also adjust the case of cpsr and fps. */ - -/* Initial value: Register names used in ARM's ISA documentation. */ -static char * arm_register_name_strings[] = -{"r0", "r1", "r2", "r3", /* 0 1 2 3 */ - "r4", "r5", "r6", "r7", /* 4 5 6 7 */ - "r8", "r9", "r10", "r11", /* 8 9 10 11 */ - "r12", "sp", "lr", "pc", /* 12 13 14 15 */ - "f0", "f1", "f2", "f3", /* 16 17 18 19 */ - "f4", "f5", "f6", "f7", /* 20 21 22 23 */ - "fps", "cpsr" }; /* 24 25 */ -static char **arm_register_names = arm_register_name_strings; - -/* Valid register name flavors. */ -static const char **valid_flavors; - -/* Disassembly flavor to use. Default to "std" register names. */ -static const char *disassembly_flavor; -static int current_option; /* Index to that option in the opcodes table. */ - -/* This is used to keep the bfd arch_info in sync with the disassembly - flavor. */ -static void set_disassembly_flavor_sfunc(char *, int, - struct cmd_list_element *); -static void set_disassembly_flavor (void); - -static void convert_from_extended (void *ptr, void *dbl); - -/* Define other aspects of the stack frame. We keep the offsets of - all saved registers, 'cause we need 'em a lot! We also keep the - current size of the stack frame, and the offset of the frame - pointer from the stack pointer (for frameless functions, and when - we're still in the prologue of a function with a frame) */ - -struct frame_extra_info -{ - int framesize; - int frameoffset; - int framereg; -}; - -/* Addresses for calling Thumb functions have the bit 0 set. - Here are some macros to test, set, or clear bit 0 of addresses. */ -#define IS_THUMB_ADDR(addr) ((addr) & 1) -#define MAKE_THUMB_ADDR(addr) ((addr) | 1) -#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) - -static int -arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe) -{ - return (chain != 0 && (FRAME_SAVED_PC (thisframe) >= LOWEST_PC)); -} - -/* Set to true if the 32-bit mode is in use. */ - -int arm_apcs_32 = 1; - -/* Flag set by arm_fix_call_dummy that tells whether the target - function is a Thumb function. This flag is checked by - arm_push_arguments. FIXME: Change the PUSH_ARGUMENTS macro (and - its use in valops.c) to pass the function address as an additional - parameter. */ - -static int target_is_thumb; - -/* Flag set by arm_fix_call_dummy that tells whether the calling - function is a Thumb function. This flag is checked by - arm_pc_is_thumb and arm_call_dummy_breakpoint_offset. */ - -static int caller_is_thumb; - -/* Determine if the program counter specified in MEMADDR is in a Thumb - function. */ - -int -arm_pc_is_thumb (CORE_ADDR memaddr) -{ - struct minimal_symbol *sym; - - /* If bit 0 of the address is set, assume this is a Thumb address. */ - if (IS_THUMB_ADDR (memaddr)) - return 1; - - /* Thumb functions have a "special" bit set in minimal symbols. */ - sym = lookup_minimal_symbol_by_pc (memaddr); - if (sym) - { - return (MSYMBOL_IS_SPECIAL (sym)); - } - else - { - return 0; - } -} - -/* Determine if the program counter specified in MEMADDR is in a call - dummy being called from a Thumb function. */ - -int -arm_pc_is_thumb_dummy (CORE_ADDR memaddr) -{ - CORE_ADDR sp = read_sp (); - - /* FIXME: Until we switch for the new call dummy macros, this heuristic - is the best we can do. We are trying to determine if the pc is on - the stack, which (hopefully) will only happen in a call dummy. - We hope the current stack pointer is not so far alway from the dummy - frame location (true if we have not pushed large data structures or - gone too many levels deep) and that our 1024 is not enough to consider - code regions as part of the stack (true for most practical purposes) */ - if (PC_IN_CALL_DUMMY (memaddr, sp, sp + 1024)) - return caller_is_thumb; - else - return 0; -} - -/* Remove useless bits from addresses in a running program. */ -static CORE_ADDR -arm_addr_bits_remove (CORE_ADDR val) -{ - if (arm_pc_is_thumb (val)) - return (val & (arm_apcs_32 ? 0xfffffffe : 0x03fffffe)); - else - return (val & (arm_apcs_32 ? 0xfffffffc : 0x03fffffc)); -} - -/* When reading symbols, we need to zap the low bit of the address, - which may be set to 1 for Thumb functions. */ -static CORE_ADDR -arm_smash_text_address (CORE_ADDR val) -{ - return val & ~1; -} - -/* Immediately after a function call, return the saved pc. Can't - always go through the frames for this because on some machines the - new frame is not set up until the new function executes some - instructions. */ - -static CORE_ADDR -arm_saved_pc_after_call (struct frame_info *frame) -{ - return ADDR_BITS_REMOVE (read_register (ARM_LR_REGNUM)); -} - -/* Determine whether the function invocation represented by FI has a - frame on the stack associated with it. If it does return zero, - otherwise return 1. */ - -static int -arm_frameless_function_invocation (struct frame_info *fi) -{ - CORE_ADDR func_start, after_prologue; - int frameless; - - /* Sometimes we have functions that do a little setup (like saving the - vN registers with the stmdb instruction, but DO NOT set up a frame. - The symbol table will report this as a prologue. However, it is - important not to try to parse these partial frames as frames, or we - will get really confused. - - So I will demand 3 instructions between the start & end of the - prologue before I call it a real prologue, i.e. at least - mov ip, sp, - stmdb sp!, {} - sub sp, ip, #4. */ - - func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); - after_prologue = SKIP_PROLOGUE (func_start); - - /* There are some frameless functions whose first two instructions - follow the standard APCS form, in which case after_prologue will - be func_start + 8. */ - - frameless = (after_prologue < func_start + 12); - return frameless; -} - -/* The address of the arguments in the frame. */ -static CORE_ADDR -arm_frame_args_address (struct frame_info *fi) -{ - return fi->frame; -} - -/* The address of the local variables in the frame. */ -static CORE_ADDR -arm_frame_locals_address (struct frame_info *fi) -{ - return fi->frame; -} - -/* The number of arguments being passed in the frame. */ -static int -arm_frame_num_args (struct frame_info *fi) -{ - /* We have no way of knowing. */ - return -1; -} - -/* A typical Thumb prologue looks like this: - push {r7, lr} - add sp, sp, #-28 - add r7, sp, #12 - Sometimes the latter instruction may be replaced by: - mov r7, sp - - or like this: - push {r7, lr} - mov r7, sp - sub sp, #12 - - or, on tpcs, like this: - sub sp,#16 - push {r7, lr} - (many instructions) - mov r7, sp - sub sp, #12 - - There is always one instruction of three classes: - 1 - push - 2 - setting of r7 - 3 - adjusting of sp - - When we have found at least one of each class we are done with the prolog. - Note that the "sub sp, #NN" before the push does not count. - */ - -static CORE_ADDR -thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end) -{ - CORE_ADDR current_pc; - int findmask = 0; /* findmask: - bit 0 - push { rlist } - bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) - bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) - */ - - for (current_pc = pc; current_pc + 2 < func_end && current_pc < pc + 40; current_pc += 2) - { - unsigned short insn = read_memory_unsigned_integer (current_pc, 2); - - if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ - { - findmask |= 1; /* push found */ - } - else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ - { - if ((findmask & 1) == 0) /* before push ? */ - continue; - else - findmask |= 4; /* add/sub sp found */ - } - else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ - { - findmask |= 2; /* setting of r7 found */ - } - else if (insn == 0x466f) /* mov r7, sp */ - { - findmask |= 2; /* setting of r7 found */ - } - else if (findmask == (4+2+1)) - { - break; /* We have found one of each type of prologue instruction */ - } - else - continue; /* something in the prolog that we don't care about or some - instruction from outside the prolog scheduled here for optimization */ - } - - return current_pc; -} - -/* Advance the PC across any function entry prologue instructions to reach - some "real" code. - - The APCS (ARM Procedure Call Standard) defines the following - prologue: - - mov ip, sp - [stmfd sp!, {a1,a2,a3,a4}] - stmfd sp!, {...,fp,ip,lr,pc} - [stfe f7, [sp, #-12]!] - [stfe f6, [sp, #-12]!] - [stfe f5, [sp, #-12]!] - [stfe f4, [sp, #-12]!] - sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn */ - -static CORE_ADDR -arm_skip_prologue (CORE_ADDR pc) -{ - unsigned long inst; - CORE_ADDR skip_pc; - CORE_ADDR func_addr, func_end; - char *func_name; - struct symtab_and_line sal; - - /* See what the symbol table says. */ - - if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) - { - struct symbol *sym; - - /* Found a function. */ - sym = lookup_symbol (func_name, NULL, VAR_NAMESPACE, NULL, NULL); - if (sym && SYMBOL_LANGUAGE (sym) != language_asm) - { - /* Don't use this trick for assembly source files. */ - sal = find_pc_line (func_addr, 0); - if ((sal.line != 0) && (sal.end < func_end)) - return sal.end; - } - } - - /* Check if this is Thumb code. */ - if (arm_pc_is_thumb (pc)) - return thumb_skip_prologue (pc, func_end); - - /* Can't find the prologue end in the symbol table, try it the hard way - by disassembling the instructions. */ - skip_pc = pc; - inst = read_memory_integer (skip_pc, 4); - if (inst != 0xe1a0c00d) /* mov ip, sp */ - return pc; - - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - - if ((inst & 0xfffff800) != 0xe92dd800) /* stmfd sp!,{...,fp,ip,lr,pc} */ - return pc; - - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - - /* Any insns after this point may float into the code, if it makes - for better instruction scheduling, so we skip them only if we - find them, but still consdier the function to be frame-ful. */ - - /* We may have either one sfmfd instruction here, or several stfe - insns, depending on the version of floating point code we - support. */ - if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - else - { - while ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */ - { - skip_pc += 4; - inst = read_memory_integer (skip_pc, 4); - } - } - - if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */ - skip_pc += 4; - - return skip_pc; -} -/* *INDENT-OFF* */ -/* Function: thumb_scan_prologue (helper function for arm_scan_prologue) - This function decodes a Thumb function prologue to determine: - 1) the size of the stack frame - 2) which registers are saved on it - 3) the offsets of saved regs - 4) the offset from the stack pointer to the frame pointer - This information is stored in the "extra" fields of the frame_info. - - A typical Thumb function prologue would create this stack frame - (offsets relative to FP) - old SP -> 24 stack parameters - 20 LR - 16 R7 - R7 -> 0 local variables (16 bytes) - SP -> -12 additional stack space (12 bytes) - The frame size would thus be 36 bytes, and the frame offset would be - 12 bytes. The frame register is R7. - - The comments for thumb_skip_prolog() describe the algorithm we use to detect - the end of the prolog */ -/* *INDENT-ON* */ - -static void -thumb_scan_prologue (struct frame_info *fi) -{ - CORE_ADDR prologue_start; - CORE_ADDR prologue_end; - CORE_ADDR current_pc; - int saved_reg[16]; /* which register has been copied to register n? */ - int findmask = 0; /* findmask: - bit 0 - push { rlist } - bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) - bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) - */ - int i; - - if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) - { - 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 - prologue_end = prologue_start + 40; /* We're in the boondocks: allow for */ - /* 16 pushes, an add, and "mv fp,sp" */ - - prologue_end = min (prologue_end, fi->pc); - - /* Initialize the saved register map. When register H is copied to - register L, we will put H in saved_reg[L]. */ - for (i = 0; i < 16; i++) - saved_reg[i] = i; - - /* Search the prologue looking for instructions that set up the - frame pointer, adjust the stack pointer, and save registers. - Do this until all basic prolog instructions are found. */ - - fi->extra_info->framesize = 0; - for (current_pc = prologue_start; - (current_pc < prologue_end) && ((findmask & 7) != 7); - current_pc += 2) - { - unsigned short insn; - int regno; - int offset; - - insn = read_memory_unsigned_integer (current_pc, 2); - - if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ - { - int mask; - findmask |= 1; /* push found */ - /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says - whether to save LR (R14). */ - mask = (insn & 0xff) | ((insn & 0x100) << 6); - - /* Calculate offsets of saved R0-R7 and LR. */ - for (regno = ARM_LR_REGNUM; regno >= 0; regno--) - if (mask & (1 << regno)) - { - fi->extra_info->framesize += 4; - fi->saved_regs[saved_reg[regno]] = - -(fi->extra_info->framesize); - saved_reg[regno] = regno; /* reset saved register map */ - } - } - else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ - { - if ((findmask & 1) == 0) /* before push ? */ - continue; - else - findmask |= 4; /* add/sub sp found */ - - offset = (insn & 0x7f) << 2; /* get scaled offset */ - if (insn & 0x80) /* is it signed? (==subtracting) */ - { - fi->extra_info->frameoffset += offset; - offset = -offset; - } - fi->extra_info->framesize -= offset; - } - else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ - { - findmask |= 2; /* setting of r7 found */ - fi->extra_info->framereg = THUMB_FP_REGNUM; - /* get scaled offset */ - fi->extra_info->frameoffset = (insn & 0xff) << 2; - } - else if (insn == 0x466f) /* mov r7, sp */ - { - findmask |= 2; /* setting of r7 found */ - fi->extra_info->framereg = THUMB_FP_REGNUM; - fi->extra_info->frameoffset = 0; - saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM; - } - else if ((insn & 0xffc0) == 0x4640) /* mov r0-r7, r8-r15 */ - { - int lo_reg = insn & 7; /* dest. register (r0-r7) */ - int hi_reg = ((insn >> 3) & 7) + 8; /* source register (r8-15) */ - saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */ - } - else - continue; /* something in the prolog that we don't care about or some - instruction from outside the prolog scheduled here for optimization */ - } -} - -/* 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->extra_info->framereg = prologue_cache.extra_info->framereg; - fi->extra_info->framesize = prologue_cache.extra_info->framesize; - fi->extra_info->frameoffset = prologue_cache.extra_info->frameoffset; - for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) - fi->saved_regs[i] = prologue_cache.saved_regs[i]; - return 1; - } - else - return 0; -} - - -/* 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.extra_info->framereg = fi->extra_info->framereg; - prologue_cache.extra_info->framesize = fi->extra_info->framesize; - prologue_cache.extra_info->frameoffset = fi->extra_info->frameoffset; - - for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) - prologue_cache.saved_regs[i] = fi->saved_regs[i]; -} - - -/* This function decodes an ARM function prologue to determine: - 1) the size of the stack frame - 2) which registers are saved on it - 3) the offsets of saved regs - 4) the offset from the stack pointer to the frame pointer - This information is stored in the "extra" fields of the frame_info. - - There are two basic forms for the ARM prologue. The fixed argument - function call will look like: - - mov ip, sp - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #4 - [sub sp, sp, #4] - - Which would create this stack frame (offsets relative to FP): - IP -> 4 (caller's stack) - FP -> 0 PC (points to address of stmfd instruction + 8 in callee) - -4 LR (return address in caller) - -8 IP (copy of caller's SP) - -12 FP (caller's FP) - SP -> -28 Local variables - - The frame size would thus be 32 bytes, and the frame offset would be - 28 bytes. The stmfd call can also save any of the vN registers it - plans to use, which increases the frame size accordingly. - - Note: The stored PC is 8 off of the STMFD instruction that stored it - because the ARM Store instructions always store PC + 8 when you read - the PC register. - - A variable argument function call will look like: - - mov ip, sp - stmfd sp!, {a1, a2, a3, a4} - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #20 - - Which would create this stack frame (offsets relative to FP): - IP -> 20 (caller's stack) - 16 A4 - 12 A3 - 8 A2 - 4 A1 - FP -> 0 PC (points to address of stmfd instruction + 8 in callee) - -4 LR (return address in caller) - -8 IP (copy of caller's SP) - -12 FP (caller's FP) - SP -> -28 Local variables - - The frame size would thus be 48 bytes, and the frame offset would be - 28 bytes. - - There is another potential complication, which is that the optimizer - will try to separate the store of fp in the "stmfd" instruction from - the "sub fp, ip, #NN" instruction. Almost anything can be there, so - we just key on the stmfd, and then scan for the "sub fp, ip, #NN"... - - Also, note, the original version of the ARM toolchain claimed that there - should be an - - instruction at the end of the prologue. I have never seen GCC produce - this, and the ARM docs don't mention it. We still test for it below in - case it happens... - - */ - -static void -arm_scan_prologue (struct frame_info *fi) -{ - int regno, sp_offset, fp_offset; - LONGEST return_value; - 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->extra_info->framereg = ARM_SP_REGNUM; - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - - /* Check for Thumb prologue. */ - if (arm_pc_is_thumb (fi->pc)) - { - thumb_scan_prologue (fi); - save_prologue_cache (fi); - return; - } - - /* 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)) - { - /* One way to find the end of the prologue (which works well - for unoptimized code) is to do the following: - - struct symtab_and_line sal = find_pc_line (prologue_start, 0); - - if (sal.line == 0) - prologue_end = fi->pc; - else if (sal.end < prologue_end) - prologue_end = sal.end; - - This mechanism is very accurate so long as the optimizer - doesn't move any instructions from the function body into the - prologue. If this happens, sal.end will be the last - instruction in the first hunk of prologue code just before - the first instruction that the scheduler has moved from - the body to the prologue. - - In order to make sure that we scan all of the prologue - instructions, we use a slightly less accurate mechanism which - may scan more than necessary. To help compensate for this - lack of accuracy, the prologue scanning loop below contains - several clauses which'll cause the loop to terminate early if - an implausible prologue instruction is encountered. - - The expression - - prologue_start + 64 - - is a suitable endpoint since it accounts for the largest - possible prologue plus up to five instructions inserted by - the scheduler. */ - - if (prologue_end > prologue_start + 64) - { - prologue_end = prologue_start + 64; /* See above. */ - } - } - else - { - /* Get address of the stmfd in the prologue of the callee; the saved - PC is the address of the stmfd + 8. */ - if (!safe_read_memory_integer (fi->frame, 4, &return_value)) - return; - else - { - prologue_start = ADDR_BITS_REMOVE (return_value) - 8; - prologue_end = prologue_start + 64; /* See above. */ - } - } - - /* Now search the prologue looking for instructions that set up the - frame pointer, adjust the stack pointer, and save registers. - - Be careful, however, and if it doesn't look like a prologue, - don't try to scan it. If, for instance, a frameless function - begins with stmfd sp!, then we will tell ourselves there is - a frame, which will confuse stack traceback, as well ad"finish" - and other operations that rely on a knowledge of the stack - traceback. - - In the APCS, the prologue should start with "mov ip, sp" so - if we don't see this as the first insn, we will stop. [Note: - This doesn't seem to be true any longer, so it's now an optional - part of the prologue. - Kevin Buettner, 2001-11-20] */ - - sp_offset = fp_offset = 0; - - if (read_memory_unsigned_integer (prologue_start, 4) - == 0xe1a0c00d) /* mov ip, sp */ - current_pc = prologue_start + 4; - else - current_pc = prologue_start; - - for (; current_pc < prologue_end; current_pc += 4) - { - unsigned int insn = read_memory_unsigned_integer (current_pc, 4); - - if ((insn & 0xffff0000) == 0xe92d0000) - /* stmfd sp!, {..., fp, ip, lr, pc} - or - stmfd sp!, {a1, a2, a3, a4} */ - { - int mask = insn & 0xffff; - - /* Calculate offsets of saved registers. */ - for (regno = ARM_PC_REGNUM; regno >= 0; regno--) - if (mask & (1 << regno)) - { - sp_offset -= 4; - fi->saved_regs[regno] = sp_offset; - } - } - else if ((insn & 0xfffff000) == 0xe24cb000) /* sub fp, ip #n */ - { - unsigned imm = insn & 0xff; /* immediate value */ - unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ - imm = (imm >> rot) | (imm << (32 - rot)); - fp_offset = -imm; - fi->extra_info->framereg = ARM_FP_REGNUM; - } - else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */ - { - unsigned imm = insn & 0xff; /* immediate value */ - unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ - imm = (imm >> rot) | (imm << (32 - rot)); - sp_offset -= imm; - } - else if ((insn & 0xffff7fff) == 0xed6d0103) /* stfe f?, [sp, -#c]! */ - { - sp_offset -= 12; - regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07); - fi->saved_regs[regno] = sp_offset; - } - else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */ - { - int n_saved_fp_regs; - unsigned int fp_start_reg, fp_bound_reg; - - if ((insn & 0x800) == 0x800) /* N0 is set */ - { - if ((insn & 0x40000) == 0x40000) /* N1 is set */ - n_saved_fp_regs = 3; - else - n_saved_fp_regs = 1; - } - else - { - if ((insn & 0x40000) == 0x40000) /* N1 is set */ - n_saved_fp_regs = 2; - else - n_saved_fp_regs = 4; - } - - fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7); - fp_bound_reg = fp_start_reg + n_saved_fp_regs; - for (; fp_start_reg < fp_bound_reg; fp_start_reg++) - { - sp_offset -= 12; - fi->saved_regs[fp_start_reg++] = sp_offset; - } - } - else if ((insn & 0xf0000000) != 0xe0000000) - break; /* Condition not true, exit early */ - else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */ - break; /* Don't scan past a block load */ - else - /* The optimizer might shove anything into the prologue, - so we just skip what we don't recognize. */ - continue; - } - - /* 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->extra_info->framesize = -sp_offset; - if (fi->extra_info->framereg == ARM_FP_REGNUM) - fi->extra_info->frameoffset = fp_offset - sp_offset; - else - fi->extra_info->frameoffset = 0; - - save_prologue_cache (fi); -} - -/* 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. */ - -static CORE_ADDR -arm_find_callers_reg (struct frame_info *fi, int regnum) -{ - for (; fi; fi = fi->next) - -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) - return generic_read_register_dummy (fi->pc, fi->frame, regnum); - else -#endif - if (fi->saved_regs[regnum] != 0) - return read_memory_integer (fi->saved_regs[regnum], - REGISTER_RAW_SIZE (regnum)); - return read_register (regnum); -} -/* Function: frame_chain Given a GDB frame, determine the address of - the calling function's frame. This will be used to create a new - GDB frame struct, and then INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC - will be called for the new frame. For ARM, we save the frame size - when we initialize the frame_info. */ - -static CORE_ADDR -arm_frame_chain (struct frame_info *fi) -{ -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - CORE_ADDR fn_start, callers_pc, fp; - - /* 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 = arm_find_callers_reg (fi, ARM_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 */ -#endif - CORE_ADDR caller_pc, fn_start; - int framereg = fi->extra_info->framereg; - - if (fi->pc < LOWEST_PC) - return 0; - - /* If the caller is the startup code, we're at the end of the chain. */ - caller_pc = FRAME_SAVED_PC (fi); - if (find_pc_partial_function (caller_pc, 0, &fn_start, 0)) - if (fn_start == entry_point_address ()) - return 0; - - /* If the caller is Thumb and the caller is ARM, or vice versa, - the frame register of the caller is different from ours. - So we must scan the prologue of the caller to determine its - frame register number. */ - /* XXX Fixme, we should try to do this without creating a temporary - caller_fi. */ - if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (fi->pc)) - { - struct frame_info caller_fi; - struct cleanup *old_chain; - - /* Create a temporary frame suitable for scanning the caller's - prologue. (Ugh.) */ - memset (&caller_fi, 0, sizeof (caller_fi)); - caller_fi.extra_info = (struct frame_extra_info *) - xcalloc (1, sizeof (struct frame_extra_info)); - old_chain = make_cleanup (xfree, caller_fi.extra_info); - caller_fi.saved_regs = (CORE_ADDR *) - xcalloc (1, SIZEOF_FRAME_SAVED_REGS); - make_cleanup (xfree, caller_fi.saved_regs); - - /* Now, scan the prologue and obtain the frame register. */ - caller_fi.pc = caller_pc; - arm_scan_prologue (&caller_fi); - framereg = caller_fi.extra_info->framereg; - - /* Deallocate the storage associated with the temporary frame - created above. */ - do_cleanups (old_chain); - } - - /* If the caller used a frame register, return its value. - Otherwise, return the caller's stack pointer. */ - if (framereg == ARM_FP_REGNUM || framereg == THUMB_FP_REGNUM) - return arm_find_callers_reg (fi, framereg); - else - return fi->frame + fi->extra_info->framesize; -} - -/* This function actually figures out the frame address for a given pc - and sp. This is tricky because we sometimes don't use an explicit - frame pointer, and the previous stack pointer isn't necessarily - recorded on the stack. The only reliable way to get this info is - to examine the prologue. FROMLEAF is a little confusing, it means - this is the next frame up the chain AFTER a frameless function. If - this is true, then the frame value for this frame is still in the - fp register. */ - -static void -arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) -{ - int reg; - CORE_ADDR sp; - - if (fi->saved_regs == NULL) - frame_saved_regs_zalloc (fi); - - fi->extra_info = (struct frame_extra_info *) - frame_obstack_alloc (sizeof (struct frame_extra_info)); - - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - fi->extra_info->framereg = 0; - - if (fi->next) - fi->pc = FRAME_SAVED_PC (fi->next); - - memset (fi->saved_regs, '\000', sizeof fi->saved_regs); - -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - 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, - ARM_SP_REGNUM); - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - return; - } - else -#endif - - /* Compute stack pointer for this frame. We use this value for both the - sigtramp and call dummy cases. */ - if (!fi->next) - sp = read_sp(); - else - sp = (fi->next->frame - fi->next->extra_info->frameoffset - + fi->next->extra_info->framesize); - - /* Determine whether or not we're in a sigtramp frame. - Unfortunately, it isn't sufficient to test - fi->signal_handler_caller because this value is sometimes set - after invoking INIT_EXTRA_FRAME_INFO. So we test *both* - fi->signal_handler_caller and IN_SIGTRAMP to determine if we need - to use the sigcontext addresses for the saved registers. - - Note: If an ARM IN_SIGTRAMP method ever needs to compare against - the name of the function, the code below will have to be changed - to first fetch the name of the function and then pass this name - to IN_SIGTRAMP. */ - - if (SIGCONTEXT_REGISTER_ADDRESS_P () - && (fi->signal_handler_caller || IN_SIGTRAMP (fi->pc, (char *)0))) - { - for (reg = 0; reg < NUM_REGS; reg++) - fi->saved_regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, fi->pc, reg); - - /* FIXME: What about thumb mode? */ - fi->extra_info->framereg = ARM_SP_REGNUM; - fi->frame = - read_memory_integer (fi->saved_regs[fi->extra_info->framereg], - REGISTER_RAW_SIZE (fi->extra_info->framereg)); - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - - } - else if (PC_IN_CALL_DUMMY (fi->pc, sp, fi->frame)) - { - CORE_ADDR rp; - CORE_ADDR callers_sp; - - /* Set rp point at the high end of the saved registers. */ - rp = fi->frame - REGISTER_SIZE; - - /* Fill in addresses of saved registers. */ - fi->saved_regs[ARM_PS_REGNUM] = rp; - rp -= REGISTER_RAW_SIZE (ARM_PS_REGNUM); - for (reg = ARM_PC_REGNUM; reg >= 0; reg--) - { - fi->saved_regs[reg] = rp; - rp -= REGISTER_RAW_SIZE (reg); - } - - callers_sp = read_memory_integer (fi->saved_regs[ARM_SP_REGNUM], - REGISTER_RAW_SIZE (ARM_SP_REGNUM)); - fi->extra_info->framereg = ARM_FP_REGNUM; - fi->extra_info->framesize = callers_sp - sp; - fi->extra_info->frameoffset = fi->frame - sp; - } - else - { - arm_scan_prologue (fi); - - if (!fi->next) - /* this is the innermost frame? */ - fi->frame = read_register (fi->extra_info->framereg); - else if (fi->extra_info->framereg == ARM_FP_REGNUM - || fi->extra_info->framereg == THUMB_FP_REGNUM) - { - /* not the innermost frame */ - /* If we have an FP, the callee saved it. */ - if (fi->next->saved_regs[fi->extra_info->framereg] != 0) - fi->frame = - read_memory_integer (fi->next - ->saved_regs[fi->extra_info->framereg], 4); - else if (fromleaf) - /* If we were called by a frameless fn. then our frame is - still in the frame pointer register on the board... */ - fi->frame = read_fp (); - } - - /* Calculate actual addresses of saved registers using offsets - determined by arm_scan_prologue. */ - for (reg = 0; reg < NUM_REGS; reg++) - if (fi->saved_regs[reg] != 0) - fi->saved_regs[reg] += (fi->frame + fi->extra_info->framesize - - fi->extra_info->frameoffset); - } -} - - -/* Find the caller of this frame. We do this by seeing if ARM_LR_REGNUM - is saved in the stack anywhere, otherwise we get it from the - registers. - - The old definition of this function was a macro: - #define FRAME_SAVED_PC(FRAME) \ - ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */ - -static CORE_ADDR -arm_frame_saved_pc (struct frame_info *fi) -{ -#if 0 /* FIXME: enable this code if we convert to new call dummy scheme. */ - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) - return generic_read_register_dummy (fi->pc, fi->frame, ARM_PC_REGNUM); - else -#endif - if (PC_IN_CALL_DUMMY (fi->pc, fi->frame - fi->extra_info->frameoffset, - fi->frame)) - { - return read_memory_integer (fi->saved_regs[ARM_PC_REGNUM], - REGISTER_RAW_SIZE (ARM_PC_REGNUM)); - } - else - { - CORE_ADDR pc = arm_find_callers_reg (fi, ARM_LR_REGNUM); - return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc; - } -} - -/* Return the frame address. On ARM, it is R11; on Thumb it is R7. - Examine the Program Status Register to decide which state we're in. */ - -static CORE_ADDR -arm_read_fp (void) -{ - if (read_register (ARM_PS_REGNUM) & 0x20) /* Bit 5 is Thumb state bit */ - return read_register (THUMB_FP_REGNUM); /* R7 if Thumb */ - else - return read_register (ARM_FP_REGNUM); /* R11 if ARM */ -} - -/* Store into a struct frame_saved_regs the addresses of the saved - registers of frame described by FRAME_INFO. This includes special - registers such as PC and FP saved in special ways in the stack - frame. SP is even more special: the address we return for it IS - the sp for the next frame. */ - -static void -arm_frame_init_saved_regs (struct frame_info *fip) -{ - - if (fip->saved_regs) - return; - - arm_init_extra_frame_info (0, fip); -} - -/* Push an empty stack frame, to record the current PC, etc. */ - -static void -arm_push_dummy_frame (void) -{ - CORE_ADDR old_sp = read_register (ARM_SP_REGNUM); - CORE_ADDR sp = old_sp; - CORE_ADDR fp, prologue_start; - int regnum; - - /* Push the two dummy prologue instructions in reverse order, - so that they'll be in the correct low-to-high order in memory. */ - /* sub fp, ip, #4 */ - sp = push_word (sp, 0xe24cb004); - /* stmdb sp!, {r0-r10, fp, ip, lr, pc} */ - prologue_start = sp = push_word (sp, 0xe92ddfff); - - /* Push a pointer to the dummy prologue + 12, because when stm - instruction stores the PC, it stores the address of the stm - instruction itself plus 12. */ - fp = sp = push_word (sp, prologue_start + 12); - - /* Push the processor status. */ - sp = push_word (sp, read_register (ARM_PS_REGNUM)); - - /* Push all 16 registers starting with r15. */ - for (regnum = ARM_PC_REGNUM; regnum >= 0; regnum--) - sp = push_word (sp, read_register (regnum)); - - /* Update fp (for both Thumb and ARM) and sp. */ - write_register (ARM_FP_REGNUM, fp); - write_register (THUMB_FP_REGNUM, fp); - write_register (ARM_SP_REGNUM, sp); -} - -/* CALL_DUMMY_WORDS: - This sequence of words is the instructions - - mov lr,pc - mov pc,r4 - illegal - - Note this is 12 bytes. */ - -static LONGEST arm_call_dummy_words[] = -{ - 0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe -}; - -/* Adjust the call_dummy_breakpoint_offset for the bp_call_dummy - breakpoint to the proper address in the call dummy, so that - `finish' after a stop in a call dummy works. - - FIXME rearnsha 2002-02018: Tweeking current_gdbarch is not an - optimal solution, but the call to arm_fix_call_dummy is immediately - followed by a call to run_stack_dummy, which is the only function - where call_dummy_breakpoint_offset is actually used. */ - - -static void -arm_set_call_dummy_breakpoint_offset (void) -{ - if (caller_is_thumb) - set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 4); - else - set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 8); -} - -/* Fix up the call dummy, based on whether the processor is currently - in Thumb or ARM mode, and whether the target function is Thumb or - ARM. There are three different situations requiring three - different dummies: - - * ARM calling ARM: uses the call dummy in tm-arm.h, which has already - been copied into the dummy parameter to this function. - * ARM calling Thumb: uses the call dummy in tm-arm.h, but with the - "mov pc,r4" instruction patched to be a "bx r4" instead. - * Thumb calling anything: uses the Thumb dummy defined below, which - works for calling both ARM and Thumb functions. - - All three call dummies expect to receive the target function - address in R4, with the low bit set if it's a Thumb function. */ - -static void -arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, - struct value **args, struct type *type, int gcc_p) -{ - static short thumb_dummy[4] = - { - 0xf000, 0xf801, /* bl label */ - 0xdf18, /* swi 24 */ - 0x4720, /* label: bx r4 */ - }; - static unsigned long arm_bx_r4 = 0xe12fff14; /* bx r4 instruction */ - - /* Set flag indicating whether the current PC is in a Thumb function. */ - caller_is_thumb = arm_pc_is_thumb (read_pc ()); - arm_set_call_dummy_breakpoint_offset (); - - /* If the target function is Thumb, set the low bit of the function - address. And if the CPU is currently in ARM mode, patch the - second instruction of call dummy to use a BX instruction to - switch to Thumb mode. */ - target_is_thumb = arm_pc_is_thumb (fun); - if (target_is_thumb) - { - fun |= 1; - if (!caller_is_thumb) - store_unsigned_integer (dummy + 4, sizeof (arm_bx_r4), arm_bx_r4); - } - - /* If the CPU is currently in Thumb mode, use the Thumb call dummy - instead of the ARM one that's already been copied. This will - work for both Thumb and ARM target functions. */ - if (caller_is_thumb) - { - int i; - char *p = dummy; - int len = sizeof (thumb_dummy) / sizeof (thumb_dummy[0]); - - for (i = 0; i < len; i++) - { - store_unsigned_integer (p, sizeof (thumb_dummy[0]), thumb_dummy[i]); - p += sizeof (thumb_dummy[0]); - } - } - - /* Put the target address in r4; the call dummy will copy this to - the PC. */ - write_register (4, fun); -} - -/* Note: ScottB - - This function does not support passing parameters using the FPA - variant of the APCS. It passes any floating point arguments in the - general registers and/or on the stack. */ - -static CORE_ADDR -arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) -{ - char *fp; - int argnum, argreg, nstack_size; - - /* Walk through the list of args and determine how large a temporary - stack is required. Need to take care here as structs may be - passed on the stack, and we have to to push them. */ - nstack_size = -4 * REGISTER_SIZE; /* Some arguments go into A1-A4. */ - if (struct_return) /* The struct address goes in A1. */ - nstack_size += REGISTER_SIZE; - - /* Walk through the arguments and add their size to nstack_size. */ - for (argnum = 0; argnum < nargs; argnum++) - { - int len; - struct type *arg_type; - - arg_type = check_typedef (VALUE_TYPE (args[argnum])); - len = TYPE_LENGTH (arg_type); - - nstack_size += len; - } - - /* Allocate room on the stack, and initialize our stack frame - pointer. */ - fp = NULL; - if (nstack_size > 0) - { - sp -= nstack_size; - fp = (char *) sp; - } - - /* Initialize the integer argument register pointer. */ - argreg = ARM_A1_REGNUM; - - /* The struct_return pointer occupies the first parameter passing - register. */ - if (struct_return) - write_register (argreg++, struct_addr); - - /* Process arguments from left to right. Store as many as allowed - in the parameter passing registers (A1-A4), and save the rest on - the temporary stack. */ - for (argnum = 0; argnum < nargs; argnum++) - { - int len; - char *val; - CORE_ADDR regval; - enum type_code typecode; - struct type *arg_type, *target_type; - - arg_type = check_typedef (VALUE_TYPE (args[argnum])); - target_type = TYPE_TARGET_TYPE (arg_type); - len = TYPE_LENGTH (arg_type); - typecode = TYPE_CODE (arg_type); - val = (char *) VALUE_CONTENTS (args[argnum]); - -#if 1 - /* I don't know why this code was disable. The only logical use - for a function pointer is to call that function, so setting - the mode bit is perfectly fine. FN */ - /* If the argument is a pointer to a function, and it is a Thumb - function, set the low bit of the pointer. */ - if (TYPE_CODE_PTR == typecode - && NULL != target_type - && TYPE_CODE_FUNC == TYPE_CODE (target_type)) - { - CORE_ADDR regval = extract_address (val, len); - if (arm_pc_is_thumb (regval)) - store_address (val, len, MAKE_THUMB_ADDR (regval)); - } -#endif - /* Copy the argument to general registers or the stack in - register-sized pieces. Large arguments are split between - registers and stack. */ - while (len > 0) - { - int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE; - - if (argreg <= ARM_LAST_ARG_REGNUM) - { - /* It's an argument being passed in a general register. */ - regval = extract_address (val, partial_len); - write_register (argreg++, regval); - } - else - { - /* Push the arguments onto the stack. */ - write_memory ((CORE_ADDR) fp, val, REGISTER_SIZE); - fp += REGISTER_SIZE; - } - - len -= partial_len; - val += partial_len; - } - } - - /* Return adjusted stack pointer. */ - return sp; -} - -/* Pop the current frame. So long as the frame info has been initialized - properly (see arm_init_extra_frame_info), this code works for dummy frames - as well as regular frames. I.e, there's no need to have a special case - for dummy frames. */ -static void -arm_pop_frame (void) -{ - int regnum; - struct frame_info *frame = get_current_frame (); - CORE_ADDR old_SP = (frame->frame - frame->extra_info->frameoffset - + frame->extra_info->framesize); - - for (regnum = 0; regnum < NUM_REGS; regnum++) - if (frame->saved_regs[regnum] != 0) - write_register (regnum, - read_memory_integer (frame->saved_regs[regnum], - REGISTER_RAW_SIZE (regnum))); - - write_register (ARM_PC_REGNUM, FRAME_SAVED_PC (frame)); - write_register (ARM_SP_REGNUM, old_SP); - - flush_cached_frames (); -} - -static void -print_fpu_flags (int flags) -{ - if (flags & (1 << 0)) - fputs ("IVO ", stdout); - if (flags & (1 << 1)) - fputs ("DVZ ", stdout); - if (flags & (1 << 2)) - fputs ("OFL ", stdout); - if (flags & (1 << 3)) - fputs ("UFL ", stdout); - if (flags & (1 << 4)) - fputs ("INX ", stdout); - putchar ('\n'); -} - -/* Print interesting information about the floating point processor - (if present) or emulator. */ -static void -arm_print_float_info (void) -{ - register unsigned long status = read_register (ARM_FPS_REGNUM); - int type; - - type = (status >> 24) & 127; - printf ("%s FPU type %d\n", - (status & (1 << 31)) ? "Hardware" : "Software", - type); - fputs ("mask: ", stdout); - print_fpu_flags (status >> 16); - fputs ("flags: ", stdout); - print_fpu_flags (status); -} - -/* Return the GDB type object for the "standard" data type of data in - register N. */ - -static struct type * -arm_register_type (int regnum) -{ - if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) - { - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) - return builtin_type_arm_ext_big; - else - return builtin_type_arm_ext_littlebyte_bigword; - } - else - return builtin_type_int32; -} - -/* Index within `registers' of the first byte of the space for - register N. */ - -static int -arm_register_byte (int regnum) -{ - if (regnum < ARM_F0_REGNUM) - return regnum * INT_REGISTER_RAW_SIZE; - else if (regnum < ARM_PS_REGNUM) - return (NUM_GREGS * INT_REGISTER_RAW_SIZE - + (regnum - ARM_F0_REGNUM) * FP_REGISTER_RAW_SIZE); - else - return (NUM_GREGS * INT_REGISTER_RAW_SIZE - + NUM_FREGS * FP_REGISTER_RAW_SIZE - + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE); -} - -/* Number of bytes of storage in the actual machine representation for - register N. All registers are 4 bytes, except fp0 - fp7, which are - 12 bytes in length. */ - -static int -arm_register_raw_size (int regnum) -{ - if (regnum < ARM_F0_REGNUM) - return INT_REGISTER_RAW_SIZE; - else if (regnum < ARM_FPS_REGNUM) - return FP_REGISTER_RAW_SIZE; - else - return STATUS_REGISTER_SIZE; -} - -/* Number of bytes of storage in a program's representation - for register N. */ -static int -arm_register_virtual_size (int regnum) -{ - if (regnum < ARM_F0_REGNUM) - return INT_REGISTER_VIRTUAL_SIZE; - else if (regnum < ARM_FPS_REGNUM) - return FP_REGISTER_VIRTUAL_SIZE; - else - return STATUS_REGISTER_SIZE; -} - - -/* NOTE: cagney/2001-08-20: Both convert_from_extended() and - convert_to_extended() use floatformat_arm_ext_littlebyte_bigword. - It is thought that this is is the floating-point register format on - little-endian systems. */ - -static void -convert_from_extended (void *ptr, void *dbl) -{ - DOUBLEST d; - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) - floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d); - else - floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword, - ptr, &d); - floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &d, dbl); -} - -static void -convert_to_extended (void *dbl, void *ptr) -{ - DOUBLEST d; - floatformat_to_doublest (TARGET_DOUBLE_FORMAT, ptr, &d); - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) - floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl); - else - floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword, - &d, dbl); -} - -static int -condition_true (unsigned long cond, unsigned long status_reg) -{ - if (cond == INST_AL || cond == INST_NV) - return 1; - - switch (cond) - { - case INST_EQ: - return ((status_reg & FLAG_Z) != 0); - case INST_NE: - return ((status_reg & FLAG_Z) == 0); - case INST_CS: - return ((status_reg & FLAG_C) != 0); - case INST_CC: - return ((status_reg & FLAG_C) == 0); - case INST_MI: - return ((status_reg & FLAG_N) != 0); - case INST_PL: - return ((status_reg & FLAG_N) == 0); - case INST_VS: - return ((status_reg & FLAG_V) != 0); - case INST_VC: - return ((status_reg & FLAG_V) == 0); - case INST_HI: - return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C); - case INST_LS: - return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C); - case INST_GE: - return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)); - case INST_LT: - return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)); - case INST_GT: - return (((status_reg & FLAG_Z) == 0) && - (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0))); - case INST_LE: - return (((status_reg & FLAG_Z) != 0) || - (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0))); - } - return 1; -} - -/* Support routines for single stepping. Calculate the next PC value. */ -#define submask(x) ((1L << ((x) + 1)) - 1) -#define bit(obj,st) (((obj) >> (st)) & 1) -#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st))) -#define sbits(obj,st,fn) \ - ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st)))) -#define BranchDest(addr,instr) \ - ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2))) -#define ARM_PC_32 1 - -static unsigned long -shifted_reg_val (unsigned long inst, int carry, unsigned long pc_val, - unsigned long status_reg) -{ - unsigned long res, shift; - int rm = bits (inst, 0, 3); - unsigned long shifttype = bits (inst, 5, 6); - - if (bit (inst, 4)) - { - int rs = bits (inst, 8, 11); - shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF; - } - else - shift = bits (inst, 7, 11); - - res = (rm == 15 - ? ((pc_val | (ARM_PC_32 ? 0 : status_reg)) - + (bit (inst, 4) ? 12 : 8)) - : read_register (rm)); - - switch (shifttype) - { - case 0: /* LSL */ - res = shift >= 32 ? 0 : res << shift; - break; - - case 1: /* LSR */ - res = shift >= 32 ? 0 : res >> shift; - break; - - case 2: /* ASR */ - if (shift >= 32) - shift = 31; - res = ((res & 0x80000000L) - ? ~((~res) >> shift) : res >> shift); - break; - - case 3: /* ROR/RRX */ - shift &= 31; - if (shift == 0) - res = (res >> 1) | (carry ? 0x80000000L : 0); - else - res = (res >> shift) | (res << (32 - shift)); - break; - } - - return res & 0xffffffff; -} - -/* Return number of 1-bits in VAL. */ - -static int -bitcount (unsigned long val) -{ - int nbits; - for (nbits = 0; val != 0; nbits++) - val &= val - 1; /* delete rightmost 1-bit in val */ - return nbits; -} - -CORE_ADDR -thumb_get_next_pc (CORE_ADDR pc) -{ - unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */ - unsigned short inst1 = read_memory_integer (pc, 2); - CORE_ADDR nextpc = pc + 2; /* default is next instruction */ - unsigned long offset; - - if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */ - { - CORE_ADDR sp; - - /* Fetch the saved PC from the stack. It's stored above - all of the other registers. */ - offset = bitcount (bits (inst1, 0, 7)) * REGISTER_SIZE; - sp = read_register (ARM_SP_REGNUM); - nextpc = (CORE_ADDR) read_memory_integer (sp + offset, 4); - nextpc = ADDR_BITS_REMOVE (nextpc); - if (nextpc == pc) - error ("Infinite loop detected"); - } - else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */ - { - unsigned long status = read_register (ARM_PS_REGNUM); - unsigned long cond = bits (inst1, 8, 11); - if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */ - nextpc = pc_val + (sbits (inst1, 0, 7) << 1); - } - else if ((inst1 & 0xf800) == 0xe000) /* unconditional branch */ - { - nextpc = pc_val + (sbits (inst1, 0, 10) << 1); - } - else if ((inst1 & 0xf800) == 0xf000) /* long branch with link */ - { - unsigned short inst2 = read_memory_integer (pc + 2, 2); - offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1); - nextpc = pc_val + offset; - } - - return nextpc; -} - -CORE_ADDR -arm_get_next_pc (CORE_ADDR pc) -{ - unsigned long pc_val; - unsigned long this_instr; - unsigned long status; - CORE_ADDR nextpc; - - if (arm_pc_is_thumb (pc)) - return thumb_get_next_pc (pc); - - pc_val = (unsigned long) pc; - this_instr = read_memory_integer (pc, 4); - status = read_register (ARM_PS_REGNUM); - nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */ - - if (condition_true (bits (this_instr, 28, 31), status)) - { - switch (bits (this_instr, 24, 27)) - { - case 0x0: - case 0x1: /* data processing */ - case 0x2: - case 0x3: - { - unsigned long operand1, operand2, result = 0; - unsigned long rn; - int c; - - if (bits (this_instr, 12, 15) != 15) - break; - - if (bits (this_instr, 22, 25) == 0 - && bits (this_instr, 4, 7) == 9) /* multiply */ - error ("Illegal update to pc in instruction"); - - /* Multiply into PC */ - c = (status & FLAG_C) ? 1 : 0; - rn = bits (this_instr, 16, 19); - operand1 = (rn == 15) ? pc_val + 8 : read_register (rn); - - if (bit (this_instr, 25)) - { - unsigned long immval = bits (this_instr, 0, 7); - unsigned long rotate = 2 * bits (this_instr, 8, 11); - operand2 = ((immval >> rotate) | (immval << (32 - rotate))) - & 0xffffffff; - } - else /* operand 2 is a shifted register */ - operand2 = shifted_reg_val (this_instr, c, pc_val, status); - - switch (bits (this_instr, 21, 24)) - { - case 0x0: /*and */ - result = operand1 & operand2; - break; - - case 0x1: /*eor */ - result = operand1 ^ operand2; - break; - - case 0x2: /*sub */ - result = operand1 - operand2; - break; - - case 0x3: /*rsb */ - result = operand2 - operand1; - break; - - case 0x4: /*add */ - result = operand1 + operand2; - break; - - case 0x5: /*adc */ - result = operand1 + operand2 + c; - break; - - case 0x6: /*sbc */ - result = operand1 - operand2 + c; - break; - - case 0x7: /*rsc */ - result = operand2 - operand1 + c; - break; - - case 0x8: - case 0x9: - case 0xa: - case 0xb: /* tst, teq, cmp, cmn */ - result = (unsigned long) nextpc; - break; - - case 0xc: /*orr */ - result = operand1 | operand2; - break; - - case 0xd: /*mov */ - /* Always step into a function. */ - result = operand2; - break; - - case 0xe: /*bic */ - result = operand1 & ~operand2; - break; - - case 0xf: /*mvn */ - result = ~operand2; - break; - } - nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result); - - if (nextpc == pc) - error ("Infinite loop detected"); - break; - } - - case 0x4: - case 0x5: /* data transfer */ - case 0x6: - case 0x7: - if (bit (this_instr, 20)) - { - /* load */ - if (bits (this_instr, 12, 15) == 15) - { - /* rd == pc */ - unsigned long rn; - unsigned long base; - - if (bit (this_instr, 22)) - error ("Illegal update to pc in instruction"); - - /* byte write to PC */ - rn = bits (this_instr, 16, 19); - base = (rn == 15) ? pc_val + 8 : read_register (rn); - if (bit (this_instr, 24)) - { - /* pre-indexed */ - int c = (status & FLAG_C) ? 1 : 0; - unsigned long offset = - (bit (this_instr, 25) - ? shifted_reg_val (this_instr, c, pc_val, status) - : bits (this_instr, 0, 11)); - - if (bit (this_instr, 23)) - base += offset; - else - base -= offset; - } - nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base, - 4); - - nextpc = ADDR_BITS_REMOVE (nextpc); - - if (nextpc == pc) - error ("Infinite loop detected"); - } - } - break; - - case 0x8: - case 0x9: /* block transfer */ - if (bit (this_instr, 20)) - { - /* LDM */ - if (bit (this_instr, 15)) - { - /* loading pc */ - int offset = 0; - - if (bit (this_instr, 23)) - { - /* up */ - unsigned long reglist = bits (this_instr, 0, 14); - offset = bitcount (reglist) * 4; - if (bit (this_instr, 24)) /* pre */ - offset += 4; - } - else if (bit (this_instr, 24)) - offset = -4; - - { - unsigned long rn_val = - read_register (bits (this_instr, 16, 19)); - nextpc = - (CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val - + offset), - 4); - } - nextpc = ADDR_BITS_REMOVE (nextpc); - if (nextpc == pc) - error ("Infinite loop detected"); - } - } - break; - - case 0xb: /* branch & link */ - case 0xa: /* branch */ - { - nextpc = BranchDest (pc, this_instr); - - nextpc = ADDR_BITS_REMOVE (nextpc); - if (nextpc == pc) - error ("Infinite loop detected"); - break; - } - - case 0xc: - case 0xd: - case 0xe: /* coproc ops */ - case 0xf: /* SWI */ - break; - - default: - fprintf_filtered (gdb_stderr, "Bad bit-field extraction\n"); - return (pc); - } - } - - return nextpc; -} - -/* single_step() is called just before we want to resume the inferior, - if we want to single-step it but there is no hardware or kernel - single-step support. We find the target of the coming instruction - and breakpoint it. - - single_step is also called just after the inferior stops. If we had - set up a simulated single-step, we undo our damage. */ - -static void -arm_software_single_step (enum target_signal sig, int insert_bpt) -{ - static int next_pc; /* State between setting and unsetting. */ - static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */ - - if (insert_bpt) - { - next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM)); - target_insert_breakpoint (next_pc, break_mem); - } - else - target_remove_breakpoint (next_pc, break_mem); -} - -#include "bfd-in2.h" -#include "libcoff.h" - -static int -gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info) -{ - if (arm_pc_is_thumb (memaddr)) - { - static asymbol *asym; - static combined_entry_type ce; - static struct coff_symbol_struct csym; - static struct _bfd fake_bfd; - static bfd_target fake_target; - - if (csym.native == NULL) - { - /* Create a fake symbol vector containing a Thumb symbol. This is - solely so that the code in print_insn_little_arm() and - print_insn_big_arm() in opcodes/arm-dis.c will detect the presence - of a Thumb symbol and switch to decoding Thumb instructions. */ - - fake_target.flavour = bfd_target_coff_flavour; - fake_bfd.xvec = &fake_target; - ce.u.syment.n_sclass = C_THUMBEXTFUNC; - csym.native = &ce; - csym.symbol.the_bfd = &fake_bfd; - csym.symbol.name = "fake"; - asym = (asymbol *) & csym; - } - - memaddr = UNMAKE_THUMB_ADDR (memaddr); - info->symbols = &asym; - } - else - info->symbols = NULL; - - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) - return print_insn_big_arm (memaddr, info); - else - return print_insn_little_arm (memaddr, info); -} - -/* The following define instruction sequences that will cause ARM - cpu's to take an undefined instruction trap. These are used to - signal a breakpoint to GDB. - - The newer ARMv4T cpu's are capable of operating in ARM or Thumb - modes. A different instruction is required for each mode. The ARM - cpu's can also be big or little endian. Thus four different - instructions are needed to support all cases. - - Note: ARMv4 defines several new instructions that will take the - undefined instruction trap. ARM7TDMI is nominally ARMv4T, but does - not in fact add the new instructions. The new undefined - instructions in ARMv4 are all instructions that had no defined - behaviour in earlier chips. There is no guarantee that they will - raise an exception, but may be treated as NOP's. In practice, it - may only safe to rely on instructions matching: - - 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 - 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x - - Even this may only true if the condition predicate is true. The - following use a condition predicate of ALWAYS so it is always TRUE. - - There are other ways of forcing a breakpoint. GNU/Linux, RISC iX, - and NetBSD all use a software interrupt rather than an undefined - instruction to force a trap. This can be handled by by the - abi-specific code during establishment of the gdbarch vector. */ - - -/* NOTE rearnsha 2002-02-18: for now we allow a non-multi-arch gdb to - override these definitions. */ -#ifndef ARM_LE_BREAKPOINT -#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7} -#endif -#ifndef ARM_BE_BREAKPOINT -#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE} -#endif -#ifndef THUMB_LE_BREAKPOINT -#define THUMB_LE_BREAKPOINT {0xfe,0xdf} -#endif -#ifndef THUMB_BE_BREAKPOINT -#define THUMB_BE_BREAKPOINT {0xdf,0xfe} -#endif - -static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT; -static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT; -static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT; -static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT; - -/* Determine the type and size of breakpoint to insert at PCPTR. Uses - the program counter value to determine whether a 16-bit or 32-bit - breakpoint should be used. It returns a pointer to a string of - bytes that encode a breakpoint instruction, stores the length of - the string to *lenptr, and adjusts the program counter (if - necessary) to point to the actual memory location where the - breakpoint should be inserted. */ - -/* XXX ??? from old tm-arm.h: if we're using RDP, then we're inserting - breakpoints and storing their handles instread of what was in - memory. It is nice that this is the same size as a handle - - otherwise remote-rdp will have to change. */ - -unsigned char * -arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (arm_pc_is_thumb (*pcptr) || arm_pc_is_thumb_dummy (*pcptr)) - { - *pcptr = UNMAKE_THUMB_ADDR (*pcptr); - *lenptr = tdep->thumb_breakpoint_size; - return tdep->thumb_breakpoint; - } - else - { - *lenptr = tdep->arm_breakpoint_size; - return tdep->arm_breakpoint; - } -} - -/* Extract from an array REGBUF containing the (raw) register state a - function return value of type TYPE, and copy that, in virtual - format, into VALBUF. */ - -static void -arm_extract_return_value (struct type *type, - char regbuf[REGISTER_BYTES], - char *valbuf) -{ - if (TYPE_CODE_FLT == TYPE_CODE (type)) - { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - switch (tdep->fp_model) - { - case ARM_FLOAT_FPA: - convert_from_extended (®buf[REGISTER_BYTE (ARM_F0_REGNUM)], - valbuf); - break; - - case ARM_FLOAT_SOFT: - case ARM_FLOAT_SOFT_VFP: - memcpy (valbuf, ®buf[REGISTER_BYTE (ARM_A1_REGNUM)], - TYPE_LENGTH (type)); - break; - - default: - internal_error - (__FILE__, __LINE__, - "arm_extract_return_value: Floating point model not supported"); - break; - } - } - else - memcpy (valbuf, ®buf[REGISTER_BYTE (ARM_A1_REGNUM)], - TYPE_LENGTH (type)); -} - -/* Extract from an array REGBUF containing the (raw) register state - the address in which a function should return its structure value. */ - -static CORE_ADDR -arm_extract_struct_value_address (char *regbuf) -{ - return extract_address (regbuf, REGISTER_RAW_SIZE(ARM_A1_REGNUM)); -} - -/* Will a function return an aggregate type in memory or in a - register? Return 0 if an aggregate type can be returned in a - register, 1 if it must be returned in memory. */ - -static int -arm_use_struct_convention (int gcc_p, struct type *type) -{ - int nRc; - register enum type_code code; - - /* In the ARM ABI, "integer" like aggregate types are returned in - registers. For an aggregate type to be integer like, its size - must be less than or equal to REGISTER_SIZE and the offset of - each addressable subfield must be zero. Note that bit fields are - not addressable, and all addressable subfields of unions always - start at offset zero. - - This function is based on the behaviour of GCC 2.95.1. - See: gcc/arm.c: arm_return_in_memory() for details. - - Note: All versions of GCC before GCC 2.95.2 do not set up the - parameters correctly for a function returning the following - structure: struct { float f;}; This should be returned in memory, - not a register. Richard Earnshaw sent me a patch, but I do not - know of any way to detect if a function like the above has been - compiled with the correct calling convention. */ - - /* All aggregate types that won't fit in a register must be returned - in memory. */ - if (TYPE_LENGTH (type) > REGISTER_SIZE) - { - return 1; - } - - /* The only aggregate types that can be returned in a register are - structs and unions. Arrays must be returned in memory. */ - code = TYPE_CODE (type); - if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code)) - { - return 1; - } - - /* Assume all other aggregate types can be returned in a register. - Run a check for structures, unions and arrays. */ - nRc = 0; - - if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code)) - { - int i; - /* Need to check if this struct/union is "integer" like. For - this to be true, its size must be less than or equal to - REGISTER_SIZE and the offset of each addressable subfield - must be zero. Note that bit fields are not addressable, and - unions always start at offset zero. If any of the subfields - is a floating point type, the struct/union cannot be an - integer type. */ - - /* For each field in the object, check: - 1) Is it FP? --> yes, nRc = 1; - 2) Is it addressable (bitpos != 0) and - not packed (bitsize == 0)? - --> yes, nRc = 1 - */ - - for (i = 0; i < TYPE_NFIELDS (type); i++) - { - enum type_code field_type_code; - field_type_code = TYPE_CODE (TYPE_FIELD_TYPE (type, i)); - - /* Is it a floating point type field? */ - if (field_type_code == TYPE_CODE_FLT) - { - nRc = 1; - break; - } - - /* If bitpos != 0, then we have to care about it. */ - if (TYPE_FIELD_BITPOS (type, i) != 0) - { - /* Bitfields are not addressable. If the field bitsize is - zero, then the field is not packed. Hence it cannot be - a bitfield or any other packed type. */ - if (TYPE_FIELD_BITSIZE (type, i) == 0) - { - nRc = 1; - break; - } - } - } - } - - return nRc; -} - -/* Write into appropriate registers a function return value of type - TYPE, given in virtual format. */ - -static void -arm_store_return_value (struct type *type, char *valbuf) -{ - if (TYPE_CODE (type) == TYPE_CODE_FLT) - { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - char buf[MAX_REGISTER_RAW_SIZE]; - - switch (tdep->fp_model) - { - case ARM_FLOAT_FPA: - - convert_to_extended (valbuf, buf); - write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf, - MAX_REGISTER_RAW_SIZE); - break; - - case ARM_FLOAT_SOFT: - case ARM_FLOAT_SOFT_VFP: - write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type)); - break; - - default: - internal_error - (__FILE__, __LINE__, - "arm_store_return_value: Floating point model not supported"); - break; - } - } - else - write_register_bytes (ARM_A1_REGNUM, valbuf, TYPE_LENGTH (type)); -} - -/* Store the address of the place in which to copy the structure the - subroutine will return. This is called from call_function. */ - -static void -arm_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) -{ - write_register (ARM_A1_REGNUM, addr); -} - -static int -arm_get_longjmp_target (CORE_ADDR *pc) -{ - CORE_ADDR jb_addr; - char buf[INT_REGISTER_RAW_SIZE]; - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - jb_addr = read_register (ARM_A1_REGNUM); - - if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf, - INT_REGISTER_RAW_SIZE)) - return 0; - - *pc = extract_address (buf, INT_REGISTER_RAW_SIZE); - return 1; -} - -/* Return non-zero if the PC is inside a thumb call thunk. */ - -int -arm_in_call_stub (CORE_ADDR pc, char *name) -{ - CORE_ADDR start_addr; - - /* Find the starting address of the function containing the PC. If - the caller didn't give us a name, look it up at the same time. */ - if (find_pc_partial_function (pc, name ? NULL : &name, &start_addr, NULL) == 0) - return 0; - - return strncmp (name, "_call_via_r", 11) == 0; -} - -/* If PC is in a Thumb call or return stub, return the address of the - target PC, which is in a register. The thunk functions are called - _called_via_xx, where x is the register name. The possible names - are r0-r9, sl, fp, ip, sp, and lr. */ - -CORE_ADDR -arm_skip_stub (CORE_ADDR pc) -{ - char *name; - CORE_ADDR start_addr; - - /* Find the starting address and name of the function containing the PC. */ - if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0) - return 0; - - /* Call thunks always start with "_call_via_". */ - if (strncmp (name, "_call_via_", 10) == 0) - { - /* Use the name suffix to determine which register contains the - target PC. */ - static char *table[15] = - {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "sl", "fp", "ip", "sp", "lr" - }; - int regno; - - for (regno = 0; regno <= 14; regno++) - if (strcmp (&name[10], table[regno]) == 0) - return read_register (regno); - } - - return 0; /* not a stub */ -} - -/* If the user changes the register disassembly flavor used for info register - and other commands, we have to also switch the flavor used in opcodes - for disassembly output. - This function is run in the set disassembly_flavor command, and does that. */ - -static void -set_disassembly_flavor_sfunc (char *args, int from_tty, - struct cmd_list_element *c) -{ - set_disassembly_flavor (); -} - -/* Return the ARM register name corresponding to register I. */ -static char * -arm_register_name (int i) -{ - return arm_register_names[i]; -} - -static void -set_disassembly_flavor (void) -{ - const char *setname, *setdesc, **regnames; - int numregs, j; - - /* Find the flavor that the user wants in the opcodes table. */ - int current = 0; - numregs = get_arm_regnames (current, &setname, &setdesc, ®names); - while ((disassembly_flavor != setname) - && (current < num_flavor_options)) - get_arm_regnames (++current, &setname, &setdesc, ®names); - current_option = current; - - /* Fill our copy. */ - for (j = 0; j < numregs; j++) - arm_register_names[j] = (char *) regnames[j]; - - /* Adjust case. */ - if (isupper (*regnames[ARM_PC_REGNUM])) - { - arm_register_names[ARM_FPS_REGNUM] = "FPS"; - arm_register_names[ARM_PS_REGNUM] = "CPSR"; - } - else - { - arm_register_names[ARM_FPS_REGNUM] = "fps"; - arm_register_names[ARM_PS_REGNUM] = "cpsr"; - } - - /* Synchronize the disassembler. */ - set_arm_regname_option (current); -} - -/* arm_othernames implements the "othernames" command. This is kind - of hacky, and I prefer the set-show disassembly-flavor which is - also used for the x86 gdb. I will keep this around, however, in - case anyone is actually using it. */ - -static void -arm_othernames (char *names, int n) -{ - /* Circle through the various flavors. */ - current_option = (current_option + 1) % num_flavor_options; - - disassembly_flavor = valid_flavors[current_option]; - set_disassembly_flavor (); -} - -/* Fetch, and possibly build, an appropriate link_map_offsets structure - for ARM linux targets using the struct offsets defined in <link.h>. - Note, however, that link.h is not actually referred to in this file. - Instead, the relevant structs offsets were obtained from examining - link.h. (We can't refer to link.h from this file because the host - system won't necessarily have it, or if it does, the structs which - it defines will refer to the host system, not the target.) */ - -struct link_map_offsets * -arm_linux_svr4_fetch_link_map_offsets (void) -{ - static struct link_map_offsets lmo; - static struct link_map_offsets *lmp = 0; - - if (lmp == 0) - { - lmp = &lmo; - - lmo.r_debug_size = 8; /* Actual size is 20, but this is all we - need. */ - - lmo.r_map_offset = 4; - lmo.r_map_size = 4; - - lmo.link_map_size = 20; /* Actual size is 552, but this is all we - need. */ - - lmo.l_addr_offset = 0; - lmo.l_addr_size = 4; - - lmo.l_name_offset = 4; - lmo.l_name_size = 4; - - lmo.l_next_offset = 12; - lmo.l_next_size = 4; - - lmo.l_prev_offset = 16; - lmo.l_prev_size = 4; - } - - return lmp; -} - -/* Test whether the coff symbol specific value corresponds to a Thumb - function. */ - -static int -coff_sym_is_thumb (int val) -{ - return (val == C_THUMBEXT || - val == C_THUMBSTAT || - val == C_THUMBEXTFUNC || - val == C_THUMBSTATFUNC || - val == C_THUMBLABEL); -} - -/* arm_coff_make_msymbol_special() - arm_elf_make_msymbol_special() - - These functions test whether the COFF or ELF symbol corresponds to - an address in thumb code, and set a "special" bit in a minimal - symbol to indicate that it does. */ - -static void -arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym) -{ - /* Thumb symbols are of type STT_LOPROC, (synonymous with - STT_ARM_TFUNC). */ - if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info) - == STT_LOPROC) - MSYMBOL_SET_SPECIAL (msym); -} - -static void -arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym) -{ - if (coff_sym_is_thumb (val)) - MSYMBOL_SET_SPECIAL (msym); -} - - -static void -process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj) -{ - enum arm_abi *os_ident_ptr = obj; - const char *name; - unsigned int sectsize; - - name = bfd_get_section_name (abfd, sect); - sectsize = bfd_section_size (abfd, sect); - - if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0) - { - unsigned int name_length, data_length, note_type; - char *note; - - /* If the section is larger than this, it's probably not what we are - looking for. */ - if (sectsize > 128) - sectsize = 128; - - note = alloca (sectsize); - - bfd_get_section_contents (abfd, sect, note, - (file_ptr) 0, (bfd_size_type) sectsize); - - name_length = bfd_h_get_32 (abfd, note); - data_length = bfd_h_get_32 (abfd, note + 4); - note_type = bfd_h_get_32 (abfd, note + 8); - - if (name_length == 4 && data_length == 16 && note_type == 1 - && strcmp (note + 12, "GNU") == 0) - { - int os_number = bfd_h_get_32 (abfd, note + 16); - - /* The case numbers are from abi-tags in glibc. */ - switch (os_number) - { - case 0 : - *os_ident_ptr = ARM_ABI_LINUX; - break; - - case 1 : - internal_error - (__FILE__, __LINE__, - "process_note_abi_sections: Hurd objects not supported"); - break; - - case 2 : - internal_error - (__FILE__, __LINE__, - "process_note_abi_sections: Solaris objects not supported"); - break; - - default : - internal_error - (__FILE__, __LINE__, - "process_note_abi_sections: unknown OS number %d", - os_number); - break; - } - } - } - /* NetBSD uses a similar trick. */ - else if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0) - { - unsigned int name_length, desc_length, note_type; - char *note; - - /* If the section is larger than this, it's probably not what we are - looking for. */ - if (sectsize > 128) - sectsize = 128; - - note = alloca (sectsize); - - bfd_get_section_contents (abfd, sect, note, - (file_ptr) 0, (bfd_size_type) sectsize); - - name_length = bfd_h_get_32 (abfd, note); - desc_length = bfd_h_get_32 (abfd, note + 4); - note_type = bfd_h_get_32 (abfd, note + 8); - - if (name_length == 7 && desc_length == 4 && note_type == 1 - && strcmp (note + 12, "NetBSD") == 0) - /* XXX Should we check the version here? - Probably not necessary yet. */ - *os_ident_ptr = ARM_ABI_NETBSD_ELF; - } -} - -/* Return one of the ELFOSABI_ constants for BFDs representing ELF - executables. If it's not an ELF executable or if the OS/ABI couldn't - be determined, simply return -1. */ - -static int -get_elfosabi (bfd *abfd) -{ - int elfosabi; - enum arm_abi arm_abi = ARM_ABI_UNKNOWN; - - elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI]; - - /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate - that we're on a SYSV system. However, GNU/Linux uses a note section - to record OS/ABI info, but leaves e_ident[EI_OSABI] zero. So we - have to check the note sections too. - - GNU/ARM tools set the EI_OSABI field to ELFOSABI_ARM, so handle that - as well. */ - if (elfosabi == 0 || elfosabi == ELFOSABI_ARM) - { - bfd_map_over_sections (abfd, - process_note_abi_tag_sections, - &arm_abi); - } - - if (arm_abi != ARM_ABI_UNKNOWN) - return arm_abi; - - switch (elfosabi) - { - case ELFOSABI_NONE: - /* Existing ARM Tools don't set this field, so look at the EI_FLAGS - field for more information. */ - - switch (EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags)) - { - case EF_ARM_EABI_VER1: - return ARM_ABI_EABI_V1; - - case EF_ARM_EABI_VER2: - return ARM_ABI_EABI_V2; - - case EF_ARM_EABI_UNKNOWN: - /* Assume GNU tools. */ - return ARM_ABI_APCS; - - default: - internal_error (__FILE__, __LINE__, - "get_elfosabi: Unknown ARM EABI version 0x%lx", - EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags)); - - } - break; - - case ELFOSABI_NETBSD: - return ARM_ABI_NETBSD_ELF; - - case ELFOSABI_FREEBSD: - return ARM_ABI_FREEBSD; - - case ELFOSABI_LINUX: - return ARM_ABI_LINUX; - - case ELFOSABI_ARM: - /* Assume GNU tools with the old APCS abi. */ - return ARM_ABI_APCS; - - default: - } - - return ARM_ABI_UNKNOWN; -} - -struct arm_abi_handler -{ - struct arm_abi_handler *next; - enum arm_abi abi; - void (*init_abi)(struct gdbarch_info, struct gdbarch *); -}; - -struct arm_abi_handler *arm_abi_handler_list = NULL; - -void -arm_gdbarch_register_os_abi (enum arm_abi abi, - void (*init_abi)(struct gdbarch_info, - struct gdbarch *)) -{ - struct arm_abi_handler **handler_p; - - for (handler_p = &arm_abi_handler_list; *handler_p != NULL; - handler_p = &(*handler_p)->next) - { - if ((*handler_p)->abi == abi) - { - internal_error - (__FILE__, __LINE__, - "arm_gdbarch_register_os_abi: A handler for this ABI variant (%d)" - " has already been registered", (int)abi); - /* If user wants to continue, override previous definition. */ - (*handler_p)->init_abi = init_abi; - return; - } - } - - (*handler_p) - = (struct arm_abi_handler *) xmalloc (sizeof (struct arm_abi_handler)); - (*handler_p)->next = NULL; - (*handler_p)->abi = abi; - (*handler_p)->init_abi = init_abi; -} - -/* Initialize the current architecture based on INFO. If possible, re-use an - architecture from ARCHES, which is a list of architectures already created - during this debugging session. - - Called e.g. at program startup, when reading a core file, and when reading - a binary file. */ - -static struct gdbarch * -arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) -{ - struct gdbarch_tdep *tdep; - struct gdbarch *gdbarch; - enum arm_abi arm_abi = ARM_ABI_UNKNOWN; - struct arm_abi_handler *abi_handler; - - /* Try to deterimine the ABI of the object we are loading. */ - - if (info.abfd != NULL) - { - switch (bfd_get_flavour (info.abfd)) - { - case bfd_target_elf_flavour: - arm_abi = get_elfosabi (info.abfd); - break; - - case bfd_target_aout_flavour: - if (strcmp (bfd_get_target(info.abfd), "a.out-arm-netbsd") == 0) - arm_abi = ARM_ABI_NETBSD_AOUT; - else - /* Assume it's an old APCS-style ABI. */ - arm_abi = ARM_ABI_APCS; - break; - - case bfd_target_coff_flavour: - /* Assume it's an old APCS-style ABI. */ - /* XXX WinCE? */ - arm_abi = ARM_ABI_APCS; - break; - - default: - /* Not sure what to do here, leave the ABI as unknown. */ - break; - } - } - - /* Find a candidate among extant architectures. */ - for (arches = gdbarch_list_lookup_by_info (arches, &info); - arches != NULL; - arches = gdbarch_list_lookup_by_info (arches->next, &info)) - { - /* Make sure the ABI selection matches. */ - tdep = gdbarch_tdep (arches->gdbarch); - if (tdep && tdep->arm_abi == arm_abi) - return arches->gdbarch; - } - - tdep = xmalloc (sizeof (struct gdbarch_tdep)); - gdbarch = gdbarch_alloc (&info, tdep); - - tdep->arm_abi = arm_abi; - if (arm_abi < ARM_ABI_INVALID) - tdep->abi_name = arm_abi_names[arm_abi]; - else - { - internal_error (__FILE__, __LINE__, "Invalid setting of arm_abi %d", - (int) arm_abi); - tdep->abi_name = "<invalid>"; - } - - /* This is the way it has always defaulted. */ - tdep->fp_model = ARM_FLOAT_FPA; - - /* Breakpoints. */ - switch (info.byte_order) - { - case BFD_ENDIAN_BIG: - tdep->arm_breakpoint = arm_default_arm_be_breakpoint; - tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint); - tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint; - tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint); - - break; - - case BFD_ENDIAN_LITTLE: - tdep->arm_breakpoint = arm_default_arm_le_breakpoint; - tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint); - tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint; - tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint); - - break; - - default: - internal_error (__FILE__, __LINE__, - "arm_gdbarch_init: bad byte order for float format"); - } - - /* On ARM targets char defaults to unsigned. */ - set_gdbarch_char_signed (gdbarch, 0); - - /* This should be low enough for everything. */ - tdep->lowest_pc = 0x20; - tdep->jb_pc = -1; /* Longjump support not enabled by default. */ - - set_gdbarch_use_generic_dummy_frames (gdbarch, 0); - - /* Call dummy code. */ - set_gdbarch_call_dummy_location (gdbarch, ON_STACK); - set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); - /* We have to give this a value now, even though we will re-set it - during each call to arm_fix_call_dummy. */ - set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 8); - set_gdbarch_call_dummy_p (gdbarch, 1); - set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); - - set_gdbarch_call_dummy_words (gdbarch, arm_call_dummy_words); - set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (arm_call_dummy_words)); - set_gdbarch_call_dummy_start_offset (gdbarch, 0); - set_gdbarch_call_dummy_length (gdbarch, 0); - - set_gdbarch_fix_call_dummy (gdbarch, arm_fix_call_dummy); - - set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_on_stack); - - set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register); - set_gdbarch_push_arguments (gdbarch, arm_push_arguments); - set_gdbarch_coerce_float_to_double (gdbarch, - standard_coerce_float_to_double); - - /* Frame handling. */ - set_gdbarch_frame_chain_valid (gdbarch, arm_frame_chain_valid); - set_gdbarch_init_extra_frame_info (gdbarch, arm_init_extra_frame_info); - set_gdbarch_read_fp (gdbarch, arm_read_fp); - set_gdbarch_frame_chain (gdbarch, arm_frame_chain); - set_gdbarch_frameless_function_invocation - (gdbarch, arm_frameless_function_invocation); - set_gdbarch_frame_saved_pc (gdbarch, arm_frame_saved_pc); - set_gdbarch_frame_args_address (gdbarch, arm_frame_args_address); - set_gdbarch_frame_locals_address (gdbarch, arm_frame_locals_address); - set_gdbarch_frame_num_args (gdbarch, arm_frame_num_args); - set_gdbarch_frame_args_skip (gdbarch, 0); - set_gdbarch_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs); - set_gdbarch_push_dummy_frame (gdbarch, arm_push_dummy_frame); - set_gdbarch_pop_frame (gdbarch, arm_pop_frame); - - /* Address manipulation. */ - set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address); - set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove); - - /* Offset from address of function to start of its code. */ - set_gdbarch_function_start_offset (gdbarch, 0); - - /* Advance PC across function entry code. */ - set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue); - - /* Get the PC when a frame might not be available. */ - set_gdbarch_saved_pc_after_call (gdbarch, arm_saved_pc_after_call); - - /* The stack grows downward. */ - set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - - /* Breakpoint manipulation. */ - set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc); - set_gdbarch_decr_pc_after_break (gdbarch, 0); - - /* Information about registers, etc. */ - set_gdbarch_print_float_info (gdbarch, arm_print_float_info); - set_gdbarch_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */ - set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM); - set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM); - set_gdbarch_register_byte (gdbarch, arm_register_byte); - set_gdbarch_register_bytes (gdbarch, - (NUM_GREGS * INT_REGISTER_RAW_SIZE - + NUM_FREGS * FP_REGISTER_RAW_SIZE - + NUM_SREGS * STATUS_REGISTER_SIZE)); - set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS); - set_gdbarch_register_raw_size (gdbarch, arm_register_raw_size); - set_gdbarch_register_virtual_size (gdbarch, arm_register_virtual_size); - set_gdbarch_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE); - set_gdbarch_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE); - set_gdbarch_register_virtual_type (gdbarch, arm_register_type); - - /* Integer registers are 4 bytes. */ - set_gdbarch_register_size (gdbarch, 4); - set_gdbarch_register_name (gdbarch, arm_register_name); - - /* Returning results. */ - set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value); - set_gdbarch_store_return_value (gdbarch, arm_store_return_value); - set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return); - set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention); - set_gdbarch_extract_struct_value_address (gdbarch, - arm_extract_struct_value_address); - - /* Single stepping. */ - /* XXX For an RDI target we should ask the target if it can single-step. */ - set_gdbarch_software_single_step (gdbarch, arm_software_single_step); - - /* Minsymbol frobbing. */ - set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special); - set_gdbarch_coff_make_msymbol_special (gdbarch, - arm_coff_make_msymbol_special); - - /* Hook in the ABI-specific overrides, if they have been registered. */ - if (arm_abi == ARM_ABI_UNKNOWN) - { - /* Don't complain about not knowing the ABI variant if we don't - have an inferior. */ - if (info.abfd) - fprintf_filtered - (gdb_stderr, "GDB doesn't recognize the ABI of the inferior. " - "Attempting to continue with the default ARM settings"); - } - else - { - for (abi_handler = arm_abi_handler_list; abi_handler != NULL; - abi_handler = abi_handler->next) - if (abi_handler->abi == arm_abi) - break; - - if (abi_handler) - abi_handler->init_abi (info, gdbarch); - else - { - /* We assume that if GDB_MULTI_ARCH is less than - GDB_MULTI_ARCH_TM that an ABI variant can be supported by - overriding definitions in this file. */ - if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) - fprintf_filtered - (gdb_stderr, - "A handler for the ABI variant \"%s\" is not built into this " - "configuration of GDB. " - "Attempting to continue with the default ARM settings", - arm_abi_names[arm_abi]); - } - } - - /* Now we have tuned the configuration, set a few final things, - based on what the OS ABI has told us. */ - - if (tdep->jb_pc >= 0) - set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target); - - /* Floating point sizes and format. */ - switch (info.byte_order) - { - case BFD_ENDIAN_BIG: - set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big); - set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big); - set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big); - - break; - - case BFD_ENDIAN_LITTLE: - set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little); - if (tdep->fp_model == ARM_FLOAT_VFP - || tdep->fp_model == ARM_FLOAT_SOFT_VFP) - { - set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little); - set_gdbarch_long_double_format (gdbarch, - &floatformat_ieee_double_little); - } - else - { - set_gdbarch_double_format - (gdbarch, &floatformat_ieee_double_littlebyte_bigword); - set_gdbarch_long_double_format - (gdbarch, &floatformat_ieee_double_littlebyte_bigword); - } - break; - - default: - internal_error (__FILE__, __LINE__, - "arm_gdbarch_init: bad byte order for float format"); - } - - /* We can't use SIZEOF_FRAME_SAVED_REGS here, since that still - references the old architecture vector, not the one we are - building here. */ - if (prologue_cache.saved_regs != NULL) - xfree (prologue_cache.saved_regs); - - prologue_cache.saved_regs = (CORE_ADDR *) - xcalloc (1, (sizeof (CORE_ADDR) - * (gdbarch_num_regs (gdbarch) + NUM_PSEUDO_REGS))); - - return gdbarch; -} - -static void -arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - if (tdep == NULL) - return; - - if (tdep->abi_name != NULL) - fprintf_unfiltered (file, "arm_dump_tdep: ABI = %s\n", tdep->abi_name); - else - internal_error (__FILE__, __LINE__, - "arm_dump_tdep: illegal setting of tdep->arm_abi (%d)", - (int) tdep->arm_abi); - - fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx", - (unsigned long) tdep->lowest_pc); -} - -static void -arm_init_abi_eabi_v1 (struct gdbarch_info info, - struct gdbarch *gdbarch) -{ - /* Place-holder. */ -} - -static void -arm_init_abi_eabi_v2 (struct gdbarch_info info, - struct gdbarch *gdbarch) -{ - /* Place-holder. */ -} - -static void -arm_init_abi_apcs (struct gdbarch_info info, - struct gdbarch *gdbarch) -{ - /* Place-holder. */ -} - -void -_initialize_arm_tdep (void) -{ - struct ui_file *stb; - long length; - struct cmd_list_element *new_cmd; - const char *setname; - const char *setdesc; - const char **regnames; - int numregs, i, j; - static char *helptext; - - if (GDB_MULTI_ARCH) - gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); - - /* Register some ABI variants for embedded systems. */ - arm_gdbarch_register_os_abi (ARM_ABI_EABI_V1, arm_init_abi_eabi_v1); - arm_gdbarch_register_os_abi (ARM_ABI_EABI_V2, arm_init_abi_eabi_v2); - arm_gdbarch_register_os_abi (ARM_ABI_APCS, arm_init_abi_apcs); - - tm_print_insn = gdb_print_insn_arm; - - /* Get the number of possible sets of register names defined in opcodes. */ - num_flavor_options = get_arm_regname_num_options (); - - /* Sync the opcode insn printer with our register viewer: */ - parse_arm_disassembler_option ("reg-names-std"); - - /* Begin creating the help text. */ - stb = mem_fileopen (); - fprintf_unfiltered (stb, "Set the disassembly flavor.\n\ -The valid values are:\n"); - - /* Initialize the array that will be passed to add_set_enum_cmd(). */ - valid_flavors = xmalloc ((num_flavor_options + 1) * sizeof (char *)); - for (i = 0; i < num_flavor_options; i++) - { - numregs = get_arm_regnames (i, &setname, &setdesc, ®names); - valid_flavors[i] = setname; - fprintf_unfiltered (stb, "%s - %s\n", setname, - setdesc); - /* Copy the default names (if found) and synchronize disassembler. */ - if (!strcmp (setname, "std")) - { - disassembly_flavor = setname; - current_option = i; - for (j = 0; j < numregs; j++) - arm_register_names[j] = (char *) regnames[j]; - set_arm_regname_option (i); - } - } - /* Mark the end of valid options. */ - valid_flavors[num_flavor_options] = NULL; - - /* Finish the creation of the help text. */ - fprintf_unfiltered (stb, "The default is \"std\"."); - helptext = ui_file_xstrdup (stb, &length); - ui_file_delete (stb); - - /* Add the disassembly-flavor command */ - new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class, - valid_flavors, - &disassembly_flavor, - helptext, - &setlist); - set_cmd_sfunc (new_cmd, set_disassembly_flavor_sfunc); - add_show_from_set (new_cmd, &showlist); - - /* ??? Maybe this should be a boolean. */ - add_show_from_set (add_set_cmd ("apcs32", no_class, - var_zinteger, (char *) &arm_apcs_32, - "Set usage of ARM 32-bit mode.\n", &setlist), - &showlist); - - /* Add the deprecated "othernames" command */ - - add_com ("othernames", class_obscure, arm_othernames, - "Switch to the next set of register names."); - - /* Fill in the prologue_cache fields. */ - prologue_cache.saved_regs = NULL; - prologue_cache.extra_info = (struct frame_extra_info *) - xcalloc (1, sizeof (struct frame_extra_info)); -} diff --git a/contrib/gdb/gdb/coff-solib.c b/contrib/gdb/gdb/coff-solib.c deleted file mode 100644 index 64dca7b..0000000 --- a/contrib/gdb/gdb/coff-solib.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/coff-solib.h b/contrib/gdb/gdb/coff-solib.h deleted file mode 100644 index 144f36d..0000000 --- a/contrib/gdb/gdb/coff-solib.h +++ /dev/null @@ -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 diff --git a/contrib/gdb/gdb/core-sol2.c b/contrib/gdb/gdb/core-sol2.c deleted file mode 100644 index e72fc2a..0000000 --- a/contrib/gdb/gdb/core-sol2.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/fr30-tdep.c b/contrib/gdb/gdb/fr30-tdep.c deleted file mode 100644 index 09f886f..0000000 --- a/contrib/gdb/gdb/fr30-tdep.c +++ /dev/null @@ -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; -} diff --git a/contrib/gdb/gdb/i386-stub.c b/contrib/gdb/gdb/i386-stub.c deleted file mode 100644 index 1251567..0000000 --- a/contrib/gdb/gdb/i386-stub.c +++ /dev/null @@ -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 (); -} diff --git a/contrib/gdb/gdb/i386aix-nat.c b/contrib/gdb/gdb/i386aix-nat.c deleted file mode 100644 index 2d8d7b9..0000000 --- a/contrib/gdb/gdb/i386aix-nat.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/i386ly-tdep.c b/contrib/gdb/gdb/i386ly-tdep.c deleted file mode 100644 index 92b544d..0000000 --- a/contrib/gdb/gdb/i386ly-tdep.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/i386m3-nat.c b/contrib/gdb/gdb/i386m3-nat.c deleted file mode 100644 index 8fbd1e8..0000000 --- a/contrib/gdb/gdb/i386m3-nat.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/i386mach-nat.c b/contrib/gdb/gdb/i386mach-nat.c deleted file mode 100644 index 6d4980b..0000000 --- a/contrib/gdb/gdb/i386mach-nat.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/i386v-nat.c b/contrib/gdb/gdb/i386v-nat.c deleted file mode 100644 index 672ddfb..0000000 --- a/contrib/gdb/gdb/i386v-nat.c +++ /dev/null @@ -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 */ diff --git a/contrib/gdb/gdb/i386v4-nat.c b/contrib/gdb/gdb/i386v4-nat.c deleted file mode 100644 index 33dbde8..0000000 --- a/contrib/gdb/gdb/i386v4-nat.c +++ /dev/null @@ -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 */ diff --git a/contrib/gdb/gdb/m3-nat.c b/contrib/gdb/gdb/m3-nat.c deleted file mode 100644 index 320cbf8..0000000 --- a/contrib/gdb/gdb/m3-nat.c +++ /dev/null @@ -1,4565 +0,0 @@ -/* Interface GDB to Mach 3.0 operating systems. - (Most) Mach 3.0 related routines live in this file. - - Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, - 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. */ - -/* - * Author: Jukka Virtanen <jtv@hut.fi> - * Computing Centre - * Helsinki University of Technology - * Finland - * - * Thanks to my friends who helped with ideas and testing: - * - * Johannes Helander, Antti Louko, Tero Mononen, - * jvh@cs.hut.fi alo@hut.fi tmo@cs.hut.fi - * - * Tero Kivinen and Eamonn McManus - * kivinen@cs.hut.fi emcmanus@gr.osf.org - * - */ - -#include <stdio.h> - -#include <mach.h> -#include <servers/netname.h> -#include <servers/machid.h> -#include <mach/message.h> -#include <mach/notify.h> -#include <mach_error.h> -#include <mach/exception.h> -#include <mach/vm_attributes.h> - -#include "defs.h" -#include "inferior.h" -#include "symtab.h" -#include "value.h" -#include "language.h" -#include "target.h" -#include "gdb_wait.h" -#include "gdbcmd.h" -#include "gdbcore.h" -#include "regcache.h" - -#if 0 -#include <servers/machid_lib.h> -#else -#define MACH_TYPE_TASK 1 -#define MACH_TYPE_THREAD 2 -#endif - -/* Included only for signal names and NSIG - - * note: There are many problems in signal handling with - * gdb in Mach 3.0 in general. - */ -#include <signal.h> -#define SIG_UNKNOWN 0 /* Exception that has no matching unix signal */ - -#include <cthreads.h> - -/* This is what a cproc looks like. This is here partly because - cthread_internals.h is not a header we can just #include, partly with - an eye towards perhaps getting this to work with cross-debugging - someday. Best solution is if CMU publishes a real interface to this - stuff. */ -#define CPROC_NEXT_OFFSET 0 -#define CPROC_NEXT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) -#define CPROC_INCARNATION_OFFSET (CPROC_NEXT_OFFSET + CPROC_NEXT_SIZE) -#define CPROC_INCARNATION_SIZE (sizeof (cthread_t)) -#define CPROC_LIST_OFFSET (CPROC_INCARNATION_OFFSET + CPROC_INCARNATION_SIZE) -#define CPROC_LIST_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) -#define CPROC_WAIT_OFFSET (CPROC_LIST_OFFSET + CPROC_LIST_SIZE) -#define CPROC_WAIT_SIZE (TARGET_PTR_BIT / HOST_CHAR_BIT) -#define CPROC_REPLY_OFFSET (CPROC_WAIT_OFFSET + CPROC_WAIT_SIZE) -#define CPROC_REPLY_SIZE (sizeof (mach_port_t)) -#define CPROC_CONTEXT_OFFSET (CPROC_REPLY_OFFSET + CPROC_REPLY_SIZE) -#define CPROC_CONTEXT_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) -#define CPROC_LOCK_OFFSET (CPROC_CONTEXT_OFFSET + CPROC_CONTEXT_SIZE) -#define CPROC_LOCK_SIZE (sizeof (spin_lock_t)) -#define CPROC_STATE_OFFSET (CPROC_LOCK_OFFSET + CPROC_LOCK_SIZE) -#define CPROC_STATE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) -#define CPROC_WIRED_OFFSET (CPROC_STATE_OFFSET + CPROC_STATE_SIZE) -#define CPROC_WIRED_SIZE (sizeof (mach_port_t)) -#define CPROC_BUSY_OFFSET (CPROC_WIRED_OFFSET + CPROC_WIRED_SIZE) -#define CPROC_BUSY_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) -#define CPROC_MSG_OFFSET (CPROC_BUSY_OFFSET + CPROC_BUSY_SIZE) -#define CPROC_MSG_SIZE (sizeof (mach_msg_header_t)) -#define CPROC_BASE_OFFSET (CPROC_MSG_OFFSET + CPROC_MSG_SIZE) -#define CPROC_BASE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) -#define CPROC_SIZE_OFFSET (CPROC_BASE_OFFSET + CPROC_BASE_SIZE) -#define CPROC_SIZE_SIZE (TARGET_INT_BIT / HOST_CHAR_BIT) -#define CPROC_SIZE (CPROC_SIZE_OFFSET + CPROC_SIZE_SIZE) - -/* Values for the state field in the cproc. */ -#define CPROC_RUNNING 0 -#define CPROC_SWITCHING 1 -#define CPROC_BLOCKED 2 -#define CPROC_CONDWAIT 4 - -/* For cproc and kernel thread mapping */ -typedef struct gdb_thread - { - mach_port_t name; - CORE_ADDR sp; - CORE_ADDR pc; - CORE_ADDR fp; - boolean_t in_emulator; - int slotid; - - /* This is for the mthreads list. It points to the cproc list. - Perhaps the two lists should be merged (or perhaps it was a mistake - to make them both use a struct gdb_thread). */ - struct gdb_thread *cproc; - - /* These are for the cproc list, which is linked through the next field - of the struct gdb_thread. */ - char raw_cproc[CPROC_SIZE]; - /* The cthread which is pointed to by the incarnation field from the - cproc. This points to the copy we've read into GDB. */ - cthread_t cthread; - /* Point back to the mthreads list. */ - int reverse_map; - struct gdb_thread *next; - } - *gdb_thread_t; - -/* - * Actions for Mach exceptions. - * - * sigmap field maps the exception to corresponding Unix signal. - * - * I do not know how to map the exception to unix signal - * if SIG_UNKNOWN is specified. - */ - -struct exception_list - { - char *name; - boolean_t forward; - boolean_t print; - int sigmap; - } -exception_map[] = -{ - { - "not_mach3_exception", FALSE, TRUE, SIG_UNKNOWN - } - , - { - "EXC_BAD_ACCESS", FALSE, TRUE, SIGSEGV - } - , - { - "EXC_BAD_INSTRUCTION", FALSE, TRUE, SIGILL - } - , - { - "EXC_ARITHMETIC", FALSE, TRUE, SIGFPE - } - , - { - "EXC_EMULATION", FALSE, TRUE, SIGEMT - } - , /* ??? */ - { - "EXC_SOFTWARE", FALSE, TRUE, SIG_UNKNOWN - } - , - { - "EXC_BREAKPOINT", FALSE, FALSE, SIGTRAP - } -}; - -/* Mach exception table size */ -int max_exception = sizeof (exception_map) / sizeof (struct exception_list) - 1; - -#define MAX_EXCEPTION max_exception - -WAITTYPE wait_status; - -/* If you define this, intercepted bsd server calls will be - * dumped while waiting the inferior to EXEC the correct - * program - */ -/* #define DUMP_SYSCALL /* debugging interceptor */ - -/* xx_debug() outputs messages if this is nonzero. - * If > 1, DUMP_SYSCALL will dump message contents. - */ -int debug_level = 0; - -/* "Temporary" debug stuff */ -void -xx_debug (char *fmt, int a, int b, int c) -{ - if (debug_level) - warning (fmt, a, b, c); -} - -/* This is in libmach.a */ -extern mach_port_t name_server_port; - -/* Set in catch_exception_raise */ -int stop_exception, stop_code, stop_subcode; -int stopped_in_exception; - -/* Thread that was the active thread when we stopped */ -thread_t stop_thread = MACH_PORT_NULL; - -char *hostname = ""; - -/* Set when task is attached or created */ -boolean_t emulator_present = FALSE; - -task_t inferior_task; -thread_t current_thread; - -/* Exception ports for inferior task */ -mach_port_t inferior_exception_port = MACH_PORT_NULL; -mach_port_t inferior_old_exception_port = MACH_PORT_NULL; - -/* task exceptions and notifications */ -mach_port_t inferior_wait_port_set = MACH_PORT_NULL; -mach_port_t our_notify_port = MACH_PORT_NULL; - -/* This is "inferior_wait_port_set" when not single stepping, and - * "singlestepped_thread_port" when we are single stepping. - * - * This is protected by a cleanup function: discard_single_step() - */ -mach_port_t currently_waiting_for = MACH_PORT_NULL; - -/* A port for external messages to gdb. - * External in the meaning that they do not come - * from the inferior_task, but rather from external - * tasks. - * - * As a debugging feature: - * A debugger debugging another debugger can stop the - * inferior debugger by the following command sequence - * (without running external programs) - * - * (top-gdb) set stop_inferior_gdb () - * (top-gdb) continue - */ -mach_port_t our_message_port = MACH_PORT_NULL; - -/* For single stepping */ -mach_port_t thread_exception_port = MACH_PORT_NULL; -mach_port_t thread_saved_exception_port = MACH_PORT_NULL; -mach_port_t singlestepped_thread_port = MACH_PORT_NULL; - -/* For machid calls */ -mach_port_t mid_server = MACH_PORT_NULL; -mach_port_t mid_auth = MACH_PORT_NULL; - -/* If gdb thinks the inferior task is not suspended, it - * must take suspend/abort the threads when it reads the state. - */ -int must_suspend_thread = 0; - -/* When single stepping, we switch the port that mach_really_wait() listens to. - * This cleanup is a guard to prevent the port set from being left to - * the singlestepped_thread_port when error() is called. - * This is nonzero only when we are single stepping. - */ -#define NULL_CLEANUP (struct cleanup *)0 -struct cleanup *cleanup_step = NULL_CLEANUP; - - -static struct target_ops m3_ops; - -static void m3_kill_inferior (); - -#if 0 -#define MACH_TYPE_EXCEPTION_PORT -1 -#endif - -/* Chain of ports to remember requested notifications. */ - -struct port_chain - { - struct port_chain *next; - mach_port_t port; - int type; - int mid; /* Now only valid with MACH_TYPE_THREAD and */ - /* MACH_TYPE_THREAD */ - }; -typedef struct port_chain *port_chain_t; - -/* Room for chain nodes comes from pchain_obstack */ -struct obstack pchain_obstack; -struct obstack *port_chain_obstack = &pchain_obstack; - -/* For thread handling */ -struct obstack Cproc_obstack; -struct obstack *cproc_obstack = &Cproc_obstack; - -/* the list of notified ports */ -port_chain_t notify_chain = (port_chain_t) NULL; - -port_chain_t -port_chain_insert (port_chain_t list, mach_port_t name, int type) -{ - kern_return_t ret; - port_chain_t new; - int mid; - - if (!MACH_PORT_VALID (name)) - return list; - - if (type == MACH_TYPE_TASK || type == MACH_TYPE_THREAD) - { - if (!MACH_PORT_VALID (mid_server)) - { - warning ("Machid server port invalid, can not map port 0x%x to MID", - name); - mid = name; - } - else - { - ret = machid_mach_register (mid_server, mid_auth, name, type, &mid); - - if (ret != KERN_SUCCESS) - { - warning ("Can not map name (0x%x) to MID with machid", name); - mid = name; - } - } - } - else - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - - new = (port_chain_t) obstack_alloc (port_chain_obstack, - sizeof (struct port_chain)); - new->next = list; - new->port = name; - new->type = type; - new->mid = mid; - - return new; -} - -port_chain_t -port_chain_delete (port_chain_t list, mach_port_t elem) -{ - if (list) - if (list->port == elem) - list = list->next; - else - while (list->next) - { - if (list->next->port == elem) - list->next = list->next->next; /* GCd with obstack_free() */ - else - list = list->next; - } - return list; -} - -void -port_chain_destroy (struct obstack *ostack) -{ - obstack_free (ostack, 0); - obstack_init (ostack); -} - -port_chain_t -port_chain_member (port_chain_t list, mach_port_t elem) -{ - while (list) - { - if (list->port == elem) - return list; - list = list->next; - } - return (port_chain_t) NULL; -} - -int -map_port_name_to_mid (mach_port_t name, int type) -{ - port_chain_t elem; - - if (!MACH_PORT_VALID (name)) - return -1; - - elem = port_chain_member (notify_chain, name); - - if (elem && (elem->type == type)) - return elem->mid; - - if (elem) - return -1; - - if (!MACH_PORT_VALID (mid_server)) - { - warning ("Machid server port invalid, can not map port 0x%x to mid", - name); - return -1; - } - else - { - int mid; - kern_return_t ret; - - ret = machid_mach_register (mid_server, mid_auth, name, type, &mid); - - if (ret != KERN_SUCCESS) - { - warning ("Can not map name (0x%x) to mid with machid", name); - return -1; - } - return mid; - } -} - -/* Guard for currently_waiting_for and singlestepped_thread_port */ -static void -discard_single_step (thread_t thread) -{ - currently_waiting_for = inferior_wait_port_set; - - cleanup_step = NULL_CLEANUP; - if (MACH_PORT_VALID (thread) && MACH_PORT_VALID (singlestepped_thread_port)) - setup_single_step (thread, FALSE); -} - -setup_single_step (thread_t thread, boolean_t start_step) -{ - kern_return_t ret; - - if (!MACH_PORT_VALID (thread)) - error ("Invalid thread supplied to setup_single_step"); - else - { - mach_port_t teport; - - /* Get the current thread exception port */ - ret = thread_get_exception_port (thread, &teport); - CHK ("Getting thread's exception port", ret); - - if (start_step) - { - if (MACH_PORT_VALID (singlestepped_thread_port)) - { - warning ("Singlestepped_thread_port (0x%x) is still valid?", - singlestepped_thread_port); - singlestepped_thread_port = MACH_PORT_NULL; - } - - /* If we are already stepping this thread */ - if (MACH_PORT_VALID (teport) && teport == thread_exception_port) - { - ret = mach_port_deallocate (mach_task_self (), teport); - CHK ("Could not deallocate thread exception port", ret); - } - else - { - ret = thread_set_exception_port (thread, thread_exception_port); - CHK ("Setting exception port for thread", ret); -#if 0 - /* Insert thread exception port to wait port set */ - ret = mach_port_move_member (mach_task_self (), - thread_exception_port, - inferior_wait_port_set); - CHK ("Moving thread exception port to inferior_wait_port_set", - ret); -#endif - thread_saved_exception_port = teport; - } - - thread_trace (thread, TRUE); - - singlestepped_thread_port = thread_exception_port; - currently_waiting_for = singlestepped_thread_port; - cleanup_step = make_cleanup (discard_single_step, thread); - } - else - { - if (!MACH_PORT_VALID (teport)) - error ("Single stepped thread had an invalid exception port?"); - - if (teport != thread_exception_port) - error ("Single stepped thread had an unknown exception port?"); - - ret = mach_port_deallocate (mach_task_self (), teport); - CHK ("Couldn't deallocate thread exception port", ret); -#if 0 - /* Remove thread exception port from wait port set */ - ret = mach_port_move_member (mach_task_self (), - thread_exception_port, - MACH_PORT_NULL); - CHK ("Removing thread exception port from inferior_wait_port_set", - ret); -#endif - /* Restore thread's old exception port */ - ret = thread_set_exception_port (thread, - thread_saved_exception_port); - CHK ("Restoring stepped thread's exception port", ret); - - if (MACH_PORT_VALID (thread_saved_exception_port)) - (void) mach_port_deallocate (mach_task_self (), - thread_saved_exception_port); - - thread_trace (thread, FALSE); - - singlestepped_thread_port = MACH_PORT_NULL; - currently_waiting_for = inferior_wait_port_set; - if (cleanup_step) - discard_cleanups (cleanup_step); - } - } -} - -static -request_notify (mach_port_t name, mach_msg_id_t variant, int type) -{ - kern_return_t ret; - mach_port_t previous_port_dummy = MACH_PORT_NULL; - - if (!MACH_PORT_VALID (name)) - return; - - if (port_chain_member (notify_chain, name)) - return; - - ret = mach_port_request_notification (mach_task_self (), - name, - variant, - 1, - our_notify_port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &previous_port_dummy); - CHK ("Serious: request_notify failed", ret); - - (void) mach_port_deallocate (mach_task_self (), - previous_port_dummy); - - notify_chain = port_chain_insert (notify_chain, name, type); -} - -reverse_msg_bits (mach_msg_header_t *msgp, int type) -{ - int rbits, lbits; - rbits = MACH_MSGH_BITS_REMOTE (msgp->msgh_bits); - lbits = type; - msgp->msgh_bits = - (msgp->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) | - MACH_MSGH_BITS (lbits, rbits); -} - -/* On the third day He said: - - Let this be global - and then it was global. - - When creating the inferior fork, the - child code in inflow.c sets the name of the - bootstrap_port in its address space to this - variable. - - The name is transferred to our address space - with mach3_read_inferior(). - - Thou shalt not do this with - task_get_bootstrap_port() in this task, since - the name in the inferior task is different than - the one we get. - - For blessed are the meek, as they shall inherit - the address space. - */ -mach_port_t original_server_port_name = MACH_PORT_NULL; - - -/* Called from inferior after FORK but before EXEC */ -static void -m3_trace_me (void) -{ - kern_return_t ret; - - /* Get the NAME of the bootstrap port in this task - so that GDB can read it */ - ret = task_get_bootstrap_port (mach_task_self (), - &original_server_port_name); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - ret = mach_port_deallocate (mach_task_self (), - original_server_port_name); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - - /* Suspend this task to let the parent change my ports. - Resumed by the debugger */ - ret = task_suspend (mach_task_self ()); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); -} - -/* - * Intercept system calls to Unix server. - * After EXEC_COUNTER calls to exec(), return. - * - * Pre-assertion: Child is suspended. (Not verified) - * Post-condition: Child is suspended after EXEC_COUNTER exec() calls. - */ - -void -intercept_exec_calls (int exec_counter) -{ - int terminal_initted = 0; - - struct syscall_msg_t - { - mach_msg_header_t header; - mach_msg_type_t type; - char room[2000]; /* Enuff space */ - }; - - struct syscall_msg_t syscall_in, syscall_out; - - mach_port_t fake_server; - mach_port_t original_server_send; - mach_port_t original_exec_reply; - mach_port_t exec_reply; - mach_port_t exec_reply_send; - mach_msg_type_name_t acquired; - mach_port_t emulator_server_port_name; - struct task_basic_info info; - mach_msg_type_number_t info_count; - - kern_return_t ret; - - if (exec_counter <= 0) - return; /* We are already set up in the correct program */ - - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &fake_server); - CHK ("create inferior_fake_server port failed", ret); - - /* Wait for inferior_task to suspend itself */ - while (1) - { - info_count = sizeof (info); - ret = task_info (inferior_task, - TASK_BASIC_INFO, - (task_info_t) & info, - &info_count); - CHK ("Task info", ret); - - if (info.suspend_count) - break; - - /* Note that the definition of the parameter was undefined - * at the time of this writing, so I just use an `ad hoc' value. - */ - (void) swtch_pri (42); /* Universal Priority Value */ - } - - /* Read the inferior's bootstrap port name */ - if (!mach3_read_inferior (&original_server_port_name, - &original_server_port_name, - sizeof (original_server_port_name))) - error ("Can't read inferior task bootstrap port name"); - - /* @@ BUG: If more than 1 send right GDB will FAIL!!! */ - /* Should get refs, and set them back when restoring */ - /* Steal the original bsd server send right from inferior */ - ret = mach_port_extract_right (inferior_task, - original_server_port_name, - MACH_MSG_TYPE_MOVE_SEND, - &original_server_send, - &acquired); - CHK ("mach_port_extract_right (bsd server send)", ret); - - if (acquired != MACH_MSG_TYPE_PORT_SEND) - error ("Incorrect right extracted, send right to bsd server expected"); - - ret = mach_port_insert_right (inferior_task, - original_server_port_name, - fake_server, - MACH_MSG_TYPE_MAKE_SEND); - CHK ("mach_port_insert_right (fake server send)", ret); - - xx_debug ("inferior task bsd server ports set up \nfs %x, ospn %x, oss %x\n", - fake_server, - original_server_port_name, original_server_send); - - /* A receive right to the reply generated by unix server exec() request */ - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &exec_reply); - CHK ("create intercepted_reply_port port failed", ret); - - /* Pass this send right to Unix server so it replies to us after exec() */ - ret = mach_port_extract_right (mach_task_self (), - exec_reply, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &exec_reply_send, - &acquired); - CHK ("mach_port_extract_right (exec_reply)", ret); - - if (acquired != MACH_MSG_TYPE_PORT_SEND_ONCE) - error ("Incorrect right extracted, send once expected for exec reply"); - - ret = mach_port_move_member (mach_task_self (), - fake_server, - inferior_wait_port_set); - CHK ("Moving fake syscall port to inferior_wait_port_set", ret); - - xx_debug ("syscall fake server set up, resuming inferior\n"); - - ret = task_resume (inferior_task); - CHK ("task_resume (startup)", ret); - - /* Read requests from the inferior. - Pass directly through everything else except exec() calls. - */ - while (exec_counter > 0) - { - ret = mach_msg (&syscall_in.header, /* header */ - MACH_RCV_MSG, /* options */ - 0, /* send size */ - sizeof (struct syscall_msg_t), /* receive size */ - inferior_wait_port_set, /* receive_name */ - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - CHK ("mach_msg (intercepted sycall)", ret); - -#ifdef DUMP_SYSCALL - print_msg (&syscall_in.header); -#endif - - /* ASSERT : msgh_local_port == fake_server */ - - if (notify_server (&syscall_in.header, &syscall_out.header)) - error ("received a notify while intercepting syscalls"); - - if (syscall_in.header.msgh_id == MIG_EXEC_SYSCALL_ID) - { - xx_debug ("Received EXEC SYSCALL, counter = %d\n", exec_counter); - if (exec_counter == 1) - { - original_exec_reply = syscall_in.header.msgh_remote_port; - syscall_in.header.msgh_remote_port = exec_reply_send; - } - - if (!terminal_initted) - { - /* Now that the child has exec'd we know it has already set its - process group. On POSIX systems, tcsetpgrp will fail with - EPERM if we try it before the child's setpgid. */ - - /* 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 (); - - terminal_initted = 1; - } - - exec_counter--; - } - - syscall_in.header.msgh_local_port = syscall_in.header.msgh_remote_port; - syscall_in.header.msgh_remote_port = original_server_send; - - reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_COPY_SEND); - - ret = mach_msg_send (&syscall_in.header); - CHK ("Forwarded syscall", ret); - } - - ret = mach_port_move_member (mach_task_self (), - fake_server, - MACH_PORT_NULL); - CHK ("Moving fake syscall out of inferior_wait_port_set", ret); - - ret = mach_port_move_member (mach_task_self (), - exec_reply, - inferior_wait_port_set); - CHK ("Moving exec_reply to inferior_wait_port_set", ret); - - ret = mach_msg (&syscall_in.header, /* header */ - MACH_RCV_MSG, /* options */ - 0, /* send size */ - sizeof (struct syscall_msg_t), /* receive size */ - inferior_wait_port_set, /* receive_name */ - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - CHK ("mach_msg (exec reply)", ret); - - ret = task_suspend (inferior_task); - CHK ("Suspending inferior after last exec", ret); - - must_suspend_thread = 0; - - xx_debug ("Received exec reply from bsd server, suspended inferior task\n"); - -#ifdef DUMP_SYSCALL - print_msg (&syscall_in.header); -#endif - - /* Message should appear as if it came from the unix server */ - syscall_in.header.msgh_local_port = MACH_PORT_NULL; - - /* and go to the inferior task original reply port */ - syscall_in.header.msgh_remote_port = original_exec_reply; - - reverse_msg_bits (&syscall_in.header, MACH_MSG_TYPE_MOVE_SEND_ONCE); - - ret = mach_msg_send (&syscall_in.header); - CHK ("Forwarding exec reply to inferior", ret); - - /* Garbage collect */ - ret = mach_port_deallocate (inferior_task, - original_server_port_name); - CHK ("deallocating fake server send right", ret); - - ret = mach_port_insert_right (inferior_task, - original_server_port_name, - original_server_send, - MACH_MSG_TYPE_MOVE_SEND); - CHK ("Restoring the original bsd server send right", ret); - - ret = mach_port_destroy (mach_task_self (), - fake_server); - fake_server = MACH_PORT_DEAD; - CHK ("mach_port_destroy (fake_server)", ret); - - ret = mach_port_destroy (mach_task_self (), - exec_reply); - exec_reply = MACH_PORT_DEAD; - CHK ("mach_port_destroy (exec_reply)", ret); - - xx_debug ("Done with exec call interception\n"); -} - -void -consume_send_rights (thread_array_t thread_list, int thread_count) -{ - int index; - - if (!thread_count) - return; - - for (index = 0; index < thread_count; index++) - { - /* Since thread kill command kills threads, don't check ret */ - (void) mach_port_deallocate (mach_task_self (), - thread_list[index]); - } -} - -/* suspend/abort/resume a thread. */ -setup_thread (mach_port_t thread, int what) -{ - kern_return_t ret; - - if (what) - { - ret = thread_suspend (thread); - CHK ("setup_thread thread_suspend", ret); - - ret = thread_abort (thread); - CHK ("setup_thread thread_abort", ret); - } - else - { - ret = thread_resume (thread); - CHK ("setup_thread thread_resume", ret); - } -} - -int -map_slot_to_mid (int slot, thread_array_t threads, int thread_count) -{ - kern_return_t ret; - int deallocate = 0; - int index; - int mid; - - if (!threads) - { - deallocate++; - ret = task_threads (inferior_task, &threads, &thread_count); - CHK ("Can not select a thread from a dead task", ret); - } - - if (slot < 0 || slot >= thread_count) - { - if (deallocate) - { - consume_send_rights (threads, thread_count); - (void) vm_deallocate (mach_task_self (), (vm_address_t) threads, - (thread_count * sizeof (mach_port_t))); - } - if (slot < 0) - error ("invalid slot number"); - else - return -(slot + 1); - } - - mid = map_port_name_to_mid (threads[slot], MACH_TYPE_THREAD); - - if (deallocate) - { - consume_send_rights (threads, thread_count); - (void) vm_deallocate (mach_task_self (), (vm_address_t) threads, - (thread_count * sizeof (mach_port_t))); - } - - return mid; -} - -static int -parse_thread_id (char *arg, int thread_count, int slots) -{ - kern_return_t ret; - int mid; - int slot; - int index; - - if (arg == 0) - return 0; - - while (*arg && (*arg == ' ' || *arg == '\t')) - arg++; - - if (!*arg) - return 0; - - /* Currently parse MID and @SLOTNUMBER */ - if (*arg != '@') - { - mid = atoi (arg); - if (mid <= 0) - error ("valid thread mid expected"); - return mid; - } - - arg++; - slot = atoi (arg); - - if (slot < 0) - error ("invalid slot number"); - - /* If you want slot numbers to remain slot numbers, set slots. - - * Well, since 0 is reserved, return the ordinal number - * of the thread rather than the slot number. Awk, this - * counts as a kludge. - */ - if (slots) - return -(slot + 1); - - if (thread_count && slot >= thread_count) - return -(slot + 1); - - mid = map_slot_to_mid (slot); - - return mid; -} - -/* THREAD_ID 0 is special; it selects the first kernel - * thread from the list (i.e. SLOTNUMBER 0) - * This is used when starting the program with 'run' or when attaching. - * - * If FLAG is 0 the context is not changed, and the registers, frame, etc - * will continue to describe the old thread. - * - * If FLAG is nonzero, really select the thread. - * If FLAG is 2, the THREAD_ID is a slotnumber instead of a mid. - * - */ -kern_return_t -select_thread (mach_port_t task, int thread_id, int flag) -{ - thread_array_t thread_list; - int thread_count; - kern_return_t ret; - int index; - thread_t new_thread = MACH_PORT_NULL; - - if (thread_id < 0) - error ("Can't select cprocs without kernel thread"); - - ret = task_threads (task, &thread_list, &thread_count); - if (ret != KERN_SUCCESS) - { - warning ("Can not select a thread from a dead task"); - m3_kill_inferior (); - return KERN_FAILURE; - } - - if (thread_count == 0) - { - /* The task can not do anything anymore, but it still - * exists as a container for memory and ports. - */ - registers_changed (); - warning ("Task %d has no threads", - map_port_name_to_mid (task, MACH_TYPE_TASK)); - current_thread = MACH_PORT_NULL; - (void) vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (mach_port_t))); - return KERN_FAILURE; - } - - if (!thread_id || flag == 2) - { - /* First thread or a slotnumber */ - if (!thread_id) - new_thread = thread_list[0]; - else - { - if (thread_id < thread_count) - new_thread = thread_list[thread_id]; - else - { - (void) vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (mach_port_t))); - error ("No such thread slot number : %d", thread_id); - } - } - } - else - { - for (index = 0; index < thread_count; index++) - if (thread_id == map_port_name_to_mid (thread_list[index], - MACH_TYPE_THREAD)) - { - new_thread = thread_list[index]; - index = -1; - break; - } - - if (index != -1) - error ("No thread with mid %d", thread_id); - } - - /* Notify when the selected thread dies */ - request_notify (new_thread, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_THREAD); - - ret = vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (mach_port_t))); - CHK ("vm_deallocate", ret); - - if (!flag) - current_thread = new_thread; - else - { -#if 0 - if (MACH_PORT_VALID (current_thread)) - { - /* Store the gdb's view of the thread we are deselecting - - * @@ I think gdb updates registers immediately when they are - * changed, so don't do this. - */ - ret = thread_abort (current_thread); - CHK ("Could not abort system calls when saving state of old thread", - ret); - target_prepare_to_store (); - target_store_registers (-1); - } -#endif - - registers_changed (); - - current_thread = new_thread; - - ret = thread_abort (current_thread); - CHK ("Could not abort system calls when selecting a thread", ret); - - stop_pc = read_pc (); - flush_cached_frames (); - - select_frame (get_current_frame (), 0); - } - - return KERN_SUCCESS; -} - -/* - * Switch to use thread named NEW_THREAD. - * Return it's MID - */ -int -switch_to_thread (thread_t new_thread) -{ - thread_t saved_thread = current_thread; - int mid; - - mid = map_port_name_to_mid (new_thread, - MACH_TYPE_THREAD); - if (mid == -1) - warning ("Can't map thread name 0x%x to mid", new_thread); - else if (select_thread (inferior_task, mid, 1) != KERN_SUCCESS) - { - if (current_thread) - current_thread = saved_thread; - error ("Could not select thread %d", mid); - } - - return mid; -} - -/* Do this in gdb after doing FORK but before STARTUP_INFERIOR. - * Note that the registers are not yet valid in the inferior task. - */ -static int -m3_trace_him (int pid) -{ - kern_return_t ret; - - push_target (&m3_ops); - - inferior_task = task_by_pid (pid); - - if (!MACH_PORT_VALID (inferior_task)) - error ("Can not map Unix pid %d to Mach task", pid); - - /* Clean up previous notifications and create new ones */ - setup_notify_port (1); - - /* When notification appears, the inferior task has died */ - request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK); - - emulator_present = have_emulator_p (inferior_task); - - /* By default, select the first thread, - * If task has no threads, gives a warning - * Does not fetch registers, since they are not yet valid. - */ - select_thread (inferior_task, 0, 0); - - inferior_exception_port = MACH_PORT_NULL; - - setup_exception_port (); - - xx_debug ("Now the debugged task is created\n"); - - /* One trap to exec the shell, one to exec the program being debugged. */ - intercept_exec_calls (2); - - return pid; -} - -setup_exception_port (void) -{ - kern_return_t ret; - - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &inferior_exception_port); - CHK ("mach_port_allocate", ret); - - /* add send right */ - ret = mach_port_insert_right (mach_task_self (), - inferior_exception_port, - inferior_exception_port, - MACH_MSG_TYPE_MAKE_SEND); - CHK ("mach_port_insert_right", ret); - - ret = mach_port_move_member (mach_task_self (), - inferior_exception_port, - inferior_wait_port_set); - CHK ("mach_port_move_member", ret); - - ret = task_get_special_port (inferior_task, - TASK_EXCEPTION_PORT, - &inferior_old_exception_port); - CHK ("task_get_special_port(old exc)", ret); - - ret = task_set_special_port (inferior_task, - TASK_EXCEPTION_PORT, - inferior_exception_port); - CHK ("task_set_special_port", ret); - - ret = mach_port_deallocate (mach_task_self (), - inferior_exception_port); - CHK ("mack_port_deallocate", ret); - -#if 0 - /* When notify appears, the inferior_task's exception - * port has been destroyed. - * - * Not used, since the dead_name_notification already - * appears when task dies. - * - */ - request_notify (inferior_exception_port, - MACH_NOTIFY_NO_SENDERS, - MACH_TYPE_EXCEPTION_PORT); -#endif -} - -/* Nonzero if gdb is waiting for a message */ -int mach_really_waiting; - -/* Wait for the inferior to stop for some reason. - - Loop on notifications until inferior_task dies. - - Loop on exceptions until stopped_in_exception comes true. - (e.g. we receive a single step trace trap) - - a message arrives to gdb's message port - - There is no other way to exit this loop. - - Returns the inferior_ptid for rest of gdb. - Side effects: Set *OURSTATUS. */ -ptid_t -mach_really_wait (ptid_t ptid, struct target_waitstatus *ourstatus) -{ - kern_return_t ret; - int w; - - struct msg - { - mach_msg_header_t header; - mach_msg_type_t foo; - int data[8000]; - } - in_msg, out_msg; - - /* Either notify (death), exception or message can stop the inferior */ - stopped_in_exception = FALSE; - - while (1) - { - QUIT; - - stop_exception = stop_code = stop_subcode = -1; - stop_thread = MACH_PORT_NULL; - - mach_really_waiting = 1; - ret = mach_msg (&in_msg.header, /* header */ - MACH_RCV_MSG, /* options */ - 0, /* send size */ - sizeof (struct msg), /* receive size */ - currently_waiting_for, /* receive name */ - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - mach_really_waiting = 0; - CHK ("mach_msg (receive)", ret); - - /* Check if we received a notify of the childs' death */ - if (notify_server (&in_msg.header, &out_msg.header)) - { - /* If inferior_task is null then the inferior has - gone away and we want to return to command level. - Otherwise it was just an informative message and we - need to look to see if there are any more. */ - if (inferior_task != MACH_PORT_NULL) - continue; - else - { - /* Collect Unix exit status for gdb */ - - wait3 (&w, WNOHANG, 0); - - /* This mess is here to check that the rest of - * gdb knows that the inferior died. It also - * tries to hack around the fact that Mach 3.0 (mk69) - * unix server (ux28) does not always know what - * has happened to it's children when mach-magic - * is applied on them. - */ - if ((!WIFEXITED (w) && WIFSTOPPED (w)) || - (WIFEXITED (w) && WEXITSTATUS (w) > 0377)) - { - WSETEXIT (w, 0); - warning ("Using exit value 0 for terminated task"); - } - else if (!WIFEXITED (w)) - { - int sig = WTERMSIG (w); - - /* Signals cause problems. Warn the user. */ - if (sig != SIGKILL) /* Bad luck if garbage matches this */ - warning ("The terminating signal stuff may be nonsense"); - else if (sig > NSIG) - { - WSETEXIT (w, 0); - warning ("Using exit value 0 for terminated task"); - } - } - store_waitstatus (ourstatus, w); - return inferior_ptid; - } - } - - /* Hmm. Check for exception, as it was not a notification. - exc_server() does an upcall to catch_exception_raise() - if this rpc is an exception. Further actions are decided - there. - */ - if (!exc_server (&in_msg.header, &out_msg.header)) - { - - /* Not an exception, check for message. - - * Messages don't come from the inferior, or if they - * do they better be asynchronous or it will hang. - */ - if (gdb_message_server (&in_msg.header)) - continue; - - error ("Unrecognized message received in mach_really_wait"); - } - - /* Send the reply of the exception rpc to the suspended task */ - ret = mach_msg_send (&out_msg.header); - CHK ("mach_msg_send (exc reply)", ret); - - if (stopped_in_exception) - { - /* Get unix state. May be changed in mach3_exception_actions() */ - wait3 (&w, WNOHANG, 0); - - mach3_exception_actions (&w, FALSE, "Task"); - - store_waitstatus (ourstatus, w); - return inferior_ptid; - } - } -} - -/* Called by macro DO_QUIT() in utils.c(quit). - * This is called just before calling error() to return to command level - */ -void -mach3_quit (void) -{ - int mid; - kern_return_t ret; - - if (mach_really_waiting) - { - ret = task_suspend (inferior_task); - - if (ret != KERN_SUCCESS) - { - warning ("Could not suspend task for interrupt: %s", - mach_error_string (ret)); - mach_really_waiting = 0; - return; - } - } - - must_suspend_thread = 0; - mach_really_waiting = 0; - - mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); - if (mid == -1) - { - warning ("Selecting first existing kernel thread"); - mid = 0; - } - - current_thread = MACH_PORT_NULL; /* Force setup */ - select_thread (inferior_task, mid, 1); - - return; -} - -#if 0 -/* bogus bogus bogus. It is NOT OK to quit out of target_wait. */ - -/* If ^C is typed when we are waiting for a message - * and your Unix server is able to notice that we - * should quit now. - * - * Called by REQUEST_QUIT() from utils.c(request_quit) - */ -void -mach3_request_quit (void) -{ - if (mach_really_waiting) - immediate_quit = 1; -} -#endif - -/* - * Gdb message server. - * Currently implemented is the STOP message, that causes - * gdb to return to the command level like ^C had been typed from terminal. - */ -int -gdb_message_server (mach_msg_header_t *InP) -{ - kern_return_t ret; - int mid; - - if (InP->msgh_local_port == our_message_port) - { - /* A message coming to our_message_port. Check validity */ - switch (InP->msgh_id) - { - - case GDB_MESSAGE_ID_STOP: - ret = task_suspend (inferior_task); - if (ret != KERN_SUCCESS) - warning ("Could not suspend task for stop message: %s", - mach_error_string (ret)); - - /* QUIT in mach_really_wait() loop. */ - request_quit (0); - break; - - default: - warning ("Invalid message id %d received, ignored.", - InP->msgh_id); - break; - } - - return 1; - } - - /* Message not handled by this server */ - return 0; -} - -/* NOTE: This is not an RPC call. It is a simpleroutine. - - * This is not called from this gdb code. - * - * It may be called by another debugger to cause this - * debugger to enter command level: - * - * (gdb) set stop_inferior_gdb () - * (gdb) continue - * - * External program "stop-gdb" implements this also. - */ -void -stop_inferior_gdb (void) -{ - kern_return_t ret; - - /* Code generated by mig, with minor cleanups :-) - - * simpleroutine stop_inferior_gdb (our_message_port : mach_port_t); - */ - - typedef struct - { - mach_msg_header_t Head; - } - Request; - - Request Mess; - - register Request *InP = &Mess; - - InP->Head.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0); - - /* msgh_size passed as argument */ - InP->Head.msgh_remote_port = our_message_port; - InP->Head.msgh_local_port = MACH_PORT_NULL; - InP->Head.msgh_seqno = 0; - InP->Head.msgh_id = GDB_MESSAGE_ID_STOP; - - ret = mach_msg (&InP->Head, - MACH_SEND_MSG | MACH_MSG_OPTION_NONE, - sizeof (Request), - 0, - MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); -} - -#ifdef THREAD_ALLOWED_TO_BREAK -/* - * Return 1 if the MID specifies the thread that caused the - * last exception. - * Since catch_exception_raise() selects the thread causing - * the last exception to current_thread, we just check that - * it is selected and the last exception was a breakpoint. - */ -int -mach_thread_for_breakpoint (int mid) -{ - int cmid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); - - if (mid < 0) - { - mid = map_slot_to_mid (-(mid + 1), 0, 0); - if (mid < 0) - return 0; /* Don't stop, no such slot */ - } - - if (!mid || cmid == -1) - return 1; /* stop */ - - return cmid == mid && stop_exception == EXC_BREAKPOINT; -} -#endif /* THREAD_ALLOWED_TO_BREAK */ - -#ifdef THREAD_PARSE_ID -/* - * Map a thread id string (MID or a @SLOTNUMBER) - * to a thread-id. - * - * 0 matches all threads. - * Otherwise the meaning is defined only in this file. - * (mach_thread_for_breakpoint uses it) - * - * @@ This allows non-existent MIDs to be specified. - * It now also allows non-existent slots to be - * specified. (Slot numbers stored are negative, - * and the magnitude is one greater than the actual - * slot index. (Since 0 is reserved)) - */ -int -mach_thread_parse_id (char *arg) -{ - int mid; - if (arg == 0) - error ("thread id expected"); - mid = parse_thread_id (arg, 0, 1); - - return mid; -} -#endif /* THREAD_PARSE_ID */ - -#ifdef THREAD_OUTPUT_ID -char * -mach_thread_output_id (int mid) -{ - static char foobar[20]; - - if (mid > 0) - sprintf (foobar, "mid %d", mid); - else if (mid < 0) - sprintf (foobar, "@%d", -(mid + 1)); - else - sprintf (foobar, "*any thread*"); - - return foobar; -} -#endif /* THREAD_OUTPUT_ID */ - -/* Called with hook PREPARE_TO_PROCEED() from infrun.c. - - * If we have switched threads and stopped at breakpoint return 1 otherwise 0. - * - * if SELECT_IT is nonzero, reselect the thread that was active when - * we stopped at a breakpoint. - * - * Note that this implementation is potentially redundant now that - * default_prepare_to_proceed() has been added. - * - * FIXME This may not support switching threads after Ctrl-C - * correctly. The default implementation does support this. - */ - -mach3_prepare_to_proceed (int select_it) -{ - if (stop_thread && - stop_thread != current_thread && - stop_exception == EXC_BREAKPOINT) - { - int mid; - - if (!select_it) - return 1; - - mid = switch_to_thread (stop_thread); - - return 1; - } - - return 0; -} - -/* this stuff here is an upcall via libmach/excServer.c - and mach_really_wait which does the actual upcall. - - The code will pass the exception to the inferior if: - - - The task that signaled is not the inferior task - (e.g. when debugging another debugger) - - - The user has explicitely requested to pass on the exceptions. - (e.g to the default unix exception handler, which maps - exceptions to signals, or the user has her own exception handler) - - - If the thread that signaled is being single-stepped and it - has set it's own exception port and the exception is not - EXC_BREAKPOINT. (Maybe this is not desirable?) - */ - -kern_return_t -catch_exception_raise (mach_port_t port, thread_t thread, task_t task, - int exception, int code, int subcode) -{ - kern_return_t ret; - boolean_t signal_thread; - int mid = map_port_name_to_mid (thread, MACH_TYPE_THREAD); - - if (!MACH_PORT_VALID (thread)) - { - /* If the exception was sent and thread dies before we - receive it, THREAD will be MACH_PORT_DEAD - */ - - current_thread = thread = MACH_PORT_NULL; - error ("Received exception from nonexistent thread"); - } - - /* Check if the task died in transit. - * @@ Isn't the thread also invalid in such case? - */ - if (!MACH_PORT_VALID (task)) - { - current_thread = thread = MACH_PORT_NULL; - error ("Received exception from nonexistent task"); - } - - if (exception < 0 || exception > MAX_EXCEPTION) - internal_error (__FILE__, __LINE__, - "catch_exception_raise: unknown exception code %d thread %d", - exception, - mid); - - if (!MACH_PORT_VALID (inferior_task)) - error ("got an exception, but inferior_task is null or dead"); - - stop_exception = exception; - stop_code = code; - stop_subcode = subcode; - stop_thread = thread; - - signal_thread = exception != EXC_BREAKPOINT && - port == singlestepped_thread_port && - MACH_PORT_VALID (thread_saved_exception_port); - - /* If it was not our inferior or if we want to forward - * the exception to the inferior's handler, do it here - * - * Note: If you have forwarded EXC_BREAKPOINT I trust you know why. - */ - if (task != inferior_task || - signal_thread || - exception_map[exception].forward) - { - mach_port_t eport = inferior_old_exception_port; - - if (signal_thread) - { - /* - GDB now forwards the exeption to thread's original handler, - since the user propably knows what he is doing. - Give a message, though. - */ - - mach3_exception_actions ((WAITTYPE *) NULL, TRUE, "Thread"); - eport = thread_saved_exception_port; - } - - /* Send the exception to the original handler */ - ret = exception_raise (eport, - thread, - task, - exception, - code, - subcode); - - (void) mach_port_deallocate (mach_task_self (), task); - (void) mach_port_deallocate (mach_task_self (), thread); - - /* If we come here, we don't want to trace any more, since we - * will never stop for tracing anyway. - */ - discard_single_step (thread); - - /* Do not stop the inferior */ - return ret; - } - - /* Now gdb handles the exception */ - stopped_in_exception = TRUE; - - ret = task_suspend (task); - CHK ("Error suspending inferior after exception", ret); - - must_suspend_thread = 0; - - if (current_thread != thread) - { - if (MACH_PORT_VALID (singlestepped_thread_port)) - /* Cleanup discards single stepping */ - error ("Exception from thread %d while singlestepping thread %d", - mid, - map_port_name_to_mid (current_thread, MACH_TYPE_THREAD)); - - /* Then select the thread that caused the exception */ - if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) - error ("Could not select thread %d causing exception", mid); - else - warning ("Gdb selected thread %d", mid); - } - - /* If we receive an exception that is not breakpoint - * exception, we interrupt the single step and return to - * debugger. Trace condition is cleared. - */ - if (MACH_PORT_VALID (singlestepped_thread_port)) - { - if (stop_exception != EXC_BREAKPOINT) - warning ("Single step interrupted by exception"); - else if (port == singlestepped_thread_port) - { - /* Single step exception occurred, remove trace bit - * and return to gdb. - */ - if (!MACH_PORT_VALID (current_thread)) - error ("Single stepped thread is not valid"); - - /* Resume threads, but leave the task suspended */ - resume_all_threads (0); - } - else - warning ("Breakpoint while single stepping?"); - - discard_single_step (current_thread); - } - - (void) mach_port_deallocate (mach_task_self (), task); - (void) mach_port_deallocate (mach_task_self (), thread); - - return KERN_SUCCESS; -} - -int -port_valid (mach_port_t port, int mask) -{ - kern_return_t ret; - mach_port_type_t type; - - ret = mach_port_type (mach_task_self (), - port, - &type); - if (ret != KERN_SUCCESS || (type & mask) != mask) - return 0; - return 1; -} - -/* @@ No vm read cache implemented yet */ -boolean_t vm_read_cache_valid = FALSE; - -/* - * Read inferior task's LEN bytes from ADDR and copy it to MYADDR - * in gdb's address space. - * - * Return 0 on failure; number of bytes read otherwise. - */ -int -mach3_read_inferior (CORE_ADDR addr, char *myaddr, int length) -{ - kern_return_t ret; - vm_address_t low_address = (vm_address_t) trunc_page (addr); - vm_size_t aligned_length = - (vm_size_t) round_page (addr + length) - low_address; - pointer_t copied_memory; - int copy_count; - - /* Get memory from inferior with page aligned addresses */ - ret = vm_read (inferior_task, - low_address, - aligned_length, - &copied_memory, - ©_count); - if (ret != KERN_SUCCESS) - { - /* the problem is that the inferior might be killed for whatever reason - * before we go to mach_really_wait. This is one place that ought to - * catch many of those errors. - * @@ A better fix would be to make all external events to GDB - * to arrive via a SINGLE port set. (Including user input!) - */ - - if (!port_valid (inferior_task, MACH_PORT_TYPE_SEND)) - { - m3_kill_inferior (); - error ("Inferior killed (task port invalid)"); - } - else - { -#ifdef OSF - extern int errno; - /* valprint.c gives nicer format if this does not - screw it. Eamonn seems to like this, so I enable - it if OSF is defined... - */ - warning ("[read inferior %x failed: %s]", - addr, mach_error_string (ret)); - errno = 0; -#endif - return 0; - } - } - - memcpy (myaddr, (char *) addr - low_address + copied_memory, length); - - ret = vm_deallocate (mach_task_self (), - copied_memory, - copy_count); - CHK ("mach3_read_inferior vm_deallocate failed", ret); - - return length; -} - -#define CHK_GOTO_OUT(str,ret) \ - do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0) - -struct vm_region_list -{ - struct vm_region_list *next; - vm_prot_t protection; - vm_address_t start; - vm_size_t length; -}; - -struct obstack region_obstack; - -/* - * Write inferior task's LEN bytes from ADDR and copy it to MYADDR - * in gdb's address space. - */ -int -mach3_write_inferior (CORE_ADDR addr, char *myaddr, int length) -{ - kern_return_t ret; - vm_address_t low_address = (vm_address_t) trunc_page (addr); - vm_size_t aligned_length = - (vm_size_t) round_page (addr + length) - low_address; - pointer_t copied_memory; - int copy_count; - int deallocate = 0; - - char *errstr = "Bug in mach3_write_inferior"; - - struct vm_region_list *region_element; - struct vm_region_list *region_head = (struct vm_region_list *) NULL; - - /* Get memory from inferior with page aligned addresses */ - ret = vm_read (inferior_task, - low_address, - aligned_length, - &copied_memory, - ©_count); - CHK_GOTO_OUT ("mach3_write_inferior vm_read failed", ret); - - deallocate++; - - memcpy ((char *) addr - low_address + copied_memory, myaddr, length); - - obstack_init (®ion_obstack); - - /* Do writes atomically. - * First check for holes and unwritable memory. - */ - { - vm_size_t remaining_length = aligned_length; - vm_address_t region_address = low_address; - - struct vm_region_list *scan; - - while (region_address < low_address + aligned_length) - { - vm_prot_t protection; - vm_prot_t max_protection; - vm_inherit_t inheritance; - boolean_t shared; - mach_port_t object_name; - vm_offset_t offset; - vm_size_t region_length = remaining_length; - vm_address_t old_address = region_address; - - ret = vm_region (inferior_task, - ®ion_address, - ®ion_length, - &protection, - &max_protection, - &inheritance, - &shared, - &object_name, - &offset); - CHK_GOTO_OUT ("vm_region failed", ret); - - /* Check for holes in memory */ - if (old_address != region_address) - { - warning ("No memory at 0x%x. Nothing written", - old_address); - ret = KERN_SUCCESS; - length = 0; - goto out; - } - - if (!(max_protection & VM_PROT_WRITE)) - { - warning ("Memory at address 0x%x is unwritable. Nothing written", - old_address); - ret = KERN_SUCCESS; - length = 0; - goto out; - } - - /* Chain the regions for later use */ - region_element = - (struct vm_region_list *) - obstack_alloc (®ion_obstack, sizeof (struct vm_region_list)); - - region_element->protection = protection; - region_element->start = region_address; - region_element->length = region_length; - - /* Chain the regions along with protections */ - region_element->next = region_head; - region_head = region_element; - - region_address += region_length; - remaining_length = remaining_length - region_length; - } - - /* If things fail after this, we give up. - * Somebody is messing up inferior_task's mappings. - */ - - /* Enable writes to the chained vm regions */ - for (scan = region_head; scan; scan = scan->next) - { - boolean_t protection_changed = FALSE; - - if (!(scan->protection & VM_PROT_WRITE)) - { - ret = vm_protect (inferior_task, - scan->start, - scan->length, - FALSE, - scan->protection | VM_PROT_WRITE); - CHK_GOTO_OUT ("vm_protect: enable write failed", ret); - } - } - - ret = vm_write (inferior_task, - low_address, - copied_memory, - aligned_length); - CHK_GOTO_OUT ("vm_write failed", ret); - - /* Set up the original region protections, if they were changed */ - for (scan = region_head; scan; scan = scan->next) - { - boolean_t protection_changed = FALSE; - - if (!(scan->protection & VM_PROT_WRITE)) - { - ret = vm_protect (inferior_task, - scan->start, - scan->length, - FALSE, - scan->protection); - CHK_GOTO_OUT ("vm_protect: enable write failed", ret); - } - } - } - -out: - if (deallocate) - { - obstack_free (®ion_obstack, 0); - - (void) vm_deallocate (mach_task_self (), - copied_memory, - copy_count); - } - - if (ret != KERN_SUCCESS) - { - warning ("%s %s", errstr, mach_error_string (ret)); - return 0; - } - - return length; -} - -/* Return 0 on failure, number of bytes handled otherwise. TARGET is - ignored. */ -static int -m3_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, - struct target_ops *target) -{ - int result; - - if (write) - result = mach3_write_inferior (memaddr, myaddr, len); - else - result = mach3_read_inferior (memaddr, myaddr, len); - - return result; -} - - -static char * -translate_state (int state) -{ - switch (state) - { - case TH_STATE_RUNNING: - return ("R"); - case TH_STATE_STOPPED: - return ("S"); - case TH_STATE_WAITING: - return ("W"); - case TH_STATE_UNINTERRUPTIBLE: - return ("U"); - case TH_STATE_HALTED: - return ("H"); - default: - return ("?"); - } -} - -static char * -translate_cstate (int state) -{ - switch (state) - { - case CPROC_RUNNING: - return "R"; - case CPROC_SWITCHING: - return "S"; - case CPROC_BLOCKED: - return "B"; - case CPROC_CONDWAIT: - return "C"; - case CPROC_CONDWAIT | CPROC_SWITCHING: - return "CS"; - default: - return "?"; - } -} - -/* type == MACH_MSG_TYPE_COPY_SEND || type == MACH_MSG_TYPE_MAKE_SEND */ - -mach_port_t /* no mach_port_name_t found in include files. */ -map_inferior_port_name (mach_port_t inferior_name, mach_msg_type_name_t type) -{ - kern_return_t ret; - mach_msg_type_name_t acquired; - mach_port_t iport; - - ret = mach_port_extract_right (inferior_task, - inferior_name, - type, - &iport, - &acquired); - CHK ("mach_port_extract_right (map_inferior_port_name)", ret); - - if (acquired != MACH_MSG_TYPE_PORT_SEND) - error ("Incorrect right extracted, (map_inferior_port_name)"); - - ret = mach_port_deallocate (mach_task_self (), - iport); - CHK ("Deallocating mapped port (map_inferior_port_name)", ret); - - return iport; -} - -/* - * Naming convention: - * Always return user defined name if found. - * _K == A kernel thread with no matching CPROC - * _C == A cproc with no current cthread - * _t == A cthread with no user defined name - * - * The digits that follow the _names are the SLOT number of the - * kernel thread if there is such a thing, otherwise just a negation - * of the sequential number of such cprocs. - */ - -static char buf[7]; - -static char * -get_thread_name (gdb_thread_t one_cproc, int id) -{ - if (one_cproc) - if (one_cproc->cthread == NULL) - { - /* cproc not mapped to any cthread */ - sprintf (buf, "_C%d", id); - } - else if (!one_cproc->cthread->name) - { - /* cproc and cthread, but no name */ - sprintf (buf, "_t%d", id); - } - else - return (char *) (one_cproc->cthread->name); - else - { - if (id < 0) - warning ("Inconsistency in thread name id %d", id); - - /* Kernel thread without cproc */ - sprintf (buf, "_K%d", id); - } - - return buf; -} - -int -fetch_thread_info (mach_port_t task, gdb_thread_t *mthreads_out) -{ - kern_return_t ret; - thread_array_t th_table; - int th_count; - gdb_thread_t mthreads = NULL; - int index; - - ret = task_threads (task, &th_table, &th_count); - if (ret != KERN_SUCCESS) - { - warning ("Error getting inferior's thread list:%s", - mach_error_string (ret)); - m3_kill_inferior (); - return -1; - } - - mthreads = (gdb_thread_t) - obstack_alloc - (cproc_obstack, - th_count * sizeof (struct gdb_thread)); - - for (index = 0; index < th_count; index++) - { - thread_t saved_thread = MACH_PORT_NULL; - int mid; - - if (must_suspend_thread) - setup_thread (th_table[index], 1); - - if (th_table[index] != current_thread) - { - saved_thread = current_thread; - - mid = switch_to_thread (th_table[index]); - } - - mthreads[index].name = th_table[index]; - mthreads[index].cproc = NULL; /* map_cprocs_to_kernel_threads() */ - mthreads[index].in_emulator = FALSE; - mthreads[index].slotid = index; - - mthreads[index].sp = read_register (SP_REGNUM); - mthreads[index].fp = read_register (FP_REGNUM); - mthreads[index].pc = read_pc (); - - if (MACH_PORT_VALID (saved_thread)) - mid = switch_to_thread (saved_thread); - - if (must_suspend_thread) - setup_thread (th_table[index], 0); - } - - consume_send_rights (th_table, th_count); - ret = vm_deallocate (mach_task_self (), (vm_address_t) th_table, - (th_count * sizeof (mach_port_t))); - if (ret != KERN_SUCCESS) - { - warning ("Error trying to deallocate thread list : %s", - mach_error_string (ret)); - } - - *mthreads_out = mthreads; - - return th_count; -} - - -/* - * Current emulator always saves the USP on top of - * emulator stack below struct emul_stack_top stuff. - */ -CORE_ADDR -fetch_usp_from_emulator_stack (CORE_ADDR sp) -{ - CORE_ADDR stack_pointer; - - sp = (sp & ~(EMULATOR_STACK_SIZE - 1)) + - EMULATOR_STACK_SIZE - sizeof (struct emul_stack_top); - - if (mach3_read_inferior (sp, - &stack_pointer, - sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) - { - warning ("Can't read user sp from emulator stack address 0x%x", sp); - return 0; - } - - return stack_pointer; -} - -#ifdef MK67 - -/* get_emulation_vector() interface was changed after mk67 */ -#define EMUL_VECTOR_COUNT 400 /* Value does not matter too much */ - -#endif /* MK67 */ - -/* Check if the emulator exists at task's address space. - */ -boolean_t -have_emulator_p (task_t task) -{ - kern_return_t ret; -#ifndef EMUL_VECTOR_COUNT - vm_offset_t *emulation_vector; - int n; -#else - vm_offset_t emulation_vector[EMUL_VECTOR_COUNT]; - int n = EMUL_VECTOR_COUNT; -#endif - int i; - int vector_start; - - ret = task_get_emulation_vector (task, - &vector_start, -#ifndef EMUL_VECTOR_COUNT - &emulation_vector, -#else - emulation_vector, -#endif - &n); - CHK ("task_get_emulation_vector", ret); - xx_debug ("%d vectors from %d at 0x%08x\n", - n, vector_start, emulation_vector); - - for (i = 0; i < n; i++) - { - vm_offset_t entry = emulation_vector[i]; - - if (EMULATOR_BASE <= entry && entry <= EMULATOR_END) - return TRUE; - else if (entry) - { - static boolean_t informed = FALSE; - if (!informed) - { - warning ("Emulation vector address 0x08%x outside emulator space", - entry); - informed = TRUE; - } - } - } - return FALSE; -} - -/* Map cprocs to kernel threads and vice versa. */ - -void -map_cprocs_to_kernel_threads (gdb_thread_t cprocs, gdb_thread_t mthreads, - int thread_count) -{ - int index; - gdb_thread_t scan; - boolean_t all_mapped = TRUE; - LONGEST stack_base; - LONGEST stack_size; - - for (scan = cprocs; scan; scan = scan->next) - { - /* Default to: no kernel thread for this cproc */ - scan->reverse_map = -1; - - /* Check if the cproc is found by its stack */ - for (index = 0; index < thread_count; index++) - { - stack_base = - extract_signed_integer (scan->raw_cproc + CPROC_BASE_OFFSET, - CPROC_BASE_SIZE); - stack_size = - extract_signed_integer (scan->raw_cproc + CPROC_SIZE_OFFSET, - CPROC_SIZE_SIZE); - if ((mthreads + index)->sp > stack_base && - (mthreads + index)->sp <= stack_base + stack_size) - { - (mthreads + index)->cproc = scan; - scan->reverse_map = index; - break; - } - } - all_mapped &= (scan->reverse_map != -1); - } - - /* Check for threads that are currently in the emulator. - * If so, they have a different stack, and the still unmapped - * cprocs may well get mapped to these threads. - * - * If: - * - cproc stack does not match any kernel thread stack pointer - * - there is at least one extra kernel thread - * that has no cproc mapped above. - * - some kernel thread stack pointer points to emulator space - * then we find the user stack pointer saved in the emulator - * stack, and try to map that to the cprocs. - * - * Also set in_emulator for kernel threads. - */ - - if (emulator_present) - { - for (index = 0; index < thread_count; index++) - { - CORE_ADDR emul_sp; - CORE_ADDR usp; - - gdb_thread_t mthread = (mthreads + index); - emul_sp = mthread->sp; - - if (mthread->cproc == NULL && - EMULATOR_BASE <= emul_sp && emul_sp <= EMULATOR_END) - { - mthread->in_emulator = emulator_present; - - if (!all_mapped && cprocs) - { - usp = fetch_usp_from_emulator_stack (emul_sp); - - /* @@ Could be more accurate */ - if (!usp) - error ("Zero stack pointer read from emulator?"); - - /* Try to match this stack pointer to the cprocs that - * don't yet have a kernel thread. - */ - for (scan = cprocs; scan; scan = scan->next) - { - - /* Check is this unmapped CPROC stack contains - * the user stack pointer saved in the - * emulator. - */ - if (scan->reverse_map == -1) - { - stack_base = - extract_signed_integer - (scan->raw_cproc + CPROC_BASE_OFFSET, - CPROC_BASE_SIZE); - stack_size = - extract_signed_integer - (scan->raw_cproc + CPROC_SIZE_OFFSET, - CPROC_SIZE_SIZE); - if (usp > stack_base && - usp <= stack_base + stack_size) - { - mthread->cproc = scan; - scan->reverse_map = index; - break; - } - } - } - } - } - } - } -} - -/* - * Format of the thread_list command - * - * slot mid sel name emul ks susp cstate wired address - */ -#define TL_FORMAT "%-2.2s %5d%c %-10.10s %1.1s%s%-5.5s %-2.2s %-5.5s " - -#define TL_HEADER "\n@ MID Name KState CState Where\n" - -void -print_tl_address (struct ui_file *stream, CORE_ADDR pc) -{ - if (!lookup_minimal_symbol_by_pc (pc)) - fprintf_filtered (stream, local_hex_format (), pc); - else - { - extern int addressprint; - extern int asm_demangle; - - int store = addressprint; - addressprint = 0; - print_address_symbolic (pc, stream, asm_demangle, ""); - addressprint = store; - } -} - -/* For thread names, but also for gdb_message_port external name */ -#define MAX_NAME_LEN 50 - -/* Returns the address of variable NAME or 0 if not found */ -CORE_ADDR -lookup_address_of_variable (char *name) -{ - struct symbol *sym; - CORE_ADDR symaddr = 0; - struct minimal_symbol *msymbol; - - sym = lookup_symbol (name, - (struct block *) NULL, - VAR_NAMESPACE, - (int *) NULL, - (struct symtab **) NULL); - - if (sym) - symaddr = SYMBOL_VALUE (sym); - - if (!symaddr) - { - msymbol = lookup_minimal_symbol (name, NULL, NULL); - - if (msymbol && msymbol->type == mst_data) - symaddr = SYMBOL_VALUE_ADDRESS (msymbol); - } - - return symaddr; -} - -static gdb_thread_t -get_cprocs (void) -{ - gdb_thread_t cproc_head; - gdb_thread_t cproc_copy; - CORE_ADDR their_cprocs; - char *buf; - char *name; - cthread_t cthread; - CORE_ADDR symaddr; - - buf = alloca (TARGET_PTR_BIT / HOST_CHAR_BIT); - symaddr = lookup_address_of_variable ("cproc_list"); - - if (!symaddr) - { - /* cproc_list is not in a file compiled with debugging - symbols, but don't give up yet */ - - symaddr = lookup_address_of_variable ("cprocs"); - - if (symaddr) - { - static int informed = 0; - if (!informed) - { - informed++; - warning ("Your program is loaded with an old threads library."); - warning ("GDB does not know the old form of threads"); - warning ("so things may not work."); - } - } - } - - /* Stripped or no -lthreads loaded or "cproc_list" is in wrong segment. */ - if (!symaddr) - return NULL; - - /* Get the address of the first cproc in the task */ - if (!mach3_read_inferior (symaddr, - buf, - TARGET_PTR_BIT / HOST_CHAR_BIT)) - error ("Can't read cproc master list at address (0x%x).", symaddr); - their_cprocs = extract_address (buf, TARGET_PTR_BIT / HOST_CHAR_BIT); - - /* Scan the CPROCs in the task. - CPROCs are chained with LIST field, not NEXT field, which - chains mutexes, condition variables and queues */ - - cproc_head = NULL; - - while (their_cprocs != (CORE_ADDR) 0) - { - CORE_ADDR cproc_copy_incarnation; - cproc_copy = (gdb_thread_t) obstack_alloc (cproc_obstack, - sizeof (struct gdb_thread)); - - if (!mach3_read_inferior (their_cprocs, - &cproc_copy->raw_cproc[0], - CPROC_SIZE)) - error ("Can't read next cproc at 0x%x.", their_cprocs); - - their_cprocs = - extract_address (cproc_copy->raw_cproc + CPROC_LIST_OFFSET, - CPROC_LIST_SIZE); - cproc_copy_incarnation = - extract_address (cproc_copy->raw_cproc + CPROC_INCARNATION_OFFSET, - CPROC_INCARNATION_SIZE); - - if (cproc_copy_incarnation == (CORE_ADDR) 0) - cproc_copy->cthread = NULL; - else - { - /* This CPROC has an attached CTHREAD. Get its name */ - cthread = (cthread_t) obstack_alloc (cproc_obstack, - sizeof (struct cthread)); - - if (!mach3_read_inferior (cproc_copy_incarnation, - cthread, - sizeof (struct cthread))) - error ("Can't read next thread at 0x%x.", - cproc_copy_incarnation); - - cproc_copy->cthread = cthread; - - if (cthread->name) - { - name = (char *) obstack_alloc (cproc_obstack, MAX_NAME_LEN); - - if (!mach3_read_inferior (cthread->name, name, MAX_NAME_LEN)) - error ("Can't read next thread's name at 0x%x.", cthread->name); - - cthread->name = name; - } - } - - /* insert in front */ - cproc_copy->next = cproc_head; - cproc_head = cproc_copy; - } - return cproc_head; -} - -#ifndef FETCH_CPROC_STATE -/* - * Check if your machine does not grok the way this routine - * fetches the FP,PC and SP of a cproc that is not - * currently attached to any kernel thread (e.g. its cproc.context - * field points to the place in stack where the context - * is saved). - * - * If it doesn't, define your own routine. - */ -#define FETCH_CPROC_STATE(mth) mach3_cproc_state (mth) - -int -mach3_cproc_state (gdb_thread_t mthread) -{ - int context; - - if (!mthread || !mthread->cproc) - return -1; - - context = extract_signed_integer - (mthread->cproc->raw_cproc + CPROC_CONTEXT_OFFSET, - CPROC_CONTEXT_SIZE); - if (context == 0) - return -1; - - mthread->sp = context + MACHINE_CPROC_SP_OFFSET; - - if (mach3_read_inferior (context + MACHINE_CPROC_PC_OFFSET, - &mthread->pc, - sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) - { - warning ("Can't read cproc pc from inferior"); - return -1; - } - - if (mach3_read_inferior (context + MACHINE_CPROC_FP_OFFSET, - &mthread->fp, - sizeof (CORE_ADDR)) != sizeof (CORE_ADDR)) - { - warning ("Can't read cproc fp from inferior"); - return -1; - } - - return 0; -} -#endif /* FETCH_CPROC_STATE */ - - -void -thread_list_command (void) -{ - thread_basic_info_data_t ths; - int thread_count; - gdb_thread_t cprocs; - gdb_thread_t scan; - int index; - char *name; - char selected; - char *wired; - int infoCnt; - kern_return_t ret; - mach_port_t mid_or_port; - gdb_thread_t their_threads; - gdb_thread_t kthread; - - int neworder = 1; - - char *fmt = "There are %d kernel threads in task %d.\n"; - - int tmid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); - - MACH_ERROR_NO_INFERIOR; - - thread_count = fetch_thread_info (inferior_task, - &their_threads); - if (thread_count == -1) - return; - - if (thread_count == 1) - fmt = "There is %d kernel thread in task %d.\n"; - - printf_filtered (fmt, thread_count, tmid); - - puts_filtered (TL_HEADER); - - cprocs = get_cprocs (); - - map_cprocs_to_kernel_threads (cprocs, their_threads, thread_count); - - for (scan = cprocs; scan; scan = scan->next) - { - int mid; - char buf[10]; - char slot[3]; - int cproc_state = - extract_signed_integer - (scan->raw_cproc + CPROC_STATE_OFFSET, CPROC_STATE_SIZE); - - selected = ' '; - - /* a wired cproc? */ - wired = (extract_address (scan->raw_cproc + CPROC_WIRED_OFFSET, - CPROC_WIRED_SIZE) - ? "wired" : ""); - - if (scan->reverse_map != -1) - kthread = (their_threads + scan->reverse_map); - else - kthread = NULL; - - if (kthread) - { - /* These cprocs have a kernel thread */ - - mid = map_port_name_to_mid (kthread->name, MACH_TYPE_THREAD); - - infoCnt = THREAD_BASIC_INFO_COUNT; - - ret = thread_info (kthread->name, - THREAD_BASIC_INFO, - (thread_info_t) & ths, - &infoCnt); - - if (ret != KERN_SUCCESS) - { - warning ("Unable to get basic info on thread %d : %s", - mid, - mach_error_string (ret)); - continue; - } - - /* Who is the first to have more than 100 threads */ - sprintf (slot, "%d", kthread->slotid % 100); - - if (kthread->name == current_thread) - selected = '*'; - - if (ths.suspend_count) - sprintf (buf, "%d", ths.suspend_count); - else - buf[0] = '\000'; - -#if 0 - if (ths.flags & TH_FLAGS_SWAPPED) - strcat (buf, "S"); -#endif - - if (ths.flags & TH_FLAGS_IDLE) - strcat (buf, "I"); - - printf_filtered (TL_FORMAT, - slot, - mid, - selected, - get_thread_name (scan, kthread->slotid), - kthread->in_emulator ? "E" : "", - translate_state (ths.run_state), - buf, - translate_cstate (cproc_state), - wired); - print_tl_address (gdb_stdout, kthread->pc); - } - else - { - /* These cprocs don't have a kernel thread. - * find out the calling frame with - * FETCH_CPROC_STATE. - */ - - struct gdb_thread state; - -#if 0 - /* jtv -> emcmanus: why do you want this here? */ - if (scan->incarnation == NULL) - continue; /* EMcM */ -#endif - - printf_filtered (TL_FORMAT, - "-", - -neworder, /* Pseudo MID */ - selected, - get_thread_name (scan, -neworder), - "", - "-", /* kernel state */ - "", - translate_cstate (cproc_state), - ""); - state.cproc = scan; - - if (FETCH_CPROC_STATE (&state) == -1) - puts_filtered ("???"); - else - print_tl_address (gdb_stdout, state.pc); - - neworder++; - } - puts_filtered ("\n"); - } - - /* Scan for kernel threads without cprocs */ - for (index = 0; index < thread_count; index++) - { - if (!their_threads[index].cproc) - { - int mid; - - char buf[10]; - char slot[3]; - - mach_port_t name = their_threads[index].name; - - mid = map_port_name_to_mid (name, MACH_TYPE_THREAD); - - infoCnt = THREAD_BASIC_INFO_COUNT; - - ret = thread_info (name, - THREAD_BASIC_INFO, - (thread_info_t) & ths, - &infoCnt); - - if (ret != KERN_SUCCESS) - { - warning ("Unable to get basic info on thread %d : %s", - mid, - mach_error_string (ret)); - continue; - } - - sprintf (slot, "%d", index % 100); - - if (name == current_thread) - selected = '*'; - else - selected = ' '; - - if (ths.suspend_count) - sprintf (buf, "%d", ths.suspend_count); - else - buf[0] = '\000'; - -#if 0 - if (ths.flags & TH_FLAGS_SWAPPED) - strcat (buf, "S"); -#endif - - if (ths.flags & TH_FLAGS_IDLE) - strcat (buf, "I"); - - printf_filtered (TL_FORMAT, - slot, - mid, - selected, - get_thread_name (NULL, index), - their_threads[index].in_emulator ? "E" : "", - translate_state (ths.run_state), - buf, - "", /* No cproc state */ - ""); /* Can't be wired */ - print_tl_address (gdb_stdout, their_threads[index].pc); - puts_filtered ("\n"); - } - } - - obstack_free (cproc_obstack, 0); - obstack_init (cproc_obstack); -} - -void -thread_select_command (char *args, int from_tty) -{ - int mid; - thread_array_t thread_list; - int thread_count; - kern_return_t ret; - int is_slot = 0; - - MACH_ERROR_NO_INFERIOR; - - if (!args) - error_no_arg ("MID or @SLOTNUMBER to specify a thread to select"); - - while (*args == ' ' || *args == '\t') - args++; - - if (*args == '@') - { - is_slot++; - args++; - } - - mid = atoi (args); - - if (mid == 0) - if (!is_slot || *args != '0') /* Rudimentary checks */ - error ("You must select threads by MID or @SLOTNUMBER"); - - if (select_thread (inferior_task, mid, is_slot ? 2 : 1) != KERN_SUCCESS) - return; - - if (from_tty) - printf_filtered ("Thread %d selected\n", - is_slot ? map_port_name_to_mid (current_thread, - MACH_TYPE_THREAD) : mid); -} - -thread_trace (mach_port_t thread, boolean_t set) -{ - int flavor = TRACE_FLAVOR; - unsigned int stateCnt = TRACE_FLAVOR_SIZE; - kern_return_t ret; - thread_state_data_t state; - - if (!MACH_PORT_VALID (thread)) - { - warning ("thread_trace: invalid thread"); - return; - } - - if (must_suspend_thread) - setup_thread (thread, 1); - - ret = thread_get_state (thread, flavor, state, &stateCnt); - CHK ("thread_trace: error reading thread state", ret); - - if (set) - { - TRACE_SET (thread, state); - } - else - { - if (!TRACE_CLEAR (thread, state)) - { - if (must_suspend_thread) - setup_thread (thread, 0); - return; - } - } - - ret = thread_set_state (thread, flavor, state, stateCnt); - CHK ("thread_trace: error writing thread state", ret); - if (must_suspend_thread) - setup_thread (thread, 0); -} - -#ifdef FLUSH_INFERIOR_CACHE - -/* When over-writing code on some machines the I-Cache must be flushed - explicitly, because it is not kept coherent by the lazy hardware. - This definitely includes breakpoints, for instance, or else we - end up looping in mysterious Bpt traps */ - -flush_inferior_icache (CORE_ADDR pc, int amount) -{ - vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH; - kern_return_t ret; - - ret = vm_machine_attribute (inferior_task, - pc, - amount, - MATTR_CACHE, - &flush); - if (ret != KERN_SUCCESS) - warning ("Error flushing inferior's cache : %s", - mach_error_string (ret)); -} -#endif /* FLUSH_INFERIOR_CACHE */ - - -static -suspend_all_threads (int from_tty) -{ - kern_return_t ret; - thread_array_t thread_list; - int thread_count, index; - int infoCnt; - thread_basic_info_data_t th_info; - - - ret = task_threads (inferior_task, &thread_list, &thread_count); - if (ret != KERN_SUCCESS) - { - warning ("Could not suspend inferior threads."); - m3_kill_inferior (); - throw_exception (RETURN_ERROR); - } - - for (index = 0; index < thread_count; index++) - { - int mid; - - mid = map_port_name_to_mid (thread_list[index], - MACH_TYPE_THREAD); - - ret = thread_suspend (thread_list[index]); - - if (ret != KERN_SUCCESS) - warning ("Error trying to suspend thread %d : %s", - mid, mach_error_string (ret)); - - if (from_tty) - { - infoCnt = THREAD_BASIC_INFO_COUNT; - ret = thread_info (thread_list[index], - THREAD_BASIC_INFO, - (thread_info_t) & th_info, - &infoCnt); - CHK ("suspend can't get thread info", ret); - - warning ("Thread %d suspend count is %d", - mid, th_info.suspend_count); - } - } - - consume_send_rights (thread_list, thread_count); - ret = vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (int))); - CHK ("Error trying to deallocate thread list", ret); -} - -void -thread_suspend_command (char *args, int from_tty) -{ - kern_return_t ret; - int mid; - mach_port_t saved_thread; - int infoCnt; - thread_basic_info_data_t th_info; - - MACH_ERROR_NO_INFERIOR; - - if (!strcasecmp (args, "all")) - { - suspend_all_threads (from_tty); - return; - } - - saved_thread = current_thread; - - mid = parse_thread_id (args, 0, 0); - - if (mid < 0) - error ("You can suspend only existing kernel threads with MID or @SLOTNUMBER"); - - if (mid == 0) - mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); - else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) - { - if (current_thread) - current_thread = saved_thread; - error ("Could not select thread %d", mid); - } - - ret = thread_suspend (current_thread); - if (ret != KERN_SUCCESS) - warning ("thread_suspend failed : %s", - mach_error_string (ret)); - - infoCnt = THREAD_BASIC_INFO_COUNT; - ret = thread_info (current_thread, - THREAD_BASIC_INFO, - (thread_info_t) & th_info, - &infoCnt); - CHK ("suspend can't get thread info", ret); - - warning ("Thread %d suspend count is %d", mid, th_info.suspend_count); - - current_thread = saved_thread; -} - -resume_all_threads (int from_tty) -{ - kern_return_t ret; - thread_array_t thread_list; - int thread_count, index; - int mid; - int infoCnt; - thread_basic_info_data_t th_info; - - ret = task_threads (inferior_task, &thread_list, &thread_count); - if (ret != KERN_SUCCESS) - { - m3_kill_inferior (); - error ("task_threads", mach_error_string (ret)); - } - - for (index = 0; index < thread_count; index++) - { - infoCnt = THREAD_BASIC_INFO_COUNT; - ret = thread_info (thread_list[index], - THREAD_BASIC_INFO, - (thread_info_t) & th_info, - &infoCnt); - CHK ("resume_all can't get thread info", ret); - - mid = map_port_name_to_mid (thread_list[index], - MACH_TYPE_THREAD); - - if (!th_info.suspend_count) - { - if (mid != -1 && from_tty) - warning ("Thread %d is not suspended", mid); - continue; - } - - ret = thread_resume (thread_list[index]); - - if (ret != KERN_SUCCESS) - warning ("Error trying to resume thread %d : %s", - mid, mach_error_string (ret)); - else if (mid != -1 && from_tty) - warning ("Thread %d suspend count is %d", - mid, --th_info.suspend_count); - } - - consume_send_rights (thread_list, thread_count); - ret = vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (int))); - CHK ("Error trying to deallocate thread list", ret); -} - -void -thread_resume_command (char *args, int from_tty) -{ - int mid; - mach_port_t saved_thread; - kern_return_t ret; - thread_basic_info_data_t th_info; - int infoCnt = THREAD_BASIC_INFO_COUNT; - - MACH_ERROR_NO_INFERIOR; - - if (!strcasecmp (args, "all")) - { - resume_all_threads (from_tty); - return; - } - - saved_thread = current_thread; - - mid = parse_thread_id (args, 0, 0); - - if (mid < 0) - error ("You can resume only existing kernel threads with MID or @SLOTNUMBER"); - - if (mid == 0) - mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); - else if (select_thread (inferior_task, mid, 0) != KERN_SUCCESS) - { - if (current_thread) - current_thread = saved_thread; - throw_exception (RETURN_ERROR); - } - - ret = thread_info (current_thread, - THREAD_BASIC_INFO, - (thread_info_t) & th_info, - &infoCnt); - CHK ("resume can't get thread info", ret); - - if (!th_info.suspend_count) - { - warning ("Thread %d is not suspended", mid); - goto out; - } - - ret = thread_resume (current_thread); - if (ret != KERN_SUCCESS) - warning ("thread_resume failed : %s", - mach_error_string (ret)); - else - { - th_info.suspend_count--; - warning ("Thread %d suspend count is %d", mid, th_info.suspend_count); - } - -out: - current_thread = saved_thread; -} - -void -thread_kill_command (char *args, int from_tty) -{ - int mid; - kern_return_t ret; - int thread_count; - thread_array_t thread_table; - int index; - mach_port_t thread_to_kill = MACH_PORT_NULL; - - - MACH_ERROR_NO_INFERIOR; - - if (!args) - error_no_arg ("thread mid to kill from the inferior task"); - - mid = parse_thread_id (args, 0, 0); - - if (mid < 0) - error ("You can kill only existing kernel threads with MID or @SLOTNUMBER"); - - if (mid) - { - ret = machid_mach_port (mid_server, mid_auth, mid, &thread_to_kill); - CHK ("thread_kill_command: machid_mach_port map failed", ret); - } - else - mid = map_port_name_to_mid (current_thread, MACH_TYPE_THREAD); - - /* Don't allow gdb to kill *any* thread in the system. Use mkill program for that */ - ret = task_threads (inferior_task, &thread_table, &thread_count); - CHK ("Error getting inferior's thread list", ret); - - if (thread_to_kill == current_thread) - { - ret = thread_terminate (thread_to_kill); - CHK ("Thread could not be terminated", ret); - - if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS) - warning ("Last thread was killed, use \"kill\" command to kill task"); - } - else - for (index = 0; index < thread_count; index++) - if (thread_table[index] == thread_to_kill) - { - ret = thread_terminate (thread_to_kill); - CHK ("Thread could not be terminated", ret); - } - - if (thread_count > 1) - consume_send_rights (thread_table, thread_count); - - ret = vm_deallocate (mach_task_self (), (vm_address_t) thread_table, - (thread_count * sizeof (mach_port_t))); - CHK ("Error trying to deallocate thread list", ret); - - warning ("Thread %d killed", mid); -} - - -/* Task specific commands; add more if you like */ - -void -task_resume_command (char *args, int from_tty) -{ - kern_return_t ret; - task_basic_info_data_t ta_info; - int infoCnt = TASK_BASIC_INFO_COUNT; - int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); - - MACH_ERROR_NO_INFERIOR; - - /* Would be trivial to change, but is it desirable? */ - if (args) - error ("Currently gdb can resume only it's inferior task"); - - ret = task_info (inferior_task, - TASK_BASIC_INFO, - (task_info_t) & ta_info, - &infoCnt); - CHK ("task_resume_command: task_info failed", ret); - - if (ta_info.suspend_count == 0) - error ("Inferior task %d is not suspended", mid); - else if (ta_info.suspend_count == 1 && - from_tty && - !query ("Suspend count is now 1. Do you know what you are doing? ")) - error ("Task not resumed"); - - ret = task_resume (inferior_task); - CHK ("task_resume_command: task_resume", ret); - - if (ta_info.suspend_count == 1) - { - warning ("Inferior task %d is no longer suspended", mid); - must_suspend_thread = 1; - /* @@ This is not complete: Registers change all the time when not - suspended! */ - registers_changed (); - } - else - warning ("Inferior task %d suspend count is now %d", - mid, ta_info.suspend_count - 1); -} - - -void -task_suspend_command (char *args, int from_tty) -{ - kern_return_t ret; - task_basic_info_data_t ta_info; - int infoCnt = TASK_BASIC_INFO_COUNT; - int mid = map_port_name_to_mid (inferior_task, MACH_TYPE_TASK); - - MACH_ERROR_NO_INFERIOR; - - /* Would be trivial to change, but is it desirable? */ - if (args) - error ("Currently gdb can suspend only it's inferior task"); - - ret = task_suspend (inferior_task); - CHK ("task_suspend_command: task_suspend", ret); - - must_suspend_thread = 0; - - ret = task_info (inferior_task, - TASK_BASIC_INFO, - (task_info_t) & ta_info, - &infoCnt); - CHK ("task_suspend_command: task_info failed", ret); - - warning ("Inferior task %d suspend count is now %d", - mid, ta_info.suspend_count); -} - -static char * -get_size (int bytes) -{ - static char size[30]; - int zz = bytes / 1024; - - if (zz / 1024) - sprintf (size, "%-2.1f M", ((float) bytes) / (1024.0 * 1024.0)); - else - sprintf (size, "%d K", zz); - - return size; -} - -/* Does this require the target task to be suspended?? I don't think so. */ -void -task_info_command (char *args, int from_tty) -{ - int mid = -5; - mach_port_t task; - kern_return_t ret; - task_basic_info_data_t ta_info; - int infoCnt = TASK_BASIC_INFO_COUNT; - int page_size = round_page (1); - int thread_count = 0; - - if (MACH_PORT_VALID (inferior_task)) - mid = map_port_name_to_mid (inferior_task, - MACH_TYPE_TASK); - - task = inferior_task; - - if (args) - { - int tmid = atoi (args); - - if (tmid <= 0) - error ("Invalid mid %d for task info", tmid); - - if (tmid != mid) - { - mid = tmid; - ret = machid_mach_port (mid_server, mid_auth, tmid, &task); - CHK ("task_info_command: machid_mach_port map failed", ret); - } - } - - if (mid < 0) - error ("You have to give the task MID as an argument"); - - ret = task_info (task, - TASK_BASIC_INFO, - (task_info_t) & ta_info, - &infoCnt); - CHK ("task_info_command: task_info failed", ret); - - printf_filtered ("\nTask info for task %d:\n\n", mid); - printf_filtered (" Suspend count : %d\n", ta_info.suspend_count); - printf_filtered (" Base priority : %d\n", ta_info.base_priority); - printf_filtered (" Virtual size : %s\n", get_size (ta_info.virtual_size)); - printf_filtered (" Resident size : %s\n", get_size (ta_info.resident_size)); - - { - thread_array_t thread_list; - - ret = task_threads (task, &thread_list, &thread_count); - CHK ("task_info_command: task_threads", ret); - - printf_filtered (" Thread count : %d\n", thread_count); - - consume_send_rights (thread_list, thread_count); - ret = vm_deallocate (mach_task_self (), - (vm_address_t) thread_list, - (thread_count * sizeof (int))); - CHK ("Error trying to deallocate thread list", ret); - } - if (have_emulator_p (task)) - printf_filtered (" Emulator at : 0x%x..0x%x\n", - EMULATOR_BASE, EMULATOR_END); - else - printf_filtered (" No emulator.\n"); - - if (thread_count && task == inferior_task) - printf_filtered ("\nUse the \"thread list\" command to see the threads\n"); -} - -/* You may either FORWARD the exception to the inferior, or KEEP - * it and return to GDB command level. - * - * exception mid [ forward | keep ] - */ - -static void -exception_command (char *args, int from_tty) -{ - char *scan = args; - int exception; - int len; - - if (!args) - error_no_arg ("exception number action"); - - while (*scan == ' ' || *scan == '\t') - scan++; - - if ('0' <= *scan && *scan <= '9') - while ('0' <= *scan && *scan <= '9') - scan++; - else - error ("exception number action"); - - exception = atoi (args); - if (exception <= 0 || exception > MAX_EXCEPTION) - error ("Allowed exception numbers are in range 1..%d", - MAX_EXCEPTION); - - if (*scan != ' ' && *scan != '\t') - error ("exception number must be followed by a space"); - else - while (*scan == ' ' || *scan == '\t') - scan++; - - args = scan; - len = 0; - while (*scan) - { - len++; - scan++; - } - - if (!len) - error ("exception number action"); - - if (!strncasecmp (args, "forward", len)) - exception_map[exception].forward = TRUE; - else if (!strncasecmp (args, "keep", len)) - exception_map[exception].forward = FALSE; - else - error ("exception action is either \"keep\" or \"forward\""); -} - -static void -print_exception_info (int exception) -{ - boolean_t forward = exception_map[exception].forward; - - printf_filtered ("%s\t(%d): ", exception_map[exception].name, - exception); - if (!forward) - if (exception_map[exception].sigmap != SIG_UNKNOWN) - printf_filtered ("keep and handle as signal %d\n", - exception_map[exception].sigmap); - else - printf_filtered ("keep and handle as unknown signal %d\n", - exception_map[exception].sigmap); - else - printf_filtered ("forward exception to inferior\n"); -} - -void -exception_info (char *args, int from_tty) -{ - int exception; - - if (!args) - for (exception = 1; exception <= MAX_EXCEPTION; exception++) - print_exception_info (exception); - else - { - exception = atoi (args); - - if (exception <= 0 || exception > MAX_EXCEPTION) - error ("Invalid exception number, values from 1 to %d allowed", - MAX_EXCEPTION); - print_exception_info (exception); - } -} - -/* Check for actions for mach exceptions. - */ -mach3_exception_actions (WAITTYPE *w, boolean_t force_print_only, char *who) -{ - boolean_t force_print = FALSE; - - - if (force_print_only || - exception_map[stop_exception].sigmap == SIG_UNKNOWN) - force_print = TRUE; - else - WSETSTOP (*w, exception_map[stop_exception].sigmap); - - if (exception_map[stop_exception].print || force_print) - { - target_terminal_ours (); - - printf_filtered ("\n%s received %s exception : ", - who, - exception_map[stop_exception].name); - - wrap_here (" "); - - switch (stop_exception) - { - case EXC_BAD_ACCESS: - printf_filtered ("referencing address 0x%x : %s\n", - stop_subcode, - mach_error_string (stop_code)); - break; - case EXC_BAD_INSTRUCTION: - printf_filtered - ("illegal or undefined instruction. code %d subcode %d\n", - stop_code, stop_subcode); - break; - case EXC_ARITHMETIC: - printf_filtered ("code %d\n", stop_code); - break; - case EXC_EMULATION: - printf_filtered ("code %d subcode %d\n", stop_code, stop_subcode); - break; - case EXC_SOFTWARE: - printf_filtered ("%s specific, code 0x%x\n", - stop_code < 0xffff ? "hardware" : "os emulation", - stop_code); - break; - case EXC_BREAKPOINT: - printf_filtered ("type %d (machine dependent)\n", - stop_code); - break; - default: - internal_error (__FILE__, __LINE__, - "Unknown exception"); - } - } -} - -setup_notify_port (int create_new) -{ - kern_return_t ret; - - if (MACH_PORT_VALID (our_notify_port)) - { - ret = mach_port_destroy (mach_task_self (), our_notify_port); - CHK ("Could not destroy our_notify_port", ret); - } - - our_notify_port = MACH_PORT_NULL; - notify_chain = (port_chain_t) NULL; - port_chain_destroy (port_chain_obstack); - - if (create_new) - { - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &our_notify_port); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, - "Creating notify port %s", mach_error_string (ret)); - - ret = mach_port_move_member (mach_task_self (), - our_notify_port, - inferior_wait_port_set); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, - "initial move member %s", mach_error_string (ret)); - } -} - -/* - * Register our message port to the net name server - * - * Currently used only by the external stop-gdb program - * since ^C does not work if you would like to enter - * gdb command level while debugging your program. - * - * NOTE: If the message port is sometimes used for other - * purposes also, the NAME must not be a guessable one. - * Then, there should be a way to change it. - */ - -char registered_name[MAX_NAME_LEN]; - -void -message_port_info (char *args, int from_tty) -{ - if (registered_name[0]) - printf_filtered ("gdb's message port name: '%s'\n", - registered_name); - else - printf_filtered ("gdb's message port is not currently registered\n"); -} - -void -gdb_register_port (char *name, mach_port_t port) -{ - kern_return_t ret; - static int already_signed = 0; - int len; - - if (!MACH_PORT_VALID (port) || !name || !*name) - { - warning ("Invalid registration request"); - return; - } - - if (!already_signed) - { - ret = mach_port_insert_right (mach_task_self (), - our_message_port, - our_message_port, - MACH_MSG_TYPE_MAKE_SEND); - CHK ("Failed to create a signature to our_message_port", ret); - already_signed = 1; - } - else if (already_signed > 1) - { - ret = netname_check_out (name_server_port, - registered_name, - our_message_port); - CHK ("Failed to check out gdb's message port", ret); - registered_name[0] = '\000'; - already_signed = 1; - } - - ret = netname_check_in (name_server_port, /* Name server port */ - name, /* Name of service */ - our_message_port, /* Signature */ - port); /* Creates a new send right */ - CHK ("Failed to check in the port", ret); - - len = 0; - while (len < MAX_NAME_LEN && *(name + len)) - { - registered_name[len] = *(name + len); - len++; - } - registered_name[len] = '\000'; - already_signed = 2; -} - -struct cmd_list_element *cmd_thread_list; -struct cmd_list_element *cmd_task_list; - -/*ARGSUSED */ -static void -thread_command (char *arg, int from_tty) -{ - printf_unfiltered ("\"thread\" must be followed by the name of a thread command.\n"); - help_list (cmd_thread_list, "thread ", -1, gdb_stdout); -} - -/*ARGSUSED */ -static void -task_command (char *arg, int from_tty) -{ - printf_unfiltered ("\"task\" must be followed by the name of a task command.\n"); - help_list (cmd_task_list, "task ", -1, gdb_stdout); -} - -add_mach_specific_commands (void) -{ - /* Thread handling commands */ - - /* FIXME: Move our thread support into the generic thread.c stuff so we - can share that code. */ - add_prefix_cmd ("mthread", class_stack, thread_command, - "Generic command for handling Mach threads in the debugged task.", - &cmd_thread_list, "thread ", 0, &cmdlist); - - add_com_alias ("th", "mthread", class_stack, 1); - - add_cmd ("select", class_stack, thread_select_command, - "Select and print MID of the selected thread", - &cmd_thread_list); - add_cmd ("list", class_stack, thread_list_command, - "List info of task's threads. Selected thread is marked with '*'", - &cmd_thread_list); - add_cmd ("suspend", class_run, thread_suspend_command, - "Suspend one or all of the threads in the selected task.", - &cmd_thread_list); - add_cmd ("resume", class_run, thread_resume_command, - "Resume one or all of the threads in the selected task.", - &cmd_thread_list); - add_cmd ("kill", class_run, thread_kill_command, - "Kill the specified thread MID from inferior task.", - &cmd_thread_list); -#if 0 - /* The rest of this support (condition_thread) was not merged. It probably - should not be merged in this form, but instead added to the generic GDB - thread support. */ - add_cmd ("break", class_breakpoint, condition_thread, - "Breakpoint N will only be effective for thread MID or @SLOT\n\ - If MID/@SLOT is omitted allow all threads to break at breakpoint", - &cmd_thread_list); -#endif - /* Thread command shorthands (for backward compatibility) */ - add_alias_cmd ("ts", "mthread select", 0, 0, &cmdlist); - add_alias_cmd ("tl", "mthread list", 0, 0, &cmdlist); - - /* task handling commands */ - - add_prefix_cmd ("task", class_stack, task_command, - "Generic command for handling debugged task.", - &cmd_task_list, "task ", 0, &cmdlist); - - add_com_alias ("ta", "task", class_stack, 1); - - add_cmd ("suspend", class_run, task_suspend_command, - "Suspend the inferior task.", - &cmd_task_list); - add_cmd ("resume", class_run, task_resume_command, - "Resume the inferior task.", - &cmd_task_list); - add_cmd ("info", no_class, task_info_command, - "Print information about the specified task.", - &cmd_task_list); - - /* Print my message port name */ - - add_info ("message-port", message_port_info, - "Returns the name of gdb's message port in the netnameserver"); - - /* Exception commands */ - - add_info ("exceptions", exception_info, - "What debugger does when program gets various exceptions.\n\ -Specify an exception number as argument to print info on that\n\ -exception only."); - - add_com ("exception", class_run, exception_command, - "Specify how to handle an exception.\n\ -Args are exception number followed by \"forward\" or \"keep\".\n\ -`Forward' means forward the exception to the program's normal exception\n\ -handler.\n\ -`Keep' means reenter debugger if this exception happens, and GDB maps\n\ -the exception to some signal (see info exception)\n\ -Normally \"keep\" is used to return to GDB on exception."); -} - -kern_return_t -do_mach_notify_dead_name (mach_port_t notify, mach_port_t name) -{ - kern_return_t kr = KERN_SUCCESS; - - /* Find the thing that notified */ - port_chain_t element = port_chain_member (notify_chain, name); - - /* Take name of from unreceived dead name notification list */ - notify_chain = port_chain_delete (notify_chain, name); - - if (!element) - error ("Received a dead name notify from unchained port (0x%x)", name); - - switch (element->type) - { - - case MACH_TYPE_THREAD: - target_terminal_ours_for_output (); - if (name == current_thread) - { - printf_filtered ("\nCurrent thread %d died", element->mid); - current_thread = MACH_PORT_NULL; - } - else - printf_filtered ("\nThread %d died", element->mid); - - break; - - case MACH_TYPE_TASK: - target_terminal_ours_for_output (); - if (name != inferior_task) - printf_filtered ("Task %d died, but it was not the selected task", - element->mid); - else - { - printf_filtered ("Current task %d died", element->mid); - - mach_port_destroy (mach_task_self (), name); - inferior_task = MACH_PORT_NULL; - - if (notify_chain) - warning ("There were still unreceived dead_name_notifications???"); - - /* Destroy the old notifications */ - setup_notify_port (0); - - } - break; - - default: - error ("Unregistered dead_name 0x%x notification received. Type is %d, mid is 0x%x", - name, element->type, element->mid); - break; - } - - return KERN_SUCCESS; -} - -kern_return_t -do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name) -{ - warning ("do_mach_notify_msg_accepted : notify %x, name %x", - notify, name); - return KERN_SUCCESS; -} - -kern_return_t -do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t mscount) -{ - warning ("do_mach_notify_no_senders : notify %x, mscount %x", - notify, mscount); - return KERN_SUCCESS; -} - -kern_return_t -do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name) -{ - warning ("do_mach_notify_port_deleted : notify %x, name %x", - notify, name); - return KERN_SUCCESS; -} - -kern_return_t -do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t rights) -{ - warning ("do_mach_notify_port_destroyed : notify %x, rights %x", - notify, rights); - return KERN_SUCCESS; -} - -kern_return_t -do_mach_notify_send_once (mach_port_t notify) -{ -#ifdef DUMP_SYSCALL - /* MANY of these are generated. */ - warning ("do_mach_notify_send_once : notify %x", - notify); -#endif - return KERN_SUCCESS; -} - -/* Kills the inferior. It's gone when you call this */ -static void -kill_inferior_fast (void) -{ - WAITTYPE w; - - if (PIDGET (inferior_ptid) == 0 || PIDGET (inferior_ptid) == 1) - return; - - /* kill() it, since the Unix server does not otherwise notice when - * killed with task_terminate(). - */ - if (PIDGET (inferior_ptid) > 0) - kill (PIDGET (inferior_ptid), SIGKILL); - - /* It's propably terminate already */ - (void) task_terminate (inferior_task); - - inferior_task = MACH_PORT_NULL; - current_thread = MACH_PORT_NULL; - - wait3 (&w, WNOHANG, 0); - - setup_notify_port (0); -} - -static void -m3_kill_inferior (void) -{ - kill_inferior_fast (); - target_mourn_inferior (); -} - -/* Clean up after the inferior dies. */ - -static void -m3_mourn_inferior (void) -{ - unpush_target (&m3_ops); - generic_mourn_inferior (); -} - - -/* Fork an inferior process, and start debugging it. */ - -static void -m3_create_inferior (char *exec_file, char *allargs, char **env) -{ - fork_inferior (exec_file, allargs, env, m3_trace_me, m3_trace_him, NULL, NULL); - /* We are at the first instruction we care about. */ - /* Pedal to the metal... */ - proceed ((CORE_ADDR) -1, 0, 0); -} - -/* Mark our target-struct as eligible for stray "run" and "attach" - commands. */ -static int -m3_can_run (void) -{ - return 1; -} - -/* Mach 3.0 does not need ptrace for anything - * Make sure nobody uses it on mach. - */ -ptrace (int a, int b, int c, int d) -{ - error ("Lose, Lose! Somebody called ptrace\n"); -} - -/* Resume execution of the inferior process. - If STEP is nonzero, single-step it. - If SIGNAL is nonzero, give it that signal. */ - -void -m3_resume (ptid_t ptid, int step, enum target_signal signal) -{ - kern_return_t ret; - - if (step) - { - thread_basic_info_data_t th_info; - unsigned int infoCnt = THREAD_BASIC_INFO_COUNT; - - /* There is no point in single stepping when current_thread - * is dead. - */ - if (!MACH_PORT_VALID (current_thread)) - error ("No thread selected; can not single step"); - - /* If current_thread is suspended, tracing it would never return. - */ - ret = thread_info (current_thread, - THREAD_BASIC_INFO, - (thread_info_t) & th_info, - &infoCnt); - CHK ("child_resume: can't get thread info", ret); - - if (th_info.suspend_count) - error ("Can't trace a suspended thread. Use \"thread resume\" command to resume it"); - } - - vm_read_cache_valid = FALSE; - - if (signal && PIDGET (inferior_ptid) > 0) /* Do not signal, if attached by MID */ - kill (PIDGET (inferior_ptid), target_signal_to_host (signal)); - - if (step) - { - suspend_all_threads (0); - - setup_single_step (current_thread, TRUE); - - ret = thread_resume (current_thread); - CHK ("thread_resume", ret); - } - - ret = task_resume (inferior_task); - if (ret == KERN_FAILURE) - warning ("Task was not suspended"); - else - CHK ("Resuming task", ret); - - /* HACK HACK This is needed by the multiserver system HACK HACK */ - while ((ret = task_resume (inferior_task)) == KERN_SUCCESS) - /* make sure it really runs */ ; - /* HACK HACK This is needed by the multiserver system HACK HACK */ -} - -#ifdef ATTACH_DETACH - -/* Start debugging the process with the given task */ -void -task_attach (task_t tid) -{ - kern_return_t ret; - inferior_task = tid; - - ret = task_suspend (inferior_task); - CHK ("task_attach: task_suspend", ret); - - must_suspend_thread = 0; - - setup_notify_port (1); - - request_notify (inferior_task, MACH_NOTIFY_DEAD_NAME, MACH_TYPE_TASK); - - setup_exception_port (); - - emulator_present = have_emulator_p (inferior_task); - - attach_flag = 1; -} - -/* Well, we can call error also here and leave the - * target stack inconsistent. Sigh. - * Fix this sometime (the only way to fail here is that - * the task has no threads at all, which is rare, but - * possible; or if the target task has died, which is also - * possible, but unlikely, since it has been suspended. - * (Someone must have killed it)) - */ -void -attach_to_thread (void) -{ - if (select_thread (inferior_task, 0, 1) != KERN_SUCCESS) - error ("Could not select any threads to attach to"); -} - -mid_attach (int mid) -{ - kern_return_t ret; - - ret = machid_mach_port (mid_server, mid_auth, mid, &inferior_task); - CHK ("mid_attach: machid_mach_port", ret); - - task_attach (inferior_task); - - return mid; -} - -/* - * Start debugging the process whose unix process-id is PID. - * A negative "pid" value is legal and signifies a mach_id not a unix pid. - * - * Prevent (possible unwanted) dangerous operations by enabled users - * like "atta 0" or "atta foo" (equal to the previous :-) and - * "atta pidself". Anyway, the latter is allowed by specifying a MID. - */ -static int -m3_do_attach (int pid) -{ - kern_return_t ret; - - if (pid == 0) - error ("MID=0, Debugging the master unix server does not compute"); - - /* Foo. This assumes gdb has a unix pid */ - if (pid == getpid ()) - error ("I will debug myself only by mid. (Gdb would suspend itself!)"); - - if (pid < 0) - { - mid_attach (-(pid)); - - /* inferior_ptid will be NEGATIVE! */ - inferior_ptid = pid_to_ptid (pid); - - return PIDGET (inferior_ptid); - } - - inferior_task = task_by_pid (pid); - if (!MACH_PORT_VALID (inferior_task)) - error ("Cannot map Unix pid %d to Mach task port", pid); - - task_attach (inferior_task); - - inferior_ptid = pid_to_ptid (pid); - - return PIDGET (inferior_ptid); -} - -/* Attach to process PID, then initialize for debugging it - and wait for the trace-trap that results from attaching. */ - -static void -m3_attach (char *args, int from_tty) -{ - char *exec_file; - int pid; - - if (!args) - error_no_arg ("process-id to attach"); - - pid = atoi (args); - - if (pid == getpid ()) /* Trying to masturbate? */ - error ("I refuse to debug myself!"); - - if (from_tty) - { - exec_file = (char *) get_exec_file (0); - - if (exec_file) - printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, - target_pid_to_str (pid_to_ptid (pid))); - else - printf_unfiltered ("Attaching to %s\n", - target_pid_to_str (pid_to_ptid (pid))); - - gdb_flush (gdb_stdout); - } - - m3_do_attach (pid_to_ptid (pid)); - inferior_ptid = pid_to_ptid (pid); - push_target (&m3_ops); -} - -void -deallocate_inferior_ports (void) -{ - kern_return_t ret; - thread_array_t thread_list; - int thread_count, index; - - if (!MACH_PORT_VALID (inferior_task)) - return; - - ret = task_threads (inferior_task, &thread_list, &thread_count); - if (ret != KERN_SUCCESS) - { - warning ("deallocate_inferior_ports: task_threads", - mach_error_string (ret)); - return; - } - - /* Get rid of send rights to task threads */ - for (index = 0; index < thread_count; index++) - { - int rights; - ret = mach_port_get_refs (mach_task_self (), - thread_list[index], - MACH_PORT_RIGHT_SEND, - &rights); - CHK ("deallocate_inferior_ports: get refs", ret); - - if (rights > 0) - { - ret = mach_port_mod_refs (mach_task_self (), - thread_list[index], - MACH_PORT_RIGHT_SEND, - -rights); - CHK ("deallocate_inferior_ports: mod refs", ret); - } - } - - ret = mach_port_mod_refs (mach_task_self (), - inferior_exception_port, - MACH_PORT_RIGHT_RECEIVE, - -1); - CHK ("deallocate_inferior_ports: cannot get rid of exception port", ret); - - ret = mach_port_deallocate (mach_task_self (), - inferior_task); - CHK ("deallocate_task_port: deallocating inferior_task", ret); - - current_thread = MACH_PORT_NULL; - inferior_task = MACH_PORT_NULL; -} - -/* Stop debugging the process whose number is PID - and continue it with signal number SIGNAL. - SIGNAL = 0 means just continue it. */ - -static void -m3_do_detach (int signal) -{ - kern_return_t ret; - - MACH_ERROR_NO_INFERIOR; - - if (current_thread != MACH_PORT_NULL) - { - /* Store the gdb's view of the thread we are deselecting - * before we detach. - * @@ I am really not sure if this is ever needeed. - */ - target_prepare_to_store (); - target_store_registers (-1); - } - - ret = task_set_special_port (inferior_task, - TASK_EXCEPTION_PORT, - inferior_old_exception_port); - CHK ("task_set_special_port", ret); - - /* Discard all requested notifications */ - setup_notify_port (0); - - if (remove_breakpoints ()) - warning ("Could not remove breakpoints when detaching"); - - if (signal && PIDGET (inferior_ptid) > 0) - kill (PIDGET (inferior_ptid), signal); - - /* the task might be dead by now */ - (void) task_resume (inferior_task); - - deallocate_inferior_ports (); - - attach_flag = 0; -} - -/* Take a program previously attached to and detaches it. - The program resumes execution and will no longer stop - on signals, etc. We'd better not have left any breakpoints - in the program or it'll die when it hits one. For this - to work, it may be necessary for the process to have been - previously attached. It *might* work if the program was - started via fork. */ - -static void -m3_detach (char *args, int from_tty) -{ - int siggnal = 0; - - if (from_tty) - { - char *exec_file = get_exec_file (0); - if (exec_file == 0) - exec_file = ""; - printf_unfiltered ("Detaching from program: %s %s\n", - exec_file, target_pid_to_str (inferior_ptid)); - gdb_flush (gdb_stdout); - } - if (args) - siggnal = atoi (args); - - m3_do_detach (siggnal); - inferior_ptid = null_ptid; - unpush_target (&m3_ops); /* Pop out of handling an inferior */ -} -#endif /* ATTACH_DETACH */ - -/* 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 -m3_prepare_to_store (void) -{ -#ifdef CHILD_PREPARE_TO_STORE - CHILD_PREPARE_TO_STORE (); -#endif -} - -/* Print status information about what we're accessing. */ - -static void -m3_files_info (struct target_ops *ignore) -{ - /* FIXME: should print MID and all that crap. */ - printf_unfiltered ("\tUsing the running image of %s %s.\n", - attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid)); -} - -static void -m3_open (char *arg, int from_tty) -{ - error ("Use the \"run\" command to start a Unix child process."); -} - -#ifdef DUMP_SYSCALL -#define STR(x) #x - -char *bsd1_names[] = -{ - "execve", - "fork", - "take_signal", - "sigreturn", - "getrusage", - "chdir", - "chroot", - "open", - "creat", - "mknod", - "link", - "symlink", - "unlink", - "access", - "stat", - "readlink", - "chmod", - "chown", - "utimes", - "truncate", - "rename", - "mkdir", - "rmdir", - "xutimes", - "mount", - "umount", - "acct", - "setquota", - "write_short", - "write_long", - "send_short", - "send_long", - "sendto_short", - "sendto_long", - "select", - "task_by_pid", - "recvfrom_short", - "recvfrom_long", - "setgroups", - "setrlimit", - "sigvec", - "sigstack", - "settimeofday", - "adjtime", - "setitimer", - "sethostname", - "bind", - "accept", - "connect", - "setsockopt", - "getsockopt", - "getsockname", - "getpeername", - "init_process", - "table_set", - "table_get", - "pioctl", - "emulator_error", - "readwrite", - "share_wakeup", - 0, - "maprw_request_it", - "maprw_release_it", - "maprw_remap", - "pid_by_task", -}; - -int bsd1_nnames = sizeof (bsd1_names) / sizeof (bsd1_names[0]); - -char * -name_str (int name, char *buf) -{ - switch (name) - { - case MACH_MSG_TYPE_BOOLEAN: - return "boolean"; - case MACH_MSG_TYPE_INTEGER_16: - return "short"; - case MACH_MSG_TYPE_INTEGER_32: - return "long"; - case MACH_MSG_TYPE_CHAR: - return "char"; - case MACH_MSG_TYPE_BYTE: - return "byte"; - case MACH_MSG_TYPE_REAL: - return "real"; - case MACH_MSG_TYPE_STRING: - return "string"; - default: - sprintf (buf, "%d", name); - return buf; - } -} - -char * -id_str (int id, char *buf) -{ - char *p; - if (id >= 101000 && id < 101000 + bsd1_nnames) - { - if (p = bsd1_names[id - 101000]) - return p; - } - if (id == 102000) - return "psignal_retry"; - if (id == 100000) - return "syscall"; - sprintf (buf, "%d", id); - return buf; -} - -print_msg (mach_msg_header_t *mp) -{ - char *fmt_x = "%20s : 0x%08x\n"; - char *fmt_d = "%20s : %10d\n"; - char *fmt_s = "%20s : %s\n"; - char buf[100]; - - puts_filtered ("\n"); -#define pr(fmt,h,x) printf_filtered(fmt,STR(x),(h).x) - pr (fmt_x, (*mp), msgh_bits); - pr (fmt_d, (*mp), msgh_size); - pr (fmt_x, (*mp), msgh_remote_port); - pr (fmt_x, (*mp), msgh_local_port); - pr (fmt_d, (*mp), msgh_kind); - printf_filtered (fmt_s, STR (msgh_id), id_str (mp->msgh_id, buf)); - - if (debug_level > 1) - { - char *p, *ep, *dp; - int plen; - p = (char *) mp; - ep = p + mp->msgh_size; - p += sizeof (*mp); - for (; p < ep; p += plen) - { - mach_msg_type_t *tp; - mach_msg_type_long_t *tlp; - int name, size, number; - tp = (mach_msg_type_t *) p; - if (tp->msgt_longform) - { - tlp = (mach_msg_type_long_t *) tp; - name = tlp->msgtl_name; - size = tlp->msgtl_size; - number = tlp->msgtl_number; - plen = sizeof (*tlp); - } - else - { - name = tp->msgt_name; - size = tp->msgt_size; - number = tp->msgt_number; - plen = sizeof (*tp); - } - printf_filtered ("name=%-16s size=%2d number=%7d inline=%d long=%d deal=%d\n", - name_str (name, buf), size, number, tp->msgt_inline, - tp->msgt_longform, tp->msgt_deallocate); - dp = p + plen; - if (tp->msgt_inline) - { - int l; - l = size * number / 8; - l = (l + sizeof (long) - 1) & ~((sizeof (long)) - 1); - plen += l; - print_data (dp, size, number); - } - else - { - plen += sizeof (int *); - } - printf_filtered ("plen=%d\n", plen); - } - } -} - -print_data (char *p, int size, int number) -{ - int *ip; - short *sp; - int i; - - switch (size) - { - case 8: - for (i = 0; i < number; i++) - { - printf_filtered (" %02x", p[i]); - } - break; - case 16: - sp = (short *) p; - for (i = 0; i < number; i++) - { - printf_filtered (" %04x", sp[i]); - } - break; - case 32: - ip = (int *) p; - for (i = 0; i < number; i++) - { - printf_filtered (" %08x", ip[i]); - } - break; - } - puts_filtered ("\n"); -} -#endif /* DUMP_SYSCALL */ - -static void -m3_stop (void) -{ - error ("to_stop target function not implemented"); -} - -static char * -m3_pid_to_exec_file (int pid) -{ - error ("to_pid_to_exec_file target function not implemented"); - return NULL; /* To keep all compilers happy. */ -} - -static void -init_m3_ops (void) -{ - m3_ops.to_shortname = "mach"; - m3_ops.to_longname = "Mach child process"; - m3_ops.to_doc = "Mach child process (started by the \"run\" command)."; - m3_ops.to_open = m3_open; - m3_ops.to_attach = m3_attach; - m3_ops.to_detach = m3_detach; - m3_ops.to_resume = m3_resume; - m3_ops.to_wait = mach_really_wait; - m3_ops.to_fetch_registers = fetch_inferior_registers; - m3_ops.to_store_registers = store_inferior_registers; - m3_ops.to_prepare_to_store = m3_prepare_to_store; - m3_ops.to_xfer_memory = m3_xfer_memory; - m3_ops.to_files_info = m3_files_info; - m3_ops.to_insert_breakpoint = memory_insert_breakpoint; - m3_ops.to_remove_breakpoint = memory_remove_breakpoint; - m3_ops.to_terminal_init = terminal_init_inferior; - m3_ops.to_terminal_inferior = terminal_inferior; - m3_ops.to_terminal_ours_for_output = terminal_ours_for_output; - m3_ops.to_terminal_ours = terminal_ours; - m3_ops.to_terminal_info = child_terminal_info; - m3_ops.to_kill = m3_kill_inferior; - m3_ops.to_create_inferior = m3_create_inferior; - m3_ops.to_mourn_inferior = m3_mourn_inferior; - m3_ops.to_can_run = m3_can_run; - m3_ops.to_stop = m3_stop; - m3_ops.to_pid_to_exec_file = m3_pid_to_exec_file; - m3_ops.to_stratum = process_stratum; - m3_ops.to_has_all_memory = 1; - m3_ops.to_has_memory = 1; - m3_ops.to_has_stack = 1; - m3_ops.to_has_registers = 1; - m3_ops.to_has_execution = 1; - m3_ops.to_magic = OPS_MAGIC; -} - -void -_initialize_m3_nat (void) -{ - kern_return_t ret; - - init_m3_ops (); - add_target (&m3_ops); - - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_PORT_SET, - &inferior_wait_port_set); - if (ret != KERN_SUCCESS) - internal_error (__FILE__, __LINE__, - "initial port set %s", mach_error_string (ret)); - - /* mach_really_wait now waits for this */ - currently_waiting_for = inferior_wait_port_set; - - ret = netname_look_up (name_server_port, hostname, "MachID", &mid_server); - if (ret != KERN_SUCCESS) - { - mid_server = MACH_PORT_NULL; - - warning ("initialize machid: netname_lookup_up(MachID) : %s", - mach_error_string (ret)); - warning ("Some (most?) features disabled..."); - } - - mid_auth = mach_privileged_host_port (); - if (mid_auth == MACH_PORT_NULL) - mid_auth = mach_task_self (); - - obstack_init (port_chain_obstack); - - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &thread_exception_port); - CHK ("Creating thread_exception_port for single stepping", ret); - - ret = mach_port_insert_right (mach_task_self (), - thread_exception_port, - thread_exception_port, - MACH_MSG_TYPE_MAKE_SEND); - CHK ("Inserting send right to thread_exception_port", ret); - - /* Allocate message port */ - ret = mach_port_allocate (mach_task_self (), - MACH_PORT_RIGHT_RECEIVE, - &our_message_port); - if (ret != KERN_SUCCESS) - warning ("Creating message port %s", mach_error_string (ret)); - else - { - char buf[MAX_NAME_LEN]; - ret = mach_port_move_member (mach_task_self (), - our_message_port, - inferior_wait_port_set); - if (ret != KERN_SUCCESS) - warning ("message move member %s", mach_error_string (ret)); - - - /* @@@@ No way to change message port name currently */ - /* Foo. This assumes gdb has a unix pid */ - sprintf (buf, "gdb-%d", getpid ()); - gdb_register_port (buf, our_message_port); - } - - /* Heap for thread commands */ - obstack_init (cproc_obstack); - - add_mach_specific_commands (); -} diff --git a/contrib/gdb/gdb/minimon.h b/contrib/gdb/gdb/minimon.h deleted file mode 100644 index 94fd774..0000000 --- a/contrib/gdb/gdb/minimon.h +++ /dev/null @@ -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; - }; diff --git a/contrib/gdb/gdb/monitor.c b/contrib/gdb/gdb/monitor.c deleted file mode 100644 index e760d43..0000000 --- a/contrib/gdb/gdb/monitor.c +++ /dev/null @@ -1,2386 +0,0 @@ -/* Remote debugging interface for boot monitors, for GDB. - - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - - Contributed by Cygnus Support. Written by Rob Savoye for Cygnus. - Resurrected from the ashes by Stu Grossman. - - 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 various remote-* modules. It is a collection - of generic support functions so GDB can talk directly to a ROM based - monitor. This saves use from having to hack an exception based handler - into existence, and makes for quick porting. - - This module talks to a debug monitor called 'MONITOR', which - We communicate with MONITOR via either a direct serial line, or a TCP - (or possibly TELNET) stream to a terminal multiplexor, - which in turn talks to the target board. */ - -/* FIXME 32x64: This code assumes that registers and addresses are at - most 32 bits long. If they can be larger, you will need to declare - values as LONGEST and use %llx or some such to print values when - building commands to send to the monitor. Since we don't know of - any actual 64-bit targets with ROM monitors that use this code, - it's not an issue right now. -sts 4/18/96 */ - -#include "defs.h" -#include "gdbcore.h" -#include "target.h" -#include <signal.h> -#include <ctype.h> -#include "gdb_string.h" -#include <sys/types.h> -#include "command.h" -#include "serial.h" -#include "monitor.h" -#include "gdbcmd.h" -#include "inferior.h" -#include "gdb_regex.h" -#include "srec.h" -#include "regcache.h" - -static char *dev_name; -static struct target_ops *targ_ops; - -static void monitor_vsprintf (char *sndbuf, char *pattern, va_list args); - -static int readchar (int timeout); - -static void monitor_fetch_register (int regno); -static void monitor_store_register (int regno); - -static void monitor_printable_string (char *newstr, char *oldstr, int len); -static void monitor_error (char *function, char *message, CORE_ADDR memaddr, int len, char *string, int final_char); -static void monitor_detach (char *args, int from_tty); -static void monitor_resume (ptid_t ptid, int step, enum target_signal sig); -static void monitor_interrupt (int signo); -static void monitor_interrupt_twice (int signo); -static void monitor_interrupt_query (void); -static void monitor_wait_cleanup (void *old_timeout); - -static ptid_t monitor_wait (ptid_t ptid, struct target_waitstatus *status); -static void monitor_fetch_registers (int regno); -static void monitor_store_registers (int regno); -static void monitor_prepare_to_store (void); -static int monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, - int write, - struct mem_attrib *attrib, - struct target_ops *target); -static void monitor_files_info (struct target_ops *ops); -static int monitor_insert_breakpoint (CORE_ADDR addr, char *shadow); -static int monitor_remove_breakpoint (CORE_ADDR addr, char *shadow); -static void monitor_kill (void); -static void monitor_load (char *file, int from_tty); -static void monitor_mourn_inferior (void); -static void monitor_stop (void); - -static int monitor_read_memory (CORE_ADDR addr, char *myaddr, int len); -static int monitor_write_memory (CORE_ADDR addr, char *myaddr, int len); -static int monitor_write_memory_bytes (CORE_ADDR addr, char *myaddr, int len); -static int monitor_write_memory_block (CORE_ADDR memaddr, - char *myaddr, int len); -static int monitor_expect_regexp (struct re_pattern_buffer *pat, - char *buf, int buflen); -static void monitor_dump_regs (void); -#if 0 -static int from_hex (int a); -static unsigned long get_hex_word (void); -#endif -static void parse_register_dump (char *, int); - -static struct monitor_ops *current_monitor; - -static int hashmark; /* flag set by "set hash" */ - -static int timeout = 30; - -static int in_monitor_wait = 0; /* Non-zero means we are in monitor_wait() */ - -static void (*ofunc) (); /* Old SIGINT signal handler */ - -static CORE_ADDR *breakaddr; - -/* Descriptor for I/O to remote machine. Initialize it to NULL so - that monitor_open knows that we don't have a file open when the - program starts. */ - -static struct serial *monitor_desc = NULL; - -/* Pointer to regexp pattern matching data */ - -static struct re_pattern_buffer register_pattern; -static char register_fastmap[256]; - -static struct re_pattern_buffer getmem_resp_delim_pattern; -static char getmem_resp_delim_fastmap[256]; - -static struct re_pattern_buffer setmem_resp_delim_pattern; -static char setmem_resp_delim_fastmap[256]; - -static struct re_pattern_buffer setreg_resp_delim_pattern; -static char setreg_resp_delim_fastmap[256]; - -static int dump_reg_flag; /* Non-zero means do a dump_registers cmd when - monitor_wait wakes up. */ - -static int first_time = 0; /* is this the first time we're executing after - gaving created the child proccess? */ - -#define TARGET_BUF_SIZE 2048 - -/* Monitor specific debugging information. Typically only useful to - the developer of a new monitor interface. */ - -static void monitor_debug (const char *fmt, ...) ATTR_FORMAT(printf, 1, 2); - -static int monitor_debug_p = 0; - -/* NOTE: This file alternates between monitor_debug_p and remote_debug - when determining if debug information is printed. Perhaphs this - could be simplified. */ - -static void -monitor_debug (const char *fmt, ...) -{ - if (monitor_debug_p) - { - va_list args; - va_start (args, fmt); - vfprintf_filtered (gdb_stdlog, fmt, args); - va_end (args); - } -} - - -/* Convert a string into a printable representation, Return # byte in - the new string. When LEN is >0 it specifies the size of the - string. Otherwize strlen(oldstr) is used. */ - -static void -monitor_printable_string (char *newstr, char *oldstr, int len) -{ - int ch; - int i; - - if (len <= 0) - len = strlen (oldstr); - - for (i = 0; i < len; i++) - { - ch = oldstr[i]; - switch (ch) - { - default: - if (isprint (ch)) - *newstr++ = ch; - - else - { - sprintf (newstr, "\\x%02x", ch & 0xff); - newstr += 4; - } - break; - - case '\\': - *newstr++ = '\\'; - *newstr++ = '\\'; - break; - case '\b': - *newstr++ = '\\'; - *newstr++ = 'b'; - break; - case '\f': - *newstr++ = '\\'; - *newstr++ = 't'; - break; - case '\n': - *newstr++ = '\\'; - *newstr++ = 'n'; - break; - case '\r': - *newstr++ = '\\'; - *newstr++ = 'r'; - break; - case '\t': - *newstr++ = '\\'; - *newstr++ = 't'; - break; - case '\v': - *newstr++ = '\\'; - *newstr++ = 'v'; - break; - } - } - - *newstr++ = '\0'; -} - -/* Print monitor errors with a string, converting the string to printable - representation. */ - -static void -monitor_error (char *function, char *message, - CORE_ADDR memaddr, int len, char *string, int final_char) -{ - int real_len = (len == 0 && string != (char *) 0) ? strlen (string) : len; - char *safe_string = alloca ((real_len * 4) + 1); - monitor_printable_string (safe_string, string, real_len); - - if (final_char) - error ("%s (0x%s): %s: %s%c", function, paddr_nz (memaddr), message, safe_string, final_char); - else - error ("%s (0x%s): %s: %s", function, paddr_nz (memaddr), message, safe_string); -} - -/* Convert hex digit A to a number. */ - -static int -fromhex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - else if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - else if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - else - error ("Invalid hex digit %d", a); -} - -/* monitor_vsprintf - similar to vsprintf but handles 64-bit addresses - - This function exists to get around the problem that many host platforms - don't have a printf that can print 64-bit addresses. The %A format - specification is recognized as a special case, and causes the argument - to be printed as a 64-bit hexadecimal address. - - Only format specifiers of the form "[0-9]*[a-z]" are recognized. - If it is a '%s' format, the argument is a string; otherwise the - argument is assumed to be a long integer. - - %% is also turned into a single %. - */ - -static void -monitor_vsprintf (char *sndbuf, char *pattern, va_list args) -{ - char format[10]; - char fmt; - char *p; - int i; - long arg_int; - CORE_ADDR arg_addr; - char *arg_string; - - for (p = pattern; *p; p++) - { - if (*p == '%') - { - /* Copy the format specifier to a separate buffer. */ - format[0] = *p++; - for (i = 1; *p >= '0' && *p <= '9' && i < (int) sizeof (format) - 2; - i++, p++) - format[i] = *p; - format[i] = fmt = *p; - format[i + 1] = '\0'; - - /* Fetch the next argument and print it. */ - switch (fmt) - { - case '%': - strcpy (sndbuf, "%"); - break; - case 'A': - arg_addr = va_arg (args, CORE_ADDR); - strcpy (sndbuf, paddr_nz (arg_addr)); - break; - case 's': - arg_string = va_arg (args, char *); - sprintf (sndbuf, format, arg_string); - break; - default: - arg_int = va_arg (args, long); - sprintf (sndbuf, format, arg_int); - break; - } - sndbuf += strlen (sndbuf); - } - else - *sndbuf++ = *p; - } - *sndbuf = '\0'; -} - - -/* monitor_printf_noecho -- Send data to monitor, but don't expect an echo. - Works just like printf. */ - -void -monitor_printf_noecho (char *pattern,...) -{ - va_list args; - char sndbuf[2000]; - int len; - - va_start (args, pattern); - - monitor_vsprintf (sndbuf, pattern, args); - - len = strlen (sndbuf); - if (len + 1 > sizeof sndbuf) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - - if (monitor_debug_p) - { - char *safe_string = (char *) alloca ((strlen (sndbuf) * 4) + 1); - monitor_printable_string (safe_string, sndbuf, 0); - fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string); - } - - monitor_write (sndbuf, len); -} - -/* monitor_printf -- Send data to monitor and check the echo. Works just like - printf. */ - -void -monitor_printf (char *pattern,...) -{ - va_list args; - char sndbuf[2000]; - int len; - - va_start (args, pattern); - - monitor_vsprintf (sndbuf, pattern, args); - - len = strlen (sndbuf); - if (len + 1 > sizeof sndbuf) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - - if (monitor_debug_p) - { - char *safe_string = (char *) alloca ((len * 4) + 1); - monitor_printable_string (safe_string, sndbuf, 0); - fprintf_unfiltered (gdb_stdlog, "sent[%s]\n", safe_string); - } - - monitor_write (sndbuf, len); - - /* We used to expect that the next immediate output was the characters we - just output, but sometimes some extra junk appeared before the characters - we expected, like an extra prompt, or a portmaster sending telnet negotiations. - So, just start searching for what we sent, and skip anything unknown. */ - monitor_debug ("ExpectEcho\n"); - monitor_expect (sndbuf, (char *) 0, 0); -} - - -/* Write characters to the remote system. */ - -void -monitor_write (char *buf, int buflen) -{ - if (serial_write (monitor_desc, buf, buflen)) - fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n", - safe_strerror (errno)); -} - - -/* Read a binary character from the remote system, doing all the fancy - timeout stuff, but without interpreting the character in any way, - and without printing remote debug information. */ - -int -monitor_readchar (void) -{ - int c; - int looping; - - do - { - looping = 0; - c = serial_readchar (monitor_desc, timeout); - - if (c >= 0) - c &= 0xff; /* don't lose bit 7 */ - } - while (looping); - - if (c >= 0) - return c; - - if (c == SERIAL_TIMEOUT) - error ("Timeout reading from remote system."); - - perror_with_name ("remote-monitor"); -} - - -/* Read a character from the remote system, doing all the fancy - timeout stuff. */ - -static int -readchar (int timeout) -{ - int c; - static enum - { - last_random, last_nl, last_cr, last_crnl - } - state = last_random; - int looping; - - do - { - looping = 0; - c = serial_readchar (monitor_desc, timeout); - - if (c >= 0) - { - c &= 0x7f; - /* This seems to interfere with proper function of the - input stream */ - if (monitor_debug_p || remote_debug) - { - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - puts_debug ("read -->", buf, "<--"); - } - - } - - /* Canonicialize \n\r combinations into one \r */ - if ((current_monitor->flags & MO_HANDLE_NL) != 0) - { - if ((c == '\r' && state == last_nl) - || (c == '\n' && state == last_cr)) - { - state = last_crnl; - looping = 1; - } - else if (c == '\r') - state = last_cr; - else if (c != '\n') - state = last_random; - else - { - state = last_nl; - c = '\r'; - } - } - } - while (looping); - - if (c >= 0) - return c; - - if (c == SERIAL_TIMEOUT) -#if 0 - /* I fail to see how detaching here can be useful */ - if (in_monitor_wait) /* Watchdog went off */ - { - target_mourn_inferior (); - error ("GDB serial timeout has expired. Target detached.\n"); - } - else -#endif - error ("Timeout reading from remote system."); - - perror_with_name ("remote-monitor"); -} - -/* Scan input from the remote system, until STRING is found. If BUF is non- - zero, then collect input until we have collected either STRING or BUFLEN-1 - chars. In either case we terminate BUF with a 0. If input overflows BUF - because STRING can't be found, return -1, else return number of chars in BUF - (minus the terminating NUL). Note that in the non-overflow case, STRING - will be at the end of BUF. */ - -int -monitor_expect (char *string, char *buf, int buflen) -{ - char *p = string; - int obuflen = buflen; - int c; - extern struct target_ops *targ_ops; - - if (monitor_debug_p) - { - char *safe_string = (char *) alloca ((strlen (string) * 4) + 1); - monitor_printable_string (safe_string, string, 0); - fprintf_unfiltered (gdb_stdlog, "MON Expecting '%s'\n", safe_string); - } - - immediate_quit++; - while (1) - { - if (buf) - { - if (buflen < 2) - { - *buf = '\000'; - immediate_quit--; - return -1; - } - - c = readchar (timeout); - if (c == '\000') - continue; - *buf++ = c; - buflen--; - } - else - c = readchar (timeout); - - /* Don't expect any ^C sent to be echoed */ - - if (*p == '\003' || c == *p) - { - p++; - if (*p == '\0') - { - immediate_quit--; - - if (buf) - { - *buf++ = '\000'; - return obuflen - buflen; - } - else - return 0; - } - } - else if ((c == '\021' || c == '\023') && - (STREQ (targ_ops->to_shortname, "m32r") - || STREQ (targ_ops->to_shortname, "mon2000"))) - { /* m32r monitor emits random DC1/DC3 chars */ - continue; - } - else - { - /* We got a character that doesn't match the string. We need to - back up p, but how far? If we're looking for "..howdy" and the - monitor sends "...howdy"? There's certainly a match in there, - but when we receive the third ".", we won't find it if we just - restart the matching at the beginning of the string. - - This is a Boyer-Moore kind of situation. We want to reset P to - the end of the longest prefix of STRING that is a suffix of - what we've read so far. In the example above, that would be - ".." --- the longest prefix of "..howdy" that is a suffix of - "...". This longest prefix could be the empty string, if C - is nowhere to be found in STRING. - - If this longest prefix is not the empty string, it must contain - C, so let's search from the end of STRING for instances of C, - and see if the portion of STRING before that is a suffix of - what we read before C. Actually, we can search backwards from - p, since we know no prefix can be longer than that. - - Note that we can use STRING itself, along with C, as a record - of what we've received so far. :) */ - int i; - - for (i = (p - string) - 1; i >= 0; i--) - if (string[i] == c) - { - /* Is this prefix a suffix of what we've read so far? - In other words, does - string[0 .. i-1] == string[p - i, p - 1]? */ - if (! memcmp (string, p - i, i)) - { - p = string + i + 1; - break; - } - } - if (i < 0) - p = string; - } - } -} - -/* Search for a regexp. */ - -static int -monitor_expect_regexp (struct re_pattern_buffer *pat, char *buf, int buflen) -{ - char *mybuf; - char *p; - monitor_debug ("MON Expecting regexp\n"); - if (buf) - mybuf = buf; - else - { - mybuf = alloca (TARGET_BUF_SIZE); - buflen = TARGET_BUF_SIZE; - } - - p = mybuf; - while (1) - { - int retval; - - if (p - mybuf >= buflen) - { /* Buffer about to overflow */ - -/* On overflow, we copy the upper half of the buffer to the lower half. Not - great, but it usually works... */ - - memcpy (mybuf, mybuf + buflen / 2, buflen / 2); - p = mybuf + buflen / 2; - } - - *p++ = readchar (timeout); - - retval = re_search (pat, mybuf, p - mybuf, 0, p - mybuf, NULL); - if (retval >= 0) - return 1; - } -} - -/* Keep discarding input until we see the MONITOR 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 monitor_expect_prompt(). Exception: monitor_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 monitor_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. */ - -int -monitor_expect_prompt (char *buf, int buflen) -{ - monitor_debug ("MON Expecting prompt\n"); - return monitor_expect (current_monitor->prompt, buf, buflen); -} - -/* Get N 32-bit words from remote, each preceded by a space, and put - them in registers starting at REGNO. */ - -#if 0 -static unsigned long -get_hex_word (void) -{ - unsigned long val; - int i; - int ch; - - do - ch = readchar (timeout); - while (isspace (ch)); - - val = from_hex (ch); - - for (i = 7; i >= 1; i--) - { - ch = readchar (timeout); - if (!isxdigit (ch)) - break; - val = (val << 4) | from_hex (ch); - } - - return val; -} -#endif - -static void -compile_pattern (char *pattern, struct re_pattern_buffer *compiled_pattern, - char *fastmap) -{ - int tmp; - const char *val; - - compiled_pattern->fastmap = fastmap; - - tmp = re_set_syntax (RE_SYNTAX_EMACS); - val = re_compile_pattern (pattern, - strlen (pattern), - compiled_pattern); - re_set_syntax (tmp); - - if (val) - error ("compile_pattern: Can't compile pattern string `%s': %s!", pattern, val); - - if (fastmap) - re_compile_fastmap (compiled_pattern); -} - -/* Open a connection to a remote debugger. NAME is the filename used - for communication. */ - -void -monitor_open (char *args, struct monitor_ops *mon_ops, int from_tty) -{ - char *name; - char **p; - - if (mon_ops->magic != MONITOR_OPS_MAGIC) - error ("Magic number of monitor_ops struct wrong."); - - targ_ops = mon_ops->target; - name = targ_ops->to_shortname; - - if (!args) - error ("Use `target %s DEVICE-NAME' to use a serial port, or \n\ -`target %s HOST-NAME:PORT-NUMBER' to use a network connection.", name, name); - - target_preopen (from_tty); - - /* Setup pattern for register dump */ - - if (mon_ops->register_pattern) - compile_pattern (mon_ops->register_pattern, ®ister_pattern, - register_fastmap); - - if (mon_ops->getmem.resp_delim) - compile_pattern (mon_ops->getmem.resp_delim, &getmem_resp_delim_pattern, - getmem_resp_delim_fastmap); - - if (mon_ops->setmem.resp_delim) - compile_pattern (mon_ops->setmem.resp_delim, &setmem_resp_delim_pattern, - setmem_resp_delim_fastmap); - - if (mon_ops->setreg.resp_delim) - compile_pattern (mon_ops->setreg.resp_delim, &setreg_resp_delim_pattern, - setreg_resp_delim_fastmap); - - unpush_target (targ_ops); - - if (dev_name) - xfree (dev_name); - dev_name = xstrdup (args); - - monitor_desc = serial_open (dev_name); - - if (!monitor_desc) - perror_with_name (dev_name); - - if (baud_rate != -1) - { - if (serial_setbaudrate (monitor_desc, baud_rate)) - { - serial_close (monitor_desc); - perror_with_name (dev_name); - } - } - - serial_raw (monitor_desc); - - serial_flush_input (monitor_desc); - - /* some systems only work with 2 stop bits */ - - serial_setstopbits (monitor_desc, mon_ops->stopbits); - - current_monitor = mon_ops; - - /* See if we can wake up the monitor. First, try sending a stop sequence, - then send the init strings. Last, remove all breakpoints. */ - - if (current_monitor->stop) - { - monitor_stop (); - if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0) - { - monitor_debug ("EXP Open echo\n"); - monitor_expect_prompt (NULL, 0); - } - } - - /* wake up the monitor and see if it's alive */ - for (p = mon_ops->init; *p != NULL; p++) - { - /* Some of the characters we send may not be echoed, - but we hope to get a prompt at the end of it all. */ - - if ((current_monitor->flags & MO_NO_ECHO_ON_OPEN) == 0) - monitor_printf (*p); - else - monitor_printf_noecho (*p); - monitor_expect_prompt (NULL, 0); - } - - serial_flush_input (monitor_desc); - - /* Alloc breakpoints */ - if (mon_ops->set_break != NULL) - { - if (mon_ops->num_breakpoints == 0) - mon_ops->num_breakpoints = 8; - - breakaddr = (CORE_ADDR *) xmalloc (mon_ops->num_breakpoints * sizeof (CORE_ADDR)); - memset (breakaddr, 0, mon_ops->num_breakpoints * sizeof (CORE_ADDR)); - } - - /* Remove all breakpoints */ - - if (mon_ops->clr_all_break) - { - monitor_printf (mon_ops->clr_all_break); - monitor_expect_prompt (NULL, 0); - } - - if (from_tty) - printf_unfiltered ("Remote target %s connected to %s\n", name, dev_name); - - push_target (targ_ops); - - inferior_ptid = pid_to_ptid (42000); /* Make run command think we are busy... */ - - /* Give monitor_wait something to read */ - - monitor_printf (current_monitor->line_term); - - start_remote (); -} - -/* Close out all files and local state before this target loses - control. */ - -void -monitor_close (int quitting) -{ - if (monitor_desc) - serial_close (monitor_desc); - - /* Free breakpoint memory */ - if (breakaddr != NULL) - { - xfree (breakaddr); - breakaddr = NULL; - } - - monitor_desc = NULL; -} - -/* Terminate the open connection to the remote debugger. Use this - when you want to detach and do something else with your gdb. */ - -static void -monitor_detach (char *args, int from_tty) -{ - pop_target (); /* calls monitor_close to do the real work */ - if (from_tty) - printf_unfiltered ("Ending remote %s debugging\n", target_shortname); -} - -/* Convert VALSTR into the target byte-ordered value of REGNO and store it. */ - -char * -monitor_supply_register (int regno, char *valstr) -{ - ULONGEST val; - unsigned char regbuf[MAX_REGISTER_RAW_SIZE]; - char *p; - - val = 0; - p = valstr; - while (p && *p != '\0') - { - if (*p == '\r' || *p == '\n') - { - while (*p != '\0') - p++; - break; - } - if (isspace (*p)) - { - p++; - continue; - } - if (!isxdigit (*p) && *p != 'x') - { - break; - } - - val <<= 4; - val += fromhex (*p++); - } - monitor_debug ("Supplying Register %d %s\n", regno, valstr); - - if (val == 0 && valstr == p) - error ("monitor_supply_register (%d): bad value from monitor: %s.", - regno, valstr); - - /* supply register stores in target byte order, so swap here */ - - store_unsigned_integer (regbuf, REGISTER_RAW_SIZE (regno), val); - - supply_register (regno, regbuf); - - return p; -} - -/* Tell the remote machine to resume. */ - -static void -monitor_resume (ptid_t ptid, int step, enum target_signal sig) -{ - /* Some monitors require a different command when starting a program */ - monitor_debug ("MON resume\n"); - if (current_monitor->flags & MO_RUN_FIRST_TIME && first_time == 1) - { - first_time = 0; - monitor_printf ("run\r"); - if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT) - dump_reg_flag = 1; - return; - } - if (step) - monitor_printf (current_monitor->step); - else - { - if (current_monitor->continue_hook) - (*current_monitor->continue_hook) (); - else - monitor_printf (current_monitor->cont); - if (current_monitor->flags & MO_NEED_REGDUMP_AFTER_CONT) - dump_reg_flag = 1; - } -} - -/* Parse the output of a register dump command. A monitor specific - regexp is used to extract individual register descriptions of the - form REG=VAL. Each description is split up into a name and a value - string which are passed down to monitor specific code. */ - -static void -parse_register_dump (char *buf, int len) -{ - monitor_debug ("MON Parsing register dump\n"); - while (1) - { - int regnamelen, vallen; - char *regname, *val; - /* Element 0 points to start of register name, and element 1 - points to the start of the register value. */ - struct re_registers register_strings; - - memset (®ister_strings, 0, sizeof (struct re_registers)); - - if (re_search (®ister_pattern, buf, len, 0, len, - ®ister_strings) == -1) - break; - - regnamelen = register_strings.end[1] - register_strings.start[1]; - regname = buf + register_strings.start[1]; - vallen = register_strings.end[2] - register_strings.start[2]; - val = buf + register_strings.start[2]; - - current_monitor->supply_register (regname, regnamelen, val, vallen); - - buf += register_strings.end[0]; - len -= register_strings.end[0]; - } -} - -/* Send ^C to target to halt it. Target will respond, and send us a - packet. */ - -static void -monitor_interrupt (int signo) -{ - /* If this doesn't work, try more severe steps. */ - signal (signo, monitor_interrupt_twice); - - if (monitor_debug_p || remote_debug) - fprintf_unfiltered (gdb_stdlog, "monitor_interrupt called\n"); - - target_stop (); -} - -/* The user typed ^C twice. */ - -static void -monitor_interrupt_twice (int signo) -{ - signal (signo, ofunc); - - monitor_interrupt_query (); - - signal (signo, monitor_interrupt); -} - -/* Ask the user what to do when an interrupt is received. */ - -static void -monitor_interrupt_query (void) -{ - target_terminal_ours (); - - if (query ("Interrupted while waiting for the program.\n\ -Give up (and stop debugging it)? ")) - { - target_mourn_inferior (); - throw_exception (RETURN_QUIT); - } - - target_terminal_inferior (); -} - -static void -monitor_wait_cleanup (void *old_timeout) -{ - timeout = *(int *) old_timeout; - signal (SIGINT, ofunc); - in_monitor_wait = 0; -} - - - -void -monitor_wait_filter (char *buf, - int bufmax, - int *ext_resp_len, - struct target_waitstatus *status -) -{ - int resp_len; - do - { - resp_len = monitor_expect_prompt (buf, bufmax); - *ext_resp_len = resp_len; - - if (resp_len <= 0) - fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf); - } - while (resp_len < 0); - - /* Print any output characters that were preceded by ^O. */ - /* FIXME - This would be great as a user settabgle flag */ - if (monitor_debug_p || remote_debug - || current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT) - { - int i; - - for (i = 0; i < resp_len - 1; i++) - if (buf[i] == 0x0f) - putchar_unfiltered (buf[++i]); - } -} - - - -/* Wait until the remote machine stops, then return, storing status in - status just as `wait' would. */ - -static ptid_t -monitor_wait (ptid_t ptid, struct target_waitstatus *status) -{ - int old_timeout = timeout; - char buf[TARGET_BUF_SIZE]; - int resp_len; - struct cleanup *old_chain; - - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = 0; - - old_chain = make_cleanup (monitor_wait_cleanup, &old_timeout); - monitor_debug ("MON wait\n"); - -#if 0 - /* This is somthing other than a maintenance command */ - in_monitor_wait = 1; - timeout = watchdog > 0 ? watchdog : -1; -#else - timeout = -1; /* Don't time out -- user program is running. */ -#endif - - ofunc = (void (*)()) signal (SIGINT, monitor_interrupt); - - if (current_monitor->wait_filter) - (*current_monitor->wait_filter) (buf, sizeof (buf), &resp_len, status); - else - monitor_wait_filter (buf, sizeof (buf), &resp_len, status); - -#if 0 /* Transferred to monitor wait filter */ - do - { - resp_len = monitor_expect_prompt (buf, sizeof (buf)); - - if (resp_len <= 0) - fprintf_unfiltered (gdb_stderr, "monitor_wait: excessive response from monitor: %s.", buf); - } - while (resp_len < 0); - - /* Print any output characters that were preceded by ^O. */ - /* FIXME - This would be great as a user settabgle flag */ - if (monitor_debug_p || remote_debug - || current_monitor->flags & MO_PRINT_PROGRAM_OUTPUT) - { - int i; - - for (i = 0; i < resp_len - 1; i++) - if (buf[i] == 0x0f) - putchar_unfiltered (buf[++i]); - } -#endif - - signal (SIGINT, ofunc); - - timeout = old_timeout; -#if 0 - if (dump_reg_flag && current_monitor->dump_registers) - { - dump_reg_flag = 0; - monitor_printf (current_monitor->dump_registers); - resp_len = monitor_expect_prompt (buf, sizeof (buf)); - } - - if (current_monitor->register_pattern) - parse_register_dump (buf, resp_len); -#else - monitor_debug ("Wait fetching registers after stop\n"); - monitor_dump_regs (); -#endif - - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_TRAP; - - discard_cleanups (old_chain); - - in_monitor_wait = 0; - - return inferior_ptid; -} - -/* Fetch register REGNO, or all registers if REGNO is -1. Returns - errno value. */ - -static void -monitor_fetch_register (int regno) -{ - char *name; - char *zerobuf; - char *regbuf; - int i; - - regbuf = alloca (MAX_REGISTER_RAW_SIZE * 2 + 1); - zerobuf = alloca (MAX_REGISTER_RAW_SIZE); - memset (zerobuf, 0, MAX_REGISTER_RAW_SIZE); - - name = current_monitor->regnames[regno]; - monitor_debug ("MON fetchreg %d '%s'\n", regno, name ? name : "(null name)"); - - if (!name || (*name == '\0')) - { - monitor_debug ("No register known for %d\n", regno); - supply_register (regno, zerobuf); - return; - } - - /* send the register examine command */ - - monitor_printf (current_monitor->getreg.cmd, name); - - /* If RESP_DELIM is specified, we search for that as a leading - delimiter for the register value. Otherwise, we just start - searching from the start of the buf. */ - - if (current_monitor->getreg.resp_delim) - { - monitor_debug ("EXP getreg.resp_delim\n"); - monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); - /* Handle case of first 32 registers listed in pairs. */ - if (current_monitor->flags & MO_32_REGS_PAIRED - && (regno & 1) != 0 && regno < 32) - { - monitor_debug ("EXP getreg.resp_delim\n"); - monitor_expect (current_monitor->getreg.resp_delim, NULL, 0); - } - } - - /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set */ - if (current_monitor->flags & MO_HEX_PREFIX) - { - int c; - c = readchar (timeout); - while (c == ' ') - c = readchar (timeout); - if ((c == '0') && ((c = readchar (timeout)) == 'x')) - ; - else - error ("Bad value returned from monitor while fetching register %x.", - regno); - } - - /* Read upto the maximum number of hex digits for this register, skipping - spaces, but stop reading if something else is seen. Some monitors - like to drop leading zeros. */ - - for (i = 0; i < REGISTER_RAW_SIZE (regno) * 2; i++) - { - int c; - c = readchar (timeout); - while (c == ' ') - c = readchar (timeout); - - if (!isxdigit (c)) - break; - - regbuf[i] = c; - } - - regbuf[i] = '\000'; /* terminate the number */ - monitor_debug ("REGVAL '%s'\n", regbuf); - - /* If TERM is present, we wait for that to show up. Also, (if TERM - is present), we will send TERM_CMD if that is present. In any - case, we collect all of the output into buf, and then wait for - the normal prompt. */ - - if (current_monitor->getreg.term) - { - monitor_debug ("EXP getreg.term\n"); - monitor_expect (current_monitor->getreg.term, NULL, 0); /* get response */ - } - - if (current_monitor->getreg.term_cmd) - { - monitor_debug ("EMIT getreg.term.cmd\n"); - monitor_printf (current_monitor->getreg.term_cmd); - } - if (!current_monitor->getreg.term || /* Already expected or */ - current_monitor->getreg.term_cmd) /* ack expected */ - monitor_expect_prompt (NULL, 0); /* get response */ - - monitor_supply_register (regno, regbuf); -} - -/* Sometimes, it takes several commands to dump the registers */ -/* This is a primitive for use by variations of monitor interfaces in - case they need to compose the operation. - */ -int -monitor_dump_reg_block (char *block_cmd) -{ - char buf[TARGET_BUF_SIZE]; - int resp_len; - monitor_printf (block_cmd); - resp_len = monitor_expect_prompt (buf, sizeof (buf)); - parse_register_dump (buf, resp_len); - return 1; -} - - -/* Read the remote registers into the block regs. */ -/* Call the specific function if it has been provided */ - -static void -monitor_dump_regs (void) -{ - char buf[TARGET_BUF_SIZE]; - int resp_len; - if (current_monitor->dumpregs) - (*(current_monitor->dumpregs)) (); /* call supplied function */ - else if (current_monitor->dump_registers) /* default version */ - { - monitor_printf (current_monitor->dump_registers); - resp_len = monitor_expect_prompt (buf, sizeof (buf)); - parse_register_dump (buf, resp_len); - } - else - internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Need some way to read registers */ -} - -static void -monitor_fetch_registers (int regno) -{ - monitor_debug ("MON fetchregs\n"); - if (current_monitor->getreg.cmd) - { - if (regno >= 0) - { - monitor_fetch_register (regno); - return; - } - - for (regno = 0; regno < NUM_REGS; regno++) - monitor_fetch_register (regno); - } - else - { - monitor_dump_regs (); - } -} - -/* Store register REGNO, or all if REGNO == 0. Return errno value. */ - -static void -monitor_store_register (int regno) -{ - char *name; - ULONGEST val; - - name = current_monitor->regnames[regno]; - if (!name || (*name == '\0')) - { - monitor_debug ("MON Cannot store unknown register\n"); - return; - } - - val = read_register (regno); - monitor_debug ("MON storeg %d %s\n", regno, - phex (val, REGISTER_RAW_SIZE (regno))); - - /* send the register deposit command */ - - if (current_monitor->flags & MO_REGISTER_VALUE_FIRST) - monitor_printf (current_monitor->setreg.cmd, val, name); - else if (current_monitor->flags & MO_SETREG_INTERACTIVE) - monitor_printf (current_monitor->setreg.cmd, name); - else - monitor_printf (current_monitor->setreg.cmd, name, val); - - if (current_monitor->setreg.resp_delim) - { - monitor_debug ("EXP setreg.resp_delim\n"); - monitor_expect_regexp (&setreg_resp_delim_pattern, NULL, 0); - if (current_monitor->flags & MO_SETREG_INTERACTIVE) - monitor_printf ("%s\r", paddr_nz (val)); - } - if (current_monitor->setreg.term) - { - monitor_debug ("EXP setreg.term\n"); - monitor_expect (current_monitor->setreg.term, NULL, 0); - if (current_monitor->flags & MO_SETREG_INTERACTIVE) - monitor_printf ("%s\r", paddr_nz (val)); - monitor_expect_prompt (NULL, 0); - } - else - monitor_expect_prompt (NULL, 0); - if (current_monitor->setreg.term_cmd) /* Mode exit required */ - { - monitor_debug ("EXP setreg_termcmd\n"); - monitor_printf ("%s", current_monitor->setreg.term_cmd); - monitor_expect_prompt (NULL, 0); - } -} /* monitor_store_register */ - -/* Store the remote registers. */ - -static void -monitor_store_registers (int regno) -{ - if (regno >= 0) - { - monitor_store_register (regno); - return; - } - - for (regno = 0; regno < NUM_REGS; regno++) - monitor_store_register (regno); -} - -/* 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 -monitor_prepare_to_store (void) -{ - /* Do nothing, since we can store individual regs */ -} - -static void -monitor_files_info (struct target_ops *ops) -{ - printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baud_rate); -} - -static int -monitor_write_memory (CORE_ADDR memaddr, char *myaddr, int len) -{ - unsigned int val, hostval; - char *cmd; - int i; - - monitor_debug ("MON write %d %s\n", len, paddr (memaddr)); - - if (current_monitor->flags & MO_ADDR_BITS_REMOVE) - memaddr = ADDR_BITS_REMOVE (memaddr); - - /* Use memory fill command for leading 0 bytes. */ - - if (current_monitor->fill) - { - for (i = 0; i < len; i++) - if (myaddr[i] != 0) - break; - - if (i > 4) /* More than 4 zeros is worth doing */ - { - monitor_debug ("MON FILL %d\n", i); - if (current_monitor->flags & MO_FILL_USES_ADDR) - monitor_printf (current_monitor->fill, memaddr, (memaddr + i) - 1, 0); - else - monitor_printf (current_monitor->fill, memaddr, i, 0); - - monitor_expect_prompt (NULL, 0); - - return i; - } - } - -#if 0 - /* Can't actually use long longs if VAL is an int (nice idea, though). */ - if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->setmem.cmdll) - { - len = 8; - cmd = current_monitor->setmem.cmdll; - } - else -#endif - if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->setmem.cmdl) - { - len = 4; - cmd = current_monitor->setmem.cmdl; - } - else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->setmem.cmdw) - { - len = 2; - cmd = current_monitor->setmem.cmdw; - } - else - { - len = 1; - cmd = current_monitor->setmem.cmdb; - } - - val = extract_unsigned_integer (myaddr, len); - - if (len == 4) - { - hostval = *(unsigned int *) myaddr; - monitor_debug ("Hostval(%08x) val(%08x)\n", hostval, val); - } - - - if (current_monitor->flags & MO_NO_ECHO_ON_SETMEM) - monitor_printf_noecho (cmd, memaddr, val); - else if (current_monitor->flags & MO_SETMEM_INTERACTIVE) - { - - monitor_printf_noecho (cmd, memaddr); - - if (current_monitor->setmem.resp_delim) - { - monitor_debug ("EXP setmem.resp_delim"); - monitor_expect_regexp (&setmem_resp_delim_pattern, NULL, 0); - monitor_printf ("%x\r", val); - } - if (current_monitor->setmem.term) - { - monitor_debug ("EXP setmem.term"); - monitor_expect (current_monitor->setmem.term, NULL, 0); - monitor_printf ("%x\r", val); - } - if (current_monitor->setmem.term_cmd) - { /* Emit this to get out of the memory editing state */ - monitor_printf ("%s", current_monitor->setmem.term_cmd); - /* Drop through to expecting a prompt */ - } - } - else - monitor_printf (cmd, memaddr, val); - - monitor_expect_prompt (NULL, 0); - - return len; -} - - -static int -monitor_write_even_block (CORE_ADDR memaddr, char *myaddr, int len) -{ - unsigned int val; - int written = 0;; - /* Enter the sub mode */ - monitor_printf (current_monitor->setmem.cmdl, memaddr); - monitor_expect_prompt (NULL, 0); - - while (len) - { - val = extract_unsigned_integer (myaddr, 4); /* REALLY */ - monitor_printf ("%x\r", val); - myaddr += 4; - memaddr += 4; - written += 4; - monitor_debug (" @ %s\n", paddr (memaddr)); - /* If we wanted to, here we could validate the address */ - monitor_expect_prompt (NULL, 0); - } - /* Now exit the sub mode */ - monitor_printf (current_monitor->getreg.term_cmd); - monitor_expect_prompt (NULL, 0); - return written; -} - - -static int -monitor_write_memory_bytes (CORE_ADDR memaddr, char *myaddr, int len) -{ - unsigned char val; - int written = 0; - if (len == 0) - return 0; - /* Enter the sub mode */ - monitor_printf (current_monitor->setmem.cmdb, memaddr); - monitor_expect_prompt (NULL, 0); - while (len) - { - val = *myaddr; - monitor_printf ("%x\r", val); - myaddr++; - memaddr++; - written++; - /* If we wanted to, here we could validate the address */ - monitor_expect_prompt (NULL, 0); - len--; - } - /* Now exit the sub mode */ - monitor_printf (current_monitor->getreg.term_cmd); - monitor_expect_prompt (NULL, 0); - return written; -} - - -static void -longlongendswap (unsigned char *a) -{ - int i, j; - unsigned char x; - i = 0; - j = 7; - while (i < 4) - { - x = *(a + i); - *(a + i) = *(a + j); - *(a + j) = x; - i++, j--; - } -} -/* Format 32 chars of long long value, advance the pointer */ -static char *hexlate = "0123456789abcdef"; -static char * -longlong_hexchars (unsigned long long value, - char *outbuff) -{ - if (value == 0) - { - *outbuff++ = '0'; - return outbuff; - } - else - { - static unsigned char disbuf[8]; /* disassembly buffer */ - unsigned char *scan, *limit; /* loop controls */ - unsigned char c, nib; - int leadzero = 1; - scan = disbuf; - limit = scan + 8; - { - unsigned long long *dp; - dp = (unsigned long long *) scan; - *dp = value; - } - longlongendswap (disbuf); /* FIXME: ONly on big endian hosts */ - while (scan < limit) - { - c = *scan++; /* a byte of our long long value */ - if (leadzero) - { - if (c == 0) - continue; - else - leadzero = 0; /* henceforth we print even zeroes */ - } - nib = c >> 4; /* high nibble bits */ - *outbuff++ = hexlate[nib]; - nib = c & 0x0f; /* low nibble bits */ - *outbuff++ = hexlate[nib]; - } - return outbuff; - } -} /* longlong_hexchars */ - - - -/* I am only going to call this when writing virtual byte streams. - Which possably entails endian conversions - */ -static int -monitor_write_memory_longlongs (CORE_ADDR memaddr, char *myaddr, int len) -{ - static char hexstage[20]; /* At least 16 digits required, plus null */ - char *endstring; - long long *llptr; - long long value; - int written = 0; - llptr = (unsigned long long *) myaddr; - if (len == 0) - return 0; - monitor_printf (current_monitor->setmem.cmdll, memaddr); - monitor_expect_prompt (NULL, 0); - while (len >= 8) - { - value = *llptr; - endstring = longlong_hexchars (*llptr, hexstage); - *endstring = '\0'; /* NUll terminate for printf */ - monitor_printf ("%s\r", hexstage); - llptr++; - memaddr += 8; - written += 8; - /* If we wanted to, here we could validate the address */ - monitor_expect_prompt (NULL, 0); - len -= 8; - } - /* Now exit the sub mode */ - monitor_printf (current_monitor->getreg.term_cmd); - monitor_expect_prompt (NULL, 0); - return written; -} /* */ - - - -/* ----- MONITOR_WRITE_MEMORY_BLOCK ---------------------------- */ -/* This is for the large blocks of memory which may occur in downloading. - And for monitors which use interactive entry, - And for monitors which do not have other downloading methods. - Without this, we will end up calling monitor_write_memory many times - and do the entry and exit of the sub mode many times - This currently assumes... - MO_SETMEM_INTERACTIVE - ! MO_NO_ECHO_ON_SETMEM - To use this, the you have to patch the monitor_cmds block with - this function. Otherwise, its not tuned up for use by all - monitor variations. - */ - -static int -monitor_write_memory_block (CORE_ADDR memaddr, char *myaddr, int len) -{ - int written; - written = 0; - /* FIXME: This would be a good place to put the zero test */ -#if 1 - if ((len > 8) && (((len & 0x07)) == 0) && current_monitor->setmem.cmdll) - { - return monitor_write_memory_longlongs (memaddr, myaddr, len); - } -#endif -#if 0 - if (len > 4) - { - int sublen; - written = monitor_write_even_block (memaddr, myaddr, len); - /* Adjust calling parameters by written amount */ - memaddr += written; - myaddr += written; - len -= written; - } -#endif - written = monitor_write_memory_bytes (memaddr, myaddr, len); - return written; -} - -/* This is an alternate form of monitor_read_memory which is used for monitors - which can only read a single byte/word/etc. at a time. */ - -static int -monitor_read_memory_single (CORE_ADDR memaddr, char *myaddr, int len) -{ - unsigned int val; - char membuf[sizeof (int) * 2 + 1]; - char *p; - char *cmd; - - monitor_debug ("MON read single\n"); -#if 0 - /* Can't actually use long longs (nice idea, though). In fact, the - call to strtoul below will fail if it tries to convert a value - that's too big to fit in a long. */ - if ((memaddr & 0x7) == 0 && len >= 8 && current_monitor->getmem.cmdll) - { - len = 8; - cmd = current_monitor->getmem.cmdll; - } - else -#endif - if ((memaddr & 0x3) == 0 && len >= 4 && current_monitor->getmem.cmdl) - { - len = 4; - cmd = current_monitor->getmem.cmdl; - } - else if ((memaddr & 0x1) == 0 && len >= 2 && current_monitor->getmem.cmdw) - { - len = 2; - cmd = current_monitor->getmem.cmdw; - } - else - { - len = 1; - cmd = current_monitor->getmem.cmdb; - } - - /* Send the examine command. */ - - monitor_printf (cmd, memaddr); - - /* If RESP_DELIM is specified, we search for that as a leading - delimiter for the memory value. Otherwise, we just start - searching from the start of the buf. */ - - if (current_monitor->getmem.resp_delim) - { - monitor_debug ("EXP getmem.resp_delim\n"); - monitor_expect_regexp (&getmem_resp_delim_pattern, NULL, 0); - } - - /* Now, read the appropriate number of hex digits for this loc, - skipping spaces. */ - - /* Skip leading spaces and "0x" if MO_HEX_PREFIX flag is set. */ - if (current_monitor->flags & MO_HEX_PREFIX) - { - int c; - - c = readchar (timeout); - while (c == ' ') - c = readchar (timeout); - if ((c == '0') && ((c = readchar (timeout)) == 'x')) - ; - else - monitor_error ("monitor_read_memory_single", - "bad response from monitor", - memaddr, 0, NULL, 0); - } - - { - int i; - for (i = 0; i < len * 2; i++) - { - int c; - - while (1) - { - c = readchar (timeout); - if (isxdigit (c)) - break; - if (c == ' ') - continue; - - monitor_error ("monitor_read_memory_single", - "bad response from monitor", - memaddr, i, membuf, 0); - } - membuf[i] = c; - } - membuf[i] = '\000'; /* terminate the number */ - } - -/* If TERM is present, we wait for that to show up. Also, (if TERM is - present), we will send TERM_CMD if that is present. In any case, we collect - all of the output into buf, and then wait for the normal prompt. */ - - if (current_monitor->getmem.term) - { - monitor_expect (current_monitor->getmem.term, NULL, 0); /* get response */ - - if (current_monitor->getmem.term_cmd) - { - monitor_printf (current_monitor->getmem.term_cmd); - monitor_expect_prompt (NULL, 0); - } - } - else - monitor_expect_prompt (NULL, 0); /* get response */ - - p = membuf; - val = strtoul (membuf, &p, 16); - - if (val == 0 && membuf == p) - monitor_error ("monitor_read_memory_single", - "bad value from monitor", - memaddr, 0, membuf, 0); - - /* supply register stores in target byte order, so swap here */ - - store_unsigned_integer (myaddr, len, val); - - return len; -} - -/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's - memory at MEMADDR. Returns length moved. Currently, we do no more - than 16 bytes at a time. */ - -static int -monitor_read_memory (CORE_ADDR memaddr, char *myaddr, int len) -{ - unsigned int val; - char buf[512]; - char *p, *p1; - int resp_len; - int i; - CORE_ADDR dumpaddr; - - if (len <= 0) - { - monitor_debug ("Zero length call to monitor_read_memory\n"); - return 0; - } - - monitor_debug ("MON read block ta(%s) ha(%lx) %d\n", - paddr_nz (memaddr), (long) myaddr, len); - - if (current_monitor->flags & MO_ADDR_BITS_REMOVE) - memaddr = ADDR_BITS_REMOVE (memaddr); - - if (current_monitor->flags & MO_GETMEM_READ_SINGLE) - return monitor_read_memory_single (memaddr, myaddr, len); - - len = min (len, 16); - - /* Some dumpers align the first data with the preceeding 16 - byte boundary. Some print blanks and start at the - requested boundary. EXACT_DUMPADDR - */ - - dumpaddr = (current_monitor->flags & MO_EXACT_DUMPADDR) - ? memaddr : memaddr & ~0x0f; - - /* See if xfer would cross a 16 byte boundary. If so, clip it. */ - if (((memaddr ^ (memaddr + len - 1)) & ~0xf) != 0) - len = ((memaddr + len) & ~0xf) - memaddr; - - /* send the memory examine command */ - - if (current_monitor->flags & MO_GETMEM_NEEDS_RANGE) - monitor_printf (current_monitor->getmem.cmdb, memaddr, memaddr + len); - else if (current_monitor->flags & MO_GETMEM_16_BOUNDARY) - monitor_printf (current_monitor->getmem.cmdb, dumpaddr); - else - monitor_printf (current_monitor->getmem.cmdb, memaddr, len); - - /* If TERM is present, we wait for that to show up. Also, (if TERM - is present), we will send TERM_CMD if that is present. In any - case, we collect all of the output into buf, and then wait for - the normal prompt. */ - - if (current_monitor->getmem.term) - { - resp_len = monitor_expect (current_monitor->getmem.term, buf, sizeof buf); /* get response */ - - if (resp_len <= 0) - monitor_error ("monitor_read_memory", - "excessive response from monitor", - memaddr, resp_len, buf, 0); - - if (current_monitor->getmem.term_cmd) - { - serial_write (monitor_desc, current_monitor->getmem.term_cmd, - strlen (current_monitor->getmem.term_cmd)); - monitor_expect_prompt (NULL, 0); - } - } - else - resp_len = monitor_expect_prompt (buf, sizeof buf); /* get response */ - - p = buf; - - /* If RESP_DELIM is specified, we search for that as a leading - delimiter for the values. Otherwise, we just start searching - from the start of the buf. */ - - if (current_monitor->getmem.resp_delim) - { - int retval, tmp; - struct re_registers resp_strings; - monitor_debug ("MON getmem.resp_delim %s\n", current_monitor->getmem.resp_delim); - - memset (&resp_strings, 0, sizeof (struct re_registers)); - tmp = strlen (p); - retval = re_search (&getmem_resp_delim_pattern, p, tmp, 0, tmp, - &resp_strings); - - if (retval < 0) - monitor_error ("monitor_read_memory", - "bad response from monitor", - memaddr, resp_len, buf, 0); - - p += resp_strings.end[0]; -#if 0 - p = strstr (p, current_monitor->getmem.resp_delim); - if (!p) - monitor_error ("monitor_read_memory", - "bad response from monitor", - memaddr, resp_len, buf, 0); - p += strlen (current_monitor->getmem.resp_delim); -#endif - } - monitor_debug ("MON scanning %d ,%lx '%s'\n", len, (long) p, p); - if (current_monitor->flags & MO_GETMEM_16_BOUNDARY) - { - char c; - int fetched = 0; - i = len; - c = *p; - - - while (!(c == '\000' || c == '\n' || c == '\r') && i > 0) - { - if (isxdigit (c)) - { - if ((dumpaddr >= memaddr) && (i > 0)) - { - val = fromhex (c) * 16 + fromhex (*(p + 1)); - *myaddr++ = val; - if (monitor_debug_p || remote_debug) - fprintf_unfiltered (gdb_stdlog, "[%02x]", val); - --i; - fetched++; - } - ++dumpaddr; - ++p; - } - ++p; /* skip a blank or other non hex char */ - c = *p; - } - if (fetched == 0) - error ("Failed to read via monitor"); - if (monitor_debug_p || remote_debug) - fprintf_unfiltered (gdb_stdlog, "\n"); - return fetched; /* Return the number of bytes actually read */ - } - monitor_debug ("MON scanning bytes\n"); - - for (i = len; i > 0; i--) - { - /* Skip non-hex chars, but bomb on end of string and newlines */ - - while (1) - { - if (isxdigit (*p)) - break; - - if (*p == '\000' || *p == '\n' || *p == '\r') - monitor_error ("monitor_read_memory", - "badly terminated response from monitor", - memaddr, resp_len, buf, 0); - p++; - } - - val = strtoul (p, &p1, 16); - - if (val == 0 && p == p1) - monitor_error ("monitor_read_memory", - "bad value from monitor", - memaddr, resp_len, buf, 0); - - *myaddr++ = val; - - if (i == 1) - break; - - p = p1; - } - - return len; -} - -/* Transfer LEN bytes between target address MEMADDR and GDB address - MYADDR. Returns 0 for success, errno code for failure. TARGET is - unused. */ - -static int -monitor_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, - struct mem_attrib *attrib, struct target_ops *target) -{ - int res; - - if (write) - { - if (current_monitor->flags & MO_HAS_BLOCKWRITES) - res = monitor_write_memory_block(memaddr, myaddr, len); - else - res = monitor_write_memory(memaddr, myaddr, len); - } - else - { - res = monitor_read_memory(memaddr, myaddr, len); - } - - return res; -} - -static void -monitor_kill (void) -{ - return; /* ignore attempts to kill target system */ -} - -/* All we actually do is set the PC to the start address of exec_bfd, and start - the program at that point. */ - -static void -monitor_create_inferior (char *exec_file, char *args, char **env) -{ - if (args && (*args != '\000')) - error ("Args are not supported by the monitor."); - - first_time = 1; - clear_proceed_status (); - proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0); -} - -/* 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 -monitor_mourn_inferior (void) -{ - unpush_target (targ_ops); - generic_mourn_inferior (); /* Do all the proper things now */ -} - -/* Tell the monitor to add a breakpoint. */ - -static int -monitor_insert_breakpoint (CORE_ADDR addr, char *shadow) -{ - int i; - unsigned char *bp; - int bplen; - - monitor_debug ("MON inst bkpt %s\n", paddr (addr)); - if (current_monitor->set_break == NULL) - error ("No set_break defined for this monitor"); - - if (current_monitor->flags & MO_ADDR_BITS_REMOVE) - addr = ADDR_BITS_REMOVE (addr); - - /* Determine appropriate breakpoint size for this address. */ - bp = memory_breakpoint_from_pc (&addr, &bplen); - - for (i = 0; i < current_monitor->num_breakpoints; i++) - { - if (breakaddr[i] == 0) - { - breakaddr[i] = addr; - monitor_read_memory (addr, shadow, bplen); - monitor_printf (current_monitor->set_break, addr); - monitor_expect_prompt (NULL, 0); - return 0; - } - } - - error ("Too many breakpoints (> %d) for monitor.", current_monitor->num_breakpoints); -} - -/* Tell the monitor to remove a breakpoint. */ - -static int -monitor_remove_breakpoint (CORE_ADDR addr, char *shadow) -{ - int i; - - monitor_debug ("MON rmbkpt %s\n", paddr (addr)); - if (current_monitor->clr_break == NULL) - error ("No clr_break defined for this monitor"); - - if (current_monitor->flags & MO_ADDR_BITS_REMOVE) - addr = ADDR_BITS_REMOVE (addr); - - for (i = 0; i < current_monitor->num_breakpoints; i++) - { - if (breakaddr[i] == addr) - { - breakaddr[i] = 0; - /* some monitors remove breakpoints based on the address */ - if (current_monitor->flags & MO_CLR_BREAK_USES_ADDR) - monitor_printf (current_monitor->clr_break, addr); - else if (current_monitor->flags & MO_CLR_BREAK_1_BASED) - monitor_printf (current_monitor->clr_break, i + 1); - else - monitor_printf (current_monitor->clr_break, i); - monitor_expect_prompt (NULL, 0); - return 0; - } - } - fprintf_unfiltered (gdb_stderr, - "Can't find breakpoint associated with 0x%s\n", - paddr_nz (addr)); - return 1; -} - -/* monitor_wait_srec_ack -- wait for the target to send an acknowledgement for - an S-record. Return non-zero if the ACK is received properly. */ - -static int -monitor_wait_srec_ack (void) -{ - int ch; - - if (current_monitor->flags & MO_SREC_ACK_PLUS) - { - return (readchar (timeout) == '+'); - } - else if (current_monitor->flags & MO_SREC_ACK_ROTATE) - { - /* Eat two backspaces, a "rotating" char (|/-\), and a space. */ - if ((ch = readchar (1)) < 0) - return 0; - if ((ch = readchar (1)) < 0) - return 0; - if ((ch = readchar (1)) < 0) - return 0; - if ((ch = readchar (1)) < 0) - return 0; - } - return 1; -} - -/* monitor_load -- download a file. */ - -static void -monitor_load (char *file, int from_tty) -{ - monitor_debug ("MON load\n"); - - if (current_monitor->load_routine) - current_monitor->load_routine (monitor_desc, file, hashmark); - else - { /* The default is ascii S-records */ - int n; - unsigned long load_offset; - char buf[128]; - - /* enable user to specify address for downloading as 2nd arg to load */ - n = sscanf (file, "%s 0x%lx", buf, &load_offset); - if (n > 1) - file = buf; - else - load_offset = 0; - - monitor_printf (current_monitor->load); - if (current_monitor->loadresp) - monitor_expect (current_monitor->loadresp, NULL, 0); - - load_srec (monitor_desc, file, (bfd_vma) load_offset, - 32, SREC_ALL, hashmark, - current_monitor->flags & MO_SREC_ACK ? - monitor_wait_srec_ack : NULL); - - monitor_expect_prompt (NULL, 0); - } - - /* Finally, make the PC point at the start address */ - if (exec_bfd) - write_pc (bfd_get_start_address (exec_bfd)); - - /* There used to be code here which would clear inferior_ptid and - call clear_symtab_users. None of that should be necessary: - monitor targets should behave like remote protocol targets, and - since generic_load does none of those things, this function - shouldn't either. - - Furthermore, clearing inferior_ptid is *incorrect*. After doing - a load, we still have a valid connection to the monitor, with a - live processor state to fiddle with. The user can type - `continue' or `jump *start' and make the program run. If they do - these things, however, GDB will be talking to a running program - while inferior_ptid is null_ptid; this makes things like - reinit_frame_cache very confused. */ -} - -static void -monitor_stop (void) -{ - monitor_debug ("MON stop\n"); - if ((current_monitor->flags & MO_SEND_BREAK_ON_STOP) != 0) - serial_send_break (monitor_desc); - if (current_monitor->stop) - monitor_printf_noecho (current_monitor->stop); -} - -/* Put a COMMAND string out to MONITOR. Output from MONITOR is placed - in OUTPUT until the prompt is seen. FIXME: We read the characters - ourseleves here cause of a nasty echo. */ - -static void -monitor_rcmd (char *command, - struct ui_file *outbuf) -{ - char *p; - int resp_len; - char buf[1000]; - - if (monitor_desc == NULL) - error ("monitor target not open."); - - p = current_monitor->prompt; - - /* Send the command. Note that if no args were supplied, then we're - just sending the monitor a newline, which is sometimes useful. */ - - monitor_printf ("%s\r", (command ? command : "")); - - resp_len = monitor_expect_prompt (buf, sizeof buf); - - fputs_unfiltered (buf, outbuf); /* Output the response */ -} - -/* Convert hex digit A to a number. */ - -#if 0 -static int -from_hex (int a) -{ - if (a >= '0' && a <= '9') - return a - '0'; - if (a >= 'a' && a <= 'f') - return a - 'a' + 10; - if (a >= 'A' && a <= 'F') - return a - 'A' + 10; - - error ("Reply contains invalid hex digit 0x%x", a); -} -#endif - -char * -monitor_get_dev_name (void) -{ - return dev_name; -} - -static struct target_ops monitor_ops; - -static void -init_base_monitor_ops (void) -{ - monitor_ops.to_shortname = NULL; - monitor_ops.to_longname = NULL; - monitor_ops.to_doc = NULL; - monitor_ops.to_open = NULL; - monitor_ops.to_close = monitor_close; - monitor_ops.to_attach = NULL; - monitor_ops.to_post_attach = NULL; - monitor_ops.to_require_attach = NULL; - monitor_ops.to_detach = monitor_detach; - monitor_ops.to_require_detach = NULL; - monitor_ops.to_resume = monitor_resume; - monitor_ops.to_wait = monitor_wait; - monitor_ops.to_post_wait = NULL; - monitor_ops.to_fetch_registers = monitor_fetch_registers; - monitor_ops.to_store_registers = monitor_store_registers; - monitor_ops.to_prepare_to_store = monitor_prepare_to_store; - monitor_ops.to_xfer_memory = monitor_xfer_memory; - monitor_ops.to_files_info = monitor_files_info; - monitor_ops.to_insert_breakpoint = monitor_insert_breakpoint; - monitor_ops.to_remove_breakpoint = monitor_remove_breakpoint; - monitor_ops.to_terminal_init = 0; - monitor_ops.to_terminal_inferior = 0; - monitor_ops.to_terminal_ours_for_output = 0; - monitor_ops.to_terminal_ours = 0; - monitor_ops.to_terminal_info = 0; - monitor_ops.to_kill = monitor_kill; - monitor_ops.to_load = monitor_load; - monitor_ops.to_lookup_symbol = 0; - monitor_ops.to_create_inferior = monitor_create_inferior; - monitor_ops.to_post_startup_inferior = NULL; - monitor_ops.to_acknowledge_created_inferior = NULL; - monitor_ops.to_clone_and_follow_inferior = NULL; - monitor_ops.to_post_follow_inferior_by_clone = NULL; - monitor_ops.to_insert_fork_catchpoint = NULL; - monitor_ops.to_remove_fork_catchpoint = NULL; - monitor_ops.to_insert_vfork_catchpoint = NULL; - monitor_ops.to_remove_vfork_catchpoint = NULL; - monitor_ops.to_has_forked = NULL; - monitor_ops.to_has_vforked = NULL; - monitor_ops.to_can_follow_vfork_prior_to_exec = NULL; - monitor_ops.to_post_follow_vfork = NULL; - monitor_ops.to_insert_exec_catchpoint = NULL; - monitor_ops.to_remove_exec_catchpoint = NULL; - monitor_ops.to_has_execd = NULL; - monitor_ops.to_reported_exec_events_per_exec_call = NULL; - monitor_ops.to_has_exited = NULL; - monitor_ops.to_mourn_inferior = monitor_mourn_inferior; - monitor_ops.to_can_run = 0; - monitor_ops.to_notice_signals = 0; - monitor_ops.to_thread_alive = 0; - monitor_ops.to_stop = monitor_stop; - monitor_ops.to_rcmd = monitor_rcmd; - monitor_ops.to_pid_to_exec_file = NULL; - monitor_ops.to_stratum = process_stratum; - monitor_ops.DONT_USE = 0; - monitor_ops.to_has_all_memory = 1; - monitor_ops.to_has_memory = 1; - monitor_ops.to_has_stack = 1; - monitor_ops.to_has_registers = 1; - monitor_ops.to_has_execution = 1; - monitor_ops.to_sections = 0; - monitor_ops.to_sections_end = 0; - monitor_ops.to_magic = OPS_MAGIC; -} /* init_base_monitor_ops */ - -/* Init the target_ops structure pointed at by OPS */ - -void -init_monitor_ops (struct target_ops *ops) -{ - if (monitor_ops.to_magic != OPS_MAGIC) - init_base_monitor_ops (); - - memcpy (ops, &monitor_ops, sizeof monitor_ops); -} - -/* Define additional commands that are usually only used by monitors. */ - -void -_initialize_remote_monitors (void) -{ - init_base_monitor_ops (); - add_show_from_set (add_set_cmd ("hash", no_class, var_boolean, - (char *) &hashmark, - "Set display of activity while downloading a file.\n\ -When enabled, a hashmark \'#\' is displayed.", - &setlist), - &showlist); - - add_show_from_set - (add_set_cmd ("monitor", no_class, var_zinteger, - (char *) &monitor_debug_p, - "Set debugging of remote monitor communication.\n\ -When enabled, communication between GDB and the remote monitor\n\ -is displayed.", &setdebuglist), - &showdebuglist); -} diff --git a/contrib/gdb/gdb/monitor.h b/contrib/gdb/gdb/monitor.h deleted file mode 100644 index 85a44ff..0000000 --- a/contrib/gdb/gdb/monitor.h +++ /dev/null @@ -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 diff --git a/contrib/gdb/gdb/osfsolib.c b/contrib/gdb/gdb/osfsolib.c deleted file mode 100644 index 345ab08..0000000 --- a/contrib/gdb/gdb/osfsolib.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/ppcbug-rom.c b/contrib/gdb/gdb/ppcbug-rom.c deleted file mode 100644 index 712af06..0000000 --- a/contrib/gdb/gdb/ppcbug-rom.c +++ /dev/null @@ -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); -} diff --git a/contrib/gdb/gdb/procfs.c b/contrib/gdb/gdb/procfs.c deleted file mode 100644 index 55e0496..0000000 --- a/contrib/gdb/gdb/procfs.c +++ /dev/null @@ -1,5857 +0,0 @@ -/* Machine independent support for SVR4 /proc (process file system) for GDB. - Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - Written by Michael Snyder at Cygnus Solutions. - Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others. - -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 "elf-bfd.h" /* for elfcore_write_* */ -#include "gdbcmd.h" -#include "gdbthread.h" - -#if defined (NEW_PROC_API) -#define _STRUCTURED_PROC 1 /* Should be done by configure script. */ -#endif - -#include <sys/procfs.h> -#ifdef HAVE_SYS_FAULT_H -#include <sys/fault.h> -#endif -#ifdef HAVE_SYS_SYSCALL_H -#include <sys/syscall.h> -#endif -#include <sys/errno.h> -#include <sys/wait.h> -#include <signal.h> -#include <ctype.h> - -/* - * PROCFS.C - * - * This module provides the interface between GDB and the - * /proc file system, which is used on many versions of Unix - * as a means for debuggers to control other processes. - * Examples of the systems that use this interface are: - * Irix - * Solaris - * OSF - * Unixware - * AIX5 - * - * /proc works by imitating a file system: you open a simulated file - * that represents the process you wish to interact with, and - * perform operations on that "file" in order to examine or change - * the state of the other process. - * - * The most important thing to know about /proc and this module - * is that there are two very different interfaces to /proc: - * One that uses the ioctl system call, and - * another that uses read and write system calls. - * This module has to support both /proc interfaces. This means - * that there are two different ways of doing every basic operation. - * - * In order to keep most of the code simple and clean, I have - * defined an interface "layer" which hides all these system calls. - * An ifdef (NEW_PROC_API) determines which interface we are using, - * and most or all occurrances of this ifdef should be confined to - * this interface layer. - */ - - -/* Determine which /proc API we are using: - The ioctl API defines PIOCSTATUS, while - the read/write (multiple fd) API never does. */ - -#ifdef NEW_PROC_API -#include <sys/types.h> -#include "gdb_dirent.h" /* opendir/readdir, for listing the LWP's */ -#endif - -#include <fcntl.h> /* for O_RDONLY */ -#include <unistd.h> /* for "X_OK" */ -#include "gdb_stat.h" /* for struct stat */ - -/* Note: procfs-utils.h must be included after the above system header - files, because it redefines various system calls using macros. - This may be incompatible with the prototype declarations. */ - -#include "proc-utils.h" - -/* Prototypes for supply_gregset etc. */ -#include "gregset.h" - -/* =================== TARGET_OPS "MODULE" =================== */ - -/* - * This module defines the GDB target vector and its methods. - */ - -static void procfs_open (char *, int); -static void procfs_attach (char *, int); -static void procfs_detach (char *, int); -static void procfs_resume (ptid_t, int, enum target_signal); -static int procfs_can_run (void); -static void procfs_stop (void); -static void procfs_files_info (struct target_ops *); -static void procfs_fetch_registers (int); -static void procfs_store_registers (int); -static void procfs_notice_signals (ptid_t); -static void procfs_prepare_to_store (void); -static void procfs_kill_inferior (void); -static void procfs_mourn_inferior (void); -static void procfs_create_inferior (char *, char *, char **); -static ptid_t procfs_wait (ptid_t, struct target_waitstatus *); -static int procfs_xfer_memory (CORE_ADDR, char *, int, int, - struct mem_attrib *attrib, - struct target_ops *); - -static int procfs_thread_alive (ptid_t); - -void procfs_find_new_threads (void); -char *procfs_pid_to_str (ptid_t); - -static int proc_find_memory_regions (int (*) (CORE_ADDR, - unsigned long, - int, int, int, - void *), - void *); - -static char * procfs_make_note_section (bfd *, int *); - -struct target_ops procfs_ops; /* the target vector */ - -static void -init_procfs_ops (void) -{ - procfs_ops.to_shortname = "procfs"; - procfs_ops.to_longname = "Unix /proc child process"; - procfs_ops.to_doc = - "Unix /proc child process (started by the \"run\" command)."; - procfs_ops.to_open = procfs_open; - procfs_ops.to_can_run = procfs_can_run; - procfs_ops.to_create_inferior = procfs_create_inferior; - procfs_ops.to_kill = procfs_kill_inferior; - procfs_ops.to_mourn_inferior = procfs_mourn_inferior; - procfs_ops.to_attach = procfs_attach; - procfs_ops.to_detach = procfs_detach; - procfs_ops.to_wait = procfs_wait; - procfs_ops.to_resume = procfs_resume; - procfs_ops.to_prepare_to_store = procfs_prepare_to_store; - procfs_ops.to_fetch_registers = procfs_fetch_registers; - procfs_ops.to_store_registers = procfs_store_registers; - procfs_ops.to_xfer_memory = procfs_xfer_memory; - procfs_ops.to_insert_breakpoint = memory_insert_breakpoint; - procfs_ops.to_remove_breakpoint = memory_remove_breakpoint; - procfs_ops.to_notice_signals = procfs_notice_signals; - procfs_ops.to_files_info = procfs_files_info; - procfs_ops.to_stop = procfs_stop; - - procfs_ops.to_terminal_init = terminal_init_inferior; - procfs_ops.to_terminal_inferior = terminal_inferior; - procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output; - procfs_ops.to_terminal_ours = terminal_ours; - procfs_ops.to_terminal_info = child_terminal_info; - - procfs_ops.to_find_new_threads = procfs_find_new_threads; - procfs_ops.to_thread_alive = procfs_thread_alive; - procfs_ops.to_pid_to_str = procfs_pid_to_str; - - procfs_ops.to_has_all_memory = 1; - procfs_ops.to_has_memory = 1; - procfs_ops.to_has_execution = 1; - procfs_ops.to_has_stack = 1; - procfs_ops.to_has_registers = 1; - procfs_ops.to_stratum = process_stratum; - procfs_ops.to_has_thread_control = tc_schedlock; - procfs_ops.to_find_memory_regions = proc_find_memory_regions; - procfs_ops.to_make_corefile_notes = procfs_make_note_section; - procfs_ops.to_magic = OPS_MAGIC; -} - -/* =================== END, TARGET_OPS "MODULE" =================== */ - -/* - * World Unification: - * - * Put any typedefs, defines etc. here that are required for - * the unification of code that handles different versions of /proc. - */ - -#ifdef NEW_PROC_API /* Solaris 7 && 8 method for watchpoints */ -#ifdef WA_READ - enum { READ_WATCHFLAG = WA_READ, - WRITE_WATCHFLAG = WA_WRITE, - EXEC_WATCHFLAG = WA_EXEC, - AFTER_WATCHFLAG = WA_TRAPAFTER - }; -#endif -#else /* Irix method for watchpoints */ - enum { READ_WATCHFLAG = MA_READ, - WRITE_WATCHFLAG = MA_WRITE, - EXEC_WATCHFLAG = MA_EXEC, - AFTER_WATCHFLAG = 0 /* trapafter not implemented */ - }; -#endif - -/* gdb_sigset_t */ -#ifdef HAVE_PR_SIGSET_T -typedef pr_sigset_t gdb_sigset_t; -#else -typedef sigset_t gdb_sigset_t; -#endif - -/* sigaction */ -#ifdef HAVE_PR_SIGACTION64_T -typedef pr_sigaction64_t gdb_sigaction_t; -#else -typedef struct sigaction gdb_sigaction_t; -#endif - -/* siginfo */ -#ifdef HAVE_PR_SIGINFO64_T -typedef pr_siginfo64_t gdb_siginfo_t; -#else -typedef struct siginfo gdb_siginfo_t; -#endif - -/* gdb_premptysysset */ -#ifdef premptysysset -#define gdb_premptysysset premptysysset -#else -#define gdb_premptysysset premptyset -#endif - -/* praddsysset */ -#ifdef praddsysset -#define gdb_praddsysset praddsysset -#else -#define gdb_praddsysset praddset -#endif - -/* prdelsysset */ -#ifdef prdelsysset -#define gdb_prdelsysset prdelsysset -#else -#define gdb_prdelsysset prdelset -#endif - -/* prissyssetmember */ -#ifdef prissyssetmember -#define gdb_pr_issyssetmember prissyssetmember -#else -#define gdb_pr_issyssetmember prismember -#endif - -/* As a feature test, saying ``#if HAVE_PRSYSENT_T'' everywhere isn't - as intuitively descriptive as it could be, so we'll define - DYNAMIC_SYSCALLS to mean the same thing. Anyway, at the time of - this writing, this feature is only found on AIX5 systems and - basically means that the set of syscalls is not fixed. I.e, - there's no nice table that one can #include to get all of the - syscall numbers. Instead, they're stored in /proc/PID/sysent - for each process. We are at least guaranteed that they won't - change over the lifetime of the process. But each process could - (in theory) have different syscall numbers. -*/ -#ifdef HAVE_PRSYSENT_T -#define DYNAMIC_SYSCALLS -#endif - - - -/* =================== STRUCT PROCINFO "MODULE" =================== */ - - /* FIXME: this comment will soon be out of date W.R.T. threads. */ - -/* The procinfo struct is a wrapper to hold all the state information - concerning a /proc process. There should be exactly one procinfo - for each process, and since GDB currently can debug only one - process at a time, that means there should be only one procinfo. - All of the LWP's of a process can be accessed indirectly thru the - single process procinfo. - - However, against the day when GDB may debug more than one process, - this data structure is kept in a list (which for now will hold no - more than one member), and many functions will have a pointer to a - procinfo as an argument. - - There will be a separate procinfo structure for use by the (not yet - implemented) "info proc" command, so that we can print useful - information about any random process without interfering with the - inferior's procinfo information. */ - -#ifdef NEW_PROC_API -/* format strings for /proc paths */ -# ifndef CTL_PROC_NAME_FMT -# define MAIN_PROC_NAME_FMT "/proc/%d" -# define CTL_PROC_NAME_FMT "/proc/%d/ctl" -# define AS_PROC_NAME_FMT "/proc/%d/as" -# define MAP_PROC_NAME_FMT "/proc/%d/map" -# define STATUS_PROC_NAME_FMT "/proc/%d/status" -# define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/8096/lstatus") -# endif -/* the name of the proc status struct depends on the implementation */ -typedef pstatus_t gdb_prstatus_t; -typedef lwpstatus_t gdb_lwpstatus_t; -#else /* ! NEW_PROC_API */ -/* format strings for /proc paths */ -# ifndef CTL_PROC_NAME_FMT -# define MAIN_PROC_NAME_FMT "/proc/%05d" -# define CTL_PROC_NAME_FMT "/proc/%05d" -# define AS_PROC_NAME_FMT "/proc/%05d" -# define MAP_PROC_NAME_FMT "/proc/%05d" -# define STATUS_PROC_NAME_FMT "/proc/%05d" -# define MAX_PROC_NAME_SIZE sizeof("/proc/ttttppppp") -# endif -/* the name of the proc status struct depends on the implementation */ -typedef prstatus_t gdb_prstatus_t; -typedef prstatus_t gdb_lwpstatus_t; -#endif /* NEW_PROC_API */ - -typedef struct procinfo { - struct procinfo *next; - int pid; /* Process ID */ - int tid; /* Thread/LWP id */ - - /* process state */ - int was_stopped; - int ignore_next_sigstop; - - /* The following four fd fields may be identical, or may contain - several different fd's, depending on the version of /proc - (old ioctl or new read/write). */ - - int ctl_fd; /* File descriptor for /proc control file */ - /* - * The next three file descriptors are actually only needed in the - * read/write, multiple-file-descriptor implemenation (NEW_PROC_API). - * However, to avoid a bunch of #ifdefs in the code, we will use - * them uniformly by (in the case of the ioctl single-file-descriptor - * implementation) filling them with copies of the control fd. - */ - int status_fd; /* File descriptor for /proc status file */ - int as_fd; /* File descriptor for /proc as file */ - - char pathname[MAX_PROC_NAME_SIZE]; /* Pathname to /proc entry */ - - fltset_t saved_fltset; /* Saved traced hardware fault set */ - gdb_sigset_t saved_sigset; /* Saved traced signal set */ - gdb_sigset_t saved_sighold; /* Saved held signal set */ - sysset_t *saved_exitset; /* Saved traced system call exit set */ - sysset_t *saved_entryset; /* Saved traced system call entry set */ - - gdb_prstatus_t prstatus; /* Current process status info */ - -#ifndef NEW_PROC_API - gdb_fpregset_t fpregset; /* Current floating point registers */ -#endif - -#ifdef DYNAMIC_SYSCALLS - int num_syscalls; /* Total number of syscalls */ - char **syscall_names; /* Syscall number to name map */ -#endif - - struct procinfo *thread_list; - - int status_valid : 1; - int gregs_valid : 1; - int fpregs_valid : 1; - int threads_valid: 1; -} procinfo; - -static char errmsg[128]; /* shared error msg buffer */ - -/* Function prototypes for procinfo module: */ - -static procinfo *find_procinfo_or_die (int pid, int tid); -static procinfo *find_procinfo (int pid, int tid); -static procinfo *create_procinfo (int pid, int tid); -static void destroy_procinfo (procinfo * p); -static void do_destroy_procinfo_cleanup (void *); -static void dead_procinfo (procinfo * p, char *msg, int killp); -static int open_procinfo_files (procinfo * p, int which); -static void close_procinfo_files (procinfo * p); -static int sysset_t_size (procinfo *p); -static sysset_t *sysset_t_alloc (procinfo * pi); -#ifdef DYNAMIC_SYSCALLS -static void load_syscalls (procinfo *pi); -static void free_syscalls (procinfo *pi); -static int find_syscall (procinfo *pi, char *name); -#endif /* DYNAMIC_SYSCALLS */ - -/* The head of the procinfo list: */ -static procinfo * procinfo_list; - -/* - * Function: find_procinfo - * - * Search the procinfo list. - * - * Returns: pointer to procinfo, or NULL if not found. - */ - -static procinfo * -find_procinfo (int pid, int tid) -{ - procinfo *pi; - - for (pi = procinfo_list; pi; pi = pi->next) - if (pi->pid == pid) - break; - - if (pi) - if (tid) - { - /* Don't check threads_valid. If we're updating the - thread_list, we want to find whatever threads are already - here. This means that in general it is the caller's - responsibility to check threads_valid and update before - calling find_procinfo, if the caller wants to find a new - thread. */ - - for (pi = pi->thread_list; pi; pi = pi->next) - if (pi->tid == tid) - break; - } - - return pi; -} - -/* - * Function: find_procinfo_or_die - * - * Calls find_procinfo, but errors on failure. - */ - -static procinfo * -find_procinfo_or_die (int pid, int tid) -{ - procinfo *pi = find_procinfo (pid, tid); - - if (pi == NULL) - { - if (tid) - error ("procfs: couldn't find pid %d (kernel thread %d) in procinfo list.", - pid, tid); - else - error ("procfs: couldn't find pid %d in procinfo list.", pid); - } - return pi; -} - -/* open_with_retry() is a wrapper for open(). The appropriate - open() call is attempted; if unsuccessful, it will be retried as - many times as needed for the EAGAIN and EINTR conditions. - - For other conditions, open_with_retry() will retry the open() a - limited number of times. In addition, a short sleep is imposed - prior to retrying the open(). The reason for this sleep is to give - the kernel a chance to catch up and create the file in question in - the event that GDB "wins" the race to open a file before the kernel - has created it. */ - -static int -open_with_retry (const char *pathname, int flags) -{ - int retries_remaining, status; - - retries_remaining = 2; - - while (1) - { - status = open (pathname, flags); - - if (status >= 0 || retries_remaining == 0) - break; - else if (errno != EINTR && errno != EAGAIN) - { - retries_remaining--; - sleep (1); - } - } - - return status; -} - -/* - * Function: open_procinfo_files - * - * Open the file descriptor for the process or LWP. - * ifdef NEW_PROC_API, we only open the control file descriptor; - * the others are opened lazily as needed. - * else (if not NEW_PROC_API), there is only one real - * file descriptor, but we keep multiple copies of it so that - * the code that uses them does not have to be #ifdef'd. - * - * Return: file descriptor, or zero for failure. - */ - -enum { FD_CTL, FD_STATUS, FD_AS }; - -static int -open_procinfo_files (procinfo *pi, int which) -{ -#ifdef NEW_PROC_API - char tmp[MAX_PROC_NAME_SIZE]; -#endif - int fd; - - /* - * This function is getting ALMOST long enough to break up into several. - * Here is some rationale: - * - * NEW_PROC_API (Solaris 2.6, Solaris 2.7, Unixware): - * There are several file descriptors that may need to be open - * for any given process or LWP. The ones we're intereted in are: - * - control (ctl) write-only change the state - * - status (status) read-only query the state - * - address space (as) read/write access memory - * - map (map) read-only virtual addr map - * Most of these are opened lazily as they are needed. - * The pathnames for the 'files' for an LWP look slightly - * different from those of a first-class process: - * Pathnames for a process (<proc-id>): - * /proc/<proc-id>/ctl - * /proc/<proc-id>/status - * /proc/<proc-id>/as - * /proc/<proc-id>/map - * Pathnames for an LWP (lwp-id): - * /proc/<proc-id>/lwp/<lwp-id>/lwpctl - * /proc/<proc-id>/lwp/<lwp-id>/lwpstatus - * An LWP has no map or address space file descriptor, since - * the memory map and address space are shared by all LWPs. - * - * Everyone else (Solaris 2.5, Irix, OSF) - * There is only one file descriptor for each process or LWP. - * For convenience, we copy the same file descriptor into all - * three fields of the procinfo struct (ctl_fd, status_fd, and - * as_fd, see NEW_PROC_API above) so that code that uses them - * doesn't need any #ifdef's. - * Pathname for all: - * /proc/<proc-id> - * - * Solaris 2.5 LWP's: - * Each LWP has an independent file descriptor, but these - * are not obtained via the 'open' system call like the rest: - * instead, they're obtained thru an ioctl call (PIOCOPENLWP) - * to the file descriptor of the parent process. - * - * OSF threads: - * These do not even have their own independent file descriptor. - * All operations are carried out on the file descriptor of the - * parent process. Therefore we just call open again for each - * thread, getting a new handle for the same 'file'. - */ - -#ifdef NEW_PROC_API - /* - * In this case, there are several different file descriptors that - * we might be asked to open. The control file descriptor will be - * opened early, but the others will be opened lazily as they are - * needed. - */ - - strcpy (tmp, pi->pathname); - switch (which) { /* which file descriptor to open? */ - case FD_CTL: - if (pi->tid) - strcat (tmp, "/lwpctl"); - else - strcat (tmp, "/ctl"); - fd = open_with_retry (tmp, O_WRONLY); - if (fd <= 0) - return 0; /* fail */ - pi->ctl_fd = fd; - break; - case FD_AS: - if (pi->tid) - return 0; /* there is no 'as' file descriptor for an lwp */ - strcat (tmp, "/as"); - fd = open_with_retry (tmp, O_RDWR); - if (fd <= 0) - return 0; /* fail */ - pi->as_fd = fd; - break; - case FD_STATUS: - if (pi->tid) - strcat (tmp, "/lwpstatus"); - else - strcat (tmp, "/status"); - fd = open_with_retry (tmp, O_RDONLY); - if (fd <= 0) - return 0; /* fail */ - pi->status_fd = fd; - break; - default: - return 0; /* unknown file descriptor */ - } -#else /* not NEW_PROC_API */ - /* - * In this case, there is only one file descriptor for each procinfo - * (ie. each process or LWP). In fact, only the file descriptor for - * the process can actually be opened by an 'open' system call. - * The ones for the LWPs have to be obtained thru an IOCTL call - * on the process's file descriptor. - * - * For convenience, we copy each procinfo's single file descriptor - * into all of the fields occupied by the several file descriptors - * of the NEW_PROC_API implementation. That way, the code that uses - * them can be written without ifdefs. - */ - - -#ifdef PIOCTSTATUS /* OSF */ - /* Only one FD; just open it. */ - if ((fd = open_with_retry (pi->pathname, O_RDWR)) == 0) - return 0; -#else /* Sol 2.5, Irix, other? */ - if (pi->tid == 0) /* Master procinfo for the process */ - { - fd = open_with_retry (pi->pathname, O_RDWR); - if (fd <= 0) - return 0; /* fail */ - } - else /* LWP thread procinfo */ - { -#ifdef PIOCOPENLWP /* Sol 2.5, thread/LWP */ - procinfo *process; - int lwpid = pi->tid; - - /* Find the procinfo for the entire process. */ - if ((process = find_procinfo (pi->pid, 0)) == NULL) - return 0; /* fail */ - - /* Now obtain the file descriptor for the LWP. */ - if ((fd = ioctl (process->ctl_fd, PIOCOPENLWP, &lwpid)) <= 0) - return 0; /* fail */ -#else /* Irix, other? */ - return 0; /* Don't know how to open threads */ -#endif /* Sol 2.5 PIOCOPENLWP */ - } -#endif /* OSF PIOCTSTATUS */ - pi->ctl_fd = pi->as_fd = pi->status_fd = fd; -#endif /* NEW_PROC_API */ - - return 1; /* success */ -} - -/* - * Function: create_procinfo - * - * Allocate a data structure and link it into the procinfo list. - * (First tries to find a pre-existing one (FIXME: why?) - * - * Return: pointer to new procinfo struct. - */ - -static procinfo * -create_procinfo (int pid, int tid) -{ - procinfo *pi, *parent; - - if ((pi = find_procinfo (pid, tid))) - return pi; /* Already exists, nothing to do. */ - - /* find parent before doing malloc, to save having to cleanup */ - if (tid != 0) - parent = find_procinfo_or_die (pid, 0); /* FIXME: should I - create it if it - doesn't exist yet? */ - - pi = (procinfo *) xmalloc (sizeof (procinfo)); - memset (pi, 0, sizeof (procinfo)); - pi->pid = pid; - pi->tid = tid; - -#ifdef DYNAMIC_SYSCALLS - load_syscalls (pi); -#endif - - pi->saved_entryset = sysset_t_alloc (pi); - pi->saved_exitset = sysset_t_alloc (pi); - - /* Chain into list. */ - if (tid == 0) - { - sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid); - pi->next = procinfo_list; - procinfo_list = pi; - } - else - { -#ifdef NEW_PROC_API - sprintf (pi->pathname, "/proc/%05d/lwp/%d", pid, tid); -#else - sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid); -#endif - pi->next = parent->thread_list; - parent->thread_list = pi; - } - return pi; -} - -/* - * Function: close_procinfo_files - * - * Close all file descriptors associated with the procinfo - */ - -static void -close_procinfo_files (procinfo *pi) -{ - if (pi->ctl_fd > 0) - close (pi->ctl_fd); -#ifdef NEW_PROC_API - if (pi->as_fd > 0) - close (pi->as_fd); - if (pi->status_fd > 0) - close (pi->status_fd); -#endif - pi->ctl_fd = pi->as_fd = pi->status_fd = 0; -} - -/* - * Function: destroy_procinfo - * - * Destructor function. Close, unlink and deallocate the object. - */ - -static void -destroy_one_procinfo (procinfo **list, procinfo *pi) -{ - procinfo *ptr; - - /* Step one: unlink the procinfo from its list */ - if (pi == *list) - *list = pi->next; - else - for (ptr = *list; ptr; ptr = ptr->next) - if (ptr->next == pi) - { - ptr->next = pi->next; - break; - } - - /* Step two: close any open file descriptors */ - close_procinfo_files (pi); - - /* Step three: free the memory. */ -#ifdef DYNAMIC_SYSCALLS - free_syscalls (pi); -#endif - xfree (pi->saved_entryset); - xfree (pi->saved_exitset); - xfree (pi); -} - -static void -destroy_procinfo (procinfo *pi) -{ - procinfo *tmp; - - if (pi->tid != 0) /* destroy a thread procinfo */ - { - tmp = find_procinfo (pi->pid, 0); /* find the parent process */ - destroy_one_procinfo (&tmp->thread_list, pi); - } - else /* destroy a process procinfo and all its threads */ - { - /* First destroy the children, if any; */ - while (pi->thread_list != NULL) - destroy_one_procinfo (&pi->thread_list, pi->thread_list); - /* Then destroy the parent. Genocide!!! */ - destroy_one_procinfo (&procinfo_list, pi); - } -} - -static void -do_destroy_procinfo_cleanup (void *pi) -{ - destroy_procinfo (pi); -} - -enum { NOKILL, KILL }; - -/* - * Function: dead_procinfo - * - * To be called on a non_recoverable error for a procinfo. - * Prints error messages, optionally sends a SIGKILL to the process, - * then destroys the data structure. - */ - -static void -dead_procinfo (procinfo *pi, char *msg, int kill_p) -{ - char procfile[80]; - - if (pi->pathname) - { - print_sys_errmsg (pi->pathname, errno); - } - else - { - sprintf (procfile, "process %d", pi->pid); - print_sys_errmsg (procfile, errno); - } - if (kill_p == KILL) - kill (pi->pid, SIGKILL); - - destroy_procinfo (pi); - error (msg); -} - -/* - * Function: sysset_t_size - * - * Returns the (complete) size of a sysset_t struct. Normally, this - * is just sizeof (syset_t), but in the case of Monterey/64, the actual - * size of sysset_t isn't known until runtime. - */ - -static int -sysset_t_size (procinfo * pi) -{ -#ifndef DYNAMIC_SYSCALLS - return sizeof (sysset_t); -#else - return sizeof (sysset_t) - sizeof (uint64_t) - + sizeof (uint64_t) * ((pi->num_syscalls + (8 * sizeof (uint64_t) - 1)) - / (8 * sizeof (uint64_t))); -#endif -} - -/* Function: sysset_t_alloc - - Allocate and (partially) initialize a sysset_t struct. */ - -static sysset_t * -sysset_t_alloc (procinfo * pi) -{ - sysset_t *ret; - int size = sysset_t_size (pi); - ret = xmalloc (size); -#ifdef DYNAMIC_SYSCALLS - ret->pr_size = (pi->num_syscalls + (8 * sizeof (uint64_t) - 1)) - / (8 * sizeof (uint64_t)); -#endif - return ret; -} - -#ifdef DYNAMIC_SYSCALLS - -/* Function: load_syscalls - - Extract syscall numbers and names from /proc/<pid>/sysent. Initialize - pi->num_syscalls with the number of syscalls and pi->syscall_names - with the names. (Certain numbers may be skipped in which case the - names for these numbers will be left as NULL.) */ - -#define MAX_SYSCALL_NAME_LENGTH 256 -#define MAX_SYSCALLS 65536 - -static void -load_syscalls (procinfo *pi) -{ - char pathname[MAX_PROC_NAME_SIZE]; - int sysent_fd; - prsysent_t header; - prsyscall_t *syscalls; - int i, size, maxcall; - - pi->num_syscalls = 0; - pi->syscall_names = 0; - - /* Open the file descriptor for the sysent file */ - sprintf (pathname, "/proc/%d/sysent", pi->pid); - sysent_fd = open_with_retry (pathname, O_RDONLY); - if (sysent_fd < 0) - { - error ("load_syscalls: Can't open /proc/%d/sysent", pi->pid); - } - - size = sizeof header - sizeof (prsyscall_t); - if (read (sysent_fd, &header, size) != size) - { - error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid); - } - - if (header.pr_nsyscalls == 0) - { - error ("load_syscalls: /proc/%d/sysent contains no syscalls!", pi->pid); - } - - size = header.pr_nsyscalls * sizeof (prsyscall_t); - syscalls = xmalloc (size); - - if (read (sysent_fd, syscalls, size) != size) - { - xfree (syscalls); - error ("load_syscalls: Error reading /proc/%d/sysent", pi->pid); - } - - /* Find maximum syscall number. This may not be the same as - pr_nsyscalls since that value refers to the number of entries - in the table. (Also, the docs indicate that some system - call numbers may be skipped.) */ - - maxcall = syscalls[0].pr_number; - - for (i = 1; i < header.pr_nsyscalls; i++) - if (syscalls[i].pr_number > maxcall - && syscalls[i].pr_nameoff > 0 - && syscalls[i].pr_number < MAX_SYSCALLS) - maxcall = syscalls[i].pr_number; - - pi->num_syscalls = maxcall+1; - pi->syscall_names = xmalloc (pi->num_syscalls * sizeof (char *)); - - for (i = 0; i < pi->num_syscalls; i++) - pi->syscall_names[i] = NULL; - - /* Read the syscall names in */ - for (i = 0; i < header.pr_nsyscalls; i++) - { - char namebuf[MAX_SYSCALL_NAME_LENGTH]; - int nread; - int callnum; - - if (syscalls[i].pr_number >= MAX_SYSCALLS - || syscalls[i].pr_number < 0 - || syscalls[i].pr_nameoff <= 0 - || (lseek (sysent_fd, (off_t) syscalls[i].pr_nameoff, SEEK_SET) - != (off_t) syscalls[i].pr_nameoff)) - continue; - - nread = read (sysent_fd, namebuf, sizeof namebuf); - if (nread <= 0) - continue; - - callnum = syscalls[i].pr_number; - - if (pi->syscall_names[callnum] != NULL) - { - /* FIXME: Generate warning */ - continue; - } - - namebuf[nread-1] = '\0'; - size = strlen (namebuf) + 1; - pi->syscall_names[callnum] = xmalloc (size); - strncpy (pi->syscall_names[callnum], namebuf, size-1); - pi->syscall_names[callnum][size-1] = '\0'; - } - - close (sysent_fd); - xfree (syscalls); -} - -/* Function: free_syscalls - - Free the space allocated for the syscall names from the procinfo - structure. */ - -static void -free_syscalls (procinfo *pi) -{ - if (pi->syscall_names) - { - int i; - - for (i = 0; i < pi->num_syscalls; i++) - if (pi->syscall_names[i] != NULL) - xfree (pi->syscall_names[i]); - - xfree (pi->syscall_names); - pi->syscall_names = 0; - } -} - -/* Function: find_syscall - - Given a name, look up (and return) the corresponding syscall number. - If no match is found, return -1. */ - -static int -find_syscall (procinfo *pi, char *name) -{ - int i; - for (i = 0; i < pi->num_syscalls; i++) - { - if (pi->syscall_names[i] && strcmp (name, pi->syscall_names[i]) == 0) - return i; - } - return -1; -} -#endif - -/* =================== END, STRUCT PROCINFO "MODULE" =================== */ - -/* =================== /proc "MODULE" =================== */ - -/* - * This "module" is the interface layer between the /proc system API - * and the gdb target vector functions. This layer consists of - * access functions that encapsulate each of the basic operations - * that we need to use from the /proc API. - * - * The main motivation for this layer is to hide the fact that - * there are two very different implementations of the /proc API. - * Rather than have a bunch of #ifdefs all thru the gdb target vector - * functions, we do our best to hide them all in here. - */ - -int proc_get_status (procinfo * pi); -long proc_flags (procinfo * pi); -int proc_why (procinfo * pi); -int proc_what (procinfo * pi); -int proc_set_run_on_last_close (procinfo * pi); -int proc_unset_run_on_last_close (procinfo * pi); -int proc_set_inherit_on_fork (procinfo * pi); -int proc_unset_inherit_on_fork (procinfo * pi); -int proc_set_async (procinfo * pi); -int proc_unset_async (procinfo * pi); -int proc_stop_process (procinfo * pi); -int proc_trace_signal (procinfo * pi, int signo); -int proc_ignore_signal (procinfo * pi, int signo); -int proc_clear_current_fault (procinfo * pi); -int proc_set_current_signal (procinfo * pi, int signo); -int proc_clear_current_signal (procinfo * pi); -int proc_set_gregs (procinfo * pi); -int proc_set_fpregs (procinfo * pi); -int proc_wait_for_stop (procinfo * pi); -int proc_run_process (procinfo * pi, int step, int signo); -int proc_kill (procinfo * pi, int signo); -int proc_parent_pid (procinfo * pi); -int proc_get_nthreads (procinfo * pi); -int proc_get_current_thread (procinfo * pi); -int proc_set_held_signals (procinfo * pi, gdb_sigset_t * sighold); -int proc_set_traced_sysexit (procinfo * pi, sysset_t * sysset); -int proc_set_traced_sysentry (procinfo * pi, sysset_t * sysset); -int proc_set_traced_faults (procinfo * pi, fltset_t * fltset); -int proc_set_traced_signals (procinfo * pi, gdb_sigset_t * sigset); - -int proc_update_threads (procinfo * pi); -int proc_iterate_over_threads (procinfo * pi, - int (*func) (procinfo *, procinfo *, void *), - void *ptr); - -gdb_gregset_t *proc_get_gregs (procinfo * pi); -gdb_fpregset_t *proc_get_fpregs (procinfo * pi); -sysset_t *proc_get_traced_sysexit (procinfo * pi, sysset_t * save); -sysset_t *proc_get_traced_sysentry (procinfo * pi, sysset_t * save); -fltset_t *proc_get_traced_faults (procinfo * pi, fltset_t * save); -gdb_sigset_t *proc_get_traced_signals (procinfo * pi, gdb_sigset_t * save); -gdb_sigset_t *proc_get_held_signals (procinfo * pi, gdb_sigset_t * save); -gdb_sigset_t *proc_get_pending_signals (procinfo * pi, gdb_sigset_t * save); -gdb_sigaction_t *proc_get_signal_actions (procinfo * pi, gdb_sigaction_t *save); - -void proc_warn (procinfo * pi, char *func, int line); -void proc_error (procinfo * pi, char *func, int line); - -void -proc_warn (procinfo *pi, char *func, int line) -{ - sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname); - print_sys_errmsg (errmsg, errno); -} - -void -proc_error (procinfo *pi, char *func, int line) -{ - sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname); - perror_with_name (errmsg); -} - -/* - * Function: proc_get_status - * - * Updates the status struct in the procinfo. - * There is a 'valid' flag, to let other functions know when - * this function needs to be called (so the status is only - * read when it is needed). The status file descriptor is - * also only opened when it is needed. - * - * Return: non-zero for success, zero for failure. - */ - -int -proc_get_status (procinfo *pi) -{ - /* Status file descriptor is opened "lazily" */ - if (pi->status_fd == 0 && - open_procinfo_files (pi, FD_STATUS) == 0) - { - pi->status_valid = 0; - return 0; - } - -#ifdef NEW_PROC_API - if (lseek (pi->status_fd, 0, SEEK_SET) < 0) - pi->status_valid = 0; /* fail */ - else - { - /* Sigh... I have to read a different data structure, - depending on whether this is a main process or an LWP. */ - if (pi->tid) - pi->status_valid = (read (pi->status_fd, - (char *) &pi->prstatus.pr_lwp, - sizeof (lwpstatus_t)) - == sizeof (lwpstatus_t)); - else - { - pi->status_valid = (read (pi->status_fd, - (char *) &pi->prstatus, - sizeof (gdb_prstatus_t)) - == sizeof (gdb_prstatus_t)); -#if 0 /*def UNIXWARE*/ - if (pi->status_valid && - (pi->prstatus.pr_lwp.pr_flags & PR_ISTOP) && - pi->prstatus.pr_lwp.pr_why == PR_REQUESTED) - /* Unixware peculiarity -- read the damn thing again! */ - pi->status_valid = (read (pi->status_fd, - (char *) &pi->prstatus, - sizeof (gdb_prstatus_t)) - == sizeof (gdb_prstatus_t)); -#endif /* UNIXWARE */ - } - } -#else /* ioctl method */ -#ifdef PIOCTSTATUS /* osf */ - if (pi->tid == 0) /* main process */ - { - /* Just read the danged status. Now isn't that simple? */ - pi->status_valid = - (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0); - } - else - { - int win; - struct { - long pr_count; - tid_t pr_error_thread; - struct prstatus status; - } thread_status; - - thread_status.pr_count = 1; - thread_status.status.pr_tid = pi->tid; - win = (ioctl (pi->status_fd, PIOCTSTATUS, &thread_status) >= 0); - if (win) - { - memcpy (&pi->prstatus, &thread_status.status, - sizeof (pi->prstatus)); - pi->status_valid = 1; - } - } -#else - /* Just read the danged status. Now isn't that simple? */ - pi->status_valid = (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0); -#endif -#endif - - if (pi->status_valid) - { - PROC_PRETTYFPRINT_STATUS (proc_flags (pi), - proc_why (pi), - proc_what (pi), - proc_get_current_thread (pi)); - } - - /* The status struct includes general regs, so mark them valid too */ - pi->gregs_valid = pi->status_valid; -#ifdef NEW_PROC_API - /* In the read/write multiple-fd model, - the status struct includes the fp regs too, so mark them valid too */ - pi->fpregs_valid = pi->status_valid; -#endif - return pi->status_valid; /* True if success, false if failure. */ -} - -/* - * Function: proc_flags - * - * returns the process flags (pr_flags field). - */ - -long -proc_flags (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; /* FIXME: not a good failure value (but what is?) */ - -#ifdef NEW_PROC_API -# ifdef UNIXWARE - /* UnixWare 7.1 puts process status flags, e.g. PR_ASYNC, in - pstatus_t and LWP status flags, e.g. PR_STOPPED, in lwpstatus_t. - The two sets of flags don't overlap. */ - return pi->prstatus.pr_flags | pi->prstatus.pr_lwp.pr_flags; -# else - return pi->prstatus.pr_lwp.pr_flags; -# endif -#else - return pi->prstatus.pr_flags; -#endif -} - -/* - * Function: proc_why - * - * returns the pr_why field (why the process stopped). - */ - -int -proc_why (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; /* FIXME: not a good failure value (but what is?) */ - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_why; -#else - return pi->prstatus.pr_why; -#endif -} - -/* - * Function: proc_what - * - * returns the pr_what field (details of why the process stopped). - */ - -int -proc_what (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; /* FIXME: not a good failure value (but what is?) */ - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_what; -#else - return pi->prstatus.pr_what; -#endif -} - -#ifndef PIOCSSPCACT /* The following is not supported on OSF. */ -/* - * Function: proc_nsysarg - * - * returns the pr_nsysarg field (number of args to the current syscall). - */ - -int -proc_nsysarg (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_nsysarg; -#else - return pi->prstatus.pr_nsysarg; -#endif -} - -/* - * Function: proc_sysargs - * - * returns the pr_sysarg field (pointer to the arguments of current syscall). - */ - -long * -proc_sysargs (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifdef NEW_PROC_API - return (long *) &pi->prstatus.pr_lwp.pr_sysarg; -#else - return (long *) &pi->prstatus.pr_sysarg; -#endif -} - -/* - * Function: proc_syscall - * - * returns the pr_syscall field (id of current syscall if we are in one). - */ - -int -proc_syscall (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_syscall; -#else - return pi->prstatus.pr_syscall; -#endif -} -#endif /* PIOCSSPCACT */ - -/* - * Function: proc_cursig: - * - * returns the pr_cursig field (current signal). - */ - -long -proc_cursig (struct procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; /* FIXME: not a good failure value (but what is?) */ - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_cursig; -#else - return pi->prstatus.pr_cursig; -#endif -} - -/* - * Function: proc_modify_flag - * - * === I appologize for the messiness of this function. - * === This is an area where the different versions of - * === /proc are more inconsistent than usual. MVS - * - * Set or reset any of the following process flags: - * PR_FORK -- forked child will inherit trace flags - * PR_RLC -- traced process runs when last /proc file closed. - * PR_KLC -- traced process is killed when last /proc file closed. - * PR_ASYNC -- LWP's get to run/stop independently. - * - * There are three methods for doing this function: - * 1) Newest: read/write [PCSET/PCRESET/PCUNSET] - * [Sol6, Sol7, UW] - * 2) Middle: PIOCSET/PIOCRESET - * [Irix, Sol5] - * 3) Oldest: PIOCSFORK/PIOCRFORK/PIOCSRLC/PIOCRRLC - * [OSF, Sol5] - * - * Note: Irix does not define PR_ASYNC. - * Note: OSF does not define PR_KLC. - * Note: OSF is the only one that can ONLY use the oldest method. - * - * Arguments: - * pi -- the procinfo - * flag -- one of PR_FORK, PR_RLC, or PR_ASYNC - * mode -- 1 for set, 0 for reset. - * - * Returns non-zero for success, zero for failure. - */ - -enum { FLAG_RESET, FLAG_SET }; - -static int -proc_modify_flag (procinfo *pi, long flag, long mode) -{ - long win = 0; /* default to fail */ - - /* - * These operations affect the process as a whole, and applying - * them to an individual LWP has the same meaning as applying them - * to the main process. Therefore, if we're ever called with a - * pointer to an LWP's procinfo, let's substitute the process's - * procinfo and avoid opening the LWP's file descriptor - * unnecessarily. - */ - - if (pi->pid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API /* Newest method: UnixWare and newer Solarii */ - /* First normalize the PCUNSET/PCRESET command opcode - (which for no obvious reason has a different definition - from one operating system to the next...) */ -#ifdef PCUNSET -#define GDBRESET PCUNSET -#else -#ifdef PCRESET -#define GDBRESET PCRESET -#endif -#endif - { - procfs_ctl_t arg[2]; - - if (mode == FLAG_SET) /* Set the flag (RLC, FORK, or ASYNC) */ - arg[0] = PCSET; - else /* Reset the flag */ - arg[0] = GDBRESET; - - arg[1] = flag; - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); - } -#else -#ifdef PIOCSET /* Irix/Sol5 method */ - if (mode == FLAG_SET) /* Set the flag (hopefully RLC, FORK, or ASYNC) */ - { - win = (ioctl (pi->ctl_fd, PIOCSET, &flag) >= 0); - } - else /* Reset the flag */ - { - win = (ioctl (pi->ctl_fd, PIOCRESET, &flag) >= 0); - } - -#else -#ifdef PIOCSRLC /* Oldest method: OSF */ - switch (flag) { - case PR_RLC: - if (mode == FLAG_SET) /* Set run-on-last-close */ - { - win = (ioctl (pi->ctl_fd, PIOCSRLC, NULL) >= 0); - } - else /* Clear run-on-last-close */ - { - win = (ioctl (pi->ctl_fd, PIOCRRLC, NULL) >= 0); - } - break; - case PR_FORK: - if (mode == FLAG_SET) /* Set inherit-on-fork */ - { - win = (ioctl (pi->ctl_fd, PIOCSFORK, NULL) >= 0); - } - else /* Clear inherit-on-fork */ - { - win = (ioctl (pi->ctl_fd, PIOCRFORK, NULL) >= 0); - } - break; - default: - win = 0; /* fail -- unknown flag (can't do PR_ASYNC) */ - break; - } -#endif -#endif -#endif -#undef GDBRESET - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - if (!win) - warning ("procfs: modify_flag failed to turn %s %s", - flag == PR_FORK ? "PR_FORK" : - flag == PR_RLC ? "PR_RLC" : -#ifdef PR_ASYNC - flag == PR_ASYNC ? "PR_ASYNC" : -#endif -#ifdef PR_KLC - flag == PR_KLC ? "PR_KLC" : -#endif - "<unknown flag>", - mode == FLAG_RESET ? "off" : "on"); - - return win; -} - -/* - * Function: proc_set_run_on_last_close - * - * Set the run_on_last_close flag. - * Process with all threads will become runnable - * when debugger closes all /proc fds. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_run_on_last_close (procinfo *pi) -{ - return proc_modify_flag (pi, PR_RLC, FLAG_SET); -} - -/* - * Function: proc_unset_run_on_last_close - * - * Reset the run_on_last_close flag. - * Process will NOT become runnable - * when debugger closes its file handles. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_unset_run_on_last_close (procinfo *pi) -{ - return proc_modify_flag (pi, PR_RLC, FLAG_RESET); -} - -#ifdef PR_KLC -/* - * Function: proc_set_kill_on_last_close - * - * Set the kill_on_last_close flag. - * Process with all threads will be killed when debugger - * closes all /proc fds (or debugger exits or dies). - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_kill_on_last_close (procinfo *pi) -{ - return proc_modify_flag (pi, PR_KLC, FLAG_SET); -} - -/* - * Function: proc_unset_kill_on_last_close - * - * Reset the kill_on_last_close flag. - * Process will NOT be killed when debugger - * closes its file handles (or exits or dies). - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_unset_kill_on_last_close (procinfo *pi) -{ - return proc_modify_flag (pi, PR_KLC, FLAG_RESET); -} -#endif /* PR_KLC */ - -/* - * Function: proc_set_inherit_on_fork - * - * Set inherit_on_fork flag. - * If the process forks a child while we are registered for events - * in the parent, then we will also recieve events from the child. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_inherit_on_fork (procinfo *pi) -{ - return proc_modify_flag (pi, PR_FORK, FLAG_SET); -} - -/* - * Function: proc_unset_inherit_on_fork - * - * Reset inherit_on_fork flag. - * If the process forks a child while we are registered for events - * in the parent, then we will NOT recieve events from the child. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_unset_inherit_on_fork (procinfo *pi) -{ - return proc_modify_flag (pi, PR_FORK, FLAG_RESET); -} - -#ifdef PR_ASYNC -/* - * Function: proc_set_async - * - * Set PR_ASYNC flag. - * If one LWP stops because of a debug event (signal etc.), - * the remaining LWPs will continue to run. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_async (procinfo *pi) -{ - return proc_modify_flag (pi, PR_ASYNC, FLAG_SET); -} - -/* - * Function: proc_unset_async - * - * Reset PR_ASYNC flag. - * If one LWP stops because of a debug event (signal etc.), - * then all other LWPs will stop as well. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_unset_async (procinfo *pi) -{ - return proc_modify_flag (pi, PR_ASYNC, FLAG_RESET); -} -#endif /* PR_ASYNC */ - -/* - * Function: proc_stop_process - * - * Request the process/LWP to stop. Does not wait. - * Returns non-zero for success, zero for failure. - */ - -int -proc_stop_process (procinfo *pi) -{ - int win; - - /* - * We might conceivably apply this operation to an LWP, and - * the LWP's ctl file descriptor might not be open. - */ - - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - return 0; - else - { -#ifdef NEW_PROC_API - procfs_ctl_t cmd = PCSTOP; - win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd)); -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) >= 0); - /* Note: the call also reads the prstatus. */ - if (win) - { - pi->status_valid = 1; - PROC_PRETTYFPRINT_STATUS (proc_flags (pi), - proc_why (pi), - proc_what (pi), - proc_get_current_thread (pi)); - } -#endif - } - - return win; -} - -/* - * Function: proc_wait_for_stop - * - * Wait for the process or LWP to stop (block until it does). - * Returns non-zero for success, zero for failure. - */ - -int -proc_wait_for_stop (procinfo *pi) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - procfs_ctl_t cmd = PCWSTOP; - win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd)); - /* We been runnin' and we stopped -- need to update status. */ - pi->status_valid = 0; - } -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCWSTOP, &pi->prstatus) >= 0); - /* Above call also refreshes the prstatus. */ - if (win) - { - pi->status_valid = 1; - PROC_PRETTYFPRINT_STATUS (proc_flags (pi), - proc_why (pi), - proc_what (pi), - proc_get_current_thread (pi)); - } -#endif - - return win; -} - -/* - * Function: proc_run_process - * - * Make the process or LWP runnable. - * Options (not all are implemented): - * - single-step - * - clear current fault - * - clear current signal - * - abort the current system call - * - stop as soon as finished with system call - * - (ioctl): set traced signal set - * - (ioctl): set held signal set - * - (ioctl): set traced fault set - * - (ioctl): set start pc (vaddr) - * Always clear the current fault. - * Clear the current signal if 'signo' is zero. - * - * Arguments: - * pi the process or LWP to operate on. - * step if true, set the process or LWP to trap after one instr. - * signo if zero, clear the current signal if any. - * if non-zero, set the current signal to this one. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_run_process (procinfo *pi, int step, int signo) -{ - int win; - int runflags; - - /* - * We will probably have to apply this operation to individual threads, - * so make sure the control file descriptor is open. - */ - - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - { - return 0; - } - - runflags = PRCFAULT; /* always clear current fault */ - if (step) - runflags |= PRSTEP; - if (signo == 0) - runflags |= PRCSIG; - else if (signo != -1) /* -1 means do nothing W.R.T. signals */ - proc_set_current_signal (pi, signo); - -#ifdef NEW_PROC_API - { - procfs_ctl_t cmd[2]; - - cmd[0] = PCRUN; - cmd[1] = runflags; - win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd)); - } -#else /* ioctl method */ - { - prrun_t prrun; - - memset (&prrun, 0, sizeof (prrun)); - prrun.pr_flags = runflags; - win = (ioctl (pi->ctl_fd, PIOCRUN, &prrun) >= 0); - } -#endif - - return win; -} - -/* - * Function: proc_set_traced_signals - * - * Register to trace signals in the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_traced_signals (procinfo *pi, gdb_sigset_t *sigset) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char sigset[sizeof (gdb_sigset_t)]; - } arg; - - arg.cmd = PCSTRACE; - memcpy (&arg.sigset, sigset, sizeof (gdb_sigset_t)); - - win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg)); - } -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCSTRACE, sigset) >= 0); -#endif - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - if (!win) - warning ("procfs: set_traced_signals failed"); - return win; -} - -/* - * Function: proc_set_traced_faults - * - * Register to trace hardware faults in the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_traced_faults (procinfo *pi, fltset_t *fltset) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char fltset[sizeof (fltset_t)]; - } arg; - - arg.cmd = PCSFAULT; - memcpy (&arg.fltset, fltset, sizeof (fltset_t)); - - win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg)); - } -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCSFAULT, fltset) >= 0); -#endif - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - return win; -} - -/* - * Function: proc_set_traced_sysentry - * - * Register to trace entry to system calls in the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_traced_sysentry (procinfo *pi, sysset_t *sysset) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct gdb_proc_ctl_pcsentry { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char sysset[sizeof (sysset_t)]; - } *argp; - int argp_size = sizeof (struct gdb_proc_ctl_pcsentry) - - sizeof (sysset_t) - + sysset_t_size (pi); - - argp = xmalloc (argp_size); - - argp->cmd = PCSENTRY; - memcpy (&argp->sysset, sysset, sysset_t_size (pi)); - - win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size); - xfree (argp); - } -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCSENTRY, sysset) >= 0); -#endif - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - return win; -} - -/* - * Function: proc_set_traced_sysexit - * - * Register to trace exit from system calls in the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_traced_sysexit (procinfo *pi, sysset_t *sysset) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct gdb_proc_ctl_pcsexit { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char sysset[sizeof (sysset_t)]; - } *argp; - int argp_size = sizeof (struct gdb_proc_ctl_pcsexit) - - sizeof (sysset_t) - + sysset_t_size (pi); - - argp = xmalloc (argp_size); - - argp->cmd = PCSEXIT; - memcpy (&argp->sysset, sysset, sysset_t_size (pi)); - - win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size); - xfree (argp); - } -#else /* ioctl method */ - win = (ioctl (pi->ctl_fd, PIOCSEXIT, sysset) >= 0); -#endif - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - return win; -} - -/* - * Function: proc_set_held_signals - * - * Specify the set of blocked / held signals in the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_held_signals (procinfo *pi, gdb_sigset_t *sighold) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char hold[sizeof (gdb_sigset_t)]; - } arg; - - arg.cmd = PCSHOLD; - memcpy (&arg.hold, sighold, sizeof (gdb_sigset_t)); - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); - } -#else - win = (ioctl (pi->ctl_fd, PIOCSHOLD, sighold) >= 0); -#endif - /* The above operation renders the procinfo's cached pstatus obsolete. */ - pi->status_valid = 0; - - return win; -} - -/* - * Function: proc_get_pending_signals - * - * returns the set of signals that are pending in the process or LWP. - * Will also copy the sigset if 'save' is non-zero. - */ - -gdb_sigset_t * -proc_get_pending_signals (procinfo *pi, gdb_sigset_t *save) -{ - gdb_sigset_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifdef NEW_PROC_API - ret = &pi->prstatus.pr_lwp.pr_lwppend; -#else - ret = &pi->prstatus.pr_sigpend; -#endif - if (save && ret) - memcpy (save, ret, sizeof (gdb_sigset_t)); - - return ret; -} - -/* - * Function: proc_get_signal_actions - * - * returns the set of signal actions. - * Will also copy the sigactionset if 'save' is non-zero. - */ - -gdb_sigaction_t * -proc_get_signal_actions (procinfo *pi, gdb_sigaction_t *save) -{ - gdb_sigaction_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifdef NEW_PROC_API - ret = &pi->prstatus.pr_lwp.pr_action; -#else - ret = &pi->prstatus.pr_action; -#endif - if (save && ret) - memcpy (save, ret, sizeof (gdb_sigaction_t)); - - return ret; -} - -/* - * Function: proc_get_held_signals - * - * returns the set of signals that are held / blocked. - * Will also copy the sigset if 'save' is non-zero. - */ - -gdb_sigset_t * -proc_get_held_signals (procinfo *pi, gdb_sigset_t *save) -{ - gdb_sigset_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifdef UNIXWARE - ret = &pi->prstatus.pr_lwp.pr_context.uc_sigmask; -#else - ret = &pi->prstatus.pr_lwp.pr_lwphold; -#endif /* UNIXWARE */ -#else /* not NEW_PROC_API */ - { - static gdb_sigset_t sigheld; - - if (ioctl (pi->ctl_fd, PIOCGHOLD, &sigheld) >= 0) - ret = &sigheld; - } -#endif /* NEW_PROC_API */ - if (save && ret) - memcpy (save, ret, sizeof (gdb_sigset_t)); - - return ret; -} - -/* - * Function: proc_get_traced_signals - * - * returns the set of signals that are traced / debugged. - * Will also copy the sigset if 'save' is non-zero. - */ - -gdb_sigset_t * -proc_get_traced_signals (procinfo *pi, gdb_sigset_t *save) -{ - gdb_sigset_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - - ret = &pi->prstatus.pr_sigtrace; -#else - { - static gdb_sigset_t sigtrace; - - if (ioctl (pi->ctl_fd, PIOCGTRACE, &sigtrace) >= 0) - ret = &sigtrace; - } -#endif - if (save && ret) - memcpy (save, ret, sizeof (gdb_sigset_t)); - - return ret; -} - -/* - * Function: proc_trace_signal - * - * Add 'signo' to the set of signals that are traced. - * Returns non-zero for success, zero for failure. - */ - -int -proc_trace_signal (procinfo *pi, int signo) -{ - gdb_sigset_t temp; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (pi) - { - if (proc_get_traced_signals (pi, &temp)) - { - praddset (&temp, signo); - return proc_set_traced_signals (pi, &temp); - } - } - - return 0; /* failure */ -} - -/* - * Function: proc_ignore_signal - * - * Remove 'signo' from the set of signals that are traced. - * Returns non-zero for success, zero for failure. - */ - -int -proc_ignore_signal (procinfo *pi, int signo) -{ - gdb_sigset_t temp; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (pi) - { - if (proc_get_traced_signals (pi, &temp)) - { - prdelset (&temp, signo); - return proc_set_traced_signals (pi, &temp); - } - } - - return 0; /* failure */ -} - -/* - * Function: proc_get_traced_faults - * - * returns the set of hardware faults that are traced /debugged. - * Will also copy the faultset if 'save' is non-zero. - */ - -fltset_t * -proc_get_traced_faults (procinfo *pi, fltset_t *save) -{ - fltset_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - - ret = &pi->prstatus.pr_flttrace; -#else - { - static fltset_t flttrace; - - if (ioctl (pi->ctl_fd, PIOCGFAULT, &flttrace) >= 0) - ret = &flttrace; - } -#endif - if (save && ret) - memcpy (save, ret, sizeof (fltset_t)); - - return ret; -} - -/* - * Function: proc_get_traced_sysentry - * - * returns the set of syscalls that are traced /debugged on entry. - * Will also copy the syscall set if 'save' is non-zero. - */ - -sysset_t * -proc_get_traced_sysentry (procinfo *pi, sysset_t *save) -{ - sysset_t *ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifndef DYNAMIC_SYSCALLS - ret = &pi->prstatus.pr_sysentry; -#else /* DYNAMIC_SYSCALLS */ - { - static sysset_t *sysentry; - size_t size; - - if (!sysentry) - sysentry = sysset_t_alloc (pi); - ret = sysentry; - if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0) - return NULL; - if (pi->prstatus.pr_sysentry_offset == 0) - { - gdb_premptysysset (sysentry); - } - else - { - int rsize; - - if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysentry_offset, - SEEK_SET) - != (off_t) pi->prstatus.pr_sysentry_offset) - return NULL; - size = sysset_t_size (pi); - gdb_premptysysset (sysentry); - rsize = read (pi->status_fd, sysentry, size); - if (rsize < 0) - return NULL; - } - } -#endif /* DYNAMIC_SYSCALLS */ -#else /* !NEW_PROC_API */ - { - static sysset_t sysentry; - - if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysentry) >= 0) - ret = &sysentry; - } -#endif /* NEW_PROC_API */ - if (save && ret) - memcpy (save, ret, sysset_t_size (pi)); - - return ret; -} - -/* - * Function: proc_get_traced_sysexit - * - * returns the set of syscalls that are traced /debugged on exit. - * Will also copy the syscall set if 'save' is non-zero. - */ - -sysset_t * -proc_get_traced_sysexit (procinfo *pi, sysset_t *save) -{ - sysset_t * ret = NULL; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - if (!pi->status_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifndef DYNAMIC_SYSCALLS - ret = &pi->prstatus.pr_sysexit; -#else /* DYNAMIC_SYSCALLS */ - { - static sysset_t *sysexit; - size_t size; - - if (!sysexit) - sysexit = sysset_t_alloc (pi); - ret = sysexit; - if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0) - return NULL; - if (pi->prstatus.pr_sysexit_offset == 0) - { - gdb_premptysysset (sysexit); - } - else - { - int rsize; - - if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysexit_offset, SEEK_SET) - != (off_t) pi->prstatus.pr_sysexit_offset) - return NULL; - size = sysset_t_size (pi); - gdb_premptysysset (sysexit); - rsize = read (pi->status_fd, sysexit, size); - if (rsize < 0) - return NULL; - } - } -#endif /* DYNAMIC_SYSCALLS */ -#else - { - static sysset_t sysexit; - - if (ioctl (pi->ctl_fd, PIOCGEXIT, &sysexit) >= 0) - ret = &sysexit; - } -#endif - if (save && ret) - memcpy (save, ret, sysset_t_size (pi)); - - return ret; -} - -/* - * Function: proc_clear_current_fault - * - * The current fault (if any) is cleared; the associated signal - * will not be sent to the process or LWP when it resumes. - * Returns non-zero for success, zero for failure. - */ - -int -proc_clear_current_fault (procinfo *pi) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - procfs_ctl_t cmd = PCCFAULT; - win = (write (pi->ctl_fd, (void *) &cmd, sizeof (cmd)) == sizeof (cmd)); - } -#else - win = (ioctl (pi->ctl_fd, PIOCCFAULT, 0) >= 0); -#endif - - return win; -} - -/* - * Function: proc_set_current_signal - * - * Set the "current signal" that will be delivered next to the process. - * NOTE: semantics are different from those of KILL. - * This signal will be delivered to the process or LWP - * immediately when it is resumed (even if the signal is held/blocked); - * it will NOT immediately cause another event of interest, and will NOT - * first trap back to the debugger. - * - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_current_signal (procinfo *pi, int signo) -{ - int win; - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char sinfo[sizeof (gdb_siginfo_t)]; - } arg; - gdb_siginfo_t *mysinfo; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef PROCFS_DONT_PIOCSSIG_CURSIG - /* With Alpha OSF/1 procfs, the kernel gets really confused if it - * receives a PIOCSSIG with a signal identical to the current signal, - * it messes up the current signal. Work around the kernel bug. - */ - if (signo > 0 && - signo == proc_cursig (pi)) - return 1; /* I assume this is a success? */ -#endif - - /* The pointer is just a type alias. */ - mysinfo = (gdb_siginfo_t *) &arg.sinfo; - mysinfo->si_signo = signo; - mysinfo->si_code = 0; - mysinfo->si_pid = getpid (); /* ?why? */ - mysinfo->si_uid = getuid (); /* ?why? */ - -#ifdef NEW_PROC_API - arg.cmd = PCSSIG; - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); -#else - win = (ioctl (pi->ctl_fd, PIOCSSIG, (void *) &arg.sinfo) >= 0); -#endif - - return win; -} - -/* - * Function: proc_clear_current_signal - * - * The current signal (if any) is cleared, and - * is not sent to the process or LWP when it resumes. - * Returns non-zero for success, zero for failure. - */ - -int -proc_clear_current_signal (procinfo *pi) -{ - int win; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - -#ifdef NEW_PROC_API - { - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char sinfo[sizeof (gdb_siginfo_t)]; - } arg; - gdb_siginfo_t *mysinfo; - - arg.cmd = PCSSIG; - /* The pointer is just a type alias. */ - mysinfo = (gdb_siginfo_t *) &arg.sinfo; - mysinfo->si_signo = 0; - mysinfo->si_code = 0; - mysinfo->si_errno = 0; - mysinfo->si_pid = getpid (); /* ?why? */ - mysinfo->si_uid = getuid (); /* ?why? */ - - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); - } -#else - win = (ioctl (pi->ctl_fd, PIOCSSIG, 0) >= 0); -#endif - - return win; -} - -/* - * Function: proc_get_gregs - * - * Get the general registers for the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -gdb_gregset_t * -proc_get_gregs (procinfo *pi) -{ - if (!pi->status_valid || !pi->gregs_valid) - if (!proc_get_status (pi)) - return NULL; - - /* - * OK, sorry about the ifdef's. - * There's three cases instead of two, because - * in this instance Unixware and Solaris/RW differ. - */ - -#ifdef NEW_PROC_API -#ifdef UNIXWARE /* ugh, a true architecture dependency */ - return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs; -#else /* not Unixware */ - return &pi->prstatus.pr_lwp.pr_reg; -#endif /* Unixware */ -#else /* not NEW_PROC_API */ - return &pi->prstatus.pr_reg; -#endif /* NEW_PROC_API */ -} - -/* - * Function: proc_get_fpregs - * - * Get the floating point registers for the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -gdb_fpregset_t * -proc_get_fpregs (procinfo *pi) -{ -#ifdef NEW_PROC_API - if (!pi->status_valid || !pi->fpregs_valid) - if (!proc_get_status (pi)) - return NULL; - -#ifdef UNIXWARE /* a true architecture dependency */ - return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs; -#else - return &pi->prstatus.pr_lwp.pr_fpreg; -#endif /* Unixware */ - -#else /* not NEW_PROC_API */ - if (pi->fpregs_valid) - return &pi->fpregset; /* already got 'em */ - else - { - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - { - return NULL; - } - else - { -#ifdef PIOCTGFPREG - struct { - long pr_count; - tid_t pr_error_thread; - tfpregset_t thread_1; - } thread_fpregs; - - thread_fpregs.pr_count = 1; - thread_fpregs.thread_1.tid = pi->tid; - - if (pi->tid == 0 && - ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0) - { - pi->fpregs_valid = 1; - return &pi->fpregset; /* got 'em now! */ - } - else if (pi->tid != 0 && - ioctl (pi->ctl_fd, PIOCTGFPREG, &thread_fpregs) >= 0) - { - memcpy (&pi->fpregset, &thread_fpregs.thread_1.pr_fpregs, - sizeof (pi->fpregset)); - pi->fpregs_valid = 1; - return &pi->fpregset; /* got 'em now! */ - } - else - { - return NULL; - } -#else - if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0) - { - pi->fpregs_valid = 1; - return &pi->fpregset; /* got 'em now! */ - } - else - { - return NULL; - } -#endif - } - } -#endif -} - -/* - * Function: proc_set_gregs - * - * Write the general registers back to the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_gregs (procinfo *pi) -{ - gdb_gregset_t *gregs; - int win; - - if ((gregs = proc_get_gregs (pi)) == NULL) - return 0; /* get_regs has already warned */ - - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - { - return 0; - } - else - { -#ifdef NEW_PROC_API - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char gregs[sizeof (gdb_gregset_t)]; - } arg; - - arg.cmd = PCSREG; - memcpy (&arg.gregs, gregs, sizeof (arg.gregs)); - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); -#else - win = (ioctl (pi->ctl_fd, PIOCSREG, gregs) >= 0); -#endif - } - - /* Policy: writing the regs invalidates our cache. */ - pi->gregs_valid = 0; - return win; -} - -/* - * Function: proc_set_fpregs - * - * Modify the floating point register set of the process or LWP. - * Returns non-zero for success, zero for failure. - */ - -int -proc_set_fpregs (procinfo *pi) -{ - gdb_fpregset_t *fpregs; - int win; - - if ((fpregs = proc_get_fpregs (pi)) == NULL) - return 0; /* get_fpregs has already warned */ - - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - { - return 0; - } - else - { -#ifdef NEW_PROC_API - struct { - procfs_ctl_t cmd; - /* Use char array to avoid alignment issues. */ - char fpregs[sizeof (gdb_fpregset_t)]; - } arg; - - arg.cmd = PCSFPREG; - memcpy (&arg.fpregs, fpregs, sizeof (arg.fpregs)); - win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg)); -#else -#ifdef PIOCTSFPREG - if (pi->tid == 0) - win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0); - else - { - struct { - long pr_count; - tid_t pr_error_thread; - tfpregset_t thread_1; - } thread_fpregs; - - thread_fpregs.pr_count = 1; - thread_fpregs.thread_1.tid = pi->tid; - memcpy (&thread_fpregs.thread_1.pr_fpregs, fpregs, - sizeof (*fpregs)); - win = (ioctl (pi->ctl_fd, PIOCTSFPREG, &thread_fpregs) >= 0); - } -#else - win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0); -#endif /* osf PIOCTSFPREG */ -#endif /* NEW_PROC_API */ - } - - /* Policy: writing the regs invalidates our cache. */ - pi->fpregs_valid = 0; - return win; -} - -/* - * Function: proc_kill - * - * Send a signal to the proc or lwp with the semantics of "kill()". - * Returns non-zero for success, zero for failure. - */ - -int -proc_kill (procinfo *pi, int signo) -{ - int win; - - /* - * We might conceivably apply this operation to an LWP, and - * the LWP's ctl file descriptor might not be open. - */ - - if (pi->ctl_fd == 0 && - open_procinfo_files (pi, FD_CTL) == 0) - { - return 0; - } - else - { -#ifdef NEW_PROC_API - procfs_ctl_t cmd[2]; - - cmd[0] = PCKILL; - cmd[1] = signo; - win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd)); -#else /* ioctl method */ - /* FIXME: do I need the Alpha OSF fixups present in - procfs.c/unconditionally_kill_inferior? Perhaps only for SIGKILL? */ - win = (ioctl (pi->ctl_fd, PIOCKILL, &signo) >= 0); -#endif - } - - return win; -} - -/* - * Function: proc_parent_pid - * - * Find the pid of the process that started this one. - * Returns the parent process pid, or zero. - */ - -int -proc_parent_pid (procinfo *pi) -{ - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; - - return pi->prstatus.pr_ppid; -} - - -/* - * Function: proc_set_watchpoint - * - */ - -int -proc_set_watchpoint (procinfo *pi, CORE_ADDR addr, int len, int wflags) -{ -#if !defined (TARGET_HAS_HARDWARE_WATCHPOINTS) - return 0; -#else -/* Horrible hack! Detect Solaris 2.5, because this doesn't work on 2.5 */ -#if defined (PIOCOPENLWP) || defined (UNIXWARE) /* Solaris 2.5: bail out */ - return 0; -#else - struct { - procfs_ctl_t cmd; - char watch[sizeof (prwatch_t)]; - } arg; - prwatch_t *pwatch; - - pwatch = (prwatch_t *) &arg.watch; -#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */ - pwatch->pr_vaddr = (uintptr_t) address_to_host_pointer (addr); -#else - pwatch->pr_vaddr = (caddr_t) address_to_host_pointer (addr); -#endif - pwatch->pr_size = len; - pwatch->pr_wflags = wflags; -#if defined(NEW_PROC_API) && defined (PCWATCH) - arg.cmd = PCWATCH; - return (write (pi->ctl_fd, &arg, sizeof (arg)) == sizeof (arg)); -#else -#if defined (PIOCSWATCH) - return (ioctl (pi->ctl_fd, PIOCSWATCH, pwatch) >= 0); -#else - return 0; /* Fail */ -#endif -#endif -#endif -#endif -} - -#ifdef TM_I386SOL2_H /* Is it hokey to use this? */ - -#include <sys/sysi86.h> - -/* - * Function: proc_get_LDT_entry - * - * Inputs: - * procinfo *pi; - * int key; - * - * The 'key' is actually the value of the lower 16 bits of - * the GS register for the LWP that we're interested in. - * - * Return: matching ssh struct (LDT entry). - */ - -struct ssd * -proc_get_LDT_entry (procinfo *pi, int key) -{ - static struct ssd *ldt_entry = NULL; -#ifdef NEW_PROC_API - char pathname[MAX_PROC_NAME_SIZE]; - struct cleanup *old_chain = NULL; - int fd; - - /* Allocate space for one LDT entry. - This alloc must persist, because we return a pointer to it. */ - if (ldt_entry == NULL) - ldt_entry = (struct ssd *) xmalloc (sizeof (struct ssd)); - - /* Open the file descriptor for the LDT table. */ - sprintf (pathname, "/proc/%d/ldt", pi->pid); - if ((fd = open_with_retry (pathname, O_RDONLY)) < 0) - { - proc_warn (pi, "proc_get_LDT_entry (open)", __LINE__); - return NULL; - } - /* Make sure it gets closed again! */ - old_chain = make_cleanup_close (fd); - - /* Now 'read' thru the table, find a match and return it. */ - while (read (fd, ldt_entry, sizeof (struct ssd)) == sizeof (struct ssd)) - { - if (ldt_entry->sel == 0 && - ldt_entry->bo == 0 && - ldt_entry->acc1 == 0 && - ldt_entry->acc2 == 0) - break; /* end of table */ - /* If key matches, return this entry. */ - if (ldt_entry->sel == key) - return ldt_entry; - } - /* Loop ended, match not found. */ - return NULL; -#else - int nldt, i; - static int nalloc = 0; - - /* Get the number of LDT entries. */ - if (ioctl (pi->ctl_fd, PIOCNLDT, &nldt) < 0) - { - proc_warn (pi, "proc_get_LDT_entry (PIOCNLDT)", __LINE__); - return NULL; - } - - /* Allocate space for the number of LDT entries. */ - /* This alloc has to persist, 'cause we return a pointer to it. */ - if (nldt > nalloc) - { - ldt_entry = (struct ssd *) - xrealloc (ldt_entry, (nldt + 1) * sizeof (struct ssd)); - nalloc = nldt; - } - - /* Read the whole table in one gulp. */ - if (ioctl (pi->ctl_fd, PIOCLDT, ldt_entry) < 0) - { - proc_warn (pi, "proc_get_LDT_entry (PIOCLDT)", __LINE__); - return NULL; - } - - /* Search the table and return the (first) entry matching 'key'. */ - for (i = 0; i < nldt; i++) - if (ldt_entry[i].sel == key) - return &ldt_entry[i]; - - /* Loop ended, match not found. */ - return NULL; -#endif -} - -#endif /* TM_I386SOL2_H */ - -/* =============== END, non-thread part of /proc "MODULE" =============== */ - -/* =================== Thread "MODULE" =================== */ - -/* NOTE: you'll see more ifdefs and duplication of functions here, - since there is a different way to do threads on every OS. */ - -/* - * Function: proc_get_nthreads - * - * Return the number of threads for the process - */ - -#if defined (PIOCNTHR) && defined (PIOCTLIST) -/* - * OSF version - */ -int -proc_get_nthreads (procinfo *pi) -{ - int nthreads = 0; - - if (ioctl (pi->ctl_fd, PIOCNTHR, &nthreads) < 0) - proc_warn (pi, "procfs: PIOCNTHR failed", __LINE__); - - return nthreads; -} - -#else -#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */ -/* - * Solaris and Unixware version - */ -int -proc_get_nthreads (procinfo *pi) -{ - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; - - /* - * NEW_PROC_API: only works for the process procinfo, - * because the LWP procinfos do not get prstatus filled in. - */ -#ifdef NEW_PROC_API - if (pi->tid != 0) /* find the parent process procinfo */ - pi = find_procinfo_or_die (pi->pid, 0); -#endif - return pi->prstatus.pr_nlwp; -} - -#else -/* - * Default version - */ -int -proc_get_nthreads (procinfo *pi) -{ - return 0; -} -#endif -#endif - -/* - * Function: proc_get_current_thread (LWP version) - * - * Return the ID of the thread that had an event of interest. - * (ie. the one that hit a breakpoint or other traced event). - * All other things being equal, this should be the ID of a - * thread that is currently executing. - */ - -#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */ -/* - * Solaris and Unixware version - */ -int -proc_get_current_thread (procinfo *pi) -{ - /* - * Note: this should be applied to the root procinfo for the process, - * not to the procinfo for an LWP. If applied to the procinfo for - * an LWP, it will simply return that LWP's ID. In that case, - * find the parent process procinfo. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - if (!pi->status_valid) - if (!proc_get_status (pi)) - return 0; - -#ifdef NEW_PROC_API - return pi->prstatus.pr_lwp.pr_lwpid; -#else - return pi->prstatus.pr_who; -#endif -} - -#else -#if defined (PIOCNTHR) && defined (PIOCTLIST) -/* - * OSF version - */ -int -proc_get_current_thread (procinfo *pi) -{ -#if 0 /* FIXME: not ready for prime time? */ - return pi->prstatus.pr_tid; -#else - return 0; -#endif -} - -#else -/* - * Default version - */ -int -proc_get_current_thread (procinfo *pi) -{ - return 0; -} - -#endif -#endif - -/* - * Function: proc_update_threads - * - * Discover the IDs of all the threads within the process, and - * create a procinfo for each of them (chained to the parent). - * - * This unfortunately requires a different method on every OS. - * - * Return: non-zero for success, zero for failure. - */ - -int -proc_delete_dead_threads (procinfo *parent, procinfo *thread, void *ignore) -{ - if (thread && parent) /* sanity */ - { - thread->status_valid = 0; - if (!proc_get_status (thread)) - destroy_one_procinfo (&parent->thread_list, thread); - } - return 0; /* keep iterating */ -} - -#if defined (PIOCLSTATUS) -/* - * Solaris 2.5 (ioctl) version - */ -int -proc_update_threads (procinfo *pi) -{ - gdb_prstatus_t *prstatus; - struct cleanup *old_chain = NULL; - procinfo *thread; - int nlwp, i; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL); - - if ((nlwp = proc_get_nthreads (pi)) <= 1) - return 1; /* Process is not multi-threaded; nothing to do. */ - - prstatus = xmalloc (sizeof (gdb_prstatus_t) * (nlwp + 1)); - - old_chain = make_cleanup (xfree, prstatus); - if (ioctl (pi->ctl_fd, PIOCLSTATUS, prstatus) < 0) - proc_error (pi, "update_threads (PIOCLSTATUS)", __LINE__); - - /* Skip element zero, which represents the process as a whole. */ - for (i = 1; i < nlwp + 1; i++) - { - if ((thread = create_procinfo (pi->pid, prstatus[i].pr_who)) == NULL) - proc_error (pi, "update_threads, create_procinfo", __LINE__); - - memcpy (&thread->prstatus, &prstatus[i], sizeof (*prstatus)); - thread->status_valid = 1; - } - pi->threads_valid = 1; - do_cleanups (old_chain); - return 1; -} -#else -#ifdef NEW_PROC_API -/* - * Unixware and Solaris 6 (and later) version - */ -static void -do_closedir_cleanup (void *dir) -{ - closedir (dir); -} - -int -proc_update_threads (procinfo *pi) -{ - char pathname[MAX_PROC_NAME_SIZE + 16]; - struct dirent *direntry; - struct cleanup *old_chain = NULL; - procinfo *thread; - DIR *dirp; - int lwpid; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL); - - /* - * Unixware - * - * Note: this brute-force method is the only way I know of - * to accomplish this task on Unixware. This method will - * also work on Solaris 2.6 and 2.7. There is a much simpler - * and more elegant way to do this on Solaris, but the margins - * of this manuscript are too small to write it here... ;-) - */ - - strcpy (pathname, pi->pathname); - strcat (pathname, "/lwp"); - if ((dirp = opendir (pathname)) == NULL) - proc_error (pi, "update_threads, opendir", __LINE__); - - old_chain = make_cleanup (do_closedir_cleanup, dirp); - while ((direntry = readdir (dirp)) != NULL) - if (direntry->d_name[0] != '.') /* skip '.' and '..' */ - { - lwpid = atoi (&direntry->d_name[0]); - if ((thread = create_procinfo (pi->pid, lwpid)) == NULL) - proc_error (pi, "update_threads, create_procinfo", __LINE__); - } - pi->threads_valid = 1; - do_cleanups (old_chain); - return 1; -} -#else -#ifdef PIOCTLIST -/* - * OSF version - */ -int -proc_update_threads (procinfo *pi) -{ - int nthreads, i; - tid_t *threads; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL); - - nthreads = proc_get_nthreads (pi); - if (nthreads < 2) - return 0; /* nothing to do for 1 or fewer threads */ - - threads = xmalloc (nthreads * sizeof (tid_t)); - - if (ioctl (pi->ctl_fd, PIOCTLIST, threads) < 0) - proc_error (pi, "procfs: update_threads (PIOCTLIST)", __LINE__); - - for (i = 0; i < nthreads; i++) - { - if (!find_procinfo (pi->pid, threads[i])) - if (!create_procinfo (pi->pid, threads[i])) - proc_error (pi, "update_threads, create_procinfo", __LINE__); - } - pi->threads_valid = 1; - return 1; -} -#else -/* - * Default version - */ -int -proc_update_threads (procinfo *pi) -{ - return 0; -} -#endif /* OSF PIOCTLIST */ -#endif /* NEW_PROC_API */ -#endif /* SOL 2.5 PIOCLSTATUS */ - -/* - * Function: proc_iterate_over_threads - * - * Description: - * Given a pointer to a function, call that function once - * for each lwp in the procinfo list, until the function - * returns non-zero, in which event return the value - * returned by the function. - * - * Note: this function does NOT call update_threads. - * If you want to discover new threads first, you must - * call that function explicitly. This function just makes - * a quick pass over the currently-known procinfos. - * - * Arguments: - * pi - parent process procinfo - * func - per-thread function - * ptr - opaque parameter for function. - * - * Return: - * First non-zero return value from the callee, or zero. - */ - -int -proc_iterate_over_threads (procinfo *pi, - int (*func) (procinfo *, procinfo *, void *), - void *ptr) -{ - procinfo *thread, *next; - int retval = 0; - - /* - * We should never have to apply this operation to any procinfo - * except the one for the main process. If that ever changes - * for any reason, then take out the following clause and - * replace it with one that makes sure the ctl_fd is open. - */ - - if (pi->tid != 0) - pi = find_procinfo_or_die (pi->pid, 0); - - for (thread = pi->thread_list; thread != NULL; thread = next) - { - next = thread->next; /* in case thread is destroyed */ - if ((retval = (*func) (pi, thread, ptr)) != 0) - break; - } - - return retval; -} - -/* =================== END, Thread "MODULE" =================== */ - -/* =================== END, /proc "MODULE" =================== */ - -/* =================== GDB "MODULE" =================== */ - -/* - * Here are all of the gdb target vector functions and their friends. - */ - -static ptid_t do_attach (ptid_t ptid); -static void do_detach (int signo); -static int register_gdb_signals (procinfo *, gdb_sigset_t *); - -/* - * Function: procfs_debug_inferior - * - * Sets up the inferior to be debugged. - * Registers to trace signals, hardware faults, and syscalls. - * Note: does not set RLC flag: caller may want to customize that. - * - * Returns: zero for success (note! unlike most functions in this module) - * On failure, returns the LINE NUMBER where it failed! - */ - -static int -procfs_debug_inferior (procinfo *pi) -{ - fltset_t traced_faults; - gdb_sigset_t traced_signals; - sysset_t *traced_syscall_entries; - sysset_t *traced_syscall_exits; - int status; - -#ifdef PROCFS_DONT_TRACE_FAULTS - /* On some systems (OSF), we don't trace hardware faults. - Apparently it's enough that we catch them as signals. - Wonder why we don't just do that in general? */ - premptyset (&traced_faults); /* don't trace faults. */ -#else - /* Register to trace hardware faults in the child. */ - prfillset (&traced_faults); /* trace all faults... */ - prdelset (&traced_faults, FLTPAGE); /* except page fault. */ -#endif - if (!proc_set_traced_faults (pi, &traced_faults)) - return __LINE__; - - /* Register to trace selected signals in the child. */ - premptyset (&traced_signals); - if (!register_gdb_signals (pi, &traced_signals)) - return __LINE__; - - - /* Register to trace the 'exit' system call (on entry). */ - traced_syscall_entries = sysset_t_alloc (pi); - gdb_premptysysset (traced_syscall_entries); -#ifdef SYS_exit - gdb_praddsysset (traced_syscall_entries, SYS_exit); -#endif -#ifdef SYS_lwpexit - gdb_praddsysset (traced_syscall_entries, SYS_lwpexit); /* And _lwp_exit... */ -#endif -#ifdef SYS_lwp_exit - gdb_praddsysset (traced_syscall_entries, SYS_lwp_exit); -#endif -#ifdef DYNAMIC_SYSCALLS - { - int callnum = find_syscall (pi, "_exit"); - if (callnum >= 0) - gdb_praddsysset (traced_syscall_entries, callnum); - } -#endif - - status = proc_set_traced_sysentry (pi, traced_syscall_entries); - xfree (traced_syscall_entries); - if (!status) - return __LINE__; - -#ifdef PRFS_STOPEXEC /* defined on OSF */ - /* OSF method for tracing exec syscalls. Quoting: - Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace - exits from exec system calls because of the user level loader. */ - /* FIXME: make nice and maybe move into an access function. */ - { - int prfs_flags; - - if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0) - return __LINE__; - - prfs_flags |= PRFS_STOPEXEC; - - if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0) - return __LINE__; - } -#else /* not PRFS_STOPEXEC */ - /* Everyone else's (except OSF) method for tracing exec syscalls */ - /* GW: Rationale... - Not all systems with /proc have all the exec* syscalls with the same - names. On the SGI, for example, there is no SYS_exec, but there - *is* a SYS_execv. So, we try to account for that. */ - - traced_syscall_exits = sysset_t_alloc (pi); - gdb_premptysysset (traced_syscall_exits); -#ifdef SYS_exec - gdb_praddsysset (traced_syscall_exits, SYS_exec); -#endif -#ifdef SYS_execve - gdb_praddsysset (traced_syscall_exits, SYS_execve); -#endif -#ifdef SYS_execv - gdb_praddsysset (traced_syscall_exits, SYS_execv); -#endif - -#ifdef SYS_lwpcreate - gdb_praddsysset (traced_syscall_exits, SYS_lwpcreate); - gdb_praddsysset (traced_syscall_exits, SYS_lwpexit); -#endif - -#ifdef SYS_lwp_create /* FIXME: once only, please */ - gdb_praddsysset (traced_syscall_exits, SYS_lwp_create); - gdb_praddsysset (traced_syscall_exits, SYS_lwp_exit); -#endif - -#ifdef DYNAMIC_SYSCALLS - { - int callnum = find_syscall (pi, "execve"); - if (callnum >= 0) - gdb_praddsysset (traced_syscall_exits, callnum); - callnum = find_syscall (pi, "ra_execve"); - if (callnum >= 0) - gdb_praddsysset (traced_syscall_exits, callnum); - } -#endif - - status = proc_set_traced_sysexit (pi, traced_syscall_exits); - xfree (traced_syscall_exits); - if (!status) - return __LINE__; - -#endif /* PRFS_STOPEXEC */ - return 0; -} - -static void -procfs_attach (char *args, int from_tty) -{ - char *exec_file; - int pid; - - if (!args) - error_no_arg ("process-id to attach"); - - pid = atoi (args); - if (pid == getpid ()) - error ("Attaching GDB to itself is not a good idea..."); - - if (from_tty) - { - exec_file = get_exec_file (0); - - if (exec_file) - printf_filtered ("Attaching to program `%s', %s\n", - exec_file, target_pid_to_str (pid_to_ptid (pid))); - else - printf_filtered ("Attaching to %s\n", - target_pid_to_str (pid_to_ptid (pid))); - - fflush (stdout); - } - inferior_ptid = do_attach (pid_to_ptid (pid)); - push_target (&procfs_ops); -} - -static void -procfs_detach (char *args, int from_tty) -{ - char *exec_file; - int signo = 0; - - if (from_tty) - { - exec_file = get_exec_file (0); - if (exec_file == 0) - exec_file = ""; - printf_filtered ("Detaching from program: %s %s\n", - exec_file, target_pid_to_str (inferior_ptid)); - fflush (stdout); - } - if (args) - signo = atoi (args); - - do_detach (signo); - inferior_ptid = null_ptid; - unpush_target (&procfs_ops); /* Pop out of handling an inferior */ -} - -static ptid_t -do_attach (ptid_t ptid) -{ - procinfo *pi; - int fail; - - if ((pi = create_procinfo (PIDGET (ptid), 0)) == NULL) - perror ("procfs: out of memory in 'attach'"); - - if (!open_procinfo_files (pi, FD_CTL)) - { - fprintf_filtered (gdb_stderr, "procfs:%d -- ", __LINE__); - sprintf (errmsg, "do_attach: couldn't open /proc file for process %d", - PIDGET (ptid)); - dead_procinfo (pi, errmsg, NOKILL); - } - - /* Stop the process (if it isn't already stopped). */ - if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)) - { - pi->was_stopped = 1; - proc_prettyprint_why (proc_why (pi), proc_what (pi), 1); - } - else - { - pi->was_stopped = 0; - /* Set the process to run again when we close it. */ - if (!proc_set_run_on_last_close (pi)) - dead_procinfo (pi, "do_attach: couldn't set RLC.", NOKILL); - - /* Now stop the process. */ - if (!proc_stop_process (pi)) - dead_procinfo (pi, "do_attach: couldn't stop the process.", NOKILL); - pi->ignore_next_sigstop = 1; - } - /* Save some of the /proc state to be restored if we detach. */ - if (!proc_get_traced_faults (pi, &pi->saved_fltset)) - dead_procinfo (pi, "do_attach: couldn't save traced faults.", NOKILL); - if (!proc_get_traced_signals (pi, &pi->saved_sigset)) - dead_procinfo (pi, "do_attach: couldn't save traced signals.", NOKILL); - if (!proc_get_traced_sysentry (pi, pi->saved_entryset)) - dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.", - NOKILL); - if (!proc_get_traced_sysexit (pi, pi->saved_exitset)) - dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.", - NOKILL); - if (!proc_get_held_signals (pi, &pi->saved_sighold)) - dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL); - - if ((fail = procfs_debug_inferior (pi)) != 0) - dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL); - - /* Let GDB know that the inferior was attached. */ - attach_flag = 1; - return MERGEPID (pi->pid, proc_get_current_thread (pi)); -} - -static void -do_detach (int signo) -{ - procinfo *pi; - - /* Find procinfo for the main process */ - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); /* FIXME: threads */ - if (signo) - if (!proc_set_current_signal (pi, signo)) - proc_warn (pi, "do_detach, set_current_signal", __LINE__); - - if (!proc_set_traced_signals (pi, &pi->saved_sigset)) - proc_warn (pi, "do_detach, set_traced_signal", __LINE__); - - if (!proc_set_traced_faults (pi, &pi->saved_fltset)) - proc_warn (pi, "do_detach, set_traced_faults", __LINE__); - - if (!proc_set_traced_sysentry (pi, pi->saved_entryset)) - proc_warn (pi, "do_detach, set_traced_sysentry", __LINE__); - - if (!proc_set_traced_sysexit (pi, pi->saved_exitset)) - proc_warn (pi, "do_detach, set_traced_sysexit", __LINE__); - - if (!proc_set_held_signals (pi, &pi->saved_sighold)) - proc_warn (pi, "do_detach, set_held_signals", __LINE__); - - if (signo || (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))) - if (signo || !(pi->was_stopped) || - query ("Was stopped when attached, make it runnable again? ")) - { - /* Clear any pending signal. */ - if (!proc_clear_current_fault (pi)) - proc_warn (pi, "do_detach, clear_current_fault", __LINE__); - - if (!proc_set_run_on_last_close (pi)) - proc_warn (pi, "do_detach, set_rlc", __LINE__); - } - - attach_flag = 0; - destroy_procinfo (pi); -} - -/* - * fetch_registers - * - * Since the /proc interface cannot give us individual registers, - * we pay no attention to the (regno) argument, and just fetch them all. - * This results in the possibility that we will do unnecessarily many - * fetches, since we may be called repeatedly for individual registers. - * So we cache the results, and mark the cache invalid when the process - * is resumed. - */ - -static void -procfs_fetch_registers (int regno) -{ - gdb_fpregset_t *fpregs; - gdb_gregset_t *gregs; - procinfo *pi; - int pid; - int tid; - - pid = PIDGET (inferior_ptid); - tid = TIDGET (inferior_ptid); - - /* First look up procinfo for the main process. */ - pi = find_procinfo_or_die (pid, 0); - - /* If the event thread is not the same as GDB's requested thread - (ie. inferior_ptid), then look up procinfo for the requested - thread. */ - if ((tid != 0) && - (tid != proc_get_current_thread (pi))) - pi = find_procinfo_or_die (pid, tid); - - if (pi == NULL) - error ("procfs: fetch_registers failed to find procinfo for %s", - target_pid_to_str (inferior_ptid)); - - if ((gregs = proc_get_gregs (pi)) == NULL) - proc_error (pi, "fetch_registers, get_gregs", __LINE__); - - supply_gregset (gregs); - - if (FP0_REGNUM >= 0) /* need floating point? */ - { - if ((regno >= 0 && regno < FP0_REGNUM) || - regno == PC_REGNUM || - (NPC_REGNUM >= 0 && regno == NPC_REGNUM) || - regno == FP_REGNUM || - regno == SP_REGNUM) - return; /* not a floating point register */ - - if ((fpregs = proc_get_fpregs (pi)) == NULL) - proc_error (pi, "fetch_registers, get_fpregs", __LINE__); - - supply_fpregset (fpregs); - } -} - -/* 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, such as - /proc, this makes sure that registers contains all the registers - from the program being debugged. */ - -static void -procfs_prepare_to_store (void) -{ -#ifdef CHILD_PREPARE_TO_STORE - CHILD_PREPARE_TO_STORE (); -#endif -} - -/* - * store_registers - * - * Since the /proc interface will not read individual registers, - * we will cache these requests until the process is resumed, and - * only then write them back to the inferior process. - * - * FIXME: is that a really bad idea? Have to think about cases - * where writing one register might affect the value of others, etc. - */ - -static void -procfs_store_registers (int regno) -{ - gdb_fpregset_t *fpregs; - gdb_gregset_t *gregs; - procinfo *pi; - int pid; - int tid; - - pid = PIDGET (inferior_ptid); - tid = TIDGET (inferior_ptid); - - /* First find procinfo for main process */ - pi = find_procinfo_or_die (pid, 0); - - /* If current lwp for process is not the same as requested thread - (ie. inferior_ptid), then find procinfo for the requested thread. */ - - if ((tid != 0) && - (tid != proc_get_current_thread (pi))) - pi = find_procinfo_or_die (pid, tid); - - if (pi == NULL) - error ("procfs: store_registers: failed to find procinfo for %s", - target_pid_to_str (inferior_ptid)); - - if ((gregs = proc_get_gregs (pi)) == NULL) - proc_error (pi, "store_registers, get_gregs", __LINE__); - - fill_gregset (gregs, regno); - if (!proc_set_gregs (pi)) - proc_error (pi, "store_registers, set_gregs", __LINE__); - - if (FP0_REGNUM >= 0) /* need floating point? */ - { - if ((regno >= 0 && regno < FP0_REGNUM) || - regno == PC_REGNUM || - (NPC_REGNUM >= 0 && regno == NPC_REGNUM) || - regno == FP_REGNUM || - regno == SP_REGNUM) - return; /* not a floating point register */ - - if ((fpregs = proc_get_fpregs (pi)) == NULL) - proc_error (pi, "store_registers, get_fpregs", __LINE__); - - fill_fpregset (fpregs, regno); - if (!proc_set_fpregs (pi)) - proc_error (pi, "store_registers, set_fpregs", __LINE__); - } -} - -static int -syscall_is_lwp_exit (procinfo *pi, int scall) -{ - -#ifdef SYS_lwp_exit - if (scall == SYS_lwp_exit) - return 1; -#endif -#ifdef SYS_lwpexit - if (scall == SYS_lwpexit) - return 1; -#endif - return 0; -} - -static int -syscall_is_exit (procinfo *pi, int scall) -{ -#ifdef SYS_exit - if (scall == SYS_exit) - return 1; -#endif -#ifdef DYNAMIC_SYSCALLS - if (find_syscall (pi, "_exit") == scall) - return 1; -#endif - return 0; -} - -static int -syscall_is_exec (procinfo *pi, int scall) -{ -#ifdef SYS_exec - if (scall == SYS_exec) - return 1; -#endif -#ifdef SYS_execv - if (scall == SYS_execv) - return 1; -#endif -#ifdef SYS_execve - if (scall == SYS_execve) - return 1; -#endif -#ifdef DYNAMIC_SYSCALLS - if (find_syscall (pi, "_execve")) - return 1; - if (find_syscall (pi, "ra_execve")) - return 1; -#endif - return 0; -} - -static int -syscall_is_lwp_create (procinfo *pi, int scall) -{ -#ifdef SYS_lwp_create - if (scall == SYS_lwp_create) - return 1; -#endif -#ifdef SYS_lwpcreate - if (scall == SYS_lwpcreate) - return 1; -#endif - return 0; -} - -/* - * Function: target_wait - * - * Retrieve the next stop event from the child process. - * If child has not stopped yet, wait for it to stop. - * Translate /proc eventcodes (or possibly wait eventcodes) - * into gdb internal event codes. - * - * Return: id of process (and possibly thread) that incurred the event. - * event codes are returned thru a pointer parameter. - */ - -static ptid_t -procfs_wait (ptid_t ptid, struct target_waitstatus *status) -{ - /* First cut: loosely based on original version 2.1 */ - procinfo *pi; - int wstat; - int temp_tid; - ptid_t retval, temp_ptid; - int why, what, flags; - int retry = 0; - -wait_again: - - retry++; - wstat = 0; - retval = pid_to_ptid (-1); - - /* Find procinfo for main process */ - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - if (pi) - { - /* We must assume that the status is stale now... */ - pi->status_valid = 0; - pi->gregs_valid = 0; - pi->fpregs_valid = 0; - -#if 0 /* just try this out... */ - flags = proc_flags (pi); - why = proc_why (pi); - if ((flags & PR_STOPPED) && (why == PR_REQUESTED)) - pi->status_valid = 0; /* re-read again, IMMEDIATELY... */ -#endif - /* If child is not stopped, wait for it to stop. */ - if (!(proc_flags (pi) & (PR_STOPPED | PR_ISTOP)) && - !proc_wait_for_stop (pi)) - { - /* wait_for_stop failed: has the child terminated? */ - if (errno == ENOENT) - { - int wait_retval; - - /* /proc file not found; presumably child has terminated. */ - wait_retval = wait (&wstat); /* "wait" for the child's exit */ - - if (wait_retval != PIDGET (inferior_ptid)) /* wrong child? */ - error ("procfs: couldn't stop process %d: wait returned %d\n", - PIDGET (inferior_ptid), wait_retval); - /* FIXME: might I not just use waitpid? - Or try find_procinfo to see if I know about this child? */ - retval = pid_to_ptid (wait_retval); - } - else if (errno == EINTR) - goto wait_again; - else - { - /* Unknown error from wait_for_stop. */ - proc_error (pi, "target_wait (wait_for_stop)", __LINE__); - } - } - else - { - /* This long block is reached if either: - a) the child was already stopped, or - b) we successfully waited for the child with wait_for_stop. - This block will analyze the /proc status, and translate it - into a waitstatus for GDB. - - If we actually had to call wait because the /proc file - is gone (child terminated), then we skip this block, - because we already have a waitstatus. */ - - flags = proc_flags (pi); - why = proc_why (pi); - what = proc_what (pi); - - if (flags & (PR_STOPPED | PR_ISTOP)) - { -#ifdef PR_ASYNC - /* If it's running async (for single_thread control), - set it back to normal again. */ - if (flags & PR_ASYNC) - if (!proc_unset_async (pi)) - proc_error (pi, "target_wait, unset_async", __LINE__); -#endif - - if (info_verbose) - proc_prettyprint_why (why, what, 1); - - /* The 'pid' we will return to GDB is composed of - the process ID plus the lwp ID. */ - retval = MERGEPID (pi->pid, proc_get_current_thread (pi)); - - switch (why) { - case PR_SIGNALLED: - wstat = (what << 8) | 0177; - break; - case PR_SYSENTRY: - if (syscall_is_lwp_exit (pi, what)) - { - printf_filtered ("[%s exited]\n", - target_pid_to_str (retval)); - delete_thread (retval); - status->kind = TARGET_WAITKIND_SPURIOUS; - return retval; - } - else if (syscall_is_exit (pi, what)) - { - /* Handle SYS_exit call only */ - /* Stopped at entry to SYS_exit. - Make it runnable, resume it, then use - the wait system call to get its exit code. - Proc_run_process always clears the current - fault and signal. - Then return its exit status. */ - pi->status_valid = 0; - wstat = 0; - /* FIXME: what we should do is return - TARGET_WAITKIND_SPURIOUS. */ - if (!proc_run_process (pi, 0, 0)) - proc_error (pi, "target_wait, run_process", __LINE__); - if (attach_flag) - { - /* Don't call wait: simulate waiting for exit, - return a "success" exit code. Bogus: what if - it returns something else? */ - wstat = 0; - retval = inferior_ptid; /* ? ? ? */ - } - else - { - int temp = wait (&wstat); - - /* FIXME: shouldn't I make sure I get the right - event from the right process? If (for - instance) I have killed an earlier inferior - process but failed to clean up after it - somehow, I could get its termination event - here. */ - - /* If wait returns -1, that's what we return to GDB. */ - if (temp < 0) - retval = pid_to_ptid (temp); - } - } - else - { - printf_filtered ("procfs: trapped on entry to "); - proc_prettyprint_syscall (proc_what (pi), 0); - printf_filtered ("\n"); -#ifndef PIOCSSPCACT - { - long i, nsysargs, *sysargs; - - if ((nsysargs = proc_nsysarg (pi)) > 0 && - (sysargs = proc_sysargs (pi)) != NULL) - { - printf_filtered ("%ld syscall arguments:\n", nsysargs); - for (i = 0; i < nsysargs; i++) - printf_filtered ("#%ld: 0x%08lx\n", - i, sysargs[i]); - } - - } -#endif - if (status) - { - /* How to exit gracefully, returning "unknown event" */ - status->kind = TARGET_WAITKIND_SPURIOUS; - return inferior_ptid; - } - else - { - /* How to keep going without returning to wfi: */ - target_resume (ptid, 0, TARGET_SIGNAL_0); - goto wait_again; - } - } - break; - case PR_SYSEXIT: - if (syscall_is_exec (pi, what)) - { - /* Hopefully this is our own "fork-child" execing - the real child. Hoax this event into a trap, and - GDB will see the child about to execute its start - address. */ - wstat = (SIGTRAP << 8) | 0177; - } - else if (syscall_is_lwp_create (pi, what)) - { - /* - * This syscall is somewhat like fork/exec. - * We will get the event twice: once for the parent LWP, - * and once for the child. We should already know about - * the parent LWP, but the child will be new to us. So, - * whenever we get this event, if it represents a new - * thread, simply add the thread to the list. - */ - - /* If not in procinfo list, add it. */ - temp_tid = proc_get_current_thread (pi); - if (!find_procinfo (pi->pid, temp_tid)) - create_procinfo (pi->pid, temp_tid); - - temp_ptid = MERGEPID (pi->pid, temp_tid); - /* If not in GDB's thread list, add it. */ - if (!in_thread_list (temp_ptid)) - { - printf_filtered ("[New %s]\n", - target_pid_to_str (temp_ptid)); - add_thread (temp_ptid); - } - /* Return to WFI, but tell it to immediately resume. */ - status->kind = TARGET_WAITKIND_SPURIOUS; - return inferior_ptid; - } - else if (syscall_is_lwp_exit (pi, what)) - { - printf_filtered ("[%s exited]\n", - target_pid_to_str (retval)); - delete_thread (retval); - status->kind = TARGET_WAITKIND_SPURIOUS; - return retval; - } - else if (0) - { - /* FIXME: Do we need to handle SYS_sproc, - SYS_fork, or SYS_vfork here? The old procfs - seemed to use this event to handle threads on - older (non-LWP) systems, where I'm assuming - that threads were actually separate processes. - Irix, maybe? Anyway, low priority for now. */ - } - else - { - printf_filtered ("procfs: trapped on exit from "); - proc_prettyprint_syscall (proc_what (pi), 0); - printf_filtered ("\n"); -#ifndef PIOCSSPCACT - { - long i, nsysargs, *sysargs; - - if ((nsysargs = proc_nsysarg (pi)) > 0 && - (sysargs = proc_sysargs (pi)) != NULL) - { - printf_filtered ("%ld syscall arguments:\n", nsysargs); - for (i = 0; i < nsysargs; i++) - printf_filtered ("#%ld: 0x%08lx\n", - i, sysargs[i]); - } - } -#endif - status->kind = TARGET_WAITKIND_SPURIOUS; - return inferior_ptid; - } - break; - case PR_REQUESTED: -#if 0 /* FIXME */ - wstat = (SIGSTOP << 8) | 0177; - break; -#else - if (retry < 5) - { - printf_filtered ("Retry #%d:\n", retry); - pi->status_valid = 0; - goto wait_again; - } - else - { - /* If not in procinfo list, add it. */ - temp_tid = proc_get_current_thread (pi); - if (!find_procinfo (pi->pid, temp_tid)) - create_procinfo (pi->pid, temp_tid); - - /* If not in GDB's thread list, add it. */ - temp_ptid = MERGEPID (pi->pid, temp_tid); - if (!in_thread_list (temp_ptid)) - { - printf_filtered ("[New %s]\n", - target_pid_to_str (temp_ptid)); - add_thread (temp_ptid); - } - - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = 0; - return retval; - } -#endif - case PR_JOBCONTROL: - wstat = (what << 8) | 0177; - break; - case PR_FAULTED: - switch (what) { /* FIXME: FAULTED_USE_SIGINFO */ -#ifdef FLTWATCH - case FLTWATCH: - wstat = (SIGTRAP << 8) | 0177; - break; -#endif -#ifdef FLTKWATCH - case FLTKWATCH: - wstat = (SIGTRAP << 8) | 0177; - break; -#endif - /* FIXME: use si_signo where possible. */ - case FLTPRIV: -#if (FLTILL != FLTPRIV) /* avoid "duplicate case" error */ - case FLTILL: -#endif - wstat = (SIGILL << 8) | 0177; - break; - case FLTBPT: -#if (FLTTRACE != FLTBPT) /* avoid "duplicate case" error */ - case FLTTRACE: -#endif - wstat = (SIGTRAP << 8) | 0177; - break; - case FLTSTACK: - case FLTACCESS: -#if (FLTBOUNDS != FLTSTACK) /* avoid "duplicate case" error */ - case FLTBOUNDS: -#endif - wstat = (SIGSEGV << 8) | 0177; - break; - case FLTIOVF: - case FLTIZDIV: -#if (FLTFPE != FLTIOVF) /* avoid "duplicate case" error */ - case FLTFPE: -#endif - wstat = (SIGFPE << 8) | 0177; - break; - case FLTPAGE: /* Recoverable page fault */ - default: /* FIXME: use si_signo if possible for fault */ - retval = pid_to_ptid (-1); - printf_filtered ("procfs:%d -- ", __LINE__); - printf_filtered ("child stopped for unknown reason:\n"); - proc_prettyprint_why (why, what, 1); - error ("... giving up..."); - break; - } - break; /* case PR_FAULTED: */ - default: /* switch (why) unmatched */ - printf_filtered ("procfs:%d -- ", __LINE__); - printf_filtered ("child stopped for unknown reason:\n"); - proc_prettyprint_why (why, what, 1); - error ("... giving up..."); - break; - } - /* - * Got this far without error: - * If retval isn't in the threads database, add it. - */ - if (PIDGET (retval) > 0 && - !ptid_equal (retval, inferior_ptid) && - !in_thread_list (retval)) - { - /* - * We have a new thread. - * We need to add it both to GDB's list and to our own. - * If we don't create a procinfo, resume may be unhappy - * later. - */ - printf_filtered ("[New %s]\n", target_pid_to_str (retval)); - add_thread (retval); - if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL) - create_procinfo (PIDGET (retval), TIDGET (retval)); - - /* In addition, it's possible that this is the first - * new thread we've seen, in which case we may not - * have created entries for inferior_ptid yet. - */ - if (TIDGET (inferior_ptid) != 0) - { - if (!in_thread_list (inferior_ptid)) - add_thread (inferior_ptid); - if (find_procinfo (PIDGET (inferior_ptid), - TIDGET (inferior_ptid)) == NULL) - create_procinfo (PIDGET (inferior_ptid), - TIDGET (inferior_ptid)); - } - } - } - else /* flags do not indicate STOPPED */ - { - /* surely this can't happen... */ - printf_filtered ("procfs:%d -- process not stopped.\n", - __LINE__); - proc_prettyprint_flags (flags, 1); - error ("procfs: ...giving up..."); - } - } - - if (status) - store_waitstatus (status, wstat); - } - - return retval; -} - -/* Transfer LEN bytes between GDB address MYADDR and target address - MEMADDR. If DOWRITE is non-zero, transfer them to the target, - otherwise transfer them from the target. TARGET is unused. - - The return value is 0 if an error occurred or no bytes were - transferred. Otherwise, it will be a positive value which - indicates the number of bytes transferred between gdb and the - target. (Note that the interface also makes provisions for - negative values, but this capability isn't implemented here.) */ - -static int -procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite, - struct mem_attrib *attrib, struct target_ops *target) -{ - procinfo *pi; - int nbytes = 0; - - /* Find procinfo for main process */ - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - if (pi->as_fd == 0 && - open_procinfo_files (pi, FD_AS) == 0) - { - proc_warn (pi, "xfer_memory, open_proc_files", __LINE__); - return 0; - } - - if (lseek (pi->as_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr) - { - if (dowrite) - { -#ifdef NEW_PROC_API - PROCFS_NOTE ("write memory: "); -#else - PROCFS_NOTE ("write memory: \n"); -#endif - nbytes = write (pi->as_fd, myaddr, len); - } - else - { - PROCFS_NOTE ("read memory: \n"); - nbytes = read (pi->as_fd, myaddr, len); - } - if (nbytes < 0) - { - nbytes = 0; - } - } - return nbytes; -} - -/* - * Function: invalidate_cache - * - * Called by target_resume before making child runnable. - * Mark cached registers and status's invalid. - * If there are "dirty" caches that need to be written back - * to the child process, do that. - * - * File descriptors are also cached. - * As they are a limited resource, we cannot hold onto them indefinitely. - * However, as they are expensive to open, we don't want to throw them - * away indescriminately either. As a compromise, we will keep the - * file descriptors for the parent process, but discard any file - * descriptors we may have accumulated for the threads. - * - * Return value: - * As this function is called by iterate_over_threads, it always - * returns zero (so that iterate_over_threads will keep iterating). - */ - - -static int -invalidate_cache (procinfo *parent, procinfo *pi, void *ptr) -{ - /* - * About to run the child; invalidate caches and do any other cleanup. - */ - -#if 0 - if (pi->gregs_dirty) - if (parent == NULL || - proc_get_current_thread (parent) != pi->tid) - if (!proc_set_gregs (pi)) /* flush gregs cache */ - proc_warn (pi, "target_resume, set_gregs", - __LINE__); - if (FP0_REGNUM >= 0) - if (pi->fpregs_dirty) - if (parent == NULL || - proc_get_current_thread (parent) != pi->tid) - if (!proc_set_fpregs (pi)) /* flush fpregs cache */ - proc_warn (pi, "target_resume, set_fpregs", - __LINE__); -#endif - - if (parent != NULL) - { - /* The presence of a parent indicates that this is an LWP. - Close any file descriptors that it might have open. - We don't do this to the master (parent) procinfo. */ - - close_procinfo_files (pi); - } - pi->gregs_valid = 0; - pi->fpregs_valid = 0; -#if 0 - pi->gregs_dirty = 0; - pi->fpregs_dirty = 0; -#endif - pi->status_valid = 0; - pi->threads_valid = 0; - - return 0; -} - -#if 0 -/* - * Function: make_signal_thread_runnable - * - * A callback function for iterate_over_threads. - * Find the asynchronous signal thread, and make it runnable. - * See if that helps matters any. - */ - -static int -make_signal_thread_runnable (procinfo *process, procinfo *pi, void *ptr) -{ -#ifdef PR_ASLWP - if (proc_flags (pi) & PR_ASLWP) - { - if (!proc_run_process (pi, 0, -1)) - proc_error (pi, "make_signal_thread_runnable", __LINE__); - return 1; - } -#endif - return 0; -} -#endif - -/* - * Function: target_resume - * - * Make the child process runnable. Normally we will then call - * procfs_wait and wait for it to stop again (unles gdb is async). - * - * Arguments: - * step: if true, then arrange for the child to stop again - * after executing a single instruction. - * signo: if zero, then cancel any pending signal. - * If non-zero, then arrange for the indicated signal - * to be delivered to the child when it runs. - * pid: if -1, then allow any child thread to run. - * if non-zero, then allow only the indicated thread to run. - ******* (not implemented yet) - */ - -static void -procfs_resume (ptid_t ptid, int step, enum target_signal signo) -{ - procinfo *pi, *thread; - int native_signo; - - /* 2.1: - prrun.prflags |= PRSVADDR; - prrun.pr_vaddr = $PC; set resume address - prrun.prflags |= PRSTRACE; trace signals in pr_trace (all) - prrun.prflags |= PRSFAULT; trace faults in pr_fault (all but PAGE) - prrun.prflags |= PRCFAULT; clear current fault. - - PRSTRACE and PRSFAULT can be done by other means - (proc_trace_signals, proc_trace_faults) - PRSVADDR is unnecessary. - PRCFAULT may be replaced by a PIOCCFAULT call (proc_clear_current_fault) - This basically leaves PRSTEP and PRCSIG. - PRCSIG is like PIOCSSIG (proc_clear_current_signal). - So basically PR_STEP is the sole argument that must be passed - to proc_run_process (for use in the prrun struct by ioctl). */ - - /* Find procinfo for main process */ - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - - /* First cut: ignore pid argument */ - errno = 0; - - /* Convert signal to host numbering. */ - if (signo == 0 || - (signo == TARGET_SIGNAL_STOP && pi->ignore_next_sigstop)) - native_signo = 0; - else - native_signo = target_signal_to_host (signo); - - pi->ignore_next_sigstop = 0; - - /* Running the process voids all cached registers and status. */ - /* Void the threads' caches first */ - proc_iterate_over_threads (pi, invalidate_cache, NULL); - /* Void the process procinfo's caches. */ - invalidate_cache (NULL, pi, NULL); - - if (PIDGET (ptid) != -1) - { - /* Resume a specific thread, presumably suppressing the others. */ - thread = find_procinfo (PIDGET (ptid), TIDGET (ptid)); - if (thread != NULL) - { - if (thread->tid != 0) - { - /* We're to resume a specific thread, and not the others. - * Set the child process's PR_ASYNC flag. - */ -#ifdef PR_ASYNC - if (!proc_set_async (pi)) - proc_error (pi, "target_resume, set_async", __LINE__); -#endif -#if 0 - proc_iterate_over_threads (pi, - make_signal_thread_runnable, - NULL); -#endif - pi = thread; /* substitute the thread's procinfo for run */ - } - } - } - - if (!proc_run_process (pi, step, native_signo)) - { - if (errno == EBUSY) - warning ("resume: target already running. Pretend to resume, and hope for the best!\n"); - else - proc_error (pi, "target_resume", __LINE__); - } -} - -/* - * Function: register_gdb_signals - * - * Traverse the list of signals that GDB knows about - * (see "handle" command), and arrange for the target - * to be stopped or not, according to these settings. - * - * Returns non-zero for success, zero for failure. - */ - -static int -register_gdb_signals (procinfo *pi, gdb_sigset_t *signals) -{ - int signo; - - for (signo = 0; signo < NSIG; signo ++) - if (signal_stop_state (target_signal_from_host (signo)) == 0 && - signal_print_state (target_signal_from_host (signo)) == 0 && - signal_pass_state (target_signal_from_host (signo)) == 1) - prdelset (signals, signo); - else - praddset (signals, signo); - - return proc_set_traced_signals (pi, signals); -} - -/* - * Function: target_notice_signals - * - * Set up to trace signals in the child process. - */ - -static void -procfs_notice_signals (ptid_t ptid) -{ - gdb_sigset_t signals; - procinfo *pi = find_procinfo_or_die (PIDGET (ptid), 0); - - if (proc_get_traced_signals (pi, &signals) && - register_gdb_signals (pi, &signals)) - return; - else - proc_error (pi, "notice_signals", __LINE__); -} - -/* - * Function: target_files_info - * - * Print status information about the child process. - */ - -static void -procfs_files_info (struct target_ops *ignore) -{ - printf_filtered ("\tUsing the running image of %s %s via /proc.\n", - attach_flag? "attached": "child", - target_pid_to_str (inferior_ptid)); -} - -/* - * Function: target_open - * - * A dummy: you don't open procfs. - */ - -static void -procfs_open (char *args, int from_tty) -{ - error ("Use the \"run\" command to start a Unix child process."); -} - -/* - * Function: target_can_run - * - * This tells GDB that this target vector can be invoked - * for "run" or "attach". - */ - -int procfs_suppress_run = 0; /* Non-zero if procfs should pretend not to - be a runnable target. Used by targets - that can sit atop procfs, such as solaris - thread support. */ - - -static int -procfs_can_run (void) -{ - /* This variable is controlled by modules that sit atop procfs that - may layer their own process structure atop that provided here. - sol-thread.c does this because of the Solaris two-level thread - model. */ - - /* NOTE: possibly obsolete -- use the thread_stratum approach instead. */ - - return !procfs_suppress_run; -} - -/* - * Function: target_stop - * - * Stop the child process asynchronously, as when the - * gdb user types control-c or presses a "stop" button. - * - * Works by sending kill(SIGINT) to the child's process group. - */ - -static void -procfs_stop (void) -{ - extern pid_t inferior_process_group; - - kill (-inferior_process_group, SIGINT); -} - -/* - * Function: unconditionally_kill_inferior - * - * Make it die. Wait for it to die. Clean up after it. - * Note: this should only be applied to the real process, - * not to an LWP, because of the check for parent-process. - * If we need this to work for an LWP, it needs some more logic. - */ - -static void -unconditionally_kill_inferior (procinfo *pi) -{ - int parent_pid; - - parent_pid = proc_parent_pid (pi); -#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL - /* FIXME: use access functions */ - /* Alpha OSF/1-3.x procfs needs a clear of the current signal - before the PIOCKILL, otherwise it might generate a corrupted core - file for the inferior. */ - if (ioctl (pi->ctl_fd, PIOCSSIG, NULL) < 0) - { - printf_filtered ("unconditionally_kill: SSIG failed!\n"); - } -#endif -#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL - /* Alpha OSF/1-2.x procfs needs a PIOCSSIG call with a SIGKILL signal - to kill the inferior, otherwise it might remain stopped with a - pending SIGKILL. - We do not check the result of the PIOCSSIG, the inferior might have - died already. */ - { - gdb_siginfo_t newsiginfo; - - memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); - newsiginfo.si_signo = SIGKILL; - newsiginfo.si_code = 0; - newsiginfo.si_errno = 0; - newsiginfo.si_pid = getpid (); - newsiginfo.si_uid = getuid (); - /* FIXME: use proc_set_current_signal */ - ioctl (pi->ctl_fd, PIOCSSIG, &newsiginfo); - } -#else /* PROCFS_NEED_PIOCSSIG_FOR_KILL */ - if (!proc_kill (pi, SIGKILL)) - proc_error (pi, "unconditionally_kill, proc_kill", __LINE__); -#endif /* PROCFS_NEED_PIOCSSIG_FOR_KILL */ - destroy_procinfo (pi); - - /* If pi is GDB's child, wait for it to die. */ - if (parent_pid == getpid ()) - /* FIXME: should we use waitpid to make sure we get the right event? - Should we check the returned event? */ - { -#if 0 - int status, ret; - - ret = waitpid (pi->pid, &status, 0); -#else - wait (NULL); -#endif - } -} - -/* - * Function: target_kill_inferior - * - * We're done debugging it, and we want it to go away. - * Then we want GDB to forget all about it. - */ - -static void -procfs_kill_inferior (void) -{ - if (!ptid_equal (inferior_ptid, null_ptid)) /* ? */ - { - /* Find procinfo for main process */ - procinfo *pi = find_procinfo (PIDGET (inferior_ptid), 0); - - if (pi) - unconditionally_kill_inferior (pi); - target_mourn_inferior (); - } -} - -/* - * Function: target_mourn_inferior - * - * Forget we ever debugged this thing! - */ - -static void -procfs_mourn_inferior (void) -{ - procinfo *pi; - - if (!ptid_equal (inferior_ptid, null_ptid)) - { - /* Find procinfo for main process */ - pi = find_procinfo (PIDGET (inferior_ptid), 0); - if (pi) - destroy_procinfo (pi); - } - unpush_target (&procfs_ops); - generic_mourn_inferior (); -} - -/* - * Function: init_inferior - * - * When GDB forks to create a runnable inferior process, - * this function is called on the parent side of the fork. - * It's job is to do whatever is necessary to make the child - * ready to be debugged, and then wait for the child to synchronize. - */ - -static void -procfs_init_inferior (int pid) -{ - procinfo *pi; - gdb_sigset_t signals; - int fail; - - /* This routine called on the parent side (GDB side) - after GDB forks the inferior. */ - - push_target (&procfs_ops); - - if ((pi = create_procinfo (pid, 0)) == NULL) - perror ("procfs: out of memory in 'init_inferior'"); - - if (!open_procinfo_files (pi, FD_CTL)) - proc_error (pi, "init_inferior, open_proc_files", __LINE__); - - /* - xmalloc // done - open_procinfo_files // done - link list // done - prfillset (trace) - procfs_notice_signals - prfillset (fault) - prdelset (FLTPAGE) - PIOCWSTOP - PIOCSFAULT - */ - - /* If not stopped yet, wait for it to stop. */ - if (!(proc_flags (pi) & PR_STOPPED) && - !(proc_wait_for_stop (pi))) - dead_procinfo (pi, "init_inferior: wait_for_stop failed", KILL); - - /* Save some of the /proc state to be restored if we detach. */ - /* FIXME: Why? In case another debugger was debugging it? - We're it's parent, for Ghu's sake! */ - if (!proc_get_traced_signals (pi, &pi->saved_sigset)) - proc_error (pi, "init_inferior, get_traced_signals", __LINE__); - if (!proc_get_held_signals (pi, &pi->saved_sighold)) - proc_error (pi, "init_inferior, get_held_signals", __LINE__); - if (!proc_get_traced_faults (pi, &pi->saved_fltset)) - proc_error (pi, "init_inferior, get_traced_faults", __LINE__); - if (!proc_get_traced_sysentry (pi, pi->saved_entryset)) - proc_error (pi, "init_inferior, get_traced_sysentry", __LINE__); - if (!proc_get_traced_sysexit (pi, pi->saved_exitset)) - proc_error (pi, "init_inferior, get_traced_sysexit", __LINE__); - - /* Register to trace selected signals in the child. */ - prfillset (&signals); - if (!register_gdb_signals (pi, &signals)) - proc_error (pi, "init_inferior, register_signals", __LINE__); - - if ((fail = procfs_debug_inferior (pi)) != 0) - proc_error (pi, "init_inferior (procfs_debug_inferior)", fail); - - /* FIXME: logically, we should really be turning OFF run-on-last-close, - and possibly even turning ON kill-on-last-close at this point. But - I can't make that change without careful testing which I don't have - time to do right now... */ - /* Turn on run-on-last-close flag so that the child - will die if GDB goes away for some reason. */ - if (!proc_set_run_on_last_close (pi)) - proc_error (pi, "init_inferior, set_RLC", __LINE__); - - /* The 'process ID' we return to GDB is composed of - the actual process ID plus the lwp ID. */ - inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi)); - -#ifdef START_INFERIOR_TRAPS_EXPECTED - startup_inferior (START_INFERIOR_TRAPS_EXPECTED); -#else - /* One trap to exec the shell, one to exec the program being debugged. */ - startup_inferior (2); -#endif /* START_INFERIOR_TRAPS_EXPECTED */ -} - -/* - * Function: set_exec_trap - * - * When GDB forks to create a new process, this function is called - * on the child side of the fork before GDB exec's the user program. - * Its job is to make the child minimally debuggable, so that the - * parent GDB process can connect to the child and take over. - * This function should do only the minimum to make that possible, - * and to synchronize with the parent process. The parent process - * should take care of the details. - */ - -static void -procfs_set_exec_trap (void) -{ - /* This routine called on the child side (inferior side) - after GDB forks the inferior. It must use only local variables, - because it may be sharing data space with its parent. */ - - procinfo *pi; - sysset_t *exitset; - - if ((pi = create_procinfo (getpid (), 0)) == NULL) - perror_with_name ("procfs: create_procinfo failed in child."); - - if (open_procinfo_files (pi, FD_CTL) == 0) - { - proc_warn (pi, "set_exec_trap, open_proc_files", __LINE__); - gdb_flush (gdb_stderr); - /* no need to call "dead_procinfo", because we're going to exit. */ - _exit (127); - } - -#ifdef PRFS_STOPEXEC /* defined on OSF */ - /* OSF method for tracing exec syscalls. Quoting: - Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace - exits from exec system calls because of the user level loader. */ - /* FIXME: make nice and maybe move into an access function. */ - { - int prfs_flags; - - if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0) - { - proc_warn (pi, "set_exec_trap (PIOCGSPCACT)", __LINE__); - gdb_flush (gdb_stderr); - _exit (127); - } - prfs_flags |= PRFS_STOPEXEC; - - if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0) - { - proc_warn (pi, "set_exec_trap (PIOCSSPCACT)", __LINE__); - gdb_flush (gdb_stderr); - _exit (127); - } - } -#else /* not PRFS_STOPEXEC */ - /* Everyone else's (except OSF) method for tracing exec syscalls */ - /* GW: Rationale... - Not all systems with /proc have all the exec* syscalls with the same - names. On the SGI, for example, there is no SYS_exec, but there - *is* a SYS_execv. So, we try to account for that. */ - - exitset = sysset_t_alloc (pi); - gdb_premptysysset (exitset); -#ifdef SYS_exec - gdb_praddsysset (exitset, SYS_exec); -#endif -#ifdef SYS_execve - gdb_praddsysset (exitset, SYS_execve); -#endif -#ifdef SYS_execv - gdb_praddsysset (exitset, SYS_execv); -#endif -#ifdef DYNAMIC_SYSCALLS - { - int callnum = find_syscall (pi, "execve"); - - if (callnum >= 0) - gdb_praddsysset (exitset, callnum); - - callnum = find_syscall (pi, "ra_execve"); - if (callnum >= 0) - gdb_praddsysset (exitset, callnum); - } -#endif /* DYNAMIC_SYSCALLS */ - - if (!proc_set_traced_sysexit (pi, exitset)) - { - proc_warn (pi, "set_exec_trap, set_traced_sysexit", __LINE__); - gdb_flush (gdb_stderr); - _exit (127); - } -#endif /* PRFS_STOPEXEC */ - - /* FIXME: should this be done in the parent instead? */ - /* Turn off inherit on fork flag so that all grand-children - of gdb start with tracing flags cleared. */ - if (!proc_unset_inherit_on_fork (pi)) - proc_warn (pi, "set_exec_trap, unset_inherit", __LINE__); - - /* Turn off run on last close flag, so that the child process - cannot run away just because we close our handle on it. - We want it to wait for the parent to attach. */ - if (!proc_unset_run_on_last_close (pi)) - proc_warn (pi, "set_exec_trap, unset_RLC", __LINE__); - - /* FIXME: No need to destroy the procinfo -- - we have our own address space, and we're about to do an exec! */ - /*destroy_procinfo (pi);*/ -} - -/* - * Function: create_inferior - * - * This function is called BEFORE gdb forks the inferior process. - * Its only real responsibility is to set things up for the fork, - * and tell GDB which two functions to call after the fork (one - * for the parent, and one for the child). - * - * This function does a complicated search for a unix shell program, - * which it then uses to parse arguments and environment variables - * to be sent to the child. I wonder whether this code could not - * be abstracted out and shared with other unix targets such as - * infptrace? - */ - -static void -procfs_create_inferior (char *exec_file, char *allargs, char **env) -{ - char *shell_file = getenv ("SHELL"); - char *tryname; - if (shell_file != NULL && strchr (shell_file, '/') == NULL) - { - - /* We will be looking down the PATH to find shell_file. If we - just do this the normal way (via execlp, which operates by - attempting an exec for each element of the PATH until it - finds one which succeeds), then there will be an exec for - each failed attempt, each of which will cause a PR_SYSEXIT - stop, and we won't know how to distinguish the PR_SYSEXIT's - for these failed execs with the ones for successful execs - (whether the exec has succeeded is stored at that time in the - carry bit or some such architecture-specific and - non-ABI-specified place). - - So I can't think of anything better than to search the PATH - now. This has several disadvantages: (1) There is a race - condition; if we find a file now and it is deleted before we - exec it, we lose, even if the deletion leaves a valid file - further down in the PATH, (2) there is no way to know exactly - what an executable (in the sense of "capable of being - exec'd") file is. Using access() loses because it may lose - if the caller is the superuser; failing to use it loses if - there are ACLs or some such. */ - - char *p; - char *p1; - /* FIXME-maybe: might want "set path" command so user can change what - path is used from within GDB. */ - char *path = getenv ("PATH"); - int len; - struct stat statbuf; - - if (path == NULL) - path = "/bin:/usr/bin"; - - tryname = alloca (strlen (path) + strlen (shell_file) + 2); - for (p = path; p != NULL; p = p1 ? p1 + 1: NULL) - { - p1 = strchr (p, ':'); - if (p1 != NULL) - len = p1 - p; - else - len = strlen (p); - strncpy (tryname, p, len); - tryname[len] = '\0'; - strcat (tryname, "/"); - strcat (tryname, shell_file); - if (access (tryname, X_OK) < 0) - continue; - if (stat (tryname, &statbuf) < 0) - continue; - if (!S_ISREG (statbuf.st_mode)) - /* We certainly need to reject directories. I'm not quite - as sure about FIFOs, sockets, etc., but I kind of doubt - that people want to exec() these things. */ - continue; - break; - } - if (p == NULL) - /* Not found. This must be an error rather than merely passing - the file to execlp(), because execlp() would try all the - exec()s, causing GDB to get confused. */ - error ("procfs:%d -- Can't find shell %s in PATH", - __LINE__, shell_file); - - shell_file = tryname; - } - - fork_inferior (exec_file, allargs, env, procfs_set_exec_trap, - procfs_init_inferior, NULL, shell_file); - - /* We are at the first instruction we care about. */ - /* Pedal to the metal... */ - - proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0); -} - -/* - * Function: notice_thread - * - * Callback for find_new_threads. - * Calls "add_thread". - */ - -static int -procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr) -{ - ptid_t gdb_threadid = MERGEPID (pi->pid, thread->tid); - - if (!in_thread_list (gdb_threadid)) - add_thread (gdb_threadid); - - return 0; -} - -/* - * Function: target_find_new_threads - * - * Query all the threads that the target knows about, - * and give them back to GDB to add to its list. - */ - -void -procfs_find_new_threads (void) -{ - procinfo *pi; - - /* Find procinfo for main process */ - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - proc_update_threads (pi); - proc_iterate_over_threads (pi, procfs_notice_thread, NULL); -} - -/* - * Function: target_thread_alive - * - * Return true if the thread is still 'alive'. - * - * This guy doesn't really seem to be doing his job. - * Got to investigate how to tell when a thread is really gone. - */ - -static int -procfs_thread_alive (ptid_t ptid) -{ - int proc, thread; - procinfo *pi; - - proc = PIDGET (ptid); - thread = TIDGET (ptid); - /* If I don't know it, it ain't alive! */ - if ((pi = find_procinfo (proc, thread)) == NULL) - return 0; - - /* If I can't get its status, it ain't alive! - What's more, I need to forget about it! */ - if (!proc_get_status (pi)) - { - destroy_procinfo (pi); - return 0; - } - /* I couldn't have got its status if it weren't alive, so it's alive. */ - return 1; -} - -/* - * Function: target_pid_to_str - * - * Return a string to be used to identify the thread in - * the "info threads" display. - */ - -char * -procfs_pid_to_str (ptid_t ptid) -{ - static char buf[80]; - int proc, thread; - procinfo *pi; - - proc = PIDGET (ptid); - thread = TIDGET (ptid); - pi = find_procinfo (proc, thread); - - if (thread == 0) - sprintf (buf, "Process %d", proc); - else - sprintf (buf, "LWP %d", thread); - return &buf[0]; -} - -/* - * Function: procfs_set_watchpoint - * Insert a watchpoint - */ - -int -procfs_set_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rwflag, - int after) -{ -#ifndef UNIXWARE -#ifndef AIX5 - int pflags = 0; - procinfo *pi; - - pi = find_procinfo_or_die (PIDGET (ptid) == -1 ? - PIDGET (inferior_ptid) : PIDGET (ptid), 0); - - /* Translate from GDB's flags to /proc's */ - if (len > 0) /* len == 0 means delete watchpoint */ - { - switch (rwflag) { /* FIXME: need an enum! */ - case hw_write: /* default watchpoint (write) */ - pflags = WRITE_WATCHFLAG; - break; - case hw_read: /* read watchpoint */ - pflags = READ_WATCHFLAG; - break; - case hw_access: /* access watchpoint */ - pflags = READ_WATCHFLAG | WRITE_WATCHFLAG; - break; - case hw_execute: /* execution HW breakpoint */ - pflags = EXEC_WATCHFLAG; - break; - default: /* Something weird. Return error. */ - return -1; - } - if (after) /* Stop after r/w access is completed. */ - pflags |= AFTER_WATCHFLAG; - } - - if (!proc_set_watchpoint (pi, addr, len, pflags)) - { - if (errno == E2BIG) /* Typical error for no resources */ - return -1; /* fail */ - /* GDB may try to remove the same watchpoint twice. - If a remove request returns no match, don't error. */ - if (errno == ESRCH && len == 0) - return 0; /* ignore */ - proc_error (pi, "set_watchpoint", __LINE__); - } -#endif /* AIX5 */ -#endif /* UNIXWARE */ - return 0; -} - -/* - * Function: stopped_by_watchpoint - * - * Returns non-zero if process is stopped on a hardware watchpoint fault, - * else returns zero. - */ - -int -procfs_stopped_by_watchpoint (ptid_t ptid) -{ - procinfo *pi; - - pi = find_procinfo_or_die (PIDGET (ptid) == -1 ? - PIDGET (inferior_ptid) : PIDGET (ptid), 0); - - if (!pi) /* If no process, then not stopped by watchpoint! */ - return 0; - - if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)) - { - if (proc_why (pi) == PR_FAULTED) - { -#ifdef FLTWATCH - if (proc_what (pi) == FLTWATCH) - return 1; -#endif -#ifdef FLTKWATCH - if (proc_what (pi) == FLTKWATCH) - return 1; -#endif - } - } - return 0; -} - -#ifdef TM_I386SOL2_H -/* - * Function: procfs_find_LDT_entry - * - * Input: - * ptid_t ptid; // The GDB-style pid-plus-LWP. - * - * Return: - * pointer to the corresponding LDT entry. - */ - -struct ssd * -procfs_find_LDT_entry (ptid_t ptid) -{ - gdb_gregset_t *gregs; - int key; - procinfo *pi; - - /* Find procinfo for the lwp. */ - if ((pi = find_procinfo (PIDGET (ptid), TIDGET (ptid))) == NULL) - { - warning ("procfs_find_LDT_entry: could not find procinfo for %d:%d.", - PIDGET (ptid), TIDGET (ptid)); - return NULL; - } - /* get its general registers. */ - if ((gregs = proc_get_gregs (pi)) == NULL) - { - warning ("procfs_find_LDT_entry: could not read gregs for %d:%d.", - PIDGET (ptid), TIDGET (ptid)); - return NULL; - } - /* Now extract the GS register's lower 16 bits. */ - key = (*gregs)[GS] & 0xffff; - - /* Find the matching entry and return it. */ - return proc_get_LDT_entry (pi, key); -} -#endif /* TM_I386SOL2_H */ - -/* - * Memory Mappings Functions: - */ - -/* - * Function: iterate_over_mappings - * - * Call a callback function once for each mapping, passing it the mapping, - * an optional secondary callback function, and some optional opaque data. - * Quit and return the first non-zero value returned from the callback. - * - * Arguments: - * pi -- procinfo struct for the process to be mapped. - * func -- callback function to be called by this iterator. - * data -- optional opaque data to be passed to the callback function. - * child_func -- optional secondary function pointer to be passed - * to the child function. - * - * Return: First non-zero return value from the callback function, - * or zero. - */ - -static int -iterate_over_mappings (procinfo *pi, int (*child_func) (), void *data, - int (*func) (struct prmap *map, - int (*child_func) (), - void *data)) -{ - char pathname[MAX_PROC_NAME_SIZE]; - struct prmap *prmaps; - struct prmap *prmap; - int funcstat; - int map_fd; - int nmap; -#ifdef NEW_PROC_API - struct stat sbuf; -#endif - - /* Get the number of mappings, allocate space, - and read the mappings into prmaps. */ -#ifdef NEW_PROC_API - /* Open map fd. */ - sprintf (pathname, "/proc/%d/map", pi->pid); - if ((map_fd = open (pathname, O_RDONLY)) < 0) - proc_error (pi, "iterate_over_mappings (open)", __LINE__); - - /* Make sure it gets closed again. */ - make_cleanup_close (map_fd); - - /* Use stat to determine the file size, and compute - the number of prmap_t objects it contains. */ - if (fstat (map_fd, &sbuf) != 0) - proc_error (pi, "iterate_over_mappings (fstat)", __LINE__); - - nmap = sbuf.st_size / sizeof (prmap_t); - prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); - if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps)) - != (nmap * sizeof (*prmaps))) - proc_error (pi, "iterate_over_mappings (read)", __LINE__); -#else - /* Use ioctl command PIOCNMAP to get number of mappings. */ - if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0) - proc_error (pi, "iterate_over_mappings (PIOCNMAP)", __LINE__); - - prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps)); - if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0) - proc_error (pi, "iterate_over_mappings (PIOCMAP)", __LINE__); -#endif - - for (prmap = prmaps; nmap > 0; prmap++, nmap--) - if ((funcstat = (*func) (prmap, child_func, data)) != 0) - return funcstat; - - return 0; -} - -/* - * Function: solib_mappings_callback - * - * Calls the supplied callback function once for each mapped address - * space in the process. The callback function receives an open - * file descriptor for the file corresponding to that mapped - * address space (if there is one), and the base address of the - * mapped space. Quit when the callback function returns a - * nonzero value, or at teh end of the mappings. - * - * Returns: the first non-zero return value of the callback function, - * or zero. - */ - -int solib_mappings_callback (struct prmap *map, - int (*func) (int, CORE_ADDR), - void *data) -{ - procinfo *pi = data; - int fd; - -#ifdef NEW_PROC_API - char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)]; - - if (map->pr_vaddr == 0 && map->pr_size == 0) - return -1; /* sanity */ - - if (map->pr_mapname[0] == 0) - { - fd = -1; /* no map file */ - } - else - { - sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname); - /* Note: caller's responsibility to close this fd! */ - fd = open_with_retry (name, O_RDONLY); - /* Note: we don't test the above call for failure; - we just pass the FD on as given. Sometimes there is - no file, so the open may return failure, but that's - not a problem. */ - } -#else - fd = ioctl (pi->ctl_fd, PIOCOPENM, &map->pr_vaddr); - /* Note: we don't test the above call for failure; - we just pass the FD on as given. Sometimes there is - no file, so the ioctl may return failure, but that's - not a problem. */ -#endif - return (*func) (fd, (CORE_ADDR) map->pr_vaddr); -} - -/* - * Function: proc_iterate_over_mappings - * - * Uses the unified "iterate_over_mappings" function - * to implement the exported interface to solib-svr4.c. - * - * Given a pointer to a function, call that function once for every - * mapped address space in the process. The callback function - * receives an open file descriptor for the file corresponding to - * that mapped address space (if there is one), and the base address - * of the mapped space. Quit when the callback function returns a - * nonzero value, or at teh end of the mappings. - * - * Returns: the first non-zero return value of the callback function, - * or zero. - */ - -int -proc_iterate_over_mappings (int (*func) (int, CORE_ADDR)) -{ - procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - - return iterate_over_mappings (pi, func, pi, solib_mappings_callback); -} - -/* - * Function: find_memory_regions_callback - * - * Implements the to_find_memory_regions method. - * Calls an external function for each memory region. - * External function will have the signiture: - * - * int callback (CORE_ADDR vaddr, - * unsigned long size, - * int read, int write, int execute, - * void *data); - * - * Returns the integer value returned by the callback. - */ - -static int -find_memory_regions_callback (struct prmap *map, - int (*func) (CORE_ADDR, - unsigned long, - int, int, int, - void *), - void *data) -{ - return (*func) ((CORE_ADDR) map->pr_vaddr, - map->pr_size, - (map->pr_mflags & MA_READ) != 0, - (map->pr_mflags & MA_WRITE) != 0, - (map->pr_mflags & MA_EXEC) != 0, - data); -} - -/* - * Function: proc_find_memory_regions - * - * External interface. Calls a callback function once for each - * mapped memory region in the child process, passing as arguments - * CORE_ADDR virtual_address, - * unsigned long size, - * int read, TRUE if region is readable by the child - * int write, TRUE if region is writable by the child - * int execute TRUE if region is executable by the child. - * - * Stops iterating and returns the first non-zero value - * returned by the callback. - */ - -static int -proc_find_memory_regions (int (*func) (CORE_ADDR, - unsigned long, - int, int, int, - void *), - void *data) -{ - procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - - return iterate_over_mappings (pi, func, data, - find_memory_regions_callback); -} - -/* - * Function: mappingflags - * - * Returns an ascii representation of a memory mapping's flags. - */ - -static char * -mappingflags (flags) - long flags; -{ - static char asciiflags[8]; - - strcpy (asciiflags, "-------"); -#if defined (MA_PHYS) - if (flags & MA_PHYS) - asciiflags[0] = 'd'; -#endif - if (flags & MA_STACK) - asciiflags[1] = 's'; - if (flags & MA_BREAK) - asciiflags[2] = 'b'; - if (flags & MA_SHARED) - asciiflags[3] = 's'; - if (flags & MA_READ) - asciiflags[4] = 'r'; - if (flags & MA_WRITE) - asciiflags[5] = 'w'; - if (flags & MA_EXEC) - asciiflags[6] = 'x'; - return (asciiflags); -} - -/* - * Function: info_mappings_callback - * - * Callback function, does the actual work for 'info proc mappings'. - */ - -/* ARGSUSED */ -static int -info_mappings_callback (struct prmap *map, int (*ignore) (), void *unused) -{ - char *data_fmt_string; - - if (TARGET_ADDR_BIT == 32) - data_fmt_string = "\t%#10lx %#10lx %#10x %#10x %7s\n"; - else - data_fmt_string = " %#18lx %#18lx %#10x %#10x %7s\n"; - - printf_filtered (data_fmt_string, - (unsigned long) map->pr_vaddr, - (unsigned long) map->pr_vaddr + map->pr_size - 1, - map->pr_size, -#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */ - (unsigned int) map->pr_offset, -#else - map->pr_off, -#endif - mappingflags (map->pr_mflags)); - - return 0; -} - -/* - * Function: info_proc_mappings - * - * Implement the "info proc mappings" subcommand. - */ - -static void -info_proc_mappings (procinfo *pi, int summary) -{ - char *header_fmt_string; - - if (TARGET_PTR_BIT == 32) - header_fmt_string = "\t%10s %10s %10s %10s %7s\n"; - else - header_fmt_string = " %18s %18s %10s %10s %7s\n"; - - if (summary) - return; /* No output for summary mode. */ - - printf_filtered ("Mapped address spaces:\n\n"); - printf_filtered (header_fmt_string, - "Start Addr", - " End Addr", - " Size", - " Offset", - "Flags"); - - iterate_over_mappings (pi, NULL, NULL, info_mappings_callback); - printf_filtered ("\n"); -} - -/* - * Function: info_proc_cmd - * - * Implement the "info proc" command. - */ - -static void -info_proc_cmd (char *args, int from_tty) -{ - struct cleanup *old_chain; - procinfo *process = NULL; - procinfo *thread = NULL; - char **argv = NULL; - char *tmp = NULL; - int pid = 0; - int tid = 0; - int mappings = 0; - - old_chain = make_cleanup (null_cleanup, 0); - if (args) - { - if ((argv = buildargv (args)) == NULL) - nomem (0); - else - make_cleanup_freeargv (argv); - } - while (argv != NULL && *argv != NULL) - { - if (isdigit (argv[0][0])) - { - pid = strtoul (argv[0], &tmp, 10); - if (*tmp == '/') - tid = strtoul (++tmp, NULL, 10); - } - else if (argv[0][0] == '/') - { - tid = strtoul (argv[0] + 1, NULL, 10); - } - else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0) - { - mappings = 1; - } - else - { - /* [...] */ - } - argv++; - } - if (pid == 0) - pid = PIDGET (inferior_ptid); - if (pid == 0) - error ("No current process: you must name one."); - else - { - /* Have pid, will travel. - First see if it's a process we're already debugging. */ - process = find_procinfo (pid, 0); - if (process == NULL) - { - /* No. So open a procinfo for it, but - remember to close it again when finished. */ - process = create_procinfo (pid, 0); - make_cleanup (do_destroy_procinfo_cleanup, process); - if (!open_procinfo_files (process, FD_CTL)) - proc_error (process, "info proc, open_procinfo_files", __LINE__); - } - } - if (tid != 0) - thread = create_procinfo (pid, tid); - - if (process) - { - printf_filtered ("process %d flags:\n", process->pid); - proc_prettyprint_flags (proc_flags (process), 1); - if (proc_flags (process) & (PR_STOPPED | PR_ISTOP)) - proc_prettyprint_why (proc_why (process), proc_what (process), 1); - if (proc_get_nthreads (process) > 1) - printf_filtered ("Process has %d threads.\n", - proc_get_nthreads (process)); - } - if (thread) - { - printf_filtered ("thread %d flags:\n", thread->tid); - proc_prettyprint_flags (proc_flags (thread), 1); - if (proc_flags (thread) & (PR_STOPPED | PR_ISTOP)) - proc_prettyprint_why (proc_why (thread), proc_what (thread), 1); - } - - if (mappings) - { - info_proc_mappings (process, 0); - } - - do_cleanups (old_chain); -} - -static void -proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode) -{ - procinfo *pi; - sysset_t *sysset; - int syscallnum = 0; - - if (PIDGET (inferior_ptid) <= 0) - error ("you must be debugging a process to use this command."); - - if (args == NULL || args[0] == 0) - error_no_arg ("system call to trace"); - - pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - if (isdigit (args[0])) - { - syscallnum = atoi (args); - if (entry_or_exit == PR_SYSENTRY) - sysset = proc_get_traced_sysentry (pi, NULL); - else - sysset = proc_get_traced_sysexit (pi, NULL); - - if (sysset == NULL) - proc_error (pi, "proc-trace, get_traced_sysset", __LINE__); - - if (mode == FLAG_SET) - gdb_praddsysset (sysset, syscallnum); - else - gdb_prdelsysset (sysset, syscallnum); - - if (entry_or_exit == PR_SYSENTRY) - { - if (!proc_set_traced_sysentry (pi, sysset)) - proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__); - } - else - { - if (!proc_set_traced_sysexit (pi, sysset)) - proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__); - } - } -} - -static void -proc_trace_sysentry_cmd (char *args, int from_tty) -{ - proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_SET); -} - -static void -proc_trace_sysexit_cmd (char *args, int from_tty) -{ - proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_SET); -} - -static void -proc_untrace_sysentry_cmd (char *args, int from_tty) -{ - proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_RESET); -} - -static void -proc_untrace_sysexit_cmd (char *args, int from_tty) -{ - proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_RESET); -} - - -void -_initialize_procfs (void) -{ - init_procfs_ops (); - add_target (&procfs_ops); - add_info ("proc", info_proc_cmd, - "Show /proc process information about any running process.\n\ -Specify process id, or use the program being debugged by default.\n\ -Specify keyword 'mappings' for detailed info on memory mappings."); - add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd, - "Give a trace of entries into the syscall."); - add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd, - "Give a trace of exits from the syscall."); - add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd, - "Cancel a trace of entries into the syscall."); - add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd, - "Cancel a trace of exits from the syscall."); -} - -/* =================== END, GDB "MODULE" =================== */ - - - -/* miscellaneous stubs: */ -/* The following satisfy a few random symbols mostly created by */ -/* the solaris threads implementation, which I will chase down */ -/* later. */ - -/* - * Return a pid for which we guarantee - * we will be able to find a 'live' procinfo. - */ - -ptid_t -procfs_first_available (void) -{ - return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1); -} - -/* =================== GCORE .NOTE "MODULE" =================== */ -#if defined (UNIXWARE) || defined (PIOCOPENLWP) || defined (PCAGENT) -/* gcore only implemented on solaris and unixware (so far) */ - -static char * -procfs_do_thread_registers (bfd *obfd, ptid_t ptid, - char *note_data, int *note_size) -{ - gdb_gregset_t gregs; - gdb_fpregset_t fpregs; - unsigned long merged_pid; - - merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid); - - fill_gregset (&gregs, -1); -#if defined (UNIXWARE) - note_data = (char *) elfcore_write_lwpstatus (obfd, - note_data, - note_size, - merged_pid, - stop_signal, - &gregs); -#else - note_data = (char *) elfcore_write_prstatus (obfd, - note_data, - note_size, - merged_pid, - stop_signal, - &gregs); -#endif - fill_fpregset (&fpregs, -1); - note_data = (char *) elfcore_write_prfpreg (obfd, - note_data, - note_size, - &fpregs, - sizeof (fpregs)); - return note_data; -} - -struct procfs_corefile_thread_data { - bfd *obfd; - char *note_data; - int *note_size; -}; - -static int -procfs_corefile_thread_callback (procinfo *pi, procinfo *thread, void *data) -{ - struct procfs_corefile_thread_data *args = data; - - if (pi != NULL && thread->tid != 0) - { - ptid_t saved_ptid = inferior_ptid; - inferior_ptid = MERGEPID (pi->pid, thread->tid); - args->note_data = procfs_do_thread_registers (args->obfd, inferior_ptid, - args->note_data, - args->note_size); - inferior_ptid = saved_ptid; - } - return 0; -} - -static char * -procfs_make_note_section (bfd *obfd, int *note_size) -{ - struct cleanup *old_chain; - gdb_gregset_t gregs; - gdb_fpregset_t fpregs; - char fname[16] = {'\0'}; - char psargs[80] = {'\0'}; - procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); - char *note_data = NULL; - char *inf_args; - struct procfs_corefile_thread_data thread_args; - - if (get_exec_file (0)) - { - strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname)); - strncpy (psargs, get_exec_file (0), - sizeof (psargs)); - - inf_args = get_inferior_args (); - if (inf_args && *inf_args && - strlen (inf_args) < ((int) sizeof (psargs) - (int) strlen (psargs))) - { - strncat (psargs, " ", - sizeof (psargs) - strlen (psargs)); - strncat (psargs, inf_args, - sizeof (psargs) - strlen (psargs)); - } - } - - note_data = (char *) elfcore_write_prpsinfo (obfd, - note_data, - note_size, - fname, - psargs); - -#ifdef UNIXWARE - fill_gregset (&gregs, -1); - note_data = elfcore_write_pstatus (obfd, note_data, note_size, - PIDGET (inferior_ptid), - stop_signal, &gregs); -#endif - - thread_args.obfd = obfd; - thread_args.note_data = note_data; - thread_args.note_size = note_size; - proc_iterate_over_threads (pi, procfs_corefile_thread_callback, &thread_args); - - if (thread_args.note_data == note_data) - { - /* iterate_over_threads didn't come up with any threads; - just use inferior_ptid. */ - note_data = procfs_do_thread_registers (obfd, inferior_ptid, - note_data, note_size); - } - else - { - note_data = thread_args.note_data; - } - - make_cleanup (xfree, note_data); - return note_data; -} -#else /* !(Solaris or Unixware) */ -static char * -procfs_make_note_section (bfd *obfd, int *note_size) -{ - error ("gcore not implemented for this host."); - return NULL; /* lint */ -} -#endif /* Solaris or Unixware */ -/* =================== END GCORE .NOTE "MODULE" =================== */ diff --git a/contrib/gdb/gdb/remote-mips.c b/contrib/gdb/gdb/remote-mips.c deleted file mode 100644 index 385b69a..0000000 --- a/contrib/gdb/gdb/remote-mips.c +++ /dev/null @@ -1,3599 +0,0 @@ -/* Remote debugging interface for MIPS remote debugging protocol. - - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002 Free Software Foundation, Inc. - - Contributed by Cygnus Support. Written by Ian Lance Taylor - <ian@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 "bfd.h" -#include "symfile.h" -#include "gdbcmd.h" -#include "gdbcore.h" -#include "serial.h" -#include "target.h" -#include "remote-utils.h" -#include "gdb_string.h" -#include "gdb_stat.h" -#include "regcache.h" -#include <ctype.h> - - -/* Breakpoint types. Values 0, 1, and 2 must agree with the watch - types passed by breakpoint.c to target_insert_watchpoint. - Value 3 is our own invention, and is used for ordinary instruction - breakpoints. Value 4 is used to mark an unused watchpoint in tables. */ -enum break_type - { - BREAK_WRITE, /* 0 */ - BREAK_READ, /* 1 */ - BREAK_ACCESS, /* 2 */ - BREAK_FETCH, /* 3 */ - BREAK_UNUSED /* 4 */ - }; - -/* Prototypes for local functions. */ - -static int mips_readchar (int timeout); - -static int mips_receive_header (unsigned char *hdr, int *pgarbage, - int ch, int timeout); - -static int mips_receive_trailer (unsigned char *trlr, int *pgarbage, - int *pch, int timeout); - -static int mips_cksum (const unsigned char *hdr, - const unsigned char *data, int len); - -static void mips_send_packet (const char *s, int get_ack); - -static void mips_send_command (const char *cmd, int prompt); - -static int mips_receive_packet (char *buff, int throw_error, int timeout); - -static ULONGEST mips_request (int cmd, ULONGEST addr, ULONGEST data, - int *perr, int timeout, char *buff); - -static void mips_initialize (void); - -static void mips_open (char *name, int from_tty); - -static void pmon_open (char *name, int from_tty); - -static void ddb_open (char *name, int from_tty); - -static void lsi_open (char *name, int from_tty); - -static void mips_close (int quitting); - -static void mips_detach (char *args, int from_tty); - -static void mips_resume (ptid_t ptid, int step, - enum target_signal siggnal); - -static ptid_t mips_wait (ptid_t ptid, - struct target_waitstatus *status); - -static int mips_map_regno (int regno); - -static void mips_fetch_registers (int regno); - -static void mips_prepare_to_store (void); - -static void mips_store_registers (int regno); - -static unsigned int mips_fetch_word (CORE_ADDR addr); - -static int mips_store_word (CORE_ADDR addr, unsigned int value, - char *old_contents); - -static int mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, - int write, - struct mem_attrib *attrib, - struct target_ops *target); - -static void mips_files_info (struct target_ops *ignore); - -static void mips_create_inferior (char *execfile, char *args, char **env); - -static void mips_mourn_inferior (void); - -static int pmon_makeb64 (unsigned long v, char *p, int n, int *chksum); - -static int pmon_zeroset (int recsize, char **buff, int *amount, - unsigned int *chksum); - -static int pmon_checkset (int recsize, char **buff, int *value); - -static void pmon_make_fastrec (char **outbuf, unsigned char *inbuf, - int *inptr, int inamount, int *recsize, - unsigned int *csum, unsigned int *zerofill); - -static int pmon_check_ack (char *mesg); - -static void pmon_start_download (void); - -static void pmon_end_download (int final, int bintotal); - -static void pmon_download (char *buffer, int length); - -static void pmon_load_fast (char *file); - -static void mips_load (char *file, int from_tty); - -static int mips_make_srec (char *buffer, int type, CORE_ADDR memaddr, - unsigned char *myaddr, int len); - -static int set_breakpoint (CORE_ADDR addr, int len, enum break_type type); - -static int clear_breakpoint (CORE_ADDR addr, int len, enum break_type type); - -static int common_breakpoint (int set, CORE_ADDR addr, int len, - enum break_type type); - -/* Forward declarations. */ -extern struct target_ops mips_ops; -extern struct target_ops pmon_ops; -extern struct target_ops ddb_ops; -/* *INDENT-OFF* */ -/* The MIPS remote debugging interface is built on top of a simple - packet protocol. Each packet is organized as follows: - - SYN The first character is always a SYN (ASCII 026, or ^V). SYN - may not appear anywhere else in the packet. Any time a SYN is - seen, a new packet should be assumed to have begun. - - TYPE_LEN - This byte contains the upper five bits of the logical length - of the data section, plus a single bit indicating whether this - is a data packet or an acknowledgement. The documentation - indicates that this bit is 1 for a data packet, but the actual - board uses 1 for an acknowledgement. The value of the byte is - 0x40 + (ack ? 0x20 : 0) + (len >> 6) - (we always have 0 <= len < 1024). Acknowledgement packets do - not carry data, and must have a data length of 0. - - LEN1 This byte contains the lower six bits of the logical length of - the data section. The value is - 0x40 + (len & 0x3f) - - SEQ This byte contains the six bit sequence number of the packet. - The value is - 0x40 + seq - An acknowlegment packet contains the sequence number of the - packet being acknowledged plus 1 modulo 64. Data packets are - transmitted in sequence. There may only be one outstanding - unacknowledged data packet at a time. The sequence numbers - are independent in each direction. If an acknowledgement for - the previous packet is received (i.e., an acknowledgement with - the sequence number of the packet just sent) the packet just - sent should be retransmitted. If no acknowledgement is - received within a timeout period, the packet should be - retransmitted. This has an unfortunate failure condition on a - high-latency line, as a delayed acknowledgement may lead to an - endless series of duplicate packets. - - DATA The actual data bytes follow. The following characters are - escaped inline with DLE (ASCII 020, or ^P): - SYN (026) DLE S - DLE (020) DLE D - ^C (003) DLE C - ^S (023) DLE s - ^Q (021) DLE q - The additional DLE characters are not counted in the logical - length stored in the TYPE_LEN and LEN1 bytes. - - CSUM1 - CSUM2 - CSUM3 - These bytes contain an 18 bit checksum of the complete - contents of the packet excluding the SEQ byte and the - CSUM[123] bytes. The checksum is simply the twos complement - addition of all the bytes treated as unsigned characters. The - values of the checksum bytes are: - CSUM1: 0x40 + ((cksum >> 12) & 0x3f) - CSUM2: 0x40 + ((cksum >> 6) & 0x3f) - CSUM3: 0x40 + (cksum & 0x3f) - - It happens that the MIPS remote debugging protocol always - communicates with ASCII strings. Because of this, this - implementation doesn't bother to handle the DLE quoting mechanism, - since it will never be required. */ -/* *INDENT-ON* */ - - -/* The SYN character which starts each packet. */ -#define SYN '\026' - -/* The 0x40 used to offset each packet (this value ensures that all of - the header and trailer bytes, other than SYN, are printable ASCII - characters). */ -#define HDR_OFFSET 0x40 - -/* The indices of the bytes in the packet header. */ -#define HDR_INDX_SYN 0 -#define HDR_INDX_TYPE_LEN 1 -#define HDR_INDX_LEN1 2 -#define HDR_INDX_SEQ 3 -#define HDR_LENGTH 4 - -/* The data/ack bit in the TYPE_LEN header byte. */ -#define TYPE_LEN_DA_BIT 0x20 -#define TYPE_LEN_DATA 0 -#define TYPE_LEN_ACK TYPE_LEN_DA_BIT - -/* How to compute the header bytes. */ -#define HDR_SET_SYN(data, len, seq) (SYN) -#define HDR_SET_TYPE_LEN(data, len, seq) \ - (HDR_OFFSET \ - + ((data) ? TYPE_LEN_DATA : TYPE_LEN_ACK) \ - + (((len) >> 6) & 0x1f)) -#define HDR_SET_LEN1(data, len, seq) (HDR_OFFSET + ((len) & 0x3f)) -#define HDR_SET_SEQ(data, len, seq) (HDR_OFFSET + (seq)) - -/* Check that a header byte is reasonable. */ -#define HDR_CHECK(ch) (((ch) & HDR_OFFSET) == HDR_OFFSET) - -/* Get data from the header. These macros evaluate their argument - multiple times. */ -#define HDR_IS_DATA(hdr) \ - (((hdr)[HDR_INDX_TYPE_LEN] & TYPE_LEN_DA_BIT) == TYPE_LEN_DATA) -#define HDR_GET_LEN(hdr) \ - ((((hdr)[HDR_INDX_TYPE_LEN] & 0x1f) << 6) + (((hdr)[HDR_INDX_LEN1] & 0x3f))) -#define HDR_GET_SEQ(hdr) ((unsigned int)(hdr)[HDR_INDX_SEQ] & 0x3f) - -/* The maximum data length. */ -#define DATA_MAXLEN 1023 - -/* The trailer offset. */ -#define TRLR_OFFSET HDR_OFFSET - -/* The indices of the bytes in the packet trailer. */ -#define TRLR_INDX_CSUM1 0 -#define TRLR_INDX_CSUM2 1 -#define TRLR_INDX_CSUM3 2 -#define TRLR_LENGTH 3 - -/* How to compute the trailer bytes. */ -#define TRLR_SET_CSUM1(cksum) (TRLR_OFFSET + (((cksum) >> 12) & 0x3f)) -#define TRLR_SET_CSUM2(cksum) (TRLR_OFFSET + (((cksum) >> 6) & 0x3f)) -#define TRLR_SET_CSUM3(cksum) (TRLR_OFFSET + (((cksum) ) & 0x3f)) - -/* Check that a trailer byte is reasonable. */ -#define TRLR_CHECK(ch) (((ch) & TRLR_OFFSET) == TRLR_OFFSET) - -/* Get data from the trailer. This evaluates its argument multiple - times. */ -#define TRLR_GET_CKSUM(trlr) \ - ((((trlr)[TRLR_INDX_CSUM1] & 0x3f) << 12) \ - + (((trlr)[TRLR_INDX_CSUM2] & 0x3f) << 6) \ - + ((trlr)[TRLR_INDX_CSUM3] & 0x3f)) - -/* The sequence number modulos. */ -#define SEQ_MODULOS (64) - -/* PMON commands to load from the serial port or UDP socket. */ -#define LOAD_CMD "load -b -s tty0\r" -#define LOAD_CMD_UDP "load -b -s udp\r" - -/* The target vectors for the four different remote MIPS targets. - These are initialized with code in _initialize_remote_mips instead - of static initializers, to make it easier to extend the target_ops - vector later. */ -struct target_ops mips_ops, pmon_ops, ddb_ops, lsi_ops; - -enum mips_monitor_type - { - /* IDT/SIM monitor being used: */ - MON_IDT, - /* PMON monitor being used: */ - MON_PMON, /* 3.0.83 [COGENT,EB,FP,NET] Algorithmics Ltd. Nov 9 1995 17:19:50 */ - MON_DDB, /* 2.7.473 [DDBVR4300,EL,FP,NET] Risq Modular Systems, Thu Jun 6 09:28:40 PDT 1996 */ - MON_LSI, /* 4.3.12 [EB,FP], LSI LOGIC Corp. Tue Feb 25 13:22:14 1997 */ - /* Last and unused value, for sizing vectors, etc. */ - MON_LAST - }; -static enum mips_monitor_type mips_monitor = MON_LAST; - -/* The monitor prompt text. If the user sets the PMON prompt - to some new value, the GDB `set monitor-prompt' command must also - be used to inform GDB about the expected prompt. Otherwise, GDB - will not be able to connect to PMON in mips_initialize(). - If the `set monitor-prompt' command is not used, the expected - default prompt will be set according the target: - target prompt - ----- ----- - pmon PMON> - ddb NEC010> - lsi PMON> - */ -static char *mips_monitor_prompt; - -/* Set to 1 if the target is open. */ -static int mips_is_open; - -/* Currently active target description (if mips_is_open == 1) */ -static struct target_ops *current_ops; - -/* Set to 1 while the connection is being initialized. */ -static int mips_initializing; - -/* Set to 1 while the connection is being brought down. */ -static int mips_exiting; - -/* The next sequence number to send. */ -static unsigned int mips_send_seq; - -/* The next sequence number we expect to receive. */ -static unsigned int mips_receive_seq; - -/* The time to wait before retransmitting a packet, in seconds. */ -static int mips_retransmit_wait = 3; - -/* The number of times to try retransmitting a packet before giving up. */ -static int mips_send_retries = 10; - -/* The number of garbage characters to accept when looking for an - SYN for the next packet. */ -static int mips_syn_garbage = 10; - -/* The time to wait for a packet, in seconds. */ -static int mips_receive_wait = 5; - -/* Set if we have sent a packet to the board but have not yet received - a reply. */ -static int mips_need_reply = 0; - -/* Handle used to access serial I/O stream. */ -static struct serial *mips_desc; - -/* UDP handle used to download files to target. */ -static struct serial *udp_desc; -static int udp_in_use; - -/* TFTP filename used to download files to DDB board, in the form - host:filename. */ -static char *tftp_name; /* host:filename */ -static char *tftp_localname; /* filename portion of above */ -static int tftp_in_use; -static FILE *tftp_file; - -/* Counts the number of times the user tried to interrupt the target (usually - via ^C. */ -static int interrupt_count; - -/* If non-zero, means that the target is running. */ -static int mips_wait_flag = 0; - -/* If non-zero, monitor supports breakpoint commands. */ -static int monitor_supports_breakpoints = 0; - -/* Data cache header. */ - -#if 0 /* not used (yet?) */ -static DCACHE *mips_dcache; -#endif - -/* Non-zero means that we've just hit a read or write watchpoint */ -static int hit_watchpoint; - -/* Table of breakpoints/watchpoints (used only on LSI PMON target). - The table is indexed by a breakpoint number, which is an integer - from 0 to 255 returned by the LSI PMON when a breakpoint is set. - */ -#define MAX_LSI_BREAKPOINTS 256 -struct lsi_breakpoint_info - { - enum break_type type; /* type of breakpoint */ - CORE_ADDR addr; /* address of breakpoint */ - int len; /* length of region being watched */ - unsigned long value; /* value to watch */ - } -lsi_breakpoints[MAX_LSI_BREAKPOINTS]; - -/* Error/warning codes returned by LSI PMON for breakpoint commands. - Warning values may be ORed together; error values may not. */ -#define W_WARN 0x100 /* This bit is set if the error code is a warning */ -#define W_MSK 0x101 /* warning: Range feature is supported via mask */ -#define W_VAL 0x102 /* warning: Value check is not supported in hardware */ -#define W_QAL 0x104 /* warning: Requested qualifiers are not supported in hardware */ - -#define E_ERR 0x200 /* This bit is set if the error code is an error */ -#define E_BPT 0x200 /* error: No such breakpoint number */ -#define E_RGE 0x201 /* error: Range is not supported */ -#define E_QAL 0x202 /* error: The requested qualifiers can not be used */ -#define E_OUT 0x203 /* error: Out of hardware resources */ -#define E_NON 0x204 /* error: Hardware breakpoint not supported */ - -struct lsi_error - { - int code; /* error code */ - char *string; /* string associated with this code */ - }; - -struct lsi_error lsi_warning_table[] = -{ - {W_MSK, "Range feature is supported via mask"}, - {W_VAL, "Value check is not supported in hardware"}, - {W_QAL, "Requested qualifiers are not supported in hardware"}, - {0, NULL} -}; - -struct lsi_error lsi_error_table[] = -{ - {E_BPT, "No such breakpoint number"}, - {E_RGE, "Range is not supported"}, - {E_QAL, "The requested qualifiers can not be used"}, - {E_OUT, "Out of hardware resources"}, - {E_NON, "Hardware breakpoint not supported"}, - {0, NULL} -}; - -/* Set to 1 with the 'set monitor-warnings' command to enable printing - of warnings returned by PMON when hardware breakpoints are used. */ -static int monitor_warnings; - - -static void -close_ports (void) -{ - mips_is_open = 0; - serial_close (mips_desc); - - if (udp_in_use) - { - serial_close (udp_desc); - udp_in_use = 0; - } - tftp_in_use = 0; -} - -/* Handle low-level error that we can't recover from. Note that just - error()ing out from target_wait or some such low-level place will cause - all hell to break loose--the rest of GDB will tend to get left in an - inconsistent state. */ - -static NORETURN void -mips_error (char *string,...) -{ - va_list args; - - va_start (args, string); - - target_terminal_ours (); - wrap_here (""); /* Force out any buffered output */ - gdb_flush (gdb_stdout); - if (error_pre_print) - fprintf_filtered (gdb_stderr, error_pre_print); - vfprintf_filtered (gdb_stderr, string, args); - fprintf_filtered (gdb_stderr, "\n"); - va_end (args); - gdb_flush (gdb_stderr); - - /* Clean up in such a way that mips_close won't try to talk to the - board (it almost surely won't work since we weren't able to talk to - it). */ - close_ports (); - - printf_unfiltered ("Ending remote MIPS debugging.\n"); - target_mourn_inferior (); - - throw_exception (RETURN_ERROR); -} - -/* putc_readable - print a character, displaying non-printable chars in - ^x notation or in hex. */ - -static void -fputc_readable (int ch, struct ui_file *file) -{ - if (ch == '\n') - fputc_unfiltered ('\n', file); - else if (ch == '\r') - fprintf_unfiltered (file, "\\r"); - else if (ch < 0x20) /* ASCII control character */ - fprintf_unfiltered (file, "^%c", ch + '@'); - else if (ch >= 0x7f) /* non-ASCII characters (rubout or greater) */ - fprintf_unfiltered (file, "[%02x]", ch & 0xff); - else - fputc_unfiltered (ch, file); -} - - -/* puts_readable - print a string, displaying non-printable chars in - ^x notation or in hex. */ - -static void -fputs_readable (const char *string, struct ui_file *file) -{ - int c; - - while ((c = *string++) != '\0') - fputc_readable (c, file); -} - - -/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if - timed out. TIMEOUT specifies timeout value in seconds. - */ - -int -mips_expect_timeout (const char *string, int timeout) -{ - const char *p = string; - - if (remote_debug) - { - fprintf_unfiltered (gdb_stdlog, "Expected \""); - fputs_readable (string, gdb_stdlog); - fprintf_unfiltered (gdb_stdlog, "\", got \""); - } - - immediate_quit++; - while (1) - { - int c; - - /* Must use serial_readchar() here cuz mips_readchar would get - confused if we were waiting for the mips_monitor_prompt... */ - - c = serial_readchar (mips_desc, timeout); - - if (c == SERIAL_TIMEOUT) - { - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "\": FAIL\n"); - return 0; - } - - if (remote_debug) - fputc_readable (c, gdb_stdlog); - - if (c == *p++) - { - if (*p == '\0') - { - immediate_quit--; - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "\": OK\n"); - return 1; - } - } - else - { - p = string; - if (c == *p) - p++; - } - } -} - -/* Wait until STRING shows up in mips_desc. Returns 1 if successful, else 0 if - timed out. The timeout value is hard-coded to 2 seconds. Use - mips_expect_timeout if a different timeout value is needed. - */ - -int -mips_expect (const char *string) -{ - return mips_expect_timeout (string, remote_timeout); -} - -/* Read the required number of characters into the given buffer (which - is assumed to be large enough). The only failure is a timeout. */ -int -mips_getstring (char *string, int n) -{ - char *p = string; - int c; - - immediate_quit++; - while (n > 0) - { - c = serial_readchar (mips_desc, remote_timeout); - - if (c == SERIAL_TIMEOUT) - { - fprintf_unfiltered (gdb_stderr, - "Failed to read %d characters from target (TIMEOUT)\n", n); - immediate_quit--; - return 0; - } - - *p++ = c; - n--; - } - - immediate_quit--; - return 1; -} - -/* Read a character from the remote, aborting on error. Returns - SERIAL_TIMEOUT on timeout (since that's what serial_readchar() - returns). FIXME: If we see the string mips_monitor_prompt from the - board, then we are debugging on the main console port, and we have - somehow dropped out of remote debugging mode. In this case, we - automatically go back in to remote debugging mode. This is a hack, - put in because I can't find any way for a program running on the - remote board to terminate without also ending remote debugging - mode. I assume users won't have any trouble with this; for one - thing, the IDT documentation generally assumes that the remote - debugging port is not the console port. This is, however, very - convenient for DejaGnu when you only have one connected serial - port. */ - -static int -mips_readchar (int timeout) -{ - int ch; - static int state = 0; - int mips_monitor_prompt_len = strlen (mips_monitor_prompt); - - { - int i; - - i = timeout; - if (i == -1 && watchdog > 0) - i = watchdog; - } - - if (state == mips_monitor_prompt_len) - timeout = 1; - ch = serial_readchar (mips_desc, timeout); - - if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */ - { - target_mourn_inferior (); - error ("Watchdog has expired. Target detached.\n"); - } - - if (ch == SERIAL_EOF) - mips_error ("End of file from remote"); - if (ch == SERIAL_ERROR) - mips_error ("Error reading from remote: %s", safe_strerror (errno)); - if (remote_debug > 1) - { - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - if (ch != SERIAL_TIMEOUT) - fprintf_unfiltered (gdb_stdlog, "Read '%c' %d 0x%x\n", ch, ch, ch); - else - fprintf_unfiltered (gdb_stdlog, "Timed out in read\n"); - } - - /* If we have seen mips_monitor_prompt and we either time out, or - we see a @ (which was echoed from a packet we sent), reset the - board as described above. The first character in a packet after - the SYN (which is not echoed) is always an @ unless the packet is - more than 64 characters long, which ours never are. */ - if ((ch == SERIAL_TIMEOUT || ch == '@') - && state == mips_monitor_prompt_len - && !mips_initializing - && !mips_exiting) - { - if (remote_debug > 0) - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - fprintf_unfiltered (gdb_stdlog, "Reinitializing MIPS debugging mode\n"); - - mips_need_reply = 0; - mips_initialize (); - - state = 0; - - /* At this point, about the only thing we can do is abort the command - in progress and get back to command level as quickly as possible. */ - - error ("Remote board reset, debug protocol re-initialized."); - } - - if (ch == mips_monitor_prompt[state]) - ++state; - else - state = 0; - - return ch; -} - -/* Get a packet header, putting the data in the supplied buffer. - PGARBAGE is a pointer to the number of garbage characters received - so far. CH is the last character received. Returns 0 for success, - or -1 for timeout. */ - -static int -mips_receive_header (unsigned char *hdr, int *pgarbage, int ch, int timeout) -{ - int i; - - while (1) - { - /* Wait for a SYN. mips_syn_garbage is intended to prevent - sitting here indefinitely if the board sends us one garbage - character per second. ch may already have a value from the - last time through the loop. */ - while (ch != SYN) - { - ch = mips_readchar (timeout); - if (ch == SERIAL_TIMEOUT) - return -1; - if (ch != SYN) - { - /* Printing the character here lets the user of gdb see - what the program is outputting, if the debugging is - being done on the console port. Don't use _filtered: - we can't deal with a QUIT out of target_wait and - buffered target output confuses the user. */ - if (!mips_initializing || remote_debug > 0) - { - if (isprint (ch) || isspace (ch)) - { - fputc_unfiltered (ch, gdb_stdtarg); - } - else - { - fputc_readable (ch, gdb_stdtarg); - } - gdb_flush (gdb_stdtarg); - } - - /* Only count unprintable characters. */ - if (! (isprint (ch) || isspace (ch))) - (*pgarbage) += 1; - - if (mips_syn_garbage > 0 - && *pgarbage > mips_syn_garbage) - mips_error ("Debug protocol failure: more than %d characters before a sync.", - mips_syn_garbage); - } - } - - /* Get the packet header following the SYN. */ - for (i = 1; i < HDR_LENGTH; i++) - { - ch = mips_readchar (timeout); - if (ch == SERIAL_TIMEOUT) - return -1; - /* Make sure this is a header byte. */ - if (ch == SYN || !HDR_CHECK (ch)) - break; - - hdr[i] = ch; - } - - /* If we got the complete header, we can return. Otherwise we - loop around and keep looking for SYN. */ - if (i >= HDR_LENGTH) - return 0; - } -} - -/* Get a packet header, putting the data in the supplied buffer. - PGARBAGE is a pointer to the number of garbage characters received - so far. The last character read is returned in *PCH. Returns 0 - for success, -1 for timeout, -2 for error. */ - -static int -mips_receive_trailer (unsigned char *trlr, int *pgarbage, int *pch, int timeout) -{ - int i; - int ch; - - for (i = 0; i < TRLR_LENGTH; i++) - { - ch = mips_readchar (timeout); - *pch = ch; - if (ch == SERIAL_TIMEOUT) - return -1; - if (!TRLR_CHECK (ch)) - return -2; - trlr[i] = ch; - } - return 0; -} - -/* Get the checksum of a packet. HDR points to the packet header. - DATA points to the packet data. LEN is the length of DATA. */ - -static int -mips_cksum (const unsigned char *hdr, const unsigned char *data, int len) -{ - register const unsigned char *p; - register int c; - register int cksum; - - cksum = 0; - - /* The initial SYN is not included in the checksum. */ - c = HDR_LENGTH - 1; - p = hdr + 1; - while (c-- != 0) - cksum += *p++; - - c = len; - p = data; - while (c-- != 0) - cksum += *p++; - - return cksum; -} - -/* Send a packet containing the given ASCII string. */ - -static void -mips_send_packet (const char *s, int get_ack) -{ - /* unsigned */ int len; - unsigned char *packet; - register int cksum; - int try; - - len = strlen (s); - if (len > DATA_MAXLEN) - mips_error ("MIPS protocol data packet too long: %s", s); - - packet = (unsigned char *) alloca (HDR_LENGTH + len + TRLR_LENGTH + 1); - - packet[HDR_INDX_SYN] = HDR_SET_SYN (1, len, mips_send_seq); - packet[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (1, len, mips_send_seq); - packet[HDR_INDX_LEN1] = HDR_SET_LEN1 (1, len, mips_send_seq); - packet[HDR_INDX_SEQ] = HDR_SET_SEQ (1, len, mips_send_seq); - - memcpy (packet + HDR_LENGTH, s, len); - - cksum = mips_cksum (packet, packet + HDR_LENGTH, len); - packet[HDR_LENGTH + len + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); - packet[HDR_LENGTH + len + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); - packet[HDR_LENGTH + len + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); - - /* Increment the sequence number. This will set mips_send_seq to - the sequence number we expect in the acknowledgement. */ - mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS; - - /* We can only have one outstanding data packet, so we just wait for - the acknowledgement here. Keep retransmitting the packet until - we get one, or until we've tried too many times. */ - for (try = 0; try < mips_send_retries; try++) - { - int garbage; - int ch; - - if (remote_debug > 0) - { - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0'; - fprintf_unfiltered (gdb_stdlog, "Writing \"%s\"\n", packet + 1); - } - - if (serial_write (mips_desc, packet, - HDR_LENGTH + len + TRLR_LENGTH) != 0) - mips_error ("write to target failed: %s", safe_strerror (errno)); - - if (!get_ack) - return; - - garbage = 0; - ch = 0; - while (1) - { - unsigned char hdr[HDR_LENGTH + 1]; - unsigned char trlr[TRLR_LENGTH + 1]; - int err; - unsigned int seq; - - /* Get the packet header. If we time out, resend the data - packet. */ - err = mips_receive_header (hdr, &garbage, ch, mips_retransmit_wait); - if (err != 0) - break; - - ch = 0; - - /* If we get a data packet, assume it is a duplicate and - ignore it. FIXME: If the acknowledgement is lost, this - data packet may be the packet the remote sends after the - acknowledgement. */ - if (HDR_IS_DATA (hdr)) - { - int i; - - /* Ignore any errors raised whilst attempting to ignore - packet. */ - - len = HDR_GET_LEN (hdr); - - for (i = 0; i < len; i++) - { - int rch; - - rch = mips_readchar (remote_timeout); - if (rch == SYN) - { - ch = SYN; - break; - } - if (rch == SERIAL_TIMEOUT) - break; - /* ignore the character */ - } - - if (i == len) - (void) mips_receive_trailer (trlr, &garbage, &ch, - remote_timeout); - - /* We don't bother checking the checksum, or providing an - ACK to the packet. */ - continue; - } - - /* If the length is not 0, this is a garbled packet. */ - if (HDR_GET_LEN (hdr) != 0) - continue; - - /* Get the packet trailer. */ - err = mips_receive_trailer (trlr, &garbage, &ch, - mips_retransmit_wait); - - /* If we timed out, resend the data packet. */ - if (err == -1) - break; - - /* If we got a bad character, reread the header. */ - if (err != 0) - continue; - - /* If the checksum does not match the trailer checksum, this - is a bad packet; ignore it. */ - if (mips_cksum (hdr, (unsigned char *) NULL, 0) - != TRLR_GET_CKSUM (trlr)) - continue; - - if (remote_debug > 0) - { - hdr[HDR_LENGTH] = '\0'; - trlr[TRLR_LENGTH] = '\0'; - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - fprintf_unfiltered (gdb_stdlog, "Got ack %d \"%s%s\"\n", - HDR_GET_SEQ (hdr), hdr + 1, trlr); - } - - /* If this ack is for the current packet, we're done. */ - seq = HDR_GET_SEQ (hdr); - if (seq == mips_send_seq) - return; - - /* If this ack is for the last packet, resend the current - packet. */ - if ((seq + 1) % SEQ_MODULOS == mips_send_seq) - break; - - /* Otherwise this is a bad ack; ignore it. Increment the - garbage count to ensure that we do not stay in this loop - forever. */ - ++garbage; - } - } - - mips_error ("Remote did not acknowledge packet"); -} - -/* Receive and acknowledge a packet, returning the data in BUFF (which - should be DATA_MAXLEN + 1 bytes). The protocol documentation - implies that only the sender retransmits packets, so this code just - waits silently for a packet. It returns the length of the received - packet. If THROW_ERROR is nonzero, call error() on errors. If not, - don't print an error message and return -1. */ - -static int -mips_receive_packet (char *buff, int throw_error, int timeout) -{ - int ch; - int garbage; - int len; - unsigned char ack[HDR_LENGTH + TRLR_LENGTH + 1]; - int cksum; - - ch = 0; - garbage = 0; - while (1) - { - unsigned char hdr[HDR_LENGTH]; - unsigned char trlr[TRLR_LENGTH]; - int i; - int err; - - if (mips_receive_header (hdr, &garbage, ch, timeout) != 0) - { - if (throw_error) - mips_error ("Timed out waiting for remote packet"); - else - return -1; - } - - ch = 0; - - /* An acknowledgement is probably a duplicate; ignore it. */ - if (!HDR_IS_DATA (hdr)) - { - len = HDR_GET_LEN (hdr); - /* Check if the length is valid for an ACK, we may aswell - try and read the remainder of the packet: */ - if (len == 0) - { - /* Ignore the error condition, since we are going to - ignore the packet anyway. */ - (void) mips_receive_trailer (trlr, &garbage, &ch, timeout); - } - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - if (remote_debug > 0) - fprintf_unfiltered (gdb_stdlog, "Ignoring unexpected ACK\n"); - continue; - } - - len = HDR_GET_LEN (hdr); - for (i = 0; i < len; i++) - { - int rch; - - rch = mips_readchar (timeout); - if (rch == SYN) - { - ch = SYN; - break; - } - if (rch == SERIAL_TIMEOUT) - { - if (throw_error) - mips_error ("Timed out waiting for remote packet"); - else - return -1; - } - buff[i] = rch; - } - - if (i < len) - { - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - if (remote_debug > 0) - fprintf_unfiltered (gdb_stdlog, - "Got new SYN after %d chars (wanted %d)\n", - i, len); - continue; - } - - err = mips_receive_trailer (trlr, &garbage, &ch, timeout); - if (err == -1) - { - if (throw_error) - mips_error ("Timed out waiting for packet"); - else - return -1; - } - if (err == -2) - { - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - if (remote_debug > 0) - fprintf_unfiltered (gdb_stdlog, "Got SYN when wanted trailer\n"); - continue; - } - - /* If this is the wrong sequence number, ignore it. */ - if (HDR_GET_SEQ (hdr) != mips_receive_seq) - { - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - if (remote_debug > 0) - fprintf_unfiltered (gdb_stdlog, - "Ignoring sequence number %d (want %d)\n", - HDR_GET_SEQ (hdr), mips_receive_seq); - continue; - } - - if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr)) - break; - - if (remote_debug > 0) - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - printf_unfiltered ("Bad checksum; data %d, trailer %d\n", - mips_cksum (hdr, buff, len), - TRLR_GET_CKSUM (trlr)); - - /* The checksum failed. Send an acknowledgement for the - previous packet to tell the remote to resend the packet. */ - ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq); - ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq); - ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq); - ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq); - - cksum = mips_cksum (ack, (unsigned char *) NULL, 0); - - ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); - ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); - ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); - - if (remote_debug > 0) - { - ack[HDR_LENGTH + TRLR_LENGTH] = '\0'; - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq, - ack + 1); - } - - if (serial_write (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0) - { - if (throw_error) - mips_error ("write to target failed: %s", safe_strerror (errno)); - else - return -1; - } - } - - if (remote_debug > 0) - { - buff[len] = '\0'; - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - printf_unfiltered ("Got packet \"%s\"\n", buff); - } - - /* We got the packet. Send an acknowledgement. */ - mips_receive_seq = (mips_receive_seq + 1) % SEQ_MODULOS; - - ack[HDR_INDX_SYN] = HDR_SET_SYN (0, 0, mips_receive_seq); - ack[HDR_INDX_TYPE_LEN] = HDR_SET_TYPE_LEN (0, 0, mips_receive_seq); - ack[HDR_INDX_LEN1] = HDR_SET_LEN1 (0, 0, mips_receive_seq); - ack[HDR_INDX_SEQ] = HDR_SET_SEQ (0, 0, mips_receive_seq); - - cksum = mips_cksum (ack, (unsigned char *) NULL, 0); - - ack[HDR_LENGTH + TRLR_INDX_CSUM1] = TRLR_SET_CSUM1 (cksum); - ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum); - ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum); - - if (remote_debug > 0) - { - ack[HDR_LENGTH + TRLR_LENGTH] = '\0'; - /* Don't use _filtered; we can't deal with a QUIT out of - target_wait, and I think this might be called from there. */ - printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq, - ack + 1); - } - - if (serial_write (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0) - { - if (throw_error) - mips_error ("write to target failed: %s", safe_strerror (errno)); - else - return -1; - } - - return len; -} - -/* Optionally send a request to the remote system and optionally wait - for the reply. This implements the remote debugging protocol, - which is built on top of the packet protocol defined above. Each - request has an ADDR argument and a DATA argument. The following - requests are defined: - - \0 don't send a request; just wait for a reply - i read word from instruction space at ADDR - d read word from data space at ADDR - I write DATA to instruction space at ADDR - D write DATA to data space at ADDR - r read register number ADDR - R set register number ADDR to value DATA - c continue execution (if ADDR != 1, set pc to ADDR) - s single step (if ADDR != 1, set pc to ADDR) - - The read requests return the value requested. The write requests - return the previous value in the changed location. The execution - requests return a UNIX wait value (the approximate signal which - caused execution to stop is in the upper eight bits). - - If PERR is not NULL, this function waits for a reply. If an error - occurs, it sets *PERR to 1 and sets errno according to what the - target board reports. */ - -static ULONGEST -mips_request (int cmd, - ULONGEST addr, - ULONGEST data, - int *perr, - int timeout, - char *buff) -{ - char myBuff[DATA_MAXLEN + 1]; - int len; - int rpid; - char rcmd; - int rerrflg; - unsigned long rresponse; - - if (buff == (char *) NULL) - buff = myBuff; - - if (cmd != '\0') - { - if (mips_need_reply) - internal_error (__FILE__, __LINE__, - "mips_request: Trying to send command before reply"); - sprintf (buff, "0x0 %c 0x%s 0x%s", cmd, paddr_nz (addr), paddr_nz (data)); - mips_send_packet (buff, 1); - mips_need_reply = 1; - } - - if (perr == (int *) NULL) - return 0; - - if (!mips_need_reply) - internal_error (__FILE__, __LINE__, - "mips_request: Trying to get reply before command"); - - mips_need_reply = 0; - - len = mips_receive_packet (buff, 1, timeout); - buff[len] = '\0'; - - if (sscanf (buff, "0x%x %c 0x%x 0x%lx", - &rpid, &rcmd, &rerrflg, &rresponse) != 4 - || (cmd != '\0' && rcmd != cmd)) - mips_error ("Bad response from remote board"); - - if (rerrflg != 0) - { - *perr = 1; - - /* FIXME: This will returns MIPS errno numbers, which may or may - not be the same as errno values used on other systems. If - they stick to common errno values, they will be the same, but - if they don't, they must be translated. */ - errno = rresponse; - - return 0; - } - - *perr = 0; - return rresponse; -} - -static void -mips_initialize_cleanups (PTR arg) -{ - mips_initializing = 0; -} - -static void -mips_exit_cleanups (PTR arg) -{ - mips_exiting = 0; -} - -static void -mips_send_command (const char *cmd, int prompt) -{ - serial_write (mips_desc, cmd, strlen (cmd)); - mips_expect (cmd); - mips_expect ("\n"); - if (prompt) - mips_expect (mips_monitor_prompt); -} - -/* Enter remote (dbx) debug mode: */ -static void -mips_enter_debug (void) -{ - /* Reset the sequence numbers, ready for the new debug sequence: */ - mips_send_seq = 0; - mips_receive_seq = 0; - - if (mips_monitor != MON_IDT) - mips_send_command ("debug\r", 0); - else /* assume IDT monitor by default */ - mips_send_command ("db tty0\r", 0); - - sleep (1); - serial_write (mips_desc, "\r", sizeof "\r" - 1); - - /* We don't need to absorb any spurious characters here, since the - mips_receive_header will eat up a reasonable number of characters - whilst looking for the SYN, however this avoids the "garbage" - being displayed to the user. */ - if (mips_monitor != MON_IDT) - mips_expect ("\r"); - - { - char buff[DATA_MAXLEN + 1]; - if (mips_receive_packet (buff, 1, 3) < 0) - mips_error ("Failed to initialize (didn't receive packet)."); - } -} - -/* Exit remote (dbx) debug mode, returning to the monitor prompt: */ -static int -mips_exit_debug (void) -{ - int err; - struct cleanup *old_cleanups = make_cleanup (mips_exit_cleanups, NULL); - - mips_exiting = 1; - - if (mips_monitor != MON_IDT) - { - /* The DDB (NEC) and MiniRISC (LSI) versions of PMON exit immediately, - so we do not get a reply to this command: */ - mips_request ('x', 0, 0, NULL, mips_receive_wait, NULL); - mips_need_reply = 0; - if (!mips_expect (" break!")) - return -1; - } - else - mips_request ('x', 0, 0, &err, mips_receive_wait, NULL); - - if (!mips_expect (mips_monitor_prompt)) - return -1; - - do_cleanups (old_cleanups); - - return 0; -} - -/* Initialize a new connection to the MIPS board, and make sure we are - really connected. */ - -static void -mips_initialize (void) -{ - int err; - struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL); - int j; - - /* What is this code doing here? I don't see any way it can happen, and - it might mean mips_initializing didn't get cleared properly. - So I'll make it a warning. */ - - if (mips_initializing) - { - warning ("internal error: mips_initialize called twice"); - return; - } - - mips_wait_flag = 0; - mips_initializing = 1; - - /* At this point, the packit protocol isn't responding. We'll try getting - into the monitor, and restarting the protocol. */ - - /* Force the system into the monitor. After this we *should* be at - the mips_monitor_prompt. */ - if (mips_monitor != MON_IDT) - j = 0; /* start by checking if we are already at the prompt */ - else - j = 1; /* start by sending a break */ - for (; j <= 4; j++) - { - switch (j) - { - case 0: /* First, try sending a CR */ - serial_flush_input (mips_desc); - serial_write (mips_desc, "\r", 1); - break; - case 1: /* First, try sending a break */ - serial_send_break (mips_desc); - break; - case 2: /* Then, try a ^C */ - serial_write (mips_desc, "\003", 1); - break; - case 3: /* Then, try escaping from download */ - { - if (mips_monitor != MON_IDT) - { - char tbuff[7]; - - /* We shouldn't need to send multiple termination - sequences, since the target performs line (or - block) reads, and then processes those - packets. In-case we were downloading a large packet - we flush the output buffer before inserting a - termination sequence. */ - serial_flush_output (mips_desc); - sprintf (tbuff, "\r/E/E\r"); - serial_write (mips_desc, tbuff, 6); - } - else - { - char srec[10]; - int i; - - /* We are possibly in binary download mode, having - aborted in the middle of an S-record. ^C won't - work because of binary mode. The only reliable way - out is to send enough termination packets (8 bytes) - to fill up and then overflow the largest size - S-record (255 bytes in this case). This amounts to - 256/8 + 1 packets. - */ - - mips_make_srec (srec, '7', 0, NULL, 0); - - for (i = 1; i <= 33; i++) - { - serial_write (mips_desc, srec, 8); - - if (serial_readchar (mips_desc, 0) >= 0) - break; /* Break immediatly if we get something from - the board. */ - } - } - } - break; - case 4: - mips_error ("Failed to initialize."); - } - - if (mips_expect (mips_monitor_prompt)) - break; - } - - if (mips_monitor != MON_IDT) - { - /* Sometimes PMON ignores the first few characters in the first - command sent after a load. Sending a blank command gets - around that. */ - mips_send_command ("\r", -1); - - /* Ensure the correct target state: */ - if (mips_monitor != MON_LSI) - mips_send_command ("set regsize 64\r", -1); - mips_send_command ("set hostport tty0\r", -1); - mips_send_command ("set brkcmd \"\"\r", -1); - /* Delete all the current breakpoints: */ - mips_send_command ("db *\r", -1); - /* NOTE: PMON does not have breakpoint support through the - "debug" mode, only at the monitor command-line. */ - } - - mips_enter_debug (); - - /* Clear all breakpoints: */ - if ((mips_monitor == MON_IDT - && clear_breakpoint (-1, 0, BREAK_UNUSED) == 0) - || mips_monitor == MON_LSI) - monitor_supports_breakpoints = 1; - else - monitor_supports_breakpoints = 0; - - do_cleanups (old_cleanups); - - /* If this doesn't call error, we have connected; we don't care if - the request itself succeeds or fails. */ - - mips_request ('r', 0, 0, &err, mips_receive_wait, NULL); - set_current_frame (create_new_frame (read_fp (), read_pc ())); - select_frame (get_current_frame (), 0); -} - -/* Open a connection to the remote board. */ -static void -common_open (struct target_ops *ops, char *name, int from_tty, - enum mips_monitor_type new_monitor, - const char *new_monitor_prompt) -{ - char *ptype; - char *serial_port_name; - char *remote_name = 0; - char *local_name = 0; - char **argv; - - if (name == 0) - error ( - "To open a MIPS remote debugging connection, you need to specify what serial\n\ -device is attached to the target board (e.g., /dev/ttya).\n" - "If you want to use TFTP to download to the board, specify the name of a\n" - "temporary file to be used by GDB for downloads as the second argument.\n" - "This filename must be in the form host:filename, where host is the name\n" - "of the host running the TFTP server, and the file must be readable by the\n" - "world. If the local name of the temporary file differs from the name as\n" - "seen from the board via TFTP, specify that name as the third parameter.\n"); - - /* Parse the serial port name, the optional TFTP name, and the - optional local TFTP name. */ - if ((argv = buildargv (name)) == NULL) - nomem (0); - make_cleanup_freeargv (argv); - - serial_port_name = xstrdup (argv[0]); - if (argv[1]) /* remote TFTP name specified? */ - { - remote_name = argv[1]; - if (argv[2]) /* local TFTP filename specified? */ - local_name = argv[2]; - } - - target_preopen (from_tty); - - if (mips_is_open) - unpush_target (current_ops); - - /* Open and initialize the serial port. */ - mips_desc = serial_open (serial_port_name); - if (mips_desc == NULL) - perror_with_name (serial_port_name); - - if (baud_rate != -1) - { - if (serial_setbaudrate (mips_desc, baud_rate)) - { - serial_close (mips_desc); - perror_with_name (serial_port_name); - } - } - - serial_raw (mips_desc); - - /* Open and initialize the optional download port. If it is in the form - hostname#portnumber, it's a UDP socket. If it is in the form - hostname:filename, assume it's the TFTP filename that must be - passed to the DDB board to tell it where to get the load file. */ - if (remote_name) - { - if (strchr (remote_name, '#')) - { - udp_desc = serial_open (remote_name); - if (!udp_desc) - perror_with_name ("Unable to open UDP port"); - udp_in_use = 1; - } - else - { - /* Save the remote and local names of the TFTP temp file. If - the user didn't specify a local name, assume it's the same - as the part of the remote name after the "host:". */ - if (tftp_name) - xfree (tftp_name); - if (tftp_localname) - xfree (tftp_localname); - if (local_name == NULL) - if ((local_name = strchr (remote_name, ':')) != NULL) - local_name++; /* skip over the colon */ - if (local_name == NULL) - local_name = remote_name; /* local name same as remote name */ - tftp_name = xstrdup (remote_name); - tftp_localname = xstrdup (local_name); - tftp_in_use = 1; - } - } - - current_ops = ops; - mips_is_open = 1; - - /* Reset the expected monitor prompt if it's never been set before. */ - if (mips_monitor_prompt == NULL) - mips_monitor_prompt = xstrdup (new_monitor_prompt); - mips_monitor = new_monitor; - - mips_initialize (); - - if (from_tty) - printf_unfiltered ("Remote MIPS debugging using %s\n", serial_port_name); - - /* Switch to using remote target now. */ - push_target (ops); - - /* FIXME: Should we call start_remote here? */ - - /* Try to figure out the processor model if possible. */ - ptype = mips_read_processor_type (); - if (ptype) - mips_set_processor_type_command (xstrdup (ptype), 0); - -/* This is really the job of start_remote however, that makes an assumption - that the target is about to print out a status message of some sort. That - doesn't happen here (in fact, it may not be possible to get the monitor to - send the appropriate packet). */ - - flush_cached_frames (); - registers_changed (); - stop_pc = read_pc (); - set_current_frame (create_new_frame (read_fp (), stop_pc)); - select_frame (get_current_frame (), 0); - print_stack_frame (selected_frame, -1, 1); - xfree (serial_port_name); -} - -static void -mips_open (char *name, int from_tty) -{ - const char *monitor_prompt = NULL; - if (TARGET_ARCHITECTURE != NULL - && TARGET_ARCHITECTURE->arch == bfd_arch_mips) - { - switch (TARGET_ARCHITECTURE->mach) - { - case bfd_mach_mips4100: - case bfd_mach_mips4300: - case bfd_mach_mips4600: - case bfd_mach_mips4650: - case bfd_mach_mips5000: - monitor_prompt = "<RISQ> "; - break; - } - } - if (monitor_prompt == NULL) - monitor_prompt = "<IDT>"; - common_open (&mips_ops, name, from_tty, MON_IDT, monitor_prompt); -} - -static void -pmon_open (char *name, int from_tty) -{ - common_open (&pmon_ops, name, from_tty, MON_PMON, "PMON> "); -} - -static void -ddb_open (char *name, int from_tty) -{ - common_open (&ddb_ops, name, from_tty, MON_DDB, "NEC010>"); -} - -static void -lsi_open (char *name, int from_tty) -{ - int i; - - /* Clear the LSI breakpoint table. */ - for (i = 0; i < MAX_LSI_BREAKPOINTS; i++) - lsi_breakpoints[i].type = BREAK_UNUSED; - - common_open (&lsi_ops, name, from_tty, MON_LSI, "PMON> "); -} - -/* Close a connection to the remote board. */ - -static void -mips_close (int quitting) -{ - if (mips_is_open) - { - /* Get the board out of remote debugging mode. */ - (void) mips_exit_debug (); - - close_ports (); - } -} - -/* Detach from the remote board. */ - -static void -mips_detach (char *args, int from_tty) -{ - if (args) - error ("Argument given to \"detach\" when remotely debugging."); - - pop_target (); - - mips_close (1); - - if (from_tty) - printf_unfiltered ("Ending remote MIPS debugging.\n"); -} - -/* Tell the target board to resume. This does not wait for a reply - from the board, except in the case of single-stepping on LSI boards, - where PMON does return a reply. */ - -static void -mips_resume (ptid_t ptid, int step, enum target_signal siggnal) -{ - int err; - - /* LSI PMON requires returns a reply packet "0x1 s 0x0 0x57f" after - a single step, so we wait for that. */ - mips_request (step ? 's' : 'c', 1, siggnal, - mips_monitor == MON_LSI && step ? &err : (int *) NULL, - mips_receive_wait, NULL); -} - -/* Return the signal corresponding to SIG, where SIG is the number which - the MIPS protocol uses for the signal. */ -enum target_signal -mips_signal_from_protocol (int sig) -{ - /* We allow a few more signals than the IDT board actually returns, on - the theory that there is at least *some* hope that perhaps the numbering - for these signals is widely agreed upon. */ - if (sig <= 0 - || sig > 31) - return TARGET_SIGNAL_UNKNOWN; - - /* Don't want to use target_signal_from_host because we are converting - from MIPS signal numbers, not host ones. Our internal numbers - match the MIPS numbers for the signals the board can return, which - are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP. */ - return (enum target_signal) sig; -} - -/* Wait until the remote stops, and return a wait status. */ - -static ptid_t -mips_wait (ptid_t ptid, struct target_waitstatus *status) -{ - int rstatus; - int err; - char buff[DATA_MAXLEN]; - int rpc, rfp, rsp; - char flags[20]; - int nfields; - int i; - - interrupt_count = 0; - hit_watchpoint = 0; - - /* If we have not sent a single step or continue command, then the - board is waiting for us to do something. Return a status - indicating that it is stopped. */ - if (!mips_need_reply) - { - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = TARGET_SIGNAL_TRAP; - return inferior_ptid; - } - - /* No timeout; we sit here as long as the program continues to execute. */ - mips_wait_flag = 1; - rstatus = mips_request ('\000', 0, 0, &err, -1, buff); - mips_wait_flag = 0; - if (err) - mips_error ("Remote failure: %s", safe_strerror (errno)); - - /* On returning from a continue, the PMON monitor seems to start - echoing back the messages we send prior to sending back the - ACK. The code can cope with this, but to try and avoid the - unnecessary serial traffic, and "spurious" characters displayed - to the user, we cheat and reset the debug protocol. The problems - seems to be caused by a check on the number of arguments, and the - command length, within the monitor causing it to echo the command - as a bad packet. */ - if (mips_monitor == MON_PMON) - { - mips_exit_debug (); - mips_enter_debug (); - } - - /* See if we got back extended status. If so, pick out the pc, fp, sp, etc... */ - - nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s", - &rpc, &rfp, &rsp, flags); - if (nfields >= 3) - { - char buf[MAX_REGISTER_RAW_SIZE]; - - store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rpc); - supply_register (PC_REGNUM, buf); - - store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rfp); - supply_register (30, buf); /* This register they are avoiding and so it is unnamed */ - - store_unsigned_integer (buf, REGISTER_RAW_SIZE (SP_REGNUM), rsp); - supply_register (SP_REGNUM, buf); - - store_unsigned_integer (buf, REGISTER_RAW_SIZE (FP_REGNUM), 0); - supply_register (FP_REGNUM, buf); - - if (nfields == 9) - { - int i; - - for (i = 0; i <= 2; i++) - if (flags[i] == 'r' || flags[i] == 'w') - hit_watchpoint = 1; - else if (flags[i] == '\000') - break; - } - } - - if (strcmp (target_shortname, "lsi") == 0) - { -#if 0 - /* If this is an LSI PMON target, see if we just hit a hardrdware watchpoint. - Right now, PMON doesn't give us enough information to determine which - breakpoint we hit. So we have to look up the PC in our own table - of breakpoints, and if found, assume it's just a normal instruction - fetch breakpoint, not a data watchpoint. FIXME when PMON - provides some way to tell us what type of breakpoint it is. */ - int i; - CORE_ADDR pc = read_pc (); - - hit_watchpoint = 1; - for (i = 0; i < MAX_LSI_BREAKPOINTS; i++) - { - if (lsi_breakpoints[i].addr == pc - && lsi_breakpoints[i].type == BREAK_FETCH) - { - hit_watchpoint = 0; - break; - } - } -#else - /* If a data breakpoint was hit, PMON returns the following packet: - 0x1 c 0x0 0x57f 0x1 - The return packet from an ordinary breakpoint doesn't have the - extra 0x01 field tacked onto the end. */ - if (nfields == 1 && rpc == 1) - hit_watchpoint = 1; -#endif - } - - /* NOTE: The following (sig) numbers are defined by PMON: - SPP_SIGTRAP 5 breakpoint - SPP_SIGINT 2 - SPP_SIGSEGV 11 - SPP_SIGBUS 10 - SPP_SIGILL 4 - SPP_SIGFPE 8 - SPP_SIGTERM 15 */ - - /* Translate a MIPS waitstatus. We use constants here rather than WTERMSIG - and so on, because the constants we want here are determined by the - MIPS protocol and have nothing to do with what host we are running on. */ - if ((rstatus & 0xff) == 0) - { - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = (((rstatus) >> 8) & 0xff); - } - else if ((rstatus & 0xff) == 0x7f) - { - status->kind = TARGET_WAITKIND_STOPPED; - status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0xff); - - /* If the stop PC is in the _exit function, assume - we hit the 'break 0x3ff' instruction in _exit, so this - is not a normal breakpoint. */ - if (strcmp (target_shortname, "lsi") == 0) - { - char *func_name; - CORE_ADDR func_start; - CORE_ADDR pc = read_pc (); - - find_pc_partial_function (pc, &func_name, &func_start, NULL); - if (func_name != NULL && strcmp (func_name, "_exit") == 0 - && func_start == pc) - status->kind = TARGET_WAITKIND_EXITED; - } - } - else - { - status->kind = TARGET_WAITKIND_SIGNALLED; - status->value.sig = mips_signal_from_protocol (rstatus & 0x7f); - } - - return inferior_ptid; -} - -/* We have to map between the register numbers used by gdb and the - register numbers used by the debugging protocol. This function - assumes that we are using tm-mips.h. */ - -#define REGNO_OFFSET 96 - -static int -mips_map_regno (int regno) -{ - if (regno < 32) - return regno; - if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) - return regno - FP0_REGNUM + 32; - switch (regno) - { - case PC_REGNUM: - return REGNO_OFFSET + 0; - case CAUSE_REGNUM: - return REGNO_OFFSET + 1; - case HI_REGNUM: - return REGNO_OFFSET + 2; - case LO_REGNUM: - return REGNO_OFFSET + 3; - case FCRCS_REGNUM: - return REGNO_OFFSET + 4; - case FCRIR_REGNUM: - return REGNO_OFFSET + 5; - default: - /* FIXME: Is there a way to get the status register? */ - return 0; - } -} - -/* Fetch the remote registers. */ - -static void -mips_fetch_registers (int regno) -{ - unsigned LONGEST val; - int err; - - if (regno == -1) - { - for (regno = 0; regno < NUM_REGS; regno++) - mips_fetch_registers (regno); - return; - } - - if (regno == FP_REGNUM || regno == ZERO_REGNUM) - /* FP_REGNUM on the mips is a hack which is just supposed to read - zero (see also mips-nat.c). */ - val = 0; - else - { - /* If PMON doesn't support this register, don't waste serial - bandwidth trying to read it. */ - int pmon_reg = mips_map_regno (regno); - if (regno != 0 && pmon_reg == 0) - val = 0; - else - { - /* Unfortunately the PMON version in the Vr4300 board has been - compiled without the 64bit register access commands. This - means we cannot get hold of the full register width. */ - if (mips_monitor == MON_DDB) - val = (unsigned) mips_request ('t', pmon_reg, 0, - &err, mips_receive_wait, NULL); - else - val = mips_request ('r', pmon_reg, 0, - &err, mips_receive_wait, NULL); - if (err) - mips_error ("Can't read register %d: %s", regno, - safe_strerror (errno)); - } - } - - { - char buf[MAX_REGISTER_RAW_SIZE]; - - /* We got the number the register holds, but gdb expects to see a - value in the target byte ordering. */ - store_unsigned_integer (buf, REGISTER_RAW_SIZE (regno), val); - supply_register (regno, buf); - } -} - -/* Prepare to store registers. The MIPS protocol can store individual - registers, so this function doesn't have to do anything. */ - -static void -mips_prepare_to_store (void) -{ -} - -/* Store remote register(s). */ - -static void -mips_store_registers (int regno) -{ - int err; - - if (regno == -1) - { - for (regno = 0; regno < NUM_REGS; regno++) - mips_store_registers (regno); - return; - } - - mips_request ('R', mips_map_regno (regno), - read_register (regno), - &err, mips_receive_wait, NULL); - if (err) - mips_error ("Can't write register %d: %s", regno, safe_strerror (errno)); -} - -/* Fetch a word from the target board. */ - -static unsigned int -mips_fetch_word (CORE_ADDR addr) -{ - unsigned int val; - int err; - - val = mips_request ('d', addr, 0, &err, mips_receive_wait, NULL); - if (err) - { - /* Data space failed; try instruction space. */ - val = mips_request ('i', addr, 0, &err, - mips_receive_wait, NULL); - if (err) - mips_error ("Can't read address 0x%s: %s", - paddr_nz (addr), safe_strerror (errno)); - } - return val; -} - -/* Store a word to the target board. Returns errno code or zero for - success. If OLD_CONTENTS is non-NULL, put the old contents of that - memory location there. */ - -/* FIXME! make sure only 32-bit quantities get stored! */ -static int -mips_store_word (CORE_ADDR addr, unsigned int val, char *old_contents) -{ - int err; - unsigned int oldcontents; - - oldcontents = mips_request ('D', addr, val, &err, - mips_receive_wait, NULL); - if (err) - { - /* Data space failed; try instruction space. */ - oldcontents = mips_request ('I', addr, val, &err, - mips_receive_wait, NULL); - if (err) - return errno; - } - if (old_contents != NULL) - store_unsigned_integer (old_contents, 4, oldcontents); - return 0; -} - -/* Read or write LEN bytes from inferior memory at MEMADDR, - transferring to or from debugger address MYADDR. Write to inferior - if SHOULD_WRITE is nonzero. Returns length of data written or - read; 0 for error. Note that protocol gives us the correct value - for a longword, since it transfers values in ASCII. We want the - byte values, so we have to swap the longword values. */ - -static int mask_address_p = 1; - -static int -mips_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write, - struct mem_attrib *attrib, struct target_ops *target) -{ - int i; - CORE_ADDR addr; - int count; - char *buffer; - int status; - - /* PMON targets do not cope well with 64 bit addresses. Mask the - value down to 32 bits. */ - if (mask_address_p) - memaddr &= (CORE_ADDR) 0xffffffff; - - /* Round starting address down to longword boundary. */ - addr = memaddr & ~3; - /* Round ending address up; get number of longwords that makes. */ - count = (((memaddr + len) - addr) + 3) / 4; - /* Allocate buffer of that many longwords. */ - buffer = alloca (count * 4); - - if (write) - { - /* Fill start and end extra bytes of buffer with existing data. */ - if (addr != memaddr || len < 4) - { - /* Need part of initial word -- fetch it. */ - store_unsigned_integer (&buffer[0], 4, mips_fetch_word (addr)); - } - - if (count > 1) - { - /* Need part of last word -- fetch it. FIXME: we do this even - if we don't need it. */ - store_unsigned_integer (&buffer[(count - 1) * 4], 4, - mips_fetch_word (addr + (count - 1) * 4)); - } - - /* Copy data to be written over corresponding part of buffer */ - - memcpy ((char *) buffer + (memaddr & 3), myaddr, len); - - /* Write the entire buffer. */ - - for (i = 0; i < count; i++, addr += 4) - { - status = mips_store_word (addr, - extract_unsigned_integer (&buffer[i * 4], 4), - NULL); - /* Report each kilobyte (we download 32-bit words at a time) */ - if (i % 256 == 255) - { - printf_unfiltered ("*"); - gdb_flush (gdb_stdout); - } - if (status) - { - errno = status; - return 0; - } - /* FIXME: Do we want a QUIT here? */ - } - if (count >= 256) - printf_unfiltered ("\n"); - } - else - { - /* Read all the longwords */ - for (i = 0; i < count; i++, addr += 4) - { - store_unsigned_integer (&buffer[i * 4], 4, mips_fetch_word (addr)); - QUIT; - } - - /* Copy appropriate bytes out of the buffer. */ - memcpy (myaddr, buffer + (memaddr & 3), len); - } - return len; -} - -/* Print info on this target. */ - -static void -mips_files_info (struct target_ops *ignore) -{ - printf_unfiltered ("Debugging a MIPS board over a serial line.\n"); -} - -/* Kill the process running on the board. This will actually only - work if we are doing remote debugging over the console input. I - think that if IDT/sim had the remote debug interrupt enabled on the - right port, we could interrupt the process with a break signal. */ - -static void -mips_kill (void) -{ - if (!mips_wait_flag) - return; - - interrupt_count++; - - if (interrupt_count >= 2) - { - interrupt_count = 0; - - target_terminal_ours (); - - if (query ("Interrupted while waiting for the program.\n\ -Give up (and stop debugging it)? ")) - { - /* Clean up in such a way that mips_close won't try to talk to the - board (it almost surely won't work since we weren't able to talk to - it). */ - mips_wait_flag = 0; - close_ports (); - - printf_unfiltered ("Ending remote MIPS debugging.\n"); - target_mourn_inferior (); - - throw_exception (RETURN_QUIT); - } - - target_terminal_inferior (); - } - - if (remote_debug > 0) - printf_unfiltered ("Sending break\n"); - - serial_send_break (mips_desc); - -#if 0 - if (mips_is_open) - { - char cc; - - /* Send a ^C. */ - cc = '\003'; - serial_write (mips_desc, &cc, 1); - sleep (1); - target_mourn_inferior (); - } -#endif -} - -/* Start running on the target board. */ - -static void -mips_create_inferior (char *execfile, char *args, char **env) -{ - CORE_ADDR entry_pt; - - if (args && *args) - { - warning ("\ -Can't pass arguments to remote MIPS board; arguments ignored."); - /* And don't try to use them on the next "run" command. */ - execute_command ("set args", 0); - } - - if (execfile == 0 || exec_bfd == 0) - error ("No executable file specified"); - - entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd); - - init_wait_for_inferior (); - - /* FIXME: Should we set inferior_ptid here? */ - - proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0); -} - -/* Clean up after a process. Actually nothing to do. */ - -static void -mips_mourn_inferior (void) -{ - if (current_ops != NULL) - unpush_target (current_ops); - generic_mourn_inferior (); -} - -/* We can write a breakpoint and read the shadow contents in one - operation. */ - -/* Insert a breakpoint. On targets that don't have built-in breakpoint - support, we read the contents of the target location and stash it, - then overwrite it with a breakpoint instruction. ADDR is the target - location in the target machine. CONTENTS_CACHE is a pointer to - memory allocated for saving the target contents. It is guaranteed - by the caller to be long enough to save sizeof BREAKPOINT bytes (this - is accomplished via BREAKPOINT_MAX). */ - -static int -mips_insert_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - if (monitor_supports_breakpoints) - return set_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH); - else - return memory_insert_breakpoint (addr, contents_cache); -} - -static int -mips_remove_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - if (monitor_supports_breakpoints) - return clear_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH); - else - return memory_remove_breakpoint (addr, contents_cache); -} - -#if 0 /* currently not used */ -/* PMON does not currently provide support for the debug mode 'b' - commands to manipulate breakpoints. However, if we wanted to use - the monitor breakpoints (rather than the GDB BREAK_INSN version) - then this code performs the work needed to leave debug mode, - set/clear the breakpoint, and then return to debug mode. */ - -#define PMON_MAX_BP (33) /* 32 SW, 1 HW */ -static CORE_ADDR mips_pmon_bp_info[PMON_MAX_BP]; -/* NOTE: The code relies on this vector being zero-initialised by the system */ - -static int -pmon_insert_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - int status; - - if (monitor_supports_breakpoints) - { - char tbuff[12]; /* space for breakpoint command */ - int bpnum; - CORE_ADDR bpaddr; - - /* PMON does not support debug level breakpoint set/remove: */ - if (mips_exit_debug ()) - mips_error ("Failed to exit debug mode"); - - sprintf (tbuff, "b %08x\r", addr); - mips_send_command (tbuff, 0); - - mips_expect ("Bpt "); - - if (!mips_getstring (tbuff, remote_timeout)) - return 1; - tbuff[2] = '\0'; /* terminate the string */ - if (sscanf (tbuff, "%d", &bpnum) != 1) - { - fprintf_unfiltered (gdb_stderr, - "Invalid decimal breakpoint number from target: %s\n", tbuff); - return 1; - } - - mips_expect (" = "); - - /* Lead in the hex number we are expecting: */ - tbuff[0] = '0'; - tbuff[1] = 'x'; - - /* FIXME!! only 8 bytes! need to expand for Bfd64; - which targets return 64-bit addresses? PMON returns only 32! */ - if (!mips_getstring (&tbuff[2], 8)) - return 1; - tbuff[10] = '\0'; /* terminate the string */ - - if (sscanf (tbuff, "0x%08x", &bpaddr) != 1) - { - fprintf_unfiltered (gdb_stderr, - "Invalid hex address from target: %s\n", tbuff); - return 1; - } - - if (bpnum >= PMON_MAX_BP) - { - fprintf_unfiltered (gdb_stderr, - "Error: Returned breakpoint number %d outside acceptable range (0..%d)\n", - bpnum, PMON_MAX_BP - 1); - return 1; - } - - if (bpaddr != addr) - fprintf_unfiltered (gdb_stderr, "Warning: Breakpoint addresses do not match: 0x%x != 0x%x\n", addr, bpaddr); - - mips_pmon_bp_info[bpnum] = bpaddr; - - mips_expect ("\r\n"); - mips_expect (mips_monitor_prompt); - - mips_enter_debug (); - - return 0; - } - - return mips_store_word (addr, BREAK_INSN, contents_cache); -} - -static int -pmon_remove_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - if (monitor_supports_breakpoints) - { - int bpnum; - char tbuff[7]; /* enough for delete breakpoint command */ - - for (bpnum = 0; bpnum < PMON_MAX_BP; bpnum++) - if (mips_pmon_bp_info[bpnum] == addr) - break; - - if (bpnum >= PMON_MAX_BP) - { - fprintf_unfiltered (gdb_stderr, - "pmon_remove_breakpoint: Failed to find breakpoint at address 0x%s\n", - paddr_nz (addr)); - return 1; - } - - if (mips_exit_debug ()) - mips_error ("Failed to exit debug mode"); - - sprintf (tbuff, "db %02d\r", bpnum); - - mips_send_command (tbuff, -1); - /* NOTE: If the breakpoint does not exist then a "Bpt <dd> not - set" message will be returned. */ - - mips_enter_debug (); - - return 0; - } - - return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE); -} -#endif - - -/* Tell whether this target can support a hardware breakpoint. CNT - is the number of hardware breakpoints already installed. This - implements the TARGET_CAN_USE_HARDWARE_WATCHPOINT macro. */ - -int -remote_mips_can_use_hardware_watchpoint (int cnt) -{ - return cnt < MAX_LSI_BREAKPOINTS && strcmp (target_shortname, "lsi") == 0; -} - - -/* Compute a don't care mask for the region bounding ADDR and ADDR + LEN - 1. - This is used for memory ref breakpoints. */ - -static unsigned long -calculate_mask (CORE_ADDR addr, int len) -{ - unsigned long mask; - int i; - - mask = addr ^ (addr + len - 1); - - for (i = 32; i >= 0; i--) - if (mask == 0) - break; - else - mask >>= 1; - - mask = (unsigned long) 0xffffffff >> i; - - return mask; -} - - -/* Insert a hardware breakpoint. This works only on LSI targets, which - implement ordinary breakpoints using hardware facilities. */ - -int -remote_mips_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - if (strcmp (target_shortname, "lsi") == 0) - return mips_insert_breakpoint (addr, contents_cache); - else - return -1; -} - - -/* Remove a hardware breakpoint. This works only on LSI targets, which - implement ordinary breakpoints using hardware facilities. */ - -int -remote_mips_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache) -{ - if (strcmp (target_shortname, "lsi") == 0) - return mips_remove_breakpoint (addr, contents_cache); - else - return -1; -} - -/* Set a data watchpoint. ADDR and LEN should be obvious. TYPE is 0 - for a write watchpoint, 1 for a read watchpoint, or 2 for a read/write - watchpoint. */ - -int -remote_mips_set_watchpoint (CORE_ADDR addr, int len, int type) -{ - if (set_breakpoint (addr, len, type)) - return -1; - - return 0; -} - -int -remote_mips_remove_watchpoint (CORE_ADDR addr, int len, int type) -{ - if (clear_breakpoint (addr, len, type)) - return -1; - - return 0; -} - -int -remote_mips_stopped_by_watchpoint (void) -{ - return hit_watchpoint; -} - - -/* Insert a breakpoint. */ - -static int -set_breakpoint (CORE_ADDR addr, int len, enum break_type type) -{ - return common_breakpoint (1, addr, len, type); -} - - -/* Clear a breakpoint. */ - -static int -clear_breakpoint (CORE_ADDR addr, int len, enum break_type type) -{ - return common_breakpoint (0, addr, len, type); -} - - -/* Check the error code from the return packet for an LSI breakpoint - command. If there's no error, just return 0. If it's a warning, - print the warning text and return 0. If it's an error, print - the error text and return 1. <ADDR> is the address of the breakpoint - that was being set. <RERRFLG> is the error code returned by PMON. - This is a helper function for common_breakpoint. */ - -static int -check_lsi_error (CORE_ADDR addr, int rerrflg) -{ - struct lsi_error *err; - char *saddr = paddr_nz (addr); /* printable address string */ - - if (rerrflg == 0) /* no error */ - return 0; - - /* Warnings can be ORed together, so check them all. */ - if (rerrflg & W_WARN) - { - if (monitor_warnings) - { - int found = 0; - for (err = lsi_warning_table; err->code != 0; err++) - { - if ((err->code & rerrflg) == err->code) - { - found = 1; - fprintf_unfiltered (gdb_stderr, - "common_breakpoint (0x%s): Warning: %s\n", - saddr, - err->string); - } - } - if (!found) - fprintf_unfiltered (gdb_stderr, - "common_breakpoint (0x%s): Unknown warning: 0x%x\n", - saddr, - rerrflg); - } - return 0; - } - - /* Errors are unique, i.e. can't be ORed together. */ - for (err = lsi_error_table; err->code != 0; err++) - { - if ((err->code & rerrflg) == err->code) - { - fprintf_unfiltered (gdb_stderr, - "common_breakpoint (0x%s): Error: %s\n", - saddr, - err->string); - return 1; - } - } - fprintf_unfiltered (gdb_stderr, - "common_breakpoint (0x%s): Unknown error: 0x%x\n", - saddr, - rerrflg); - return 1; -} - - -/* This routine sends a breakpoint command to the remote target. - - <SET> is 1 if setting a breakpoint, or 0 if clearing a breakpoint. - <ADDR> is the address of the breakpoint. - <LEN> the length of the region to break on. - <TYPE> is the type of breakpoint: - 0 = write (BREAK_WRITE) - 1 = read (BREAK_READ) - 2 = read/write (BREAK_ACCESS) - 3 = instruction fetch (BREAK_FETCH) - - Return 0 if successful; otherwise 1. */ - -static int -common_breakpoint (int set, CORE_ADDR addr, int len, enum break_type type) -{ - char buf[DATA_MAXLEN + 1]; - char cmd, rcmd; - int rpid, rerrflg, rresponse, rlen; - int nfields; - - addr = ADDR_BITS_REMOVE (addr); - - if (mips_monitor == MON_LSI) - { - if (set == 0) /* clear breakpoint */ - { - /* The LSI PMON "clear breakpoint" has this form: - <pid> 'b' <bptn> 0x0 - reply: - <pid> 'b' 0x0 <code> - - <bptn> is a breakpoint number returned by an earlier 'B' command. - Possible return codes: OK, E_BPT. */ - - int i; - - /* Search for the breakpoint in the table. */ - for (i = 0; i < MAX_LSI_BREAKPOINTS; i++) - if (lsi_breakpoints[i].type == type - && lsi_breakpoints[i].addr == addr - && lsi_breakpoints[i].len == len) - break; - - /* Clear the table entry and tell PMON to clear the breakpoint. */ - if (i == MAX_LSI_BREAKPOINTS) - { - warning ("common_breakpoint: Attempt to clear bogus breakpoint at %s\n", - paddr_nz (addr)); - return 1; - } - - lsi_breakpoints[i].type = BREAK_UNUSED; - sprintf (buf, "0x0 b 0x%x 0x0", i); - mips_send_packet (buf, 1); - - rlen = mips_receive_packet (buf, 1, mips_receive_wait); - buf[rlen] = '\0'; - - nfields = sscanf (buf, "0x%x b 0x0 0x%x", &rpid, &rerrflg); - if (nfields != 2) - mips_error ("common_breakpoint: Bad response from remote board: %s", buf); - - return (check_lsi_error (addr, rerrflg)); - } - else - /* set a breakpoint */ - { - /* The LSI PMON "set breakpoint" command has this form: - <pid> 'B' <addr> 0x0 - reply: - <pid> 'B' <bptn> <code> - - The "set data breakpoint" command has this form: - - <pid> 'A' <addr1> <type> [<addr2> [<value>]] - - where: type= "0x1" = read - "0x2" = write - "0x3" = access (read or write) - - The reply returns two values: - bptn - a breakpoint number, which is a small integer with - possible values of zero through 255. - code - an error return code, a value of zero indicates a - succesful completion, other values indicate various - errors and warnings. - - Possible return codes: OK, W_QAL, E_QAL, E_OUT, E_NON. - - */ - - if (type == BREAK_FETCH) /* instruction breakpoint */ - { - cmd = 'B'; - sprintf (buf, "0x0 B 0x%s 0x0", paddr_nz (addr)); - } - else - /* watchpoint */ - { - cmd = 'A'; - sprintf (buf, "0x0 A 0x%s 0x%x 0x%s", paddr_nz (addr), - type == BREAK_READ ? 1 : (type == BREAK_WRITE ? 2 : 3), - paddr_nz (addr + len - 1)); - } - mips_send_packet (buf, 1); - - rlen = mips_receive_packet (buf, 1, mips_receive_wait); - buf[rlen] = '\0'; - - nfields = sscanf (buf, "0x%x %c 0x%x 0x%x", - &rpid, &rcmd, &rresponse, &rerrflg); - if (nfields != 4 || rcmd != cmd || rresponse > 255) - mips_error ("common_breakpoint: Bad response from remote board: %s", buf); - - if (rerrflg != 0) - if (check_lsi_error (addr, rerrflg)) - return 1; - - /* rresponse contains PMON's breakpoint number. Record the - information for this breakpoint so we can clear it later. */ - lsi_breakpoints[rresponse].type = type; - lsi_breakpoints[rresponse].addr = addr; - lsi_breakpoints[rresponse].len = len; - - return 0; - } - } - else - { - /* On non-LSI targets, the breakpoint command has this form: - 0x0 <CMD> <ADDR> <MASK> <FLAGS> - <MASK> is a don't care mask for addresses. - <FLAGS> is any combination of `r', `w', or `f' for read/write/fetch. - */ - unsigned long mask; - - mask = calculate_mask (addr, len); - addr &= ~mask; - - if (set) /* set a breakpoint */ - { - char *flags; - switch (type) - { - case BREAK_WRITE: /* write */ - flags = "w"; - break; - case BREAK_READ: /* read */ - flags = "r"; - break; - case BREAK_ACCESS: /* read/write */ - flags = "rw"; - break; - case BREAK_FETCH: /* fetch */ - flags = "f"; - break; - default: - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - } - - cmd = 'B'; - sprintf (buf, "0x0 B 0x%s 0x%s %s", paddr_nz (addr), - paddr_nz (mask), flags); - } - else - { - cmd = 'b'; - sprintf (buf, "0x0 b 0x%s", paddr_nz (addr)); - } - - mips_send_packet (buf, 1); - - rlen = mips_receive_packet (buf, 1, mips_receive_wait); - buf[rlen] = '\0'; - - nfields = sscanf (buf, "0x%x %c 0x%x 0x%x", - &rpid, &rcmd, &rerrflg, &rresponse); - - if (nfields != 4 || rcmd != cmd) - mips_error ("common_breakpoint: Bad response from remote board: %s", - buf); - - if (rerrflg != 0) - { - /* Ddb returns "0x0 b 0x16 0x0\000", whereas - Cogent returns "0x0 b 0xffffffff 0x16\000": */ - if (mips_monitor == MON_DDB) - rresponse = rerrflg; - if (rresponse != 22) /* invalid argument */ - fprintf_unfiltered (gdb_stderr, - "common_breakpoint (0x%s): Got error: 0x%x\n", - paddr_nz (addr), rresponse); - return 1; - } - } - return 0; -} - -static void -send_srec (char *srec, int len, CORE_ADDR addr) -{ - while (1) - { - int ch; - - serial_write (mips_desc, srec, len); - - ch = mips_readchar (remote_timeout); - - switch (ch) - { - case SERIAL_TIMEOUT: - error ("Timeout during download."); - break; - case 0x6: /* ACK */ - return; - case 0x15: /* NACK */ - fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %s! Retrying.\n", paddr_u (addr)); - continue; - default: - error ("Download got unexpected ack char: 0x%x, retrying.\n", ch); - } - } -} - -/* Download a binary file by converting it to S records. */ - -static void -mips_load_srec (char *args) -{ - bfd *abfd; - asection *s; - char *buffer, srec[1024]; - unsigned int i; - unsigned int srec_frame = 200; - int reclen; - static int hashmark = 1; - - buffer = alloca (srec_frame * 2 + 256); - - abfd = bfd_openr (args, 0); - if (!abfd) - { - printf_filtered ("Unable to open file %s\n", args); - return; - } - - if (bfd_check_format (abfd, bfd_object) == 0) - { - printf_filtered ("File is not an object file\n"); - return; - } - -/* This actually causes a download in the IDT binary format: */ - mips_send_command (LOAD_CMD, 0); - - for (s = abfd->sections; s; s = s->next) - { - if (s->flags & SEC_LOAD) - { - unsigned int numbytes; - - /* FIXME! vma too small????? */ - printf_filtered ("%s\t: 0x%4lx .. 0x%4lx ", s->name, - (long) s->vma, - (long) (s->vma + s->_raw_size)); - gdb_flush (gdb_stdout); - - for (i = 0; i < s->_raw_size; i += numbytes) - { - numbytes = min (srec_frame, s->_raw_size - i); - - bfd_get_section_contents (abfd, s, buffer, i, numbytes); - - reclen = mips_make_srec (srec, '3', s->vma + i, buffer, numbytes); - send_srec (srec, reclen, s->vma + i); - - if (ui_load_progress_hook) - ui_load_progress_hook (s->name, i); - - if (hashmark) - { - putchar_unfiltered ('#'); - gdb_flush (gdb_stdout); - } - - } /* Per-packet (or S-record) loop */ - - putchar_unfiltered ('\n'); - } /* Loadable sections */ - } - if (hashmark) - putchar_unfiltered ('\n'); - - /* Write a type 7 terminator record. no data for a type 7, and there - is no data, so len is 0. */ - - reclen = mips_make_srec (srec, '7', abfd->start_address, NULL, 0); - - send_srec (srec, reclen, abfd->start_address); - - serial_flush_input (mips_desc); -} - -/* - * mips_make_srec -- make an srecord. This writes each line, one at a - * time, each with it's own header and trailer line. - * An srecord looks like this: - * - * byte count-+ address - * start ---+ | | data +- checksum - * | | | | - * S01000006F6B692D746573742E73726563E4 - * S315000448600000000000000000FC00005900000000E9 - * S31A0004000023C1400037DE00F023604000377B009020825000348D - * S30B0004485A0000000000004E - * S70500040000F6 - * - * S<type><length><address><data><checksum> - * - * Where - * - length - * is the number of bytes following upto the checksum. Note that - * this is not the number of chars following, since it takes two - * chars to represent a byte. - * - type - * is one of: - * 0) header record - * 1) two byte address data record - * 2) three byte address data record - * 3) four byte address data record - * 7) four byte address termination record - * 8) three byte address termination record - * 9) two byte address termination record - * - * - address - * is the start address of the data following, or in the case of - * a termination record, the start address of the image - * - data - * is the data. - * - checksum - * is the sum of all the raw byte data in the record, from the length - * upwards, modulo 256 and subtracted from 255. - * - * This routine returns the length of the S-record. - * - */ - -static int -mips_make_srec (char *buf, int type, CORE_ADDR memaddr, unsigned char *myaddr, - int len) -{ - unsigned char checksum; - int i; - - /* Create the header for the srec. addr_size is the number of bytes in the address, - and 1 is the number of bytes in the count. */ - - /* FIXME!! bigger buf required for 64-bit! */ - buf[0] = 'S'; - buf[1] = type; - buf[2] = len + 4 + 1; /* len + 4 byte address + 1 byte checksum */ - /* This assumes S3 style downloads (4byte addresses). There should - probably be a check, or the code changed to make it more - explicit. */ - buf[3] = memaddr >> 24; - buf[4] = memaddr >> 16; - buf[5] = memaddr >> 8; - buf[6] = memaddr; - memcpy (&buf[7], myaddr, len); - - /* Note that the checksum is calculated on the raw data, not the - hexified data. It includes the length, address and the data - portions of the packet. */ - checksum = 0; - buf += 2; /* Point at length byte */ - for (i = 0; i < len + 4 + 1; i++) - checksum += *buf++; - - *buf = ~checksum; - - return len + 8; -} - -/* The following manifest controls whether we enable the simple flow - control support provided by the monitor. If enabled the code will - wait for an affirmative ACK between transmitting packets. */ -#define DOETXACK (1) - -/* The PMON fast-download uses an encoded packet format constructed of - 3byte data packets (encoded as 4 printable ASCII characters), and - escape sequences (preceded by a '/'): - - 'K' clear checksum - 'C' compare checksum (12bit value, not included in checksum calculation) - 'S' define symbol name (for addr) terminated with "," and padded to 4char boundary - 'Z' zero fill multiple of 3bytes - 'B' byte (12bit encoded value, of 8bit data) - 'A' address (36bit encoded value) - 'E' define entry as original address, and exit load - - The packets are processed in 4 character chunks, so the escape - sequences that do not have any data (or variable length data) - should be padded to a 4 character boundary. The decoder will give - an error if the complete message block size is not a multiple of - 4bytes (size of record). - - The encoding of numbers is done in 6bit fields. The 6bit value is - used to index into this string to get the specific character - encoding for the value: */ -static char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,."; - -/* Convert the number of bits required into an encoded number, 6bits - at a time (range 0..63). Keep a checksum if required (passed - pointer non-NULL). The function returns the number of encoded - characters written into the buffer. */ -static int -pmon_makeb64 (unsigned long v, char *p, int n, int *chksum) -{ - int count = (n / 6); - - if ((n % 12) != 0) - { - fprintf_unfiltered (gdb_stderr, - "Fast encoding bitcount must be a multiple of 12bits: %dbit%s\n", n, (n == 1) ? "" : "s"); - return (0); - } - if (n > 36) - { - fprintf_unfiltered (gdb_stderr, - "Fast encoding cannot process more than 36bits at the moment: %dbits\n", n); - return (0); - } - - /* Deal with the checksum: */ - if (chksum != NULL) - { - switch (n) - { - case 36: - *chksum += ((v >> 24) & 0xFFF); - case 24: - *chksum += ((v >> 12) & 0xFFF); - case 12: - *chksum += ((v >> 0) & 0xFFF); - } - } - - do - { - n -= 6; - *p++ = encoding[(v >> n) & 0x3F]; - } - while (n > 0); - - return (count); -} - -/* Shorthand function (that could be in-lined) to output the zero-fill - escape sequence into the data stream. */ -static int -pmon_zeroset (int recsize, char **buff, int *amount, unsigned int *chksum) -{ - int count; - - sprintf (*buff, "/Z"); - count = pmon_makeb64 (*amount, (*buff + 2), 12, chksum); - *buff += (count + 2); - *amount = 0; - return (recsize + count + 2); -} - -static int -pmon_checkset (int recsize, char **buff, int *value) -{ - int count; - - /* Add the checksum (without updating the value): */ - sprintf (*buff, "/C"); - count = pmon_makeb64 (*value, (*buff + 2), 12, NULL); - *buff += (count + 2); - sprintf (*buff, "\n"); - *buff += 2; /* include zero terminator */ - /* Forcing a checksum validation clears the sum: */ - *value = 0; - return (recsize + count + 3); -} - -/* Amount of padding we leave after at the end of the output buffer, - for the checksum and line termination characters: */ -#define CHECKSIZE (4 + 4 + 4 + 2) -/* zero-fill, checksum, transfer end and line termination space. */ - -/* The amount of binary data loaded from the object file in a single - operation: */ -#define BINCHUNK (1024) - -/* Maximum line of data accepted by the monitor: */ -#define MAXRECSIZE (550) -/* NOTE: This constant depends on the monitor being used. This value - is for PMON 5.x on the Cogent Vr4300 board. */ - -static void -pmon_make_fastrec (char **outbuf, unsigned char *inbuf, int *inptr, - int inamount, int *recsize, unsigned int *csum, - unsigned int *zerofill) -{ - int count = 0; - char *p = *outbuf; - - /* This is a simple check to ensure that our data will fit within - the maximum allowable record size. Each record output is 4bytes - in length. We must allow space for a pending zero fill command, - the record, and a checksum record. */ - while ((*recsize < (MAXRECSIZE - CHECKSIZE)) && ((inamount - *inptr) > 0)) - { - /* Process the binary data: */ - if ((inamount - *inptr) < 3) - { - if (*zerofill != 0) - *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); - sprintf (p, "/B"); - count = pmon_makeb64 (inbuf[*inptr], &p[2], 12, csum); - p += (2 + count); - *recsize += (2 + count); - (*inptr)++; - } - else - { - unsigned int value = ((inbuf[*inptr + 0] << 16) | (inbuf[*inptr + 1] << 8) | inbuf[*inptr + 2]); - /* Simple check for zero data. TODO: A better check would be - to check the last, and then the middle byte for being zero - (if the first byte is not). We could then check for - following runs of zeros, and if above a certain size it is - worth the 4 or 8 character hit of the byte insertions used - to pad to the start of the zeroes. NOTE: This also depends - on the alignment at the end of the zero run. */ - if (value == 0x00000000) - { - (*zerofill)++; - if (*zerofill == 0xFFF) /* 12bit counter */ - *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); - } - else - { - if (*zerofill != 0) - *recsize = pmon_zeroset (*recsize, &p, zerofill, csum); - count = pmon_makeb64 (value, p, 24, csum); - p += count; - *recsize += count; - } - *inptr += 3; - } - } - - *outbuf = p; - return; -} - -static int -pmon_check_ack (char *mesg) -{ -#if defined(DOETXACK) - int c; - - if (!tftp_in_use) - { - c = serial_readchar (udp_in_use ? udp_desc : mips_desc, - remote_timeout); - if ((c == SERIAL_TIMEOUT) || (c != 0x06)) - { - fprintf_unfiltered (gdb_stderr, - "Failed to receive valid ACK for %s\n", mesg); - return (-1); /* terminate the download */ - } - } -#endif /* DOETXACK */ - return (0); -} - -/* pmon_download - Send a sequence of characters to the PMON download port, - which is either a serial port or a UDP socket. */ - -static void -pmon_start_download (void) -{ - if (tftp_in_use) - { - /* Create the temporary download file. */ - if ((tftp_file = fopen (tftp_localname, "w")) == NULL) - perror_with_name (tftp_localname); - } - else - { - mips_send_command (udp_in_use ? LOAD_CMD_UDP : LOAD_CMD, 0); - mips_expect ("Downloading from "); - mips_expect (udp_in_use ? "udp" : "tty0"); - mips_expect (", ^C to abort\r\n"); - } -} - -static int -mips_expect_download (char *string) -{ - if (!mips_expect (string)) - { - fprintf_unfiltered (gdb_stderr, "Load did not complete successfully.\n"); - if (tftp_in_use) - remove (tftp_localname); /* Remove temporary file */ - return 0; - } - else - return 1; -} - -static void -pmon_check_entry_address (char *entry_address, int final) -{ - char hexnumber[9]; /* includes '\0' space */ - mips_expect_timeout (entry_address, tftp_in_use ? 15 : remote_timeout); - sprintf (hexnumber, "%x", final); - mips_expect (hexnumber); - mips_expect ("\r\n"); -} - -static int -pmon_check_total (int bintotal) -{ - char hexnumber[9]; /* includes '\0' space */ - mips_expect ("\r\ntotal = 0x"); - sprintf (hexnumber, "%x", bintotal); - mips_expect (hexnumber); - return mips_expect_download (" bytes\r\n"); -} - -static void -pmon_end_download (int final, int bintotal) -{ - char hexnumber[9]; /* includes '\0' space */ - - if (tftp_in_use) - { - static char *load_cmd_prefix = "load -b -s "; - char *cmd; - struct stat stbuf; - - /* Close off the temporary file containing the load data. */ - fclose (tftp_file); - tftp_file = NULL; - - /* Make the temporary file readable by the world. */ - if (stat (tftp_localname, &stbuf) == 0) - chmod (tftp_localname, stbuf.st_mode | S_IROTH); - - /* Must reinitialize the board to prevent PMON from crashing. */ - mips_send_command ("initEther\r", -1); - - /* Send the load command. */ - cmd = xmalloc (strlen (load_cmd_prefix) + strlen (tftp_name) + 2); - strcpy (cmd, load_cmd_prefix); - strcat (cmd, tftp_name); - strcat (cmd, "\r"); - mips_send_command (cmd, 0); - xfree (cmd); - if (!mips_expect_download ("Downloading from ")) - return; - if (!mips_expect_download (tftp_name)) - return; - if (!mips_expect_download (", ^C to abort\r\n")) - return; - } - - /* Wait for the stuff that PMON prints after the load has completed. - The timeout value for use in the tftp case (15 seconds) was picked - arbitrarily but might be too small for really large downloads. FIXME. */ - switch (mips_monitor) - { - case MON_LSI: - pmon_check_ack ("termination"); - pmon_check_entry_address ("Entry address is ", final); - if (!pmon_check_total (bintotal)) - return; - break; - default: - pmon_check_entry_address ("Entry Address = ", final); - pmon_check_ack ("termination"); - if (!pmon_check_total (bintotal)) - return; - break; - } - - if (tftp_in_use) - remove (tftp_localname); /* Remove temporary file */ -} - -static void -pmon_download (char *buffer, int length) -{ - if (tftp_in_use) - fwrite (buffer, 1, length, tftp_file); - else - serial_write (udp_in_use ? udp_desc : mips_desc, buffer, length); -} - -static void -pmon_load_fast (char *file) -{ - bfd *abfd; - asection *s; - unsigned char *binbuf; - char *buffer; - int reclen; - unsigned int csum = 0; - int hashmark = !tftp_in_use; - int bintotal = 0; - int final = 0; - int finished = 0; - - buffer = (char *) xmalloc (MAXRECSIZE + 1); - binbuf = (unsigned char *) xmalloc (BINCHUNK); - - abfd = bfd_openr (file, 0); - if (!abfd) - { - printf_filtered ("Unable to open file %s\n", file); - return; - } - - if (bfd_check_format (abfd, bfd_object) == 0) - { - printf_filtered ("File is not an object file\n"); - return; - } - - /* Setup the required download state: */ - mips_send_command ("set dlproto etxack\r", -1); - mips_send_command ("set dlecho off\r", -1); - /* NOTE: We get a "cannot set variable" message if the variable is - already defined to have the argument we give. The code doesn't - care, since it just scans to the next prompt anyway. */ - /* Start the download: */ - pmon_start_download (); - - /* Zero the checksum */ - sprintf (buffer, "/Kxx\n"); - reclen = strlen (buffer); - pmon_download (buffer, reclen); - finished = pmon_check_ack ("/Kxx"); - - for (s = abfd->sections; s && !finished; s = s->next) - if (s->flags & SEC_LOAD) /* only deal with loadable sections */ - { - bintotal += s->_raw_size; - final = (s->vma + s->_raw_size); - - printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, (unsigned int) s->vma, - (unsigned int) (s->vma + s->_raw_size)); - gdb_flush (gdb_stdout); - - /* Output the starting address */ - sprintf (buffer, "/A"); - reclen = pmon_makeb64 (s->vma, &buffer[2], 36, &csum); - buffer[2 + reclen] = '\n'; - buffer[3 + reclen] = '\0'; - reclen += 3; /* for the initial escape code and carriage return */ - pmon_download (buffer, reclen); - finished = pmon_check_ack ("/A"); - - if (!finished) - { - unsigned int binamount; - unsigned int zerofill = 0; - char *bp = buffer; - unsigned int i; - - reclen = 0; - - for (i = 0; ((i < s->_raw_size) && !finished); i += binamount) - { - int binptr = 0; - - binamount = min (BINCHUNK, s->_raw_size - i); - - bfd_get_section_contents (abfd, s, binbuf, i, binamount); - - /* This keeps a rolling checksum, until we decide to output - the line: */ - for (; ((binamount - binptr) > 0);) - { - pmon_make_fastrec (&bp, binbuf, &binptr, binamount, &reclen, &csum, &zerofill); - if (reclen >= (MAXRECSIZE - CHECKSIZE)) - { - reclen = pmon_checkset (reclen, &bp, &csum); - pmon_download (buffer, reclen); - finished = pmon_check_ack ("data record"); - if (finished) - { - zerofill = 0; /* do not transmit pending zerofills */ - break; - } - - if (ui_load_progress_hook) - ui_load_progress_hook (s->name, i); - - if (hashmark) - { - putchar_unfiltered ('#'); - gdb_flush (gdb_stdout); - } - - bp = buffer; - reclen = 0; /* buffer processed */ - } - } - } - - /* Ensure no out-standing zerofill requests: */ - if (zerofill != 0) - reclen = pmon_zeroset (reclen, &bp, &zerofill, &csum); - - /* and then flush the line: */ - if (reclen > 0) - { - reclen = pmon_checkset (reclen, &bp, &csum); - /* Currently pmon_checkset outputs the line terminator by - default, so we write out the buffer so far: */ - pmon_download (buffer, reclen); - finished = pmon_check_ack ("record remnant"); - } - } - - putchar_unfiltered ('\n'); - } - - /* Terminate the transfer. We know that we have an empty output - buffer at this point. */ - sprintf (buffer, "/E/E\n"); /* include dummy padding characters */ - reclen = strlen (buffer); - pmon_download (buffer, reclen); - - if (finished) - { /* Ignore the termination message: */ - serial_flush_input (udp_in_use ? udp_desc : mips_desc); - } - else - { /* Deal with termination message: */ - pmon_end_download (final, bintotal); - } - - return; -} - -/* mips_load -- download a file. */ - -static void -mips_load (char *file, int from_tty) -{ - /* Get the board out of remote debugging mode. */ - if (mips_exit_debug ()) - error ("mips_load: Couldn't get into monitor mode."); - - if (mips_monitor != MON_IDT) - pmon_load_fast (file); - else - mips_load_srec (file); - - mips_initialize (); - - /* Finally, make the PC point at the start address */ - if (mips_monitor != MON_IDT) - { - /* Work around problem where PMON monitor updates the PC after a load - to a different value than GDB thinks it has. The following ensures - that the write_pc() WILL update the PC value: */ - register_valid[PC_REGNUM] = 0; - } - if (exec_bfd) - write_pc (bfd_get_start_address (exec_bfd)); - - inferior_ptid = null_ptid; /* No process now */ - -/* This is necessary because many things were based on the PC at the time that - we attached to the monitor, which is no longer valid now that we have loaded - new code (and just changed the PC). Another way to do this might be to call - normal_stop, except that the stack may not be valid, and things would get - horribly confused... */ - - clear_symtab_users (); -} - - -/* Pass the command argument as a packet to PMON verbatim. */ - -static void -pmon_command (char *args, int from_tty) -{ - char buf[DATA_MAXLEN + 1]; - int rlen; - - sprintf (buf, "0x0 %s", args); - mips_send_packet (buf, 1); - printf_filtered ("Send packet: %s\n", buf); - - rlen = mips_receive_packet (buf, 1, mips_receive_wait); - buf[rlen] = '\0'; - printf_filtered ("Received packet: %s\n", buf); -} - -void -_initialize_remote_mips (void) -{ - /* Initialize the fields in mips_ops that are common to all four targets. */ - mips_ops.to_longname = "Remote MIPS debugging over serial line"; - mips_ops.to_close = mips_close; - mips_ops.to_detach = mips_detach; - mips_ops.to_resume = mips_resume; - mips_ops.to_fetch_registers = mips_fetch_registers; - mips_ops.to_store_registers = mips_store_registers; - mips_ops.to_prepare_to_store = mips_prepare_to_store; - mips_ops.to_xfer_memory = mips_xfer_memory; - mips_ops.to_files_info = mips_files_info; - mips_ops.to_insert_breakpoint = mips_insert_breakpoint; - mips_ops.to_remove_breakpoint = mips_remove_breakpoint; - mips_ops.to_kill = mips_kill; - mips_ops.to_load = mips_load; - mips_ops.to_create_inferior = mips_create_inferior; - mips_ops.to_mourn_inferior = mips_mourn_inferior; - mips_ops.to_stratum = process_stratum; - mips_ops.to_has_all_memory = 1; - mips_ops.to_has_memory = 1; - mips_ops.to_has_stack = 1; - mips_ops.to_has_registers = 1; - mips_ops.to_has_execution = 1; - mips_ops.to_magic = OPS_MAGIC; - - /* Copy the common fields to all four target vectors. */ - pmon_ops = ddb_ops = lsi_ops = mips_ops; - - /* Initialize target-specific fields in the target vectors. */ - mips_ops.to_shortname = "mips"; - mips_ops.to_doc = "\ -Debug a board using the MIPS remote debugging protocol over a serial line.\n\ -The argument is the device it is connected to or, if it contains a colon,\n\ -HOST:PORT to access a board over a network"; - mips_ops.to_open = mips_open; - mips_ops.to_wait = mips_wait; - - pmon_ops.to_shortname = "pmon"; - pmon_ops.to_doc = "\ -Debug a board using the PMON MIPS remote debugging protocol over a serial\n\ -line. The argument is the device it is connected to or, if it contains a\n\ -colon, HOST:PORT to access a board over a network"; - pmon_ops.to_open = pmon_open; - pmon_ops.to_wait = mips_wait; - - ddb_ops.to_shortname = "ddb"; - ddb_ops.to_doc = "\ -Debug a board using the PMON MIPS remote debugging protocol over a serial\n\ -line. The first argument is the device it is connected to or, if it contains\n\ -a colon, HOST:PORT to access a board over a network. The optional second\n\ -parameter is the temporary file in the form HOST:FILENAME to be used for\n\ -TFTP downloads to the board. The optional third parameter is the local name\n\ -of the TFTP temporary file, if it differs from the filename seen by the board."; - ddb_ops.to_open = ddb_open; - ddb_ops.to_wait = mips_wait; - - lsi_ops.to_shortname = "lsi"; - lsi_ops.to_doc = pmon_ops.to_doc; - lsi_ops.to_open = lsi_open; - lsi_ops.to_wait = mips_wait; - - /* Add the targets. */ - add_target (&mips_ops); - add_target (&pmon_ops); - add_target (&ddb_ops); - add_target (&lsi_ops); - - add_show_from_set ( - add_set_cmd ("timeout", no_class, var_zinteger, - (char *) &mips_receive_wait, - "Set timeout in seconds for remote MIPS serial I/O.", - &setlist), - &showlist); - - add_show_from_set ( - add_set_cmd ("retransmit-timeout", no_class, var_zinteger, - (char *) &mips_retransmit_wait, - "Set retransmit timeout in seconds for remote MIPS serial I/O.\n\ -This is the number of seconds to wait for an acknowledgement to a packet\n\ -before resending the packet.", &setlist), - &showlist); - - add_show_from_set ( - add_set_cmd ("syn-garbage-limit", no_class, var_zinteger, - (char *) &mips_syn_garbage, - "Set the maximum number of characters to ignore when scanning for a SYN.\n\ -This is the maximum number of characters GDB will ignore when trying to\n\ -synchronize with the remote system. A value of -1 means that there is no limit\n\ -(Note that these characters are printed out even though they are ignored.)", - &setlist), - &showlist); - - add_show_from_set - (add_set_cmd ("monitor-prompt", class_obscure, var_string, - (char *) &mips_monitor_prompt, - "Set the prompt that GDB expects from the monitor.", - &setlist), - &showlist); - - add_show_from_set ( - add_set_cmd ("monitor-warnings", class_obscure, var_zinteger, - (char *) &monitor_warnings, - "Set printing of monitor warnings.\n" - "When enabled, monitor warnings about hardware breakpoints " - "will be displayed.", - &setlist), - &showlist); - - add_com ("pmon <command>", class_obscure, pmon_command, - "Send a packet to PMON (must be in debug mode)."); - - add_show_from_set (add_set_cmd ("mask-address", no_class, - var_boolean, &mask_address_p, - "Set zeroing of upper 32 bits of 64-bit addresses when talking to PMON targets.\n\ -Use \"on\" to enable the masking and \"off\" to disable it.\n", - &setlist), - &showlist); -} diff --git a/contrib/gdb/gdb/remote-rdp.c b/contrib/gdb/gdb/remote-rdp.c deleted file mode 100644 index 2f9183a..0000000 --- a/contrib/gdb/gdb/remote-rdp.c +++ /dev/null @@ -1,1456 +0,0 @@ -/* Remote debugging for the ARM RDP interface. - - Copyright 1994, 1995, 1998, 1999, 2000, 2001, 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. - - - */ - - -/* - Much of this file (in particular the SWI stuff) is based on code by - David Taylor (djt1000@uk.ac.cam.hermes). - - I hacked on and simplified it by removing a lot of sexy features he - had added, and some of the (unix specific) workarounds he'd done - for other GDB problems - which if they still exist should be fixed - in GDB, not in a remote-foo thing . I also made it conform more to - the doc I have; which may be wrong. - - Steve Chamberlain (sac@cygnus.com). - */ - - -#include "defs.h" -#include "inferior.h" -#include "value.h" -#include "callback.h" -#include "command.h" -#include <ctype.h> -#include <fcntl.h> -#include "symfile.h" -#include "remote-utils.h" -#include "gdb_string.h" -#include "gdbcore.h" -#include "regcache.h" -#include "serial.h" - -#include "arm-tdep.h" - -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -extern struct target_ops remote_rdp_ops; -static struct serial *io; -static host_callback *callback = &default_callback; - -struct - { - int step_info; - int break_info; - int model_info; - int target_info; - int can_step; - char command_line[10]; - int rdi_level; - int rdi_stopped_status; - } -ds; - - - -/* Definitions for the RDP protocol. */ - -#define RDP_MOUTHFULL (1<<6) -#define FPU_COPRO_NUMBER 1 - -#define RDP_OPEN 0 -#define RDP_OPEN_TYPE_COLD 0 -#define RDP_OPEN_TYPE_WARM 1 -#define RDP_OPEN_TYPE_BAUDRATE 2 - -#define RDP_OPEN_BAUDRATE_9600 1 -#define RDP_OPEN_BAUDRATE_19200 2 -#define RDP_OPEN_BAUDRATE_38400 3 - -#define RDP_OPEN_TYPE_RETURN_SEX (1<<3) - -#define RDP_CLOSE 1 - -#define RDP_MEM_READ 2 - -#define RDP_MEM_WRITE 3 - -#define RDP_CPU_READ 4 -#define RDP_CPU_WRITE 5 -#define RDP_CPU_READWRITE_MODE_CURRENT 255 -#define RDP_CPU_READWRITE_MASK_PC (1<<16) -#define RDP_CPU_READWRITE_MASK_CPSR (1<<17) -#define RDP_CPU_READWRITE_MASK_SPSR (1<<18) - -#define RDP_COPRO_READ 6 -#define RDP_COPRO_WRITE 7 -#define RDP_FPU_READWRITE_MASK_FPS (1<<8) - -#define RDP_SET_BREAK 0xa -#define RDP_SET_BREAK_TYPE_PC_EQUAL 0 -#define RDP_SET_BREAK_TYPE_GET_HANDLE (0x10) - -#define RDP_CLEAR_BREAK 0xb - -#define RDP_EXEC 0x10 -#define RDP_EXEC_TYPE_SYNC 0 - -#define RDP_STEP 0x11 - -#define RDP_INFO 0x12 -#define RDP_INFO_ABOUT_STEP 2 -#define RDP_INFO_ABOUT_STEP_GT_1 1 -#define RDP_INFO_ABOUT_STEP_TO_JMP 2 -#define RDP_INFO_ABOUT_STEP_1 4 -#define RDP_INFO_ABOUT_TARGET 0 -#define RDP_INFO_ABOUT_BREAK 1 -#define RDP_INFO_ABOUT_BREAK_COMP 1 -#define RDP_INFO_ABOUT_BREAK_RANGE 2 -#define RDP_INFO_ABOUT_BREAK_BYTE_READ 4 -#define RDP_INFO_ABOUT_BREAK_HALFWORD_READ 8 -#define RDP_INFO_ABOUT_BREAK_WORD_READ (1<<4) -#define RDP_INFO_ABOUT_BREAK_BYTE_WRITE (1<<5) -#define RDP_INFO_ABOUT_BREAK_HALFWORD_WRITE (1<<6) -#define RDP_INFO_ABOUT_BREAK_WORD_WRITE (1<<7) -#define RDP_INFO_ABOUT_BREAK_MASK (1<<8) -#define RDP_INFO_ABOUT_BREAK_THREAD_BREAK (1<<9) -#define RDP_INFO_ABOUT_BREAK_THREAD_WATCH (1<<10) -#define RDP_INFO_ABOUT_BREAK_COND (1<<11) -#define RDP_INFO_VECTOR_CATCH (0x180) -#define RDP_INFO_ICEBREAKER (7) -#define RDP_INFO_SET_CMDLINE (0x300) - -#define RDP_SELECT_CONFIG (0x16) -#define RDI_ConfigCPU 0 -#define RDI_ConfigSystem 1 -#define RDI_MatchAny 0 -#define RDI_MatchExactly 1 -#define RDI_MatchNoEarlier 2 - -#define RDP_RESET 0x7f - -/* Returns from RDP */ -#define RDP_RES_STOPPED 0x20 -#define RDP_RES_SWI 0x21 -#define RDP_RES_FATAL 0x5e -#define RDP_RES_VALUE 0x5f -#define RDP_RES_VALUE_LITTLE_ENDIAN 240 -#define RDP_RES_VALUE_BIG_ENDIAN 241 -#define RDP_RES_RESET 0x7f -#define RDP_RES_AT_BREAKPOINT 143 -#define RDP_RES_IDUNNO 0xe6 -#define RDP_OSOpReply 0x13 -#define RDP_OSOpWord 2 -#define RDP_OSOpNothing 0 - -static int timeout = 2; - -static char *commandline = NULL; - -static int -remote_rdp_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len, - int write, - struct mem_attrib *attrib, - struct target_ops *target); - - -/* Stuff for talking to the serial layer. */ - -static unsigned char -get_byte (void) -{ - int c = serial_readchar (io, timeout); - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "[%02x]\n", c); - - if (c == SERIAL_TIMEOUT) - { - if (timeout == 0) - return (unsigned char) c; - - error ("Timeout reading from remote_system"); - } - - return c; -} - -/* Note that the target always speaks little-endian to us, - even if it's a big endian machine. */ -static unsigned int -get_word (void) -{ - unsigned int val = 0; - unsigned int c; - int n; - for (n = 0; n < 4; n++) - { - c = get_byte (); - val |= c << (n * 8); - } - return val; -} - -static void -put_byte (char val) -{ - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "(%02x)\n", val); - serial_write (io, &val, 1); -} - -static void -put_word (int val) -{ - /* We always send in little endian */ - unsigned char b[4]; - b[0] = val; - b[1] = val >> 8; - b[2] = val >> 16; - b[3] = val >> 24; - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "(%04x)", val); - - serial_write (io, b, 4); -} - - - -/* Stuff for talking to the RDP layer. */ - -/* This is a bit more fancy that need be so that it syncs even in nasty cases. - - I'be been unable to make it reliably sync up with the change - baudrate open command. It likes to sit and say it's been reset, - with no more action. So I took all that code out. I'd rather sync - reliably at 9600 than wait forever for a possible 19200 connection. - - */ -static void -rdp_init (int cold, int tty) -{ - int sync = 0; - int type = cold ? RDP_OPEN_TYPE_COLD : RDP_OPEN_TYPE_WARM; - int baudtry = 9600; - - time_t now = time (0); - time_t stop_time = now + 10; /* Try and sync for 10 seconds, then give up */ - - - while (time (0) < stop_time && !sync) - { - int restype; - QUIT; - - serial_flush_input (io); - serial_flush_output (io); - - if (tty) - printf_unfiltered ("Trying to connect at %d baud.\n", baudtry); - - /* - ** It seems necessary to reset an EmbeddedICE to get it going. - ** This has the side benefit of displaying the startup banner. - */ - if (cold) - { - put_byte (RDP_RESET); - while ((restype = serial_readchar (io, 1)) > 0) - { - switch (restype) - { - case SERIAL_TIMEOUT: - break; - case RDP_RESET: - /* Sent at start of reset process: ignore */ - break; - default: - printf_unfiltered ("%c", isgraph (restype) ? restype : ' '); - break; - } - } - - if (restype == 0) - { - /* Got end-of-banner mark */ - printf_filtered ("\n"); - } - } - - put_byte (RDP_OPEN); - - put_byte (type | RDP_OPEN_TYPE_RETURN_SEX); - put_word (0); - - while (!sync && (restype = serial_readchar (io, 1)) > 0) - { - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "[%02x]\n", restype); - - switch (restype) - { - case SERIAL_TIMEOUT: - break; - - case RDP_RESET: - while ((restype = serial_readchar (io, 1)) == RDP_RESET) - ; - do - { - printf_unfiltered ("%c", isgraph (restype) ? restype : ' '); - } - while ((restype = serial_readchar (io, 1)) > 0); - - if (tty) - { - printf_unfiltered ("\nThe board has sent notification that it was reset.\n"); - printf_unfiltered ("Waiting for it to settle down...\n"); - } - sleep (3); - if (tty) - printf_unfiltered ("\nTrying again.\n"); - cold = 0; - break; - - default: - break; - - case RDP_RES_VALUE: - { - int resval = serial_readchar (io, 1); - - if (remote_debug) - fprintf_unfiltered (gdb_stdlog, "[%02x]\n", resval); - - switch (resval) - { - case SERIAL_TIMEOUT: - break; - case RDP_RES_VALUE_LITTLE_ENDIAN: - target_byte_order = BFD_ENDIAN_LITTLE; - sync = 1; - break; - case RDP_RES_VALUE_BIG_ENDIAN: - target_byte_order = BFD_ENDIAN_BIG; - sync = 1; - break; - default: - break; - } - } - } - } - } - - if (!sync) - { - error ("Couldn't reset the board, try pressing the reset button"); - } -} - - -void -send_rdp (char *template,...) -{ - char buf[200]; - char *dst = buf; - va_list alist; - va_start (alist, template); - - while (*template) - { - unsigned int val; - int *pi; - int *pstat; - char *pc; - int i; - switch (*template++) - { - case 'b': - val = va_arg (alist, int); - *dst++ = val; - break; - case 'w': - val = va_arg (alist, int); - *dst++ = val; - *dst++ = val >> 8; - *dst++ = val >> 16; - *dst++ = val >> 24; - break; - case 'S': - val = get_byte (); - if (val != RDP_RES_VALUE) - { - printf_unfiltered ("got bad res value of %d, %x\n", val, val); - } - break; - case 'V': - pstat = va_arg (alist, int *); - pi = va_arg (alist, int *); - - *pstat = get_byte (); - /* Check the result was zero, if not read the syndrome */ - if (*pstat) - { - *pi = get_word (); - } - break; - case 'Z': - /* Check the result code */ - switch (get_byte ()) - { - case 0: - /* Success */ - break; - case 253: - /* Target can't do it; never mind */ - printf_unfiltered ("RDP: Insufficient privilege\n"); - return; - case 254: - /* Target can't do it; never mind */ - printf_unfiltered ("RDP: Unimplemented message\n"); - return; - case 255: - error ("Command garbled"); - break; - default: - error ("Corrupt reply from target"); - break; - } - break; - case 'W': - /* Read a word from the target */ - pi = va_arg (alist, int *); - *pi = get_word (); - break; - case 'P': - /* Read in some bytes from the target. */ - pc = va_arg (alist, char *); - val = va_arg (alist, int); - for (i = 0; i < val; i++) - { - pc[i] = get_byte (); - } - break; - case 'p': - /* send what's being pointed at */ - pc = va_arg (alist, char *); - val = va_arg (alist, int); - dst = buf; - serial_write (io, pc, val); - break; - case '-': - /* Send whats in the queue */ - if (dst != buf) - { - serial_write (io, buf, dst - buf); - dst = buf; - } - break; - case 'B': - pi = va_arg (alist, int *); - *pi = get_byte (); - break; - default: - internal_error (__FILE__, __LINE__, "failed internal consistency check"); - } - } - va_end (alist); - - if (dst != buf) - internal_error (__FILE__, __LINE__, "failed internal consistency check"); -} - - -static int -rdp_write (CORE_ADDR memaddr, char *buf, int len) -{ - int res; - int val; - - send_rdp ("bww-p-SV", RDP_MEM_WRITE, memaddr, len, buf, len, &res, &val); - - if (res) - { - return val; - } - return len; -} - - -static int -rdp_read (CORE_ADDR memaddr, char *buf, int len) -{ - int res; - int val; - send_rdp ("bww-S-P-V", - RDP_MEM_READ, memaddr, len, - buf, len, - &res, &val); - if (res) - { - return val; - } - return len; -} - -static void -rdp_fetch_one_register (int mask, char *buf) -{ - int val; - send_rdp ("bbw-SWZ", RDP_CPU_READ, RDP_CPU_READWRITE_MODE_CURRENT, mask, &val); - store_signed_integer (buf, 4, val); -} - -static void -rdp_fetch_one_fpu_register (int mask, char *buf) -{ -#if 0 - /* !!! Since the PIE board doesn't work as documented, - and it doesn't have FPU hardware anyway and since it - slows everything down, I've disabled this. */ - int val; - if (mask == RDP_FPU_READWRITE_MASK_FPS) - { - /* this guy is only a word */ - send_rdp ("bbw-SWZ", RDP_COPRO_READ, FPU_COPRO_NUMBER, mask, &val); - store_signed_integer (buf, 4, val); - } - else - { - /* There are 12 bytes long - !! fixme about endianness - */ - int dummy; /* I've seen these come back as four words !! */ - send_rdp ("bbw-SWWWWZ", RDP_COPRO_READ, FPU_COPRO_NUMBER, mask, buf + 0, buf + 4, buf + 8, &dummy); - } -#endif - memset (buf, 0, MAX_REGISTER_RAW_SIZE); -} - - -static void -rdp_store_one_register (int mask, char *buf) -{ - int val = extract_unsigned_integer (buf, 4); - - send_rdp ("bbww-SZ", - RDP_CPU_WRITE, RDP_CPU_READWRITE_MODE_CURRENT, mask, val); -} - - -static void -rdp_store_one_fpu_register (int mask, char *buf) -{ -#if 0 - /* See comment in fetch_one_fpu_register */ - if (mask == RDP_FPU_READWRITE_MASK_FPS) - { - int val = extract_unsigned_integer (buf, 4); - /* this guy is only a word */ - send_rdp ("bbww-SZ", RDP_COPRO_WRITE, - FPU_COPRO_NUMBER, - mask, val); - } - else - { - /* There are 12 bytes long - !! fixme about endianness - */ - int dummy = 0; - /* I've seen these come as four words, not the three advertized !! */ - printf ("Sending mask %x\n", mask); - send_rdp ("bbwwwww-SZ", - RDP_COPRO_WRITE, - FPU_COPRO_NUMBER, - mask, - *(int *) (buf + 0), - *(int *) (buf + 4), - *(int *) (buf + 8), - 0); - - printf ("done mask %x\n", mask); - } -#endif -} - - -/* Convert between GDB requests and the RDP layer. */ - -static void -remote_rdp_fetch_register (int regno) -{ - if (regno == -1) - { - for (regno = 0; regno < NUM_REGS; regno++) - remote_rdp_fetch_register (regno); - } - else - { - char buf[MAX_REGISTER_RAW_SIZE]; - if (regno < 15) - rdp_fetch_one_register (1 << regno, buf); - else if (regno == ARM_PC_REGNUM) - rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_PC, buf); - else if (regno == ARM_PS_REGNUM) - rdp_fetch_one_register (RDP_CPU_READWRITE_MASK_CPSR, buf); - else if (regno == ARM_FPS_REGNUM) - rdp_fetch_one_fpu_register (RDP_FPU_READWRITE_MASK_FPS, buf); - else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) - rdp_fetch_one_fpu_register (1 << (regno - ARM_F0_REGNUM), buf); - else - { - printf ("Help me with fetch reg %d\n", regno); - } - supply_register (regno, buf); - } -} - - -static void -remote_rdp_store_register (int regno) -{ - if (regno == -1) - { - for (regno = 0; regno < NUM_REGS; regno++) - remote_rdp_store_register (regno); - } - else - { - char tmp[MAX_REGISTER_RAW_SIZE]; - read_register_gen (regno, tmp); - if (regno < 15) - rdp_store_one_register (1 << regno, tmp); - else if (regno == ARM_PC_REGNUM) - rdp_store_one_register (RDP_CPU_READWRITE_MASK_PC, tmp); - else if (regno == ARM_PS_REGNUM) - rdp_store_one_register (RDP_CPU_READWRITE_MASK_CPSR, tmp); - else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM) - rdp_store_one_fpu_register (1 << (regno - ARM_F0_REGNUM), tmp); - else - { - printf ("Help me with reg %d\n", regno); - } - } -} - -static void -remote_rdp_kill (void) -{ - callback->shutdown (callback); -} - - -static void -rdp_info (void) -{ - send_rdp ("bw-S-W-Z", RDP_INFO, RDP_INFO_ABOUT_STEP, - &ds.step_info); - send_rdp ("bw-S-W-Z", RDP_INFO, RDP_INFO_ABOUT_BREAK, - &ds.break_info); - send_rdp ("bw-S-WW-Z", RDP_INFO, RDP_INFO_ABOUT_TARGET, - &ds.target_info, - &ds.model_info); - - ds.can_step = ds.step_info & RDP_INFO_ABOUT_STEP_1; - - ds.rdi_level = (ds.target_info >> 5) & 3; -} - - -static void -rdp_execute_start (void) -{ - /* Start it off, but don't wait for it */ - send_rdp ("bb-", RDP_EXEC, RDP_EXEC_TYPE_SYNC); -} - - -static void -rdp_set_command_line (char *command, char *args) -{ - /* - ** We could use RDP_INFO_SET_CMDLINE to send this, but EmbeddedICE systems - ** don't implement that, and get all confused at the unexpected text. - ** Instead, just keep a copy, and send it when the target does a SWI_GetEnv - */ - - if (commandline != NULL) - xfree (commandline); - - xasprintf (&commandline, "%s %s", command, args); -} - -static void -rdp_catch_vectors (void) -{ - /* - ** We want the target monitor to intercept the abort vectors - ** i.e. stop the program if any of these are used. - */ - send_rdp ("bww-SZ", RDP_INFO, RDP_INFO_VECTOR_CATCH, - /* - ** Specify a bitmask including - ** the reset vector - ** the undefined instruction vector - ** the prefetch abort vector - ** the data abort vector - ** the address exception vector - */ - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) - ); -} - - - -#define a_byte 1 -#define a_word 2 -#define a_string 3 - - -typedef struct -{ - CORE_ADDR n; - const char *s; -} -argsin; - -#define ABYTE 1 -#define AWORD 2 -#define ASTRING 3 -#define ADDRLEN 4 - -#define SWI_WriteC 0x0 -#define SWI_Write0 0x2 -#define SWI_ReadC 0x4 -#define SWI_CLI 0x5 -#define SWI_GetEnv 0x10 -#define SWI_Exit 0x11 -#define SWI_EnterOS 0x16 - -#define SWI_GetErrno 0x60 -#define SWI_Clock 0x61 - -#define SWI_Time 0x63 -#define SWI_Remove 0x64 -#define SWI_Rename 0x65 -#define SWI_Open 0x66 - -#define SWI_Close 0x68 -#define SWI_Write 0x69 -#define SWI_Read 0x6a -#define SWI_Seek 0x6b -#define SWI_Flen 0x6c - -#define SWI_IsTTY 0x6e -#define SWI_TmpNam 0x6f -#define SWI_InstallHandler 0x70 -#define SWI_GenerateError 0x71 - - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -static int translate_open_mode[] = -{ - O_RDONLY, /* "r" */ - O_RDONLY + O_BINARY, /* "rb" */ - O_RDWR, /* "r+" */ - O_RDWR + O_BINARY, /* "r+b" */ - O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ - O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ - O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ - O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ - O_WRONLY + O_APPEND + O_CREAT, /* "a" */ - O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ - O_RDWR + O_APPEND + O_CREAT, /* "a+" */ - O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ -}; - -static int -exec_swi (int swi, argsin *args) -{ - int i; - char c; - switch (swi) - { - case SWI_WriteC: - callback->write_stdout (callback, &c, 1); - return 0; - case SWI_Write0: - for (i = 0; i < args->n; i++) - callback->write_stdout (callback, args->s, strlen (args->s)); - return 0; - case SWI_ReadC: - callback->read_stdin (callback, &c, 1); - args->n = c; - return 1; - case SWI_CLI: - args->n = callback->system (callback, args->s); - return 1; - case SWI_GetErrno: - args->n = callback->get_errno (callback); - return 1; - case SWI_Time: - args->n = callback->time (callback, NULL); - return 1; - - case SWI_Clock: - /* return number of centi-seconds... */ - args->n = -#ifdef CLOCKS_PER_SEC - (CLOCKS_PER_SEC >= 100) - ? (clock () / (CLOCKS_PER_SEC / 100)) - : ((clock () * 100) / CLOCKS_PER_SEC); -#else - /* presume unix... clock() returns microseconds */ - clock () / 10000; -#endif - return 1; - - case SWI_Remove: - args->n = callback->unlink (callback, args->s); - return 1; - case SWI_Rename: - args->n = callback->rename (callback, args[0].s, args[1].s); - return 1; - - case SWI_Open: - /* Now we need to decode the Demon open mode */ - i = translate_open_mode[args[1].n]; - - /* Filename ":tt" is special: it denotes stdin/out */ - if (strcmp (args->s, ":tt") == 0) - { - if (i == O_RDONLY) /* opening tty "r" */ - args->n = 0 /* stdin */ ; - else - args->n = 1 /* stdout */ ; - } - else - args->n = callback->open (callback, args->s, i); - return 1; - - case SWI_Close: - args->n = callback->close (callback, args->n); - return 1; - - case SWI_Write: - /* Return the number of bytes *not* written */ - args->n = args[1].n - - callback->write (callback, args[0].n, args[1].s, args[1].n); - return 1; - - case SWI_Read: - { - char *copy = alloca (args[2].n); - int done = callback->read (callback, args[0].n, copy, args[2].n); - if (done > 0) - remote_rdp_xfer_inferior_memory (args[1].n, copy, done, 1, 0, 0); - args->n = args[2].n - done; - return 1; - } - - case SWI_Seek: - /* Return non-zero on failure */ - args->n = callback->lseek (callback, args[0].n, args[1].n, 0) < 0; - return 1; - - case SWI_Flen: - { - long old = callback->lseek (callback, args->n, 0, SEEK_CUR); - args->n = callback->lseek (callback, args->n, 0, SEEK_END); - callback->lseek (callback, args->n, old, 0); - return 1; - } - - case SWI_IsTTY: - args->n = callback->isatty (callback, args->n); - return 1; - - case SWI_GetEnv: - if (commandline != NULL) - { - int len = strlen (commandline); - if (len > 255) - { - len = 255; - commandline[255] = '\0'; - } - remote_rdp_xfer_inferior_memory (args[0].n, - commandline, len + 1, 1, 0, 0); - } - else - remote_rdp_xfer_inferior_memory (args[0].n, "", 1, 1, 0, 0); - return 1; - - default: - return 0; - } -} - - -static void -handle_swi (void) -{ - argsin args[3]; - char *buf; - int len; - int count = 0; - - int swino = get_word (); - int type = get_byte (); - while (type != 0) - { - switch (type & 0x3) - { - case ABYTE: - args[count].n = get_byte (); - break; - - case AWORD: - args[count].n = get_word (); - break; - - case ASTRING: - /* If the word is under 32 bytes it will be sent otherwise - an address to it is passed. Also: Special case of 255 */ - - len = get_byte (); - if (len > 32) - { - if (len == 255) - { - len = get_word (); - } - buf = alloca (len); - remote_rdp_xfer_inferior_memory (get_word (), - buf, - len, - 0, - 0, - 0); - } - else - { - int i; - buf = alloca (len + 1); - for (i = 0; i < len; i++) - buf[i] = get_byte (); - buf[i] = 0; - } - args[count].n = len; - args[count].s = buf; - break; - - default: - error ("Unimplemented SWI argument"); - } - - type = type >> 2; - count++; - } - - if (exec_swi (swino, args)) - { - /* We have two options here reply with either a byte or a word - which is stored in args[0].n. There is no harm in replying with - a word all the time, so thats what I do! */ - send_rdp ("bbw-", RDP_OSOpReply, RDP_OSOpWord, args[0].n); - } - else - { - send_rdp ("bb-", RDP_OSOpReply, RDP_OSOpNothing); - } -} - -static void -rdp_execute_finish (void) -{ - int running = 1; - - while (running) - { - int res; - res = serial_readchar (io, 1); - while (res == SERIAL_TIMEOUT) - { - QUIT; - printf_filtered ("Waiting for target..\n"); - res = serial_readchar (io, 1); - } - - switch (res) - { - case RDP_RES_SWI: - handle_swi (); - break; - case RDP_RES_VALUE: - send_rdp ("B", &ds.rdi_stopped_status); - running = 0; - break; - case RDP_RESET: - printf_filtered ("Target reset\n"); - running = 0; - break; - default: - printf_filtered ("Ignoring %x\n", res); - break; - } - } -} - - -static void -rdp_execute (void) -{ - rdp_execute_start (); - rdp_execute_finish (); -} - -static int -remote_rdp_insert_breakpoint (CORE_ADDR addr, char *save) -{ - int res; - if (ds.rdi_level > 0) - { - send_rdp ("bwb-SWB", - RDP_SET_BREAK, - addr, - RDP_SET_BREAK_TYPE_PC_EQUAL | RDP_SET_BREAK_TYPE_GET_HANDLE, - save, - &res); - } - else - { - send_rdp ("bwb-SB", - RDP_SET_BREAK, - addr, - RDP_SET_BREAK_TYPE_PC_EQUAL, - &res); - } - return res; -} - -static int -remote_rdp_remove_breakpoint (CORE_ADDR addr, char *save) -{ - int res; - if (ds.rdi_level > 0) - { - send_rdp ("b-p-S-B", - RDP_CLEAR_BREAK, - save, 4, - &res); - } - else - { - send_rdp ("bw-S-B", - RDP_CLEAR_BREAK, - addr, - &res); - } - return res; -} - -static void -rdp_step (void) -{ - if (ds.can_step && 0) - { - /* The pie board can't do steps so I can't test this, and - the other code will always work. */ - int status; - send_rdp ("bbw-S-B", - RDP_STEP, 0, 1, - &status); - } - else - { - char handle[4]; - CORE_ADDR pc = read_register (ARM_PC_REGNUM); - pc = arm_get_next_pc (pc); - remote_rdp_insert_breakpoint (pc, handle); - rdp_execute (); - remote_rdp_remove_breakpoint (pc, handle); - } -} - -static void -remote_rdp_open (char *args, int from_tty) -{ - int not_icebreaker; - - if (!args) - error_no_arg ("serial port device name"); - - baud_rate = 9600; - - target_preopen (from_tty); - - io = serial_open (args); - - if (!io) - perror_with_name (args); - - serial_raw (io); - - rdp_init (1, from_tty); - - - if (from_tty) - { - printf_unfiltered ("Remote RDP debugging using %s at %d baud\n", args, baud_rate); - } - - rdp_info (); - - /* Need to set up the vector interception state */ - rdp_catch_vectors (); - - /* - ** If it's an EmbeddedICE, we need to set the processor config. - ** Assume we can always have ARM7TDI... - */ - send_rdp ("bw-SB", RDP_INFO, RDP_INFO_ICEBREAKER, ¬_icebreaker); - if (!not_icebreaker) - { - const char *CPU = "ARM7TDI"; - int ICEversion; - int len = strlen (CPU); - - send_rdp ("bbbbw-p-SWZ", - RDP_SELECT_CONFIG, - RDI_ConfigCPU, /* Aspect: set the CPU */ - len, /* The number of bytes in the name */ - RDI_MatchAny, /* We'll take whatever we get */ - 0, /* We'll take whatever version's there */ - CPU, len, - &ICEversion); - } - - /* command line initialised on 'run' */ - - push_target (&remote_rdp_ops); - - callback->init (callback); - flush_cached_frames (); - registers_changed (); - stop_pc = read_pc (); - set_current_frame (create_new_frame (read_fp (), stop_pc)); - select_frame (get_current_frame (), 0); - print_stack_frame (selected_frame, -1, 1); -} - - - -/* Close out all files and local state before this target loses control. */ - -static void -remote_rdp_close (int quitting) -{ - callback->shutdown (callback); - if (io) - serial_close (io); - io = 0; -} - - -/* Resume execution of the target process. STEP says whether to single-step - or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given - to the target, or zero for no signal. */ - -static void -remote_rdp_resume (ptid_t ptid, int step, enum target_signal siggnal) -{ - if (step) - rdp_step (); - else - rdp_execute (); -} - -/* 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 ptid_t -remote_rdp_wait (ptid_t ptid, struct target_waitstatus *status) -{ - switch (ds.rdi_stopped_status) - { - default: - case RDP_RES_RESET: - case RDP_RES_SWI: - status->kind = TARGET_WAITKIND_EXITED; - status->value.integer = read_register (0); - break; - case RDP_RES_AT_BREAKPOINT: - status->kind = TARGET_WAITKIND_STOPPED; - /* The signal in sigrc is a host signal. That probably - should be fixed. */ - status->value.sig = TARGET_SIGNAL_TRAP; - break; -#if 0 - case rdp_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; -#endif - } - - 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 -remote_rdp_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 -remote_rdp_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len, - int write, struct mem_attrib *attrib, - struct target_ops *target) -{ - /* I infer from D Taylor's code that there's a limit on the amount - we can transfer in one chunk.. */ - int done = 0; - while (done < len) - { - int justdone; - int thisbite = len - done; - if (thisbite > RDP_MOUTHFULL) - thisbite = RDP_MOUTHFULL; - - QUIT; - - if (write) - { - justdone = rdp_write (memaddr + done, myaddr + done, thisbite); - } - else - { - justdone = rdp_read (memaddr + done, myaddr + done, thisbite); - } - - done += justdone; - - if (justdone != thisbite) - break; - } - return done; -} - - - -struct yn -{ - const char *name; - int bit; -}; -static struct yn stepinfo[] = -{ - {"Step more than one instruction", RDP_INFO_ABOUT_STEP_GT_1}, - {"Step to jump", RDP_INFO_ABOUT_STEP_TO_JMP}, - {"Step one instruction", RDP_INFO_ABOUT_STEP_1}, - {0} -}; - -static struct yn breakinfo[] = -{ - {"comparison breakpoints supported", RDP_INFO_ABOUT_BREAK_COMP}, - {"range breakpoints supported", RDP_INFO_ABOUT_BREAK_RANGE}, - {"watchpoints for byte reads supported", RDP_INFO_ABOUT_BREAK_BYTE_READ}, - {"watchpoints for half-word reads supported", RDP_INFO_ABOUT_BREAK_HALFWORD_READ}, - {"watchpoints for word reads supported", RDP_INFO_ABOUT_BREAK_WORD_READ}, - {"watchpoints for byte writes supported", RDP_INFO_ABOUT_BREAK_BYTE_WRITE}, - {"watchpoints for half-word writes supported", RDP_INFO_ABOUT_BREAK_HALFWORD_WRITE}, - {"watchpoints for word writes supported", RDP_INFO_ABOUT_BREAK_WORD_WRITE}, - {"mask break/watch-points supported", RDP_INFO_ABOUT_BREAK_MASK}, -{"thread-specific breakpoints supported", RDP_INFO_ABOUT_BREAK_THREAD_BREAK}, -{"thread-specific watchpoints supported", RDP_INFO_ABOUT_BREAK_THREAD_WATCH}, - {"conditional breakpoints supported", RDP_INFO_ABOUT_BREAK_COND}, - {0} -}; - - -static void -dump_bits (struct yn *t, int info) -{ - while (t->name) - { - printf_unfiltered (" %-45s : %s\n", t->name, (info & t->bit) ? "Yes" : "No"); - t++; - } -} - -static void -remote_rdp_files_info (struct target_ops *target) -{ - printf_filtered ("Target capabilities:\n"); - dump_bits (stepinfo, ds.step_info); - dump_bits (breakinfo, ds.break_info); - printf_unfiltered ("target level RDI %x\n", (ds.target_info >> 5) & 3); -} - - -static void -remote_rdp_create_inferior (char *exec_file, char *allargs, char **env) -{ - CORE_ADDR entry_point; - - if (exec_file == 0 || exec_bfd == 0) - error ("No executable file specified."); - - entry_point = (CORE_ADDR) bfd_get_start_address (exec_bfd); - - remote_rdp_kill (); - remove_breakpoints (); - init_wait_for_inferior (); - - /* This gives us a chance to set up the command line */ - rdp_set_command_line (exec_file, allargs); - - inferior_ptid = pid_to_ptid (42); - insert_breakpoints (); /* Needed to get correct instruction in cache */ - - /* - ** RDP targets don't provide any facility to set the top of memory, - ** so we don't bother to look for MEMSIZE in the environment. - */ - - /* Let's go! */ - proceed (entry_point, TARGET_SIGNAL_DEFAULT, 0); -} - -/* Accept any stray run/attach commands */ -static int -remote_rdp_can_run (void) -{ - return 1; -} - -/* Attach doesn't need to do anything */ -static void -remote_rdp_attach (char *args, int from_tty) -{ - return; -} - -/* Define the target subroutine names */ - -struct target_ops remote_rdp_ops; - -static void -init_remote_rdp_ops (void) -{ - remote_rdp_ops.to_shortname = "rdp"; - remote_rdp_ops.to_longname = "Remote Target using the RDProtocol"; - remote_rdp_ops.to_doc = "Use a remote ARM system which uses the ARM Remote Debugging Protocol"; - remote_rdp_ops.to_open = remote_rdp_open; - remote_rdp_ops.to_close = remote_rdp_close; - remote_rdp_ops.to_attach = remote_rdp_attach; - remote_rdp_ops.to_post_attach = NULL; - remote_rdp_ops.to_require_attach = NULL; - remote_rdp_ops.to_detach = NULL; - remote_rdp_ops.to_require_detach = NULL; - remote_rdp_ops.to_resume = remote_rdp_resume; - remote_rdp_ops.to_wait = remote_rdp_wait; - remote_rdp_ops.to_post_wait = NULL; - remote_rdp_ops.to_fetch_registers = remote_rdp_fetch_register; - remote_rdp_ops.to_store_registers = remote_rdp_store_register; - remote_rdp_ops.to_prepare_to_store = remote_rdp_prepare_to_store; - remote_rdp_ops.to_xfer_memory = remote_rdp_xfer_inferior_memory; - remote_rdp_ops.to_files_info = remote_rdp_files_info; - remote_rdp_ops.to_insert_breakpoint = remote_rdp_insert_breakpoint; - remote_rdp_ops.to_remove_breakpoint = remote_rdp_remove_breakpoint; - remote_rdp_ops.to_terminal_init = NULL; - remote_rdp_ops.to_terminal_inferior = NULL; - remote_rdp_ops.to_terminal_ours_for_output = NULL; - remote_rdp_ops.to_terminal_ours = NULL; - remote_rdp_ops.to_terminal_info = NULL; - remote_rdp_ops.to_kill = remote_rdp_kill; - remote_rdp_ops.to_load = generic_load; - remote_rdp_ops.to_lookup_symbol = NULL; - remote_rdp_ops.to_create_inferior = remote_rdp_create_inferior; - remote_rdp_ops.to_post_startup_inferior = NULL; - remote_rdp_ops.to_acknowledge_created_inferior = NULL; - remote_rdp_ops.to_clone_and_follow_inferior = NULL; - remote_rdp_ops.to_post_follow_inferior_by_clone = NULL; - remote_rdp_ops.to_insert_fork_catchpoint = NULL; - remote_rdp_ops.to_remove_fork_catchpoint = NULL; - remote_rdp_ops.to_insert_vfork_catchpoint = NULL; - remote_rdp_ops.to_remove_vfork_catchpoint = NULL; - remote_rdp_ops.to_has_forked = NULL; - remote_rdp_ops.to_has_vforked = NULL; - remote_rdp_ops.to_can_follow_vfork_prior_to_exec = NULL; - remote_rdp_ops.to_post_follow_vfork = NULL; - remote_rdp_ops.to_insert_exec_catchpoint = NULL; - remote_rdp_ops.to_remove_exec_catchpoint = NULL; - remote_rdp_ops.to_has_execd = NULL; - remote_rdp_ops.to_reported_exec_events_per_exec_call = NULL; - remote_rdp_ops.to_has_exited = NULL; - remote_rdp_ops.to_mourn_inferior = generic_mourn_inferior; - remote_rdp_ops.to_can_run = remote_rdp_can_run; - remote_rdp_ops.to_notice_signals = 0; - remote_rdp_ops.to_thread_alive = 0; - remote_rdp_ops.to_stop = 0; - remote_rdp_ops.to_pid_to_exec_file = NULL; - remote_rdp_ops.to_stratum = process_stratum; - remote_rdp_ops.DONT_USE = NULL; - remote_rdp_ops.to_has_all_memory = 1; - remote_rdp_ops.to_has_memory = 1; - remote_rdp_ops.to_has_stack = 1; - remote_rdp_ops.to_has_registers = 1; - remote_rdp_ops.to_has_execution = 1; - remote_rdp_ops.to_sections = NULL; - remote_rdp_ops.to_sections_end = NULL; - remote_rdp_ops.to_magic = OPS_MAGIC; -} - -void -_initialize_remote_rdp (void) -{ - init_remote_rdp_ops (); - add_target (&remote_rdp_ops); -} diff --git a/contrib/gdb/gdb/remote-sim.c b/contrib/gdb/gdb/remote-sim.c deleted file mode 100644 index 1d037c8..0000000 --- a/contrib/gdb/gdb/remote-sim.c +++ /dev/null @@ -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."); -} diff --git a/contrib/gdb/gdb/remote-st.c b/contrib/gdb/gdb/remote-st.c deleted file mode 100644 index 46d8eab..0000000 --- a/contrib/gdb/gdb/remote-st.c +++ /dev/null @@ -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."); -} diff --git a/contrib/gdb/gdb/srec.h b/contrib/gdb/gdb/srec.h deleted file mode 100644 index d2d9876..0000000 --- a/contrib/gdb/gdb/srec.h +++ /dev/null @@ -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 */ diff --git a/contrib/gdb/gdb/standalone.c b/contrib/gdb/gdb/standalone.c deleted file mode 100644 index 6ae8f53..0000000 --- a/contrib/gdb/gdb/standalone.c +++ /dev/null @@ -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; -} diff --git a/contrib/gdb/gdb/xcoffread.c b/contrib/gdb/gdb/xcoffread.c deleted file mode 100644 index 965473a..0000000 --- a/contrib/gdb/gdb/xcoffread.c +++ /dev/null @@ -1,3046 +0,0 @@ -/* Read AIX xcoff symbol tables and convert to internal format, for GDB. - Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, - 1996, 1997, 1998, 1999, 2000, 2001 - Free Software Foundation, Inc. - Derived from coffread.c, dbxread.c, and a lot of hacking. - 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 <sys/types.h> -#include <fcntl.h> -#include <ctype.h> -#include "gdb_string.h" - -#include <sys/param.h> -#ifndef NO_SYS_FILE -#include <sys/file.h> -#endif -#include "gdb_stat.h" - -#include "coff/internal.h" -#include "libcoff.h" /* FIXME, internal data from BFD */ -#include "coff/rs6000.h" - -#include "symtab.h" -#include "gdbtypes.h" -#include "symfile.h" -#include "objfiles.h" -#include "buildsym.h" -#include "stabsread.h" -#include "expression.h" -#include "complaints.h" - -#include "gdb-stabs.h" - -/* For interface with stabsread.c. */ -#include "aout/stab_gnu.h" - - -/* We put a pointer to this structure in the read_symtab_private field - of the psymtab. */ - -struct symloc - { - - /* First symbol number for this file. */ - - int first_symnum; - - /* Number of symbols in the section of the symbol table devoted to - this file's symbols (actually, the section bracketed may contain - more than just this file's symbols). If numsyms is 0, the only - reason for this thing's existence is the dependency list. Nothing - else will happen when it is read in. */ - - int numsyms; - - /* Position of the start of the line number information for this psymtab. */ - unsigned int lineno_off; - }; - -/* Remember what we deduced to be the source language of this psymtab. */ - -static enum language psymtab_language = language_unknown; - - -/* Simplified internal version of coff symbol table information */ - -struct coff_symbol - { - char *c_name; - int c_symnum; /* symbol number of this entry */ - int c_naux; /* 0 if syment only, 1 if syment + auxent */ - long c_value; - unsigned char c_sclass; - int c_secnum; - unsigned int c_type; - }; - -/* last function's saved coff symbol `cs' */ - -static struct coff_symbol fcn_cs_saved; - -static bfd *symfile_bfd; - -/* Core address of start and end of text of current source file. - This is calculated from the first function seen after a C_FILE - symbol. */ - - -static CORE_ADDR cur_src_end_addr; - -/* Core address of the end of the first object file. */ - -static CORE_ADDR first_object_file_end; - -/* initial symbol-table-debug-string vector length */ - -#define INITIAL_STABVECTOR_LENGTH 40 - -/* Nonzero if within a function (so symbols should be local, - if nothing says specifically). */ - -int within_function; - -/* Size of a COFF symbol. I think it is always 18, so I'm not sure - there is any reason not to just use a #define, but might as well - ask BFD for the size and store it here, I guess. */ - -static unsigned local_symesz; - -struct coff_symfile_info - { - file_ptr min_lineno_offset; /* Where in file lowest line#s are */ - file_ptr max_lineno_offset; /* 1+last byte of line#s in file */ - - /* Pointer to the string table. */ - char *strtbl; - - /* Pointer to debug section. */ - char *debugsec; - - /* Pointer to the a.out symbol table. */ - char *symtbl; - - /* Number of symbols in symtbl. */ - int symtbl_num_syms; - - /* Offset in data section to TOC anchor. */ - CORE_ADDR toc_offset; - }; - -static struct complaint storclass_complaint = -{"Unexpected storage class: %d", 0, 0}; - -static struct complaint bf_notfound_complaint = -{"line numbers off, `.bf' symbol not found", 0, 0}; - -static struct complaint ef_complaint = -{"Mismatched .ef symbol ignored starting at symnum %d", 0, 0}; - -static struct complaint eb_complaint = -{"Mismatched .eb symbol ignored starting at symnum %d", 0, 0}; - -static void xcoff_initial_scan (struct objfile *, int); - -static void scan_xcoff_symtab (struct objfile *); - -static char *xcoff_next_symbol_text (struct objfile *); - -static void record_include_begin (struct coff_symbol *); - -static void -enter_line_range (struct subfile *, unsigned, unsigned, - CORE_ADDR, CORE_ADDR, unsigned *); - -static void init_stringtab (bfd *, file_ptr, struct objfile *); - -static void xcoff_symfile_init (struct objfile *); - -static void xcoff_new_init (struct objfile *); - -static void xcoff_symfile_finish (struct objfile *); - -static void -xcoff_symfile_offsets (struct objfile *, struct section_addr_info *addrs); - -static void find_linenos (bfd *, sec_ptr, PTR); - -static char *coff_getfilename (union internal_auxent *, struct objfile *); - -static void read_symbol (struct internal_syment *, int); - -static int read_symbol_lineno (int); - -static CORE_ADDR read_symbol_nvalue (int); - -static struct symbol *process_xcoff_symbol (struct coff_symbol *, - struct objfile *); - -static void read_xcoff_symtab (struct partial_symtab *); - -#if 0 -static void add_stab_to_list (char *, struct pending_stabs **); -#endif - -static int compare_lte (const void *, const void *); - -static struct linetable *arrange_linetable (struct linetable *); - -static void record_include_end (struct coff_symbol *); - -static void process_linenos (CORE_ADDR, CORE_ADDR); - - -/* Translate from a COFF section number (target_index) to a SECT_OFF_* - code. */ -static int secnum_to_section (int, struct objfile *); -static asection *secnum_to_bfd_section (int, struct objfile *); - -struct find_targ_sec_arg - { - int targ_index; - int *resultp; - asection **bfd_sect; - struct objfile *objfile; - }; - -static void find_targ_sec (bfd *, asection *, void *); - -static void -find_targ_sec (bfd *abfd, asection *sect, PTR obj) -{ - struct find_targ_sec_arg *args = (struct find_targ_sec_arg *) obj; - struct objfile *objfile = args->objfile; - if (sect->target_index == args->targ_index) - { - /* This is the section. Figure out what SECT_OFF_* code it is. */ - if (bfd_get_section_flags (abfd, sect) & SEC_CODE) - *args->resultp = SECT_OFF_TEXT (objfile); - else if (bfd_get_section_flags (abfd, sect) & SEC_LOAD) - *args->resultp = SECT_OFF_DATA (objfile); - else - *args->resultp = sect->index; - *args->bfd_sect = sect; - } -} - -/* Return the section number (SECT_OFF_*) that CS points to. */ -static int -secnum_to_section (int secnum, struct objfile *objfile) -{ - int off = SECT_OFF_TEXT (objfile); - asection *sect = NULL; - struct find_targ_sec_arg args; - args.targ_index = secnum; - args.resultp = &off; - args.bfd_sect = § - args.objfile = objfile; - bfd_map_over_sections (objfile->obfd, find_targ_sec, &args); - return off; -} - -/* Return the BFD section that CS points to. */ -static asection * -secnum_to_bfd_section (int secnum, struct objfile *objfile) -{ - int off = SECT_OFF_TEXT (objfile); - asection *sect = NULL; - struct find_targ_sec_arg args; - args.targ_index = secnum; - args.resultp = &off; - args.bfd_sect = § - args.objfile = objfile; - bfd_map_over_sections (objfile->obfd, find_targ_sec, &args); - return sect; -} - -/* add a given stab string into given stab vector. */ - -#if 0 - -static void -add_stab_to_list (char *stabname, struct pending_stabs **stabvector) -{ - if (*stabvector == NULL) - { - *stabvector = (struct pending_stabs *) - xmalloc (sizeof (struct pending_stabs) + - INITIAL_STABVECTOR_LENGTH * sizeof (char *)); - (*stabvector)->count = 0; - (*stabvector)->length = INITIAL_STABVECTOR_LENGTH; - } - else if ((*stabvector)->count >= (*stabvector)->length) - { - (*stabvector)->length += INITIAL_STABVECTOR_LENGTH; - *stabvector = (struct pending_stabs *) - xrealloc ((char *) *stabvector, sizeof (struct pending_stabs) + - (*stabvector)->length * sizeof (char *)); - } - (*stabvector)->stab[(*stabvector)->count++] = stabname; -} - -#endif -/* *INDENT-OFF* */ -/* Linenos are processed on a file-by-file basis. - - Two reasons: - - 1) xlc (IBM's native c compiler) postpones static function code - emission to the end of a compilation unit. This way it can - determine if those functions (statics) are needed or not, and - can do some garbage collection (I think). This makes line - numbers and corresponding addresses unordered, and we end up - with a line table like: - - - lineno addr - foo() 10 0x100 - 20 0x200 - 30 0x300 - - foo3() 70 0x400 - 80 0x500 - 90 0x600 - - static foo2() - 40 0x700 - 50 0x800 - 60 0x900 - - and that breaks gdb's binary search on line numbers, if the - above table is not sorted on line numbers. And that sort - should be on function based, since gcc can emit line numbers - like: - - 10 0x100 - for the init/test part of a for stmt. - 20 0x200 - 30 0x300 - 10 0x400 - for the increment part of a for stmt. - - arrange_linetable() will do this sorting. - - 2) aix symbol table might look like: - - c_file // beginning of a new file - .bi // beginning of include file - .ei // end of include file - .bi - .ei - - basically, .bi/.ei pairs do not necessarily encapsulate - their scope. They need to be recorded, and processed later - on when we come the end of the compilation unit. - Include table (inclTable) and process_linenos() handle - that. */ -/* *INDENT-ON* */ - - - -/* compare line table entry addresses. */ - -static int -compare_lte (const void *lte1p, const void *lte2p) -{ - struct linetable_entry *lte1 = (struct linetable_entry *) lte1p; - struct linetable_entry *lte2 = (struct linetable_entry *) lte2p; - return lte1->pc - lte2->pc; -} - -/* Given a line table with function entries are marked, arrange its functions - in ascending order and strip off function entry markers and return it in - a newly created table. If the old one is good enough, return the old one. */ -/* FIXME: I think all this stuff can be replaced by just passing - sort_linevec = 1 to end_symtab. */ - -static struct linetable * -arrange_linetable (struct linetable *oldLineTb) -{ - int ii, jj, newline, /* new line count */ - function_count; /* # of functions */ - - struct linetable_entry *fentry; /* function entry vector */ - int fentry_size; /* # of function entries */ - struct linetable *newLineTb; /* new line table */ - -#define NUM_OF_FUNCTIONS 20 - - fentry_size = NUM_OF_FUNCTIONS; - fentry = (struct linetable_entry *) - xmalloc (fentry_size * sizeof (struct linetable_entry)); - - for (function_count = 0, ii = 0; ii < oldLineTb->nitems; ++ii) - { - - if (oldLineTb->item[ii].line == 0) - { /* function entry found. */ - - if (function_count >= fentry_size) - { /* make sure you have room. */ - fentry_size *= 2; - fentry = (struct linetable_entry *) - xrealloc (fentry, fentry_size * sizeof (struct linetable_entry)); - } - fentry[function_count].line = ii; - fentry[function_count].pc = oldLineTb->item[ii].pc; - ++function_count; - } - } - - if (function_count == 0) - { - xfree (fentry); - return oldLineTb; - } - else if (function_count > 1) - qsort (fentry, function_count, sizeof (struct linetable_entry), compare_lte); - - /* allocate a new line table. */ - newLineTb = (struct linetable *) - xmalloc - (sizeof (struct linetable) + - (oldLineTb->nitems - function_count) * sizeof (struct linetable_entry)); - - /* if line table does not start with a function beginning, copy up until - a function begin. */ - - newline = 0; - if (oldLineTb->item[0].line != 0) - for (newline = 0; - newline < oldLineTb->nitems && oldLineTb->item[newline].line; ++newline) - newLineTb->item[newline] = oldLineTb->item[newline]; - - /* Now copy function lines one by one. */ - - for (ii = 0; ii < function_count; ++ii) - { - for (jj = fentry[ii].line + 1; - jj < oldLineTb->nitems && oldLineTb->item[jj].line != 0; - ++jj, ++newline) - newLineTb->item[newline] = oldLineTb->item[jj]; - } - xfree (fentry); - newLineTb->nitems = oldLineTb->nitems - function_count; - return newLineTb; -} - -/* include file support: C_BINCL/C_EINCL pairs will be kept in the - following `IncludeChain'. At the end of each symtab (end_symtab), - we will determine if we should create additional symtab's to - represent if (the include files. */ - - -typedef struct _inclTable -{ - char *name; /* include filename */ - - /* Offsets to the line table. end points to the last entry which is - part of this include file. */ - int begin, end; - - struct subfile *subfile; - unsigned funStartLine; /* start line # of its function */ -} -InclTable; - -#define INITIAL_INCLUDE_TABLE_LENGTH 20 -static InclTable *inclTable; /* global include table */ -static int inclIndx; /* last entry to table */ -static int inclLength; /* table length */ -static int inclDepth; /* nested include depth */ - -static void allocate_include_entry (void); - -static void -record_include_begin (struct coff_symbol *cs) -{ - if (inclDepth) - { - /* In xcoff, we assume include files cannot be nested (not in .c files - of course, but in corresponding .s files.). */ - - /* This can happen with old versions of GCC. - GCC 2.3.3-930426 does not exhibit this on a test case which - a user said produced the message for him. */ - static struct complaint msg = - {"Nested C_BINCL symbols", 0, 0}; - complain (&msg); - } - ++inclDepth; - - allocate_include_entry (); - - inclTable[inclIndx].name = cs->c_name; - inclTable[inclIndx].begin = cs->c_value; -} - -static void -record_include_end (struct coff_symbol *cs) -{ - InclTable *pTbl; - - if (inclDepth == 0) - { - static struct complaint msg = - {"Mismatched C_BINCL/C_EINCL pair", 0, 0}; - complain (&msg); - } - - allocate_include_entry (); - - pTbl = &inclTable[inclIndx]; - pTbl->end = cs->c_value; - - --inclDepth; - ++inclIndx; -} - -static void -allocate_include_entry (void) -{ - if (inclTable == NULL) - { - inclTable = (InclTable *) - xmalloc (sizeof (InclTable) * INITIAL_INCLUDE_TABLE_LENGTH); - memset (inclTable, - '\0', sizeof (InclTable) * INITIAL_INCLUDE_TABLE_LENGTH); - inclLength = INITIAL_INCLUDE_TABLE_LENGTH; - inclIndx = 0; - } - else if (inclIndx >= inclLength) - { - inclLength += INITIAL_INCLUDE_TABLE_LENGTH; - inclTable = (InclTable *) - xrealloc (inclTable, sizeof (InclTable) * inclLength); - memset (inclTable + inclLength - INITIAL_INCLUDE_TABLE_LENGTH, - '\0', sizeof (InclTable) * INITIAL_INCLUDE_TABLE_LENGTH); - } -} - -/* Global variable to pass the psymtab down to all the routines involved - in psymtab to symtab processing. */ -static struct partial_symtab *this_symtab_psymtab; - -/* given the start and end addresses of a compilation unit (or a csect, - at times) process its lines and create appropriate line vectors. */ - -static void -process_linenos (CORE_ADDR start, CORE_ADDR end) -{ - int offset, ii; - file_ptr max_offset = - ((struct coff_symfile_info *) this_symtab_psymtab->objfile->sym_private) - ->max_lineno_offset; - - /* subfile structure for the main compilation unit. */ - struct subfile main_subfile; - - /* In the main source file, any time we see a function entry, we - reset this variable to function's absolute starting line number. - All the following line numbers in the function are relative to - this, and we record absolute line numbers in record_line(). */ - - unsigned int main_source_baseline = 0; - - unsigned *firstLine; - - offset = - ((struct symloc *) this_symtab_psymtab->read_symtab_private)->lineno_off; - if (offset == 0) - goto return_after_cleanup; - - memset (&main_subfile, '\0', sizeof (main_subfile)); - - if (inclIndx == 0) - /* All source lines were in the main source file. None in include files. */ - - enter_line_range (&main_subfile, offset, 0, start, end, - &main_source_baseline); - - else - { - /* There was source with line numbers in include files. */ - - int linesz = - coff_data (this_symtab_psymtab->objfile->obfd)->local_linesz; - main_source_baseline = 0; - - for (ii = 0; ii < inclIndx; ++ii) - { - struct subfile *tmpSubfile; - - /* If there is main file source before include file, enter it. */ - if (offset < inclTable[ii].begin) - { - enter_line_range - (&main_subfile, offset, inclTable[ii].begin - linesz, - start, 0, &main_source_baseline); - } - - /* Have a new subfile for the include file. */ - - tmpSubfile = inclTable[ii].subfile = - (struct subfile *) xmalloc (sizeof (struct subfile)); - - memset (tmpSubfile, '\0', sizeof (struct subfile)); - firstLine = &(inclTable[ii].funStartLine); - - /* Enter include file's lines now. */ - enter_line_range (tmpSubfile, inclTable[ii].begin, - inclTable[ii].end, start, 0, firstLine); - - if (offset <= inclTable[ii].end) - offset = inclTable[ii].end + linesz; - } - - /* All the include files' line have been processed at this point. Now, - enter remaining lines of the main file, if any left. */ - if (offset < max_offset + 1 - linesz) - { - enter_line_range (&main_subfile, offset, 0, start, end, - &main_source_baseline); - } - } - - /* Process main file's line numbers. */ - if (main_subfile.line_vector) - { - struct linetable *lineTb, *lv; - - lv = main_subfile.line_vector; - - /* Line numbers are not necessarily ordered. xlc compilation will - put static function to the end. */ - - lineTb = arrange_linetable (lv); - if (lv == lineTb) - { - current_subfile->line_vector = (struct linetable *) - xrealloc (lv, (sizeof (struct linetable) - + lv->nitems * sizeof (struct linetable_entry))); - } - else - { - xfree (lv); - current_subfile->line_vector = lineTb; - } - - current_subfile->line_vector_length = - current_subfile->line_vector->nitems; - } - - /* Now, process included files' line numbers. */ - - for (ii = 0; ii < inclIndx; ++ii) - { - if ((inclTable[ii].subfile)->line_vector) /* Useless if!!! FIXMEmgo */ - { - struct linetable *lineTb, *lv; - - lv = (inclTable[ii].subfile)->line_vector; - - /* Line numbers are not necessarily ordered. xlc compilation will - put static function to the end. */ - - lineTb = arrange_linetable (lv); - - push_subfile (); - - /* For the same include file, we might want to have more than one - subfile. This happens if we have something like: - - ...... - #include "foo.h" - ...... - #include "foo.h" - ...... - - while foo.h including code in it. (stupid but possible) - Since start_subfile() looks at the name and uses an - existing one if finds, we need to provide a fake name and - fool it. */ - -#if 0 - start_subfile (inclTable[ii].name, (char *) 0); -#else - { - /* Pick a fake name that will produce the same results as this - one when passed to deduce_language_from_filename. Kludge on - top of kludge. */ - char *fakename = strrchr (inclTable[ii].name, '.'); - if (fakename == NULL) - fakename = " ?"; - start_subfile (fakename, (char *) 0); - xfree (current_subfile->name); - } - current_subfile->name = xstrdup (inclTable[ii].name); -#endif - - if (lv == lineTb) - { - current_subfile->line_vector = - (struct linetable *) xrealloc - (lv, (sizeof (struct linetable) - + lv->nitems * sizeof (struct linetable_entry))); - - } - else - { - xfree (lv); - current_subfile->line_vector = lineTb; - } - - current_subfile->line_vector_length = - current_subfile->line_vector->nitems; - start_subfile (pop_subfile (), (char *) 0); - } - } - -return_after_cleanup: - - /* We don't want to keep alloc/free'ing the global include file table. */ - inclIndx = 0; - - /* Start with a fresh subfile structure for the next file. */ - memset (&main_subfile, '\0', sizeof (struct subfile)); -} - -void -aix_process_linenos (void) -{ - /* process line numbers and enter them into line vector */ - process_linenos (last_source_start_addr, cur_src_end_addr); -} - - -/* Enter a given range of lines into the line vector. - can be called in the following two ways: - enter_line_range (subfile, beginoffset, endoffset, startaddr, 0, firstLine) or - enter_line_range (subfile, beginoffset, 0, startaddr, endaddr, firstLine) - - endoffset points to the last line table entry that we should pay - attention to. */ - -static void -enter_line_range (struct subfile *subfile, unsigned beginoffset, unsigned endoffset, /* offsets to line table */ - CORE_ADDR startaddr, /* offsets to line table */ - CORE_ADDR endaddr, unsigned *firstLine) -{ - unsigned int curoffset; - CORE_ADDR addr; - void *ext_lnno; - struct internal_lineno int_lnno; - unsigned int limit_offset; - bfd *abfd; - int linesz; - - if (endoffset == 0 && startaddr == 0 && endaddr == 0) - return; - curoffset = beginoffset; - limit_offset = - ((struct coff_symfile_info *) this_symtab_psymtab->objfile->sym_private) - ->max_lineno_offset; - - if (endoffset != 0) - { - if (endoffset >= limit_offset) - { - static struct complaint msg = - {"Bad line table offset in C_EINCL directive", 0, 0}; - complain (&msg); - return; - } - limit_offset = endoffset; - } - else - limit_offset -= 1; - - abfd = this_symtab_psymtab->objfile->obfd; - linesz = coff_data (abfd)->local_linesz; - ext_lnno = alloca (linesz); - - while (curoffset <= limit_offset) - { - bfd_seek (abfd, curoffset, SEEK_SET); - bfd_bread (ext_lnno, linesz, abfd); - bfd_coff_swap_lineno_in (abfd, ext_lnno, &int_lnno); - - /* Find the address this line represents. */ - addr = (int_lnno.l_lnno - ? int_lnno.l_addr.l_paddr - : read_symbol_nvalue (int_lnno.l_addr.l_symndx)); - addr += ANOFFSET (this_symtab_psymtab->objfile->section_offsets, - SECT_OFF_TEXT (this_symtab_psymtab->objfile)); - - if (addr < startaddr || (endaddr && addr >= endaddr)) - return; - - if (int_lnno.l_lnno == 0) - { - *firstLine = read_symbol_lineno (int_lnno.l_addr.l_symndx); - record_line (subfile, 0, addr); - --(*firstLine); - } - else - record_line (subfile, *firstLine + int_lnno.l_lnno, addr); - curoffset += linesz; - } -} - - -/* Save the vital information for use when closing off the current file. - NAME is the file name the symbols came from, START_ADDR is the first - text address for the file, and SIZE is the number of bytes of text. */ - -#define complete_symtab(name, start_addr) { \ - last_source_file = savestring (name, strlen (name)); \ - last_source_start_addr = start_addr; \ -} - - -/* Refill the symbol table input buffer - and set the variables that control fetching entries from it. - Reports an error if no data available. - This function can read past the end of the symbol table - (into the string table) but this does no harm. */ - -/* Reading symbol table has to be fast! Keep the followings as macros, rather - than functions. */ - -#define RECORD_MINIMAL_SYMBOL(NAME, ADDR, TYPE, SECTION, OBJFILE) \ -{ \ - char *namestr; \ - namestr = (NAME); \ - if (namestr[0] == '.') ++namestr; \ - prim_record_minimal_symbol_and_info (namestr, (ADDR), (TYPE), \ - (char *)NULL, (SECTION), (asection *)NULL, (OBJFILE)); \ - misc_func_recorded = 1; \ -} - - -/* xcoff has static blocks marked in `.bs', `.es' pairs. They cannot be - nested. At any given time, a symbol can only be in one static block. - This is the base address of current static block, zero if non exists. */ - -static int static_block_base = 0; - -/* Section number for the current static block. */ - -static int static_block_section = -1; - -/* true if space for symbol name has been allocated. */ - -static int symname_alloced = 0; - -/* Next symbol to read. Pointer into raw seething symbol table. */ - -static char *raw_symbol; - -/* This is the function which stabsread.c calls to get symbol - continuations. */ - -static char * -xcoff_next_symbol_text (struct objfile *objfile) -{ - struct internal_syment symbol; - static struct complaint msg = - {"Unexpected symbol continuation", 0, 0}; - char *retval; - /* FIXME: is this the same as the passed arg? */ - objfile = this_symtab_psymtab->objfile; - - bfd_coff_swap_sym_in (objfile->obfd, raw_symbol, &symbol); - if (symbol.n_zeroes) - { - complain (&msg); - - /* Return something which points to '\0' and hope the symbol reading - code does something reasonable. */ - retval = ""; - } - else if (symbol.n_sclass & 0x80) - { - retval = - ((struct coff_symfile_info *) objfile->sym_private)->debugsec - + symbol.n_offset; - raw_symbol += - coff_data (objfile->obfd)->local_symesz; - ++symnum; - } - else - { - complain (&msg); - - /* Return something which points to '\0' and hope the symbol reading - code does something reasonable. */ - retval = ""; - } - return retval; -} - -/* Read symbols for a given partial symbol table. */ - -static void -read_xcoff_symtab (struct partial_symtab *pst) -{ - struct objfile *objfile = pst->objfile; - bfd *abfd = objfile->obfd; - char *raw_auxptr; /* Pointer to first raw aux entry for sym */ - char *strtbl = ((struct coff_symfile_info *) objfile->sym_private)->strtbl; - char *debugsec = - ((struct coff_symfile_info *) objfile->sym_private)->debugsec; - char *debugfmt = xcoff_data (abfd)->xcoff64 ? "XCOFF64" : "XCOFF"; - - struct internal_syment symbol[1]; - union internal_auxent main_aux; - struct coff_symbol cs[1]; - CORE_ADDR file_start_addr = 0; - CORE_ADDR file_end_addr = 0; - - int next_file_symnum = -1; - unsigned int max_symnum; - int just_started = 1; - int depth = 0; - int fcn_start_addr = 0; - - struct coff_symbol fcn_stab_saved; - - /* fcn_cs_saved is global because process_xcoff_symbol needs it. */ - union internal_auxent fcn_aux_saved; - struct context_stack *new; - - char *filestring = " _start_ "; /* Name of the current file. */ - - char *last_csect_name; /* last seen csect's name and value */ - CORE_ADDR last_csect_val; - int last_csect_sec; - - this_symtab_psymtab = pst; - - /* Get the appropriate COFF "constants" related to the file we're - handling. */ - local_symesz = coff_data (abfd)->local_symesz; - - last_source_file = NULL; - last_csect_name = 0; - last_csect_val = 0; - - start_stabs (); - start_symtab (filestring, (char *) NULL, file_start_addr); - record_debugformat (debugfmt); - symnum = ((struct symloc *) pst->read_symtab_private)->first_symnum; - max_symnum = - symnum + ((struct symloc *) pst->read_symtab_private)->numsyms; - first_object_file_end = 0; - - raw_symbol = - ((struct coff_symfile_info *) objfile->sym_private)->symtbl - + symnum * local_symesz; - - while (symnum < max_symnum) - { - - QUIT; /* make this command interruptable. */ - - /* READ_ONE_SYMBOL (symbol, cs, symname_alloced); */ - /* read one symbol into `cs' structure. After processing the - whole symbol table, only string table will be kept in memory, - symbol table and debug section of xcoff will be freed. Thus - we can mark symbols with names in string table as - `alloced'. */ - { - int ii; - - /* Swap and align the symbol into a reasonable C structure. */ - bfd_coff_swap_sym_in (abfd, raw_symbol, symbol); - - cs->c_symnum = symnum; - cs->c_naux = symbol->n_numaux; - if (symbol->n_zeroes) - { - symname_alloced = 0; - /* We must use the original, unswapped, name here so the name field - pointed to by cs->c_name will persist throughout xcoffread. If - we use the new field, it gets overwritten for each symbol. */ - cs->c_name = ((struct external_syment *) raw_symbol)->e.e_name; - /* If it's exactly E_SYMNMLEN characters long it isn't - '\0'-terminated. */ - if (cs->c_name[E_SYMNMLEN - 1] != '\0') - { - char *p; - p = obstack_alloc (&objfile->symbol_obstack, E_SYMNMLEN + 1); - strncpy (p, cs->c_name, E_SYMNMLEN); - p[E_SYMNMLEN] = '\0'; - cs->c_name = p; - symname_alloced = 1; - } - } - else if (symbol->n_sclass & 0x80) - { - cs->c_name = debugsec + symbol->n_offset; - symname_alloced = 0; - } - else - { - /* in string table */ - cs->c_name = strtbl + (int) symbol->n_offset; - symname_alloced = 1; - } - cs->c_value = symbol->n_value; - cs->c_sclass = symbol->n_sclass; - cs->c_secnum = symbol->n_scnum; - cs->c_type = (unsigned) symbol->n_type; - - raw_symbol += local_symesz; - ++symnum; - - /* Save addr of first aux entry. */ - raw_auxptr = raw_symbol; - - /* Skip all the auxents associated with this symbol. */ - for (ii = symbol->n_numaux; ii; --ii) - { - raw_symbol += coff_data (abfd)->local_auxesz; - ++symnum; - } - } - - /* if symbol name starts with ".$" or "$", ignore it. */ - if (cs->c_name[0] == '$' - || (cs->c_name[1] == '$' && cs->c_name[0] == '.')) - continue; - - if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) - { - if (last_source_file) - { - pst->symtab = - end_symtab (cur_src_end_addr, objfile, SECT_OFF_TEXT (objfile)); - end_stabs (); - } - - start_stabs (); - start_symtab ("_globals_", (char *) NULL, (CORE_ADDR) 0); - record_debugformat (debugfmt); - cur_src_end_addr = first_object_file_end; - /* done with all files, everything from here on is globals */ - } - - if ((cs->c_sclass == C_EXT || cs->c_sclass == C_HIDEXT) - && cs->c_naux == 1) - { - /* Dealing with a symbol with a csect entry. */ - -#define CSECT(PP) ((PP)->x_csect) -#define CSECT_LEN(PP) (CSECT(PP).x_scnlen.l) -#define CSECT_ALIGN(PP) (SMTYP_ALIGN(CSECT(PP).x_smtyp)) -#define CSECT_SMTYP(PP) (SMTYP_SMTYP(CSECT(PP).x_smtyp)) -#define CSECT_SCLAS(PP) (CSECT(PP).x_smclas) - - /* Convert the auxent to something we can access. */ - bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, - 0, cs->c_naux, &main_aux); - - switch (CSECT_SMTYP (&main_aux)) - { - - case XTY_ER: - /* Ignore all external references. */ - continue; - - case XTY_SD: - /* A section description. */ - { - switch (CSECT_SCLAS (&main_aux)) - { - - case XMC_PR: - { - - /* A program csect is seen. We have to allocate one - symbol table for each program csect. Normally gdb - prefers one symtab for each source file. In case - of AIX, one source file might include more than one - [PR] csect, and they don't have to be adjacent in - terms of the space they occupy in memory. Thus, one - single source file might get fragmented in the - memory and gdb's file start and end address - approach does not work! GCC (and I think xlc) seem - to put all the code in the unnamed program csect. */ - - if (last_csect_name) - { - complete_symtab (filestring, file_start_addr); - cur_src_end_addr = file_end_addr; - end_symtab (file_end_addr, objfile, SECT_OFF_TEXT (objfile)); - end_stabs (); - start_stabs (); - /* Give all csects for this source file the same - name. */ - start_symtab (filestring, NULL, (CORE_ADDR) 0); - record_debugformat (debugfmt); - } - - /* If this is the very first csect seen, - basically `__start'. */ - if (just_started) - { - first_object_file_end - = cs->c_value + CSECT_LEN (&main_aux); - just_started = 0; - } - - file_start_addr = - cs->c_value + ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile)); - file_end_addr = file_start_addr + CSECT_LEN (&main_aux); - - if (cs->c_name && (cs->c_name[0] == '.' - || cs->c_name[0] == '@')) - { - last_csect_name = cs->c_name; - last_csect_val = cs->c_value; - last_csect_sec = secnum_to_section (cs->c_secnum, objfile); - } - } - continue; - - /* All other symbols are put into the minimal symbol - table only. */ - - case XMC_RW: - continue; - - case XMC_TC0: - continue; - - case XMC_TC: - continue; - - default: - /* Ignore the symbol. */ - continue; - } - } - break; - - case XTY_LD: - - switch (CSECT_SCLAS (&main_aux)) - { - case XMC_PR: - /* a function entry point. */ - function_entry_point: - - fcn_start_addr = cs->c_value; - - /* save the function header info, which will be used - when `.bf' is seen. */ - fcn_cs_saved = *cs; - fcn_aux_saved = main_aux; - continue; - - case XMC_GL: - /* shared library function trampoline code entry point. */ - continue; - - case XMC_DS: - /* The symbols often have the same names as debug symbols for - functions, and confuse lookup_symbol. */ - continue; - - default: - /* xlc puts each variable in a separate csect, so we get - an XTY_SD for each variable. But gcc puts several - variables in a csect, so that each variable only gets - an XTY_LD. This will typically be XMC_RW; I suspect - XMC_RO and XMC_BS might be possible too. - These variables are put in the minimal symbol table - only. */ - continue; - } - break; - - case XTY_CM: - /* Common symbols are put into the minimal symbol table only. */ - continue; - - default: - break; - } - } - - /* If explicitly specified as a function, treat is as one. This check - evaluates to true for @FIX* bigtoc CSECT symbols, so it must occur - after the above CSECT check. */ - if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF) - { - bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, - 0, cs->c_naux, &main_aux); - goto function_entry_point; - } - - switch (cs->c_sclass) - { - - case C_FILE: - - /* c_value field contains symnum of next .file entry in table - or symnum of first global after last .file. */ - - next_file_symnum = cs->c_value; - - /* Complete symbol table for last object file containing - debugging information. */ - - /* Whether or not there was a csect in the previous file, we - have to call `end_stabs' and `start_stabs' to reset - type_vector, line_vector, etc. structures. */ - - complete_symtab (filestring, file_start_addr); - cur_src_end_addr = file_end_addr; - end_symtab (file_end_addr, objfile, SECT_OFF_TEXT (objfile)); - end_stabs (); - - /* XCOFF, according to the AIX 3.2 documentation, puts the filename - in cs->c_name. But xlc 1.3.0.2 has decided to do things the - standard COFF way and put it in the auxent. We use the auxent if - the symbol is ".file" and an auxent exists, otherwise use the symbol - itself. Simple enough. */ - if (!strcmp (cs->c_name, ".file") && cs->c_naux > 0) - { - bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, - 0, cs->c_naux, &main_aux); - filestring = coff_getfilename (&main_aux, objfile); - } - else - filestring = cs->c_name; - - start_stabs (); - start_symtab (filestring, (char *) NULL, (CORE_ADDR) 0); - record_debugformat (debugfmt); - last_csect_name = 0; - - /* reset file start and end addresses. A compilation unit with no text - (only data) should have zero file boundaries. */ - file_start_addr = file_end_addr = 0; - break; - - case C_FUN: - fcn_stab_saved = *cs; - break; - - case C_FCN: - if (STREQ (cs->c_name, ".bf")) - { - CORE_ADDR off = ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile)); - bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, - 0, cs->c_naux, &main_aux); - - within_function = 1; - - new = push_context (0, fcn_start_addr + off); - - new->name = define_symbol - (fcn_cs_saved.c_value + off, - fcn_stab_saved.c_name, 0, 0, objfile); - if (new->name != NULL) - SYMBOL_SECTION (new->name) = SECT_OFF_TEXT (objfile); - } - else if (STREQ (cs->c_name, ".ef")) - { - - bfd_coff_swap_aux_in (abfd, raw_auxptr, cs->c_type, cs->c_sclass, - 0, cs->c_naux, &main_aux); - - /* The value of .ef is the address of epilogue code; - not useful for gdb. */ - /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno - contains number of lines to '}' */ - - if (context_stack_depth <= 0) - { /* We attempted to pop an empty context stack */ - complain (&ef_complaint, cs->c_symnum); - within_function = 0; - break; - } - new = pop_context (); - /* Stack must be empty now. */ - if (context_stack_depth > 0 || new == NULL) - { - complain (&ef_complaint, cs->c_symnum); - within_function = 0; - break; - } - - finish_block (new->name, &local_symbols, new->old_blocks, - new->start_addr, - (fcn_cs_saved.c_value - + fcn_aux_saved.x_sym.x_misc.x_fsize - + ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile))), - objfile); - within_function = 0; - } - break; - - case C_BSTAT: - /* Begin static block. */ - { - struct internal_syment symbol; - - read_symbol (&symbol, cs->c_value); - static_block_base = symbol.n_value; - static_block_section = - secnum_to_section (symbol.n_scnum, objfile); - } - break; - - case C_ESTAT: - /* End of static block. */ - static_block_base = 0; - static_block_section = -1; - break; - - case C_ARG: - case C_REGPARM: - case C_REG: - case C_TPDEF: - case C_STRTAG: - case C_UNTAG: - case C_ENTAG: - { - static struct complaint msg = - {"Unrecognized storage class %d.", 0, 0}; - complain (&msg, cs->c_sclass); - } - break; - - case C_LABEL: - case C_NULL: - /* Ignore these. */ - break; - - case C_HIDEXT: - case C_STAT: - break; - - case C_BINCL: - /* beginning of include file */ - /* In xlc output, C_BINCL/C_EINCL pair doesn't show up in sorted - order. Thus, when wee see them, we might not know enough info - to process them. Thus, we'll be saving them into a table - (inclTable) and postpone their processing. */ - - record_include_begin (cs); - break; - - case C_EINCL: - /* End of include file. */ - /* See the comment after case C_BINCL. */ - record_include_end (cs); - break; - - case C_BLOCK: - if (STREQ (cs->c_name, ".bb")) - { - depth++; - new = push_context (depth, - (cs->c_value - + ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile)))); - } - else if (STREQ (cs->c_name, ".eb")) - { - if (context_stack_depth <= 0) - { /* We attempted to pop an empty context stack */ - complain (&eb_complaint, cs->c_symnum); - break; - } - new = pop_context (); - if (depth-- != new->depth) - { - complain (&eb_complaint, cs->c_symnum); - break; - } - if (local_symbols && context_stack_depth > 0) - { - /* Make a block for the local symbols within. */ - finish_block (new->name, &local_symbols, new->old_blocks, - new->start_addr, - (cs->c_value - + ANOFFSET (objfile->section_offsets, - SECT_OFF_TEXT (objfile))), - objfile); - } - local_symbols = new->locals; - } - break; - - default: - process_xcoff_symbol (cs, objfile); - break; - } - } - - if (last_source_file) - { - struct symtab *s; - - complete_symtab (filestring, file_start_addr); - cur_src_end_addr = file_end_addr; - s = end_symtab (file_end_addr, objfile, SECT_OFF_TEXT (objfile)); - /* When reading symbols for the last C_FILE of the objfile, try - to make sure that we set pst->symtab to the symtab for the - file, not to the _globals_ symtab. I'm not sure whether this - actually works right or when/if it comes up. */ - if (pst->symtab == NULL) - pst->symtab = s; - end_stabs (); - } -} - -#define SYMBOL_DUP(SYMBOL1, SYMBOL2) \ - (SYMBOL2) = (struct symbol *) \ - obstack_alloc (&objfile->symbol_obstack, sizeof (struct symbol)); \ - *(SYMBOL2) = *(SYMBOL1); - - -#define SYMNAME_ALLOC(NAME, ALLOCED) \ - (ALLOCED) ? (NAME) : obsavestring ((NAME), strlen (NAME), &objfile->symbol_obstack); - - -static struct type *func_symbol_type; -static struct type *var_symbol_type; - -/* process one xcoff symbol. */ - -static struct symbol * -process_xcoff_symbol (register struct coff_symbol *cs, struct objfile *objfile) -{ - struct symbol onesymbol; - register struct symbol *sym = &onesymbol; - struct symbol *sym2 = NULL; - char *name, *pp; - - int sec; - CORE_ADDR off; - - if (cs->c_secnum < 0) - { - /* The value is a register number, offset within a frame, etc., - and does not get relocated. */ - off = 0; - sec = -1; - } - else - { - sec = secnum_to_section (cs->c_secnum, objfile); - off = ANOFFSET (objfile->section_offsets, sec); - } - - name = cs->c_name; - if (name[0] == '.') - ++name; - - memset (sym, '\0', sizeof (struct symbol)); - - /* default assumptions */ - SYMBOL_VALUE_ADDRESS (sym) = cs->c_value + off; - SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; - SYMBOL_SECTION (sym) = secnum_to_section (cs->c_secnum, objfile); - - if (ISFCN (cs->c_type)) - { - /* At this point, we don't know the type of the function. This - will be patched with the type from its stab entry later on in - patch_block_stabs (), unless the file was compiled without -g. */ - - SYMBOL_NAME (sym) = SYMNAME_ALLOC (name, symname_alloced); - SYMBOL_TYPE (sym) = func_symbol_type; - - SYMBOL_CLASS (sym) = LOC_BLOCK; - SYMBOL_DUP (sym, sym2); - - if (cs->c_sclass == C_EXT) - add_symbol_to_list (sym2, &global_symbols); - else if (cs->c_sclass == C_HIDEXT || cs->c_sclass == C_STAT) - add_symbol_to_list (sym2, &file_symbols); - } - else - { - /* In case we can't figure out the type, provide default. */ - SYMBOL_TYPE (sym) = var_symbol_type; - - switch (cs->c_sclass) - { -#if 0 - /* The values of functions and global symbols are now resolved - via the global_sym_chain in stabsread.c. */ - case C_FUN: - if (fcn_cs_saved.c_sclass == C_EXT) - add_stab_to_list (name, &global_stabs); - else - add_stab_to_list (name, &file_stabs); - break; - - case C_GSYM: - add_stab_to_list (name, &global_stabs); - break; -#endif - - case C_BCOMM: - common_block_start (cs->c_name, objfile); - break; - - case C_ECOMM: - common_block_end (objfile); - break; - - default: - complain (&storclass_complaint, cs->c_sclass); - /* FALLTHROUGH */ - - case C_DECL: - case C_PSYM: - case C_RPSYM: - case C_ECOML: - case C_LSYM: - case C_RSYM: - case C_GSYM: - - { - sym = define_symbol (cs->c_value + off, cs->c_name, 0, 0, objfile); - if (sym != NULL) - { - SYMBOL_SECTION (sym) = sec; - } - return sym; - } - - case C_STSYM: - - /* For xlc (not GCC), the 'V' symbol descriptor is used for - all statics and we need to distinguish file-scope versus - function-scope using within_function. We do this by - changing the string we pass to define_symbol to use 'S' - where we need to, which is not necessarily super-clean, - but seems workable enough. */ - - if (*name == ':' || (pp = (char *) strchr (name, ':')) == NULL) - return NULL; - - ++pp; - if (*pp == 'V' && !within_function) - *pp = 'S'; - sym = define_symbol ((cs->c_value - + ANOFFSET (objfile->section_offsets, - static_block_section)), - cs->c_name, 0, 0, objfile); - if (sym != NULL) - { - SYMBOL_VALUE_ADDRESS (sym) += static_block_base; - SYMBOL_SECTION (sym) = static_block_section; - } - return sym; - - } - } - return sym2; -} - -/* Extract the file name from the aux entry of a C_FILE symbol. - Result is in static storage and is only good for temporary use. */ - -static char * -coff_getfilename (union internal_auxent *aux_entry, struct objfile *objfile) -{ - static char buffer[BUFSIZ]; - - if (aux_entry->x_file.x_n.x_zeroes == 0) - strcpy (buffer, - ((struct coff_symfile_info *) objfile->sym_private)->strtbl - + aux_entry->x_file.x_n.x_offset); - else - { - strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); - buffer[FILNMLEN] = '\0'; - } - return (buffer); -} - -/* Set *SYMBOL to symbol number symno in symtbl. */ -static void -read_symbol (struct internal_syment *symbol, int symno) -{ - int nsyms = - ((struct coff_symfile_info *) this_symtab_psymtab->objfile->sym_private) - ->symtbl_num_syms; - char *stbl = - ((struct coff_symfile_info *) this_symtab_psymtab->objfile->sym_private) - ->symtbl; - if (symno < 0 || symno >= nsyms) - { - static struct complaint msg = - {"Invalid symbol offset", 0, 0}; - complain (&msg); - symbol->n_value = 0; - symbol->n_scnum = -1; - return; - } - bfd_coff_swap_sym_in (this_symtab_psymtab->objfile->obfd, - stbl + (symno * local_symesz), - symbol); -} - -/* Get value corresponding to symbol number symno in symtbl. */ - -static CORE_ADDR -read_symbol_nvalue (int symno) -{ - struct internal_syment symbol[1]; - - read_symbol (symbol, symno); - return symbol->n_value; -} - - -/* Find the address of the function corresponding to symno, where - symno is the symbol pointed to by the linetable. */ - -static int -read_symbol_lineno (int symno) -{ - struct objfile *objfile = this_symtab_psymtab->objfile; - boolean xcoff64 = xcoff_data (objfile->obfd)->xcoff64; - - struct coff_symfile_info *info = - (struct coff_symfile_info *)objfile->sym_private; - int nsyms = info->symtbl_num_syms; - char *stbl = info->symtbl; - char *strtbl = info->strtbl; - - struct internal_syment symbol[1]; - union internal_auxent main_aux[1]; - - if (symno < 0) - { - complain (&bf_notfound_complaint); - return 0; - } - - /* Note that just searching for a short distance (e.g. 50 symbols) - is not enough, at least in the following case. - - .extern foo - [many .stabx entries] - [a few functions, referring to foo] - .globl foo - .bf - - What happens here is that the assembler moves the .stabx entries - to right before the ".bf" for foo, but the symbol for "foo" is before - all the stabx entries. See PR gdb/2222. */ - - /* Maintaining a table of .bf entries might be preferable to this search. - If I understand things correctly it would need to be done only for - the duration of a single psymtab to symtab conversion. */ - while (symno < nsyms) - { - bfd_coff_swap_sym_in (symfile_bfd, - stbl + (symno * local_symesz), symbol); - if (symbol->n_sclass == C_FCN) - { - char *name = xcoff64 ? strtbl + symbol->n_offset : symbol->n_name; - if (STREQ (name, ".bf")) - goto gotit; - } - symno += symbol->n_numaux + 1; - } - - complain (&bf_notfound_complaint); - return 0; - -gotit: - /* take aux entry and return its lineno */ - symno++; - bfd_coff_swap_aux_in (objfile->obfd, stbl + symno * local_symesz, - symbol->n_type, symbol->n_sclass, - 0, symbol->n_numaux, main_aux); - - return main_aux->x_sym.x_misc.x_lnsz.x_lnno; -} - -/* Support for line number handling */ - -/* This function is called for every section; it finds the outer limits - * of the line table (minimum and maximum file offset) so that the - * mainline code can read the whole thing for efficiency. - */ -static void -find_linenos (bfd *abfd, sec_ptr asect, PTR vpinfo) -{ - struct coff_symfile_info *info; - int size, count; - file_ptr offset, maxoff; - - count = asect->lineno_count; - - if (!STREQ (asect->name, ".text") || count == 0) - return; - - size = count * coff_data (abfd)->local_linesz; - info = (struct coff_symfile_info *) vpinfo; - offset = asect->line_filepos; - maxoff = offset + size; - - if (offset < info->min_lineno_offset || info->min_lineno_offset == 0) - info->min_lineno_offset = offset; - - if (maxoff > info->max_lineno_offset) - info->max_lineno_offset = maxoff; -} - -static void xcoff_psymtab_to_symtab_1 (struct partial_symtab *); - -static void -xcoff_psymtab_to_symtab_1 (struct partial_symtab *pst) -{ - struct cleanup *old_chain; - int i; - - if (!pst) - return; - - if (pst->readin) - { - fprintf_unfiltered - (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", - pst->filename); - return; - } - - /* Read in all partial symtabs on which this one is dependent */ - for (i = 0; i < pst->number_of_dependencies; i++) - if (!pst->dependencies[i]->readin) - { - /* Inform about additional files that need to be read in. */ - if (info_verbose) - { - fputs_filtered (" ", gdb_stdout); - wrap_here (""); - fputs_filtered ("and ", gdb_stdout); - wrap_here (""); - printf_filtered ("%s...", pst->dependencies[i]->filename); - wrap_here (""); /* Flush output */ - gdb_flush (gdb_stdout); - } - xcoff_psymtab_to_symtab_1 (pst->dependencies[i]); - } - - if (((struct symloc *) pst->read_symtab_private)->numsyms != 0) - { - /* Init stuff necessary for reading in symbols. */ - stabsread_init (); - buildsym_init (); - old_chain = make_cleanup (really_free_pendings, 0); - - read_xcoff_symtab (pst); - sort_symtab_syms (pst->symtab); - - do_cleanups (old_chain); - } - - pst->readin = 1; -} - -static void xcoff_psymtab_to_symtab (struct partial_symtab *); - -/* Read in all of the symbols for a given psymtab for real. - Be verbose about it if the user wants that. */ - -static void -xcoff_psymtab_to_symtab (struct partial_symtab *pst) -{ - bfd *sym_bfd; - - if (!pst) - return; - - if (pst->readin) - { - fprintf_unfiltered - (gdb_stderr, "Psymtab for %s already read in. Shouldn't happen.\n", - pst->filename); - return; - } - - if (((struct symloc *) pst->read_symtab_private)->numsyms != 0 - || pst->number_of_dependencies) - { - /* Print the message now, before reading the string table, - to avoid disconcerting pauses. */ - if (info_verbose) - { - printf_filtered ("Reading in symbols for %s...", pst->filename); - gdb_flush (gdb_stdout); - } - - sym_bfd = pst->objfile->obfd; - - next_symbol_text_func = xcoff_next_symbol_text; - - xcoff_psymtab_to_symtab_1 (pst); - - /* Match with global symbols. This only needs to be done once, - after all of the symtabs and dependencies have been read in. */ - scan_file_globals (pst->objfile); - - /* Finish up the debug error message. */ - if (info_verbose) - printf_filtered ("done.\n"); - } -} - -static void -xcoff_new_init (struct objfile *objfile) -{ - stabsread_new_init (); - buildsym_new_init (); -} - -/* Do initialization in preparation for reading symbols from OBJFILE. - - We will only be called if this is an XCOFF or XCOFF-like file. - BFD handles figuring out the format of the file, and code in symfile.c - uses BFD's determination to vector to us. */ - -static void -xcoff_symfile_init (struct objfile *objfile) -{ - /* Allocate struct to keep track of the symfile */ - objfile->sym_private = xmmalloc (objfile->md, - sizeof (struct coff_symfile_info)); - - /* XCOFF objects may be reordered, so set OBJF_REORDERED. If we - find this causes a significant slowdown in gdb then we could - set it in the debug symbol readers only when necessary. */ - objfile->flags |= OBJF_REORDERED; - - init_entry_point_info (objfile); -} - -/* Perform any local cleanups required when we are done with a particular - objfile. I.E, we are in the process of discarding all symbol information - for an objfile, freeing up all memory held for it, and unlinking the - objfile struct from the global list of known objfiles. */ - -static void -xcoff_symfile_finish (struct objfile *objfile) -{ - if (objfile->sym_private != NULL) - { - xmfree (objfile->md, objfile->sym_private); - } - - /* Start with a fresh include table for the next objfile. */ - if (inclTable) - { - xfree (inclTable); - inclTable = NULL; - } - inclIndx = inclLength = inclDepth = 0; -} - - -static void -init_stringtab (bfd *abfd, file_ptr offset, struct objfile *objfile) -{ - long length; - int val; - unsigned char lengthbuf[4]; - char *strtbl; - - ((struct coff_symfile_info *) objfile->sym_private)->strtbl = NULL; - - if (bfd_seek (abfd, offset, SEEK_SET) < 0) - error ("cannot seek to string table in %s: %s", - bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); - - val = bfd_bread ((char *) lengthbuf, sizeof lengthbuf, abfd); - length = bfd_h_get_32 (abfd, lengthbuf); - - /* If no string table is needed, then the file may end immediately - after the symbols. Just return with `strtbl' set to NULL. */ - - if (val != sizeof lengthbuf || length < sizeof lengthbuf) - return; - - /* Allocate string table from symbol_obstack. We will need this table - as long as we have its symbol table around. */ - - strtbl = (char *) obstack_alloc (&objfile->symbol_obstack, length); - ((struct coff_symfile_info *) objfile->sym_private)->strtbl = strtbl; - - /* Copy length buffer, the first byte is usually zero and is - used for stabs with a name length of zero. */ - memcpy (strtbl, lengthbuf, sizeof lengthbuf); - if (length == sizeof lengthbuf) - return; - - val = bfd_bread (strtbl + sizeof lengthbuf, length - sizeof lengthbuf, abfd); - - if (val != length - sizeof lengthbuf) - error ("cannot read string table from %s: %s", - bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); - if (strtbl[length - 1] != '\0') - error ("bad symbol file: string table does not end with null character"); - - return; -} - -/* If we have not yet seen a function for this psymtab, this is 0. If we - have seen one, it is the offset in the line numbers of the line numbers - for the psymtab. */ -static unsigned int first_fun_line_offset; - -static struct partial_symtab *xcoff_start_psymtab - (struct objfile *, char *, int, - struct partial_symbol **, struct partial_symbol **); - -/* Allocate and partially fill a partial symtab. It will be - completely filled at the end of the symbol list. - - SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR - is the address relative to which its symbols are (incremental) or 0 - (normal). */ - -static struct partial_symtab * -xcoff_start_psymtab (struct objfile *objfile, char *filename, int first_symnum, - struct partial_symbol **global_syms, - struct partial_symbol **static_syms) -{ - struct partial_symtab *result = - start_psymtab_common (objfile, objfile->section_offsets, - filename, - /* We fill in textlow later. */ - 0, - global_syms, static_syms); - - result->read_symtab_private = (char *) - obstack_alloc (&objfile->psymbol_obstack, sizeof (struct symloc)); - ((struct symloc *) result->read_symtab_private)->first_symnum = first_symnum; - result->read_symtab = xcoff_psymtab_to_symtab; - - /* Deduce the source language from the filename for this psymtab. */ - psymtab_language = deduce_language_from_filename (filename); - - return result; -} - -static struct partial_symtab *xcoff_end_psymtab - (struct partial_symtab *, char **, int, int, - struct partial_symtab **, int, int); - -/* Close off the current usage of PST. - Returns PST, or NULL if the partial symtab was empty and thrown away. - - CAPPING_SYMBOL_NUMBER is the end of pst (exclusive). - - INCLUDE_LIST, NUM_INCLUDES, DEPENDENCY_LIST, and NUMBER_DEPENDENCIES - are the information for includes and dependencies. */ - -static struct partial_symtab * -xcoff_end_psymtab (struct partial_symtab *pst, char **include_list, - int num_includes, int capping_symbol_number, - struct partial_symtab **dependency_list, - int number_dependencies, int textlow_not_set) -{ - int i; - struct objfile *objfile = pst->objfile; - - if (capping_symbol_number != -1) - ((struct symloc *) pst->read_symtab_private)->numsyms = - capping_symbol_number - - ((struct symloc *) pst->read_symtab_private)->first_symnum; - ((struct symloc *) pst->read_symtab_private)->lineno_off = - first_fun_line_offset; - first_fun_line_offset = 0; - pst->n_global_syms = - objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset); - pst->n_static_syms = - objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset); - - pst->number_of_dependencies = number_dependencies; - if (number_dependencies) - { - pst->dependencies = (struct partial_symtab **) - obstack_alloc (&objfile->psymbol_obstack, - number_dependencies * sizeof (struct partial_symtab *)); - memcpy (pst->dependencies, dependency_list, - number_dependencies * sizeof (struct partial_symtab *)); - } - else - pst->dependencies = 0; - - for (i = 0; i < num_includes; i++) - { - struct partial_symtab *subpst = - allocate_psymtab (include_list[i], objfile); - - subpst->section_offsets = pst->section_offsets; - subpst->read_symtab_private = - (char *) obstack_alloc (&objfile->psymbol_obstack, - sizeof (struct symloc)); - ((struct symloc *) subpst->read_symtab_private)->first_symnum = 0; - ((struct symloc *) subpst->read_symtab_private)->numsyms = 0; - subpst->textlow = 0; - subpst->texthigh = 0; - - /* We could save slight bits of space by only making one of these, - shared by the entire set of include files. FIXME-someday. */ - subpst->dependencies = (struct partial_symtab **) - obstack_alloc (&objfile->psymbol_obstack, - sizeof (struct partial_symtab *)); - subpst->dependencies[0] = pst; - subpst->number_of_dependencies = 1; - - subpst->globals_offset = - subpst->n_global_syms = - subpst->statics_offset = - subpst->n_static_syms = 0; - - subpst->readin = 0; - subpst->symtab = 0; - subpst->read_symtab = pst->read_symtab; - } - - sort_pst_symbols (pst); - - /* If there is already a psymtab or symtab for a file of this name, - remove it. (If there is a symtab, more drastic things also - happen.) This happens in VxWorks. */ - free_named_symtabs (pst->filename); - - if (num_includes == 0 - && number_dependencies == 0 - && pst->n_global_syms == 0 - && pst->n_static_syms == 0) - { - /* Throw away this psymtab, it's empty. We can't deallocate it, since - it is on the obstack, but we can forget to chain it on the list. */ - /* Empty psymtabs happen as a result of header files which don't have - any symbols in them. There can be a lot of them. */ - - discard_psymtab (pst); - - /* Indicate that psymtab was thrown away. */ - pst = (struct partial_symtab *) NULL; - } - return pst; -} - -static void swap_sym (struct internal_syment *, - union internal_auxent *, char **, char **, - unsigned int *, struct objfile *); - -/* Swap raw symbol at *RAW and put the name in *NAME, the symbol in - *SYMBOL, the first auxent in *AUX. Advance *RAW and *SYMNUMP over - the symbol and its auxents. */ - -static void -swap_sym (struct internal_syment *symbol, union internal_auxent *aux, - char **name, char **raw, unsigned int *symnump, - struct objfile *objfile) -{ - bfd_coff_swap_sym_in (objfile->obfd, *raw, symbol); - if (symbol->n_zeroes) - { - /* If it's exactly E_SYMNMLEN characters long it isn't - '\0'-terminated. */ - if (symbol->n_name[E_SYMNMLEN - 1] != '\0') - { - /* FIXME: wastes memory for symbols which we don't end up putting - into the minimal symbols. */ - char *p; - p = obstack_alloc (&objfile->psymbol_obstack, E_SYMNMLEN + 1); - strncpy (p, symbol->n_name, E_SYMNMLEN); - p[E_SYMNMLEN] = '\0'; - *name = p; - } - else - /* Point to the unswapped name as that persists as long as the - objfile does. */ - *name = ((struct external_syment *) *raw)->e.e_name; - } - else if (symbol->n_sclass & 0x80) - { - *name = ((struct coff_symfile_info *) objfile->sym_private)->debugsec - + symbol->n_offset; - } - else - { - *name = ((struct coff_symfile_info *) objfile->sym_private)->strtbl - + symbol->n_offset; - } - ++*symnump; - *raw += coff_data (objfile->obfd)->local_symesz; - if (symbol->n_numaux > 0) - { - bfd_coff_swap_aux_in (objfile->obfd, *raw, symbol->n_type, - symbol->n_sclass, 0, symbol->n_numaux, aux); - - *symnump += symbol->n_numaux; - *raw += coff_data (objfile->obfd)->local_symesz * symbol->n_numaux; - } -} - -static void -scan_xcoff_symtab (struct objfile *objfile) -{ - CORE_ADDR toc_offset = 0; /* toc offset value in data section. */ - char *filestring = NULL; - - char *namestring; - int past_first_source_file = 0; - bfd *abfd; - asection *bfd_sect; - unsigned int nsyms; - - /* Current partial symtab */ - struct partial_symtab *pst; - - /* List of current psymtab's include files */ - char **psymtab_include_list; - int includes_allocated; - int includes_used; - - /* Index within current psymtab dependency list */ - struct partial_symtab **dependency_list; - int dependencies_used, dependencies_allocated; - - char *sraw_symbol; - struct internal_syment symbol; - union internal_auxent main_aux[5]; - unsigned int ssymnum; - - char *last_csect_name = NULL; /* last seen csect's name and value */ - CORE_ADDR last_csect_val = 0; - int last_csect_sec = 0; - int misc_func_recorded = 0; /* true if any misc. function */ - int textlow_not_set = 1; - - pst = (struct partial_symtab *) 0; - - includes_allocated = 30; - includes_used = 0; - psymtab_include_list = (char **) alloca (includes_allocated * - sizeof (char *)); - - dependencies_allocated = 30; - dependencies_used = 0; - dependency_list = - (struct partial_symtab **) alloca (dependencies_allocated * - sizeof (struct partial_symtab *)); - - last_source_file = NULL; - - abfd = objfile->obfd; - - sraw_symbol = ((struct coff_symfile_info *) objfile->sym_private)->symtbl; - nsyms = ((struct coff_symfile_info *) objfile->sym_private)->symtbl_num_syms; - ssymnum = 0; - while (ssymnum < nsyms) - { - int sclass; - - QUIT; - - bfd_coff_swap_sym_in (abfd, sraw_symbol, &symbol); - sclass = symbol.n_sclass; - - switch (sclass) - { - case C_EXT: - case C_HIDEXT: - { - /* The CSECT auxent--always the last auxent. */ - union internal_auxent csect_aux; - unsigned int symnum_before = ssymnum; - - swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol, - &ssymnum, objfile); - if (symbol.n_numaux > 1) - { - bfd_coff_swap_aux_in - (objfile->obfd, - sraw_symbol - coff_data (abfd)->local_symesz, - symbol.n_type, - symbol.n_sclass, - symbol.n_numaux - 1, - symbol.n_numaux, - &csect_aux); - } - else - csect_aux = main_aux[0]; - - /* If symbol name starts with ".$" or "$", ignore it. */ - if (namestring[0] == '$' - || (namestring[0] == '.' && namestring[1] == '$')) - break; - - switch (csect_aux.x_csect.x_smtyp & 0x7) - { - case XTY_SD: - switch (csect_aux.x_csect.x_smclas) - { - case XMC_PR: - if (last_csect_name) - { - /* If no misc. function recorded in the last - seen csect, enter it as a function. This - will take care of functions like strcmp() - compiled by xlc. */ - - if (!misc_func_recorded) - { - RECORD_MINIMAL_SYMBOL - (last_csect_name, last_csect_val, - mst_text, last_csect_sec, - objfile); - } - - if (pst != NULL) - { - /* We have to allocate one psymtab for - each program csect, because their text - sections need not be adjacent. */ - xcoff_end_psymtab - (pst, psymtab_include_list, includes_used, - symnum_before, dependency_list, - dependencies_used, textlow_not_set); - includes_used = 0; - dependencies_used = 0; - /* Give all psymtabs for this source file the same - name. */ - pst = xcoff_start_psymtab - (objfile, - filestring, - symnum_before, - objfile->global_psymbols.next, - objfile->static_psymbols.next); - } - } - /* Activate the misc_func_recorded mechanism for - compiler- and linker-generated CSECTs like ".strcmp" - and "@FIX1". */ - if (namestring && (namestring[0] == '.' - || namestring[0] == '@')) - { - last_csect_name = namestring; - last_csect_val = symbol.n_value; - last_csect_sec = - secnum_to_section (symbol.n_scnum, objfile); - } - if (pst != NULL) - { - CORE_ADDR highval = - symbol.n_value + csect_aux.x_csect.x_scnlen.l; - if (highval > pst->texthigh) - pst->texthigh = highval; - if (pst->textlow == 0 || symbol.n_value < pst->textlow) - pst->textlow = symbol.n_value; - } - misc_func_recorded = 0; - break; - - case XMC_RW: - /* Data variables are recorded in the minimal symbol - table, except for section symbols. */ - if (*namestring != '.') - prim_record_minimal_symbol_and_info - (namestring, symbol.n_value, - sclass == C_HIDEXT ? mst_file_data : mst_data, - NULL, secnum_to_section (symbol.n_scnum, objfile), - NULL, objfile); - break; - - case XMC_TC0: - if (toc_offset) - warning ("More than one XMC_TC0 symbol found."); - toc_offset = symbol.n_value; - - /* Make TOC offset relative to start address of section. */ - bfd_sect = secnum_to_bfd_section (symbol.n_scnum, objfile); - if (bfd_sect) - toc_offset -= bfd_section_vma (objfile->obfd, bfd_sect); - break; - - case XMC_TC: - /* These symbols tell us where the TOC entry for a - variable is, not the variable itself. */ - break; - - default: - break; - } - break; - - case XTY_LD: - switch (csect_aux.x_csect.x_smclas) - { - case XMC_PR: - /* A function entry point. */ - - if (first_fun_line_offset == 0 && symbol.n_numaux > 1) - first_fun_line_offset = - main_aux[0].x_sym.x_fcnary.x_fcn.x_lnnoptr; - RECORD_MINIMAL_SYMBOL - (namestring, symbol.n_value, - sclass == C_HIDEXT ? mst_file_text : mst_text, - secnum_to_section (symbol.n_scnum, objfile), - objfile); - break; - - case XMC_GL: - /* shared library function trampoline code entry - point. */ - - /* record trampoline code entries as - mst_solib_trampoline symbol. When we lookup mst - symbols, we will choose mst_text over - mst_solib_trampoline. */ - RECORD_MINIMAL_SYMBOL - (namestring, symbol.n_value, - mst_solib_trampoline, - secnum_to_section (symbol.n_scnum, objfile), - objfile); - break; - - case XMC_DS: - /* The symbols often have the same names as - debug symbols for functions, and confuse - lookup_symbol. */ - break; - - default: - - /* xlc puts each variable in a separate csect, - so we get an XTY_SD for each variable. But - gcc puts several variables in a csect, so - that each variable only gets an XTY_LD. We - still need to record them. This will - typically be XMC_RW; I suspect XMC_RO and - XMC_BS might be possible too. */ - if (*namestring != '.') - prim_record_minimal_symbol_and_info - (namestring, symbol.n_value, - sclass == C_HIDEXT ? mst_file_data : mst_data, - NULL, secnum_to_section (symbol.n_scnum, objfile), - NULL, objfile); - break; - } - break; - - case XTY_CM: - switch (csect_aux.x_csect.x_smclas) - { - case XMC_RW: - case XMC_BS: - /* Common variables are recorded in the minimal symbol - table, except for section symbols. */ - if (*namestring != '.') - prim_record_minimal_symbol_and_info - (namestring, symbol.n_value, - sclass == C_HIDEXT ? mst_file_bss : mst_bss, - NULL, secnum_to_section (symbol.n_scnum, objfile), - NULL, objfile); - break; - } - break; - - default: - break; - } - } - break; - case C_FILE: - { - unsigned int symnum_before; - - symnum_before = ssymnum; - swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol, - &ssymnum, objfile); - - /* See if the last csect needs to be recorded. */ - - if (last_csect_name && !misc_func_recorded) - { - - /* If no misc. function recorded in the last seen csect, enter - it as a function. This will take care of functions like - strcmp() compiled by xlc. */ - - RECORD_MINIMAL_SYMBOL - (last_csect_name, last_csect_val, - mst_text, last_csect_sec, objfile); - } - - if (pst) - { - xcoff_end_psymtab (pst, psymtab_include_list, includes_used, - symnum_before, dependency_list, - dependencies_used, textlow_not_set); - includes_used = 0; - dependencies_used = 0; - } - first_fun_line_offset = 0; - - /* XCOFF, according to the AIX 3.2 documentation, puts the - filename in cs->c_name. But xlc 1.3.0.2 has decided to - do things the standard COFF way and put it in the auxent. - We use the auxent if the symbol is ".file" and an auxent - exists, otherwise use the symbol itself. */ - if (!strcmp (namestring, ".file") && symbol.n_numaux > 0) - { - filestring = coff_getfilename (&main_aux[0], objfile); - } - else - filestring = namestring; - - pst = xcoff_start_psymtab (objfile, - filestring, - symnum_before, - objfile->global_psymbols.next, - objfile->static_psymbols.next); - last_csect_name = NULL; - } - break; - - default: - { - static struct complaint msg = - {"Storage class %d not recognized during scan", 0, 0}; - complain (&msg, sclass); - } - /* FALLTHROUGH */ - - /* C_FCN is .bf and .ef symbols. I think it is sufficient - to handle only the C_FUN and C_EXT. */ - case C_FCN: - - case C_BSTAT: - case C_ESTAT: - case C_ARG: - case C_REGPARM: - case C_REG: - case C_TPDEF: - case C_STRTAG: - case C_UNTAG: - case C_ENTAG: - case C_LABEL: - case C_NULL: - - /* C_EINCL means we are switching back to the main file. But there - is no reason to care; the only thing we want to know about - includes is the names of all the included (.h) files. */ - case C_EINCL: - - case C_BLOCK: - - /* I don't think C_STAT is used in xcoff; C_HIDEXT appears to be - used instead. */ - case C_STAT: - - /* I don't think the name of the common block (as opposed to the - variables within it) is something which is user visible - currently. */ - case C_BCOMM: - case C_ECOMM: - - case C_PSYM: - case C_RPSYM: - - /* I think we can ignore C_LSYM; types on xcoff seem to use C_DECL - so C_LSYM would appear to be only for locals. */ - case C_LSYM: - - case C_AUTO: - case C_RSYM: - { - /* We probably could save a few instructions by assuming that - C_LSYM, C_PSYM, etc., never have auxents. */ - int naux1 = symbol.n_numaux + 1; - ssymnum += naux1; - sraw_symbol += bfd_coff_symesz (abfd) * naux1; - } - break; - - case C_BINCL: - { - /* Mark down an include file in the current psymtab */ - enum language tmp_language; - swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol, - &ssymnum, objfile); - - tmp_language = deduce_language_from_filename (namestring); - - /* Only change the psymtab's language if we've learned - something useful (eg. tmp_language is not language_unknown). - In addition, to match what start_subfile does, never change - from C++ to C. */ - if (tmp_language != language_unknown - && (tmp_language != language_c - || psymtab_language != language_cplus)) - psymtab_language = tmp_language; - - /* In C++, one may expect the same filename to come round many - times, when code is coming alternately from the main file - and from inline functions in other files. So I check to see - if this is a file we've seen before -- either the main - source file, or a previously included file. - - This seems to be a lot of time to be spending on N_SOL, but - things like "break c-exp.y:435" need to work (I - suppose the psymtab_include_list could be hashed or put - in a binary tree, if profiling shows this is a major hog). */ - if (pst && STREQ (namestring, pst->filename)) - continue; - { - register int i; - for (i = 0; i < includes_used; i++) - if (STREQ (namestring, psymtab_include_list[i])) - { - i = -1; - break; - } - if (i == -1) - continue; - } - psymtab_include_list[includes_used++] = namestring; - if (includes_used >= includes_allocated) - { - char **orig = psymtab_include_list; - - psymtab_include_list = (char **) - alloca ((includes_allocated *= 2) * - sizeof (char *)); - memcpy ((PTR) psymtab_include_list, (PTR) orig, - includes_used * sizeof (char *)); - } - continue; - } - case C_FUN: - /* The value of the C_FUN is not the address of the function (it - appears to be the address before linking), but as long as it - is smaller than the actual address, then find_pc_partial_function - will use the minimal symbols instead. I hope. */ - - case C_GSYM: - case C_ECOML: - case C_DECL: - case C_STSYM: - { - - static struct complaint function_outside_compilation_unit = { - "function `%s' appears to be defined outside of all compilation units", 0, 0 - }; - - char *p; - swap_sym (&symbol, &main_aux[0], &namestring, &sraw_symbol, - &ssymnum, objfile); - - p = (char *) strchr (namestring, ':'); - if (!p) - continue; /* Not a debugging symbol. */ - - /* Main processing section for debugging symbols which - the initial read through the symbol tables needs to worry - about. If we reach this point, the symbol which we are - considering is definitely one we are interested in. - p must also contain the (valid) index into the namestring - which indicates the debugging type symbol. */ - - switch (p[1]) - { - case 'S': - symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); -#ifdef STATIC_TRANSFORM_NAME - namestring = STATIC_TRANSFORM_NAME (namestring); -#endif - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_STATIC, - &objfile->static_psymbols, - 0, symbol.n_value, - psymtab_language, objfile); - continue; - - case 'G': - symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)); - /* The addresses in these entries are reported to be - wrong. See the code that reads 'G's for symtabs. */ - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_STATIC, - &objfile->global_psymbols, - 0, symbol.n_value, - psymtab_language, objfile); - continue; - - case 'T': - /* When a 'T' entry is defining an anonymous enum, it - may have a name which is the empty string, or a - single space. Since they're not really defining a - symbol, those shouldn't go in the partial symbol - table. We do pick up the elements of such enums at - 'check_enum:', below. */ - if (p >= namestring + 2 - || (p == namestring + 1 - && namestring[0] != ' ')) - { - add_psymbol_to_list (namestring, p - namestring, - STRUCT_NAMESPACE, LOC_TYPEDEF, - &objfile->static_psymbols, - symbol.n_value, 0, - psymtab_language, objfile); - if (p[2] == 't') - { - /* Also a typedef with the same name. */ - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_TYPEDEF, - &objfile->static_psymbols, - symbol.n_value, 0, - psymtab_language, objfile); - p += 1; - } - /* The semantics of C++ state that "struct foo { ... }" - also defines a typedef for "foo". Unfortuantely, cfront - never makes the typedef when translating from C++ to C. - We make the typedef here so that "ptype foo" works as - expected for cfront translated code. */ - else if (psymtab_language == language_cplus) - { - /* Also a typedef with the same name. */ - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_TYPEDEF, - &objfile->static_psymbols, - symbol.n_value, 0, - psymtab_language, objfile); - } - } - goto check_enum; - - case 't': - if (p != namestring) /* a name is there, not just :T... */ - { - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_TYPEDEF, - &objfile->static_psymbols, - symbol.n_value, 0, - psymtab_language, objfile); - } - check_enum: - /* If this is an enumerated type, we need to - add all the enum constants to the partial symbol - table. This does not cover enums without names, e.g. - "enum {a, b} c;" in C, but fortunately those are - rare. There is no way for GDB to find those from the - enum type without spending too much time on it. Thus - to solve this problem, the compiler needs to put out the - enum in a nameless type. GCC2 does this. */ - - /* We are looking for something of the form - <name> ":" ("t" | "T") [<number> "="] "e" - {<constant> ":" <value> ","} ";". */ - - /* Skip over the colon and the 't' or 'T'. */ - p += 2; - /* This type may be given a number. Also, numbers can come - in pairs like (0,26). Skip over it. */ - while ((*p >= '0' && *p <= '9') - || *p == '(' || *p == ',' || *p == ')' - || *p == '=') - p++; - - if (*p++ == 'e') - { - /* The aix4 compiler emits extra crud before the members. */ - if (*p == '-') - { - /* Skip over the type (?). */ - while (*p != ':') - p++; - - /* Skip over the colon. */ - p++; - } - - /* We have found an enumerated type. */ - /* According to comments in read_enum_type - a comma could end it instead of a semicolon. - I don't know where that happens. - Accept either. */ - while (*p && *p != ';' && *p != ',') - { - char *q; - - /* Check for and handle cretinous dbx symbol name - continuation! */ - if (*p == '\\' || (*p == '?' && p[1] == '\0')) - p = next_symbol_text (objfile); - - /* Point to the character after the name - of the enum constant. */ - for (q = p; *q && *q != ':'; q++) - ; - /* Note that the value doesn't matter for - enum constants in psymtabs, just in symtabs. */ - add_psymbol_to_list (p, q - p, - VAR_NAMESPACE, LOC_CONST, - &objfile->static_psymbols, 0, - 0, psymtab_language, objfile); - /* Point past the name. */ - p = q; - /* Skip over the value. */ - while (*p && *p != ',') - p++; - /* Advance past the comma. */ - if (*p) - p++; - } - } - continue; - - case 'c': - /* Constant, e.g. from "const" in Pascal. */ - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_CONST, - &objfile->static_psymbols, symbol.n_value, - 0, psymtab_language, objfile); - continue; - - case 'f': - if (! pst) - { - int name_len = p - namestring; - char *name = xmalloc (name_len + 1); - memcpy (name, namestring, name_len); - name[name_len] = '\0'; - complain (&function_outside_compilation_unit, name); - xfree (name); - } - symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_BLOCK, - &objfile->static_psymbols, - 0, symbol.n_value, - psymtab_language, objfile); - continue; - - /* Global functions were ignored here, but now they - are put into the global psymtab like one would expect. - They're also in the minimal symbol table. */ - case 'F': - if (! pst) - { - int name_len = p - namestring; - char *name = xmalloc (name_len + 1); - memcpy (name, namestring, name_len); - name[name_len] = '\0'; - complain (&function_outside_compilation_unit, name); - xfree (name); - } - symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - add_psymbol_to_list (namestring, p - namestring, - VAR_NAMESPACE, LOC_BLOCK, - &objfile->global_psymbols, - 0, symbol.n_value, - psymtab_language, objfile); - continue; - - /* Two things show up here (hopefully); static symbols of - local scope (static used inside braces) or extensions - of structure symbols. We can ignore both. */ - case 'V': - case '(': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - case '#': /* for symbol identification (used in live ranges) */ - /* added to support cfront stabs strings */ - case 'Z': /* for definition continuations */ - case 'P': /* for prototypes */ - continue; - - case ':': - /* It is a C++ nested symbol. We don't need to record it - (I don't think); if we try to look up foo::bar::baz, - then symbols for the symtab containing foo should get - read in, I think. */ - /* Someone says sun cc puts out symbols like - /foo/baz/maclib::/usr/local/bin/maclib, - which would get here with a symbol type of ':'. */ - continue; - - default: - /* Unexpected symbol descriptor. The second and subsequent stabs - of a continued stab can show up here. The question is - whether they ever can mimic a normal stab--it would be - nice if not, since we certainly don't want to spend the - time searching to the end of every string looking for - a backslash. */ - - complain (&unknown_symchar_complaint, p[1]); - - /* Ignore it; perhaps it is an extension that we don't - know about. */ - continue; - } - } - } - } - - if (pst) - { - xcoff_end_psymtab (pst, psymtab_include_list, includes_used, - ssymnum, dependency_list, - dependencies_used, textlow_not_set); - } - - /* Record the toc offset value of this symbol table into objfile structure. - If no XMC_TC0 is found, toc_offset should be zero. Another place to obtain - this information would be file auxiliary header. */ - - ((struct coff_symfile_info *) objfile->sym_private)->toc_offset = toc_offset; -} - -/* Return the toc offset value for a given objfile. */ - -CORE_ADDR -get_toc_offset (struct objfile *objfile) -{ - if (objfile) - return ((struct coff_symfile_info *) objfile->sym_private)->toc_offset; - return 0; -} - -/* Scan and build partial symbols for a symbol file. - We have been initialized by a call to dbx_symfile_init, which - put all the relevant info into a "struct dbx_symfile_info", - hung off the objfile structure. - - SECTION_OFFSETS contains offsets relative to which the symbols in the - various sections are (depending where the sections were actually loaded). - MAINLINE is true if we are reading the main symbol - table (as opposed to a shared lib or dynamically loaded file). */ - -static void -xcoff_initial_scan (struct objfile *objfile, int mainline) -{ - bfd *abfd; - int val; - struct cleanup *back_to; - int num_symbols; /* # of symbols */ - file_ptr symtab_offset; /* symbol table and */ - file_ptr stringtab_offset; /* string table file offsets */ - struct coff_symfile_info *info; - char *name; - unsigned int size; - - info = (struct coff_symfile_info *) objfile->sym_private; - symfile_bfd = abfd = objfile->obfd; - name = objfile->name; - - num_symbols = bfd_get_symcount (abfd); /* # of symbols */ - symtab_offset = obj_sym_filepos (abfd); /* symbol table file offset */ - stringtab_offset = symtab_offset + - num_symbols * coff_data (abfd)->local_symesz; - - info->min_lineno_offset = 0; - info->max_lineno_offset = 0; - bfd_map_over_sections (abfd, find_linenos, info); - - if (num_symbols > 0) - { - /* Read the string table. */ - init_stringtab (abfd, stringtab_offset, objfile); - - /* Read the .debug section, if present. */ - { - sec_ptr secp; - bfd_size_type length; - char *debugsec = NULL; - - secp = bfd_get_section_by_name (abfd, ".debug"); - if (secp) - { - length = bfd_section_size (abfd, secp); - if (length) - { - debugsec = - (char *) obstack_alloc (&objfile->symbol_obstack, length); - - if (!bfd_get_section_contents (abfd, secp, debugsec, - (file_ptr) 0, length)) - { - error ("Error reading .debug section of `%s': %s", - name, bfd_errmsg (bfd_get_error ())); - } - } - } - ((struct coff_symfile_info *) objfile->sym_private)->debugsec = - debugsec; - } - } - - /* Read the symbols. We keep them in core because we will want to - access them randomly in read_symbol*. */ - val = bfd_seek (abfd, symtab_offset, SEEK_SET); - if (val < 0) - error ("Error reading symbols from %s: %s", - name, bfd_errmsg (bfd_get_error ())); - size = coff_data (abfd)->local_symesz * num_symbols; - ((struct coff_symfile_info *) objfile->sym_private)->symtbl = - obstack_alloc (&objfile->symbol_obstack, size); - ((struct coff_symfile_info *) objfile->sym_private)->symtbl_num_syms = - num_symbols; - - val = bfd_bread (((struct coff_symfile_info *) objfile->sym_private)->symtbl, - size, abfd); - if (val != size) - perror_with_name ("reading symbol table"); - - /* If we are reinitializing, or if we have never loaded syms yet, init */ - if (mainline - || (objfile->global_psymbols.size == 0 - && objfile->static_psymbols.size == 0)) - /* I'm not sure how how good num_symbols is; the rule of thumb in - init_psymbol_list was developed for a.out. On the one hand, - num_symbols includes auxents. On the other hand, it doesn't - include N_SLINE. */ - init_psymbol_list (objfile, num_symbols); - - free_pending_blocks (); - back_to = make_cleanup (really_free_pendings, 0); - - init_minimal_symbol_collection (); - make_cleanup_discard_minimal_symbols (); - - /* Now that the symbol table data of the executable file are all in core, - process them and define symbols accordingly. */ - - scan_xcoff_symtab (objfile); - - /* Install any minimal symbols that have been collected as the current - minimal symbols for this objfile. */ - - install_minimal_symbols (objfile); - - do_cleanups (back_to); -} - -static void -xcoff_symfile_offsets (struct objfile *objfile, struct section_addr_info *addrs) -{ - asection *sect = NULL; - int i; - - objfile->num_sections = SECT_OFF_MAX; - objfile->section_offsets = (struct section_offsets *) - obstack_alloc (&objfile->psymbol_obstack, SIZEOF_SECTION_OFFSETS); - - /* Initialize the section indexes for future use. */ - sect = bfd_get_section_by_name (objfile->obfd, ".text"); - if (sect) - objfile->sect_index_text = sect->index; - - sect = bfd_get_section_by_name (objfile->obfd, ".data"); - if (sect) - objfile->sect_index_data = sect->index; - - sect = bfd_get_section_by_name (objfile->obfd, ".bss"); - if (sect) - objfile->sect_index_bss = sect->index; - - sect = bfd_get_section_by_name (objfile->obfd, ".rodata"); - if (sect) - objfile->sect_index_rodata = sect->index; - - for (i = 0; i < objfile->num_sections; ++i) - { - /* syms_from_objfile kindly subtracts from addr the - bfd_section_vma of the .text section. This strikes me as - wrong--whether the offset to be applied to symbol reading is - relative to the start address of the section depends on the - symbol format. In any event, this whole "addr" concept is - pretty broken (it doesn't handle any section but .text - sensibly), so just ignore the addr parameter and use 0. - rs6000-nat.c will set the correct section offsets via - objfile_relocate. */ - (objfile->section_offsets)->offsets[i] = 0; - } -} - -/* Register our ability to parse symbols for xcoff BFD files. */ - -static struct sym_fns xcoff_sym_fns = -{ - - /* It is possible that coff and xcoff should be merged as - they do have fundamental similarities (for example, the extra storage - classes used for stabs could presumably be recognized in any COFF file). - However, in addition to obvious things like all the csect hair, there are - some subtler differences between xcoffread.c and coffread.c, notably - the fact that coffread.c has no need to read in all the symbols, but - xcoffread.c reads all the symbols and does in fact randomly access them - (in C_BSTAT and line number processing). */ - - bfd_target_xcoff_flavour, - - xcoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ - xcoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ - xcoff_initial_scan, /* sym_read: read a symbol file into symtab */ - xcoff_symfile_finish, /* sym_finish: finished with file, cleanup */ - xcoff_symfile_offsets, /* sym_offsets: xlate offsets ext->int form */ - NULL /* next: pointer to next struct sym_fns */ -}; - -void -_initialize_xcoffread (void) -{ - add_symtab_fns (&xcoff_sym_fns); - - func_symbol_type = init_type (TYPE_CODE_FUNC, 1, 0, - "<function, no debug info>", NULL); - TYPE_TARGET_TYPE (func_symbol_type) = builtin_type_int; - var_symbol_type = - init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0, - "<variable, no debug info>", NULL); -} diff --git a/contrib/gdb/gdb/xcoffsolib.c b/contrib/gdb/gdb/xcoffsolib.c deleted file mode 100644 index 99d2cc8..0000000 --- a/contrib/gdb/gdb/xcoffsolib.c +++ /dev/null @@ -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); -} |