summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/gdb/gdb/abug-rom.c182
-rw-r--r--contrib/gdb/gdb/alpha-nat.c272
-rw-r--r--contrib/gdb/gdb/arm-tdep.c3018
-rw-r--r--contrib/gdb/gdb/coff-solib.c134
-rw-r--r--contrib/gdb/gdb/coff-solib.h186
-rw-r--r--contrib/gdb/gdb/config/nm-gnu.h43
-rw-r--r--contrib/gdb/gdb/config/nm-lynx.h86
-rw-r--r--contrib/gdb/gdb/config/nm-nbsd.h27
-rw-r--r--contrib/gdb/gdb/config/nm-sysv4.h34
-rw-r--r--contrib/gdb/gdb/config/tm-lynx.h32
-rw-r--r--contrib/gdb/gdb/config/tm-sunos.h32
-rw-r--r--contrib/gdb/gdb/config/tm-sysv4.h37
-rw-r--r--contrib/gdb/gdb/config/xm-nbsd.h26
-rw-r--r--contrib/gdb/gdb/config/xm-sysv4.h29
-rw-r--r--contrib/gdb/gdb/cpu32bug-rom.c180
-rw-r--r--contrib/gdb/gdb/gnu-nat.c3409
-rw-r--r--contrib/gdb/gdb/gnu-nat.h101
-rw-r--r--contrib/gdb/gdb/i386-stub.c952
-rw-r--r--contrib/gdb/gdb/i386gnu-nat.c293
-rw-r--r--contrib/gdb/gdb/i386ly-tdep.c81
-rw-r--r--contrib/gdb/gdb/i386v-nat.c277
-rw-r--r--contrib/gdb/gdb/i386v4-nat.c160
-rw-r--r--contrib/gdb/gdb/lynx-nat.c624
-rw-r--r--contrib/gdb/gdb/minimon.h601
-rw-r--r--contrib/gdb/gdb/monitor.c2310
-rw-r--r--contrib/gdb/gdb/monitor.h260
-rw-r--r--contrib/gdb/gdb/ppcbug-rom.c225
-rw-r--r--contrib/gdb/gdb/procfs.c5960
-rw-r--r--contrib/gdb/gdb/remote-e7000.c2194
-rw-r--r--contrib/gdb/gdb/remote-est.c186
-rw-r--r--contrib/gdb/gdb/remote-hms.c159
-rw-r--r--contrib/gdb/gdb/remote-mips.c3421
-rw-r--r--contrib/gdb/gdb/remote-rdp.c1431
-rw-r--r--contrib/gdb/gdb/remote-sds.c1130
-rw-r--r--contrib/gdb/gdb/remote-sim.c900
-rw-r--r--contrib/gdb/gdb/remote-st.c803
-rw-r--r--contrib/gdb/gdb/remote-vx.c1409
-rw-r--r--contrib/gdb/gdb/remote-vx68.c160
-rw-r--r--contrib/gdb/gdb/remote-vxmips.c201
-rw-r--r--contrib/gdb/gdb/remote-vxsparc.c128
-rw-r--r--contrib/gdb/gdb/ser-e7kpc.c436
-rw-r--r--contrib/gdb/gdb/ser-go32.c964
-rw-r--r--contrib/gdb/gdb/somread.c736
-rw-r--r--contrib/gdb/gdb/somsolib.c1624
-rw-r--r--contrib/gdb/gdb/somsolib.h178
-rw-r--r--contrib/gdb/gdb/srec.h39
-rw-r--r--contrib/gdb/gdb/standalone.c580
-rw-r--r--contrib/gdb/gdb/stop-gdb.c109
-rw-r--r--contrib/gdb/gdb/tui/tui.c590
-rw-r--r--contrib/gdb/gdb/tui/tui.h100
-rw-r--r--contrib/gdb/gdb/xcoffread.c3033
-rw-r--r--contrib/gdb/gdb/xcoffsolib.c196
-rw-r--r--contrib/gdb/gdb/xmodem.c275
-rw-r--r--contrib/gdb/gdb/xmodem.h32
-rw-r--r--contrib/gdb/include/COPYING340
-rw-r--r--contrib/gdb/include/ansidecl.h315
-rw-r--r--contrib/gdb/include/bfdlink.h686
-rw-r--r--contrib/gdb/include/bout.h191
-rw-r--r--contrib/gdb/include/demangle.h533
-rw-r--r--contrib/gdb/include/dis-asm.h317
-rw-r--r--contrib/gdb/include/floatformat.h133
-rw-r--r--contrib/gdb/include/fopen-bin.h27
-rw-r--r--contrib/gdb/include/fopen-same.h27
-rw-r--r--contrib/gdb/include/gdbm.h91
-rw-r--r--contrib/gdb/include/getopt.h144
-rw-r--r--contrib/gdb/include/hp-symtab.h1866
-rw-r--r--contrib/gdb/include/ieee.h165
-rw-r--r--contrib/gdb/include/libiberty.h335
-rw-r--r--contrib/gdb/include/oasys.h192
-rw-r--r--contrib/gdb/include/obstack.h611
-rw-r--r--contrib/gdb/include/os9k.h181
-rw-r--r--contrib/gdb/include/progress.h37
-rwxr-xr-xcontrib/gdb/move-if-change32
73 files changed, 46808 insertions, 0 deletions
diff --git a/contrib/gdb/gdb/abug-rom.c b/contrib/gdb/gdb/abug-rom.c
new file mode 100644
index 0000000..543f702
--- /dev/null
+++ b/contrib/gdb/gdb/abug-rom.c
@@ -0,0 +1,182 @@
+/* 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"
+
+#include "m68k-tdep.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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+abug_regname (int index)
+{
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "PC",
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * 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 = NULL; /* registers names */
+ abug_cmds.regname = abug_regname;
+ abug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+};
+
+static void
+abug_open (char *args, int from_tty)
+{
+ monitor_open (args, &abug_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_abug_rom; /* -Wmissing-prototypes */
+
+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/alpha-nat.c b/contrib/gdb/gdb/alpha-nat.c
new file mode 100644
index 0000000..0a78d94
--- /dev/null
+++ b/contrib/gdb/gdb/alpha-nat.c
@@ -0,0 +1,272 @@
+/* Low level Alpha interface, for GDB when running native.
+ Copyright 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003
+ 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 "gdb_string.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "regcache.h"
+
+#include "alpha-tdep.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);
+
+/* 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)
+{
+ int regno;
+ 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 const core_reg_mapping[ALPHA_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
+ };
+
+ for (regno = 0; regno < ALPHA_NUM_REGS; regno++)
+ {
+ if (CANNOT_FETCH_REGISTER (regno))
+ {
+ supply_register (regno, NULL);
+ continue;
+ }
+ addr = 8 * core_reg_mapping[regno];
+ if (addr < 0 || addr >= core_reg_size)
+ {
+ /* ??? UNIQUE is a new addition. Don't generate an error. */
+ if (regno == ALPHA_UNIQUE_REGNUM)
+ {
+ supply_register (regno, NULL);
+ continue;
+ }
+ 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;
+ }
+
+ switch (which)
+ {
+ case 0: /* integer registers */
+ /* PC is in slot 32; UNIQUE is in slot 33, if present. */
+ alpha_supply_int_regs (-1, core_reg_sect, core_reg_sect + 31*8,
+ (core_reg_size >= 33 * 8
+ ? core_reg_sect + 32*8 : NULL));
+ break;
+
+ case 2: /* floating-point registers */
+ /* FPCR is in slot 32. */
+ alpha_supply_fp_regs (-1, core_reg_sect, core_reg_sect + 31*8);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* Map gdb internal register number to a ptrace ``address''.
+ These ``addresses'' are defined in <sys/ptrace.h>, with
+ the exception of ALPHA_UNIQUE_PTRACE_ADDR. */
+
+#ifndef ALPHA_UNIQUE_PTRACE_ADDR
+#define ALPHA_UNIQUE_PTRACE_ADDR 0
+#endif
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+ if (regno == PC_REGNUM)
+ return PC;
+ if (regno == ALPHA_UNIQUE_REGNUM)
+ return ALPHA_UNIQUE_PTRACE_ADDR;
+ if (regno < FP0_REGNUM)
+ return GPR_BASE + regno;
+ else
+ return FPR_BASE + regno - FP0_REGNUM;
+}
+
+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"
+
+/* Locate the UNIQUE value within the gregset_t. */
+#ifndef ALPHA_REGSET_UNIQUE
+#define ALPHA_REGSET_UNIQUE(ptr) NULL
+#endif
+
+/*
+ * See the comment in m68k-tdep.c regarding the utility of these functions.
+ */
+
+void
+supply_gregset (gdb_gregset_t *gregsetp)
+{
+ long *regp = ALPHA_REGSET_BASE (gregsetp);
+ void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
+
+ /* PC is in slot 32. */
+ alpha_supply_int_regs (-1, regp, regp + 31, unique);
+}
+
+void
+fill_gregset (gdb_gregset_t *gregsetp, int regno)
+{
+ long *regp = ALPHA_REGSET_BASE (gregsetp);
+ void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
+
+ /* PC is in slot 32. */
+ alpha_fill_int_regs (regno, regp, regp + 31, unique);
+}
+
+/*
+ * 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)
+{
+ long *regp = ALPHA_REGSET_BASE (fpregsetp);
+
+ /* FPCR is in slot 32. */
+ alpha_supply_fp_regs (-1, regp, regp + 31);
+}
+
+void
+fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
+{
+ long *regp = ALPHA_REGSET_BASE (fpregsetp);
+
+ /* FPCR is in slot 32. */
+ alpha_fill_fp_regs (regno, regp, regp + 31);
+}
+#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
new file mode 100644
index 0000000..0034690
--- /dev/null
+++ b/contrib/gdb/gdb/arm-tdep.c
@@ -0,0 +1,3018 @@
+/* Common target dependent code for GDB on ARM systems.
+ Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004 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 "gdb_string.h"
+#include "dis-asm.h" /* For register styles. */
+#include "regcache.h"
+#include "doublest.h"
+#include "value.h"
+#include "arch-utils.h"
+#include "osabi.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+
+#include "arm-tdep.h"
+#include "gdb/sim-arm.h"
+
+#include "elf-bfd.h"
+#include "coff/internal.h"
+#include "elf/arm.h"
+
+#include "gdb_assert.h"
+
+static int arm_debug;
+
+/* 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.
+
+ MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
+ MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol. */
+
+#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)
+
+/* The list of available "set arm ..." and "show arm ..." commands. */
+static struct cmd_list_element *setarmcmdlist = NULL;
+static struct cmd_list_element *showarmcmdlist = NULL;
+
+/* The type of floating-point to use. Keep this in sync with enum
+ arm_float_model, and the help string in _initialize_arm_tdep. */
+static const char *fp_model_strings[] =
+{
+ "auto",
+ "softfpa",
+ "fpa",
+ "softvfp",
+ "vfp"
+};
+
+/* A variable that can be configured by the user. */
+static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
+static const char *current_fp_model = "auto";
+
+/* Number of different reg name sets (options). */
+static int num_disassembly_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 styles. */
+static const char **valid_disassembly_styles;
+
+/* Disassembly style to use. Default to "std" register names. */
+static const char *disassembly_style;
+/* Index to that option in the opcodes table. */
+static int current_option;
+
+/* This is used to keep the bfd arch_info in sync with the disassembly
+ style. */
+static void set_disassembly_style_sfunc(char *, int,
+ struct cmd_list_element *);
+static void set_disassembly_style (void);
+
+static void convert_from_extended (const struct floatformat *, const void *,
+ void *);
+static void convert_to_extended (const struct floatformat *, void *,
+ const void *);
+
+struct arm_prologue_cache
+{
+ /* The stack pointer at the time this frame was created; i.e. the
+ caller's stack pointer when this function was called. It is used
+ to identify this frame. */
+ CORE_ADDR prev_sp;
+
+ /* The frame base for this frame is just prev_sp + frame offset -
+ frame size. FRAMESIZE is the size of this stack frame, and
+ FRAMEOFFSET if the initial offset from the stack pointer (this
+ frame's stack pointer, not PREV_SP) to the frame base. */
+
+ int framesize;
+ int frameoffset;
+
+ /* The register used to hold the frame pointer for this frame. */
+ int framereg;
+
+ /* Saved register offsets. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* 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)
+
+/* 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 (DEPRECATED_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_apcs_32)
+ return (val & (arm_pc_is_thumb (val) ? 0xfffffffe : 0xfffffffc));
+ else
+ return (val & 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_frame_func (fi) + 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;
+}
+
+/* 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;
+ /* 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 findmask = 0;
+
+ 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))
+ {
+ /* We have found one of each type of prologue instruction */
+ break;
+ }
+ else
+ /* Something in the prolog that we don't care about or some
+ instruction from outside the prolog scheduled here for
+ optimization. */
+ continue;
+ }
+
+ 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 = 0;
+ char *func_name;
+ struct symtab_and_line sal;
+
+ /* If we're in a dummy frame, don't even try to skip the prologue. */
+ if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+ return pc;
+
+ /* 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_DOMAIN, 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. */
+
+ /* Like arm_scan_prologue, stop no later than pc + 64. */
+ if (func_end == 0 || func_end > pc + 64)
+ func_end = pc + 64;
+
+ for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
+ {
+ inst = read_memory_integer (skip_pc, 4);
+
+ /* "mov ip, sp" is no longer a required part of the prologue. */
+ if (inst == 0xe1a0c00d) /* mov ip, sp */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ continue;
+
+ /* Some prologues begin with "str lr, [sp, #-4]!". */
+ if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
+ continue;
+
+ if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
+ continue;
+
+ if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
+ continue;
+
+ /* 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 consider 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]! */
+ continue;
+
+ if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
+ continue;
+
+ if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe54b0000 || /* strb r(0123),[r11,#-nn] */
+ (inst & 0xffffc0f0) == 0xe14b00b0 || /* strh r(0123),[r11,#-nn] */
+ (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
+ continue;
+
+ if ((inst & 0xffffc000) == 0xe5cd0000 || /* strb r(0123),[sp,#nn] */
+ (inst & 0xffffc0f0) == 0xe1cd00b0 || /* strh r(0123),[sp,#nn] */
+ (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
+ continue;
+
+ /* Un-recognized instruction; stop scanning. */
+ break;
+ }
+
+ return skip_pc; /* End of prologue */
+}
+
+/* *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
+
+ 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 (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
+{
+ CORE_ADDR prologue_start;
+ CORE_ADDR prologue_end;
+ CORE_ADDR current_pc;
+ /* Which register has been copied to register n? */
+ int saved_reg[16];
+ /* 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 findmask = 0;
+ int i;
+
+ if (find_pc_partial_function (prev_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 = prev_pc;
+ else if (sal.end < prologue_end) /* next line begins after fn end */
+ prologue_end = sal.end; /* (probably means no prologue) */
+ }
+ else
+ /* We're in the boondocks: allow for
+ 16 pushes, an add, and "mv fp,sp". */
+ prologue_end = prologue_start + 40;
+
+ prologue_end = min (prologue_end, prev_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. */
+
+ cache->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))
+ {
+ cache->framesize += 4;
+ cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
+ /* Reset saved register map. */
+ saved_reg[regno] = regno;
+ }
+ }
+ 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) */
+ {
+ cache->frameoffset += offset;
+ offset = -offset;
+ }
+ cache->framesize -= offset;
+ }
+ else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */
+ {
+ findmask |= 2; /* setting of r7 found */
+ cache->framereg = THUMB_FP_REGNUM;
+ /* get scaled offset */
+ cache->frameoffset = (insn & 0xff) << 2;
+ }
+ else if (insn == 0x466f) /* mov r7, sp */
+ {
+ findmask |= 2; /* setting of r7 found */
+ cache->framereg = THUMB_FP_REGNUM;
+ cache->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
+ /* Something in the prolog that we don't care about or some
+ instruction from outside the prolog scheduled here for
+ optimization. */
+ continue;
+ }
+}
+
+/* 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 *next_frame, struct arm_prologue_cache *cache)
+{
+ int regno, sp_offset, fp_offset, ip_offset;
+ CORE_ADDR prologue_start, prologue_end, current_pc;
+ CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
+
+ /* Assume there is no frame until proven otherwise. */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->framesize = 0;
+ cache->frameoffset = 0;
+
+ /* Check for Thumb prologue. */
+ if (arm_pc_is_thumb (prev_pc))
+ {
+ thumb_scan_prologue (prev_pc, cache);
+ 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 (prev_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 = prev_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
+ {
+ /* We have no symbol information. Our only option is to assume this
+ function has a standard stack frame and the normal frame register.
+ Then, we can find the value of our frame pointer on entrance to
+ the callee (or at the present moment if this is the innermost frame).
+ The value stored there should be the address of the stmfd + 8. */
+ CORE_ADDR frame_loc;
+ LONGEST return_value;
+
+ frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
+ if (!safe_read_memory_integer (frame_loc, 4, &return_value))
+ return;
+ else
+ {
+ prologue_start = ADDR_BITS_REMOVE (return_value) - 8;
+ prologue_end = prologue_start + 64; /* See above. */
+ }
+ }
+
+ if (prev_pc < prologue_end)
+ prologue_end = prev_pc;
+
+ /* 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 as "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]
+
+ [Note further: The "mov ip,sp" only seems to be missing in
+ frameless functions at optimization level "-O2" or above,
+ in which case it is often (but not always) replaced by
+ "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */
+
+ sp_offset = fp_offset = ip_offset = 0;
+
+ for (current_pc = prologue_start;
+ current_pc < prologue_end;
+ current_pc += 4)
+ {
+ unsigned int insn = read_memory_unsigned_integer (current_pc, 4);
+
+ if (insn == 0xe1a0c00d) /* mov ip, sp */
+ {
+ ip_offset = 0;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = imm;
+ continue;
+ }
+ else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+ {
+ unsigned imm = insn & 0xff; /* immediate value */
+ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */
+ imm = (imm >> rot) | (imm << (32 - rot));
+ ip_offset = -imm;
+ continue;
+ }
+ else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */
+ {
+ sp_offset -= 4;
+ cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
+ continue;
+ }
+ else 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;
+ cache->saved_regs[regno].addr = sp_offset;
+ }
+ }
+ else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */
+ (insn & 0xffffc0f0) == 0xe14b00b0 || /* strh rx,[r11,#-n] */
+ (insn & 0xffffc000) == 0xe50b0000) /* str rx,[r11,#-n] */
+ {
+ /* No need to add this to saved_regs -- it's just an arg reg. */
+ continue;
+ }
+ else if ((insn & 0xffffc000) == 0xe5cd0000 || /* strb rx,[sp,#n] */
+ (insn & 0xffffc0f0) == 0xe1cd00b0 || /* strh rx,[sp,#n] */
+ (insn & 0xffffc000) == 0xe58d0000) /* str rx,[sp,#n] */
+ {
+ /* No need to add this to saved_regs -- it's just an arg reg. */
+ continue;
+ }
+ 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 + ip_offset;
+ cache->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);
+ cache->saved_regs[regno].addr = 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;
+ cache->saved_regs[fp_start_reg++].addr = 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]. */
+ cache->framesize = -sp_offset;
+ if (cache->framereg == ARM_FP_REGNUM)
+ cache->frameoffset = fp_offset - sp_offset;
+ else
+ cache->frameoffset = 0;
+}
+
+static struct arm_prologue_cache *
+arm_make_prologue_cache (struct frame_info *next_frame)
+{
+ int reg;
+ struct arm_prologue_cache *cache;
+ CORE_ADDR unwound_fp;
+
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ arm_scan_prologue (next_frame, cache);
+
+ unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+ if (unwound_fp == 0)
+ return cache;
+
+ cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
+
+ /* Calculate actual addresses of saved registers using offsets
+ determined by arm_scan_prologue. */
+ for (reg = 0; reg < NUM_REGS; reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
+
+ return cache;
+}
+
+/* Our frame ID for a normal frame is the current function's starting PC
+ and the caller's SP when we were called. */
+
+static void
+arm_prologue_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+ struct frame_id id;
+ CORE_ADDR func;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ func = frame_func_unwind (next_frame);
+
+ /* This is meant to halt the backtrace at "_start". Make sure we
+ don't halt it at a generic dummy frame. */
+ if (func <= LOWEST_PC)
+ return;
+
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return;
+
+ id = frame_id_build (cache->prev_sp, func);
+
+ /* Check that we're not going round in circles with the same frame
+ ID (but avoid applying the test to sentinel frames which do go
+ round in circles). */
+ if (frame_relative_level (next_frame) >= 0
+ && get_frame_type (next_frame) == NORMAL_FRAME
+ && frame_id_eq (get_frame_id (next_frame), id))
+ return;
+
+ *this_id = id;
+}
+
+static void
+arm_prologue_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ /* If we are asked to unwind the PC, then we need to return the LR
+ instead. The saved value of PC points into this frame's
+ prologue, not the next frame's resume location. */
+ if (prev_regnum == ARM_PC_REGNUM)
+ prev_regnum = ARM_LR_REGNUM;
+
+ /* SP is generally not saved to the stack, but this frame is
+ identified by NEXT_FRAME's stack pointer at the time of the call.
+ The value was already reconstructed into PREV_SP. */
+ if (prev_regnum == ARM_SP_REGNUM)
+ {
+ *lvalp = not_lval;
+ if (valuep)
+ store_unsigned_integer (valuep, 4, cache->prev_sp);
+ return;
+ }
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
+}
+
+struct frame_unwind arm_prologue_unwind = {
+ NORMAL_FRAME,
+ arm_prologue_this_id,
+ arm_prologue_prev_register
+};
+
+static const struct frame_unwind *
+arm_prologue_unwind_sniffer (struct frame_info *next_frame)
+{
+ return &arm_prologue_unwind;
+}
+
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (next_frame);
+ cache = *this_cache;
+
+ return cache->prev_sp + cache->frameoffset - cache->framesize;
+}
+
+struct frame_base arm_normal_base = {
+ &arm_prologue_unwind,
+ arm_normal_frame_base,
+ arm_normal_frame_base,
+ arm_normal_frame_base
+};
+
+static struct arm_prologue_cache *
+arm_make_sigtramp_cache (struct frame_info *next_frame)
+{
+ struct arm_prologue_cache *cache;
+ int reg;
+
+ cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+
+ cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
+
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ for (reg = 0; reg < NUM_REGS; reg++)
+ cache->saved_regs[reg].addr
+ = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
+ frame_pc_unwind (next_frame), reg);
+
+ /* FIXME: What about thumb mode? */
+ cache->framereg = ARM_SP_REGNUM;
+ cache->prev_sp
+ = read_memory_integer (cache->saved_regs[cache->framereg].addr,
+ register_size (current_gdbarch, cache->framereg));
+
+ return cache;
+}
+
+static void
+arm_sigtramp_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
+
+ /* FIXME drow/2003-07-07: This isn't right if we single-step within
+ the sigtramp frame; the PC should be the beginning of the trampoline. */
+ *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
+}
+
+static void
+arm_sigtramp_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int prev_regnum,
+ int *optimized,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ void *valuep)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_sigtramp_cache (next_frame);
+ cache = *this_cache;
+
+ trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+ optimized, lvalp, addrp, realnump, valuep);
+}
+
+struct frame_unwind arm_sigtramp_unwind = {
+ SIGTRAMP_FRAME,
+ arm_sigtramp_this_id,
+ arm_sigtramp_prev_register
+};
+
+static const struct frame_unwind *
+arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+{
+ /* Note: If an ARM PC_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 PC_IN_SIGTRAMP. */
+
+ if (SIGCONTEXT_REGISTER_ADDRESS_P ()
+ && PC_IN_SIGTRAMP (frame_pc_unwind (next_frame), (char *) 0))
+ return &arm_sigtramp_unwind;
+
+ return NULL;
+}
+
+/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos() and returned from
+ arm_push_dummy_call, and the PC needs to match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
+
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+ be used to construct the previous frame's ID, after looking up the
+ containing function). */
+
+static CORE_ADDR
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+ return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+}
+
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
+}
+
+/* DEPRECATED_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
+};
+
+/* When arguments must be pushed onto the stack, they go on in reverse
+ order. The code below implements a FILO (stack) to do this. */
+
+struct stack_item
+{
+ int len;
+ struct stack_item *prev;
+ void *data;
+};
+
+static struct stack_item *
+push_stack_item (struct stack_item *prev, void *contents, int len)
+{
+ struct stack_item *si;
+ si = xmalloc (sizeof (struct stack_item));
+ si->data = xmalloc (len);
+ si->len = len;
+ si->prev = prev;
+ memcpy (si->data, contents, len);
+ return si;
+}
+
+static struct stack_item *
+pop_stack_item (struct stack_item *si)
+{
+ struct stack_item *dead = si;
+ si = si->prev;
+ xfree (dead->data);
+ xfree (dead);
+ return si;
+}
+
+/* We currently only support passing parameters in integer registers. This
+ conforms with GCC's default model. Several other variants exist and
+ we should probably support some of them based on the selected ABI. */
+
+static CORE_ADDR
+arm_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int argnum;
+ int argreg;
+ int nstack;
+ struct stack_item *si = NULL;
+
+ /* Set the return address. For the ARM, the return breakpoint is
+ always at BP_ADDR. */
+ /* XXX Fix for Thumb. */
+ regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
+
+ /* 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 = 0;
+
+ argreg = ARM_A1_REGNUM;
+ nstack = 0;
+
+ /* Some platforms require a double-word aligned stack. Make sure sp
+ is correctly aligned before we start. We always do this even if
+ it isn't really needed -- it can never hurt things. */
+ sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
+
+ /* The struct_return pointer occupies the first parameter
+ passing register. */
+ if (struct_return)
+ {
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
+ REGISTER_NAME (argreg), paddr (struct_addr));
+ regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
+ argreg++;
+ }
+
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ int len;
+ struct type *arg_type;
+ struct type *target_type;
+ enum type_code typecode;
+ char *val;
+
+ arg_type = check_typedef (VALUE_TYPE (args[argnum]));
+ len = TYPE_LENGTH (arg_type);
+ target_type = TYPE_TARGET_TYPE (arg_type);
+ typecode = TYPE_CODE (arg_type);
+ val = VALUE_CONTENTS (args[argnum]);
+
+ /* If the argument is a pointer to a function, and it is a
+ Thumb function, create a LOCAL copy of the value and set
+ the THUMB bit in it. */
+ if (TYPE_CODE_PTR == typecode
+ && target_type != NULL
+ && TYPE_CODE_FUNC == TYPE_CODE (target_type))
+ {
+ CORE_ADDR regval = extract_unsigned_integer (val, len);
+ if (arm_pc_is_thumb (regval))
+ {
+ val = alloca (len);
+ store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
+ }
+ }
+
+ /* 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 < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
+
+ if (argreg <= ARM_LAST_ARG_REGNUM)
+ {
+ /* The argument is being passed in a general purpose
+ register. */
+ CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
+ argnum, REGISTER_NAME (argreg),
+ phex (regval, DEPRECATED_REGISTER_SIZE));
+ regcache_cooked_write_unsigned (regcache, argreg, regval);
+ argreg++;
+ }
+ else
+ {
+ /* Push the arguments onto the stack. */
+ if (arm_debug)
+ fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
+ argnum, nstack);
+ si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE);
+ nstack += DEPRECATED_REGISTER_SIZE;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+ }
+ }
+ /* If we have an odd number of words to push, then decrement the stack
+ by one word now, so first stack argument will be dword aligned. */
+ if (nstack & 4)
+ sp -= 4;
+
+ while (si)
+ {
+ sp -= si->len;
+ write_memory (sp, si->data, si->len);
+ si = pop_stack_item (si);
+ }
+
+ /* Finally, update teh SP register. */
+ regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
+
+ return sp;
+}
+
+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 (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ 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 (struct gdbarch *gdbarch, 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_SIZE;
+ else if (regnum < ARM_PS_REGNUM)
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
+ else
+ return (NUM_GREGS * INT_REGISTER_SIZE
+ + NUM_FREGS * FP_REGISTER_SIZE
+ + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
+}
+
+/* Map GDB internal REGNUM onto the Arm simulator register numbers. */
+static int
+arm_register_sim_regno (int regnum)
+{
+ int reg = regnum;
+ gdb_assert (reg >= 0 && reg < NUM_REGS);
+
+ if (reg < NUM_GREGS)
+ return SIM_ARM_R0_REGNUM + reg;
+ reg -= NUM_GREGS;
+
+ if (reg < NUM_FREGS)
+ return SIM_ARM_FP0_REGNUM + reg;
+ reg -= NUM_FREGS;
+
+ if (reg < NUM_SREGS)
+ return SIM_ARM_FPS_REGNUM + reg;
+ reg -= NUM_SREGS;
+
+ internal_error (__FILE__, __LINE__, "Bad REGNUM %d", regnum);
+}
+
+/* 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 (const struct floatformat *fmt, const 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 (fmt, &d, dbl);
+}
+
+static void
+convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
+{
+ DOUBLEST d;
+ floatformat_to_doublest (fmt, 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)) * DEPRECATED_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, and blx */
+ {
+ unsigned short inst2 = read_memory_integer (pc + 2, 2);
+ offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
+ nextpc = pc_val + offset;
+ /* For BLX make sure to clear the low bits. */
+ if (bits (inst2, 11, 12) == 1)
+ nextpc = nextpc & 0xfffffffc;
+ }
+ else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
+ {
+ if (bits (inst1, 3, 6) == 0x0f)
+ nextpc = pc_val;
+ else
+ nextpc = read_register (bits (inst1, 3, 6));
+
+ nextpc = ADDR_BITS_REMOVE (nextpc);
+ if (nextpc == pc)
+ error ("Infinite loop detected");
+ }
+
+ 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");
+
+ /* BX <reg>, BLX <reg> */
+ if (bits (this_instr, 4, 28) == 0x12fff1
+ || bits (this_instr, 4, 28) == 0x12fff3)
+ {
+ rn = bits (this_instr, 0, 3);
+ result = (rn == 15) ? pc_val + 8 : read_register (rn);
+ nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+
+ if (nextpc == pc)
+ error ("Infinite loop detected");
+
+ return nextpc;
+ }
+
+ /* 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);
+
+ /* BLX */
+ if (bits (this_instr, 28, 31) == INST_NV)
+ nextpc |= bit (this_instr, 24) << 1;
+
+ 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. */
+
+static const 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,
+ struct regcache *regs,
+ void *dst)
+{
+ bfd_byte *valbuf = dst;
+
+ if (TYPE_CODE_FLT == TYPE_CODE (type))
+ {
+ switch (arm_get_fp_model (current_gdbarch))
+ {
+ case ARM_FLOAT_FPA:
+ {
+ /* The value is in register F0 in internal format. We need to
+ extract the raw value and then convert it to the desired
+ internal type. */
+ bfd_byte tmpbuf[FP_REGISTER_SIZE];
+
+ regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
+ convert_from_extended (floatformat_from_type (type), tmpbuf,
+ valbuf);
+ }
+ break;
+
+ case ARM_FLOAT_SOFT_FPA:
+ case ARM_FLOAT_SOFT_VFP:
+ regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
+ if (TYPE_LENGTH (type) > 4)
+ regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
+ valbuf + INT_REGISTER_SIZE);
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "arm_extract_return_value: Floating point model not supported");
+ break;
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_CHAR
+ || TYPE_CODE (type) == TYPE_CODE_BOOL
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ /* If the the type is a plain integer, then the access is
+ straight-forward. Otherwise we have to play around a bit more. */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ ULONGEST tmp;
+
+ while (len > 0)
+ {
+ /* By using store_unsigned_integer we avoid having to do
+ anything special for small big-endian values. */
+ regcache_cooked_read_unsigned (regs, regno++, &tmp);
+ store_unsigned_integer (valbuf,
+ (len > INT_REGISTER_SIZE
+ ? INT_REGISTER_SIZE : len),
+ tmp);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+ else
+ {
+ /* For a structure or union the behaviour is as if the value had
+ been stored to word-aligned memory and then loaded into
+ registers with 32-bit load instruction(s). */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+
+ while (len > 0)
+ {
+ regcache_cooked_read (regs, regno++, tmpbuf);
+ memcpy (valbuf, tmpbuf,
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+}
+
+/* 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 (struct regcache *regcache)
+{
+ ULONGEST ret;
+
+ regcache_cooked_read_unsigned (regcache, ARM_A1_REGNUM, &ret);
+ return ret;
+}
+
+/* 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;
+ enum type_code code;
+
+ CHECK_TYPEDEF (type);
+
+ /* 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 DEPRECATED_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) > DEPRECATED_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
+ DEPRECATED_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 (check_typedef (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, struct regcache *regs,
+ const void *src)
+{
+ const bfd_byte *valbuf = src;
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ char buf[MAX_REGISTER_SIZE];
+
+ switch (arm_get_fp_model (current_gdbarch))
+ {
+ case ARM_FLOAT_FPA:
+
+ convert_to_extended (floatformat_from_type (type), buf, valbuf);
+ regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
+ break;
+
+ case ARM_FLOAT_SOFT_FPA:
+ case ARM_FLOAT_SOFT_VFP:
+ regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
+ if (TYPE_LENGTH (type) > 4)
+ regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
+ valbuf + INT_REGISTER_SIZE);
+ break;
+
+ default:
+ internal_error
+ (__FILE__, __LINE__,
+ "arm_store_return_value: Floating point model not supported");
+ break;
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_CHAR
+ || TYPE_CODE (type) == TYPE_CODE_BOOL
+ || TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ if (TYPE_LENGTH (type) <= 4)
+ {
+ /* Values of one word or less are zero/sign-extended and
+ returned in r0. */
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+ LONGEST val = unpack_long (type, valbuf);
+
+ store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
+ regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
+ }
+ else
+ {
+ /* Integral values greater than one word are stored in consecutive
+ registers starting with r0. This will always be a multiple of
+ the regiser size. */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+
+ while (len > 0)
+ {
+ regcache_cooked_write (regs, regno++, valbuf);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+ }
+ else
+ {
+ /* For a structure or union the behaviour is as if the value had
+ been stored to word-aligned memory and then loaded into
+ registers with 32-bit load instruction(s). */
+ int len = TYPE_LENGTH (type);
+ int regno = ARM_A1_REGNUM;
+ bfd_byte tmpbuf[INT_REGISTER_SIZE];
+
+ while (len > 0)
+ {
+ memcpy (tmpbuf, valbuf,
+ len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+ regcache_cooked_write (regs, regno++, tmpbuf);
+ len -= INT_REGISTER_SIZE;
+ valbuf += INT_REGISTER_SIZE;
+ }
+ }
+}
+
+static int
+arm_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char buf[INT_REGISTER_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_SIZE))
+ return 0;
+
+ *pc = extract_unsigned_integer (buf, INT_REGISTER_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 (0 == find_pc_partial_function (pc, name ? NULL : &name,
+ &start_addr, NULL))
+ 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 */
+}
+
+static void
+set_arm_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set arm\" must be followed by an apporpriate subcommand.\n");
+ help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
+}
+
+static void
+show_arm_command (char *args, int from_tty)
+{
+ cmd_show_list (showarmcmdlist, from_tty, "");
+}
+
+enum arm_float_model
+arm_get_fp_model (struct gdbarch *gdbarch)
+{
+ if (arm_fp_model == ARM_FLOAT_AUTO)
+ return gdbarch_tdep (gdbarch)->fp_model;
+
+ return arm_fp_model;
+}
+
+static void
+arm_set_fp (struct gdbarch *gdbarch)
+{
+ enum arm_float_model fp_model = arm_get_fp_model (gdbarch);
+
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE
+ && (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA))
+ {
+ set_gdbarch_double_format (gdbarch,
+ &floatformat_ieee_double_littlebyte_bigword);
+ set_gdbarch_long_double_format
+ (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
+ }
+ else
+ {
+ set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
+ set_gdbarch_long_double_format (gdbarch,
+ &floatformat_ieee_double_little);
+ }
+}
+
+static void
+set_fp_model_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ enum arm_float_model fp_model;
+
+ for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
+ if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
+ {
+ arm_fp_model = fp_model;
+ break;
+ }
+
+ if (fp_model == ARM_FLOAT_LAST)
+ internal_error (__FILE__, __LINE__, "Invalid fp model accepted: %s.",
+ current_fp_model);
+
+ if (gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ arm_set_fp (current_gdbarch);
+}
+
+static void
+show_fp_model (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ if (arm_fp_model == ARM_FLOAT_AUTO
+ && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+ printf_filtered (" - the default for the current ABI is \"%s\".\n",
+ fp_model_strings[tdep->fp_model]);
+}
+
+/* If the user changes the register disassembly style used for info
+ register and other commands, we have to also switch the style used
+ in opcodes for disassembly output. This function is run in the "set
+ arm disassembly" command, and does that. */
+
+static void
+set_disassembly_style_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_disassembly_style ();
+}
+
+/* Return the ARM register name corresponding to register I. */
+static const char *
+arm_register_name (int i)
+{
+ return arm_register_names[i];
+}
+
+static void
+set_disassembly_style (void)
+{
+ const char *setname, *setdesc, **regnames;
+ int numregs, j;
+
+ /* Find the style that the user wants in the opcodes table. */
+ int current = 0;
+ numregs = get_arm_regnames (current, &setname, &setdesc, &regnames);
+ while ((disassembly_style != setname)
+ && (current < num_disassembly_options))
+ get_arm_regnames (++current, &setname, &setdesc, &regnames);
+ 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 deprecated
+ by the "set arm disassembly" command. */
+
+static void
+arm_othernames (char *names, int n)
+{
+ /* Circle through the various flavors. */
+ current_option = (current_option + 1) % num_disassembly_options;
+
+ disassembly_style = valid_disassembly_styles[current_option];
+ set_disassembly_style ();
+}
+
+/* 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
+arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+ write_register_pid (ARM_PC_REGNUM, pc, ptid);
+
+ /* If necessary, set the T bit. */
+ if (arm_apcs_32)
+ {
+ CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+ if (arm_pc_is_thumb (pc))
+ write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+ else
+ write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+ }
+}
+
+static enum gdb_osabi
+arm_elf_osabi_sniffer (bfd *abfd)
+{
+ unsigned int elfosabi, eflags;
+ enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+ elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+ switch (elfosabi)
+ {
+ case ELFOSABI_NONE:
+ /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
+ file are conforming to the base specification for that machine
+ (there are no OS-specific extensions). In order to determine the
+ real OS in use we must look for OS notes that have been added. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* Existing ARM tools don't set this field, so look at the EI_FLAGS
+ field for more information. */
+ eflags = EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags);
+ switch (eflags)
+ {
+ case EF_ARM_EABI_VER1:
+ osabi = GDB_OSABI_ARM_EABI_V1;
+ break;
+
+ case EF_ARM_EABI_VER2:
+ osabi = GDB_OSABI_ARM_EABI_V2;
+ break;
+
+ case EF_ARM_EABI_UNKNOWN:
+ /* Assume GNU tools. */
+ osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_elf_osabi_sniffer: Unknown ARM EABI "
+ "version 0x%x", eflags);
+ }
+ }
+ break;
+
+ case ELFOSABI_ARM:
+ /* GNU tools use this value. Check note sections in this case,
+ as well. */
+ bfd_map_over_sections (abfd,
+ generic_elf_osabi_sniff_abi_tag_sections,
+ &osabi);
+ if (osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* Assume APCS ABI. */
+ osabi = GDB_OSABI_ARM_APCS;
+ }
+ break;
+
+ case ELFOSABI_FREEBSD:
+ osabi = GDB_OSABI_FREEBSD_ELF;
+ break;
+
+ case ELFOSABI_NETBSD:
+ osabi = GDB_OSABI_NETBSD_ELF;
+ break;
+
+ case ELFOSABI_LINUX:
+ osabi = GDB_OSABI_LINUX;
+ break;
+ }
+
+ return osabi;
+}
+
+
+/* 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;
+
+ /* Try to deterimine the ABI of the object we are loading. */
+
+ if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ switch (bfd_get_flavour (info.abfd))
+ {
+ case bfd_target_aout_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ info.osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ case bfd_target_coff_flavour:
+ /* Assume it's an old APCS-style ABI. */
+ /* XXX WinCE? */
+ info.osabi = GDB_OSABI_ARM_APCS;
+ break;
+
+ default:
+ /* Leave it as "unknown". */
+ break;
+ }
+ }
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* We used to default to FPA for generic ARM, but almost nobody uses that
+ now, and we now provide a way for the user to force the model. So
+ default to the most useful variant. */
+ tdep->fp_model = ARM_FLOAT_SOFT_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_deprecated_call_dummy_words (gdbarch, arm_call_dummy_words);
+ set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
+
+ set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
+
+ set_gdbarch_write_pc (gdbarch, arm_write_pc);
+
+ /* Frame handling. */
+ set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+ set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
+
+ set_gdbarch_deprecated_frameless_function_invocation (gdbarch, arm_frameless_function_invocation);
+
+ frame_base_set_default (gdbarch, &arm_normal_base);
+
+ /* Address manipulation. */
+ set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
+ set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
+
+ /* 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_deprecated_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);
+
+ /* Information about registers, etc. */
+ set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
+ set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */
+ set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
+ set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
+ set_gdbarch_deprecated_register_bytes (gdbarch,
+ (NUM_GREGS * INT_REGISTER_SIZE
+ + NUM_FREGS * FP_REGISTER_SIZE
+ + NUM_SREGS * STATUS_REGISTER_SIZE));
+ set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
+ set_gdbarch_register_type (gdbarch, arm_register_type);
+
+ /* Internal <-> external register number maps. */
+ set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
+
+ /* Integer registers are 4 bytes. */
+ set_gdbarch_deprecated_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_use_struct_convention (gdbarch, arm_use_struct_convention);
+ set_gdbarch_deprecated_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);
+
+ /* Disassembly. */
+ set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
+
+ /* 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. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ /* Add some default predicates. */
+ frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
+ frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
+
+ /* 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);
+ arm_set_fp (gdbarch);
+ break;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ "arm_gdbarch_init: bad byte order for float format");
+ }
+
+ 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;
+
+ 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. */
+}
+
+extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_arm_tdep (void)
+{
+ struct ui_file *stb;
+ long length;
+ struct cmd_list_element *new_set, *new_show;
+ const char *setname;
+ const char *setdesc;
+ const char **regnames;
+ int numregs, i, j;
+ static char *helptext;
+
+ gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
+
+ /* Register an ELF OS ABI sniffer for ARM binaries. */
+ gdbarch_register_osabi_sniffer (bfd_arch_arm,
+ bfd_target_elf_flavour,
+ arm_elf_osabi_sniffer);
+
+ /* Register some ABI variants for embedded systems. */
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V1,
+ arm_init_abi_eabi_v1);
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V2,
+ arm_init_abi_eabi_v2);
+ gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS,
+ arm_init_abi_apcs);
+
+ /* Get the number of possible sets of register names defined in opcodes. */
+ num_disassembly_options = get_arm_regname_num_options ();
+
+ /* Add root prefix command for all "set arm"/"show arm" commands. */
+ add_prefix_cmd ("arm", no_class, set_arm_command,
+ "Various ARM-specific commands.",
+ &setarmcmdlist, "set arm ", 0, &setlist);
+
+ add_prefix_cmd ("arm", no_class, show_arm_command,
+ "Various ARM-specific commands.",
+ &showarmcmdlist, "show arm ", 0, &showlist);
+
+ /* 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 style.\n"
+ "The valid values are:\n");
+
+ /* Initialize the array that will be passed to add_set_enum_cmd(). */
+ valid_disassembly_styles
+ = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
+ for (i = 0; i < num_disassembly_options; i++)
+ {
+ numregs = get_arm_regnames (i, &setname, &setdesc, &regnames);
+ valid_disassembly_styles[i] = setname;
+ fprintf_unfiltered (stb, "%s - %s\n", setname,
+ setdesc);
+ /* Copy the default names (if found) and synchronize disassembler. */
+ if (!strcmp (setname, "std"))
+ {
+ disassembly_style = 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_disassembly_styles[num_disassembly_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 deprecated disassembly-flavor command. */
+ new_set = add_set_enum_cmd ("disassembly-flavor", no_class,
+ valid_disassembly_styles,
+ &disassembly_style,
+ helptext,
+ &setlist);
+ set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
+ deprecate_cmd (new_set, "set arm disassembly");
+ deprecate_cmd (add_show_from_set (new_set, &showlist),
+ "show arm disassembly");
+
+ /* And now add the new interface. */
+ new_set = add_set_enum_cmd ("disassembler", no_class,
+ valid_disassembly_styles, &disassembly_style,
+ helptext, &setarmcmdlist);
+
+ set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
+ add_show_from_set (new_set, &showarmcmdlist);
+
+ add_setshow_cmd_full ("apcs32", no_class,
+ var_boolean, (char *) &arm_apcs_32,
+ "Set usage of ARM 32-bit mode.",
+ "Show usage of ARM 32-bit mode.",
+ NULL, NULL,
+ &setlist, &showlist, &new_set, &new_show);
+ deprecate_cmd (new_set, "set arm apcs32");
+ deprecate_cmd (new_show, "show arm apcs32");
+
+ add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
+ "Set usage of ARM 32-bit mode. "
+ "When off, a 26-bit PC will be used.",
+ "Show usage of ARM 32-bit mode. "
+ "When off, a 26-bit PC will be used.",
+ NULL, NULL,
+ &setarmcmdlist, &showarmcmdlist);
+
+ /* Add a command to allow the user to force the FPU model. */
+ new_set = add_set_enum_cmd
+ ("fpu", no_class, fp_model_strings, &current_fp_model,
+ "Set the floating point type.\n"
+ "auto - Determine the FP typefrom the OS-ABI.\n"
+ "softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n"
+ "fpa - FPA co-processor (GCC compiled).\n"
+ "softvfp - Software FP with pure-endian doubles.\n"
+ "vfp - VFP co-processor.",
+ &setarmcmdlist);
+ set_cmd_sfunc (new_set, set_fp_model_sfunc);
+ set_cmd_sfunc (add_show_from_set (new_set, &showarmcmdlist), show_fp_model);
+
+ /* Add the deprecated "othernames" command. */
+ deprecate_cmd (add_com ("othernames", class_obscure, arm_othernames,
+ "Switch to the next set of register names."),
+ "set arm disassembly");
+
+ /* Debugging flag. */
+ add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
+ "Set ARM debugging. "
+ "When on, arm-specific debugging is enabled.",
+ "Show ARM debugging. "
+ "When on, arm-specific debugging is enabled.",
+ NULL, NULL,
+ &setdebuglist, &showdebuglist);
+}
diff --git a/contrib/gdb/gdb/coff-solib.c b/contrib/gdb/gdb/coff-solib.c
new file mode 100644
index 0000000..64dca7b
--- /dev/null
+++ b/contrib/gdb/gdb/coff-solib.c
@@ -0,0 +1,134 @@
+/* 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
new file mode 100644
index 0000000..d29f96a
--- /dev/null
+++ b/contrib/gdb/gdb/coff-solib.h
@@ -0,0 +1,186 @@
+/* COFF (SVR3) Shared library declarations for GDB, the GNU Debugger.
+ Copyright 1992, 1993, 1998, 1999, 2000, 2003 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) \
+""
+
+/* 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/config/nm-gnu.h b/contrib/gdb/gdb/config/nm-gnu.h
new file mode 100644
index 0000000..73a4180
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-gnu.h
@@ -0,0 +1,43 @@
+/* Common declarations for the GNU Hurd
+
+ Copyright 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef __NM_GNU_H__
+#define __NM_GNU_H__
+
+#include <unistd.h>
+#include <mach.h>
+#include <mach/exception.h>
+#include "regcache.h"
+
+extern char *gnu_target_pid_to_str (int pid);
+
+/* Before storing, we need to read all the registers. */
+#define CHILD_PREPARE_TO_STORE() deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES)
+
+/* Don't do wait_for_inferior on attach. */
+#define ATTACH_NO_WAIT
+
+/* Use SVR4 style shared library support */
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+#define NO_CORE_OPS
+
+#endif /* __NM_GNU_H__ */
diff --git a/contrib/gdb/gdb/config/nm-lynx.h b/contrib/gdb/gdb/config/nm-lynx.h
new file mode 100644
index 0000000..4a55a13
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-lynx.h
@@ -0,0 +1,86 @@
+/* Native-dependent definitions for LynxOS.
+
+ Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef NM_LYNX_H
+#define NM_LYNX_H
+
+struct target_waitstatus;
+
+#include <sys/conf.h>
+#include <sys/kernel.h>
+/* sys/kernel.h should define this, but doesn't always, sigh. */
+#ifndef __LYNXOS
+#define __LYNXOS
+#endif
+#include <sys/mem.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/itimer.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include "gdbthread.h"
+
+/* This is the amount to subtract from u.u_ar0 to get the offset in
+ the core file of the register values. */
+
+#define KERNEL_U_ADDR USRSTACK
+
+/* As of LynxOS 2.2.2 (beta 8/15/94), this is int. Previous versions seem to
+ have had no prototype, so I'm not sure why GDB used to define this to
+ char *. */
+#define PTRACE_ARG3_TYPE int
+
+/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
+
+#define FETCH_INFERIOR_REGISTERS
+
+/* Thread ID of stopped thread. */
+
+#define WIFTID(x) (((union wait *)&x)->w_tid)
+
+/* Override child_wait in inftarg.c */
+
+#define CHILD_WAIT
+
+/* Override child_resume in infptrace.c */
+
+#define CHILD_RESUME
+
+/* Override child_thread_alive in intarg.c */
+
+#define CHILD_THREAD_ALIVE
+
+#include "target.h"
+
+extern ptid_t child_wait (ptid_t ptid,
+ struct target_waitstatus *status);
+
+/* Lynx needs a special definition of this so that we can
+ print out the pid and thread number seperately. */
+
+
+/* override child_pid_to_str in inftarg.c */
+#define CHILD_PID_TO_STR
+extern char *lynx_pid_to_str (ptid_t ptid);
+
+#endif /* NM_LYNX_H */
diff --git a/contrib/gdb/gdb/config/nm-nbsd.h b/contrib/gdb/gdb/config/nm-nbsd.h
new file mode 100644
index 0000000..5078c56
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-nbsd.h
@@ -0,0 +1,27 @@
+/* Native-dependent definitions for NetBSD.
+ Copyright 1994, 1996, 1999 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. */
+
+#define PTRACE_ARG3_TYPE char*
+
+#define FETCH_INFERIOR_REGISTERS
+
+#define ATTACH_DETACH
+
+#include "solib.h" /* Support for shared libraries. */
diff --git a/contrib/gdb/gdb/config/nm-sysv4.h b/contrib/gdb/gdb/config/nm-sysv4.h
new file mode 100644
index 0000000..4b4f098
--- /dev/null
+++ b/contrib/gdb/gdb/config/nm-sysv4.h
@@ -0,0 +1,34 @@
+/* Definitions for running gdb on a host machine running any flavor of SVR4.
+ Copyright 1991, 1992, 1993, 1998 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* Use SVR4 style shared library support */
+
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+
+/* SVR4 has /proc support, so use it instead of ptrace. */
+
+#define USE_PROC_FS
+
+/* SVR4 machines can easily do attach and detach via /proc (procfs.c)
+ support */
+
+#define ATTACH_DETACH
diff --git a/contrib/gdb/gdb/config/tm-lynx.h b/contrib/gdb/gdb/config/tm-lynx.h
new file mode 100644
index 0000000..7fbc06f
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-lynx.h
@@ -0,0 +1,32 @@
+/* Macro definitions for LynxOS targets.
+ Copyright 1993, 1995 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef TM_LYNX_H
+#define TM_LYNX_H
+
+#include "coff-solib.h" /* COFF shared library support */
+
+/* Lynx's signal.h doesn't seem to have any macros for what signal numbers
+ the real-time events are. */
+#define REALTIME_LO 33
+/* One more than the last one. */
+#define REALTIME_HI 64
+
+#endif /* TM_LYNX_H */
diff --git a/contrib/gdb/gdb/config/tm-sunos.h b/contrib/gdb/gdb/config/tm-sunos.h
new file mode 100644
index 0000000..c8db07e
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-sunos.h
@@ -0,0 +1,32 @@
+/* Target machine sub-description for SunOS version 4.
+ This is included by other tm-*.h files to specify SunOS-specific stuff.
+ Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "solib.h" /* Support for shared libraries. */
+
+/* Return non-zero if we are in a shared library trampoline code stub. */
+
+#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \
+ lookup_solib_trampoline_symbol_by_pc (pc)
+
+/* If PC is in a shared library trampoline code, return the PC
+ where the function itself actually starts. If not, return 0. */
+
+#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc)
diff --git a/contrib/gdb/gdb/config/tm-sysv4.h b/contrib/gdb/gdb/config/tm-sysv4.h
new file mode 100644
index 0000000..9a39af2
--- /dev/null
+++ b/contrib/gdb/gdb/config/tm-sysv4.h
@@ -0,0 +1,37 @@
+/* Macro definitions for GDB on all SVR4 target systems.
+ Copyright 1991, 1992, 1993, 1994, 1996, 1997, 2000
+ Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* For SVR4 shared libraries, each call to a library routine goes through
+ a small piece of trampoline code in the ".plt" section.
+ The horribly ugly wait_for_inferior() routine uses this macro to detect
+ when we have stepped into one of these fragments.
+ We do not use lookup_solib_trampoline_symbol_by_pc, because
+ we cannot always find the shared library trampoline symbols
+ (e.g. on Irix5). */
+
+#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) in_plt_section((pc), (name))
+extern int in_plt_section (CORE_ADDR, char *);
+
+/* If PC is in a shared library trampoline code, return the PC
+ where the function itself actually starts. If not, return 0. */
+
+#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc)
diff --git a/contrib/gdb/gdb/config/xm-nbsd.h b/contrib/gdb/gdb/config/xm-nbsd.h
new file mode 100644
index 0000000..c8d00f6
--- /dev/null
+++ b/contrib/gdb/gdb/config/xm-nbsd.h
@@ -0,0 +1,26 @@
+/* Host-dependent definitions for any CPU running NetBSD.
+ Copyright 1993, 1994, 1995, 1996, 1999 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 this to get things like NGROUPS which <limits.h> doesn't
+ define on some systems. */
+#include <sys/param.h>
+
+/* NetBSD has termios facilities. */
+#define HAVE_TERMIOS
diff --git a/contrib/gdb/gdb/config/xm-sysv4.h b/contrib/gdb/gdb/config/xm-sysv4.h
new file mode 100644
index 0000000..614d403
--- /dev/null
+++ b/contrib/gdb/gdb/config/xm-sysv4.h
@@ -0,0 +1,29 @@
+/* Definitions for running gdb on a host machine running any flavor of SVR4.
+ Copyright 1991, 1992, 1993, 1995, 1998 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support (fnf@cygnus.com).
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* SVR4 has termios facilities. */
+
+#undef HAVE_TERMIO
+#define HAVE_TERMIOS
+
+/* SVR4 is a derivative of System V Release 3 (USG) */
+
+#define USG
diff --git a/contrib/gdb/gdb/cpu32bug-rom.c b/contrib/gdb/gdb/cpu32bug-rom.c
new file mode 100644
index 0000000..03b3132
--- /dev/null
+++ b/contrib/gdb/gdb/cpu32bug-rom.c
@@ -0,0 +1,180 @@
+/* Remote debugging interface for CPU32Bug Rom monitor for GDB, the GNU debugger.
+ Copyright 1995, 1996, 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"
+
+#include "m68k-tdep.h"
+
+static void cpu32bug_open (char *args, int from_tty);
+
+static void
+cpu32bug_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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_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 const char *
+cpu32bug_regname (int index)
+{
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "SR", "PC"
+ };
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * Define the monitor command strings. Since these are passed directly
+ * through to a printf style function, we need can include formatting
+ * strings. We also need a CR or LF on the end.
+ */
+
+static struct target_ops cpu32bug_ops;
+
+static char *cpu32bug_inits[] =
+{"\r", NULL};
+
+static struct monitor_ops cpu32bug_cmds;
+
+static void
+init_cpu32bug_cmds (void)
+{
+ cpu32bug_cmds.flags = MO_CLR_BREAK_USES_ADDR;
+ cpu32bug_cmds.init = cpu32bug_inits; /* Init strings */
+ cpu32bug_cmds.cont = "g\r"; /* continue command */
+ cpu32bug_cmds.step = "t\r"; /* single step */
+ cpu32bug_cmds.stop = NULL; /* interrupt command */
+ cpu32bug_cmds.set_break = "br %x\r"; /* set a breakpoint */
+ cpu32bug_cmds.clr_break = "nobr %x\r"; /* clear a breakpoint */
+ cpu32bug_cmds.clr_all_break = "nobr\r"; /* clear all breakpoints */
+ cpu32bug_cmds.fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
+ cpu32bug_cmds.setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
+ cpu32bug_cmds.setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
+ cpu32bug_cmds.setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
+ cpu32bug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ cpu32bug_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ cpu32bug_cmds.setmem.term = NULL; /* setreg.term */
+ cpu32bug_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ cpu32bug_cmds.getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
+ cpu32bug_cmds.getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
+ cpu32bug_cmds.getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
+ cpu32bug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ cpu32bug_cmds.getmem.resp_delim = " "; /* getmem.resp_delim */
+ cpu32bug_cmds.getmem.term = NULL; /* getmem.term */
+ cpu32bug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ cpu32bug_cmds.setreg.cmd = "rs %s %x\r"; /* setreg.cmd (name, value) */
+ cpu32bug_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ cpu32bug_cmds.setreg.term = NULL; /* setreg.term */
+ cpu32bug_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ cpu32bug_cmds.getreg.cmd = "rs %s\r"; /* getreg.cmd (name) */
+ cpu32bug_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
+ cpu32bug_cmds.getreg.term = NULL; /* getreg.term */
+ cpu32bug_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
+ cpu32bug_cmds.dump_registers = "rd\r"; /* dump_registers */
+ cpu32bug_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
+ cpu32bug_cmds.supply_register = cpu32bug_supply_register; /* supply_register */
+ cpu32bug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ cpu32bug_cmds.load = "lo\r"; /* download command */
+ cpu32bug_cmds.loadresp = "\n"; /* load response */
+ cpu32bug_cmds.prompt = "CPU32Bug>"; /* monitor command prompt */
+ cpu32bug_cmds.line_term = "\r"; /* end-of-line terminator */
+ cpu32bug_cmds.cmd_end = NULL; /* optional command terminator */
+ cpu32bug_cmds.target = &cpu32bug_ops; /* target operations */
+ cpu32bug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ cpu32bug_cmds.regnames = NULL; /* registers names */
+ cpu32bug_cmds.regname = cpu32bug_regname;
+ cpu32bug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+}; /* init_cpu32bug_cmds */
+
+static void
+cpu32bug_open (char *args, int from_tty)
+{
+ monitor_open (args, &cpu32bug_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_cpu32bug_rom; /* -Wmissing-prototypes */
+
+void
+_initialize_cpu32bug_rom (void)
+{
+ init_cpu32bug_cmds ();
+ init_monitor_ops (&cpu32bug_ops);
+
+ cpu32bug_ops.to_shortname = "cpu32bug";
+ cpu32bug_ops.to_longname = "CPU32Bug monitor";
+ cpu32bug_ops.to_doc = "Debug via the CPU32Bug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ cpu32bug_ops.to_open = cpu32bug_open;
+
+ add_target (&cpu32bug_ops);
+}
diff --git a/contrib/gdb/gdb/gnu-nat.c b/contrib/gdb/gdb/gnu-nat.c
new file mode 100644
index 0000000..a61d577
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-nat.c
@@ -0,0 +1,3409 @@
+/* Interface GDB to the GNU Hurd.
+ Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Some code and ideas from m3-nat.c by Jukka Virtanen <jtv@hut.fi>
+
+ 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>
+#include <errno.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include "gdb_string.h"
+#include <sys/ptrace.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/exception.h>
+#include <mach/message.h>
+#include <mach/notify.h>
+#include <mach/vm_attributes.h>
+
+#include <hurd.h>
+#include <hurd/interrupt.h>
+#include <hurd/msg.h>
+#include <hurd/msg_request.h>
+#include <hurd/process.h>
+#include <hurd/process_request.h>
+#include <hurd/signal.h>
+#include <hurd/sigpreempt.h>
+
+#include <portinfo.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 "gdbthread.h"
+#include "gdb_assert.h"
+#include "gdb_obstack.h"
+
+#include "gnu-nat.h"
+
+#include "exc_request_S.h"
+#include "notify_S.h"
+#include "process_reply_S.h"
+#include "msg_reply_S.h"
+#include "exc_request_U.h"
+#include "msg_U.h"
+
+static process_t proc_server = MACH_PORT_NULL;
+
+/* If we've sent a proc_wait_request to the proc server, the pid of the
+ process we asked about. We can only ever have one outstanding. */
+int proc_wait_pid = 0;
+
+/* The number of wait requests we've sent, and expect replies from. */
+int proc_waits_pending = 0;
+
+int gnu_debug_flag = 0;
+
+/* Forward decls */
+
+extern struct target_ops gnu_ops;
+
+struct inf *make_inf ();
+void inf_clear_wait (struct inf *inf);
+void inf_cleanup (struct inf *inf);
+void inf_startup (struct inf *inf, int pid);
+int inf_update_suspends (struct inf *inf);
+void inf_set_pid (struct inf *inf, pid_t pid);
+void inf_validate_procs (struct inf *inf);
+void inf_steal_exc_ports (struct inf *inf);
+void inf_restore_exc_ports (struct inf *inf);
+struct proc *inf_tid_to_proc (struct inf *inf, int tid);
+void inf_set_threads_resume_sc (struct inf *inf,
+ struct proc *run_thread,
+ int run_others);
+int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
+void inf_suspend (struct inf *inf);
+void inf_resume (struct inf *inf);
+void inf_set_step_thread (struct inf *inf, struct proc *proc);
+void inf_detach (struct inf *inf);
+void inf_attach (struct inf *inf, int pid);
+void inf_signal (struct inf *inf, enum target_signal sig);
+void inf_continue (struct inf *inf);
+
+#define inf_debug(_inf, msg, args...) \
+ do { struct inf *__inf = (_inf); \
+ debug ("{inf %d %p}: " msg, __inf->pid, __inf , ##args); } while (0)
+
+void proc_abort (struct proc *proc, int force);
+struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
+struct proc *_proc_free (struct proc *proc);
+int proc_update_sc (struct proc *proc);
+error_t proc_get_exception_port (struct proc *proc, mach_port_t * port);
+error_t proc_set_exception_port (struct proc *proc, mach_port_t port);
+static mach_port_t _proc_get_exc_port (struct proc *proc);
+void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
+void proc_restore_exc_port (struct proc *proc);
+int proc_trace (struct proc *proc, int set);
+
+/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
+ to INF's msg port and task port respectively. If it has no msg port,
+ EIEIO is returned. INF must refer to a running process! */
+#define INF_MSGPORT_RPC(inf, rpc_expr) \
+ HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \
+ (refport = inf->task->port, 0), 0, \
+ msgport ? (rpc_expr) : EIEIO)
+
+/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure
+ there's someone around to deal with the RPC (and resuspend things
+ afterwards). This effects INF's threads' resume_sc count. */
+#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \
+ (inf_set_threads_resume_sc_for_signal_thread (inf) \
+ ? ({ error_t __e; \
+ inf_resume (inf); \
+ __e = INF_MSGPORT_RPC (inf, rpc_expr); \
+ inf_suspend (inf); \
+ __e; }) \
+ : EIEIO)
+
+
+/* The state passed by an exception message. */
+struct exc_state
+ {
+ int exception; /* The exception code */
+ int code, subcode;
+ mach_port_t handler; /* The real exception port to handle this. */
+ mach_port_t reply; /* The reply port from the exception call. */
+ };
+
+/* The results of the last wait an inf did. */
+struct inf_wait
+ {
+ struct target_waitstatus status; /* The status returned to gdb. */
+ struct exc_state exc; /* The exception that caused us to return. */
+ struct proc *thread; /* The thread in question. */
+ int suppress; /* Something trivial happened. */
+ };
+
+/* The state of an inferior. */
+struct inf
+ {
+ /* Fields describing the current inferior. */
+
+ struct proc *task; /* The mach task. */
+ struct proc *threads; /* A linked list of all threads in TASK. */
+
+ /* True if THREADS needn't be validated by querying the task. We assume that
+ we and the task in question are the only ones frobbing the thread list,
+ so as long as we don't let any code run, we don't have to worry about
+ THREADS changing. */
+ int threads_up_to_date;
+
+ pid_t pid; /* The real system PID. */
+
+ struct inf_wait wait; /* What to return from target_wait. */
+
+ /* One thread proc in INF may be in `single-stepping mode'. This is it. */
+ struct proc *step_thread;
+
+ /* The thread we think is the signal thread. */
+ struct proc *signal_thread;
+
+ mach_port_t event_port; /* Where we receive various msgs. */
+
+ /* True if we think at least one thread in the inferior could currently be
+ running. */
+ unsigned int running:1;
+
+ /* True if the process has stopped (in the proc server sense). Note that
+ since a proc server `stop' leaves the signal thread running, the inf can
+ be RUNNING && STOPPED... */
+ unsigned int stopped:1;
+
+ /* True if the inferior has no message port. */
+ unsigned int nomsg:1;
+
+ /* True if the inferior is traced. */
+ unsigned int traced:1;
+
+ /* True if we shouldn't try waiting for the inferior, usually because we
+ can't for some reason. */
+ unsigned int no_wait:1;
+
+ /* When starting a new inferior, we don't try to validate threads until all
+ the proper execs have been done. This is a count of how many execs we
+ expect to happen. */
+ unsigned pending_execs;
+
+ /* Fields describing global state */
+
+ /* The task suspend count used when gdb has control. This is normally 1 to
+ make things easier for us, but sometimes (like when attaching to vital
+ system servers) it may be desirable to let the task continue to run
+ (pausing individual threads as necessary). */
+ int pause_sc;
+
+ /* The task suspend count left when detaching from a task. */
+ int detach_sc;
+
+ /* The initial values used for the run_sc and pause_sc of newly discovered
+ threads -- see the definition of those fields in struct proc. */
+ int default_thread_run_sc;
+ int default_thread_pause_sc;
+ int default_thread_detach_sc;
+
+ /* True if the process should be traced when started/attached. Newly
+ started processes *must* be traced at first to exec them properly, but
+ if this is false, tracing is turned off as soon it has done so. */
+ int want_signals;
+
+ /* True if exceptions from the inferior process should be trapped. This
+ must be on to use breakpoints. */
+ int want_exceptions;
+ };
+
+
+int
+__proc_pid (struct proc *proc)
+{
+ return proc->inf->pid;
+}
+
+
+/* Update PROC's real suspend count to match it's desired one. Returns true
+ if we think PROC is now in a runnable state. */
+int
+proc_update_sc (struct proc *proc)
+{
+ int running;
+ int err = 0;
+ int delta = proc->sc - proc->cur_sc;
+
+ if (delta)
+ proc_debug (proc, "sc: %d --> %d", proc->cur_sc, proc->sc);
+
+ if (proc->sc == 0 && proc->state_changed)
+ /* Since PROC may start running, we must write back any state changes. */
+ {
+ gdb_assert (proc_is_thread (proc));
+ proc_debug (proc, "storing back changed thread state");
+ err = thread_set_state (proc->port, THREAD_STATE_FLAVOR,
+ (thread_state_t) &proc->state, THREAD_STATE_SIZE);
+ if (!err)
+ proc->state_changed = 0;
+ }
+
+ if (delta > 0)
+ {
+ while (delta-- > 0 && !err)
+ {
+ if (proc_is_task (proc))
+ err = task_suspend (proc->port);
+ else
+ err = thread_suspend (proc->port);
+ }
+ }
+ else
+ {
+ while (delta++ < 0 && !err)
+ {
+ if (proc_is_task (proc))
+ err = task_resume (proc->port);
+ else
+ err = thread_resume (proc->port);
+ }
+ }
+ if (!err)
+ proc->cur_sc = proc->sc;
+
+ /* If we got an error, then the task/thread has disappeared. */
+ running = !err && proc->sc == 0;
+
+ proc_debug (proc, "is %s", err ? "dead" : running ? "running" : "suspended");
+ if (err)
+ proc_debug (proc, "err = %s", safe_strerror (err));
+
+ if (running)
+ {
+ proc->aborted = 0;
+ proc->state_valid = proc->state_changed = 0;
+ proc->fetched_regs = 0;
+ }
+
+ return running;
+}
+
+
+/* Thread_abort is called on PROC if needed. PROC must be a thread proc.
+ If PROC is deemed `precious', then nothing is done unless FORCE is true.
+ In particular, a thread is precious if it's running (in which case forcing
+ it includes suspending it first), or if it has an exception pending. */
+void
+proc_abort (struct proc *proc, int force)
+{
+ gdb_assert (proc_is_thread (proc));
+
+ if (!proc->aborted)
+ {
+ struct inf *inf = proc->inf;
+ int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0);
+
+ if (running && force)
+ {
+ proc->sc = 1;
+ inf_update_suspends (proc->inf);
+ running = 0;
+ warning ("Stopped %s.", proc_string (proc));
+ }
+ else if (proc == inf->wait.thread && inf->wait.exc.reply && !force)
+ /* An exception is pending on PROC, which don't mess with. */
+ running = 1;
+
+ if (!running)
+ /* We only abort the thread if it's not actually running. */
+ {
+ thread_abort (proc->port);
+ proc_debug (proc, "aborted");
+ proc->aborted = 1;
+ }
+ else
+ proc_debug (proc, "not aborting");
+ }
+}
+
+/* Make sure that the state field in PROC is up to date, and return a pointer
+ to it, or 0 if something is wrong. If WILL_MODIFY is true, makes sure
+ that the thread is stopped and aborted first, and sets the state_changed
+ field in PROC to true. */
+thread_state_t
+proc_get_state (struct proc *proc, int will_modify)
+{
+ int was_aborted = proc->aborted;
+
+ proc_debug (proc, "updating state info%s",
+ will_modify ? " (with intention to modify)" : "");
+
+ proc_abort (proc, will_modify);
+
+ if (!was_aborted && proc->aborted)
+ /* PROC's state may have changed since we last fetched it. */
+ proc->state_valid = 0;
+
+ if (!proc->state_valid)
+ {
+ mach_msg_type_number_t state_size = THREAD_STATE_SIZE;
+ error_t err =
+ thread_get_state (proc->port, THREAD_STATE_FLAVOR,
+ (thread_state_t) &proc->state, &state_size);
+ proc_debug (proc, "getting thread state");
+ proc->state_valid = !err;
+ }
+
+ if (proc->state_valid)
+ {
+ if (will_modify)
+ proc->state_changed = 1;
+ return (thread_state_t) &proc->state;
+ }
+ else
+ return 0;
+}
+
+
+/* Set PORT to PROC's exception port. */
+error_t
+proc_get_exception_port (struct proc * proc, mach_port_t * port)
+{
+ if (proc_is_task (proc))
+ return task_get_exception_port (proc->port, port);
+ else
+ return thread_get_exception_port (proc->port, port);
+}
+
+/* Set PROC's exception port to PORT. */
+error_t
+proc_set_exception_port (struct proc * proc, mach_port_t port)
+{
+ proc_debug (proc, "setting exception port: %d", port);
+ if (proc_is_task (proc))
+ return task_set_exception_port (proc->port, port);
+ else
+ return thread_set_exception_port (proc->port, port);
+}
+
+/* Get PROC's exception port, cleaning up a bit if proc has died. */
+static mach_port_t
+_proc_get_exc_port (struct proc *proc)
+{
+ mach_port_t exc_port;
+ error_t err = proc_get_exception_port (proc, &exc_port);
+
+ if (err)
+ /* PROC must be dead. */
+ {
+ if (proc->exc_port)
+ mach_port_deallocate (mach_task_self (), proc->exc_port);
+ proc->exc_port = MACH_PORT_NULL;
+ if (proc->saved_exc_port)
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+ proc->saved_exc_port = MACH_PORT_NULL;
+ }
+
+ return exc_port;
+}
+
+/* Replace PROC's exception port with EXC_PORT, unless it's already been
+ done. Stash away any existing exception port so we can restore it later. */
+void
+proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
+{
+ mach_port_t cur_exc_port = _proc_get_exc_port (proc);
+
+ if (cur_exc_port)
+ {
+ error_t err = 0;
+
+ proc_debug (proc, "inserting exception port: %d", exc_port);
+
+ if (cur_exc_port != exc_port)
+ /* Put in our exception port. */
+ err = proc_set_exception_port (proc, exc_port);
+
+ if (err || cur_exc_port == proc->exc_port)
+ /* We previously set the exception port, and it's still set. So we
+ just keep the old saved port which is what the proc set. */
+ {
+ if (cur_exc_port)
+ mach_port_deallocate (mach_task_self (), cur_exc_port);
+ }
+ else
+ /* Keep a copy of PROC's old exception port so it can be restored. */
+ {
+ if (proc->saved_exc_port)
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+ proc->saved_exc_port = cur_exc_port;
+ }
+
+ proc_debug (proc, "saved exception port: %d", proc->saved_exc_port);
+
+ if (!err)
+ proc->exc_port = exc_port;
+ else
+ warning ("Error setting exception port for %s: %s",
+ proc_string (proc), safe_strerror (err));
+ }
+}
+
+/* If we previously replaced PROC's exception port, put back what we
+ found there at the time, unless *our* exception port has since been
+ overwritten, in which case who knows what's going on. */
+void
+proc_restore_exc_port (struct proc *proc)
+{
+ mach_port_t cur_exc_port = _proc_get_exc_port (proc);
+
+ if (cur_exc_port)
+ {
+ error_t err = 0;
+
+ proc_debug (proc, "restoring real exception port");
+
+ if (proc->exc_port == cur_exc_port)
+ /* Our's is still there. */
+ err = proc_set_exception_port (proc, proc->saved_exc_port);
+
+ if (proc->saved_exc_port)
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+ proc->saved_exc_port = MACH_PORT_NULL;
+
+ if (!err)
+ proc->exc_port = MACH_PORT_NULL;
+ else
+ warning ("Error setting exception port for %s: %s",
+ proc_string (proc), safe_strerror (err));
+ }
+}
+
+
+/* Turns hardware tracing in PROC on or off when SET is true or false,
+ respectively. Returns true on success. */
+int
+proc_trace (struct proc *proc, int set)
+{
+ thread_state_t state = proc_get_state (proc, 1);
+
+ if (!state)
+ return 0; /* the thread must be dead. */
+
+ proc_debug (proc, "tracing %s", set ? "on" : "off");
+
+ if (set)
+ {
+ /* XXX We don't get the exception unless the thread has its own
+ exception port???? */
+ if (proc->exc_port == MACH_PORT_NULL)
+ proc_steal_exc_port (proc, proc->inf->event_port);
+ THREAD_STATE_SET_TRACED (state);
+ }
+ else
+ THREAD_STATE_CLEAR_TRACED (state);
+
+ return 1;
+}
+
+
+/* A variable from which to assign new TIDs. */
+static int next_thread_id = 1;
+
+/* Returns a new proc structure with the given fields. Also adds a
+ notification for PORT becoming dead to be sent to INF's notify port. */
+struct proc *
+make_proc (struct inf *inf, mach_port_t port, int tid)
+{
+ error_t err;
+ mach_port_t prev_port = MACH_PORT_NULL;
+ struct proc *proc = xmalloc (sizeof (struct proc));
+
+ proc->port = port;
+ proc->tid = tid;
+ proc->inf = inf;
+ proc->next = 0;
+ proc->saved_exc_port = MACH_PORT_NULL;
+ proc->exc_port = MACH_PORT_NULL;
+
+ proc->sc = 0;
+ proc->cur_sc = 0;
+
+ /* Note that these are all the values for threads; the task simply uses the
+ corresponding field in INF directly. */
+ proc->run_sc = inf->default_thread_run_sc;
+ proc->pause_sc = inf->default_thread_pause_sc;
+ proc->detach_sc = inf->default_thread_detach_sc;
+ proc->resume_sc = proc->run_sc;
+
+ proc->aborted = 0;
+ proc->dead = 0;
+ proc->state_valid = 0;
+ proc->state_changed = 0;
+
+ proc_debug (proc, "is new");
+
+ /* Get notified when things die. */
+ err =
+ mach_port_request_notification (mach_task_self (), port,
+ MACH_NOTIFY_DEAD_NAME, 1,
+ inf->event_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &prev_port);
+ if (err)
+ warning ("Couldn't request notification for port %d: %s",
+ port, safe_strerror (err));
+ else
+ {
+ proc_debug (proc, "notifications to: %d", inf->event_port);
+ if (prev_port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), prev_port);
+ }
+
+ if (inf->want_exceptions)
+ {
+ if (proc_is_task (proc))
+ /* Make the task exception port point to us. */
+ proc_steal_exc_port (proc, inf->event_port);
+ else
+ /* Just clear thread exception ports -- they default to the
+ task one. */
+ proc_steal_exc_port (proc, MACH_PORT_NULL);
+ }
+
+ return proc;
+}
+
+/* Frees PROC and any resources it uses, and returns the value of PROC's
+ next field. */
+struct proc *
+_proc_free (struct proc *proc)
+{
+ struct inf *inf = proc->inf;
+ struct proc *next = proc->next;
+
+ proc_debug (proc, "freeing...");
+
+ if (proc == inf->step_thread)
+ /* Turn off single stepping. */
+ inf_set_step_thread (inf, 0);
+ if (proc == inf->wait.thread)
+ inf_clear_wait (inf);
+ if (proc == inf->signal_thread)
+ inf->signal_thread = 0;
+
+ if (proc->port != MACH_PORT_NULL)
+ {
+ if (proc->exc_port != MACH_PORT_NULL)
+ /* Restore the original exception port. */
+ proc_restore_exc_port (proc);
+ if (proc->cur_sc != 0)
+ /* Resume the thread/task. */
+ {
+ proc->sc = 0;
+ proc_update_sc (proc);
+ }
+ mach_port_deallocate (mach_task_self (), proc->port);
+ }
+
+ xfree (proc);
+ return next;
+}
+
+
+struct inf *
+make_inf (void)
+{
+ struct inf *inf = xmalloc (sizeof (struct inf));
+
+ inf->task = 0;
+ inf->threads = 0;
+ inf->threads_up_to_date = 0;
+ inf->pid = 0;
+ inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+ inf->wait.thread = 0;
+ inf->wait.exc.handler = MACH_PORT_NULL;
+ inf->wait.exc.reply = MACH_PORT_NULL;
+ inf->step_thread = 0;
+ inf->signal_thread = 0;
+ inf->event_port = MACH_PORT_NULL;
+ inf->running = 0;
+ inf->stopped = 0;
+ inf->nomsg = 1;
+ inf->traced = 0;
+ inf->no_wait = 0;
+ inf->pending_execs = 0;
+ inf->pause_sc = 1;
+ inf->detach_sc = 0;
+ inf->default_thread_run_sc = 0;
+ inf->default_thread_pause_sc = 0;
+ inf->default_thread_detach_sc = 0;
+ inf->want_signals = 1; /* By default */
+ inf->want_exceptions = 1; /* By default */
+
+ return inf;
+}
+
+/* Clear INF's target wait status. */
+void
+inf_clear_wait (struct inf *inf)
+{
+ inf_debug (inf, "clearing wait");
+ inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+ inf->wait.thread = 0;
+ inf->wait.suppress = 0;
+ if (inf->wait.exc.handler != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (), inf->wait.exc.handler);
+ inf->wait.exc.handler = MACH_PORT_NULL;
+ }
+ if (inf->wait.exc.reply != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (), inf->wait.exc.reply);
+ inf->wait.exc.reply = MACH_PORT_NULL;
+ }
+}
+
+
+void
+inf_cleanup (struct inf *inf)
+{
+ inf_debug (inf, "cleanup");
+
+ inf_clear_wait (inf);
+
+ inf_set_pid (inf, -1);
+ inf->pid = 0;
+ inf->running = 0;
+ inf->stopped = 0;
+ inf->nomsg = 1;
+ inf->traced = 0;
+ inf->no_wait = 0;
+ inf->pending_execs = 0;
+
+ if (inf->event_port)
+ {
+ mach_port_destroy (mach_task_self (), inf->event_port);
+ inf->event_port = MACH_PORT_NULL;
+ }
+}
+
+void
+inf_startup (struct inf *inf, int pid)
+{
+ error_t err;
+
+ inf_debug (inf, "startup: pid = %d", pid);
+
+ inf_cleanup (inf);
+
+ /* Make the port on which we receive all events. */
+ err = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE, &inf->event_port);
+ if (err)
+ error ("Error allocating event port: %s", safe_strerror (err));
+
+ /* Make a send right for it, so we can easily copy it for other people. */
+ mach_port_insert_right (mach_task_self (), inf->event_port,
+ inf->event_port, MACH_MSG_TYPE_MAKE_SEND);
+ inf_set_pid (inf, pid);
+}
+
+
+/* Close current process, if any, and attach INF to process PORT. */
+void
+inf_set_pid (struct inf *inf, pid_t pid)
+{
+ task_t task_port;
+ struct proc *task = inf->task;
+
+ inf_debug (inf, "setting pid: %d", pid);
+
+ if (pid < 0)
+ task_port = MACH_PORT_NULL;
+ else
+ {
+ error_t err = proc_pid2task (proc_server, pid, &task_port);
+ if (err)
+ error ("Error getting task for pid %d: %s", pid, safe_strerror (err));
+ }
+
+ inf_debug (inf, "setting task: %d", task_port);
+
+ if (inf->pause_sc)
+ task_suspend (task_port);
+
+ if (task && task->port != task_port)
+ {
+ inf->task = 0;
+ inf_validate_procs (inf); /* Trash all the threads. */
+ _proc_free (task); /* And the task. */
+ }
+
+ if (task_port != MACH_PORT_NULL)
+ {
+ inf->task = make_proc (inf, task_port, PROC_TID_TASK);
+ inf->threads_up_to_date = 0;
+ }
+
+ if (inf->task)
+ {
+ inf->pid = pid;
+ if (inf->pause_sc)
+ /* Reflect task_suspend above. */
+ inf->task->sc = inf->task->cur_sc = 1;
+ }
+ else
+ inf->pid = -1;
+}
+
+
+/* Validates INF's stopped, nomsg and traced field from the actual
+ proc server state. Note that the traced field is only updated from
+ the proc server state if we do not have a message port. If we do
+ have a message port we'd better look at the tracemask itself. */
+static void
+inf_validate_procinfo (struct inf *inf)
+{
+ char *noise;
+ mach_msg_type_number_t noise_len = 0;
+ struct procinfo *pi;
+ mach_msg_type_number_t pi_len = 0;
+ int info_flags = 0;
+ error_t err =
+ proc_getprocinfo (proc_server, inf->pid, &info_flags,
+ (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
+
+ if (!err)
+ {
+ inf->stopped = !!(pi->state & PI_STOPPED);
+ inf->nomsg = !!(pi->state & PI_NOMSG);
+ if (inf->nomsg)
+ inf->traced = !!(pi->state & PI_TRACED);
+ vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+ if (noise_len > 0)
+ vm_deallocate (mach_task_self (), (vm_address_t) noise, noise_len);
+ }
+}
+
+/* Validates INF's task suspend count. If it's higher than we expect,
+ verify with the user before `stealing' the extra count. */
+static void
+inf_validate_task_sc (struct inf *inf)
+{
+ char *noise;
+ mach_msg_type_number_t noise_len = 0;
+ struct procinfo *pi;
+ mach_msg_type_number_t pi_len = 0;
+ int info_flags = PI_FETCH_TASKINFO;
+ int suspend_count = -1;
+ error_t err;
+
+ retry:
+ err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
+ (procinfo_t *) &pi, &pi_len, &noise, &noise_len);
+ if (err)
+ {
+ inf->task->dead = 1; /* oh well */
+ return;
+ }
+
+ if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1)
+ {
+ /* The proc server might have suspended the task while stopping
+ it. This happens when the task is handling a traced signal.
+ Refetch the suspend count. The proc server should be
+ finished stopping the task by now. */
+ suspend_count = pi->taskinfo.suspend_count;
+ goto retry;
+ }
+
+ suspend_count = pi->taskinfo.suspend_count;
+
+ vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+ if (noise_len > 0)
+ vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+
+ if (inf->task->cur_sc < suspend_count)
+ {
+ int abort;
+
+ target_terminal_ours (); /* Allow I/O. */
+ abort = !query ("Pid %d has an additional task suspend count of %d;"
+ " clear it? ", inf->pid,
+ suspend_count - inf->task->cur_sc);
+ target_terminal_inferior (); /* Give it back to the child. */
+
+ if (abort)
+ error ("Additional task suspend count left untouched.");
+
+ inf->task->cur_sc = suspend_count;
+ }
+}
+
+/* Turns tracing for INF on or off, depending on ON, unless it already
+ is. If INF is running, the resume_sc count of INF's threads will
+ be modified, and the signal thread will briefly be run to change
+ the trace state. */
+void
+inf_set_traced (struct inf *inf, int on)
+{
+ if (on == inf->traced)
+ return;
+
+ if (inf->task && !inf->task->dead)
+ /* Make it take effect immediately. */
+ {
+ sigset_t mask = on ? ~(sigset_t) 0 : 0;
+ error_t err =
+ INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
+ INIT_TRACEMASK, mask));
+ if (err == EIEIO)
+ {
+ if (on)
+ warning ("Can't modify tracing state for pid %d: %s",
+ inf->pid, "No signal thread");
+ inf->traced = on;
+ }
+ else if (err)
+ warning ("Can't modify tracing state for pid %d: %s",
+ inf->pid, safe_strerror (err));
+ else
+ inf->traced = on;
+ }
+ else
+ inf->traced = on;
+}
+
+
+/* Makes all the real suspend count deltas of all the procs in INF
+ match the desired values. Careful to always do thread/task suspend
+ counts in the safe order. Returns true if at least one thread is
+ thought to be running. */
+int
+inf_update_suspends (struct inf *inf)
+{
+ struct proc *task = inf->task;
+ /* We don't have to update INF->threads even though we're iterating over it
+ because we'll change a thread only if it already has an existing proc
+ entry. */
+
+ inf_debug (inf, "updating suspend counts");
+
+ if (task)
+ {
+ struct proc *thread;
+ int task_running = (task->sc == 0), thread_running = 0;
+
+ if (task->sc > task->cur_sc)
+ /* The task is becoming _more_ suspended; do before any threads. */
+ task_running = proc_update_sc (task);
+
+ if (inf->pending_execs)
+ /* When we're waiting for an exec, things may be happening behind our
+ back, so be conservative. */
+ thread_running = 1;
+
+ /* Do all the thread suspend counts. */
+ for (thread = inf->threads; thread; thread = thread->next)
+ thread_running |= proc_update_sc (thread);
+
+ if (task->sc != task->cur_sc)
+ /* We didn't do the task first, because we wanted to wait for the
+ threads; do it now. */
+ task_running = proc_update_sc (task);
+
+ inf_debug (inf, "%srunning...",
+ (thread_running && task_running) ? "" : "not ");
+
+ inf->running = thread_running && task_running;
+
+ /* Once any thread has executed some code, we can't depend on the
+ threads list any more. */
+ if (inf->running)
+ inf->threads_up_to_date = 0;
+
+ return inf->running;
+ }
+
+ return 0;
+}
+
+
+/* Converts a GDB pid to a struct proc. */
+struct proc *
+inf_tid_to_thread (struct inf *inf, int tid)
+{
+ struct proc *thread = inf->threads;
+
+ while (thread)
+ if (thread->tid == tid)
+ return thread;
+ else
+ thread = thread->next;
+ return 0;
+}
+
+/* Converts a thread port to a struct proc. */
+struct proc *
+inf_port_to_thread (struct inf *inf, mach_port_t port)
+{
+ struct proc *thread = inf->threads;
+ while (thread)
+ if (thread->port == port)
+ return thread;
+ else
+ thread = thread->next;
+ return 0;
+}
+
+
+/* Make INF's list of threads be consistent with reality of TASK. */
+void
+inf_validate_procs (struct inf *inf)
+{
+ thread_array_t threads;
+ mach_msg_type_number_t num_threads, i;
+ struct proc *task = inf->task;
+
+ /* If no threads are currently running, this function will guarantee that
+ things are up to date. The exception is if there are zero threads --
+ then it is almost certainly in an odd state, and probably some outside
+ agent will create threads. */
+ inf->threads_up_to_date = inf->threads ? !inf->running : 0;
+
+ if (task)
+ {
+ error_t err = task_threads (task->port, &threads, &num_threads);
+ inf_debug (inf, "fetching threads");
+ if (err)
+ /* TASK must be dead. */
+ {
+ task->dead = 1;
+ task = 0;
+ }
+ }
+
+ if (!task)
+ {
+ num_threads = 0;
+ inf_debug (inf, "no task");
+ }
+
+ {
+ /* Make things normally linear. */
+ mach_msg_type_number_t search_start = 0;
+ /* Which thread in PROCS corresponds to each task thread, & the task. */
+ struct proc *matched[num_threads + 1];
+ /* The last thread in INF->threads, so we can add to the end. */
+ struct proc *last = 0;
+ /* The current thread we're considering. */
+ struct proc *thread = inf->threads;
+
+ memset (matched, 0, sizeof (matched));
+
+ while (thread)
+ {
+ mach_msg_type_number_t left;
+
+ for (i = search_start, left = num_threads; left; i++, left--)
+ {
+ if (i >= num_threads)
+ i -= num_threads; /* I wrapped around. */
+ if (thread->port == threads[i])
+ /* We already know about this thread. */
+ {
+ matched[i] = thread;
+ last = thread;
+ thread = thread->next;
+ search_start++;
+ break;
+ }
+ }
+
+ if (!left)
+ {
+ proc_debug (thread, "died!");
+ thread->port = MACH_PORT_NULL;
+ thread = _proc_free (thread); /* THREAD is dead. */
+ (last ? last->next : inf->threads) = thread;
+ }
+ }
+
+ for (i = 0; i < num_threads; i++)
+ {
+ if (matched[i])
+ /* Throw away the duplicate send right. */
+ mach_port_deallocate (mach_task_self (), threads[i]);
+ else
+ /* THREADS[I] is a thread we don't know about yet! */
+ {
+ thread = make_proc (inf, threads[i], next_thread_id++);
+ (last ? last->next : inf->threads) = thread;
+ last = thread;
+ proc_debug (thread, "new thread: %d", threads[i]);
+ add_thread (pid_to_ptid (thread->tid)); /* Tell GDB's generic thread code. */
+ }
+ }
+
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) threads, (num_threads * sizeof (thread_t)));
+ }
+}
+
+
+/* Makes sure that INF's thread list is synced with the actual process. */
+int
+inf_update_procs (struct inf *inf)
+{
+ if (!inf->task)
+ return 0;
+ if (!inf->threads_up_to_date)
+ inf_validate_procs (inf);
+ return !!inf->task;
+}
+
+/* Sets the resume_sc of each thread in inf. That of RUN_THREAD is set to 0,
+ and others are set to their run_sc if RUN_OTHERS is true, and otherwise
+ their pause_sc. */
+void
+inf_set_threads_resume_sc (struct inf *inf,
+ struct proc *run_thread, int run_others)
+{
+ struct proc *thread;
+ inf_update_procs (inf);
+ for (thread = inf->threads; thread; thread = thread->next)
+ if (thread == run_thread)
+ thread->resume_sc = 0;
+ else if (run_others)
+ thread->resume_sc = thread->run_sc;
+ else
+ thread->resume_sc = thread->pause_sc;
+}
+
+
+/* Cause INF to continue execution immediately; individual threads may still
+ be suspended (but their suspend counts will be updated). */
+void
+inf_resume (struct inf *inf)
+{
+ struct proc *thread;
+
+ inf_update_procs (inf);
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ thread->sc = thread->resume_sc;
+
+ if (inf->task)
+ {
+ if (!inf->pending_execs)
+ /* Try to make sure our task count is correct -- in the case where
+ we're waiting for an exec though, things are too volatile, so just
+ assume things will be reasonable (which they usually will be). */
+ inf_validate_task_sc (inf);
+ inf->task->sc = 0;
+ }
+
+ inf_update_suspends (inf);
+}
+
+/* Cause INF to stop execution immediately; individual threads may still
+ be running. */
+void
+inf_suspend (struct inf *inf)
+{
+ struct proc *thread;
+
+ inf_update_procs (inf);
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ thread->sc = thread->pause_sc;
+
+ if (inf->task)
+ inf->task->sc = inf->pause_sc;
+
+ inf_update_suspends (inf);
+}
+
+
+/* INF has one thread PROC that is in single-stepping mode. This
+ function changes it to be PROC, changing any old step_thread to be
+ a normal one. A PROC of 0 clears any existing value. */
+void
+inf_set_step_thread (struct inf *inf, struct proc *thread)
+{
+ gdb_assert (!thread || proc_is_thread (thread));
+
+ if (thread)
+ inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid);
+ else
+ inf_debug (inf, "clearing step thread");
+
+ if (inf->step_thread != thread)
+ {
+ if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL)
+ if (!proc_trace (inf->step_thread, 0))
+ return;
+ if (thread && proc_trace (thread, 1))
+ inf->step_thread = thread;
+ else
+ inf->step_thread = 0;
+ }
+}
+
+
+/* Set up the thread resume_sc's so that only the signal thread is running
+ (plus whatever other thread are set to always run). Returns true if we
+ did so, or false if we can't find a signal thread. */
+int
+inf_set_threads_resume_sc_for_signal_thread (struct inf *inf)
+{
+ if (inf->signal_thread)
+ {
+ inf_set_threads_resume_sc (inf, inf->signal_thread, 0);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static void
+inf_update_signal_thread (struct inf *inf)
+{
+ /* XXX for now we assume that if there's a msgport, the 2nd thread is
+ the signal thread. */
+ inf->signal_thread = inf->threads ? inf->threads->next : 0;
+}
+
+
+/* Detachs from INF's inferior task, letting it run once again... */
+void
+inf_detach (struct inf *inf)
+{
+ struct proc *task = inf->task;
+
+ inf_debug (inf, "detaching...");
+
+ inf_clear_wait (inf);
+ inf_set_step_thread (inf, 0);
+
+ if (task)
+ {
+ struct proc *thread;
+
+ inf_validate_procinfo (inf);
+
+ inf_set_traced (inf, 0);
+ if (inf->stopped)
+ {
+ if (inf->nomsg)
+ inf_continue (inf);
+ else
+ inf_signal (inf, TARGET_SIGNAL_0);
+ }
+
+ proc_restore_exc_port (task);
+ task->sc = inf->detach_sc;
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ {
+ proc_restore_exc_port (thread);
+ thread->sc = thread->detach_sc;
+ }
+
+ inf_update_suspends (inf);
+ }
+
+ inf_cleanup (inf);
+}
+
+/* Attaches INF to the process with process id PID, returning it in a
+ suspended state suitable for debugging. */
+void
+inf_attach (struct inf *inf, int pid)
+{
+ inf_debug (inf, "attaching: %d", pid);
+
+ if (inf->pid)
+ inf_detach (inf);
+
+ inf_startup (inf, pid);
+}
+
+
+/* Makes sure that we've got our exception ports entrenched in the process. */
+void
+inf_steal_exc_ports (struct inf *inf)
+{
+ struct proc *thread;
+
+ inf_debug (inf, "stealing exception ports");
+
+ inf_set_step_thread (inf, 0); /* The step thread is special. */
+
+ proc_steal_exc_port (inf->task, inf->event_port);
+ for (thread = inf->threads; thread; thread = thread->next)
+ proc_steal_exc_port (thread, MACH_PORT_NULL);
+}
+
+/* Makes sure the process has its own exception ports. */
+void
+inf_restore_exc_ports (struct inf *inf)
+{
+ struct proc *thread;
+
+ inf_debug (inf, "restoring exception ports");
+
+ inf_set_step_thread (inf, 0); /* The step thread is special. */
+
+ proc_restore_exc_port (inf->task);
+ for (thread = inf->threads; thread; thread = thread->next)
+ proc_restore_exc_port (thread);
+}
+
+
+/* Deliver signal SIG to INF. If INF is stopped, delivering a signal, even
+ signal 0, will continue it. INF is assumed to be in a paused state, and
+ the resume_sc's of INF's threads may be affected. */
+void
+inf_signal (struct inf *inf, enum target_signal sig)
+{
+ error_t err = 0;
+ int host_sig = target_signal_to_host (sig);
+
+#define NAME target_signal_to_name (sig)
+
+ if (host_sig >= _NSIG)
+ /* A mach exception. Exceptions are encoded in the signal space by
+ putting them after _NSIG; this assumes they're positive (and not
+ extremely large)! */
+ {
+ struct inf_wait *w = &inf->wait;
+ if (w->status.kind == TARGET_WAITKIND_STOPPED
+ && w->status.value.sig == sig
+ && w->thread && !w->thread->aborted)
+ /* We're passing through the last exception we received. This is
+ kind of bogus, because exceptions are per-thread whereas gdb
+ treats signals as per-process. We just forward the exception to
+ the correct handler, even it's not for the same thread as TID --
+ i.e., we pretend it's global. */
+ {
+ struct exc_state *e = &w->exc;
+ inf_debug (inf, "passing through exception:"
+ " task = %d, thread = %d, exc = %d"
+ ", code = %d, subcode = %d",
+ w->thread->port, inf->task->port,
+ e->exception, e->code, e->subcode);
+ err =
+ exception_raise_request (e->handler,
+ e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE,
+ w->thread->port, inf->task->port,
+ e->exception, e->code, e->subcode);
+ }
+ else
+ error ("Can't forward spontaneous exception (%s).", NAME);
+ }
+ else
+ /* A Unix signal. */
+ if (inf->stopped)
+ /* The process is stopped and expecting a signal. Just send off a
+ request and let it get handled when we resume everything. */
+ {
+ inf_debug (inf, "sending %s to stopped process", NAME);
+ err =
+ INF_MSGPORT_RPC (inf,
+ msg_sig_post_untraced_request (msgport,
+ inf->event_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ host_sig, 0,
+ refport));
+ if (!err)
+ /* Posting an untraced signal automatically continues it.
+ We clear this here rather than when we get the reply
+ because we'd rather assume it's not stopped when it
+ actually is, than the reverse. */
+ inf->stopped = 0;
+ }
+ else
+ /* It's not expecting it. We have to let just the signal thread
+ run, and wait for it to get into a reasonable state before we
+ can continue the rest of the process. When we finally resume the
+ process the signal we request will be the very first thing that
+ happens. */
+ {
+ inf_debug (inf, "sending %s to unstopped process"
+ " (so resuming signal thread)", NAME);
+ err =
+ INF_RESUME_MSGPORT_RPC (inf,
+ msg_sig_post_untraced (msgport, host_sig,
+ 0, refport));
+ }
+
+ if (err == EIEIO)
+ /* Can't do too much... */
+ warning ("Can't deliver signal %s: No signal thread.", NAME);
+ else if (err)
+ warning ("Delivering signal %s: %s", NAME, safe_strerror (err));
+
+#undef NAME
+}
+
+
+/* Continue INF without delivering a signal. This is meant to be used
+ when INF does not have a message port. */
+void
+inf_continue (struct inf *inf)
+{
+ process_t proc;
+ error_t err = proc_pid2proc (proc_server, inf->pid, &proc);
+
+ if (!err)
+ {
+ inf_debug (inf, "continuing process");
+
+ err = proc_mark_cont (proc);
+ if (!err)
+ {
+ struct proc *thread;
+
+ for (thread = inf->threads; thread; thread = thread->next)
+ thread_resume (thread->port);
+
+ inf->stopped = 0;
+ }
+ }
+
+ if (err)
+ warning ("Can't continue process: %s", safe_strerror (err));
+}
+
+
+/* The inferior used for all gdb target ops. */
+struct inf *current_inferior = 0;
+
+/* The inferior being waited for by gnu_wait. Since GDB is decidely not
+ multi-threaded, we don't bother to lock this. */
+struct inf *waiting_inf;
+
+/* Wait for something to happen in the inferior, returning what in STATUS. */
+static ptid_t
+gnu_wait (ptid_t tid, struct target_waitstatus *status)
+{
+ struct msg
+ {
+ mach_msg_header_t hdr;
+ mach_msg_type_t type;
+ int data[8000];
+ } msg;
+ error_t err;
+ struct proc *thread;
+ struct inf *inf = current_inferior;
+
+ extern int exc_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ gdb_assert (inf->task);
+
+ if (!inf->threads && !inf->pending_execs)
+ /* No threads! Assume that maybe some outside agency is frobbing our
+ task, and really look for new threads. If we can't find any, just tell
+ the user to try again later. */
+ {
+ inf_validate_procs (inf);
+ if (!inf->threads && !inf->task->dead)
+ error ("There are no threads; try again later.");
+ }
+
+ waiting_inf = inf;
+
+ inf_debug (inf, "waiting for: %d", PIDGET (tid));
+
+rewait:
+ if (proc_wait_pid != inf->pid && !inf->no_wait)
+ /* Always get information on events from the proc server. */
+ {
+ inf_debug (inf, "requesting wait on pid %d", inf->pid);
+
+ if (proc_wait_pid)
+ /* The proc server is single-threaded, and only allows a single
+ outstanding wait request, so we have to cancel the previous one. */
+ {
+ inf_debug (inf, "cancelling previous wait on pid %d", proc_wait_pid);
+ interrupt_operation (proc_server, 0);
+ }
+
+ err =
+ proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
+ if (err)
+ warning ("wait request failed: %s", safe_strerror (err));
+ else
+ {
+ inf_debug (inf, "waits pending: %d", proc_waits_pending);
+ proc_wait_pid = inf->pid;
+ /* Even if proc_waits_pending was > 0 before, we still won't
+ get any other replies, because it was either from a
+ different INF, or a different process attached to INF --
+ and the event port, which is the wait reply port, changes
+ when you switch processes. */
+ proc_waits_pending = 1;
+ }
+ }
+
+ inf_clear_wait (inf);
+
+ /* What can happen? (1) Dead name notification; (2) Exceptions arrive;
+ (3) wait reply from the proc server. */
+
+ inf_debug (inf, "waiting for an event...");
+ err = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
+ 0, sizeof (struct msg), inf->event_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+ /* Re-suspend the task. */
+ inf_suspend (inf);
+
+ if (!inf->task && inf->pending_execs)
+ /* When doing an exec, it's possible that the old task wasn't reused
+ (e.g., setuid execs). So if the task seems to have disappeared,
+ attempt to refetch it, as the pid should still be the same. */
+ inf_set_pid (inf, inf->pid);
+
+ if (err == EMACH_RCV_INTERRUPTED)
+ inf_debug (inf, "interrupted");
+ else if (err)
+ error ("Couldn't wait for an event: %s", safe_strerror (err));
+ else
+ {
+ struct
+ {
+ mach_msg_header_t hdr;
+ mach_msg_type_t err_type;
+ kern_return_t err;
+ char noise[200];
+ }
+ reply;
+
+ inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id);
+
+ /* Handle what we got. */
+ if (!notify_server (&msg.hdr, &reply.hdr)
+ && !exc_server (&msg.hdr, &reply.hdr)
+ && !process_reply_server (&msg.hdr, &reply.hdr)
+ && !msg_reply_server (&msg.hdr, &reply.hdr))
+ /* Whatever it is, it's something strange. */
+ error ("Got a strange event, msg id = %d.", msg.hdr.msgh_id);
+
+ if (reply.err)
+ error ("Handling event, msgid = %d: %s",
+ msg.hdr.msgh_id, safe_strerror (reply.err));
+ }
+
+ if (inf->pending_execs)
+ /* We're waiting for the inferior to finish execing. */
+ {
+ struct inf_wait *w = &inf->wait;
+ enum target_waitkind kind = w->status.kind;
+
+ if (kind == TARGET_WAITKIND_SPURIOUS)
+ /* Since gdb is actually counting the number of times the inferior
+ stops, expecting one stop per exec, we only return major events
+ while execing. */
+ {
+ w->suppress = 1;
+ inf_debug (inf, "pending_execs = %d, ignoring minor event",
+ inf->pending_execs);
+ }
+ else if (kind == TARGET_WAITKIND_STOPPED
+ && w->status.value.sig == TARGET_SIGNAL_TRAP)
+ /* Ah hah! A SIGTRAP from the inferior while starting up probably
+ means we've succesfully completed an exec! */
+ {
+ if (--inf->pending_execs == 0)
+ /* We're done! */
+ {
+#if 0 /* do we need this? */
+ prune_threads (1); /* Get rid of the old shell threads */
+ renumber_threads (0); /* Give our threads reasonable names. */
+#endif
+ }
+ inf_debug (inf, "pending exec completed, pending_execs => %d",
+ inf->pending_execs);
+ }
+ else if (kind == TARGET_WAITKIND_STOPPED)
+ /* It's possible that this signal is because of a crashed process
+ being handled by the hurd crash server; in this case, the process
+ will have an extra task suspend, which we need to know about.
+ Since the code in inf_resume that normally checks for this is
+ disabled while INF->pending_execs, we do the check here instead. */
+ inf_validate_task_sc (inf);
+ }
+
+ if (inf->wait.suppress)
+ /* Some totally spurious event happened that we don't consider
+ worth returning to gdb. Just keep waiting. */
+ {
+ inf_debug (inf, "suppressing return, rewaiting...");
+ inf_resume (inf);
+ goto rewait;
+ }
+
+ /* Pass back out our results. */
+ bcopy (&inf->wait.status, status, sizeof (*status));
+
+ thread = inf->wait.thread;
+ if (thread)
+ tid = pid_to_ptid (thread->tid);
+ else
+ thread = inf_tid_to_thread (inf, PIDGET (tid));
+
+ if (!thread || thread->port == MACH_PORT_NULL)
+ {
+ /* TID is dead; try and find a new thread. */
+ if (inf_update_procs (inf) && inf->threads)
+ tid = pid_to_ptid (inf->threads->tid); /* The first available thread. */
+ else
+ tid = inferior_ptid; /* let wait_for_inferior handle exit case */
+ }
+
+ if (thread && PIDGET (tid) >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS
+ && inf->pause_sc == 0 && thread->pause_sc == 0)
+ /* If something actually happened to THREAD, make sure we
+ suspend it. */
+ {
+ thread->sc = 1;
+ inf_update_suspends (inf);
+ }
+
+ inf_debug (inf, "returning tid = %d, status = %s (%d)", PIDGET (tid),
+ status->kind == TARGET_WAITKIND_EXITED ? "EXITED"
+ : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED"
+ : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED"
+ : status->kind == TARGET_WAITKIND_LOADED ? "LOADED"
+ : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS"
+ : "?",
+ status->value.integer);
+
+ return tid;
+}
+
+
+/* The rpc handler called by exc_server. */
+error_t
+S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
+ thread_t thread_port, task_t task_port,
+ int exception, int code, int subcode)
+{
+ struct inf *inf = waiting_inf;
+ struct proc *thread = inf_port_to_thread (inf, thread_port);
+
+ inf_debug (waiting_inf,
+ "thread = %d, task = %d, exc = %d, code = %d, subcode = %d",
+ thread_port, task_port, exception, code, subcode);
+
+ if (!thread)
+ /* We don't know about thread? */
+ {
+ inf_update_procs (inf);
+ thread = inf_port_to_thread (inf, thread_port);
+ if (!thread)
+ /* Give up, the generating thread is gone. */
+ return 0;
+ }
+
+ mach_port_deallocate (mach_task_self (), thread_port);
+ mach_port_deallocate (mach_task_self (), task_port);
+
+ if (!thread->aborted)
+ /* THREAD hasn't been aborted since this exception happened (abortion
+ clears any exception state), so it must be real. */
+ {
+ /* Store away the details; this will destroy any previous info. */
+ inf->wait.thread = thread;
+
+ inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
+
+ if (exception == EXC_BREAKPOINT)
+ /* GDB likes to get SIGTRAP for breakpoints. */
+ {
+ inf->wait.status.value.sig = TARGET_SIGNAL_TRAP;
+ mach_port_deallocate (mach_task_self (), reply_port);
+ }
+ else
+ /* Record the exception so that we can forward it later. */
+ {
+ if (thread->exc_port == port)
+ {
+ inf_debug (waiting_inf, "Handler is thread exception port <%d>",
+ thread->saved_exc_port);
+ inf->wait.exc.handler = thread->saved_exc_port;
+ }
+ else
+ {
+ inf_debug (waiting_inf, "Handler is task exception port <%d>",
+ inf->task->saved_exc_port);
+ inf->wait.exc.handler = inf->task->saved_exc_port;
+ gdb_assert (inf->task->exc_port == port);
+ }
+ if (inf->wait.exc.handler != MACH_PORT_NULL)
+ /* Add a reference to the exception handler. */
+ mach_port_mod_refs (mach_task_self (),
+ inf->wait.exc.handler, MACH_PORT_RIGHT_SEND,
+ 1);
+
+ inf->wait.exc.exception = exception;
+ inf->wait.exc.code = code;
+ inf->wait.exc.subcode = subcode;
+ inf->wait.exc.reply = reply_port;
+
+ /* Exceptions are encoded in the signal space by putting them after
+ _NSIG; this assumes they're positive (and not extremely large)! */
+ inf->wait.status.value.sig =
+ target_signal_from_host (_NSIG + exception);
+ }
+ }
+ else
+ /* A supppressed exception, which ignore. */
+ {
+ inf->wait.suppress = 1;
+ mach_port_deallocate (mach_task_self (), reply_port);
+ }
+
+ return 0;
+}
+
+
+/* Fill in INF's wait field after a task has died without giving us more
+ detailed information. */
+void
+inf_task_died_status (struct inf *inf)
+{
+ warning ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid);
+ inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED;
+ inf->wait.status.value.sig = TARGET_SIGNAL_KILL;
+}
+
+/* Notify server routines. The only real one is dead name notification. */
+error_t
+do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port)
+{
+ struct inf *inf = waiting_inf;
+
+ inf_debug (waiting_inf, "port = %d", dead_port);
+
+ if (inf->task && inf->task->port == dead_port)
+ {
+ proc_debug (inf->task, "is dead");
+ inf->task->port = MACH_PORT_NULL;
+ if (proc_wait_pid == inf->pid)
+ /* We have a wait outstanding on the process, which will return more
+ detailed information, so delay until we get that. */
+ inf->wait.suppress = 1;
+ else
+ /* We never waited for the process (maybe it wasn't a child), so just
+ pretend it got a SIGKILL. */
+ inf_task_died_status (inf);
+ }
+ else
+ {
+ struct proc *thread = inf_port_to_thread (inf, dead_port);
+ if (thread)
+ {
+ proc_debug (thread, "is dead");
+ thread->port = MACH_PORT_NULL;
+ }
+
+ if (inf->task->dead)
+ /* Since the task is dead, its threads are dying with it. */
+ inf->wait.suppress = 1;
+ }
+
+ mach_port_deallocate (mach_task_self (), dead_port);
+ inf->threads_up_to_date = 0; /* Just in case */
+
+ return 0;
+}
+
+
+static error_t
+ill_rpc (char *fun)
+{
+ warning ("illegal rpc: %s", fun);
+ return 0;
+}
+
+error_t
+do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count)
+{
+ return ill_rpc ("do_mach_notify_no_senders");
+}
+
+error_t
+do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_port_deleted");
+}
+
+error_t
+do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_msg_accepted");
+}
+
+error_t
+do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name)
+{
+ return ill_rpc ("do_mach_notify_port_destroyed");
+}
+
+error_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return ill_rpc ("do_mach_notify_send_once");
+}
+
+
+/* Process_reply server routines. We only use process_wait_reply. */
+
+error_t
+S_proc_wait_reply (mach_port_t reply, error_t err,
+ int status, int sigcode, rusage_t rusage, pid_t pid)
+{
+ struct inf *inf = waiting_inf;
+
+ inf_debug (inf, "err = %s, pid = %d, status = 0x%x, sigcode = %d",
+ err ? safe_strerror (err) : "0", pid, status, sigcode);
+
+ if (err && proc_wait_pid && (!inf->task || !inf->task->port))
+ /* Ack. The task has died, but the task-died notification code didn't
+ tell anyone because it thought a more detailed reply from the
+ procserver was forthcoming. However, we now learn that won't
+ happen... So we have to act like the task just died, and this time,
+ tell the world. */
+ inf_task_died_status (inf);
+
+ if (--proc_waits_pending == 0)
+ /* PROC_WAIT_PID represents the most recent wait. We will always get
+ replies in order because the proc server is single threaded. */
+ proc_wait_pid = 0;
+
+ inf_debug (inf, "waits pending now: %d", proc_waits_pending);
+
+ if (err)
+ {
+ if (err != EINTR)
+ {
+ warning ("Can't wait for pid %d: %s", inf->pid, safe_strerror (err));
+ inf->no_wait = 1;
+
+ /* Since we can't see the inferior's signals, don't trap them. */
+ inf_set_traced (inf, 0);
+ }
+ }
+ else if (pid == inf->pid)
+ {
+ store_waitstatus (&inf->wait.status, status);
+ if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED)
+ /* The process has sent us a signal, and stopped itself in a sane
+ state pending our actions. */
+ {
+ inf_debug (inf, "process has stopped itself");
+ inf->stopped = 1;
+ }
+ }
+ else
+ inf->wait.suppress = 1; /* Something odd happened. Ignore. */
+
+ return 0;
+}
+
+error_t
+S_proc_setmsgport_reply (mach_port_t reply, error_t err,
+ mach_port_t old_msg_port)
+{
+ return ill_rpc ("S_proc_setmsgport_reply");
+}
+
+error_t
+S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port)
+{
+ return ill_rpc ("S_proc_getmsgport_reply");
+}
+
+
+/* Msg_reply server routines. We only use msg_sig_post_untraced_reply. */
+
+error_t
+S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err)
+{
+ struct inf *inf = waiting_inf;
+
+ if (err == EBUSY)
+ /* EBUSY is what we get when the crash server has grabbed control of the
+ process and doesn't like what signal we tried to send it. Just act
+ like the process stopped (using a signal of 0 should mean that the
+ *next* time the user continues, it will pass signal 0, which the crash
+ server should like). */
+ {
+ inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
+ inf->wait.status.value.sig = TARGET_SIGNAL_0;
+ }
+ else if (err)
+ warning ("Signal delivery failed: %s", safe_strerror (err));
+
+ if (err)
+ /* We only get this reply when we've posted a signal to a process which we
+ thought was stopped, and which we expected to continue after the signal.
+ Given that the signal has failed for some reason, it's reasonable to
+ assume it's still stopped. */
+ inf->stopped = 1;
+ else
+ inf->wait.suppress = 1;
+
+ return 0;
+}
+
+error_t
+S_msg_sig_post_reply (mach_port_t reply, error_t err)
+{
+ return ill_rpc ("S_msg_sig_post_reply");
+}
+
+
+/* Returns the number of messages queued for the receive right PORT. */
+static mach_port_msgcount_t
+port_msgs_queued (mach_port_t port)
+{
+ struct mach_port_status status;
+ error_t err =
+ mach_port_get_receive_status (mach_task_self (), port, &status);
+
+ if (err)
+ return 0;
+ else
+ return status.mps_msgcount;
+}
+
+
+/* Resume execution of the inferior process.
+
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal.
+
+ TID STEP:
+ -1 true Single step the current thread allowing other threads to run.
+ -1 false Continue the current thread allowing other threads to run.
+ X true Single step the given thread, don't allow any others to run.
+ X false Continue the given thread, do not allow any others to run.
+ (Where X, of course, is anything except -1)
+
+ Note that a resume may not `take' if there are pending exceptions/&c
+ still unprocessed from the last resume we did (any given resume may result
+ in multiple events returned by wait).
+ */
+static void
+gnu_resume (ptid_t tid, int step, enum target_signal sig)
+{
+ struct proc *step_thread = 0;
+ struct inf *inf = current_inferior;
+
+ inf_debug (inf, "tid = %d, step = %d, sig = %d", PIDGET (tid), step, sig);
+
+ inf_validate_procinfo (inf);
+
+ if (sig != TARGET_SIGNAL_0 || inf->stopped)
+ {
+ if (sig == TARGET_SIGNAL_0 && inf->nomsg)
+ inf_continue (inf);
+ else
+ inf_signal (inf, sig);
+ }
+ else if (inf->wait.exc.reply != MACH_PORT_NULL)
+ /* We received an exception to which we have chosen not to forward, so
+ abort the faulting thread, which will perhaps retake it. */
+ {
+ proc_abort (inf->wait.thread, 1);
+ warning ("Aborting %s with unforwarded exception %s.",
+ proc_string (inf->wait.thread),
+ target_signal_to_name (inf->wait.status.value.sig));
+ }
+
+ if (port_msgs_queued (inf->event_port))
+ /* If there are still messages in our event queue, don't bother resuming
+ the process, as we're just going to stop it right away anyway. */
+ return;
+
+ inf_update_procs (inf);
+
+ if (PIDGET (tid) < 0)
+ /* Allow all threads to run, except perhaps single-stepping one. */
+ {
+ inf_debug (inf, "running all threads; tid = %d", PIDGET (inferior_ptid));
+ tid = inferior_ptid; /* What to step. */
+ inf_set_threads_resume_sc (inf, 0, 1);
+ }
+ else
+ /* Just allow a single thread to run. */
+ {
+ struct proc *thread = inf_tid_to_thread (inf, PIDGET (tid));
+ if (!thread)
+ error ("Can't run single thread id %d: no such thread!");
+ inf_debug (inf, "running one thread: %d/%d", inf->pid, thread->tid);
+ inf_set_threads_resume_sc (inf, thread, 0);
+ }
+
+ if (step)
+ {
+ step_thread = inf_tid_to_thread (inf, PIDGET (tid));
+ if (!step_thread)
+ warning ("Can't step thread id %d: no such thread.", PIDGET (tid));
+ else
+ inf_debug (inf, "stepping thread: %d/%d", inf->pid, step_thread->tid);
+ }
+ if (step_thread != inf->step_thread)
+ inf_set_step_thread (inf, step_thread);
+
+ inf_debug (inf, "here we go...");
+ inf_resume (inf);
+}
+
+
+static void
+gnu_kill_inferior (void)
+{
+ struct proc *task = current_inferior->task;
+ if (task)
+ {
+ proc_debug (task, "terminating...");
+ task_terminate (task->port);
+ inf_set_pid (current_inferior, -1);
+ }
+ target_mourn_inferior ();
+}
+
+/* Clean up after the inferior dies. */
+static void
+gnu_mourn_inferior (void)
+{
+ inf_debug (current_inferior, "rip");
+ inf_detach (current_inferior);
+ unpush_target (&gnu_ops);
+ generic_mourn_inferior ();
+}
+
+
+/* Fork an inferior process, and start debugging it. */
+
+/* Set INFERIOR_PID to the first thread available in the child, if any. */
+static int
+inf_pick_first_thread (void)
+{
+ if (current_inferior->task && current_inferior->threads)
+ /* The first thread. */
+ return current_inferior->threads->tid;
+ else
+ /* What may be the next thread. */
+ return next_thread_id;
+}
+
+static struct inf *
+cur_inf (void)
+{
+ if (!current_inferior)
+ current_inferior = make_inf ();
+ return current_inferior;
+}
+
+static void
+gnu_create_inferior (char *exec_file, char *allargs, char **env)
+{
+ struct inf *inf = cur_inf ();
+
+ void trace_me ()
+ {
+ /* We're in the child; make this process stop as soon as it execs. */
+ inf_debug (inf, "tracing self");
+ if (ptrace (PTRACE_TRACEME) != 0)
+ error ("ptrace (PTRACE_TRACEME) failed!");
+ }
+ void attach_to_child (int pid)
+ {
+ /* Attach to the now stopped child, which is actually a shell... */
+ inf_debug (inf, "attaching to child: %d", pid);
+
+ inf_attach (inf, pid);
+
+ attach_flag = 0;
+ push_target (&gnu_ops);
+
+ inf->pending_execs = 2;
+ inf->nomsg = 1;
+ inf->traced = 1;
+
+ /* Now let the child run again, knowing that it will stop immediately
+ because of the ptrace. */
+ inf_resume (inf);
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
+
+ startup_inferior (inf->pending_execs);
+ }
+
+ inf_debug (inf, "creating inferior");
+
+ fork_inferior (exec_file, allargs, env, trace_me, attach_to_child,
+ NULL, NULL);
+
+ inf_validate_procinfo (inf);
+ inf_update_signal_thread (inf);
+ inf_set_traced (inf, inf->want_signals);
+
+ /* Execing the process will have trashed our exception ports; steal them
+ back (or make sure they're restored if the user wants that). */
+ if (inf->want_exceptions)
+ inf_steal_exc_ports (inf);
+ else
+ inf_restore_exc_ports (inf);
+
+ /* Here we go! */
+ proceed ((CORE_ADDR) -1, 0, 0);
+}
+
+/* Mark our target-struct as eligible for stray "run" and "attach"
+ commands. */
+static int
+gnu_can_run (void)
+{
+ return 1;
+}
+
+
+#ifdef ATTACH_DETACH
+
+/* Attach to process PID, then initialize for debugging it
+ and wait for the trace-trap that results from attaching. */
+static void
+gnu_attach (char *args, int from_tty)
+{
+ int pid;
+ char *exec_file;
+ struct inf *inf = cur_inf ();
+
+ 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', pid %d\n",
+ exec_file, pid);
+ else
+ printf_unfiltered ("Attaching to pid %d\n", pid);
+
+ gdb_flush (gdb_stdout);
+ }
+
+ inf_debug (inf, "attaching to pid: %d", pid);
+
+ inf_attach (inf, pid);
+ inf_update_procs (inf);
+
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
+
+ attach_flag = 1;
+ push_target (&gnu_ops);
+
+ /* We have to initialize the terminal settings now, since the code
+ below might try to restore them. */
+ target_terminal_init ();
+
+ /* If the process was stopped before we attached, make it continue the next
+ time the user does a continue. */
+ inf_validate_procinfo (inf);
+
+ inf_update_signal_thread (inf);
+ inf_set_traced (inf, inf->want_signals);
+
+#if 0 /* Do we need this? */
+ renumber_threads (0); /* Give our threads reasonable names. */
+#endif
+}
+
+
+/* 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
+gnu_detach (char *args, int from_tty)
+{
+ if (from_tty)
+ {
+ char *exec_file = get_exec_file (0);
+ if (exec_file)
+ printf_unfiltered ("Detaching from program `%s' pid %d\n",
+ exec_file, current_inferior->pid);
+ else
+ printf_unfiltered ("Detaching from pid %d\n", current_inferior->pid);
+ gdb_flush (gdb_stdout);
+ }
+
+ inf_detach (current_inferior);
+
+ inferior_ptid = null_ptid;
+
+ unpush_target (&gnu_ops); /* Pop out of handling an inferior */
+}
+#endif /* ATTACH_DETACH */
+
+
+static void
+gnu_terminal_init_inferior (void)
+{
+ gdb_assert (current_inferior);
+ terminal_init_inferior_with_pgrp (current_inferior->pid);
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On machines
+ which store all the registers in one fell swoop, this makes sure
+ that registers contains all the registers from the program being
+ debugged. */
+static void
+gnu_prepare_to_store (void)
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+static void
+gnu_open (char *arg, int from_tty)
+{
+ error ("Use the \"run\" command to start a Unix child process.");
+}
+
+static void
+gnu_stop (void)
+{
+ error ("to_stop target function not implemented");
+}
+
+static char *
+gnu_pid_to_exec_file (int pid)
+{
+ error ("to_pid_to_exec_file target function not implemented");
+ return NULL;
+}
+
+
+static int
+gnu_thread_alive (ptid_t tid)
+{
+ inf_update_procs (current_inferior);
+ return !!inf_tid_to_thread (current_inferior, PIDGET (tid));
+}
+
+
+/* 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
+gnu_read_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length)
+{
+ error_t err;
+ 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;
+ int copy_count;
+
+ /* Get memory from inferior with page aligned addresses */
+ err = vm_read (task, low_address, aligned_length, &copied, &copy_count);
+ if (err)
+ return 0;
+
+ err = hurd_safe_copyin (myaddr, (void *) addr - low_address + copied, length);
+ if (err)
+ {
+ warning ("Read from inferior faulted: %s", safe_strerror (err));
+ length = 0;
+ }
+
+ err = vm_deallocate (mach_task_self (), copied, copy_count);
+ if (err)
+ warning ("gnu_read_inferior vm_deallocate failed: %s", safe_strerror (err));
+
+ 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 gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
+ task's address space. */
+int
+gnu_write_inferior (task_t task, CORE_ADDR addr, char *myaddr, int length)
+{
+ error_t err = 0;
+ 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;
+ int copy_count;
+ int deallocate = 0;
+
+ char *errstr = "Bug in gnu_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 */
+ err = vm_read (task,
+ low_address,
+ aligned_length,
+ &copied,
+ &copy_count);
+ CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err);
+
+ deallocate++;
+
+ err = hurd_safe_copyout ((void *) addr - low_address + copied,
+ myaddr, length);
+ CHK_GOTO_OUT ("Write to inferior faulted", err);
+
+ obstack_init (&region_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;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ CHK_GOTO_OUT ("vm_region failed", err);
+
+ /* Check for holes in memory */
+ if (old_address != region_address)
+ {
+ warning ("No memory at 0x%x. Nothing written",
+ old_address);
+ err = KERN_SUCCESS;
+ length = 0;
+ goto out;
+ }
+
+ if (!(max_protection & VM_PROT_WRITE))
+ {
+ warning ("Memory at address 0x%x is unwritable. Nothing written",
+ old_address);
+ err = KERN_SUCCESS;
+ length = 0;
+ goto out;
+ }
+
+ /* Chain the regions for later use */
+ region_element =
+ (struct vm_region_list *)
+ obstack_alloc (&region_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)
+ {
+ if (!(scan->protection & VM_PROT_WRITE))
+ {
+ err = vm_protect (task,
+ scan->start,
+ scan->length,
+ FALSE,
+ scan->protection | VM_PROT_WRITE);
+ CHK_GOTO_OUT ("vm_protect: enable write failed", err);
+ }
+ }
+
+ err = vm_write (task,
+ low_address,
+ copied,
+ aligned_length);
+ CHK_GOTO_OUT ("vm_write failed", err);
+
+ /* Set up the original region protections, if they were changed */
+ for (scan = region_head; scan; scan = scan->next)
+ {
+ if (!(scan->protection & VM_PROT_WRITE))
+ {
+ err = vm_protect (task,
+ scan->start,
+ scan->length,
+ FALSE,
+ scan->protection);
+ CHK_GOTO_OUT ("vm_protect: enable write failed", err);
+ }
+ }
+ }
+
+out:
+ if (deallocate)
+ {
+ obstack_free (&region_obstack, 0);
+
+ (void) vm_deallocate (mach_task_self (),
+ copied,
+ copy_count);
+ }
+
+ if (err != KERN_SUCCESS)
+ {
+ warning ("%s: %s", errstr, mach_error_string (err));
+ return 0;
+ }
+
+ return length;
+}
+
+
+/* Return 0 on failure, number of bytes handled otherwise. TARGET
+ is ignored. */
+static int
+gnu_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ task_t task = (current_inferior
+ ? (current_inferior->task
+ ? current_inferior->task->port : 0)
+ : 0);
+
+ if (task == MACH_PORT_NULL)
+ return 0;
+ else
+ {
+ inf_debug (current_inferior, "%s %p[%d] %s %p",
+ write ? "writing" : "reading", (void *) memaddr, len,
+ write ? "<--" : "-->", myaddr);
+ if (write)
+ return gnu_write_inferior (task, memaddr, myaddr, len);
+ else
+ return gnu_read_inferior (task, memaddr, myaddr, len);
+ }
+}
+
+/* Call FUNC on each memory region in the task. */
+static int
+gnu_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ error_t err;
+ task_t task;
+ vm_address_t region_address, last_region_address, last_region_end;
+ vm_prot_t last_protection;
+
+ if (current_inferior == 0 || current_inferior->task == 0)
+ return 0;
+ task = current_inferior->task->port;
+ if (task == MACH_PORT_NULL)
+ return 0;
+
+ region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
+ last_protection = VM_PROT_NONE;
+ while (region_address < VM_MAX_ADDRESS)
+ {
+ 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 = VM_MAX_ADDRESS - region_address;
+ vm_address_t old_address = region_address;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ if (err == KERN_NO_SPACE)
+ break;
+ if (err != KERN_SUCCESS)
+ {
+ warning ("vm_region failed: %s", mach_error_string (err));
+ return -1;
+ }
+
+ if (protection == last_protection && region_address == last_region_end)
+ /* This region is contiguous with and indistinguishable from
+ the previous one, so we just extend that one. */
+ last_region_end = region_address += region_length;
+ else
+ {
+ /* This region is distinct from the last one we saw, so report
+ that previous one. */
+ if (last_protection != VM_PROT_NONE)
+ (*func) (last_region_address,
+ last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+ last_region_address = region_address;
+ last_region_end = region_address += region_length;
+ last_protection = protection;
+ }
+ }
+
+ /* Report the final region. */
+ if (last_region_end > last_region_address && last_protection != VM_PROT_NONE)
+ (*func) (last_region_address, last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+
+ return 0;
+}
+
+
+/* Return printable description of proc. */
+char *
+proc_string (struct proc *proc)
+{
+ static char tid_str[80];
+ if (proc_is_task (proc))
+ sprintf (tid_str, "process %d", proc->inf->pid);
+ else
+ sprintf (tid_str, "thread %d.%d",
+ proc->inf->pid, pid_to_thread_id (MERGEPID (proc->tid, 0)));
+ return tid_str;
+}
+
+static char *
+gnu_pid_to_str (ptid_t ptid)
+{
+ struct inf *inf = current_inferior;
+ int tid = PIDGET (ptid);
+ struct proc *thread = inf_tid_to_thread (inf, tid);
+
+ if (thread)
+ return proc_string (thread);
+ else
+ {
+ static char tid_str[80];
+ sprintf (tid_str, "bogus thread id %d", tid);
+ return tid_str;
+ }
+}
+
+
+extern void gnu_store_registers (int regno);
+extern void gnu_fetch_registers (int regno);
+
+struct target_ops gnu_ops;
+
+static void
+init_gnu_ops (void)
+{
+ gnu_ops.to_shortname = "GNU"; /* to_shortname */
+ gnu_ops.to_longname = "GNU Hurd process"; /* to_longname */
+ gnu_ops.to_doc = "GNU Hurd process"; /* to_doc */
+ gnu_ops.to_open = gnu_open; /* to_open */
+ gnu_ops.to_attach = gnu_attach; /* to_attach */
+ gnu_ops.to_detach = gnu_detach; /* to_detach */
+ gnu_ops.to_resume = gnu_resume; /* to_resume */
+ gnu_ops.to_wait = gnu_wait; /* to_wait */
+ gnu_ops.to_fetch_registers = gnu_fetch_registers; /* to_fetch_registers */
+ gnu_ops.to_store_registers = gnu_store_registers; /* to_store_registers */
+ gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
+ gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
+ gnu_ops.to_find_memory_regions = gnu_find_memory_regions;
+ gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
+ gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
+ gnu_ops.to_terminal_init = gnu_terminal_init_inferior;
+ gnu_ops.to_terminal_inferior = terminal_inferior;
+ gnu_ops.to_terminal_ours_for_output = terminal_ours_for_output;
+ gnu_ops.to_terminal_save_ours = terminal_save_ours;
+ gnu_ops.to_terminal_ours = terminal_ours;
+ gnu_ops.to_terminal_info = child_terminal_info;
+ gnu_ops.to_kill = gnu_kill_inferior; /* to_kill */
+ gnu_ops.to_create_inferior = gnu_create_inferior; /* to_create_inferior */
+ gnu_ops.to_mourn_inferior = gnu_mourn_inferior; /* to_mourn_inferior */
+ gnu_ops.to_can_run = gnu_can_run; /* to_can_run */
+ gnu_ops.to_thread_alive = gnu_thread_alive; /* to_thread_alive */
+ gnu_ops.to_pid_to_str = gnu_pid_to_str; /* to_pid_to_str */
+ gnu_ops.to_stop = gnu_stop; /* to_stop */
+ gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
+ gnu_ops.to_stratum = process_stratum; /* to_stratum */
+ gnu_ops.to_has_all_memory = 1; /* to_has_all_memory */
+ gnu_ops.to_has_memory = 1; /* to_has_memory */
+ gnu_ops.to_has_stack = 1; /* to_has_stack */
+ gnu_ops.to_has_registers = 1; /* to_has_registers */
+ gnu_ops.to_has_execution = 1; /* to_has_execution */
+ gnu_ops.to_magic = OPS_MAGIC; /* to_magic */
+} /* init_gnu_ops */
+
+
+/* User task commands. */
+
+struct cmd_list_element *set_task_cmd_list = 0;
+struct cmd_list_element *show_task_cmd_list = 0;
+/* User thread commands. */
+
+/* Commands with a prefix of `set/show thread'. */
+extern struct cmd_list_element *thread_cmd_list;
+struct cmd_list_element *set_thread_cmd_list = NULL;
+struct cmd_list_element *show_thread_cmd_list = NULL;
+
+/* Commands with a prefix of `set/show thread default'. */
+struct cmd_list_element *set_thread_default_cmd_list = NULL;
+struct cmd_list_element *show_thread_default_cmd_list = NULL;
+
+static void
+set_thread_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set thread\" must be followed by the name of a thread property, or \"default\".\n");
+}
+
+static void
+show_thread_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"show thread\" must be followed by the name of a thread property, or \"default\".\n");
+}
+
+static void
+set_thread_default_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set thread default\" must be followed by the name of a thread property.\n");
+}
+
+static void
+show_thread_default_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"show thread default\" must be followed by the name of a thread property.\n");
+}
+
+static int
+parse_int_arg (char *args, char *cmd_prefix)
+{
+ if (args)
+ {
+ char *arg_end;
+ int val = strtoul (args, &arg_end, 10);
+ if (*args && *arg_end == '\0')
+ return val;
+ }
+ error ("Illegal argument for \"%s\" command, should be an integer.", cmd_prefix);
+}
+
+static int
+_parse_bool_arg (char *args, char *t_val, char *f_val, char *cmd_prefix)
+{
+ if (!args || strcmp (args, t_val) == 0)
+ return 1;
+ else if (strcmp (args, f_val) == 0)
+ return 0;
+ else
+ error ("Illegal argument for \"%s\" command, should be \"%s\" or \"%s\".",
+ cmd_prefix, t_val, f_val);
+}
+
+#define parse_bool_arg(args, cmd_prefix) \
+ _parse_bool_arg (args, "on", "off", cmd_prefix)
+
+static void
+check_empty (char *args, char *cmd_prefix)
+{
+ if (args)
+ error ("Garbage after \"%s\" command: `%s'", cmd_prefix, args);
+}
+
+/* Returns the alive thread named by INFERIOR_PID, or signals an error. */
+static struct proc *
+cur_thread (void)
+{
+ struct inf *inf = cur_inf ();
+ struct proc *thread = inf_tid_to_thread (inf, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("No current thread.");
+ return thread;
+}
+
+/* Returns the current inferior, but signals an error if it has no task. */
+static struct inf *
+active_inf (void)
+{
+ struct inf *inf = cur_inf ();
+ if (!inf->task)
+ error ("No current process.");
+ return inf;
+}
+
+
+static void
+set_task_pause_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ int old_sc = inf->pause_sc;
+
+ inf->pause_sc = parse_bool_arg (args, "set task pause");
+
+ if (old_sc == 0 && inf->pause_sc != 0)
+ /* If the task is currently unsuspended, immediately suspend it,
+ otherwise wait until the next time it gets control. */
+ inf_suspend (inf);
+}
+
+static void
+show_task_pause_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ check_empty (args, "show task pause");
+ printf_unfiltered ("The inferior task %s suspended while gdb has control.\n",
+ inf->task
+ ? (inf->pause_sc == 0 ? "isn't" : "is")
+ : (inf->pause_sc == 0 ? "won't be" : "will be"));
+}
+
+static void
+set_task_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_inf ()->detach_sc = parse_int_arg (args, "set task detach-suspend-count");
+}
+
+static void
+show_task_detach_sc_cmd (char *args, int from_tty)
+{
+ check_empty (args, "show task detach-suspend-count");
+ printf_unfiltered ("The inferior task will be left with a suspend count of %d when detaching.\n",
+ cur_inf ()->detach_sc);
+}
+
+
+static void
+set_thread_default_pause_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ inf->default_thread_pause_sc =
+ parse_bool_arg (args, "set thread default pause") ? 0 : 1;
+}
+
+static void
+show_thread_default_pause_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ int sc = inf->default_thread_pause_sc;
+ check_empty (args, "show thread default pause");
+ printf_unfiltered ("New threads %s suspended while gdb has control%s.\n",
+ sc ? "are" : "aren't",
+ !sc && inf->pause_sc ? " (but the task is)" : "");
+}
+
+static void
+set_thread_default_run_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ inf->default_thread_run_sc =
+ parse_bool_arg (args, "set thread default run") ? 0 : 1;
+}
+
+static void
+show_thread_default_run_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ check_empty (args, "show thread default run");
+ printf_unfiltered ("New threads %s allowed to run.\n",
+ inf->default_thread_run_sc == 0 ? "are" : "aren't");
+}
+
+static void
+set_thread_default_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_inf ()->default_thread_detach_sc =
+ parse_int_arg (args, "set thread default detach-suspend-count");
+}
+
+static void
+show_thread_default_detach_sc_cmd (char *args, int from_tty)
+{
+ check_empty (args, "show thread default detach-suspend-count");
+ printf_unfiltered ("New threads will get a detach-suspend-count of %d.\n",
+ cur_inf ()->default_thread_detach_sc);
+}
+
+
+/* Steal a send right called NAME in the inferior task, and make it PROC's
+ saved exception port. */
+static void
+steal_exc_port (struct proc *proc, mach_port_t name)
+{
+ error_t err;
+ mach_port_t port;
+ mach_msg_type_name_t port_type;
+
+ if (!proc || !proc->inf->task)
+ error ("No inferior task.");
+
+ err = mach_port_extract_right (proc->inf->task->port,
+ name, MACH_MSG_TYPE_COPY_SEND,
+ &port, &port_type);
+ if (err)
+ error ("Couldn't extract send right %d from inferior: %s",
+ name, safe_strerror (err));
+
+ if (proc->saved_exc_port)
+ /* Get rid of our reference to the old one. */
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+
+ proc->saved_exc_port = port;
+
+ if (!proc->exc_port)
+ /* If PROC is a thread, we may not have set its exception port before.
+ We can't use proc_steal_exc_port because it also sets saved_exc_port. */
+ {
+ proc->exc_port = proc->inf->event_port;
+ err = proc_set_exception_port (proc, proc->exc_port);
+ error ("Can't set exception port for %s: %s",
+ proc_string (proc), safe_strerror (err));
+ }
+}
+
+static void
+set_task_exc_port_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ if (!args)
+ error ("No argument to \"set task exception-port\" command.");
+ steal_exc_port (inf->task, parse_and_eval_address (args));
+}
+
+static void
+set_stopped_cmd (char *args, int from_tty)
+{
+ cur_inf ()->stopped = _parse_bool_arg (args, "yes", "no", "set stopped");
+}
+
+static void
+show_stopped_cmd (char *args, int from_tty)
+{
+ struct inf *inf = active_inf ();
+ check_empty (args, "show stopped");
+ printf_unfiltered ("The inferior process %s stopped.\n",
+ inf->stopped ? "is" : "isn't");
+}
+
+static void
+set_sig_thread_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+
+ if (!args || (!isdigit (*args) && strcmp (args, "none") != 0))
+ error ("Illegal argument to \"set signal-thread\" command.\n"
+ "Should be an integer thread ID, or `none'.");
+
+ if (strcmp (args, "none") == 0)
+ inf->signal_thread = 0;
+ else
+ {
+ int tid = PIDGET (thread_id_to_pid (atoi (args)));
+ if (tid < 0)
+ error ("Thread ID %s not known. Use the \"info threads\" command to\n"
+ "see the IDs of currently known threads.", args);
+ inf->signal_thread = inf_tid_to_thread (inf, tid);
+ }
+}
+
+static void
+show_sig_thread_cmd (char *args, int from_tty)
+{
+ struct inf *inf = active_inf ();
+ check_empty (args, "show signal-thread");
+ if (inf->signal_thread)
+ printf_unfiltered ("The signal thread is %s.\n",
+ proc_string (inf->signal_thread));
+ else
+ printf_unfiltered ("There is no signal thread.\n");
+}
+
+
+static void
+set_signals_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+
+ inf->want_signals = parse_bool_arg (args, "set signals");
+
+ if (inf->task && inf->want_signals != inf->traced)
+ /* Make this take effect immediately in a running process. */
+ inf_set_traced (inf, inf->want_signals);
+}
+
+static void
+show_signals_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ check_empty (args, "show signals");
+ printf_unfiltered ("The inferior process's signals %s intercepted.\n",
+ inf->task
+ ? (inf->traced ? "are" : "aren't")
+ : (inf->want_signals ? "will be" : "won't be"));
+}
+
+static void
+set_exceptions_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ int val = parse_bool_arg (args, "set exceptions");
+
+ if (inf->task && inf->want_exceptions != val)
+ /* Make this take effect immediately in a running process. */
+ /* XXX */ ;
+
+ inf->want_exceptions = val;
+}
+
+static void
+show_exceptions_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+ check_empty (args, "show exceptions");
+ printf_unfiltered ("Exceptions in the inferior %s trapped.\n",
+ inf->task
+ ? (inf->want_exceptions ? "are" : "aren't")
+ : (inf->want_exceptions ? "will be" : "won't be"));
+}
+
+
+static void
+set_task_cmd (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set task\" must be followed by the name"
+ " of a task property.\n");
+}
+
+static void
+show_task_cmd (char *args, int from_tty)
+{
+ struct inf *inf = cur_inf ();
+
+ check_empty (args, "show task");
+
+ show_signals_cmd (0, from_tty);
+ show_exceptions_cmd (0, from_tty);
+ show_task_pause_cmd (0, from_tty);
+
+ if (inf->pause_sc == 0)
+ show_thread_default_pause_cmd (0, from_tty);
+ show_thread_default_run_cmd (0, from_tty);
+
+ if (inf->task)
+ {
+ show_stopped_cmd (0, from_tty);
+ show_sig_thread_cmd (0, from_tty);
+ }
+
+ if (inf->detach_sc != 0)
+ show_task_detach_sc_cmd (0, from_tty);
+ if (inf->default_thread_detach_sc != 0)
+ show_thread_default_detach_sc_cmd (0, from_tty);
+}
+
+
+static void
+set_noninvasive_cmd (char *args, int from_tty)
+{
+ /* Invert the sense of the arg for each component. */
+ char *inv_args = parse_bool_arg (args, "set noninvasive") ? "off" : "on";
+
+ set_task_pause_cmd (inv_args, from_tty);
+ set_signals_cmd (inv_args, from_tty);
+ set_exceptions_cmd (inv_args, from_tty);
+}
+
+
+static void
+info_port_rights (char *args, mach_port_type_t only)
+{
+ struct inf *inf = active_inf ();
+ struct value *vmark = value_mark ();
+
+ if (args)
+ /* Explicit list of port rights. */
+ {
+ while (*args)
+ {
+ struct value *val = parse_to_comma_and_eval (&args);
+ long right = value_as_long (val);
+ error_t err =
+ print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
+ stdout);
+ if (err)
+ error ("%ld: %s.", right, safe_strerror (err));
+ }
+ }
+ else
+ /* Print all of them. */
+ {
+ error_t err =
+ print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
+ stdout);
+ if (err)
+ error ("%s.", safe_strerror (err));
+ }
+
+ value_free_to_mark (vmark);
+}
+
+static void
+info_send_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_SEND);
+}
+
+static void
+info_recv_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_RECEIVE);
+}
+
+static void
+info_port_sets_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_PORT_SET);
+}
+
+static void
+info_dead_names_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, MACH_PORT_TYPE_DEAD_NAME);
+}
+
+static void
+info_port_rights_cmd (char *args, int from_tty)
+{
+ info_port_rights (args, ~0);
+}
+
+
+static void
+add_task_commands (void)
+{
+ add_cmd ("pause", class_run, set_thread_default_pause_cmd,
+ "Set whether the new threads are suspended while gdb has control.\n\
+This property normally has no effect because the whole task is\n\
+suspended, however, that may be disabled with \"set task pause off\".\n\
+The default value is \"off\".",
+ &set_thread_default_cmd_list);
+ add_cmd ("pause", no_class, show_thread_default_pause_cmd,
+ "Show whether new threads are suspended while gdb has control.",
+ &show_thread_default_cmd_list);
+
+ add_cmd ("run", class_run, set_thread_default_run_cmd,
+ "Set whether new threads are allowed to run \
+(once gdb has noticed them).",
+ &set_thread_default_cmd_list);
+ add_cmd ("run", no_class, show_thread_default_run_cmd,
+ "Show whether new threads are allowed to run \
+(once gdb has noticed them).",
+ &show_thread_default_cmd_list);
+
+ add_cmd ("detach-suspend-count", class_run, set_thread_default_detach_sc_cmd,
+ "Set the default detach-suspend-count value for new threads.",
+ &set_thread_default_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_thread_default_detach_sc_cmd,
+ "Show the default detach-suspend-count value for new threads.",
+ &show_thread_default_cmd_list);
+
+ add_cmd ("signals", class_run, set_signals_cmd,
+ "Set whether the inferior process's signals will be intercepted.\n\
+Mach exceptions (such as breakpoint traps) are not affected.",
+ &setlist);
+ add_alias_cmd ("sigs", "signals", class_run, 1, &setlist);
+ add_cmd ("signals", no_class, show_signals_cmd,
+ "Show whether the inferior process's signals will be intercepted.",
+ &showlist);
+ add_alias_cmd ("sigs", "signals", no_class, 1, &showlist);
+
+ add_cmd ("signal-thread", class_run, set_sig_thread_cmd,
+ "Set the thread that gdb thinks is the libc signal thread.\n\
+This thread is run when delivering a signal to a non-stopped process.",
+ &setlist);
+ add_alias_cmd ("sigthread", "signal-thread", class_run, 1, &setlist);
+ add_cmd ("signal-thread", no_class, show_sig_thread_cmd,
+ "Set the thread that gdb thinks is the libc signal thread.",
+ &showlist);
+ add_alias_cmd ("sigthread", "signal-thread", no_class, 1, &showlist);
+
+ add_cmd ("stopped", class_run, set_stopped_cmd,
+ "Set whether gdb thinks the inferior process is stopped \
+as with SIGSTOP.\n\
+Stopped process will be continued by sending them a signal.",
+ &setlist);
+ add_cmd ("stopped", no_class, show_signals_cmd,
+ "Show whether gdb thinks the inferior process is stopped \
+as with SIGSTOP.",
+ &showlist);
+
+ add_cmd ("exceptions", class_run, set_exceptions_cmd,
+ "Set whether exceptions in the inferior process will be trapped.\n\
+When exceptions are turned off, neither breakpoints nor single-stepping\n\
+will work.",
+ &setlist);
+ /* Allow `set exc' despite conflict with `set exception-port'. */
+ add_alias_cmd ("exc", "exceptions", class_run, 1, &setlist);
+ add_cmd ("exceptions", no_class, show_exceptions_cmd,
+ "Show whether exceptions in the inferior process will be trapped.",
+ &showlist);
+
+ add_prefix_cmd ("task", no_class, set_task_cmd,
+ "Command prefix for setting task attributes.",
+ &set_task_cmd_list, "set task ", 0, &setlist);
+ add_prefix_cmd ("task", no_class, show_task_cmd,
+ "Command prefix for showing task attributes.",
+ &show_task_cmd_list, "show task ", 0, &showlist);
+
+ add_cmd ("pause", class_run, set_task_pause_cmd,
+ "Set whether the task is suspended while gdb has control.\n\
+A value of \"on\" takes effect immediately, otherwise nothing happens\n\
+until the next time the program is continued.\n\
+When setting this to \"off\", \"set thread default pause on\" can be\n\
+used to pause individual threads by default instead.",
+ &set_task_cmd_list);
+ add_cmd ("pause", no_class, show_task_pause_cmd,
+ "Show whether the task is suspended while gdb has control.",
+ &show_task_cmd_list);
+
+ add_cmd ("detach-suspend-count", class_run, set_task_detach_sc_cmd,
+ "Set the suspend count will leave on the thread when detaching.",
+ &set_task_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_task_detach_sc_cmd,
+ "Show the suspend count will leave on the thread when detaching.",
+ &show_task_cmd_list);
+
+ add_cmd ("exception-port", no_class, set_task_exc_port_cmd,
+ "Set the task exception port to which we forward exceptions.\n\
+The argument should be the value of the send right in the task.",
+ &set_task_cmd_list);
+ add_alias_cmd ("excp", "exception-port", no_class, 1, &set_task_cmd_list);
+ add_alias_cmd ("exc-port", "exception-port", no_class, 1,
+ &set_task_cmd_list);
+
+ /* A convenient way of turning on all options require to noninvasively
+ debug running tasks. */
+ add_cmd ("noninvasive", no_class, set_noninvasive_cmd,
+ "Set task options so that we interfere as little as possible.\n\
+This is the same as setting `task pause', `exceptions', and\n\
+`signals' to the opposite value.",
+ &setlist);
+
+ /* Commands to show information about the task's ports. */
+ add_cmd ("send-rights", class_info, info_send_rights_cmd,
+ "Show information about the task's send rights",
+ &infolist);
+ add_cmd ("receive-rights", class_info, info_recv_rights_cmd,
+ "Show information about the task's receive rights",
+ &infolist);
+ add_cmd ("port-rights", class_info, info_port_rights_cmd,
+ "Show information about the task's port rights",
+ &infolist);
+ add_cmd ("port-sets", class_info, info_port_sets_cmd,
+ "Show information about the task's port sets",
+ &infolist);
+ add_cmd ("dead-names", class_info, info_dead_names_cmd,
+ "Show information about the task's dead names",
+ &infolist);
+ add_info_alias ("ports", "port-rights", 1);
+ add_info_alias ("port", "port-rights", 1);
+ add_info_alias ("psets", "port-sets", 1);
+}
+
+
+static void
+set_thread_pause_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ int old_sc = thread->pause_sc;
+ thread->pause_sc = parse_bool_arg (args, "set thread pause");
+ if (old_sc == 0 && thread->pause_sc != 0 && thread->inf->pause_sc == 0)
+ /* If the task is currently unsuspended, immediately suspend it,
+ otherwise wait until the next time it gets control. */
+ inf_suspend (thread->inf);
+}
+
+static void
+show_thread_pause_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ int sc = thread->pause_sc;
+ check_empty (args, "show task pause");
+ printf_unfiltered ("Thread %s %s suspended while gdb has control%s.\n",
+ proc_string (thread),
+ sc ? "is" : "isn't",
+ !sc && thread->inf->pause_sc ? " (but the task is)" : "");
+}
+
+static void
+set_thread_run_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ thread->run_sc = parse_bool_arg (args, "set thread run") ? 0 : 1;
+}
+
+static void
+show_thread_run_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ check_empty (args, "show thread run");
+ printf_unfiltered ("Thread %s %s allowed to run.",
+ proc_string (thread),
+ thread->run_sc == 0 ? "is" : "isn't");
+}
+
+static void
+set_thread_detach_sc_cmd (char *args, int from_tty)
+{
+ cur_thread ()->detach_sc = parse_int_arg (args,
+ "set thread detach-suspend-count");
+}
+
+static void
+show_thread_detach_sc_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ check_empty (args, "show thread detach-suspend-count");
+ printf_unfiltered ("Thread %s will be left with a suspend count"
+ " of %d when detaching.\n",
+ proc_string (thread),
+ thread->detach_sc);
+}
+
+static void
+set_thread_exc_port_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ if (!args)
+ error ("No argument to \"set thread exception-port\" command.");
+ steal_exc_port (thread, parse_and_eval_address (args));
+}
+
+#if 0
+static void
+show_thread_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ check_empty (args, "show thread");
+ show_thread_run_cmd (0, from_tty);
+ show_thread_pause_cmd (0, from_tty);
+ if (thread->detach_sc != 0)
+ show_thread_detach_sc_cmd (0, from_tty);
+}
+#endif
+
+static void
+thread_takeover_sc_cmd (char *args, int from_tty)
+{
+ struct proc *thread = cur_thread ();
+ thread_basic_info_data_t _info;
+ thread_basic_info_t info = &_info;
+ mach_msg_type_number_t info_len = THREAD_BASIC_INFO_COUNT;
+ error_t err =
+ thread_info (thread->port, THREAD_BASIC_INFO, (int *) &info, &info_len);
+ if (err)
+ error ("%s.", safe_strerror (err));
+ thread->sc = info->suspend_count;
+ if (from_tty)
+ printf_unfiltered ("Suspend count was %d.\n", thread->sc);
+ if (info != &_info)
+ vm_deallocate (mach_task_self (), (vm_address_t) info,
+ info_len * sizeof (int));
+}
+
+
+static void
+add_thread_commands (void)
+{
+ add_prefix_cmd ("thread", no_class, set_thread_cmd,
+ "Command prefix for setting thread properties.",
+ &set_thread_cmd_list, "set thread ", 0, &setlist);
+ add_prefix_cmd ("default", no_class, show_thread_cmd,
+ "Command prefix for setting default thread properties.",
+ &set_thread_default_cmd_list, "set thread default ", 0,
+ &set_thread_cmd_list);
+ add_prefix_cmd ("thread", no_class, set_thread_default_cmd,
+ "Command prefix for showing thread properties.",
+ &show_thread_cmd_list, "show thread ", 0, &showlist);
+ add_prefix_cmd ("default", no_class, show_thread_default_cmd,
+ "Command prefix for showing default thread properties.",
+ &show_thread_default_cmd_list, "show thread default ", 0,
+ &show_thread_cmd_list);
+
+ add_cmd ("pause", class_run, set_thread_pause_cmd,
+ "Set whether the current thread is suspended \
+while gdb has control.\n\
+A value of \"on\" takes effect immediately, otherwise nothing happens\n\
+until the next time the program is continued. This property normally\n\
+has no effect because the whole task is suspended, however, that may\n\
+be disabled with \"set task pause off\".\n\
+The default value is \"off\".",
+ &set_thread_cmd_list);
+ add_cmd ("pause", no_class, show_thread_pause_cmd,
+ "Show whether the current thread is suspended \
+while gdb has control.",
+ &show_thread_cmd_list);
+
+ add_cmd ("run", class_run, set_thread_run_cmd,
+ "Set whether the current thread is allowed to run.",
+ &set_thread_cmd_list);
+ add_cmd ("run", no_class, show_thread_run_cmd,
+ "Show whether the current thread is allowed to run.",
+ &show_thread_cmd_list);
+
+ add_cmd ("detach-suspend-count", class_run, set_thread_detach_sc_cmd,
+ "Set the suspend count will leave on the thread when detaching.\n\
+Note that this is relative to suspend count when gdb noticed the thread;\n\
+use the `thread takeover-suspend-count' to force it to an absolute value.",
+ &set_thread_cmd_list);
+ add_cmd ("detach-suspend-count", no_class, show_thread_detach_sc_cmd,
+ "Show the suspend count will leave on the thread when detaching.\n\
+Note that this is relative to suspend count when gdb noticed the thread;\n\
+use the `thread takeover-suspend-count' to force it to an absolute value.",
+ &show_thread_cmd_list);
+
+ add_cmd ("exception-port", no_class, set_thread_exc_port_cmd,
+ "Set the thread exception port to which we forward exceptions.\n\
+This overrides the task exception port.\n\
+The argument should be the value of the send right in the task.",
+ &set_thread_cmd_list);
+ add_alias_cmd ("excp", "exception-port", no_class, 1, &set_thread_cmd_list);
+ add_alias_cmd ("exc-port", "exception-port", no_class, 1,
+ &set_thread_cmd_list);
+
+ add_cmd ("takeover-suspend-count", no_class, thread_takeover_sc_cmd,
+ "Force the threads absolute suspend-count to be gdb's.\n\
+Prior to giving this command, gdb's thread suspend-counts are relative\n\
+to the thread's initial suspend-count when gdb notices the threads.",
+ &thread_cmd_list);
+}
+
+
+void
+_initialize_gnu_nat (void)
+{
+ proc_server = getproc ();
+
+ init_gnu_ops ();
+ add_target (&gnu_ops);
+
+ add_task_commands ();
+ add_thread_commands ();
+ add_set_cmd ("gnu-debug", class_maintenance,
+ var_boolean, (char *) &gnu_debug_flag,
+ "Set debugging output for the gnu backend.", &maintenancelist);
+}
+
+#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 */
+
+void
+flush_inferior_icache (CORE_ADDR pc, int amount)
+{
+ vm_machine_attribute_val_t flush = MATTR_VAL_ICACHE_FLUSH;
+ error_t ret;
+
+ ret = vm_machine_attribute (current_inferior->task->port,
+ pc,
+ amount,
+ MATTR_CACHE,
+ &flush);
+ if (ret != KERN_SUCCESS)
+ warning ("Error flushing inferior's cache : %s", safe_strerror (ret));
+}
+#endif /* FLUSH_INFERIOR_CACHE */
diff --git a/contrib/gdb/gdb/gnu-nat.h b/contrib/gdb/gdb/gnu-nat.h
new file mode 100644
index 0000000..bcdfe6e
--- /dev/null
+++ b/contrib/gdb/gdb/gnu-nat.h
@@ -0,0 +1,101 @@
+/* Common things used by the various *gnu-nat.c files
+ Copyright 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef __GNU_NAT_H__
+#define __GNU_NAT_H__
+
+#include <unistd.h>
+#include <mach.h>
+
+struct inf;
+
+extern struct inf *current_inferior;
+
+/* Converts a GDB pid to a struct proc. */
+struct proc *inf_tid_to_thread (struct inf *inf, int tid);
+
+/* Makes sure that INF's thread list is synced with the actual process. */
+int inf_update_procs (struct inf *inf);
+
+/* A proc is either a thread, or the task (there can only be one task proc
+ because it always has the same TID, PROC_TID_TASK). */
+struct proc
+ {
+ thread_t port; /* The task or thread port. */
+ int tid; /* The GDB pid (actually a thread id). */
+ int num; /* An id number for threads, to print. */
+
+ mach_port_t saved_exc_port; /* The task/thread's real exception port. */
+ mach_port_t exc_port; /* Our replacement, which for. */
+
+ int sc; /* Desired suspend count. */
+ int cur_sc; /* Implemented suspend count. */
+ int run_sc; /* Default sc when the program is running. */
+ int pause_sc; /* Default sc when gdb has control. */
+ int resume_sc; /* Sc resulting from the last resume. */
+ int detach_sc; /* SC to leave around when detaching
+ from program. */
+
+ thread_state_data_t state; /* Registers, &c. */
+ int state_valid:1; /* True if STATE is up to date. */
+ int state_changed:1;
+
+ int aborted:1; /* True if thread_abort has been called. */
+ int dead:1; /* We happen to know it's actually dead. */
+
+ /* Bit mask of registers fetched by gdb. This is used when we re-fetch
+ STATE after aborting the thread, to detect that gdb may have out-of-date
+ information. */
+ unsigned long fetched_regs;
+
+ struct inf *inf; /* Where we come from. */
+
+ struct proc *next;
+ };
+
+/* The task has a thread entry with this TID. */
+#define PROC_TID_TASK (-1)
+
+#define proc_is_task(proc) ((proc)->tid == PROC_TID_TASK)
+#define proc_is_thread(proc) ((proc)->tid != PROC_TID_TASK)
+
+extern int __proc_pid (struct proc *proc);
+
+/* Make sure that the state field in PROC is up to date, and return a
+ pointer to it, or 0 if something is wrong. If WILL_MODIFY is true,
+ makes sure that the thread is stopped and aborted first, and sets
+ the state_changed field in PROC to true. */
+extern thread_state_t proc_get_state (struct proc *proc, int will_modify);
+
+/* Return printable description of proc. */
+extern char *proc_string (struct proc *proc);
+
+#define proc_debug(_proc, msg, args...) \
+ do { struct proc *__proc = (_proc); \
+ debug ("{proc %d/%d %p}: " msg, \
+ __proc_pid (__proc), __proc->tid, __proc , ##args); } while (0)
+
+extern int gnu_debug_flag;
+
+#define debug(msg, args...) \
+ do { if (gnu_debug_flag) \
+ fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", __FILE__ , __LINE__ , ##args); } while (0)
+
+#endif /* __GNU_NAT_H__ */
diff --git a/contrib/gdb/gdb/i386-stub.c b/contrib/gdb/gdb/i386-stub.c
new file mode 100644
index 0000000..1251567
--- /dev/null
+++ b/contrib/gdb/gdb/i386-stub.c
@@ -0,0 +1,952 @@
+/****************************************************************************
+
+ 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 *)&registers[ESP], ptr, 4, 0); /* SP */
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[EBP];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[EBP], ptr, 4, 0); /* FP */
+ *ptr++ = ';';
+
+ *ptr++ = hexchars[PC];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&registers[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, &regno) && *ptr++ == '=')
+ if (regno >= 0 && regno < NUMREGS)
+ {
+ hex2mem (ptr, (char *) &registers[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/i386gnu-nat.c b/contrib/gdb/gdb/i386gnu-nat.c
new file mode 100644
index 0000000..7533f09
--- /dev/null
+++ b/contrib/gdb/gdb/i386gnu-nat.c
@@ -0,0 +1,293 @@
+/* Low level interface to i386 running the GNU Hurd.
+ Copyright 1992, 1995, 1996, 1998, 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 "gdb_assert.h"
+#include <errno.h>
+#include <stdio.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+
+#include "i386-tdep.h"
+
+#include "gnu-nat.h"
+#include "i387-tdep.h"
+
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+# include "gregset.h"
+#endif
+
+/* Offset to the thread_state_t location where REG is stored. */
+#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
+
+/* At REG_OFFSET[N] is the offset to the thread_state_t location where
+ the GDB register N is stored. */
+static int reg_offset[] =
+{
+ REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx),
+ REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi),
+ REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss),
+ REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs)
+};
+
+#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum])
+
+
+/* Get the whole floating-point state of THREAD and record the
+ values of the corresponding (pseudo) registers. */
+static void
+fetch_fpregs (struct proc *thread)
+{
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ struct i386_float_state state;
+ error_t err;
+
+ err = thread_get_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, &count);
+ if (err)
+ {
+ warning ("Couldn't fetch floating-point state from %s",
+ proc_string (thread));
+ return;
+ }
+
+ if (!state.initialized)
+ /* The floating-point state isn't initialized. */
+ {
+ int i;
+
+ for (i = FP0_REGNUM; i <= FOP_REGNUM; i++)
+ supply_register (i, NULL);
+
+ return;
+ }
+
+ /* Supply the floating-point registers. */
+ i387_supply_fsave (current_regcache, -1, state.hw_state);
+}
+
+#ifdef HAVE_SYS_PROCFS_H
+/* These two calls are used by the core-regset.c code for
+ reading ELF core files. */
+void
+supply_gregset (gdb_gregset_t *gregs)
+{
+ int i;
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, REG_ADDR (gregs, i));
+}
+
+void
+supply_fpregset (gdb_fpregset_t *fpregs)
+{
+ i387_supply_fsave (current_regcache, -1, fpregs);
+}
+#endif
+
+/* Fetch register REGNO, or all regs if REGNO is -1. */
+void
+gnu_fetch_registers (int regno)
+{
+ struct proc *thread;
+
+ /* Make sure we know about new threads. */
+ inf_update_procs (current_inferior);
+
+ thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("Can't fetch registers from thread %d: No such thread",
+ PIDGET (inferior_ptid));
+
+ if (regno < I386_NUM_GREGS || regno == -1)
+ {
+ thread_state_t state;
+
+ /* This does the dirty work for us. */
+ state = proc_get_state (thread, 0);
+ if (!state)
+ {
+ warning ("Couldn't fetch registers from %s",
+ proc_string (thread));
+ return;
+ }
+
+ if (regno == -1)
+ {
+ int i;
+
+ proc_debug (thread, "fetching all register");
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, REG_ADDR (state, i));
+ thread->fetched_regs = ~0;
+ }
+ else
+ {
+ proc_debug (thread, "fetching register %s", REGISTER_NAME (regno));
+
+ supply_register (regno, REG_ADDR (state, regno));
+ thread->fetched_regs |= (1 << regno);
+ }
+ }
+
+ if (regno >= I386_NUM_GREGS || regno == -1)
+ {
+ proc_debug (thread, "fetching floating-point registers");
+
+ fetch_fpregs (thread);
+ }
+}
+
+
+/* Store the whole floating-point state into THREAD using information
+ from the corresponding (pseudo) registers. */
+static void
+store_fpregs (struct proc *thread, int regno)
+{
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ struct i386_float_state state;
+ error_t err;
+
+ err = thread_get_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, &count);
+ if (err)
+ {
+ warning ("Couldn't fetch floating-point state from %s",
+ proc_string (thread));
+ return;
+ }
+
+ /* FIXME: kettenis/2001-07-15: Is this right? Should we somehow
+ take into account DEPRECATED_REGISTER_VALID like the old code did? */
+ i387_fill_fsave (state.hw_state, regno);
+
+ err = thread_set_state (thread->port, i386_FLOAT_STATE,
+ (thread_state_t) &state, i386_FLOAT_STATE_COUNT);
+ if (err)
+ {
+ warning ("Couldn't store floating-point state into %s",
+ proc_string (thread));
+ return;
+ }
+}
+
+/* Store at least register REGNO, or all regs if REGNO == -1. */
+void
+gnu_store_registers (int regno)
+{
+ struct proc *thread;
+
+ /* Make sure we know about new threads. */
+ inf_update_procs (current_inferior);
+
+ thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
+ if (!thread)
+ error ("Couldn't store registers into thread %d: No such thread",
+ PIDGET (inferior_ptid));
+
+ if (regno < I386_NUM_GREGS || regno == -1)
+ {
+ thread_state_t state;
+ thread_state_data_t old_state;
+ int was_aborted = thread->aborted;
+ int was_valid = thread->state_valid;
+ int trace;
+
+ if (!was_aborted && was_valid)
+ memcpy (&old_state, &thread->state, sizeof (old_state));
+
+ state = proc_get_state (thread, 1);
+ if (!state)
+ {
+ warning ("Couldn't store registers into %s", proc_string (thread));
+ return;
+ }
+
+ /* Save the T bit. We might try to restore the %eflags register
+ below, but changing the T bit would seriously confuse GDB. */
+ trace = ((struct i386_thread_state *)state)->efl & 0x100;
+
+ if (!was_aborted && was_valid)
+ /* See which registers have changed after aborting the thread. */
+ {
+ int check_regno;
+
+ for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++)
+ if ((thread->fetched_regs & (1 << check_regno))
+ && memcpy (REG_ADDR (&old_state, check_regno),
+ REG_ADDR (state, check_regno),
+ DEPRECATED_REGISTER_RAW_SIZE (check_regno)))
+ /* Register CHECK_REGNO has changed! Ack! */
+ {
+ warning ("Register %s changed after the thread was aborted",
+ REGISTER_NAME (check_regno));
+ if (regno >= 0 && regno != check_regno)
+ /* Update GDB's copy of the register. */
+ supply_register (check_regno, REG_ADDR (state, check_regno));
+ else
+ warning ("... also writing this register! Suspicious...");
+ }
+ }
+
+#define fill(state, regno) \
+ memcpy (REG_ADDR(state, regno), &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)], \
+ DEPRECATED_REGISTER_RAW_SIZE (regno))
+
+ if (regno == -1)
+ {
+ int i;
+
+ proc_debug (thread, "storing all registers");
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ if (deprecated_register_valid[i])
+ fill (state, i);
+ }
+ else
+ {
+ proc_debug (thread, "storing register %s", REGISTER_NAME (regno));
+
+ gdb_assert (deprecated_register_valid[regno]);
+ fill (state, regno);
+ }
+
+ /* Restore the T bit. */
+ ((struct i386_thread_state *)state)->efl &= ~0x100;
+ ((struct i386_thread_state *)state)->efl |= trace;
+ }
+
+#undef fill
+
+ if (regno >= I386_NUM_GREGS || regno == -1)
+ {
+ proc_debug (thread, "storing floating-point registers");
+
+ store_fpregs (thread, regno);
+ }
+}
diff --git a/contrib/gdb/gdb/i386ly-tdep.c b/contrib/gdb/gdb/i386ly-tdep.c
new file mode 100644
index 0000000..2374b71
--- /dev/null
+++ b/contrib/gdb/gdb/i386ly-tdep.c
@@ -0,0 +1,81 @@
+/* Target-dependent code for Intel 386 running LynxOS.
+ Copyright 1993, 1996, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+#include "osabi.h"
+
+#include "i386-tdep.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. */
+
+static 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_nobpt (frame->pc - 7, opcode, 7);
+ if (memcmp (opcode, call_inst, 7) == 0)
+ return read_memory_unsigned_integer (read_register (SP_REGNUM) + 4, 4);
+
+ return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
+}
+
+
+/* LynxOS. */
+static void
+i386lynx_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ set_gdbarch_deprecated_saved_pc_after_call (gdbarch, i386lynx_saved_pc_after_call);
+}
+
+
+static enum gdb_osabi
+i386lynx_coff_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "coff-i386-lynx") == 0)
+ return GDB_OSABI_LYNXOS;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386lynx_tdep (void);
+
+void
+_initialize_i386lynx_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
+ i386lynx_coff_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LYNXOS,
+ i386lynx_init_abi);
+}
diff --git a/contrib/gdb/gdb/i386v-nat.c b/contrib/gdb/gdb/i386v-nat.c
new file mode 100644
index 0000000..678eabc
--- /dev/null
+++ b/contrib/gdb/gdb/i386v-nat.c
@@ -0,0 +1,277 @@
+/* Intel 386 native support for System V 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>
+
+#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS
+#include <sys/debugreg.h>
+#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"
+
+#include "i386-tdep.h"
+
+
+/* Mapping between the general-purpose registers in `struct user'
+ format and GDB's register array layout. */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* Support for the user struct. */
+
+/* Return the address of register REGNUM. BLOCKEND is the value of
+ u.u_ar0, and points to the place where GS is stored. */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+ struct user u;
+ CORE_ADDR fpstate;
+
+ if (i386_fp_regnum_p (regnum))
+ {
+#ifdef KSTKSZ /* SCO, and others? */
+ blockend += 4 * (SS + 1) - KSTKSZ;
+ fpstate = blockend + ((char *) &u.u_fps.u_fpstate - (char *) &u);
+ return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
+#else
+ fpstate = blockend + ((char *) &u.i387.st_space - (char *) &u);
+ return (fpstate + 10 * (regnum - FP0_REGNUM));
+#endif
+ }
+
+ return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct. */
+
+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
new file mode 100644
index 0000000..188f01b
--- /dev/null
+++ b/contrib/gdb/gdb/i386v4-nat.c
@@ -0,0 +1,160 @@
+/* Native-dependent code for SVR4 Unix running on i386's.
+ Copyright 1988, 1989, 1991, 1992, 1996, 1997, 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 "defs.h"
+#include "value.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#ifdef HAVE_SYS_REG_H
+#include <sys/reg.h>
+#endif
+
+#include "i386-tdep.h"
+#include "i387-tdep.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 purpose 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-purpose
+ 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;
+
+ Incidentally fpchip_state contains the FPU state in the same format
+ as used by the "fsave" instruction, and that's the only thing we
+ support here. I don't know how the emulator stores it state. The
+ Weitek stuff definitely isn't supported.
+
+ The routines defined here, provide the packing and unpacking of
+ gregset_t and fpregset_t formatted data. */
+
+#ifdef HAVE_GREGSET_T
+
+/* Mapping between the general-purpose registers in `/proc'
+ format and GDB's register array layout. */
+static int regmap[] =
+{
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ greg_t *regp = (greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ supply_register (i, (char *) (regp + regmap[i]));
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+ *GREGSETPS with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ greg_t *regp = (greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < I386_NUM_GREGS; i++)
+ if (regno == -1 || regno == i)
+ regcache_collect (i, regp + regmap[i]);
+}
+
+#endif /* HAVE_GREGSET_T */
+
+#ifdef HAVE_FPREGSET_T
+
+/* Fill GDB's register array with the floating-point register values in
+ *FPREGSETP. */
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ if (FP0_REGNUM == 0)
+ return;
+
+ i387_supply_fsave (current_regcache, -1, fpregsetp);
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ if (FP0_REGNUM == 0)
+ return;
+
+ i387_fill_fsave ((char *) fpregsetp, regno);
+}
+
+#endif /* HAVE_FPREGSET_T */
+
+#endif /* HAVE_SYS_PROCFS_H */
diff --git a/contrib/gdb/gdb/lynx-nat.c b/contrib/gdb/gdb/lynx-nat.c
new file mode 100644
index 0000000..7bfd40e
--- /dev/null
+++ b/contrib/gdb/gdb/lynx-nat.c
@@ -0,0 +1,624 @@
+/* Native-dependent code for LynxOS.
+
+ Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2003 Free
+ Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "regcache.h"
+
+#include <sys/ptrace.h>
+#Include "gdb_wait.h"
+#include <sys/fpp.h>
+
+static unsigned long registers_addr (int pid);
+static void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
+
+#define X(ENTRY)(offsetof(struct econtext, ENTRY))
+
+#ifdef I386
+/* Mappings from tm-i386v.h */
+
+static int regmap[] =
+{
+ X (eax),
+ X (ecx),
+ X (edx),
+ X (ebx),
+ X (esp), /* sp */
+ X (ebp), /* fp */
+ X (esi),
+ X (edi),
+ X (eip), /* pc */
+ X (flags), /* ps */
+ X (cs),
+ X (ss),
+ X (ds),
+ X (es),
+ X (ecode), /* Lynx doesn't give us either fs or gs, so */
+ X (fault), /* we just substitute these two in the hopes
+ that they are useful. */
+};
+#endif /* I386 */
+
+#ifdef M68K
+/* Mappings from tm-m68k.h */
+
+static int regmap[] =
+{
+ X (regs[0]), /* d0 */
+ X (regs[1]), /* d1 */
+ X (regs[2]), /* d2 */
+ X (regs[3]), /* d3 */
+ X (regs[4]), /* d4 */
+ X (regs[5]), /* d5 */
+ X (regs[6]), /* d6 */
+ X (regs[7]), /* d7 */
+ X (regs[8]), /* a0 */
+ X (regs[9]), /* a1 */
+ X (regs[10]), /* a2 */
+ X (regs[11]), /* a3 */
+ X (regs[12]), /* a4 */
+ X (regs[13]), /* a5 */
+ X (regs[14]), /* fp */
+ offsetof (st_t, usp) - offsetof (st_t, ec), /* sp */
+ X (status), /* ps */
+ X (pc),
+
+ X (fregs[0 * 3]), /* fp0 */
+ X (fregs[1 * 3]), /* fp1 */
+ X (fregs[2 * 3]), /* fp2 */
+ X (fregs[3 * 3]), /* fp3 */
+ X (fregs[4 * 3]), /* fp4 */
+ X (fregs[5 * 3]), /* fp5 */
+ X (fregs[6 * 3]), /* fp6 */
+ X (fregs[7 * 3]), /* fp7 */
+
+ X (fcregs[0]), /* fpcontrol */
+ X (fcregs[1]), /* fpstatus */
+ X (fcregs[2]), /* fpiaddr */
+ X (ssw), /* fpcode */
+ X (fault), /* fpflags */
+};
+#endif /* M68K */
+
+#ifdef SPARC
+/* Mappings from tm-sparc.h */
+
+#define FX(ENTRY)(offsetof(struct fcontext, ENTRY))
+
+static int regmap[] =
+{
+ -1, /* g0 */
+ X (g1),
+ X (g2),
+ X (g3),
+ X (g4),
+ -1, /* g5->g7 aren't saved by Lynx */
+ -1,
+ -1,
+
+ X (o[0]),
+ X (o[1]),
+ X (o[2]),
+ X (o[3]),
+ X (o[4]),
+ X (o[5]),
+ X (o[6]), /* sp */
+ X (o[7]), /* ra */
+
+ -1, -1, -1, -1, -1, -1, -1, -1, /* l0 -> l7 */
+
+ -1, -1, -1, -1, -1, -1, -1, -1, /* i0 -> i7 */
+
+ FX (f.fregs[0]), /* f0 */
+ FX (f.fregs[1]),
+ FX (f.fregs[2]),
+ FX (f.fregs[3]),
+ FX (f.fregs[4]),
+ FX (f.fregs[5]),
+ FX (f.fregs[6]),
+ FX (f.fregs[7]),
+ FX (f.fregs[8]),
+ FX (f.fregs[9]),
+ FX (f.fregs[10]),
+ FX (f.fregs[11]),
+ FX (f.fregs[12]),
+ FX (f.fregs[13]),
+ FX (f.fregs[14]),
+ FX (f.fregs[15]),
+ FX (f.fregs[16]),
+ FX (f.fregs[17]),
+ FX (f.fregs[18]),
+ FX (f.fregs[19]),
+ FX (f.fregs[20]),
+ FX (f.fregs[21]),
+ FX (f.fregs[22]),
+ FX (f.fregs[23]),
+ FX (f.fregs[24]),
+ FX (f.fregs[25]),
+ FX (f.fregs[26]),
+ FX (f.fregs[27]),
+ FX (f.fregs[28]),
+ FX (f.fregs[29]),
+ FX (f.fregs[30]),
+ FX (f.fregs[31]),
+
+ X (y),
+ X (psr),
+ X (wim),
+ X (tbr),
+ X (pc),
+ X (npc),
+ FX (fsr), /* fpsr */
+ -1, /* cpsr */
+};
+#endif /* SPARC */
+
+#ifdef rs6000
+
+static int regmap[] =
+{
+ X (iregs[0]), /* r0 */
+ X (iregs[1]),
+ X (iregs[2]),
+ X (iregs[3]),
+ X (iregs[4]),
+ X (iregs[5]),
+ X (iregs[6]),
+ X (iregs[7]),
+ X (iregs[8]),
+ X (iregs[9]),
+ X (iregs[10]),
+ X (iregs[11]),
+ X (iregs[12]),
+ X (iregs[13]),
+ X (iregs[14]),
+ X (iregs[15]),
+ X (iregs[16]),
+ X (iregs[17]),
+ X (iregs[18]),
+ X (iregs[19]),
+ X (iregs[20]),
+ X (iregs[21]),
+ X (iregs[22]),
+ X (iregs[23]),
+ X (iregs[24]),
+ X (iregs[25]),
+ X (iregs[26]),
+ X (iregs[27]),
+ X (iregs[28]),
+ X (iregs[29]),
+ X (iregs[30]),
+ X (iregs[31]),
+
+ X (fregs[0]), /* f0 */
+ X (fregs[1]),
+ X (fregs[2]),
+ X (fregs[3]),
+ X (fregs[4]),
+ X (fregs[5]),
+ X (fregs[6]),
+ X (fregs[7]),
+ X (fregs[8]),
+ X (fregs[9]),
+ X (fregs[10]),
+ X (fregs[11]),
+ X (fregs[12]),
+ X (fregs[13]),
+ X (fregs[14]),
+ X (fregs[15]),
+ X (fregs[16]),
+ X (fregs[17]),
+ X (fregs[18]),
+ X (fregs[19]),
+ X (fregs[20]),
+ X (fregs[21]),
+ X (fregs[22]),
+ X (fregs[23]),
+ X (fregs[24]),
+ X (fregs[25]),
+ X (fregs[26]),
+ X (fregs[27]),
+ X (fregs[28]),
+ X (fregs[29]),
+ X (fregs[30]),
+ X (fregs[31]),
+
+ X (srr0), /* IAR (PC) */
+ X (srr1), /* MSR (PS) */
+ X (cr), /* CR */
+ X (lr), /* LR */
+ X (ctr), /* CTR */
+ X (xer), /* XER */
+ X (mq) /* MQ */
+};
+
+#endif /* rs6000 */
+
+#if defined (I386) || defined (M68K) || defined (rs6000)
+
+/* Return the offset relative to the start of the per-thread data to the
+ saved context block. */
+
+static unsigned long
+registers_addr (int pid)
+{
+ CORE_ADDR stblock;
+ int ecpoff = offsetof (st_t, ecp);
+ CORE_ADDR ecp;
+
+ errno = 0;
+ stblock = (CORE_ADDR) ptrace (PTRACE_THREADUSER, pid, (PTRACE_ARG3_TYPE) 0,
+ 0);
+ if (errno)
+ perror_with_name ("ptrace(PTRACE_THREADUSER)");
+
+ ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, pid, (PTRACE_ARG3_TYPE) ecpoff,
+ 0);
+ if (errno)
+ perror_with_name ("ptrace(PTRACE_PEEKTHREAD)");
+
+ return ecp - stblock;
+}
+
+/* Fetch one or more registers from the inferior. REGNO == -1 to get
+ them all. We actually fetch more than requested, when convenient,
+ marking them as valid so we won't fetch them again. */
+
+void
+fetch_inferior_registers (int regno)
+{
+ int reglo, reghi;
+ int i;
+ unsigned long ecp;
+
+ if (regno == -1)
+ {
+ reglo = 0;
+ reghi = NUM_REGS - 1;
+ }
+ else
+ reglo = reghi = regno;
+
+ ecp = registers_addr (PIDGET (inferior_ptid));
+
+ {
+ char buf[MAX_REGISTER_SIZE];
+ for (regno = reglo; regno <= reghi; regno++)
+ {
+ int ptrace_fun = PTRACE_PEEKTHREAD;
+
+#ifdef M68K
+ ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
+#endif
+
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ unsigned int reg;
+
+ errno = 0;
+ reg = ptrace (ptrace_fun, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), 0);
+ if (errno)
+ perror_with_name ("ptrace(PTRACE_PEEKUSP)");
+
+ *(int *) &buf[i] = reg;
+ }
+ supply_register (regno, buf);
+ }
+ }
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+
+void
+store_inferior_registers (int regno)
+{
+ int reglo, reghi;
+ int i;
+ unsigned long ecp;
+
+ if (regno == -1)
+ {
+ reglo = 0;
+ reghi = NUM_REGS - 1;
+ }
+ else
+ reglo = reghi = regno;
+
+ ecp = registers_addr (PIDGET (inferior_ptid));
+
+ for (regno = reglo; regno <= reghi; regno++)
+ {
+ int ptrace_fun = PTRACE_POKEUSER;
+
+ if (CANNOT_STORE_REGISTER (regno))
+ continue;
+
+#ifdef M68K
+ ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER;
+#endif
+
+ for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
+ {
+ unsigned int reg;
+
+ reg = *(unsigned int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno) + i];
+
+ errno = 0;
+ ptrace (ptrace_fun, PIDGET (inferior_ptid),
+ (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), reg);
+ if (errno)
+ perror_with_name ("ptrace(PTRACE_POKEUSP)");
+ }
+ }
+}
+#endif /* defined (I386) || defined (M68K) || defined (rs6000) */
+
+/* Wait for child to do something. Return pid of child, or -1 in case
+ of error; store status through argument pointer OURSTATUS. */
+
+ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+ int save_errno;
+ int thread;
+ union wait status;
+ int pid;
+
+ while (1)
+ {
+ int sig;
+
+ set_sigint_trap (); /* Causes SIGINT to be passed on to the
+ attached process. */
+ pid = wait (&status);
+
+ save_errno = errno;
+
+ clear_sigint_trap ();
+
+ if (pid == -1)
+ {
+ if (save_errno == EINTR)
+ continue;
+ fprintf_unfiltered (gdb_stderr, "Child process unexpectedly missing: %s.\n",
+ safe_strerror (save_errno));
+ /* Claim it exited with unknown signal. */
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ return -1;
+ }
+
+ if (pid != PIDGET (inferior_ptid)) /* Some other process?!? */
+ continue;
+
+ thread = status.w_tid; /* Get thread id from status */
+
+ /* Initial thread value can only be acquired via wait, so we have to
+ resort to this hack. */
+
+ if (TIDGET (inferior_ptid) == 0 && thread != 0)
+ {
+ inferior_ptid = MERGEPID (PIDGET (inferior_ptid), thread);
+ add_thread (inferior_ptid);
+ }
+
+ ptid = BUILDPID (pid, thread);
+
+ /* We've become a single threaded process again. */
+ if (thread == 0)
+ inferior_ptid = ptid;
+
+ /* Check for thread creation. */
+ if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGTRAP
+ && !in_thread_list (ptid))
+ {
+ int realsig;
+
+ realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid),
+ (PTRACE_ARG3_TYPE) 0, 0);
+
+ if (realsig == SIGNEWTHREAD)
+ {
+ /* It's a new thread notification. We don't want to much with
+ realsig -- the code in wait_for_inferior expects SIGTRAP. */
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ ourstatus->value.sig = TARGET_SIGNAL_0;
+ return ptid;
+ }
+ else
+ error ("Signal for unknown thread was not SIGNEWTHREAD");
+ }
+
+ /* Check for thread termination. */
+ else if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == SIGTRAP
+ && in_thread_list (ptid))
+ {
+ int realsig;
+
+ realsig = ptrace (PTRACE_GETTRACESIG, PIDGET (ptid),
+ (PTRACE_ARG3_TYPE) 0, 0);
+
+ if (realsig == SIGTHREADEXIT)
+ {
+ ptrace (PTRACE_CONT, PIDGET (ptid), (PTRACE_ARG3_TYPE) 0, 0);
+ continue;
+ }
+ }
+
+#ifdef SPARC
+ /* SPARC Lynx uses an byte reversed wait status; we must use the
+ host macros to access it. These lines just a copy of
+ store_waitstatus. We can't use CHILD_SPECIAL_WAITSTATUS
+ because target.c can't include the Lynx <sys/wait.h>. */
+ if (WIFEXITED (status))
+ {
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = WEXITSTATUS (status);
+ }
+ else if (!WIFSTOPPED (status))
+ {
+ ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+ ourstatus->value.sig =
+ target_signal_from_host (WTERMSIG (status));
+ }
+ else
+ {
+ ourstatus->kind = TARGET_WAITKIND_STOPPED;
+ ourstatus->value.sig =
+ target_signal_from_host (WSTOPSIG (status));
+ }
+#else
+ store_waitstatus (ourstatus, status.w_status);
+#endif
+
+ return ptid;
+ }
+}
+
+/* Return nonzero if the given thread is still alive. */
+int
+child_thread_alive (ptid_t ptid)
+{
+ int pid = PIDGET (ptid);
+
+ /* Arggh. Apparently pthread_kill only works for threads within
+ the process that calls pthread_kill.
+
+ We want to avoid the lynx signal extensions as they simply don't
+ map well to the generic gdb interface we want to keep.
+
+ All we want to do is determine if a particular thread is alive;
+ it appears as if we can just make a harmless thread specific
+ ptrace call to do that. */
+ return (ptrace (PTRACE_THREADUSER, pid, 0, 0) != -1);
+}
+
+/* Resume execution of the inferior process.
+ If STEP is nonzero, single-step it.
+ If SIGNAL is nonzero, give it that signal. */
+
+void
+child_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ int func;
+ int pid = PIDGET (ptid);
+
+ errno = 0;
+
+ /* If pid == -1, then we want to step/continue all threads, else
+ we only want to step/continue a single thread. */
+ if (pid == -1)
+ {
+ pid = PIDGET (inferior_ptid);
+ func = step ? PTRACE_SINGLESTEP : PTRACE_CONT;
+ }
+ else
+ func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT_ONE;
+
+
+ /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where
+ it was. (If GDB wanted it to start some other way, we have already
+ written a new PC value to the child.)
+
+ If this system does not support PT_STEP, a higher level function will
+ have called single_step() to transmute the step request into a
+ continue request (by setting breakpoints on all possible successor
+ instructions), so we don't have to worry about that here. */
+
+ ptrace (func, pid, (PTRACE_ARG3_TYPE) 1, target_signal_to_host (signal));
+
+ if (errno)
+ perror_with_name ("ptrace");
+}
+
+/* Convert a Lynx process ID to a string. Returns the string in a static
+ buffer. */
+
+char *
+child_pid_to_str (ptid_t ptid)
+{
+ static char buf[40];
+
+ sprintf (buf, "process %d thread %d", PIDGET (ptid), TIDGET (ptid));
+
+ return buf;
+}
+
+/* Extract the register values out of the core file and store
+ them where `read_register' will find them.
+
+ CORE_REG_SECT points to the register values themselves, read into memory.
+ CORE_REG_SIZE is the size of that area.
+ WHICH says which set of registers we are handling (0 = int, 2 = float
+ on machines where they are discontiguous).
+ REG_ADDR is the offset from u.u_ar0 to the register values relative to
+ core_reg_sect. This is used with old-fashioned core files to
+ locate the registers in a large upage-plus-stack ".reg" section.
+ Original upage address X is at location core_reg_sect+x+reg_addr.
+ */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR reg_addr)
+{
+ struct st_entry s;
+ unsigned int regno;
+
+ for (regno = 0; regno < NUM_REGS; regno++)
+ if (regmap[regno] != -1)
+ supply_register (regno, core_reg_sect + offsetof (st_t, ec)
+ + regmap[regno]);
+
+#ifdef SPARC
+/* Fetching this register causes all of the I & L regs to be read from the
+ stack and validated. */
+
+ fetch_inferior_registers (I0_REGNUM);
+#endif
+}
+
+
+/* Register that we are able to handle lynx core file formats.
+ FIXME: is this really bfd_target_unknown_flavour? */
+
+static struct core_fns lynx_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_lynx (void)
+{
+ add_core_fns (&lynx_core_fns);
+}
diff --git a/contrib/gdb/gdb/minimon.h b/contrib/gdb/gdb/minimon.h
new file mode 100644
index 0000000..94fd774
--- /dev/null
+++ b/contrib/gdb/gdb/minimon.h
@@ -0,0 +1,601 @@
+/* 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
new file mode 100644
index 0000000..cd4f045
--- /dev/null
+++ b/contrib/gdb/gdb/monitor.c
@@ -0,0 +1,2310 @@
+/* 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;
+
+ 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
+ {
+ /* 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, &register_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_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, DEPRECATED_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 (&register_strings, 0, sizeof (struct re_registers));
+
+ if (re_search (&register_pattern, buf, len, 0, len,
+ &register_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;
+}
+
+
+
+static 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)
+{
+ const char *name;
+ char *zerobuf;
+ char *regbuf;
+ int i;
+
+ regbuf = alloca (MAX_REGISTER_SIZE * 2 + 1);
+ zerobuf = alloca (MAX_REGISTER_SIZE);
+ memset (zerobuf, 0, MAX_REGISTER_SIZE);
+
+ if (current_monitor->regname != NULL)
+ name = current_monitor->regname (regno);
+ else
+ 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 < DEPRECATED_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)
+{
+ const char *name;
+ ULONGEST val;
+
+ if (current_monitor->regname != NULL)
+ name = current_monitor->regname (regno);
+ else
+ 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, DEPRECATED_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_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
+ 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;
+ const 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 = gdbarch_breakpoint_from_pc (current_gdbarch, &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_close = monitor_close;
+ monitor_ops.to_detach = monitor_detach;
+ monitor_ops.to_resume = monitor_resume;
+ monitor_ops.to_wait = monitor_wait;
+ 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_kill = monitor_kill;
+ monitor_ops.to_load = monitor_load;
+ monitor_ops.to_create_inferior = monitor_create_inferior;
+ monitor_ops.to_mourn_inferior = monitor_mourn_inferior;
+ monitor_ops.to_stop = monitor_stop;
+ monitor_ops.to_rcmd = monitor_rcmd;
+ monitor_ops.to_stratum = process_stratum;
+ 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_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. */
+
+extern initialize_file_ftype _initialize_remote_monitors; /* -Wmissing-prototypes */
+
+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
new file mode 100644
index 0000000..2f8ca22
--- /dev/null
+++ b/contrib/gdb/gdb/monitor.h
@@ -0,0 +1,260 @@
+/* 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 target_waitstatus;
+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 */
+ /* deprecated: use regname instead */
+ const char *(*regname) (int index);
+ /* function for dynamic regname array */
+ 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);
+/* Note: The variable argument functions monitor_printf and
+ monitor_printf_noecho vararg do not take take standard format style
+ arguments. Instead they take custom formats interpretered directly
+ by monitor_vsprintf. */
+extern void monitor_printf (char *, ...);
+extern void monitor_printf_noecho (char *, ...);
+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/ppcbug-rom.c b/contrib/gdb/gdb/ppcbug-rom.c
new file mode 100644
index 0000000..0619964
--- /dev/null
+++ b/contrib/gdb/gdb/ppcbug-rom.c
@@ -0,0 +1,225 @@
+/* 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);
+}
+
+extern initialize_file_ftype _initialize_ppcbug_rom; /* -Wmissing-prototypes */
+
+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
new file mode 100644
index 0000000..352b735
--- /dev/null
+++ b/contrib/gdb/gdb/procfs.c
@@ -0,0 +1,5960 @@
+/* Machine independent support for SVR4 /proc (process file system) for GDB.
+
+ Copyright 1999, 2000, 2001, 2002, 2003 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 "gdb_wait.h"
+#include <signal.h>
+#include <ctype.h>
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "inflow.h"
+#include "auxv.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 LONGEST procfs_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ void *readbuf, const void *writebuf,
+ ULONGEST offset, LONGEST len);
+
+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 *);
+
+static int procfs_can_use_hw_breakpoint (int, int, 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_partial = procfs_xfer_partial;
+ 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_save_ours = terminal_save_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_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
+ 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;
+}
+
+
+/* Convert a target address (a.k.a. CORE_ADDR) into a host address
+ (a.k.a void pointer)! */
+
+static void *
+procfs_address_to_host_pointer (CORE_ADDR addr)
+{
+ void *ptr;
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ return ptr;
+}
+
+/*
+ * 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;
+ /* NOTE: cagney/2003-02-01: Even more horrible hack. Need to
+ convert a target address into something that can be stored in a
+ native data structure. */
+#ifdef PCAGENT /* Horrible hack: only defined on Solaris 2.6+ */
+ pwatch->pr_vaddr = (uintptr_t) procfs_address_to_host_pointer (addr);
+#else
+ pwatch->pr_vaddr = (caddr_t) procfs_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 (signo == 0 && !proc_clear_current_signal (pi))
+ proc_warn (pi, "do_detach, clear_current_signal", __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
+ || regno == DEPRECATED_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
+ || regno == DEPRECATED_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) {
+#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;
+}
+
+/* Perform a partial transfer to/from the specified object. For
+ memory transfers, fall back to the old memory xfer functions. */
+
+static LONGEST
+procfs_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, void *readbuf,
+ const void *writebuf, ULONGEST offset, LONGEST len)
+{
+ switch (object)
+ {
+ case TARGET_OBJECT_MEMORY:
+ if (readbuf)
+ return (*ops->to_xfer_memory) (offset, readbuf, len, 0/*write*/,
+ NULL, ops);
+ if (writebuf)
+ return (*ops->to_xfer_memory) (offset, readbuf, len, 1/*write*/,
+ NULL, ops);
+ return -1;
+
+#ifdef NEW_PROC_API
+ case TARGET_OBJECT_AUXV:
+ return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
+ offset, len);
+#endif
+
+ default:
+ if (ops->beneath != NULL)
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len);
+ return -1;
+ }
+}
+
+
+/* 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)
+{
+ 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));
+
+ /* Typically two, one trap to exec the shell, one to exec the
+ program being debugged. Defined by "inferior.h". */
+ startup_inferior (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;
+}
+
+/* Return non-zero if we can set a hardware watchpoint of type TYPE. TYPE
+ is one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint,
+ or bp_hardware_watchpoint. CNT is the number of watchpoints used so
+ far.
+
+ Note: procfs_can_use_hw_breakpoint() is not yet used by all
+ procfs.c targets due to the fact that some of them still define
+ TARGET_CAN_USE_HARDWARE_WATCHPOINT. */
+
+static int
+procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
+{
+#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
+ return 0;
+#else
+ /* Due to the way that proc_set_watchpoint() is implemented, host
+ and target pointers must be of the same size. If they are not,
+ we can't use hardware watchpoints. This limitation is due to the
+ fact that proc_set_watchpoint() calls
+ procfs_address_to_host_pointer(); a close inspection of
+ procfs_address_to_host_pointer will reveal that an internal error
+ will be generated when the host and target pointer sizes are
+ different. */
+ if (sizeof (void *) != TYPE_LENGTH (builtin_type_void_data_ptr))
+ return 0;
+
+ /* Other tests here??? */
+
+ return 1;
+#endif
+}
+
+/*
+ * 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 (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'.
+ */
+
+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;
+ char *auxv;
+ int auxv_len;
+
+ 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;
+ }
+
+ auxv_len = target_auxv_read (&current_target, &auxv);
+ if (auxv_len > 0)
+ {
+ note_data = elfcore_write_note (obfd, note_data, note_size,
+ "CORE", NT_AUXV, auxv, auxv_len);
+ xfree (auxv);
+ }
+
+ 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-e7000.c b/contrib/gdb/gdb/remote-e7000.c
new file mode 100644
index 0000000..c422c94
--- /dev/null
+++ b/contrib/gdb/gdb/remote-e7000.c
@@ -0,0 +1,2194 @@
+/* Remote debugging interface for Renesas E7000 ICE, for GDB
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003 Free Software Foundation, Inc.
+
+ Contributed by Cygnus Support.
+
+ Written by Steve Chamberlain for 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. */
+
+/* The E7000 is an in-circuit emulator for the Renesas H8/300-H and
+ Renesas-SH processor. It has serial port and a lan port.
+
+ The monitor command set makes it difficult to load large ammounts of
+ data over the lan without using ftp - so try not to issue load
+ commands when communicating over ethernet; use the ftpload command.
+
+ The monitor pauses for a second when dumping srecords to the serial
+ line too, so we use a slower per byte mechanism but without the
+ startup overhead. Even so, it's pretty slow... */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "gdbarch.h"
+#include "inferior.h"
+#include "target.h"
+#include "value.h"
+#include "command.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include <sys/types.h>
+#include "serial.h"
+#include "remote-utils.h"
+#include "symfile.h"
+#include "regcache.h"
+#include <time.h>
+#include <ctype.h>
+
+
+#if 1
+#define HARD_BREAKPOINTS /* Now handled by set option. */
+#define BC_BREAKPOINTS use_hard_breakpoints
+#endif
+
+#define CTRLC 0x03
+#define ENQ 0x05
+#define ACK 0x06
+#define CTRLZ 0x1a
+
+/* This file is used by 2 different targets, sh-elf and h8300. The
+ h8300 is not multiarched and doesn't use the registers defined in
+ tm-sh.h. To avoid using a macro GDB_TARGET_IS_SH, we do runtime check
+ of the target, which requires that these namse below are always
+ defined also in the h8300 case. */
+
+#if !defined (PR_REGNUM)
+#define PR_REGNUM -1
+#endif
+#if !defined (GBR_REGNUM)
+#define GBR_REGNUM -1
+#endif
+#if !defined (VBR_REGNUM)
+#define VBR_REGNUM -1
+#endif
+#if !defined (MACH_REGNUM)
+#define MACH_REGNUM -1
+#endif
+#if !defined (MACL_REGNUM)
+#define MACL_REGNUM -1
+#endif
+#if !defined (SR_REGNUM)
+#define SR_REGNUM -1
+#endif
+
+extern void report_transfer_performance (unsigned long, time_t, time_t);
+
+extern char *sh_processor_type;
+
+/* Local function declarations. */
+
+static void e7000_close (int);
+
+static void e7000_fetch_register (int);
+
+static void e7000_store_register (int);
+
+static void e7000_command (char *, int);
+
+static void e7000_login_command (char *, int);
+
+static void e7000_ftp_command (char *, int);
+
+static void e7000_drain_command (char *, int);
+
+static void expect (char *);
+
+static void expect_full_prompt (void);
+
+static void expect_prompt (void);
+
+static int e7000_parse_device (char *args, char *dev_name, int baudrate);
+/* Variables. */
+
+static struct serial *e7000_desc;
+
+/* Allow user to chose between using hardware breakpoints or memory. */
+static int use_hard_breakpoints = 0; /* use sw breakpoints by default */
+
+/* Nonzero if using the tcp serial driver. */
+
+static int using_tcp; /* direct tcp connection to target */
+static int using_tcp_remote; /* indirect connection to target
+ via tcp to controller */
+
+/* Nonzero if using the pc isa card. */
+
+static int using_pc;
+
+extern struct target_ops e7000_ops; /* Forward declaration */
+
+char *ENQSTRING = "\005";
+
+/* Nonzero if some routine (as opposed to the user) wants echoing.
+ FIXME: Do this reentrantly with an extra parameter. */
+
+static int echo;
+
+static int ctrl_c;
+
+static int timeout = 20;
+
+/* Send data to e7000debug. */
+
+static void
+puts_e7000debug (char *buf)
+{
+ if (!e7000_desc)
+ error ("Use \"target e7000 ...\" first.");
+
+ if (remote_debug)
+ printf_unfiltered ("Sending %s\n", buf);
+
+ if (serial_write (e7000_desc, buf, strlen (buf)))
+ fprintf_unfiltered (gdb_stderr, "serial_write failed: %s\n", safe_strerror (errno));
+
+ /* And expect to see it echoed, unless using the pc interface */
+#if 0
+ if (!using_pc)
+#endif
+ expect (buf);
+}
+
+static void
+putchar_e7000 (int x)
+{
+ char b[1];
+
+ b[0] = x;
+ serial_write (e7000_desc, b, 1);
+}
+
+static void
+write_e7000 (char *s)
+{
+ serial_write (e7000_desc, s, strlen (s));
+}
+
+static int
+normal (int x)
+{
+ if (x == '\n')
+ return '\r';
+ return x;
+}
+
+/* Read a character from the remote system, doing all the fancy timeout
+ stuff. Handles serial errors and EOF. If TIMEOUT == 0, and no chars,
+ returns -1, else returns next char. Discards chars > 127. */
+
+static int
+readchar (int timeout)
+{
+ int c;
+
+ do
+ {
+ c = serial_readchar (e7000_desc, timeout);
+ }
+ while (c > 127);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (timeout == 0)
+ return -1;
+ echo = 0;
+ error ("Timeout reading from remote system.");
+ }
+ else if (c < 0)
+ error ("Serial communication error");
+
+ if (remote_debug)
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_stdout);
+ }
+
+ return normal (c);
+}
+
+#if 0
+char *
+tl (int x)
+{
+ static char b[8][10];
+ static int p;
+
+ p++;
+ p &= 7;
+ if (x >= ' ')
+ {
+ b[p][0] = x;
+ b[p][1] = 0;
+ }
+ else
+ {
+ sprintf (b[p], "<%d>", x);
+ }
+
+ return b[p];
+}
+#endif
+
+/* 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)
+{
+ char *p = string;
+ int c;
+ int nl = 0;
+
+ while (1)
+ {
+ c = readchar (timeout);
+
+ if (echo)
+ {
+ if (c == '\r' || c == '\n')
+ {
+ if (!nl)
+ putchar_unfiltered ('\n');
+ nl = 1;
+ }
+ else
+ {
+ nl = 0;
+ putchar_unfiltered (c);
+ }
+ gdb_flush (gdb_stdout);
+ }
+ if (normal (c) == normal (*p++))
+ {
+ if (*p == '\0')
+ return;
+ }
+ else
+ {
+ p = string;
+
+ if (normal (c) == normal (string[0]))
+ p++;
+ }
+ }
+}
+
+/* Keep discarding input until we see the e7000 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: e7000_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
+ e7000_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 (void)
+{
+ expect (":");
+}
+
+static void
+expect_full_prompt (void)
+{
+ expect ("\r:");
+}
+
+static int
+convert_hex_digit (int ch)
+{
+ 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;
+ return -1;
+}
+
+static int
+get_hex (int *start)
+{
+ int value = convert_hex_digit (*start);
+ int try;
+
+ *start = readchar (timeout);
+ while ((try = convert_hex_digit (*start)) >= 0)
+ {
+ value <<= 4;
+ value += try;
+ *start = readchar (timeout);
+ }
+ return value;
+}
+
+#if 0
+/* 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);
+ }
+}
+#endif
+
+/* This is called not only when we first attach, but also when the
+ user types "run" after having attached. */
+
+static void
+e7000_create_inferior (char *execfile, char *args, char **env)
+{
+ int entry_pt;
+
+ if (args && *args)
+ error ("Can't pass arguments to remote E7000DEBUG process");
+
+ if (execfile == 0 || exec_bfd == 0)
+ error ("No executable file specified");
+
+ entry_pt = (int) bfd_get_start_address (exec_bfd);
+
+#ifdef CREATE_INFERIOR_HOOK
+ CREATE_INFERIOR_HOOK (0); /* No process-ID */
+#endif
+
+ /* 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? */
+ proceed ((CORE_ADDR) entry_pt, -1, 0); /* Let 'er rip... */
+}
+
+/* Open a connection to a remote debugger. NAME is the filename used
+ for communication. */
+
+static int baudrate = 9600;
+static char dev_name[100];
+
+static char *machine = "";
+static char *user = "";
+static char *passwd = "";
+static char *dir = "";
+
+/* Grab the next token and buy some space for it */
+
+static char *
+next (char **ptr)
+{
+ char *p = *ptr;
+ char *s;
+ char *r;
+ int l = 0;
+
+ while (*p && *p == ' ')
+ p++;
+ s = p;
+ while (*p && (*p != ' ' && *p != '\t'))
+ {
+ l++;
+ p++;
+ }
+ r = xmalloc (l + 1);
+ memcpy (r, s, l);
+ r[l] = 0;
+ *ptr = p;
+ return r;
+}
+
+static void
+e7000_login_command (char *args, int from_tty)
+{
+ if (args)
+ {
+ machine = next (&args);
+ user = next (&args);
+ passwd = next (&args);
+ dir = next (&args);
+ if (from_tty)
+ {
+ printf_unfiltered ("Set info to %s %s %s %s\n", machine, user, passwd, dir);
+ }
+ }
+ else
+ {
+ error ("Syntax is ftplogin <machine> <user> <passwd> <directory>");
+ }
+}
+
+/* Start an ftp transfer from the E7000 to a host */
+
+static void
+e7000_ftp_command (char *args, int from_tty)
+{
+ /* FIXME: arbitrary limit on machine names and such. */
+ char buf[200];
+
+ int oldtimeout = timeout;
+ timeout = remote_timeout;
+
+ sprintf (buf, "ftp %s\r", machine);
+ puts_e7000debug (buf);
+ expect (" Username : ");
+ sprintf (buf, "%s\r", user);
+ puts_e7000debug (buf);
+ expect (" Password : ");
+ write_e7000 (passwd);
+ write_e7000 ("\r");
+ expect ("success\r");
+ expect ("FTP>");
+ sprintf (buf, "cd %s\r", dir);
+ puts_e7000debug (buf);
+ expect ("FTP>");
+ sprintf (buf, "ll 0;s:%s\r", args);
+ puts_e7000debug (buf);
+ expect ("FTP>");
+ puts_e7000debug ("bye\r");
+ expect (":");
+ timeout = oldtimeout;
+}
+
+static int
+e7000_parse_device (char *args, char *dev_name, int baudrate)
+{
+ char junk[128];
+ int n = 0;
+ if (args && strcasecmp (args, "pc") == 0)
+ {
+ strcpy (dev_name, args);
+ using_pc = 1;
+ }
+ else
+ {
+ /* FIXME! temp hack to allow use with port master -
+ target tcp_remote <device> */
+ if (args && strncmp (args, "tcp", 10) == 0)
+ {
+ char com_type[128];
+ n = sscanf (args, " %s %s %d %s", com_type, dev_name, &baudrate, junk);
+ using_tcp_remote = 1;
+ n--;
+ }
+ else if (args)
+ {
+ n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk);
+ }
+
+ if (n != 1 && n != 2)
+ {
+ error ("Bad arguments. Usage:\ttarget e7000 <device> <speed>\n\
+or \t\ttarget e7000 <host>[:<port>]\n\
+or \t\ttarget e7000 tcp_remote <host>[:<port>]\n\
+or \t\ttarget e7000 pc\n");
+ }
+
+#if !defined(__GO32__) && !defined(_WIN32) && !defined(__CYGWIN__)
+ /* FIXME! test for ':' is ambiguous */
+ if (n == 1 && strchr (dev_name, ':') == 0)
+ {
+ /* Default to normal telnet port */
+ /* serial_open will use this to determine tcp communication */
+ strcat (dev_name, ":23");
+ }
+#endif
+ if (!using_tcp_remote && strchr (dev_name, ':'))
+ using_tcp = 1;
+ }
+
+ return n;
+}
+
+/* Stub for catch_errors. */
+
+static int
+e7000_start_remote (void *dummy)
+{
+ int loop;
+ int sync;
+ int try;
+ int quit_trying;
+
+ immediate_quit++; /* Allow user to interrupt it */
+
+ /* Hello? Are you there? */
+ sync = 0;
+ loop = 0;
+ try = 0;
+ quit_trying = 20;
+ putchar_e7000 (CTRLC);
+ while (!sync && ++try <= quit_trying)
+ {
+ int c;
+
+ printf_unfiltered ("[waiting for e7000...]\n");
+
+ write_e7000 ("\r");
+ c = readchar (1);
+
+ /* FIXME! this didn't seem right-> while (c != SERIAL_TIMEOUT)
+ * we get stuck in this loop ...
+ * We may never timeout, and never sync up :-(
+ */
+ while (!sync && c != -1)
+ {
+ /* Dont echo cr's */
+ if (c != '\r')
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_stdout);
+ }
+ /* Shouldn't we either break here, or check for sync in inner loop? */
+ if (c == ':')
+ sync = 1;
+
+ if (loop++ == 20)
+ {
+ putchar_e7000 (CTRLC);
+ loop = 0;
+ }
+
+ QUIT;
+
+ if (quit_flag)
+ {
+ putchar_e7000 (CTRLC);
+ /* Was-> quit_flag = 0; */
+ c = -1;
+ quit_trying = try + 1; /* we don't want to try anymore */
+ }
+ else
+ {
+ c = readchar (1);
+ }
+ }
+ }
+
+ if (!sync)
+ {
+ fprintf_unfiltered (gdb_stderr, "Giving up after %d tries...\n", try);
+ error ("Unable to synchronize with target.\n");
+ }
+
+ puts_e7000debug ("\r");
+ expect_prompt ();
+ puts_e7000debug ("b -\r"); /* Clear breakpoints */
+ expect_prompt ();
+
+ immediate_quit--;
+
+/* 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. */
+
+ flush_cached_frames ();
+ registers_changed ();
+ stop_pc = read_pc ();
+ print_stack_frame (get_selected_frame (), -1, 1);
+
+ return 1;
+}
+
+static void
+e7000_open (char *args, int from_tty)
+{
+ int n;
+
+ target_preopen (from_tty);
+
+ n = e7000_parse_device (args, dev_name, baudrate);
+
+ push_target (&e7000_ops);
+
+ e7000_desc = serial_open (dev_name);
+
+ if (!e7000_desc)
+ perror_with_name (dev_name);
+
+ if (serial_setbaudrate (e7000_desc, baudrate))
+ {
+ serial_close (e7000_desc);
+ perror_with_name (dev_name);
+ }
+ serial_raw (e7000_desc);
+
+ /* Start the remote connection; if error (0), discard this target.
+ In particular, if the user quits, be sure to discard it
+ (we'd be in an inconsistent state otherwise). */
+ if (!catch_errors (e7000_start_remote, (char *) 0,
+ "Couldn't establish connection to remote target\n", RETURN_MASK_ALL))
+ if (from_tty)
+ printf_filtered ("Remote target %s connected to %s\n", target_shortname,
+ dev_name);
+}
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+e7000_close (int quitting)
+{
+ if (e7000_desc)
+ {
+ serial_close (e7000_desc);
+ e7000_desc = 0;
+ }
+}
+
+/* Terminate the open connection to the remote debugger. Use this
+ when you want to detach and do something else with your gdb. */
+
+static void
+e7000_detach (char *arg, int from_tty)
+{
+ pop_target (); /* calls e7000_close to do the real work */
+ if (from_tty)
+ printf_unfiltered ("Ending remote %s debugging\n", target_shortname);
+}
+
+/* Tell the remote machine to resume. */
+
+static void
+e7000_resume (ptid_t ptid, int step, enum target_signal sigal)
+{
+ if (step)
+ puts_e7000debug ("S\r");
+ else
+ puts_e7000debug ("G\r");
+}
+
+/* Read the remote registers into the block REGS.
+
+ For the H8/300 a register dump looks like:
+
+ PC=00021A CCR=80:I*******
+ ER0 - ER3 0000000A 0000002E 0000002E 00000000
+ ER4 - ER7 00000000 00000000 00000000 00FFEFF6
+ 000218 MOV.B R1L,R2L
+ STEP NORMAL END or
+ BREAK POINT
+ */
+
+char *want_h8300h = "PC=%p CCR=%c\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7\n";
+
+char *want_nopc_h8300h = "%p CCR=%c\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7";
+
+char *want_h8300s = "PC=%p CCR=%c\n\
+ MACH=\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7\n";
+
+char *want_nopc_h8300s = "%p CCR=%c EXR=%9\n\
+ ER0 - ER3 %0 %1 %2 %3\n\
+ ER4 - ER7 %4 %5 %6 %7";
+
+char *want_sh = "PC=%16 SR=%22\n\
+PR=%17 GBR=%18 VBR=%19\n\
+MACH=%20 MACL=%21\n\
+R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n";
+
+char *want_nopc_sh = "%16 SR=%22\n\
+ PR=%17 GBR=%18 VBR=%19\n\
+ MACH=%20 MACL=%21\n\
+ R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+ R8-15 %8 %9 %10 %11 %12 %13 %14 %15";
+
+char *want_sh3 = "PC=%16 SR=%22\n\
+PR=%17 GBR=%18 VBR=%19\n\
+MACH=%20 MACL=%21 SSR=%23 SPC=%24\n\
+R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
+char *want_nopc_sh3 = "%16 SR=%22\n\
+ PR=%17 GBR=%18 VBR=%19\n\
+ MACH=%20 MACL=%21 SSR=%22 SPC=%23\n\
+ R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\
+ R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\
+ R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\
+ R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\
+ R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\
+ R4_BANK1-R7_BANK1 %37 %38 %39 %40";
+
+static int
+gch (void)
+{
+ return readchar (timeout);
+}
+
+static unsigned int
+gbyte (void)
+{
+ int high = convert_hex_digit (gch ());
+ int low = convert_hex_digit (gch ());
+
+ return (high << 4) + low;
+}
+
+static void
+fetch_regs_from_dump (int (*nextchar) (), char *want)
+{
+ int regno;
+ char buf[MAX_REGISTER_SIZE];
+
+ int thischar = nextchar ();
+
+ if (want == NULL)
+ internal_error (__FILE__, __LINE__, "Register set not selected.");
+
+ while (*want)
+ {
+ switch (*want)
+ {
+ case '\n':
+ /* Skip to end of line and then eat all new line type stuff */
+ while (thischar != '\n' && thischar != '\r')
+ thischar = nextchar ();
+ while (thischar == '\n' || thischar == '\r')
+ thischar = nextchar ();
+ want++;
+ break;
+
+ case ' ':
+ while (thischar == ' '
+ || thischar == '\t'
+ || thischar == '\r'
+ || thischar == '\n')
+ thischar = nextchar ();
+ want++;
+ break;
+
+ default:
+ if (*want == thischar)
+ {
+ want++;
+ if (*want)
+ thischar = nextchar ();
+
+ }
+ else if (thischar == ' ' || thischar == '\n' || thischar == '\r')
+ {
+ thischar = nextchar ();
+ }
+ else
+ {
+ error ("out of sync in fetch registers wanted <%s>, got <%c 0x%x>",
+ want, thischar, thischar);
+ }
+
+ break;
+ case '%':
+ /* Got a register command */
+ want++;
+ switch (*want)
+ {
+#ifdef PC_REGNUM
+ case 'p':
+ regno = PC_REGNUM;
+ want++;
+ break;
+#endif
+#ifdef CCR_REGNUM
+ case 'c':
+ regno = CCR_REGNUM;
+ want++;
+ break;
+#endif
+#ifdef SP_REGNUM
+ case 's':
+ regno = SP_REGNUM;
+ want++;
+ break;
+#endif
+#ifdef DEPRECATED_FP_REGNUM
+ case 'f':
+ regno = DEPRECATED_FP_REGNUM;
+ want++;
+ break;
+#endif
+
+ default:
+ if (isdigit (want[0]))
+ {
+ if (isdigit (want[1]))
+ {
+ regno = (want[0] - '0') * 10 + want[1] - '0';
+ want += 2;
+ }
+ else
+ {
+ regno = want[0] - '0';
+ want++;
+ }
+ }
+
+ else
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ store_signed_integer (buf,
+ DEPRECATED_REGISTER_RAW_SIZE (regno),
+ (LONGEST) get_hex (&thischar));
+ supply_register (regno, buf);
+ break;
+ }
+ }
+}
+
+static void
+e7000_fetch_registers (void)
+{
+ int regno;
+ char *wanted = NULL;
+
+ puts_e7000debug ("R\r");
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ wanted = want_sh;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_sh3:
+ case bfd_mach_sh3e:
+ case bfd_mach_sh4:
+ wanted = want_sh3;
+ }
+ }
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ wanted = want_h8300h;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_h8300s:
+ case bfd_mach_h8300sn:
+ case bfd_mach_h8300sx:
+ case bfd_mach_h8300sxn:
+ wanted = want_h8300s;
+ }
+ }
+
+ fetch_regs_from_dump (gch, wanted);
+
+ /* And supply the extra ones the simulator uses */
+ for (regno = NUM_REALREGS; regno < NUM_REGS; regno++)
+ {
+ int buf = 0;
+
+ supply_register (regno, (char *) (&buf));
+ }
+}
+
+/* Fetch register REGNO, or all registers if REGNO is -1. Returns
+ errno value. */
+
+static void
+e7000_fetch_register (int regno)
+{
+ e7000_fetch_registers ();
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+static void
+e7000_store_registers (void)
+{
+ int regno;
+
+ for (regno = 0; regno < NUM_REALREGS; regno++)
+ e7000_store_register (regno);
+
+ registers_changed ();
+}
+
+/* Store register REGNO, or all if REGNO == 0. Return errno value. */
+
+static void
+e7000_store_register (int regno)
+{
+ char buf[200];
+
+ if (regno == -1)
+ {
+ e7000_store_registers ();
+ return;
+ }
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ if (regno <= 7)
+ {
+ sprintf (buf, ".ER%d %s\r", regno, phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ else if (regno == PC_REGNUM)
+ {
+ sprintf (buf, ".PC %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+#ifdef CCR_REGNUM
+ else if (regno == CCR_REGNUM)
+ {
+ sprintf (buf, ".CCR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+#endif
+ }
+
+ else if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ if (regno == PC_REGNUM)
+ {
+ sprintf (buf, ".PC %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == SR_REGNUM)
+ {
+ sprintf (buf, ".SR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == PR_REGNUM)
+ {
+ sprintf (buf, ".PR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == GBR_REGNUM)
+ {
+ sprintf (buf, ".GBR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == VBR_REGNUM)
+ {
+ sprintf (buf, ".VBR %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == MACH_REGNUM)
+ {
+ sprintf (buf, ".MACH %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+
+ else if (regno == MACL_REGNUM)
+ {
+ sprintf (buf, ".MACL %s\r", phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ else
+ {
+ sprintf (buf, ".R%d %s\r", regno, phex_nz (read_register (regno), 0));
+ puts_e7000debug (buf);
+ }
+ }
+
+ expect_prompt ();
+}
+
+/* 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
+e7000_prepare_to_store (void)
+{
+ /* Do nothing, since we can store individual regs */
+}
+
+static void
+e7000_files_info (struct target_ops *ops)
+{
+ printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baudrate);
+}
+
+static int
+stickbyte (char *where, unsigned int what)
+{
+ static CONST char digs[] = "0123456789ABCDEF";
+
+ where[0] = digs[(what >> 4) & 0xf];
+ where[1] = digs[(what & 0xf) & 0xf];
+
+ return what;
+}
+
+/* Write a small ammount of memory. */
+
+static int
+write_small (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+ int i;
+ char buf[200];
+
+ for (i = 0; i < len; i++)
+ {
+ if (((memaddr + i) & 3) == 0 && (i + 3 < len))
+ {
+ /* Can be done with a long word */
+ sprintf (buf, "m %s %x%02x%02x%02x;l\r",
+ paddr_nz (memaddr + i),
+ myaddr[i], myaddr[i + 1], myaddr[i + 2], myaddr[i + 3]);
+ puts_e7000debug (buf);
+ i += 3;
+ }
+ else
+ {
+ sprintf (buf, "m %s %x\r", paddr_nz (memaddr + i), myaddr[i]);
+ puts_e7000debug (buf);
+ }
+ }
+
+ expect_prompt ();
+
+ return len;
+}
+
+/* Write a large ammount of memory, this only works with the serial
+ mode enabled. Command is sent as
+
+ il ;s:s\r ->
+ <- il ;s:s\r
+ <- ENQ
+ ACK ->
+ <- LO s\r
+ Srecords...
+ ^Z ->
+ <- ENQ
+ ACK ->
+ <- :
+ */
+
+static int
+write_large (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+ int i;
+#define maxstride 128
+ int stride;
+
+ puts_e7000debug ("IL ;S:FK\r");
+ expect (ENQSTRING);
+ putchar_e7000 (ACK);
+ expect ("LO FK\r");
+
+ for (i = 0; i < len; i += stride)
+ {
+ char compose[maxstride * 2 + 50];
+ int address = i + memaddr;
+ int j;
+ int check_sum;
+ int where = 0;
+ int alen;
+
+ stride = len - i;
+ if (stride > maxstride)
+ stride = maxstride;
+
+ compose[where++] = 'S';
+ check_sum = 0;
+ if (address >= 0xffffff)
+ alen = 4;
+ else if (address >= 0xffff)
+ alen = 3;
+ else
+ alen = 2;
+ /* Insert type. */
+ compose[where++] = alen - 1 + '0';
+ /* Insert length. */
+ check_sum += stickbyte (compose + where, alen + stride + 1);
+ where += 2;
+ while (alen > 0)
+ {
+ alen--;
+ check_sum += stickbyte (compose + where, address >> (8 * (alen)));
+ where += 2;
+ }
+
+ for (j = 0; j < stride; j++)
+ {
+ check_sum += stickbyte (compose + where, myaddr[i + j]);
+ where += 2;
+ }
+ stickbyte (compose + where, ~check_sum);
+ where += 2;
+ compose[where++] = '\r';
+ compose[where++] = '\n';
+ compose[where++] = 0;
+
+ serial_write (e7000_desc, compose, where);
+ j = readchar (0);
+ if (j == -1)
+ {
+ /* This is ok - nothing there */
+ }
+ else if (j == ENQ)
+ {
+ /* Hmm, it's trying to tell us something */
+ expect (":");
+ error ("Error writing memory");
+ }
+ else
+ {
+ printf_unfiltered ("@%d}@", j);
+ while ((j = readchar (0)) > 0)
+ {
+ printf_unfiltered ("@{%d}@", j);
+ }
+ }
+ }
+
+ /* Send the trailer record */
+ write_e7000 ("S70500000000FA\r");
+ putchar_e7000 (CTRLZ);
+ expect (ENQSTRING);
+ putchar_e7000 (ACK);
+ expect (":");
+
+ return len;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
+ memory at MEMADDR. Returns length moved.
+
+ Can't use the Srecord load over ethernet, so don't use fast method
+ then. */
+
+static int
+e7000_write_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+ if (len < 16 || using_tcp || using_pc)
+ return write_small (memaddr, myaddr, len);
+ else
+ return write_large (memaddr, myaddr, len);
+}
+
+/* Read LEN bytes from inferior memory at MEMADDR. Put the result
+ at debugger address MYADDR. Returns length moved.
+
+ Small transactions we send
+ m <addr>;l
+ and receive
+ 00000000 12345678 ?
+ */
+
+static int
+e7000_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+ int count;
+ int c;
+ int i;
+ char buf[200];
+ /* Starting address of this pass. */
+
+/* printf("READ INF %x %x %d\n", memaddr, myaddr, len); */
+ if (((memaddr - 1) + len) < memaddr)
+ {
+ errno = EIO;
+ return 0;
+ }
+
+ sprintf (buf, "m %s;l\r", paddr_nz (memaddr));
+ puts_e7000debug (buf);
+
+ for (count = 0; count < len; count += 4)
+ {
+ /* Suck away the address */
+ c = gch ();
+ while (c != ' ')
+ c = gch ();
+ c = gch ();
+ if (c == '*')
+ { /* Some kind of error */
+ puts_e7000debug (".\r"); /* Some errors leave us in memory input mode */
+ expect_full_prompt ();
+ return -1;
+ }
+ while (c != ' ')
+ c = gch ();
+
+ /* Now read in the data */
+ for (i = 0; i < 4; i++)
+ {
+ int b = gbyte ();
+ if (count + i < len)
+ {
+ myaddr[count + i] = b;
+ }
+ }
+
+ /* Skip the trailing ? and send a . to end and a cr for more */
+ gch ();
+ gch ();
+ if (count + 4 >= len)
+ puts_e7000debug (".\r");
+ else
+ puts_e7000debug ("\r");
+
+ }
+ expect_prompt ();
+ return len;
+}
+
+
+
+/*
+ For large transfers we used to send
+
+
+ d <addr> <endaddr>\r
+
+ and receive
+ <ADDRESS> < D A T A > < ASCII CODE >
+ 00000000 5F FD FD FF DF 7F DF FF 01 00 01 00 02 00 08 04 "_..............."
+ 00000010 FF D7 FF 7F D7 F1 7F FF 00 05 00 00 08 00 40 00 "..............@."
+ 00000020 7F FD FF F7 7F FF FF F7 00 00 00 00 00 00 00 00 "................"
+
+ A cost in chars for each transaction of 80 + 5*n-bytes.
+
+ Large transactions could be done with the srecord load code, but
+ there is a pause for a second before dumping starts, which slows the
+ average rate down!
+ */
+
+static int
+e7000_read_inferior_memory_large (CORE_ADDR memaddr, unsigned char *myaddr,
+ int len)
+{
+ int count;
+ int c;
+ char buf[200];
+
+ /* Starting address of this pass. */
+
+ if (((memaddr - 1) + len) < memaddr)
+ {
+ errno = EIO;
+ return 0;
+ }
+
+ sprintf (buf, "d %s %s\r", paddr_nz (memaddr), paddr_nz (memaddr + len - 1));
+ puts_e7000debug (buf);
+
+ count = 0;
+ c = gch ();
+
+ /* skip down to the first ">" */
+ while (c != '>')
+ c = gch ();
+ /* now skip to the end of that line */
+ while (c != '\r')
+ c = gch ();
+ c = gch ();
+
+ while (count < len)
+ {
+ /* get rid of any white space before the address */
+ while (c <= ' ')
+ c = gch ();
+
+ /* Skip the address */
+ get_hex (&c);
+
+ /* read in the bytes on the line */
+ while (c != '"' && count < len)
+ {
+ if (c == ' ')
+ c = gch ();
+ else
+ {
+ myaddr[count++] = get_hex (&c);
+ }
+ }
+ /* throw out the rest of the line */
+ while (c != '\r')
+ c = gch ();
+ }
+
+ /* wait for the ":" prompt */
+ while (c != ':')
+ c = gch ();
+
+ return len;
+}
+
+#if 0
+
+static int
+fast_but_for_the_pause_e7000_read_inferior_memory (CORE_ADDR memaddr,
+ char *myaddr, int len)
+{
+ int loop;
+ int c;
+ char buf[200];
+
+ if (((memaddr - 1) + len) < memaddr)
+ {
+ errno = EIO;
+ return 0;
+ }
+
+ sprintf (buf, "is %x@%x:s\r", memaddr, len);
+ puts_e7000debug (buf);
+ gch ();
+ c = gch ();
+ if (c != ENQ)
+ {
+ /* Got an error */
+ error ("Memory read error");
+ }
+ putchar_e7000 (ACK);
+ expect ("SV s");
+ loop = 1;
+ while (loop)
+ {
+ int type;
+ int length;
+ int addr;
+ int i;
+
+ c = gch ();
+ switch (c)
+ {
+ case ENQ: /* ENQ, at the end */
+ loop = 0;
+ break;
+ case 'S':
+ /* Start of an Srecord */
+ type = gch ();
+ length = gbyte ();
+ switch (type)
+ {
+ case '7': /* Termination record, ignore */
+ case '0':
+ case '8':
+ case '9':
+ /* Header record - ignore it */
+ while (length--)
+ {
+ gbyte ();
+ }
+ break;
+ case '1':
+ case '2':
+ case '3':
+ {
+ int alen;
+
+ alen = type - '0' + 1;
+ addr = 0;
+ while (alen--)
+ {
+ addr = (addr << 8) + gbyte ();
+ length--;
+ }
+
+ for (i = 0; i < length - 1; i++)
+ myaddr[i + addr - memaddr] = gbyte ();
+
+ gbyte (); /* Ignore checksum */
+ }
+ }
+ }
+ }
+
+ putchar_e7000 (ACK);
+ expect ("TOP ADDRESS =");
+ expect ("END ADDRESS =");
+ expect (":");
+
+ return len;
+}
+
+#endif
+
+/* 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
+e7000_xfer_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len,
+ int write, struct mem_attrib *attrib,
+ struct target_ops *target)
+{
+ if (write)
+ return e7000_write_inferior_memory (memaddr, myaddr, len);
+ else if (len < 16)
+ return e7000_read_inferior_memory (memaddr, myaddr, len);
+ else
+ return e7000_read_inferior_memory_large (memaddr, myaddr, len);
+}
+
+static void
+e7000_kill (void)
+{
+}
+
+static void
+e7000_load (char *args, int from_tty)
+{
+ struct cleanup *old_chain;
+ asection *section;
+ bfd *pbfd;
+ bfd_vma entry;
+#define WRITESIZE 0x1000
+ char buf[2 + 4 + 4 + WRITESIZE]; /* `DT' + <addr> + <len> + <data> */
+ char *filename;
+ int quiet;
+ int nostart;
+ time_t start_time, end_time; /* Start and end times of download */
+ unsigned long data_count; /* Number of bytes transferred to memory */
+ int oldtimeout = timeout;
+
+ timeout = remote_timeout;
+
+
+ /* FIXME! change test to test for type of download */
+ if (!using_tcp)
+ {
+ generic_load (args, from_tty);
+ return;
+ }
+
+ /* for direct tcp connections, we can do a fast binary download */
+ buf[0] = 'D';
+ buf[1] = 'T';
+ quiet = 0;
+ nostart = 0;
+ filename = NULL;
+
+ while (*args != '\000')
+ {
+ char *arg;
+
+ while (isspace (*args))
+ args++;
+
+ arg = args;
+
+ while ((*args != '\000') && !isspace (*args))
+ args++;
+
+ if (*args != '\000')
+ *args++ = '\000';
+
+ if (*arg != '-')
+ filename = arg;
+ else if (strncmp (arg, "-quiet", strlen (arg)) == 0)
+ quiet = 1;
+ else if (strncmp (arg, "-nostart", strlen (arg)) == 0)
+ nostart = 1;
+ else
+ error ("unknown option `%s'", arg);
+ }
+
+ if (!filename)
+ filename = get_exec_file (1);
+
+ pbfd = bfd_openr (filename, gnutarget);
+ if (pbfd == NULL)
+ {
+ perror_with_name (filename);
+ return;
+ }
+ old_chain = make_cleanup_bfd_close (pbfd);
+
+ if (!bfd_check_format (pbfd, bfd_object))
+ error ("\"%s\" is not an object file: %s", filename,
+ bfd_errmsg (bfd_get_error ()));
+
+ start_time = time (NULL);
+ data_count = 0;
+
+ puts_e7000debug ("mw\r");
+
+ expect ("\nOK");
+
+ for (section = pbfd->sections; section; section = section->next)
+ {
+ if (bfd_get_section_flags (pbfd, section) & SEC_LOAD)
+ {
+ bfd_vma section_address;
+ bfd_size_type section_size;
+ file_ptr fptr;
+
+ section_address = bfd_get_section_vma (pbfd, section);
+ section_size = bfd_get_section_size_before_reloc (section);
+
+ if (!quiet)
+ printf_filtered ("[Loading section %s at 0x%s (%s bytes)]\n",
+ bfd_get_section_name (pbfd, section),
+ paddr_nz (section_address),
+ paddr_u (section_size));
+
+ fptr = 0;
+
+ data_count += section_size;
+
+ while (section_size > 0)
+ {
+ int count;
+ static char inds[] = "|/-\\";
+ static int k = 0;
+
+ QUIT;
+
+ count = min (section_size, WRITESIZE);
+
+ buf[2] = section_address >> 24;
+ buf[3] = section_address >> 16;
+ buf[4] = section_address >> 8;
+ buf[5] = section_address;
+
+ buf[6] = count >> 24;
+ buf[7] = count >> 16;
+ buf[8] = count >> 8;
+ buf[9] = count;
+
+ bfd_get_section_contents (pbfd, section, buf + 10, fptr, count);
+
+ if (serial_write (e7000_desc, buf, count + 10))
+ fprintf_unfiltered (gdb_stderr,
+ "e7000_load: serial_write failed: %s\n",
+ safe_strerror (errno));
+
+ expect ("OK");
+
+ if (!quiet)
+ {
+ printf_unfiltered ("\r%c", inds[k++ % 4]);
+ gdb_flush (gdb_stdout);
+ }
+
+ section_address += count;
+ fptr += count;
+ section_size -= count;
+ }
+ }
+ }
+
+ write_e7000 ("ED");
+
+ expect_prompt ();
+
+ end_time = time (NULL);
+
+/* Finally, make the PC point at the start address */
+
+ 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 ();
+
+ if (!nostart)
+ {
+ entry = bfd_get_start_address (pbfd);
+
+ if (!quiet)
+ printf_unfiltered ("[Starting %s at 0x%s]\n", filename, paddr_nz (entry));
+
+/* start_routine (entry); */
+ }
+
+ report_transfer_performance (data_count, start_time, end_time);
+
+ do_cleanups (old_chain);
+ timeout = oldtimeout;
+}
+
+/* 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
+e7000_mourn_inferior (void)
+{
+ remove_breakpoints ();
+ unpush_target (&e7000_ops);
+ generic_mourn_inferior (); /* Do all the proper things now */
+}
+
+#define MAX_BREAKPOINTS 200
+#ifdef HARD_BREAKPOINTS
+#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 : MAX_BREAKPOINTS)
+#else
+#define MAX_E7000DEBUG_BREAKPOINTS MAX_BREAKPOINTS
+#endif
+
+/* Since we can change to soft breakpoints dynamically, we must define
+ more than enough. Was breakaddr[MAX_E7000DEBUG_BREAKPOINTS]. */
+static CORE_ADDR breakaddr[MAX_BREAKPOINTS] =
+{0};
+
+static int
+e7000_insert_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+ char buf[200];
+#if 0
+ static char nop[2] = NOP;
+#endif
+
+ for (i = 0; i <= MAX_E7000DEBUG_BREAKPOINTS; i++)
+ if (breakaddr[i] == 0)
+ {
+ breakaddr[i] = addr;
+ /* Save old contents, and insert a nop in the space */
+#ifdef HARD_BREAKPOINTS
+ if (BC_BREAKPOINTS)
+ {
+ sprintf (buf, "BC%d A=%s\r", i + 1, paddr_nz (addr));
+ puts_e7000debug (buf);
+ }
+ else
+ {
+ sprintf (buf, "B %s\r", paddr_nz (addr));
+ puts_e7000debug (buf);
+ }
+#else
+#if 0
+ e7000_read_inferior_memory (addr, shadow, 2);
+ e7000_write_inferior_memory (addr, nop, 2);
+#endif
+
+ sprintf (buf, "B %x\r", addr);
+ puts_e7000debug (buf);
+#endif
+ expect_prompt ();
+ return 0;
+ }
+
+ error ("Too many breakpoints ( > %d) for the E7000\n",
+ MAX_E7000DEBUG_BREAKPOINTS);
+ return 1;
+}
+
+static int
+e7000_remove_breakpoint (CORE_ADDR addr, char *shadow)
+{
+ int i;
+ char buf[200];
+
+ for (i = 0; i < MAX_E7000DEBUG_BREAKPOINTS; i++)
+ if (breakaddr[i] == addr)
+ {
+ breakaddr[i] = 0;
+#ifdef HARD_BREAKPOINTS
+ if (BC_BREAKPOINTS)
+ {
+ sprintf (buf, "BC%d - \r", i + 1);
+ puts_e7000debug (buf);
+ }
+ else
+ {
+ sprintf (buf, "B - %s\r", paddr_nz (addr));
+ puts_e7000debug (buf);
+ }
+ expect_prompt ();
+#else
+ sprintf (buf, "B - %s\r", paddr_nz (addr));
+ puts_e7000debug (buf);
+ expect_prompt ();
+
+#if 0
+ /* Replace the insn under the break */
+ e7000_write_inferior_memory (addr, shadow, 2);
+#endif
+#endif
+
+ return 0;
+ }
+
+ warning ("Can't find breakpoint associated with 0x%s\n", paddr_nz (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
+e7000_command (char *args, int fromtty)
+{
+ /* FIXME: arbitrary limit on length of args. */
+ char buf[200];
+
+ echo = 0;
+
+ if (!e7000_desc)
+ error ("e7000 target not open.");
+ if (!args)
+ {
+ puts_e7000debug ("\r");
+ }
+ else
+ {
+ sprintf (buf, "%s\r", args);
+ puts_e7000debug (buf);
+ }
+
+ echo++;
+ ctrl_c = 2;
+ expect_full_prompt ();
+ echo--;
+ ctrl_c = 0;
+ printf_unfiltered ("\n");
+
+ /* Who knows what the command did... */
+ registers_changed ();
+}
+
+
+static void
+e7000_drain_command (char *args, int fromtty)
+{
+ int c;
+
+ puts_e7000debug ("end\r");
+ putchar_e7000 (CTRLC);
+
+ while ((c = readchar (1)) != -1)
+ {
+ if (quit_flag)
+ {
+ putchar_e7000 (CTRLC);
+ quit_flag = 0;
+ }
+ if (c > ' ' && c < 127)
+ printf_unfiltered ("%c", c & 0xff);
+ else
+ printf_unfiltered ("<%x>", c & 0xff);
+ }
+}
+
+#define NITEMS 7
+
+static int
+why_stop (void)
+{
+ static char *strings[NITEMS] =
+ {
+ "STEP NORMAL",
+ "BREAK POINT",
+ "BREAK KEY",
+ "BREAK CONDI",
+ "CYCLE ACCESS",
+ "ILLEGAL INSTRUCTION",
+ "WRITE PROTECT",
+ };
+ char *p[NITEMS];
+ int c;
+ int i;
+
+ for (i = 0; i < NITEMS; ++i)
+ p[i] = strings[i];
+
+ c = gch ();
+ while (1)
+ {
+ for (i = 0; i < NITEMS; i++)
+ {
+ if (c == *(p[i]))
+ {
+ p[i]++;
+ if (*(p[i]) == 0)
+ {
+ /* found one of the choices */
+ return i;
+ }
+ }
+ else
+ p[i] = strings[i];
+ }
+
+ c = gch ();
+ }
+}
+
+/* Suck characters, if a string match, then return the strings index
+ otherwise echo them. */
+
+static int
+expect_n (char **strings)
+{
+ char *(ptr[10]);
+ int n;
+ int c;
+ char saveaway[100];
+ char *buffer = saveaway;
+ /* Count number of expect strings */
+
+ for (n = 0; strings[n]; n++)
+ {
+ ptr[n] = strings[n];
+ }
+
+ while (1)
+ {
+ int i;
+ int gotone = 0;
+
+ c = readchar (1);
+ if (c == -1)
+ {
+ printf_unfiltered ("[waiting for e7000...]\n");
+ }
+#ifdef __GO32__
+ if (kbhit ())
+ {
+ int k = getkey ();
+
+ if (k == 1)
+ quit_flag = 1;
+ }
+#endif
+ if (quit_flag)
+ {
+ putchar_e7000 (CTRLC); /* interrupt the running program */
+ quit_flag = 0;
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ if (c == ptr[i][0])
+ {
+ ptr[i]++;
+ if (ptr[i][0] == 0)
+ {
+ /* Gone all the way */
+ return i;
+ }
+ gotone = 1;
+ }
+ else
+ {
+ ptr[i] = strings[i];
+ }
+ }
+
+ if (gotone)
+ {
+ /* Save it up incase we find that there was no match */
+ *buffer++ = c;
+ }
+ else
+ {
+ if (buffer != saveaway)
+ {
+ *buffer++ = 0;
+ printf_unfiltered ("%s", buffer);
+ buffer = saveaway;
+ }
+ if (c != -1)
+ {
+ putchar_unfiltered (c);
+ gdb_flush (gdb_stdout);
+ }
+ }
+ }
+}
+
+/* We subtract two from the pc here rather than use
+ DECR_PC_AFTER_BREAK since the e7000 doesn't always add two to the
+ pc, and the simulators never do. */
+
+static void
+sub2_from_pc (void)
+{
+ char buf[4];
+ char buf2[200];
+
+ store_signed_integer (buf,
+ DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM),
+ read_register (PC_REGNUM) - 2);
+ supply_register (PC_REGNUM, buf);
+ sprintf (buf2, ".PC %s\r", phex_nz (read_register (PC_REGNUM), 0));
+ puts_e7000debug (buf2);
+}
+
+#define WAS_SLEEP 0
+#define WAS_INT 1
+#define WAS_RUNNING 2
+#define WAS_OTHER 3
+
+static char *estrings[] =
+{
+ "** SLEEP",
+ "BREAK !",
+ "** PC",
+ "PC",
+ NULL
+};
+
+/* Wait until the remote machine stops, then return, storing status in
+ STATUS just as `wait' would. */
+
+static ptid_t
+e7000_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ int stop_reason;
+ int regno;
+ int running_count = 0;
+ int had_sleep = 0;
+ int loop = 1;
+ char *wanted_nopc = NULL;
+
+ /* Then echo chars until PC= string seen */
+ gch (); /* Drop cr */
+ gch (); /* and space */
+
+ while (loop)
+ {
+ switch (expect_n (estrings))
+ {
+ case WAS_OTHER:
+ /* how did this happen ? */
+ loop = 0;
+ break;
+ case WAS_SLEEP:
+ had_sleep = 1;
+ putchar_e7000 (CTRLC);
+ loop = 0;
+ break;
+ case WAS_INT:
+ loop = 0;
+ break;
+ case WAS_RUNNING:
+ running_count++;
+ if (running_count == 20)
+ {
+ printf_unfiltered ("[running...]\n");
+ running_count = 0;
+ }
+ break;
+ default:
+ /* error? */
+ break;
+ }
+ }
+
+ /* Skip till the PC= */
+ expect ("=");
+
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_sh)
+ {
+ wanted_nopc = want_nopc_sh;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_sh3:
+ case bfd_mach_sh3e:
+ case bfd_mach_sh4:
+ wanted_nopc = want_nopc_sh3;
+ }
+ }
+ if (TARGET_ARCHITECTURE->arch == bfd_arch_h8300)
+ {
+ wanted_nopc = want_nopc_h8300h;
+ switch (TARGET_ARCHITECTURE->mach)
+ {
+ case bfd_mach_h8300s:
+ case bfd_mach_h8300sn:
+ case bfd_mach_h8300sx:
+ case bfd_mach_h8300sxn:
+ wanted_nopc = want_nopc_h8300s;
+ }
+ }
+ fetch_regs_from_dump (gch, wanted_nopc);
+
+ /* And supply the extra ones the simulator uses */
+ for (regno = NUM_REALREGS; regno < NUM_REGS; regno++)
+ {
+ int buf = 0;
+ supply_register (regno, (char *) &buf);
+ }
+
+ stop_reason = why_stop ();
+ expect_full_prompt ();
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+
+ switch (stop_reason)
+ {
+ case 1: /* Breakpoint */
+ write_pc (read_pc ()); /* PC is always off by 2 for breakpoints */
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case 0: /* Single step */
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+ case 2: /* Interrupt */
+ if (had_sleep)
+ {
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ sub2_from_pc ();
+ }
+ else
+ {
+ status->value.sig = TARGET_SIGNAL_INT;
+ }
+ break;
+ case 3:
+ break;
+ case 4:
+ printf_unfiltered ("a cycle address error?\n");
+ status->value.sig = TARGET_SIGNAL_UNKNOWN;
+ break;
+ case 5:
+ status->value.sig = TARGET_SIGNAL_ILL;
+ break;
+ case 6:
+ status->value.sig = TARGET_SIGNAL_SEGV;
+ break;
+ case 7: /* Anything else (NITEMS + 1) */
+ printf_unfiltered ("a write protect error?\n");
+ status->value.sig = TARGET_SIGNAL_UNKNOWN;
+ break;
+ default:
+ /* Get the user's attention - this should never happen. */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+
+ return inferior_ptid;
+}
+
+/* Stop the running program. */
+
+static void
+e7000_stop (void)
+{
+ /* Sending a ^C is supposed to stop the running program. */
+ putchar_e7000 (CTRLC);
+}
+
+/* Define the target subroutine names. */
+
+struct target_ops e7000_ops;
+
+static void
+init_e7000_ops (void)
+{
+ e7000_ops.to_shortname = "e7000";
+ e7000_ops.to_longname = "Remote Renesas e7000 target";
+ e7000_ops.to_doc = "Use a remote Renesas e7000 ICE 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.\n\
+eg\n\
+target e7000 /dev/ttya 9600\n\
+target e7000 foobar";
+ e7000_ops.to_open = e7000_open;
+ e7000_ops.to_close = e7000_close;
+ e7000_ops.to_detach = e7000_detach;
+ e7000_ops.to_resume = e7000_resume;
+ e7000_ops.to_wait = e7000_wait;
+ e7000_ops.to_fetch_registers = e7000_fetch_register;
+ e7000_ops.to_store_registers = e7000_store_register;
+ e7000_ops.to_prepare_to_store = e7000_prepare_to_store;
+ e7000_ops.to_xfer_memory = e7000_xfer_inferior_memory;
+ e7000_ops.to_files_info = e7000_files_info;
+ e7000_ops.to_insert_breakpoint = e7000_insert_breakpoint;
+ e7000_ops.to_remove_breakpoint = e7000_remove_breakpoint;
+ e7000_ops.to_kill = e7000_kill;
+ e7000_ops.to_load = e7000_load;
+ e7000_ops.to_create_inferior = e7000_create_inferior;
+ e7000_ops.to_mourn_inferior = e7000_mourn_inferior;
+ e7000_ops.to_stop = e7000_stop;
+ e7000_ops.to_stratum = process_stratum;
+ e7000_ops.to_has_all_memory = 1;
+ e7000_ops.to_has_memory = 1;
+ e7000_ops.to_has_stack = 1;
+ e7000_ops.to_has_registers = 1;
+ e7000_ops.to_has_execution = 1;
+ e7000_ops.to_magic = OPS_MAGIC;
+};
+
+extern initialize_file_ftype _initialize_remote_e7000; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_e7000 (void)
+{
+ init_e7000_ops ();
+ add_target (&e7000_ops);
+
+ add_com ("e7000", class_obscure, e7000_command,
+ "Send a command to the e7000 monitor.");
+
+ add_com ("ftplogin", class_obscure, e7000_login_command,
+ "Login to machine and change to directory.");
+
+ add_com ("ftpload", class_obscure, e7000_ftp_command,
+ "Fetch and load a file from previously described place.");
+
+ add_com ("drain", class_obscure, e7000_drain_command,
+ "Drain pending e7000 text buffers.");
+
+ add_show_from_set (add_set_cmd ("usehardbreakpoints", no_class,
+ var_integer, (char *) &use_hard_breakpoints,
+ "Set use of hardware breakpoints for all breakpoints.\n", &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/remote-est.c b/contrib/gdb/gdb/remote-est.c
new file mode 100644
index 0000000..a2c0f7c
--- /dev/null
+++ b/contrib/gdb/gdb/remote-est.c
@@ -0,0 +1,186 @@
+/* Remote debugging interface for EST-300 ICE, for GDB
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+ Written by Steve Chamberlain for Cygnus Support.
+ Re-written by Stu Grossman of Cygnus Support
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "serial.h"
+#include "regcache.h"
+
+#include "m68k-tdep.h"
+
+static void est_open (char *args, int from_tty);
+
+static void
+est_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' + M68K_D0_REGNUM;
+ break;
+ case 'A':
+ if (regname[1] < '0' || regname[1] > '7')
+ return;
+ regno = regname[1] - '0' + M68K_A0_REGNUM;
+ break;
+ default:
+ return;
+ }
+
+ monitor_supply_register (regno, val);
+}
+
+/*
+ * This array of registers needs to match the indexes used by GDB. The
+ * whole reason this exists is because the various ROM monitors use
+ * different names than GDB does, and don't support all the
+ * registers either. So, typing "info reg sp" becomes a "r30".
+ */
+
+static const char *
+est_regname (int index)
+{
+
+ static char *regnames[] =
+ {
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+ "SR", "PC",
+ };
+
+
+ if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
+ || (index < 0) || (index >= NUM_REGS))
+ return NULL;
+ else
+ return regnames[index];
+}
+
+/*
+ * Define the monitor command strings. Since these are passed directly
+ * through to a printf style function, we need can include formatting
+ * strings. We also need a CR or LF on the end.
+ */
+
+static struct target_ops est_ops;
+
+static char *est_inits[] =
+{"he\r", /* Resets the prompt, and clears repeated cmds */
+ NULL};
+
+static struct monitor_ops est_cmds;
+
+static void
+init_est_cmds (void)
+{
+ est_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_NEED_REGDUMP_AFTER_CONT |
+ MO_SREC_ACK | MO_SREC_ACK_PLUS;
+ est_cmds.init = est_inits; /* Init strings */
+ est_cmds.cont = "go\r"; /* continue command */
+ est_cmds.step = "sidr\r"; /* single step */
+ est_cmds.stop = "\003"; /* ^C interrupts the program */
+ est_cmds.set_break = "sb %x\r"; /* set a breakpoint */
+ est_cmds.clr_break = "rb %x\r"; /* clear a breakpoint */
+ est_cmds.clr_all_break = "rb\r"; /* clear all breakpoints */
+ est_cmds.fill = "bfb %x %x %x\r"; /* fill (start end val) */
+ est_cmds.setmem.cmdb = "smb %x %x\r"; /* setmem.cmdb (addr, value) */
+ est_cmds.setmem.cmdw = "smw %x %x\r"; /* setmem.cmdw (addr, value) */
+ est_cmds.setmem.cmdl = "sml %x %x\r"; /* setmem.cmdl (addr, value) */
+ est_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ est_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ est_cmds.setmem.term = NULL; /* setreg.term */
+ est_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ est_cmds.getmem.cmdb = "dmb %x %x\r"; /* getmem.cmdb (addr, len) */
+ est_cmds.getmem.cmdw = "dmw %x %x\r"; /* getmem.cmdw (addr, len) */
+ est_cmds.getmem.cmdl = "dml %x %x\r"; /* getmem.cmdl (addr, len) */
+ est_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
+ est_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
+ est_cmds.getmem.term = NULL; /* getmem.term */
+ est_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
+ est_cmds.setreg.cmd = "sr %s %x\r"; /* setreg.cmd (name, value) */
+ est_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ est_cmds.setreg.term = NULL; /* setreg.term */
+ est_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ est_cmds.getreg.cmd = "dr %s\r"; /* getreg.cmd (name) */
+ est_cmds.getreg.resp_delim = " = "; /* getreg.resp_delim */
+ est_cmds.getreg.term = NULL; /* getreg.term */
+ est_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */
+ est_cmds.dump_registers = "dr\r"; /* dump_registers */
+ est_cmds.register_pattern = "\\(\\w+\\) = \\([0-9a-fA-F]+\\)"; /* register_pattern */
+ est_cmds.supply_register = est_supply_register; /* supply_register */
+ est_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ est_cmds.load = "dl\r"; /* download command */
+ est_cmds.loadresp = "+"; /* load response */
+ est_cmds.prompt = ">BKM>"; /* monitor command prompt */
+ est_cmds.line_term = "\r"; /* end-of-line terminator */
+ est_cmds.cmd_end = NULL; /* optional command terminator */
+ est_cmds.target = &est_ops; /* target operations */
+ est_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ est_cmds.regnames = NULL;
+ est_cmds.regname = est_regname; /*register names*/
+ est_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_est_cmds */
+
+static void
+est_open (char *args, int from_tty)
+{
+ monitor_open (args, &est_cmds, from_tty);
+}
+
+extern initialize_file_ftype _initialize_est; /* -Wmissing-prototypes */
+
+void
+_initialize_est (void)
+{
+ init_est_cmds ();
+ init_monitor_ops (&est_ops);
+
+ est_ops.to_shortname = "est";
+ est_ops.to_longname = "EST background debug monitor";
+ est_ops.to_doc = "Debug via the EST BDM.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ est_ops.to_open = est_open;
+
+ add_target (&est_ops);
+}
diff --git a/contrib/gdb/gdb/remote-hms.c b/contrib/gdb/gdb/remote-hms.c
new file mode 100644
index 0000000..ee40051
--- /dev/null
+++ b/contrib/gdb/gdb/remote-hms.c
@@ -0,0 +1,159 @@
+/* Remote debugging interface for Renesas HMS Monitor Version 1.0
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+ Contributed by Cygnus Support. Written by 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 "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "serial.h"
+#include "regcache.h"
+
+static void hms_open (char *args, int from_tty);
+static void
+hms_supply_register (char *regname, int regnamelen, char *val, int vallen)
+{
+ int regno;
+
+ if (regnamelen != 2)
+ return;
+ if (regname[0] != 'P')
+ return;
+ /* We scan off all the registers in one go */
+
+ val = monitor_supply_register (PC_REGNUM, val);
+ /* Skip the ccr string */
+ while (*val != '=' && *val)
+ val++;
+
+ val = monitor_supply_register (CCR_REGNUM, val + 1);
+
+ /* Skip up to rest of regs */
+ while (*val != '=' && *val)
+ val++;
+
+ for (regno = 0; regno < 7; regno++)
+ {
+ val = monitor_supply_register (regno, val + 1);
+ }
+}
+
+/*
+ * This array of registers needs to match the indexes used by GDB. The
+ * whole reason this exists is because the various ROM monitors use
+ * different names than GDB does, and don't support all the
+ * registers either. So, typing "info reg sp" becomes a "r30".
+ */
+
+static char *hms_regnames[] =
+{
+ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "CCR", "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 hms_ops;
+
+static char *hms_inits[] =
+{"\003", /* Resets the prompt, and clears repeated cmds */
+ NULL};
+
+static struct monitor_ops hms_cmds;
+
+static void
+init_hms_cmds (void)
+{
+ hms_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_FILL_USES_ADDR | MO_GETMEM_NEEDS_RANGE;
+ hms_cmds.init = hms_inits; /* Init strings */
+ hms_cmds.cont = "g\r"; /* continue command */
+ hms_cmds.step = "s\r"; /* single step */
+ hms_cmds.stop = "\003"; /* ^C interrupts the program */
+ hms_cmds.set_break = "b %x\r"; /* set a breakpoint */
+ hms_cmds.clr_break = "b - %x\r"; /* clear a breakpoint */
+ hms_cmds.clr_all_break = "b -\r"; /* clear all breakpoints */
+ hms_cmds.fill = "f %x %x %x\r"; /* fill (start end val) */
+ hms_cmds.setmem.cmdb = "m.b %x=%x\r"; /* setmem.cmdb (addr, value) */
+ hms_cmds.setmem.cmdw = "m.w %x=%x\r"; /* setmem.cmdw (addr, value) */
+ hms_cmds.setmem.cmdl = NULL; /* setmem.cmdl (addr, value) */
+ hms_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
+ hms_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
+ hms_cmds.setmem.term = NULL; /* setreg.term */
+ hms_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
+ hms_cmds.getmem.cmdb = "m.b %x %x\r"; /* getmem.cmdb (addr, addr) */
+ hms_cmds.getmem.cmdw = "m.w %x %x\r"; /* getmem.cmdw (addr, addr) */
+ hms_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, addr) */
+ hms_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, addr) */
+ hms_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */
+ hms_cmds.getmem.term = ">"; /* getmem.term */
+ hms_cmds.getmem.term_cmd = "\003"; /* getmem.term_cmd */
+ hms_cmds.setreg.cmd = "r %s=%x\r"; /* setreg.cmd (name, value) */
+ hms_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */
+ hms_cmds.setreg.term = NULL; /* setreg.term */
+ hms_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */
+ hms_cmds.getreg.cmd = "r %s\r"; /* getreg.cmd (name) */
+ hms_cmds.getreg.resp_delim = " ("; /* getreg.resp_delim */
+ hms_cmds.getreg.term = ":"; /* getreg.term */
+ hms_cmds.getreg.term_cmd = "\003"; /* getreg.term_cmd */
+ hms_cmds.dump_registers = "r\r"; /* dump_registers */
+ hms_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\)"; /* register_pattern */
+ hms_cmds.supply_register = hms_supply_register; /* supply_register */
+ hms_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
+ hms_cmds.load = "tl\r"; /* download command */
+ hms_cmds.loadresp = NULL; /* load response */
+ hms_cmds.prompt = ">"; /* monitor command prompt */
+ hms_cmds.line_term = "\r"; /* end-of-command delimitor */
+ hms_cmds.cmd_end = NULL; /* optional command terminator */
+ hms_cmds.target = &hms_ops; /* target operations */
+ hms_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
+ hms_cmds.regnames = hms_regnames; /* registers names */
+ hms_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
+} /* init_hms-cmds */
+
+static void
+hms_open (char *args, int from_tty)
+{
+ monitor_open (args, &hms_cmds, from_tty);
+}
+
+int write_dos_tick_delay;
+
+extern initialize_file_ftype _initialize_remote_hms; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_hms (void)
+{
+ init_hms_cmds ();
+ init_monitor_ops (&hms_ops);
+
+ hms_ops.to_shortname = "hms";
+ hms_ops.to_longname = "Renesas Microsystems H8/300 debug monitor";
+ hms_ops.to_doc = "Debug via the HMS monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ hms_ops.to_open = hms_open;
+ /* By trial and error I've found that this delay doesn't break things */
+ write_dos_tick_delay = 1;
+ add_target (&hms_ops);
+}
diff --git a/contrib/gdb/gdb/remote-mips.c b/contrib/gdb/gdb/remote-mips.c
new file mode 100644
index 0000000..c757684
--- /dev/null
+++ b/contrib/gdb/gdb/remote-mips.c
@@ -0,0 +1,3421 @@
+/* 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>
+#include "mips-tdep.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)
+ fputs_filtered (error_pre_print, gdb_stderr);
+ 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.
+ */
+
+static 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.
+ */
+
+static int
+mips_expect (const char *string)
+{
+ return mips_expect_timeout (string, remote_timeout);
+}
+
+/* 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)
+{
+ const unsigned char *p;
+ int c;
+ 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;
+ 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 (void *arg)
+{
+ mips_initializing = 0;
+}
+
+static void
+mips_exit_cleanups (void *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);
+}
+
+/* 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. */
+ deprecated_mips_set_processor_regs_hack ();
+
+ /* 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 ();
+ print_stack_frame (get_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. */
+static 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_SIZE];
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM), rpc);
+ supply_register (PC_REGNUM, buf);
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (PC_REGNUM), rfp);
+ supply_register (30, buf); /* This register they are avoiding and so it is unnamed */
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (SP_REGNUM), rsp);
+ supply_register (SP_REGNUM, buf);
+
+ store_unsigned_integer (buf, DEPRECATED_REGISTER_RAW_SIZE (DEPRECATED_FP_REGNUM), 0);
+ supply_register (DEPRECATED_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 >= mips_regnum (current_gdbarch)->fp0
+ && regno < mips_regnum (current_gdbarch)->fp0 + 32)
+ return regno - mips_regnum (current_gdbarch)->fp0 + 32;
+ else if (regno == mips_regnum (current_gdbarch)->pc)
+ return REGNO_OFFSET + 0;
+ else if (regno == mips_regnum (current_gdbarch)->cause)
+ return REGNO_OFFSET + 1;
+ else if (regno == mips_regnum (current_gdbarch)->hi)
+ return REGNO_OFFSET + 2;
+ else if (regno == mips_regnum (current_gdbarch)->lo)
+ return REGNO_OFFSET + 3;
+ else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ return REGNO_OFFSET + 4;
+ else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ return REGNO_OFFSET + 5;
+ else
+ /* 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 == DEPRECATED_FP_REGNUM || regno == ZERO_REGNUM)
+ /* DEPRECATED_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_SIZE];
+
+ /* We got the number the register holds, but gdb expects to see a
+ value in the target byte ordering. */
+ store_unsigned_integer (buf, DEPRECATED_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 the breakpoint
+ length returned by BREAKPOINT_FROM_PC. */
+
+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);
+}
+
+/* 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
+mips_can_use_watchpoint (int type, int cnt, int othertype)
+{
+ 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;
+}
+
+
+/* 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
+mips_insert_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ if (set_breakpoint (addr, len, type))
+ return -1;
+
+ return 0;
+}
+
+int
+mips_remove_watchpoint (CORE_ADDR addr, int len, int type)
+{
+ if (clear_breakpoint (addr, len, type))
+ return -1;
+
+ return 0;
+}
+
+int
+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: */
+ deprecated_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);
+}
+
+extern initialize_file_ftype _initialize_remote_mips; /* -Wmissing-prototypes */
+
+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_insert_watchpoint = mips_insert_watchpoint;
+ mips_ops.to_remove_watchpoint = mips_remove_watchpoint;
+ mips_ops.to_stopped_by_watchpoint = mips_stopped_by_watchpoint;
+ mips_ops.to_can_use_hw_breakpoint = mips_can_use_watchpoint;
+ 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
new file mode 100644
index 0000000..eab68ea
--- /dev/null
+++ b/contrib/gdb/gdb/remote-rdp.c
@@ -0,0 +1,1431 @@
+/* Remote debugging for the ARM RDP interface.
+
+ Copyright 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003 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 "gdb/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:
+#if 0
+ /* FIXME: cagney/2003-11-22: Ever since the ARM
+ was multi-arched (in 2002-02-08), this
+ assignment has had no effect. There needs to
+ be some sort of check/decision based on the
+ current architecture's byte-order vs the remote
+ target's byte order. For the moment disable
+ the assignment to keep things building. */
+ target_byte_order = BFD_ENDIAN_LITTLE;
+#endif
+ sync = 1;
+ break;
+ case RDP_RES_VALUE_BIG_ENDIAN:
+#if 0
+ /* FIXME: cagney/2003-11-22: Ever since the ARM
+ was multi-arched (in 2002-02-08), this
+ assignment has had no effect. There needs to
+ be some sort of check/decision based on the
+ current architecture's byte-order vs the remote
+ target's byte order. For the moment disable
+ the assignment to keep things building. */
+ target_byte_order = BFD_ENDIAN_BIG;
+#endif
+ sync = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!sync)
+ {
+ error ("Couldn't reset the board, try pressing the reset button");
+ }
+}
+
+
+static 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_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_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_SIZE];
+ deprecated_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, &not_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 ();
+ print_stack_frame (get_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);
+}
+
+/* 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_resume = remote_rdp_resume;
+ remote_rdp_ops.to_wait = remote_rdp_wait;
+ 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_kill = remote_rdp_kill;
+ remote_rdp_ops.to_load = generic_load;
+ remote_rdp_ops.to_create_inferior = remote_rdp_create_inferior;
+ remote_rdp_ops.to_mourn_inferior = generic_mourn_inferior;
+ remote_rdp_ops.to_stratum = process_stratum;
+ 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_magic = OPS_MAGIC;
+}
+
+extern initialize_file_ftype _initialize_remote_rdp; /* -Wmissing-prototypes */
+
+void
+_initialize_remote_rdp (void)
+{
+ init_remote_rdp_ops ();
+ add_target (&remote_rdp_ops);
+}
diff --git a/contrib/gdb/gdb/remote-sds.c b/contrib/gdb/gdb/remote-sds.c
new file mode 100644
index 0000000..d74fd7d
--- /dev/null
+++ b/contrib/gdb/gdb/remote-sds.c
@@ -0,0 +1,1130 @@
+/* Remote target communications for serial-line targets using SDS' protocol.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This interface was written by studying the behavior of the SDS
+ monitor on an ADS 821/860 board, and by consulting the
+ documentation of the monitor that is available on Motorola's web
+ site. -sts 8/13/97 */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <fcntl.h>
+#include "frame.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+#include "serial.h"
+
+extern void _initialize_remote_sds (void);
+
+/* Declarations of local functions. */
+
+static int sds_write_bytes (CORE_ADDR, char *, int);
+
+static int sds_read_bytes (CORE_ADDR, char *, int);
+
+static void sds_files_info (struct target_ops *ignore);
+
+static int sds_xfer_memory (CORE_ADDR, char *, int, int,
+ struct mem_attrib *, struct target_ops *);
+
+static void sds_prepare_to_store (void);
+
+static void sds_fetch_registers (int);
+
+static void sds_resume (ptid_t, int, enum target_signal);
+
+static int sds_start_remote (void *);
+
+static void sds_open (char *, int);
+
+static void sds_close (int);
+
+static void sds_store_registers (int);
+
+static void sds_mourn (void);
+
+static void sds_create_inferior (char *, char *, char **);
+
+static void sds_load (char *, int);
+
+static int getmessage (unsigned char *, int);
+
+static int putmessage (unsigned char *, int);
+
+static int sds_send (unsigned char *, int);
+
+static int readchar (int);
+
+static ptid_t sds_wait (ptid_t, struct target_waitstatus *);
+
+static void sds_kill (void);
+
+static int fromhex (int);
+
+static void sds_detach (char *, int);
+
+static void sds_interrupt (int);
+
+static void sds_interrupt_twice (int);
+
+static void interrupt_query (void);
+
+static int read_frame (char *);
+
+static int sds_insert_breakpoint (CORE_ADDR, char *);
+
+static int sds_remove_breakpoint (CORE_ADDR, char *);
+
+static void init_sds_ops (void);
+
+static void sds_command (char *args, int from_tty);
+
+/* Define the target operations vector. */
+
+static struct target_ops sds_ops;
+
+/* This was 5 seconds, which is a long time to sit and wait.
+ Unless this is going though some terminal server or multiplexer or
+ other form of hairy serial connection, I would think 2 seconds would
+ be plenty. */
+
+static int sds_timeout = 2;
+
+/* Descriptor for I/O to remote machine. Initialize it to NULL so
+ that sds_open knows that we don't have a file open when the program
+ starts. */
+
+static struct serial *sds_desc = NULL;
+
+/* This limit comes from the monitor. */
+
+#define PBUFSIZ 250
+
+/* Maximum number of bytes to read/write at once. The value here
+ is chosen to fill up a packet (the headers account for the 32). */
+#define MAXBUFBYTES ((PBUFSIZ-32)/2)
+
+static int next_msg_id;
+
+static int just_started;
+
+static int message_pending;
+
+
+/* Clean up connection to a remote debugger. */
+
+static void
+sds_close (int quitting)
+{
+ if (sds_desc)
+ serial_close (sds_desc);
+ sds_desc = NULL;
+}
+
+/* Stub for catch_errors. */
+
+static int
+sds_start_remote (void *dummy)
+{
+ int c;
+ unsigned char buf[200];
+
+ immediate_quit++; /* Allow user to interrupt it */
+
+ /* Ack any packet which the remote side has already sent. */
+ serial_write (sds_desc, "{#*\r\n", 5);
+ serial_write (sds_desc, "{#}\r\n", 5);
+
+ while ((c = readchar (1)) >= 0)
+ printf_unfiltered ("%c", c);
+ printf_unfiltered ("\n");
+
+ next_msg_id = 251;
+
+ buf[0] = 26;
+ sds_send (buf, 1);
+
+ buf[0] = 0;
+ sds_send (buf, 1);
+
+ immediate_quit--;
+
+ start_remote (); /* Initialize gdb process mechanisms */
+ return 1;
+}
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+static void
+sds_open (char *name, int from_tty)
+{
+ if (name == 0)
+ error ("To open a remote debug connection, you need to specify what serial\n\
+device is attached to the remote system (e.g. /dev/ttya).");
+
+ target_preopen (from_tty);
+
+ unpush_target (&sds_ops);
+
+ sds_desc = serial_open (name);
+ if (!sds_desc)
+ perror_with_name (name);
+
+ if (baud_rate != -1)
+ {
+ if (serial_setbaudrate (sds_desc, baud_rate))
+ {
+ serial_close (sds_desc);
+ perror_with_name (name);
+ }
+ }
+
+
+ serial_raw (sds_desc);
+
+ /* If there is something sitting in the buffer we might take it as a
+ response to a command, which would be bad. */
+ serial_flush_input (sds_desc);
+
+ if (from_tty)
+ {
+ puts_filtered ("Remote debugging using ");
+ puts_filtered (name);
+ puts_filtered ("\n");
+ }
+ push_target (&sds_ops); /* Switch to using remote target now */
+
+ just_started = 1;
+
+ /* Start the remote connection; if error (0), discard this target.
+ In particular, if the user quits, be sure to discard it (we'd be
+ in an inconsistent state otherwise). */
+ if (!catch_errors (sds_start_remote, NULL,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ pop_target ();
+}
+
+/* This takes a program previously attached to and detaches it. After
+ this is done, GDB can be used to debug some other program. We
+ better not have left any breakpoints in the target program or it'll
+ die when it hits one. */
+
+static void
+sds_detach (char *args, int from_tty)
+{
+ char buf[PBUFSIZ];
+
+ if (args)
+ error ("Argument given to \"detach\" when remotely debugging.");
+
+#if 0
+ /* Tell the remote target to detach. */
+ strcpy (buf, "D");
+ sds_send (buf, 1);
+#endif
+
+ pop_target ();
+ if (from_tty)
+ puts_filtered ("Ending remote debugging.\n");
+}
+
+/* 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
+ error ("Reply contains invalid hex digit %d", a);
+}
+
+static int
+tob64 (unsigned char *inbuf, char *outbuf, int len)
+{
+ int i, sum;
+ char *p;
+
+ if (len % 3 != 0)
+ error ("bad length");
+
+ p = outbuf;
+ for (i = 0; i < len; i += 3)
+ {
+ /* Collect the next three bytes into a number. */
+ sum = ((long) *inbuf++) << 16;
+ sum |= ((long) *inbuf++) << 8;
+ sum |= ((long) *inbuf++);
+
+ /* Spit out 4 6-bit encodings. */
+ *p++ = ((sum >> 18) & 0x3f) + '0';
+ *p++ = ((sum >> 12) & 0x3f) + '0';
+ *p++ = ((sum >> 6) & 0x3f) + '0';
+ *p++ = (sum & 0x3f) + '0';
+ }
+ return (p - outbuf);
+}
+
+static int
+fromb64 (char *inbuf, char *outbuf, int len)
+{
+ int i, sum;
+
+ if (len % 4 != 0)
+ error ("bad length");
+
+ for (i = 0; i < len; i += 4)
+ {
+ /* Collect 4 6-bit digits. */
+ sum = (*inbuf++ - '0') << 18;
+ sum |= (*inbuf++ - '0') << 12;
+ sum |= (*inbuf++ - '0') << 6;
+ sum |= (*inbuf++ - '0');
+
+ /* Now take the resulting 24-bit number and get three bytes out
+ of it. */
+ *outbuf++ = (sum >> 16) & 0xff;
+ *outbuf++ = (sum >> 8) & 0xff;
+ *outbuf++ = sum & 0xff;
+ }
+
+ return (len / 4) * 3;
+}
+
+
+/* Tell the remote machine to resume. */
+
+static enum target_signal last_sent_signal = TARGET_SIGNAL_0;
+int last_sent_step;
+
+static void
+sds_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ unsigned char buf[PBUFSIZ];
+
+ last_sent_signal = siggnal;
+ last_sent_step = step;
+
+ buf[0] = (step ? 21 : 20);
+ buf[1] = 0; /* (should be signal?) */
+
+ sds_send (buf, 2);
+}
+
+/* Send a message to target to halt it. Target will respond, and send
+ us a message pending notice. */
+
+static void
+sds_interrupt (int signo)
+{
+ unsigned char buf[PBUFSIZ];
+
+ /* If this doesn't work, try more severe steps. */
+ signal (signo, sds_interrupt_twice);
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "sds_interrupt called\n");
+
+ buf[0] = 25;
+ sds_send (buf, 1);
+}
+
+static void (*ofunc) ();
+
+/* The user typed ^C twice. */
+
+static void
+sds_interrupt_twice (int signo)
+{
+ signal (signo, ofunc);
+
+ interrupt_query ();
+
+ signal (signo, sds_interrupt);
+}
+
+/* Ask the user what to do when an interrupt is received. */
+
+static void
+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 ();
+}
+
+/* If nonzero, ignore the next kill. */
+int kill_kludge;
+
+/* Wait until the remote machine stops, then return, storing status in
+ STATUS just as `wait' would. Returns "pid" (though it's not clear
+ what, if anything, that means in the case of this target). */
+
+static ptid_t
+sds_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ unsigned char buf[PBUFSIZ];
+ int retlen;
+
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+
+ ofunc = (void (*)()) signal (SIGINT, sds_interrupt);
+
+ signal (SIGINT, ofunc);
+
+ if (just_started)
+ {
+ just_started = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ return inferior_ptid;
+ }
+
+ while (1)
+ {
+ getmessage (buf, 1);
+
+ if (message_pending)
+ {
+ buf[0] = 26;
+ retlen = sds_send (buf, 1);
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Signals: %02x%02x %02x %02x\n",
+ buf[0], buf[1],
+ buf[2], buf[3]);
+ }
+ message_pending = 0;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ goto got_status;
+ }
+ }
+got_status:
+ return inferior_ptid;
+}
+
+static unsigned char sprs[16];
+
+/* Read the remote registers into the block REGS. */
+/* Currently we just read all the registers, so we don't use regno. */
+
+static void
+sds_fetch_registers (int regno)
+{
+ unsigned char buf[PBUFSIZ];
+ int i, retlen;
+ char *regs = alloca (DEPRECATED_REGISTER_BYTES);
+
+ /* Unimplemented registers read as all bits zero. */
+ memset (regs, 0, DEPRECATED_REGISTER_BYTES);
+
+ buf[0] = 18;
+ buf[1] = 1;
+ buf[2] = 0;
+ retlen = sds_send (buf, 3);
+
+ for (i = 0; i < 4 * 6; ++i)
+ regs[i + 4 * 32 + 8 * 32] = buf[i];
+ for (i = 0; i < 4 * 4; ++i)
+ sprs[i] = buf[i + 4 * 7];
+
+ buf[0] = 18;
+ buf[1] = 2;
+ buf[2] = 0;
+ retlen = sds_send (buf, 3);
+
+ for (i = 0; i < retlen; i++)
+ regs[i] = buf[i];
+
+ /* (should warn about reply too short) */
+
+ for (i = 0; i < NUM_REGS; i++)
+ supply_register (i, &regs[DEPRECATED_REGISTER_BYTE (i)]);
+}
+
+/* Prepare to store registers. Since we may send them all, we have to
+ read out the ones we don't want to change first. */
+
+static void
+sds_prepare_to_store (void)
+{
+ /* Make sure the entire registers array is valid. */
+ deprecated_read_register_bytes (0, (char *) NULL, DEPRECATED_REGISTER_BYTES);
+}
+
+/* Store register REGNO, or all registers if REGNO == -1, from the contents
+ of REGISTERS. FIXME: ignores errors. */
+
+static void
+sds_store_registers (int regno)
+{
+ unsigned char *p, buf[PBUFSIZ];
+ int i;
+
+ /* Store all the special-purpose registers. */
+ p = buf;
+ *p++ = 19;
+ *p++ = 1;
+ *p++ = 0;
+ *p++ = 0;
+ for (i = 0; i < 4 * 6; i++)
+ *p++ = deprecated_registers[i + 4 * 32 + 8 * 32];
+ for (i = 0; i < 4 * 1; i++)
+ *p++ = 0;
+ for (i = 0; i < 4 * 4; i++)
+ *p++ = sprs[i];
+
+ sds_send (buf, p - buf);
+
+ /* Store all the general-purpose registers. */
+ p = buf;
+ *p++ = 19;
+ *p++ = 2;
+ *p++ = 0;
+ *p++ = 0;
+ for (i = 0; i < 4 * 32; i++)
+ *p++ = deprecated_registers[i];
+
+ sds_send (buf, p - buf);
+
+}
+
+/* Write memory data directly to the remote machine. This does not
+ inform the data cache; the data cache uses this. MEMADDR is the
+ address in the remote memory space. MYADDR is the address of the
+ buffer in our space. LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+sds_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
+ unsigned char buf[PBUFSIZ];
+ int todo;
+ int i;
+
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = 150;
+
+ origlen = len;
+ while (len > 0)
+ {
+ todo = min (len, max_buf_size);
+
+ buf[0] = 13;
+ buf[1] = 0;
+ buf[2] = (int) (memaddr >> 24) & 0xff;
+ buf[3] = (int) (memaddr >> 16) & 0xff;
+ buf[4] = (int) (memaddr >> 8) & 0xff;
+ buf[5] = (int) (memaddr) & 0xff;
+ buf[6] = 1;
+ buf[7] = 0;
+
+ for (i = 0; i < todo; i++)
+ buf[i + 8] = myaddr[i];
+
+ sds_send (buf, 8 + todo);
+
+ /* (should look at result) */
+
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
+ }
+ return origlen;
+}
+
+/* Read memory data directly from the remote machine. This does not
+ use the data cache; the data cache uses this. MEMADDR is the
+ address in the remote memory space. MYADDR is the address of the
+ buffer in our space. LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+static int
+sds_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
+{
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen, retlen;
+ unsigned char buf[PBUFSIZ];
+ int todo;
+ int i;
+
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = 150;
+
+ origlen = len;
+ while (len > 0)
+ {
+ todo = min (len, max_buf_size);
+
+ buf[0] = 12;
+ buf[1] = 0;
+ buf[2] = (int) (memaddr >> 24) & 0xff;
+ buf[3] = (int) (memaddr >> 16) & 0xff;
+ buf[4] = (int) (memaddr >> 8) & 0xff;
+ buf[5] = (int) (memaddr) & 0xff;
+ buf[6] = (int) (todo >> 8) & 0xff;
+ buf[7] = (int) (todo) & 0xff;
+ buf[8] = 1;
+
+ retlen = sds_send (buf, 9);
+
+ if (retlen - 2 != todo)
+ {
+ return 0;
+ }
+
+ /* Reply describes memory byte by byte. */
+
+ for (i = 0; i < todo; i++)
+ myaddr[i] = buf[i + 2];
+
+ myaddr += todo;
+ memaddr += todo;
+ len -= todo;
+ }
+
+ return origlen;
+}
+
+/* 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. TARGET is unused. */
+
+static int
+sds_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int should_write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int res;
+
+ if (should_write)
+ res = sds_write_bytes (memaddr, myaddr, len);
+ else
+ res = sds_read_bytes (memaddr, myaddr, len);
+
+ return res;
+}
+
+
+static void
+sds_files_info (struct target_ops *ignore)
+{
+ puts_filtered ("Debugging over a serial connection, using SDS protocol.\n");
+}
+
+/* Stuff for dealing with the packets which are part of this protocol.
+ See comment at top of file for details. */
+
+/* Read a single character from the remote end, masking it down to 7 bits. */
+
+static int
+readchar (int timeout)
+{
+ int ch;
+
+ ch = serial_readchar (sds_desc, timeout);
+
+ if (remote_debug > 1 && ch >= 0)
+ fprintf_unfiltered (gdb_stdlog, "%c(%x)", ch, ch);
+
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ return ch;
+ default:
+ return ch & 0x7f;
+ }
+}
+
+/* An SDS-style checksum is a sum of the bytes modulo 253. (Presumably
+ because 253, 254, and 255 are special flags in the protocol.) */
+
+static int
+compute_checksum (int csum, char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; ++i)
+ csum += (unsigned char) buf[i];
+
+ csum %= 253;
+ return csum;
+}
+
+/* Send the command in BUF to the remote machine, and read the reply
+ into BUF also. */
+
+static int
+sds_send (unsigned char *buf, int len)
+{
+ putmessage (buf, len);
+
+ return getmessage (buf, 0);
+}
+
+/* Send a message to the remote machine. */
+
+static int
+putmessage (unsigned char *buf, int len)
+{
+ int i, enclen;
+ unsigned char csum = 0;
+ char buf2[PBUFSIZ], buf3[PBUFSIZ];
+ unsigned char header[3];
+ char *p;
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ if (len > 170) /* Prosanity check */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Message to send: \"");
+ for (i = 0; i < len; ++i)
+ fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ fprintf_unfiltered (gdb_stdlog, "\"\n");
+ }
+
+ p = buf2;
+ *p++ = '$';
+
+ if (len % 3 != 0)
+ {
+ buf[len] = '\0';
+ buf[len + 1] = '\0';
+ }
+
+ header[1] = next_msg_id;
+
+ header[2] = len;
+
+ csum = compute_checksum (csum, buf, len);
+ csum = compute_checksum (csum, header + 1, 2);
+
+ header[0] = csum;
+
+ tob64 (header, p, 3);
+ p += 4;
+ enclen = tob64 (buf, buf3, ((len + 2) / 3) * 3);
+
+ for (i = 0; i < enclen; ++i)
+ *p++ = buf3[i];
+ *p++ = '\r';
+ *p++ = '\n';
+
+ next_msg_id = (next_msg_id + 3) % 245;
+
+ /* Send it over and over until we get a positive ack. */
+
+ while (1)
+ {
+ if (remote_debug)
+ {
+ *p = '\0';
+ fprintf_unfiltered (gdb_stdlog, "Sending encoded: \"%s\"", buf2);
+ fprintf_unfiltered (gdb_stdlog,
+ " (Checksum %d, id %d, length %d)\n",
+ header[0], header[1], header[2]);
+ gdb_flush (gdb_stdlog);
+ }
+ if (serial_write (sds_desc, buf2, p - buf2))
+ perror_with_name ("putmessage: write failed");
+
+ return 1;
+ }
+}
+
+/* Come here after finding the start of the frame. Collect the rest
+ into BUF. Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (char *buf)
+{
+ char *bp;
+ int c;
+
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (sds_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ fputs_filtered ("Timeout in mid-message, retrying\n", gdb_stdlog);
+ return 0;
+ case '$':
+ if (remote_debug)
+ fputs_filtered ("Saw new packet start in middle of old one\n",
+ gdb_stdlog);
+ return 0; /* Start a new packet, count retries */
+ case '\r':
+ break;
+
+ case '\n':
+ {
+ *bp = '\000';
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Received encoded: \"%s\"\n",
+ buf);
+ return 1;
+ }
+
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Message too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ }
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. BUF is expected to be of size PBUFSIZ.
+ If FOREVER, wait forever rather than timing out; this is used
+ while the target is executing user code. */
+
+static int
+getmessage (unsigned char *buf, int forever)
+{
+ int c, c2, c3;
+ int tries;
+ int timeout;
+ int val, i, len, csum;
+ unsigned char header[3];
+ unsigned char inbuf[500];
+
+ strcpy (buf, "timeout");
+
+ if (forever)
+ {
+ timeout = watchdog > 0 ? watchdog : -1;
+ }
+
+ else
+ timeout = sds_timeout;
+
+#define MAX_TRIES 3
+
+ for (tries = 1; tries <= MAX_TRIES; tries++)
+ {
+ /* This can loop forever if the remote side sends us characters
+ continuously, but if it pauses, we'll get a zero from readchar
+ because of timeout. Then we'll count that as a retry. */
+
+ /* Note that we will only wait forever prior to the start of a packet.
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within sds_timeout intervals. */
+
+ do
+ {
+ c = readchar (timeout);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+ if (remote_debug)
+ fputs_filtered ("Timed out.\n", gdb_stdlog);
+ goto retry;
+ }
+ }
+ while (c != '$' && c != '{');
+
+ /* We might have seen a "trigraph", a sequence of three characters
+ that indicate various sorts of communication state. */
+
+ if (c == '{')
+ {
+ /* Read the other two chars of the trigraph. */
+ c2 = readchar (timeout);
+ c3 = readchar (timeout);
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Trigraph %c%c%c received\n",
+ c, c2, c3);
+ if (c3 == '+')
+ {
+ message_pending = 1;
+ return 0; /*???? */
+ }
+ continue;
+ }
+
+ val = read_frame (inbuf);
+
+ if (val == 1)
+ {
+ fromb64 (inbuf, header, 4);
+ /* (should check out other bits) */
+ fromb64 (inbuf + 4, buf, strlen (inbuf) - 4);
+
+ len = header[2];
+
+ csum = 0;
+ csum = compute_checksum (csum, buf, len);
+ csum = compute_checksum (csum, header + 1, 2);
+
+ if (csum != header[0])
+ fprintf_unfiltered (gdb_stderr,
+ "Checksum mismatch: computed %d, received %d\n",
+ csum, header[0]);
+
+ if (header[2] == 0xff)
+ fprintf_unfiltered (gdb_stderr, "Requesting resend...\n");
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "... (Got checksum %d, id %d, length %d)\n",
+ header[0], header[1], header[2]);
+ fprintf_unfiltered (gdb_stdlog, "Message received: \"");
+ for (i = 0; i < len; ++i)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x", (unsigned char) buf[i]);
+ }
+ fprintf_unfiltered (gdb_stdlog, "\"\n");
+ }
+
+ /* no ack required? */
+ return len;
+ }
+
+ /* Try the whole thing again. */
+ retry:
+ /* need to do something here */
+ ;
+ }
+
+ /* We have tried hard enough, and just can't receive the packet. Give up. */
+
+ printf_unfiltered ("Ignoring packet error, continuing...\n");
+ return 0;
+}
+
+static void
+sds_kill (void)
+{
+ /* Don't try to do anything to the target. */
+}
+
+static void
+sds_mourn (void)
+{
+ unpush_target (&sds_ops);
+ generic_mourn_inferior ();
+}
+
+static void
+sds_create_inferior (char *exec_file, char *args, char **env)
+{
+ inferior_ptid = pid_to_ptid (42000);
+
+ /* Clean up from the last time we were running. */
+ clear_proceed_status ();
+
+ /* Let the remote process run. */
+ proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
+}
+
+static void
+sds_load (char *filename, int from_tty)
+{
+ generic_load (filename, from_tty);
+
+ inferior_ptid = null_ptid;
+}
+
+/* The SDS monitor has commands for breakpoint insertion, although it
+ it doesn't actually manage the breakpoints, it just returns the
+ replaced instruction back to the debugger. */
+
+static int
+sds_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int i, retlen;
+ unsigned char *p, buf[PBUFSIZ];
+
+ p = buf;
+ *p++ = 16;
+ *p++ = 0;
+ *p++ = (int) (addr >> 24) & 0xff;
+ *p++ = (int) (addr >> 16) & 0xff;
+ *p++ = (int) (addr >> 8) & 0xff;
+ *p++ = (int) (addr) & 0xff;
+
+ retlen = sds_send (buf, p - buf);
+
+ for (i = 0; i < 4; ++i)
+ contents_cache[i] = buf[i + 2];
+
+ return 0;
+}
+
+static int
+sds_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ int i, retlen;
+ unsigned char *p, buf[PBUFSIZ];
+
+ p = buf;
+ *p++ = 17;
+ *p++ = 0;
+ *p++ = (int) (addr >> 24) & 0xff;
+ *p++ = (int) (addr >> 16) & 0xff;
+ *p++ = (int) (addr >> 8) & 0xff;
+ *p++ = (int) (addr) & 0xff;
+ for (i = 0; i < 4; ++i)
+ *p++ = contents_cache[i];
+
+ retlen = sds_send (buf, p - buf);
+
+ return 0;
+}
+
+static void
+init_sds_ops (void)
+{
+ sds_ops.to_shortname = "sds";
+ sds_ops.to_longname = "Remote serial target with SDS protocol";
+ sds_ops.to_doc = "Use a remote computer via a serial line; using the SDS protocol.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+ sds_ops.to_open = sds_open;
+ sds_ops.to_close = sds_close;
+ sds_ops.to_detach = sds_detach;
+ sds_ops.to_resume = sds_resume;
+ sds_ops.to_wait = sds_wait;
+ sds_ops.to_fetch_registers = sds_fetch_registers;
+ sds_ops.to_store_registers = sds_store_registers;
+ sds_ops.to_prepare_to_store = sds_prepare_to_store;
+ sds_ops.to_xfer_memory = sds_xfer_memory;
+ sds_ops.to_files_info = sds_files_info;
+ sds_ops.to_insert_breakpoint = sds_insert_breakpoint;
+ sds_ops.to_remove_breakpoint = sds_remove_breakpoint;
+ sds_ops.to_kill = sds_kill;
+ sds_ops.to_load = sds_load;
+ sds_ops.to_create_inferior = sds_create_inferior;
+ sds_ops.to_mourn_inferior = sds_mourn;
+ sds_ops.to_stratum = process_stratum;
+ sds_ops.to_has_all_memory = 1;
+ sds_ops.to_has_memory = 1;
+ sds_ops.to_has_stack = 1;
+ sds_ops.to_has_registers = 1;
+ sds_ops.to_has_execution = 1;
+ sds_ops.to_magic = OPS_MAGIC;
+}
+
+/* Put a command string, in args, out to the monitor and display the
+ reply message. */
+
+static void
+sds_command (char *args, int from_tty)
+{
+ char *p;
+ int i, len, retlen;
+ unsigned char buf[1000];
+
+ /* Convert hexadecimal chars into a byte buffer. */
+ p = args;
+ len = 0;
+ while (*p != '\0')
+ {
+ buf[len++] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ if (p[1] == '\0')
+ break;
+ p += 2;
+ }
+
+ retlen = sds_send (buf, len);
+
+ printf_filtered ("Reply is ");
+ for (i = 0; i < retlen; ++i)
+ {
+ printf_filtered ("%02x", buf[i]);
+ }
+ printf_filtered ("\n");
+}
+
+void
+_initialize_remote_sds (void)
+{
+ init_sds_ops ();
+ add_target (&sds_ops);
+
+ add_show_from_set (add_set_cmd ("sdstimeout", no_class,
+ var_integer, (char *) &sds_timeout,
+ "Set timeout value for sds read.\n", &setlist),
+ &showlist);
+
+ add_com ("sds", class_obscure, sds_command,
+ "Send a command to the SDS monitor.");
+}
diff --git a/contrib/gdb/gdb/remote-sim.c b/contrib/gdb/gdb/remote-sim.c
new file mode 100644
index 0000000..9b0b3fd
--- /dev/null
+++ b/contrib/gdb/gdb/remote-sim.c
@@ -0,0 +1,900 @@
+/* Generic remote debugging interface for simulators.
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2004 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 "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "remote-utils.h"
+#include "command.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "sim-regno.h"
+#include "arch-utils.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_stdtargerr);
+ }
+ return len;
+}
+
+/* GDB version of os_flush_stderr callback. */
+
+static void
+gdb_os_flush_stderr (host_callback *p)
+{
+ gdb_flush (gdb_stdtargerr);
+}
+
+/* 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);
+ }
+}
+
+int
+one2one_register_sim_regno (int regnum)
+{
+ /* Only makes sense to supply raw registers. */
+ gdb_assert (regnum >= 0 && regnum < NUM_REGS);
+ return regnum;
+}
+
+static void
+gdbsim_fetch_register (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ gdbsim_fetch_register (regno);
+ return;
+ }
+
+ switch (REGISTER_SIM_REGNO (regno))
+ {
+ case LEGACY_SIM_REGNO_IGNORE:
+ break;
+ case SIM_REGNO_DOES_NOT_EXIST:
+ {
+ /* For moment treat a `does not exist' register the same way
+ as an ``unavailable'' register. */
+ char buf[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ memset (buf, 0, MAX_REGISTER_SIZE);
+ supply_register (regno, buf);
+ set_register_cached (regno, -1);
+ break;
+ }
+ default:
+ {
+ static int warn_user = 1;
+ char buf[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ gdb_assert (regno >= 0 && regno < NUM_REGS);
+ memset (buf, 0, MAX_REGISTER_SIZE);
+ nr_bytes = sim_fetch_register (gdbsim_desc,
+ REGISTER_SIM_REGNO (regno),
+ buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ if (nr_bytes > 0 && nr_bytes != DEPRECATED_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, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ warn_user = 0;
+ }
+ /* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
+ indicating that GDB and the SIM have different ideas about
+ which registers are fetchable. */
+ /* Else if (nr_bytes < 0): an old simulator, that doesn't
+ think to return the register size. Just assume all is ok. */
+ 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, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ }
+ break;
+ }
+ }
+}
+
+
+static void
+gdbsim_store_register (int regno)
+{
+ if (regno == -1)
+ {
+ for (regno = 0; regno < NUM_REGS; regno++)
+ gdbsim_store_register (regno);
+ return;
+ }
+ else if (REGISTER_SIM_REGNO (regno) >= 0)
+ {
+ char tmp[MAX_REGISTER_SIZE];
+ int nr_bytes;
+ deprecated_read_register_gen (regno, tmp);
+ nr_bytes = sim_store_register (gdbsim_desc,
+ REGISTER_SIM_REGNO (regno),
+ tmp, DEPRECATED_REGISTER_RAW_SIZE (regno));
+ if (nr_bytes > 0 && nr_bytes != DEPRECATED_REGISTER_RAW_SIZE (regno))
+ internal_error (__FILE__, __LINE__,
+ "Register size different to expected");
+ /* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
+ indicating that GDB and the SIM have different ideas about
+ which registers are fetchable. */
+ if (sr_get_debug ())
+ {
+ printf_filtered ("gdbsim_store_register: %d", regno);
+ /* FIXME: We could print something more intelligible. */
+ dump_mem (tmp, DEPRECATED_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). */
+ switch (selected_byte_order ())
+ {
+ case BFD_ENDIAN_BIG:
+ strcat (arg_buf, " -E big");
+ break;
+ case BFD_ENDIAN_LITTLE:
+ strcat (arg_buf, " -E little");
+ break;
+ case BFD_ENDIAN_UNKNOWN:
+ break;
+ }
+ /* Specify the architecture of the target when it has been
+ explicitly specified */
+ if (selected_architecture_name () != NULL)
+ {
+ strcat (arg_buf, " --architecture=");
+ strcat (arg_buf, selected_architecture_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)
+{
+ return memory_insert_breakpoint (addr, contents_cache);
+}
+
+static int
+gdbsim_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+{
+ return memory_remove_breakpoint (addr, contents_cache);
+}
+
+/* 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_detach = gdbsim_detach;
+ gdbsim_ops.to_resume = gdbsim_resume;
+ gdbsim_ops.to_wait = gdbsim_wait;
+ 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_kill = gdbsim_kill;
+ gdbsim_ops.to_load = gdbsim_load;
+ gdbsim_ops.to_create_inferior = gdbsim_create_inferior;
+ gdbsim_ops.to_mourn_inferior = gdbsim_mourn_inferior;
+ gdbsim_ops.to_stop = gdbsim_stop;
+ gdbsim_ops.to_stratum = process_stratum;
+ 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_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
new file mode 100644
index 0000000..ce4c7ab
--- /dev/null
+++ b/contrib/gdb/gdb/remote-st.c
@@ -0,0 +1,803 @@
+/* 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_unfiltered (gdb_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_unfiltered (gdb_stderr, "Error writing log file.\n");
+ if (fclose (log_file) != 0)
+ fprintf_unfiltered (gdb_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_NAME just happens return
+ 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_unfiltered (gdb_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_unfiltered (gdb_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_detach = st2000_detach;
+ st2000_ops.to_resume = st2000_resume;
+ st2000_ops.to_wait = st2000_wait;
+ 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_kill = st2000_kill;
+ st2000_ops.to_create_inferior = st2000_create_inferior;
+ st2000_ops.to_mourn_inferior = st2000_mourn_inferior;
+ st2000_ops.to_stratum = process_stratum;
+ 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_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/remote-vx.c b/contrib/gdb/gdb/remote-vx.c
new file mode 100644
index 0000000..fd51781
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vx.c
@@ -0,0 +1,1409 @@
+/* Memory-access and commands for remote VxWorks processes, for GDB.
+
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999,
+ 2000, 2001, 2002 Free Software Foundation, Inc.
+
+ Contributed by Wind River Systems and 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 "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "symtab.h"
+#include "complaints.h"
+#include "gdbcmd.h"
+#include "bfd.h" /* Required by objfiles.h. */
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#define malloc bogon_malloc /* Sun claims "char *malloc()" not void * */
+#define free bogon_free /* Sun claims "int free()" not void */
+#define realloc bogon_realloc /* Sun claims "char *realloc()", not void * */
+#include <rpc/rpc.h>
+#undef malloc
+#undef free
+#undef realloc
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#include "vx-share/ptrace.h"
+#include "vx-share/xdr_ptrace.h"
+#include "vx-share/xdr_ld.h"
+#include "vx-share/xdr_rdb.h"
+#include "vx-share/dbgRpcLib.h"
+
+#include <symtab.h>
+
+/* Maximum number of bytes to transfer in a single
+ PTRACE_{READ,WRITE}DATA request. */
+#define VX_MEMXFER_MAX 4096
+
+extern void vx_read_register ();
+extern void vx_write_register ();
+extern void symbol_file_command ();
+extern enum stop_kind stop_soon; /* for wait_for_inferior */
+
+static int net_step ();
+static int net_ptrace_clnt_call (); /* Forward decl */
+static enum clnt_stat net_clnt_call (); /* Forward decl */
+
+/* Target ops structure for accessing memory and such over the net */
+
+static struct target_ops vx_ops;
+
+/* Target ops structure for accessing VxWorks child processes over the net */
+
+static struct target_ops vx_run_ops;
+
+/* Saved name of target host and called function for "info files".
+ Both malloc'd. */
+
+static char *vx_host;
+static char *vx_running; /* Called function */
+
+/* Nonzero means target that is being debugged remotely has a floating
+ point processor. */
+
+int target_has_fp;
+
+/* Default error message when the network is forking up. */
+
+static const char rpcerr[] = "network target debugging: rpc error";
+
+CLIENT *pClient; /* client used in net debugging */
+static int ptraceSock = RPC_ANYSOCK;
+
+enum clnt_stat net_clnt_call ();
+static void parse_args ();
+
+static struct timeval rpcTimeout =
+{10, 0};
+
+static char *skip_white_space ();
+static char *find_white_space ();
+
+/* Tell the VxWorks target system to download a file.
+ The load addresses of the text, data, and bss segments are
+ stored in *pTextAddr, *pDataAddr, and *pBssAddr (respectively).
+ Returns 0 for success, -1 for failure. */
+
+static int
+net_load (char *filename, CORE_ADDR *pTextAddr, CORE_ADDR *pDataAddr,
+ CORE_ADDR *pBssAddr)
+{
+ enum clnt_stat status;
+ struct ldfile ldstruct;
+ struct timeval load_timeout;
+
+ memset ((char *) &ldstruct, '\0', sizeof (ldstruct));
+
+ /* We invoke clnt_call () here directly, instead of through
+ net_clnt_call (), because we need to set a large timeout value.
+ The load on the target side can take quite a while, easily
+ more than 10 seconds. The user can kill this call by typing
+ CTRL-C if there really is a problem with the load.
+
+ Do not change the tv_sec value without checking -- select() imposes
+ a limit of 10**8 on it for no good reason that I can see... */
+
+ load_timeout.tv_sec = 99999999; /* A large number, effectively inf. */
+ load_timeout.tv_usec = 0;
+
+ status = clnt_call (pClient, VX_LOAD, xdr_wrapstring, &filename, xdr_ldfile,
+ &ldstruct, load_timeout);
+
+ if (status == RPC_SUCCESS)
+ {
+ if (*ldstruct.name == 0) /* load failed on VxWorks side */
+ return -1;
+ *pTextAddr = ldstruct.txt_addr;
+ *pDataAddr = ldstruct.data_addr;
+ *pBssAddr = ldstruct.bss_addr;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+/* returns 0 if successful, errno if RPC failed or VxWorks complains. */
+
+static int
+net_break (int addr, u_long procnum)
+{
+ enum clnt_stat status;
+ int break_status;
+ Rptrace ptrace_in; /* XXX This is stupid. It doesn't need to be a ptrace
+ structure. How about something smaller? */
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ break_status = 0;
+
+ ptrace_in.addr = addr;
+ ptrace_in.pid = PIDGET (inferior_ptid);
+
+ status = net_clnt_call (procnum, xdr_rptrace, &ptrace_in, xdr_int,
+ &break_status);
+
+ if (status != RPC_SUCCESS)
+ return errno;
+
+ if (break_status == -1)
+ return ENOMEM;
+ return break_status; /* probably (FIXME) zero */
+}
+
+/* returns 0 if successful, errno otherwise */
+
+static int
+vx_insert_breakpoint (int addr)
+{
+ return net_break (addr, VX_BREAK_ADD);
+}
+
+/* returns 0 if successful, errno otherwise */
+
+static int
+vx_remove_breakpoint (int addr)
+{
+ return net_break (addr, VX_BREAK_DELETE);
+}
+
+/* Start an inferior process and sets inferior_ptid to its pid.
+ EXEC_FILE is the file to run.
+ ALLARGS is a string containing the arguments to the program.
+ ENV is the environment vector to pass.
+ Returns process id. Errors reported with error().
+ On VxWorks, we ignore exec_file. */
+
+static void
+vx_create_inferior (char *exec_file, char *args, char **env)
+{
+ enum clnt_stat status;
+ arg_array passArgs;
+ TASK_START taskStart;
+
+ memset ((char *) &passArgs, '\0', sizeof (passArgs));
+ memset ((char *) &taskStart, '\0', sizeof (taskStart));
+
+ /* parse arguments, put them in passArgs */
+
+ parse_args (args, &passArgs);
+
+ if (passArgs.arg_array_len == 0)
+ error ("You must specify a function name to run, and arguments if any");
+
+ status = net_clnt_call (PROCESS_START, xdr_arg_array, &passArgs,
+ xdr_TASK_START, &taskStart);
+
+ if ((status != RPC_SUCCESS) || (taskStart.status == -1))
+ error ("Can't create process on remote target machine");
+
+ /* Save the name of the running function */
+ vx_running = savestring (passArgs.arg_array_val[0],
+ strlen (passArgs.arg_array_val[0]));
+
+ push_target (&vx_run_ops);
+ inferior_ptid = pid_to_ptid (taskStart.pid);
+
+ /* We will get a trace trap after one instruction.
+ Insert breakpoints and continue. */
+
+ 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 ();
+
+ stop_soon = STOP_QUIETLY;
+ wait_for_inferior (); /* Get the task spawn event */
+ stop_soon = NO_STOP_QUIETLY;
+
+ /* insert_step_breakpoint (); FIXME, do we need this? */
+ proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Fill ARGSTRUCT in argc/argv form with the arguments from the
+ argument string ARGSTRING. */
+
+static void
+parse_args (char *arg_string, arg_array *arg_struct)
+{
+ int arg_count = 0; /* number of arguments */
+ int arg_index = 0;
+ char *p0;
+
+ memset ((char *) arg_struct, '\0', sizeof (arg_array));
+
+ /* first count how many arguments there are */
+
+ p0 = arg_string;
+ while (*p0 != '\0')
+ {
+ if (*(p0 = skip_white_space (p0)) == '\0')
+ break;
+ p0 = find_white_space (p0);
+ arg_count++;
+ }
+
+ arg_struct->arg_array_len = arg_count;
+ arg_struct->arg_array_val = (char **) xmalloc ((arg_count + 1)
+ * sizeof (char *));
+
+ /* now copy argument strings into arg_struct. */
+
+ while (*(arg_string = skip_white_space (arg_string)))
+ {
+ p0 = find_white_space (arg_string);
+ arg_struct->arg_array_val[arg_index++] = savestring (arg_string,
+ p0 - arg_string);
+ arg_string = p0;
+ }
+
+ arg_struct->arg_array_val[arg_count] = NULL;
+}
+
+/* Advance a string pointer across whitespace and return a pointer
+ to the first non-white character. */
+
+static char *
+skip_white_space (char *p)
+{
+ while (*p == ' ' || *p == '\t')
+ p++;
+ return p;
+}
+
+/* Search for the first unquoted whitespace character in a string.
+ Returns a pointer to the character, or to the null terminator
+ if no whitespace is found. */
+
+static char *
+find_white_space (char *p)
+{
+ int c;
+
+ while ((c = *p) != ' ' && c != '\t' && c)
+ {
+ if (c == '\'' || c == '"')
+ {
+ while (*++p != c && *p)
+ {
+ if (*p == '\\')
+ p++;
+ }
+ if (!*p)
+ break;
+ }
+ p++;
+ }
+ return p;
+}
+
+/* Poll the VxWorks target system for an event related
+ to the debugged task.
+ Returns -1 if remote wait failed, task status otherwise. */
+
+static int
+net_wait (RDB_EVENT *pEvent)
+{
+ int pid;
+ enum clnt_stat status;
+
+ memset ((char *) pEvent, '\0', sizeof (RDB_EVENT));
+
+ pid = PIDGET (inferior_ptid);
+ status = net_clnt_call (PROCESS_WAIT, xdr_int, &pid, xdr_RDB_EVENT,
+ pEvent);
+
+ /* return (status == RPC_SUCCESS)? pEvent->status: -1; */
+ if (status == RPC_SUCCESS)
+ return ((pEvent->status) ? 1 : 0);
+ else if (status == RPC_TIMEDOUT)
+ return (1);
+ else
+ return (-1);
+}
+
+/* Suspend the remote task.
+ Returns -1 if suspend fails on target system, 0 otherwise. */
+
+static int
+net_quit (void)
+{
+ int pid;
+ int quit_status;
+ enum clnt_stat status;
+
+ quit_status = 0;
+
+ /* don't let rdbTask suspend itself by passing a pid of 0 */
+
+ if ((pid = PIDGET (inferior_ptid)) == 0)
+ return -1;
+
+ status = net_clnt_call (VX_TASK_SUSPEND, xdr_int, &pid, xdr_int,
+ &quit_status);
+
+ return (status == RPC_SUCCESS) ? quit_status : -1;
+}
+
+/* Read a register or registers from the remote system. */
+
+void
+net_read_registers (char *reg_buf, int len, u_long procnum)
+{
+ int status;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ C_bytes out_data;
+ char message[100];
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+
+ /* Initialize RPC input argument structure. */
+
+ ptrace_in.pid = PIDGET (inferior_ptid);
+ ptrace_in.info.ttype = NOINFO;
+
+ /* Initialize RPC return value structure. */
+
+ out_data.bytes = reg_buf;
+ out_data.len = len;
+ ptrace_out.info.more_data = (caddr_t) & out_data;
+
+ /* Call RPC; take an error exit if appropriate. */
+
+ status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
+ if (status)
+ error (rpcerr);
+ if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ sprintf (message, "reading %s registers", (procnum == PTRACE_GETREGS)
+ ? "general-purpose"
+ : "floating-point");
+ perror_with_name (message);
+ }
+}
+
+/* Write register values to a VxWorks target. REG_BUF points to a buffer
+ containing the raw register values, LEN is the length of REG_BUF in
+ bytes, and PROCNUM is the RPC procedure number (PTRACE_SETREGS or
+ PTRACE_SETFPREGS). An error exit is taken if the RPC call fails or
+ if an error status is returned by the remote debug server. This is
+ a utility routine used by vx_write_register (). */
+
+void
+net_write_registers (char *reg_buf, int len, u_long procnum)
+{
+ int status;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ C_bytes in_data;
+ char message[100];
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+
+ /* Initialize RPC input argument structure. */
+
+ in_data.bytes = reg_buf;
+ in_data.len = len;
+
+ ptrace_in.pid = PIDGET (inferior_ptid);
+ ptrace_in.info.ttype = DATA;
+ ptrace_in.info.more_data = (caddr_t) & in_data;
+
+ /* Call RPC; take an error exit if appropriate. */
+
+ status = net_ptrace_clnt_call (procnum, &ptrace_in, &ptrace_out);
+ if (status)
+ error (rpcerr);
+ if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ sprintf (message, "writing %s registers", (procnum == PTRACE_SETREGS)
+ ? "general-purpose"
+ : "floating-point");
+ perror_with_name (message);
+ }
+}
+
+/* Prepare to store registers. Since we will store all of them,
+ read out their current values now. */
+
+static void
+vx_prepare_to_store (void)
+{
+ /* Fetch all registers, if any of them are not yet fetched. */
+ deprecated_read_register_bytes (0, NULL, DEPRECATED_REGISTER_BYTES);
+}
+
+/* Copy LEN bytes to or from remote inferior's memory starting at MEMADDR
+ to debugger memory starting at MYADDR. WRITE is true if writing to the
+ inferior. TARGET is unused.
+ Result is the number of bytes written or read (zero if error). The
+ protocol allows us to return a negative count, indicating that we can't
+ handle the current address but can handle one N bytes further, but
+ vxworks doesn't give us that information. */
+
+static int
+vx_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ struct mem_attrib *attrib, struct target_ops *target)
+{
+ int status;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ C_bytes data;
+ enum ptracereq request;
+ int nleft, nxfer;
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+
+ ptrace_in.pid = PIDGET (inferior_ptid); /* XXX pid unnecessary for READDATA */
+ ptrace_in.addr = (int) memaddr; /* Where from */
+ ptrace_in.data = len; /* How many bytes */
+
+ if (write)
+ {
+ ptrace_in.info.ttype = DATA;
+ ptrace_in.info.more_data = (caddr_t) & data;
+
+ data.bytes = (caddr_t) myaddr; /* Where from */
+ data.len = len; /* How many bytes (again, for XDR) */
+ request = PTRACE_WRITEDATA;
+ }
+ else
+ {
+ ptrace_out.info.more_data = (caddr_t) & data;
+ request = PTRACE_READDATA;
+ }
+ /* Loop until the entire request has been satisfied, transferring
+ at most VX_MEMXFER_MAX bytes per iteration. Break from the loop
+ if an error status is returned by the remote debug server. */
+
+ nleft = len;
+ status = 0;
+
+ while (nleft > 0 && status == 0)
+ {
+ nxfer = min (nleft, VX_MEMXFER_MAX);
+
+ ptrace_in.addr = (int) memaddr;
+ ptrace_in.data = nxfer;
+ data.bytes = (caddr_t) myaddr;
+ data.len = nxfer;
+
+ /* Request a block from the remote debug server; if RPC fails,
+ report an error and return to debugger command level. */
+
+ if (net_ptrace_clnt_call (request, &ptrace_in, &ptrace_out))
+ error (rpcerr);
+
+ status = ptrace_out.status;
+ if (status == 0)
+ {
+ memaddr += nxfer;
+ myaddr += nxfer;
+ nleft -= nxfer;
+ }
+ else
+ {
+ /* A target-side error has ocurred. Set errno to the error
+ code chosen by the target so that a later perror () will
+ say something meaningful. */
+
+ errno = ptrace_out.errno_num;
+ }
+ }
+
+ /* Return the number of bytes transferred. */
+
+ return (len - nleft);
+}
+
+static void
+vx_files_info (void)
+{
+ printf_unfiltered ("\tAttached to host `%s'", vx_host);
+ printf_unfiltered (", which has %sfloating point", target_has_fp ? "" : "no ");
+ printf_unfiltered (".\n");
+}
+
+static void
+vx_run_files_info (void)
+{
+ printf_unfiltered ("\tRunning %s VxWorks process %s",
+ vx_running ? "child" : "attached",
+ local_hex_string (PIDGET (inferior_ptid)));
+ if (vx_running)
+ printf_unfiltered (", function `%s'", vx_running);
+ printf_unfiltered (".\n");
+}
+
+static void
+vx_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+ int status;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ CORE_ADDR cont_addr;
+
+ if (ptid_equal (ptid, minus_one_ptid))
+ ptid = inferior_ptid;
+
+ if (siggnal != 0 && siggnal != stop_signal)
+ error ("Cannot send signals to VxWorks processes");
+
+ /* Set CONT_ADDR to the address at which we are continuing,
+ or to 1 if we are continuing from where the program stopped.
+ This conforms to traditional ptrace () usage, but at the same
+ time has special meaning for the VxWorks remote debug server.
+ If the address is not 1, the server knows that the target
+ program is jumping to a new address, which requires special
+ handling if there is a breakpoint at the new address. */
+
+ cont_addr = read_register (PC_REGNUM);
+ if (cont_addr == stop_pc)
+ cont_addr = 1;
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+
+ ptrace_in.pid = PIDGET (ptid);
+ ptrace_in.addr = cont_addr; /* Target side insists on this, or it panics. */
+
+ if (step)
+ status = net_step ();
+ else
+ status = net_ptrace_clnt_call (PTRACE_CONT, &ptrace_in, &ptrace_out);
+
+ if (status)
+ error (rpcerr);
+ if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ perror_with_name ("Resuming remote process");
+ }
+}
+
+static void
+vx_mourn_inferior (void)
+{
+ pop_target (); /* Pop back to no-child state */
+ generic_mourn_inferior ();
+}
+
+
+static void vx_add_symbols (char *, int, CORE_ADDR, CORE_ADDR, CORE_ADDR);
+
+struct find_sect_args
+ {
+ CORE_ADDR text_start;
+ CORE_ADDR data_start;
+ CORE_ADDR bss_start;
+ };
+
+static void find_sect (bfd *, asection *, void *);
+
+static void
+find_sect (bfd *abfd, asection *sect, void *obj)
+{
+ struct find_sect_args *args = (struct find_sect_args *) obj;
+
+ if (bfd_get_section_flags (abfd, sect) & (SEC_CODE & SEC_READONLY))
+ args->text_start = bfd_get_section_vma (abfd, sect);
+ else if (bfd_get_section_flags (abfd, sect) & SEC_ALLOC)
+ {
+ if (bfd_get_section_flags (abfd, sect) & SEC_LOAD)
+ {
+ /* Exclude .ctor and .dtor sections which have SEC_CODE set but not
+ SEC_DATA. */
+ if (bfd_get_section_flags (abfd, sect) & SEC_DATA)
+ args->data_start = bfd_get_section_vma (abfd, sect);
+ }
+ else
+ args->bss_start = bfd_get_section_vma (abfd, sect);
+ }
+}
+
+static void
+vx_add_symbols (char *name, int from_tty, CORE_ADDR text_addr,
+ CORE_ADDR data_addr, CORE_ADDR bss_addr)
+{
+ struct section_offsets *offs;
+ struct objfile *objfile;
+ struct find_sect_args ss;
+
+ /* It might be nice to suppress the breakpoint_re_set which happens here
+ because we are going to do one again after the objfile_relocate. */
+ objfile = symbol_file_add (name, from_tty, NULL, 0, 0);
+
+ /* This is a (slightly cheesy) way of superceding the old symbols. A less
+ cheesy way would be to find the objfile with the same name and
+ free_objfile it. */
+ objfile_to_front (objfile);
+
+ offs =
+ (struct section_offsets *)
+ alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+ memcpy (offs, objfile->section_offsets,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ ss.text_start = 0;
+ ss.data_start = 0;
+ ss.bss_start = 0;
+ bfd_map_over_sections (objfile->obfd, find_sect, &ss);
+
+ /* Both COFF and b.out frontends use these SECT_OFF_* values. */
+ offs->offsets[SECT_OFF_TEXT (objfile)] = text_addr - ss.text_start;
+ offs->offsets[SECT_OFF_DATA (objfile)] = data_addr - ss.data_start;
+ offs->offsets[SECT_OFF_BSS (objfile)] = bss_addr - ss.bss_start;
+ objfile_relocate (objfile, offs);
+}
+
+/* This function allows the addition of incrementally linked object files. */
+
+static void
+vx_load_command (char *arg_string, int from_tty)
+{
+ CORE_ADDR text_addr;
+ CORE_ADDR data_addr;
+ CORE_ADDR bss_addr;
+
+ if (arg_string == 0)
+ error ("The load command takes a file name");
+
+ arg_string = tilde_expand (arg_string);
+ make_cleanup (xfree, arg_string);
+
+ dont_repeat ();
+
+ /* Refuse to load the module if a debugged task is running. Doing so
+ can have a number of unpleasant consequences to the running task. */
+
+ if (PIDGET (inferior_ptid) != 0 && target_has_execution)
+ {
+ if (query ("You may not load a module while the target task is running.\n\
+Kill the target task? "))
+ target_kill ();
+ else
+ error ("Load canceled.");
+ }
+
+ QUIT;
+ immediate_quit++;
+ if (net_load (arg_string, &text_addr, &data_addr, &bss_addr) == -1)
+ error ("Load failed on target machine");
+ immediate_quit--;
+
+ vx_add_symbols (arg_string, from_tty, text_addr, data_addr, bss_addr);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+}
+
+/* Single step the target program at the source or machine level.
+ Takes an error exit if rpc fails.
+ Returns -1 if remote single-step operation fails, else 0. */
+
+static int
+net_step (void)
+{
+ enum clnt_stat status;
+ int step_status;
+ SOURCE_STEP source_step;
+
+ source_step.taskId = PIDGET (inferior_ptid);
+
+ if (step_range_end)
+ {
+ source_step.startAddr = step_range_start;
+ source_step.endAddr = step_range_end;
+ }
+ else
+ {
+ source_step.startAddr = 0;
+ source_step.endAddr = 0;
+ }
+
+ status = net_clnt_call (VX_SOURCE_STEP, xdr_SOURCE_STEP, &source_step,
+ xdr_int, &step_status);
+
+ if (status == RPC_SUCCESS)
+ return step_status;
+ else
+ error (rpcerr);
+}
+
+/* Emulate ptrace using RPC calls to the VxWorks target system.
+ Returns nonzero (-1) if RPC status to VxWorks is bad, 0 otherwise. */
+
+static int
+net_ptrace_clnt_call (enum ptracereq request, Rptrace *pPtraceIn,
+ Ptrace_return *pPtraceOut)
+{
+ enum clnt_stat status;
+
+ status = net_clnt_call (request, xdr_rptrace, pPtraceIn, xdr_ptrace_return,
+ pPtraceOut);
+
+ if (status != RPC_SUCCESS)
+ return -1;
+
+ return 0;
+}
+
+/* Query the target for the name of the file from which VxWorks was
+ booted. pBootFile is the address of a pointer to the buffer to
+ receive the file name; if the pointer pointed to by pBootFile is
+ NULL, memory for the buffer will be allocated by XDR.
+ Returns -1 if rpc failed, 0 otherwise. */
+
+static int
+net_get_boot_file (char **pBootFile)
+{
+ enum clnt_stat status;
+
+ status = net_clnt_call (VX_BOOT_FILE_INQ, xdr_void, (char *) 0,
+ xdr_wrapstring, pBootFile);
+ return (status == RPC_SUCCESS) ? 0 : -1;
+}
+
+/* Fetch a list of loaded object modules from the VxWorks target
+ and store in PLOADTABLE.
+ Returns -1 if rpc failed, 0 otherwise
+ There's no way to check if the returned loadTable is correct.
+ VxWorks doesn't check it. */
+
+static int
+net_get_symbols (ldtabl *pLoadTable)
+{
+ enum clnt_stat status;
+
+ memset ((char *) pLoadTable, '\0', sizeof (struct ldtabl));
+
+ status = net_clnt_call (VX_STATE_INQ, xdr_void, 0, xdr_ldtabl, pLoadTable);
+ return (status == RPC_SUCCESS) ? 0 : -1;
+}
+
+/* Look up a symbol in the VxWorks target's symbol table.
+ Returns status of symbol read on target side (0=success, -1=fail)
+ Returns -1 and complain()s if rpc fails. */
+
+static int
+vx_lookup_symbol (char *name, /* symbol name */
+ CORE_ADDR *pAddr)
+{
+ enum clnt_stat status;
+ SYMBOL_ADDR symbolAddr;
+
+ *pAddr = 0;
+ memset ((char *) &symbolAddr, '\0', sizeof (symbolAddr));
+
+ status = net_clnt_call (VX_SYMBOL_INQ, xdr_wrapstring, &name,
+ xdr_SYMBOL_ADDR, &symbolAddr);
+ if (status != RPC_SUCCESS)
+ {
+ complaint (&symfile_complaints, "Lost contact with VxWorks target");
+ return -1;
+ }
+
+ *pAddr = symbolAddr.addr;
+ return symbolAddr.status;
+}
+
+/* Check to see if the VxWorks target has a floating point coprocessor.
+ Returns 1 if target has floating point processor, 0 otherwise.
+ Calls error() if rpc fails. */
+
+static int
+net_check_for_fp (void)
+{
+ enum clnt_stat status;
+ bool_t fp = 0; /* true if fp processor is present on target board */
+
+ status = net_clnt_call (VX_FP_INQUIRE, xdr_void, 0, xdr_bool, &fp);
+ if (status != RPC_SUCCESS)
+ error (rpcerr);
+
+ return (int) fp;
+}
+
+/* Establish an RPC connection with the VxWorks target system.
+ Calls error () if unable to establish connection. */
+
+static void
+net_connect (char *host)
+{
+ struct sockaddr_in destAddr;
+ struct hostent *destHost;
+ unsigned long addr;
+
+ /* Get the internet address for the given host. Allow a numeric
+ IP address or a hostname. */
+
+ addr = inet_addr (host);
+ if (addr == -1)
+ {
+ destHost = (struct hostent *) gethostbyname (host);
+ if (destHost == NULL)
+ /* FIXME: Probably should include hostname here in quotes.
+ For example if the user types "target vxworks vx960 " it should
+ say "Invalid host `vx960 '." not just "Invalid hostname". */
+ error ("Invalid hostname. Couldn't find remote host address.");
+ addr = *(unsigned long *) destHost->h_addr;
+ }
+
+ memset (&destAddr, '\0', sizeof (destAddr));
+
+ destAddr.sin_addr.s_addr = addr;
+ destAddr.sin_family = AF_INET;
+ destAddr.sin_port = 0; /* set to actual port that remote
+ ptrace is listening on. */
+
+ /* Create a tcp client transport on which to issue
+ calls to the remote ptrace server. */
+
+ ptraceSock = RPC_ANYSOCK;
+ pClient = clnttcp_create (&destAddr, RDBPROG, RDBVERS, &ptraceSock, 0, 0);
+ /* FIXME, here is where we deal with different version numbers of the
+ proto */
+
+ if (pClient == NULL)
+ {
+ clnt_pcreateerror ("\tnet_connect");
+ error ("Couldn't connect to remote target.");
+ }
+}
+
+/* Sleep for the specified number of milliseconds
+ * (assumed to be less than 1000).
+ * If select () is interrupted, returns immediately;
+ * takes an error exit if select () fails for some other reason.
+ */
+
+static void
+sleep_ms (long ms)
+{
+ struct timeval select_timeout;
+ int status;
+
+ select_timeout.tv_sec = 0;
+ select_timeout.tv_usec = ms * 1000;
+
+ status = select (0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0,
+ &select_timeout);
+
+ if (status < 0 && errno != EINTR)
+ perror_with_name ("select");
+}
+
+static ptid_t
+vx_wait (ptid_t ptid_to_wait_for, struct target_waitstatus *status)
+{
+ int pid;
+ RDB_EVENT rdbEvent;
+ int quit_failed;
+
+ do
+ {
+ /* If CTRL-C is hit during this loop,
+ suspend the inferior process. */
+
+ quit_failed = 0;
+ if (quit_flag)
+ {
+ quit_failed = (net_quit () == -1);
+ quit_flag = 0;
+ }
+
+ /* If a net_quit () or net_wait () call has failed,
+ allow the user to break the connection with the target.
+ We can't simply error () out of this loop, since the
+ data structures representing the state of the inferior
+ are in an inconsistent state. */
+
+ if (quit_failed || net_wait (&rdbEvent) == -1)
+ {
+ terminal_ours ();
+ if (query ("Can't %s. Disconnect from target system? ",
+ (quit_failed) ? "suspend remote task"
+ : "get status of remote task"))
+ {
+ target_mourn_inferior ();
+ error ("Use the \"target\" command to reconnect.");
+ }
+ else
+ {
+ terminal_inferior ();
+ continue;
+ }
+ }
+
+ pid = rdbEvent.taskId;
+ if (pid == 0)
+ {
+ sleep_ms (200); /* FIXME Don't kill the network too badly */
+ }
+ else if (pid != PIDGET (inferior_ptid))
+ internal_error (__FILE__, __LINE__,
+ "Bad pid for debugged task: %s\n",
+ local_hex_string ((unsigned long) pid));
+ }
+ while (pid == 0);
+
+ /* The mostly likely kind. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+
+ switch (rdbEvent.eventType)
+ {
+ case EVENT_EXIT:
+ status->kind = TARGET_WAITKIND_EXITED;
+ /* FIXME is it possible to distinguish between a
+ normal vs abnormal exit in VxWorks? */
+ status->value.integer = 0;
+ break;
+
+ case EVENT_START:
+ /* Task was just started. */
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+
+ case EVENT_STOP:
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ /* XXX was it stopped by a signal? act accordingly */
+ break;
+
+ case EVENT_BREAK: /* Breakpoint was hit. */
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+
+ case EVENT_SUSPEND: /* Task was suspended, probably by ^C. */
+ status->value.sig = TARGET_SIGNAL_INT;
+ break;
+
+ case EVENT_BUS_ERR: /* Task made evil nasty reference. */
+ status->value.sig = TARGET_SIGNAL_BUS;
+ break;
+
+ case EVENT_ZERO_DIV: /* Division by zero */
+ status->value.sig = TARGET_SIGNAL_FPE;
+ break;
+
+ case EVENT_SIGNAL:
+#ifdef I80960
+ status->value.sig = i960_fault_to_signal (rdbEvent.sigType);
+#else
+ /* Back in the old days, before enum target_signal, this code used
+ to add NSIG to the signal number and claim that PRINT_RANDOM_SIGNAL
+ would take care of it. But PRINT_RANDOM_SIGNAL has never been
+ defined except on the i960, so I don't really know what we are
+ supposed to do on other architectures. */
+ status->value.sig = TARGET_SIGNAL_UNKNOWN;
+#endif
+ break;
+ } /* switch */
+ return pid_to_ptid (pid);
+}
+
+static int
+symbol_stub (char *arg)
+{
+ symbol_file_add_main (arg, 0);
+ return 1;
+}
+
+static int
+add_symbol_stub (char *arg)
+{
+ struct ldfile *pLoadFile = (struct ldfile *) arg;
+
+ printf_unfiltered ("\t%s: ", pLoadFile->name);
+ vx_add_symbols (pLoadFile->name, 0, pLoadFile->txt_addr,
+ pLoadFile->data_addr, pLoadFile->bss_addr);
+ printf_unfiltered ("ok\n");
+ return 1;
+}
+/* Target command for VxWorks target systems.
+
+ Used in vxgdb. Takes the name of a remote target machine
+ running vxWorks and connects to it to initialize remote network
+ debugging. */
+
+static void
+vx_open (char *args, int from_tty)
+{
+ extern int close ();
+ char *bootFile;
+ extern char *source_path;
+ struct ldtabl loadTable;
+ struct ldfile *pLoadFile;
+ int i;
+ extern CLIENT *pClient;
+ int symbols_added = 0;
+
+ if (!args)
+ error_no_arg ("target machine name");
+
+ target_preopen (from_tty);
+
+ unpush_target (&vx_ops);
+ printf_unfiltered ("Attaching remote machine across net...\n");
+ gdb_flush (gdb_stdout);
+
+ /* Allow the user to kill the connect attempt by typing ^C.
+ Wait until the call to target_has_fp () completes before
+ disallowing an immediate quit, since even if net_connect ()
+ is successful, the remote debug server might be hung. */
+
+ immediate_quit++;
+
+ net_connect (args);
+ target_has_fp = net_check_for_fp ();
+ printf_filtered ("Connected to %s.\n", args);
+
+ immediate_quit--;
+
+ push_target (&vx_ops);
+
+ /* Save a copy of the target host's name. */
+ vx_host = savestring (args, strlen (args));
+
+ /* Find out the name of the file from which the target was booted
+ and load its symbol table. */
+
+ printf_filtered ("Looking in Unix path for all loaded modules:\n");
+ bootFile = NULL;
+ if (!net_get_boot_file (&bootFile))
+ {
+ if (*bootFile)
+ {
+ printf_filtered ("\t%s: ", bootFile);
+ /* This assumes that the kernel is never relocated. Hope that is an
+ accurate assumption. */
+ if (catch_errors
+ (symbol_stub,
+ bootFile,
+ "Error while reading symbols from boot file:\n",
+ RETURN_MASK_ALL))
+ puts_filtered ("ok\n");
+ }
+ else if (from_tty)
+ printf_unfiltered ("VxWorks kernel symbols not loaded.\n");
+ }
+ else
+ error ("Can't retrieve boot file name from target machine.");
+
+ clnt_freeres (pClient, xdr_wrapstring, &bootFile);
+
+ if (net_get_symbols (&loadTable) != 0)
+ error ("Can't read loaded modules from target machine");
+
+ i = 0 - 1;
+ while (++i < loadTable.tbl_size)
+ {
+ QUIT; /* FIXME, avoids clnt_freeres below: mem leak */
+ pLoadFile = &loadTable.tbl_ent[i];
+#ifdef WRS_ORIG
+ {
+ int desc;
+ struct cleanup *old_chain;
+ char *fullname = NULL;
+
+ desc = openp (source_path, 0, pLoadFile->name, O_RDONLY, 0, &fullname);
+ if (desc < 0)
+ perror_with_name (pLoadFile->name);
+ old_chain = make_cleanup (close, desc);
+ add_file_at_addr (fullname, desc, pLoadFile->txt_addr, pLoadFile->data_addr,
+ pLoadFile->bss_addr);
+ do_cleanups (old_chain);
+ }
+#else
+ /* FIXME: Is there something better to search than the PATH? (probably
+ not the source path, since source might be in different directories
+ than objects. */
+
+ if (catch_errors (add_symbol_stub, (char *) pLoadFile, (char *) 0,
+ RETURN_MASK_ALL))
+ symbols_added = 1;
+#endif
+ }
+ printf_filtered ("Done.\n");
+
+ clnt_freeres (pClient, xdr_ldtabl, &loadTable);
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ if (symbols_added)
+ reinit_frame_cache ();
+}
+
+/* Takes a task started up outside of gdb and ``attaches'' to it.
+ This stops it cold in its tracks and allows us to start tracing it. */
+
+static void
+vx_attach (char *args, int from_tty)
+{
+ unsigned long pid;
+ char *cptr = 0;
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ int status;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+ pid = strtoul (args, &cptr, 0);
+ if ((cptr == args) || (*cptr != '\0'))
+ error ("Invalid process-id -- give a single number in decimal or 0xhex");
+
+ if (from_tty)
+ printf_unfiltered ("Attaching pid %s.\n",
+ local_hex_string ((unsigned long) pid));
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+ ptrace_in.pid = pid;
+
+ status = net_ptrace_clnt_call (PTRACE_ATTACH, &ptrace_in, &ptrace_out);
+ if (status == -1)
+ error (rpcerr);
+ if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ perror_with_name ("Attaching remote process");
+ }
+
+ /* It worked... */
+
+ inferior_ptid = pid_to_ptid (pid);
+ push_target (&vx_run_ops);
+
+ if (vx_running)
+ xfree (vx_running);
+ vx_running = 0;
+}
+
+/* detach_command --
+ takes a program previously attached to and detaches it.
+ The program resumes execution 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. 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 the normal ptrace (PTRACE_TRACEME). */
+
+static void
+vx_detach (char *args, int from_tty)
+{
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ int signal = 0;
+ int status;
+
+ if (args)
+ error ("Argument given to VxWorks \"detach\".");
+
+ if (from_tty)
+ printf_unfiltered ("Detaching pid %s.\n",
+ local_hex_string (
+ (unsigned long) PIDGET (inferior_ptid)));
+
+ if (args) /* FIXME, should be possible to leave suspended */
+ signal = atoi (args);
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+ ptrace_in.pid = PIDGET (inferior_ptid);
+
+ status = net_ptrace_clnt_call (PTRACE_DETACH, &ptrace_in, &ptrace_out);
+ if (status == -1)
+ error (rpcerr);
+ if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ perror_with_name ("Detaching VxWorks process");
+ }
+
+ inferior_ptid = null_ptid;
+ pop_target (); /* go back to non-executing VxWorks connection */
+}
+
+/* vx_kill -- takes a running task and wipes it out. */
+
+static void
+vx_kill (void)
+{
+ Rptrace ptrace_in;
+ Ptrace_return ptrace_out;
+ int status;
+
+ printf_unfiltered ("Killing pid %s.\n", local_hex_string ((unsigned long) PIDGET (inferior_ptid)));
+
+ memset ((char *) &ptrace_in, '\0', sizeof (ptrace_in));
+ memset ((char *) &ptrace_out, '\0', sizeof (ptrace_out));
+ ptrace_in.pid = PIDGET (inferior_ptid);
+
+ status = net_ptrace_clnt_call (PTRACE_KILL, &ptrace_in, &ptrace_out);
+ if (status == -1)
+ warning (rpcerr);
+ else if (ptrace_out.status == -1)
+ {
+ errno = ptrace_out.errno_num;
+ perror_with_name ("Killing VxWorks process");
+ }
+
+ /* If it gives good status, the process is *gone*, no events remain.
+ If the kill failed, assume the process is gone anyhow. */
+ inferior_ptid = null_ptid;
+ pop_target (); /* go back to non-executing VxWorks connection */
+}
+
+/* Clean up from the VxWorks process target as it goes away. */
+
+static void
+vx_proc_close (int quitting)
+{
+ inferior_ptid = null_ptid; /* No longer have a process. */
+ if (vx_running)
+ xfree (vx_running);
+ vx_running = 0;
+}
+
+/* Make an RPC call to the VxWorks target.
+ Returns RPC status. */
+
+static enum clnt_stat
+net_clnt_call (enum ptracereq procNum, xdrproc_t inProc, char *in,
+ xdrproc_t outProc, char *out)
+{
+ enum clnt_stat status;
+
+ status = clnt_call (pClient, procNum, inProc, in, outProc, out, rpcTimeout);
+
+ if (status != RPC_SUCCESS)
+ clnt_perrno (status);
+
+ return status;
+}
+
+/* Clean up before losing control. */
+
+static void
+vx_close (int quitting)
+{
+ if (pClient)
+ clnt_destroy (pClient); /* The net connection */
+ pClient = 0;
+
+ if (vx_host)
+ xfree (vx_host); /* The hostname */
+ vx_host = 0;
+}
+
+/* A vxprocess target should be started via "run" not "target". */
+static void
+vx_proc_open (char *name, int from_tty)
+{
+ error ("Use the \"run\" command to start a VxWorks process.");
+}
+
+static void
+init_vx_ops (void)
+{
+ vx_ops.to_shortname = "vxworks";
+ vx_ops.to_longname = "VxWorks target memory via RPC over TCP/IP";
+ vx_ops.to_doc = "Use VxWorks target memory. \n\
+Specify the name of the machine to connect to.";
+ vx_ops.to_open = vx_open;
+ vx_ops.to_close = vx_close;
+ vx_ops.to_attach = vx_attach;
+ vx_ops.to_xfer_memory = vx_xfer_memory;
+ vx_ops.to_files_info = vx_files_info;
+ vx_ops.to_load = vx_load_command;
+ vx_ops.to_lookup_symbol = vx_lookup_symbol;
+ vx_ops.to_create_inferior = vx_create_inferior;
+ vx_ops.to_stratum = core_stratum;
+ vx_ops.to_has_all_memory = 1;
+ vx_ops.to_has_memory = 1;
+ vx_ops.to_magic = OPS_MAGIC; /* Always the last thing */
+};
+
+static void
+init_vx_run_ops (void)
+{
+ vx_run_ops.to_shortname = "vxprocess";
+ vx_run_ops.to_longname = "VxWorks process";
+ vx_run_ops.to_doc = "VxWorks process; started by the \"run\" command.";
+ vx_run_ops.to_open = vx_proc_open;
+ vx_run_ops.to_close = vx_proc_close;
+ vx_run_ops.to_detach = vx_detach;
+ vx_run_ops.to_resume = vx_resume;
+ vx_run_ops.to_wait = vx_wait;
+ vx_run_ops.to_fetch_registers = vx_read_register;
+ vx_run_ops.to_store_registers = vx_write_register;
+ vx_run_ops.to_prepare_to_store = vx_prepare_to_store;
+ vx_run_ops.to_xfer_memory = vx_xfer_memory;
+ vx_run_ops.to_files_info = vx_run_files_info;
+ vx_run_ops.to_insert_breakpoint = vx_insert_breakpoint;
+ vx_run_ops.to_remove_breakpoint = vx_remove_breakpoint;
+ vx_run_ops.to_kill = vx_kill;
+ vx_run_ops.to_load = vx_load_command;
+ vx_run_ops.to_lookup_symbol = vx_lookup_symbol;
+ vx_run_ops.to_mourn_inferior = vx_mourn_inferior;
+ vx_run_ops.to_stratum = process_stratum;
+ vx_run_ops.to_has_memory = 1;
+ vx_run_ops.to_has_stack = 1;
+ vx_run_ops.to_has_registers = 1;
+ vx_run_ops.to_has_execution = 1;
+ vx_run_ops.to_magic = OPS_MAGIC;
+}
+
+void
+_initialize_vx (void)
+{
+ init_vx_ops ();
+ add_target (&vx_ops);
+ init_vx_run_ops ();
+ add_target (&vx_run_ops);
+
+ add_show_from_set
+ (add_set_cmd ("vxworks-timeout", class_support, var_uinteger,
+ (char *) &rpcTimeout.tv_sec,
+ "Set seconds to wait for rpc calls to return.\n\
+Set the number of seconds to wait for rpc calls to return.", &setlist),
+ &showlist);
+}
diff --git a/contrib/gdb/gdb/remote-vx68.c b/contrib/gdb/gdb/remote-vx68.c
new file mode 100644
index 0000000..8cdac6f
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vx68.c
@@ -0,0 +1,160 @@
+/* 68k-dependent portions of the RPC protocol
+ used with a VxWorks target
+
+ Contributed by Wind River Systems.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include "defs.h"
+
+#include "vx-share/regPacket.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#ifdef _AIX /* IBM claims "void *malloc()" not char * */
+#define malloc bogon_malloc
+#endif
+
+#include <rpc/rpc.h>
+
+#ifdef _AIX
+#undef malloc
+#endif
+
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#include "vx-share/ptrace.h"
+#include "vx-share/xdr_ptrace.h"
+#include "vx-share/xdr_ld.h"
+#include "vx-share/xdr_rdb.h"
+#include "vx-share/dbgRpcLib.h"
+
+/* get rid of value.h if possible */
+#include <value.h>
+#include <symtab.h>
+
+/* Flag set if target has fpu */
+
+extern int target_has_fp;
+
+/* Generic register read/write routines in remote-vx.c. */
+
+extern void net_read_registers ();
+extern void net_write_registers ();
+
+/* Read a register or registers from the VxWorks target.
+ REGNO is the register to read, or -1 for all; currently,
+ it is ignored. FIXME look at regno to improve efficiency. */
+
+void
+vx_read_register (int regno)
+{
+ char mc68k_greg_packet[MC68K_GREG_PLEN];
+ char mc68k_fpreg_packet[MC68K_FPREG_PLEN];
+
+ /* Get general-purpose registers. */
+
+ net_read_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_GETREGS);
+
+ bcopy (&mc68k_greg_packet[MC68K_R_D0], deprecated_registers,
+ 16 * MC68K_GREG_SIZE);
+ bcopy (&mc68k_greg_packet[MC68K_R_SR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ MC68K_GREG_SIZE);
+ bcopy (&mc68k_greg_packet[MC68K_R_PC],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (PC_REGNUM)],
+ MC68K_GREG_SIZE);
+
+ /* Get floating-point registers, if the target system has them.
+ Otherwise, zero them. */
+
+ if (target_has_fp)
+ {
+ net_read_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN,
+ PTRACE_GETFPREGS);
+
+ bcopy (&mc68k_fpreg_packet[MC68K_R_FP0],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ MC68K_FPREG_SIZE * 8);
+ bcopy (&mc68k_fpreg_packet[MC68K_R_FPCR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
+ }
+ else
+ {
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ 0, MC68K_FPREG_SIZE * 8);
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ 0, MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
+ }
+
+ /* Mark the register cache valid. */
+
+ deprecated_registers_fetched ();
+}
+
+/* Store a register or registers into the VxWorks target.
+ REGNO is the register to store, or -1 for all; currently,
+ it is ignored. FIXME look at regno to improve efficiency. */
+
+void
+vx_write_register (int regno)
+{
+ char mc68k_greg_packet[MC68K_GREG_PLEN];
+ char mc68k_fpreg_packet[MC68K_FPREG_PLEN];
+
+ /* Store general-purpose registers. */
+
+ bcopy (deprecated_registers, &mc68k_greg_packet[MC68K_R_D0],
+ 16 * MC68K_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ &mc68k_greg_packet[MC68K_R_SR], MC68K_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (PC_REGNUM)],
+ &mc68k_greg_packet[MC68K_R_PC], MC68K_GREG_SIZE);
+
+ net_write_registers (mc68k_greg_packet, MC68K_GREG_PLEN, PTRACE_SETREGS);
+
+ /* Store floating point registers if the target has them. */
+
+ if (target_has_fp)
+ {
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ &mc68k_fpreg_packet[MC68K_R_FP0],
+ MC68K_FPREG_SIZE * 8);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FPC_REGNUM)],
+ &mc68k_fpreg_packet[MC68K_R_FPCR],
+ MC68K_FPREG_PLEN - (MC68K_FPREG_SIZE * 8));
+
+ net_write_registers (mc68k_fpreg_packet, MC68K_FPREG_PLEN,
+ PTRACE_SETFPREGS);
+ }
+}
diff --git a/contrib/gdb/gdb/remote-vxmips.c b/contrib/gdb/gdb/remote-vxmips.c
new file mode 100644
index 0000000..55ba49b
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vxmips.c
@@ -0,0 +1,201 @@
+/* MIPS-dependent portions of the RPC protocol
+ used with a VxWorks target
+
+ Contributed by Wind River Systems.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include "defs.h"
+
+#include "vx-share/regPacket.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "command.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <sys/time.h> /* UTek's <rpc/rpc.h> doesn't #incl this */
+#include <netdb.h>
+#include "vx-share/ptrace.h"
+#include "vx-share/xdr_ptrace.h"
+#include "vx-share/xdr_ld.h"
+#include "vx-share/xdr_rdb.h"
+#include "vx-share/dbgRpcLib.h"
+
+/* get rid of value.h if possible */
+#include <value.h>
+#include <symtab.h>
+
+/* Flag set if target has fpu */
+
+extern int target_has_fp;
+
+/* Generic register read/write routines in remote-vx.c. */
+
+extern void net_read_registers ();
+extern void net_write_registers ();
+
+/* Read a register or registers from the VxWorks target.
+ REGNO is the register to read, or -1 for all; currently,
+ it is ignored. FIXME look at regno to improve efficiency. */
+
+void
+vx_read_register (int regno)
+{
+ char mips_greg_packet[MIPS_GREG_PLEN];
+ char mips_fpreg_packet[MIPS_FPREG_PLEN];
+
+ /* Get general-purpose registers. */
+
+ net_read_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_GETREGS);
+
+ /* this code copies the registers obtained by RPC
+ stored in a structure(s) like this :
+
+ Register(s) Offset(s)
+ gp 0-31 0x00
+ hi 0x80
+ lo 0x84
+ sr 0x88
+ pc 0x8c
+
+ into a stucture like this:
+
+ 0x00 GP 0-31
+ 0x80 SR
+ 0x84 LO
+ 0x88 HI
+ 0x8C BAD --- Not available currently
+ 0x90 CAUSE --- Not available currently
+ 0x94 PC
+ 0x98 FP 0-31
+ 0x118 FCSR
+ 0x11C FIR --- Not available currently
+ 0x120 FP --- Not available currently
+
+ structure is 0x124 (292) bytes in length */
+
+ /* Copy the general registers. */
+
+ bcopy (&mips_greg_packet[MIPS_R_GP0], &deprecated_registers[0],
+ 32 * MIPS_GREG_SIZE);
+
+ /* Copy SR, LO, HI, and PC. */
+
+ bcopy (&mips_greg_packet[MIPS_R_SR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_LO],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_HI],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)], MIPS_GREG_SIZE);
+ bcopy (&mips_greg_packet[MIPS_R_PC],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)], MIPS_GREG_SIZE);
+
+ /* If the target has floating point registers, fetch them.
+ Otherwise, zero the floating point register values in
+ registers[] for good measure, even though we might not
+ need to. */
+
+ if (target_has_fp)
+ {
+ net_read_registers (mips_fpreg_packet, MIPS_FPREG_PLEN,
+ PTRACE_GETFPREGS);
+
+ /* Copy the floating point registers. */
+
+ bcopy (&mips_fpreg_packet[MIPS_R_FP0],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+
+ /* Copy the floating point control/status register (fpcsr). */
+
+ bcopy (&mips_fpreg_packet[MIPS_R_FPCSR],
+ &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+ }
+ else
+ {
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ 0, DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+ memset (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ 0, DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+ }
+
+ /* Mark the register cache valid. */
+
+ deprecated_registers_fetched ();
+}
+
+/* Store a register or registers into the VxWorks target.
+ REGNO is the register to store, or -1 for all; currently,
+ it is ignored. FIXME look at regno to improve efficiency. */
+
+vx_write_register (int regno)
+{
+ char mips_greg_packet[MIPS_GREG_PLEN];
+ char mips_fpreg_packet[MIPS_FPREG_PLEN];
+
+ /* Store general registers. */
+
+ bcopy (&deprecated_registers[0], &mips_greg_packet[MIPS_R_GP0],
+ 32 * MIPS_GREG_SIZE);
+
+ /* Copy SR, LO, HI, and PC. */
+
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (PS_REGNUM)],
+ &mips_greg_packet[MIPS_R_SR], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)],
+ &mips_greg_packet[MIPS_R_LO], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)],
+ &mips_greg_packet[MIPS_R_HI], MIPS_GREG_SIZE);
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)],
+ &mips_greg_packet[MIPS_R_PC], MIPS_GREG_SIZE);
+
+ net_write_registers (mips_greg_packet, MIPS_GREG_PLEN, PTRACE_SETREGS);
+
+ /* Store floating point registers if the target has them. */
+
+ if (target_has_fp)
+ {
+ /* Copy the floating point data registers. */
+
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (FP0_REGNUM)],
+ &mips_fpreg_packet[MIPS_R_FP0],
+ DEPRECATED_REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+
+ /* Copy the floating point control/status register (fpcsr). */
+
+ bcopy (&deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)],
+ &mips_fpreg_packet[MIPS_R_FPCSR],
+ DEPRECATED_REGISTER_RAW_SIZE (mips_regnum (current_gdbarch)->fp_control_status));
+
+ net_write_registers (mips_fpreg_packet, MIPS_FPREG_PLEN,
+ PTRACE_SETFPREGS);
+ }
+}
diff --git a/contrib/gdb/gdb/remote-vxsparc.c b/contrib/gdb/gdb/remote-vxsparc.c
new file mode 100644
index 0000000..118e517
--- /dev/null
+++ b/contrib/gdb/gdb/remote-vxsparc.c
@@ -0,0 +1,128 @@
+/* SPARC-specific portions of the RPC protocol for VxWorks.
+
+ Contributed by Wind River Systems.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "regcache.h"
+
+#include "gdb_string.h"
+
+#include "sparc-tdep.h"
+
+#include "vx-share/ptrace.h"
+#include "vx-share/regPacket.h"
+
+#define SPARC_R_G1 (SPARC_R_G0 + SPARC_GREG_SIZE)
+
+const struct sparc_gregset vxsparc_gregset =
+{
+ SPARC_R_PSR, /* %psr */
+ SPARC_R_PC, /* %pc */
+ SPARC_R_NPC, /* %npc */
+ SPARC_R_Y, /* %y */
+ SPARC_R_WIM, /* %wim */
+ SPARC_R_TBR, /* %tbr */
+ SPARC_R_G1, /* %g1 */
+ SPARC_R_I0 /* %l0 */
+};
+
+/* Flag set if target has an FPU. */
+
+extern int target_has_fp;
+
+/* Generic register read/write routines in remote-vx.c. */
+
+extern void net_read_registers ();
+extern void net_write_registers ();
+
+/* Read a register or registers from the VxWorks target. REGNUM is
+ the register to read, or -1 for all; currently, it is ignored.
+ FIXME: Look at REGNUM to improve efficiency. */
+
+void
+vx_read_register (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ char gregs[SPARC_GREG_PLEN];
+ char fpregs[SPARC_FPREG_PLEN];
+ CORE_ADDR sp;
+
+ /* Get the general-purpose registers. */
+ net_read_registers (gregs, SPARC_GREG_PLEN, PTRACE_GETREGS);
+ sparc32_supply_gregset (&vxsparc_gregset, regcache, -1, gregs);
+
+ /* If the target has floating-point registers, fetch them.
+ Otherwise, zero the floating-point register values in GDB's
+ register cache for good measure, even though we might not need
+ to. */
+ if (target_has_fp)
+ net_read_registers (fpregs, SPARC_FPREG_PLEN, PTRACE_GETFPREGS);
+ else
+ memset (fpregs, 0, SPARC_FPREG_PLEN);
+ sparc32_supply_fpregset (regcache, -1, fpregs);
+}
+
+/* Store a register or registers into the VxWorks target. REGNUM is
+ the register to store, or -1 for all; currently, it is ignored.
+ FIXME: Look at REGNUM to improve efficiency. */
+
+void
+vx_write_register (int regnum)
+{
+ struct regcache *regcache = current_regcache;
+ char gregs[SPARC_GREG_PLEN];
+ char fpregs[SPARC_FPREG_PLEN];
+ int gregs_p = 1;
+ int fpregs_p = 1;
+ CORE_ADDR sp;
+
+ if (regnum != -1)
+ {
+ if ((SPARC_G0_REGNUM <= regnum && regnum <= SPARC_I7_REGNUM)
+ || (SPARC32_Y_REGNUM <= regnum && regnum <= SPARC32_NPC_REGNUM))
+ fpregs_p = 0;
+ else
+ gregs_p = 0;
+ }
+
+ /* Store the general-purpose registers. */
+ if (gregs_p)
+ {
+ sparc32_collect_gregset (&vxsparc_gregset, regcache, -1, gregs);
+ net_write_registers (gregs, SPARC_GREG_PLEN, PTRACE_SETREGS);
+
+ /* Deal with the stack regs. */
+ if (regnum == -1 || regnum == SPARC_SP_REGNUM
+ || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
+ {
+ ULONGEST sp;
+
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ sparc_collect_rwindow (regcache, sp, regnum);
+ }
+ }
+
+ /* Store the floating-point registers if the target has them. */
+ if (fpregs_p && target_has_fp)
+ {
+ sparc32_collect_fpregset (regcache, -1, fpregs);
+ net_write_registers (fpregs, SPARC_FPREG_PLEN, PTRACE_SETFPREGS);
+ }
+}
diff --git a/contrib/gdb/gdb/ser-e7kpc.c b/contrib/gdb/gdb/ser-e7kpc.c
new file mode 100644
index 0000000..1efe142
--- /dev/null
+++ b/contrib/gdb/gdb/ser-e7kpc.c
@@ -0,0 +1,436 @@
+/* Remote serial interface using Renesas E7000 PC ISA card in a PC
+ Copyright 1994, 1996, 1997, 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"
+#if defined __GO32__ || defined _WIN32
+#include "serial.h"
+#include "gdb_string.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#ifdef __GO32__
+#include <sys/dos.h>
+#endif
+
+static int e7000pc_open (struct serial *scb, const char *name);
+static void e7000pc_raw (struct serial *scb);
+static int e7000pc_readchar (struct serial *scb, int timeout);
+static int e7000pc_setbaudrate (struct serial *scb, int rate);
+static int e7000pc_write (struct serial *scb, const char *str, int len);
+static void e7000pc_close (struct serial *scb);
+static serial_ttystate e7000pc_get_tty_state (struct serial *scb);
+static int e7000pc_set_tty_state (struct serial *scb, serial_ttystate state);
+
+#define OFF_DPD 0x0000
+#define OFF_DDP 0x1000
+#define OFF_CPD 0x2000
+#define OFF_CDP 0x2400
+#define OFF_FA 0x3000
+#define OFF_FB 0x3002
+#define OFF_FC 0x3004
+#define OFF_IRQTOD 0x3008
+#define OFF_IRQTOP 0x300a
+#define OFF_READY 0x300c
+#define OFF_PON 0x300e
+
+#define IDLE 0x0000
+#define CMD_CI 0x4349
+#define CMD_CO 0x434f
+#define CMD_LO 0x4c4f
+#define CMD_LS 0x4c53
+#define CMD_SV 0x5356
+#define CMD_SS 0x5353
+#define CMD_OK 0x4f4b
+#define CMD_ER 0x4552
+#define CMD_NF 0x4e46
+#define CMD_AB 0x4142
+#define CMD_ED 0x4544
+#define CMD_CE 0x4345
+
+static unsigned long fa;
+static unsigned long irqtod;
+static unsigned long ready;
+static unsigned long fb;
+static unsigned long cpd;
+static unsigned long cdp;
+static unsigned long ready;
+static unsigned long pon;
+static unsigned long irqtop;
+static unsigned long board_at;
+
+#ifdef __GO32__
+
+#define SET_BYTE(x,y) { char _buf = y;dosmemput(&_buf,1, x);}
+#define SET_WORD(x,y) { short _buf = y;dosmemput(&_buf,2, x);}
+#define GET_BYTE(x) ( dosmemget(x,1,&bb), bb)
+#define GET_WORD(x) ( dosmemget(x,2,&sb), sb)
+static unsigned char bb;
+static unsigned short sb;
+
+#else /* win32 */
+
+#define SET_BYTE(x,y) *(volatile unsigned char *)(x) = (y)
+#define SET_WORD(x,y) *(volatile unsigned short *)(x) = (y)
+#define GET_BYTE(x) (*(volatile unsigned char *)(x))
+#define GET_WORD(x) (*(volatile unsigned short *)(x))
+#define dosmemget(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#define dosmemput(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
+#endif
+
+static struct sw
+ {
+ int sw;
+ int addr;
+ }
+sigs[] =
+{
+ {
+ 0x14, 0xd0000
+ }
+ ,
+ {
+ 0x15, 0xd4000
+ }
+ ,
+ {
+ 0x16, 0xd8000
+ }
+ ,
+ {
+ 0x17, 0xdc000
+ }
+ ,
+ 0
+};
+
+#define get_ds_base() 0
+
+static int
+e7000pc_init (void)
+{
+ int try;
+ unsigned long dsbase;
+
+ dsbase = get_ds_base ();
+
+ /* Look around in memory for the board's signature */
+
+ for (try = 0; sigs[try].sw; try++)
+ {
+ int val;
+ board_at = sigs[try].addr - dsbase;
+ fa = board_at + OFF_FA;
+ fb = board_at + OFF_FB;
+ cpd = board_at + OFF_CPD;
+ cdp = board_at + OFF_CDP;
+ ready = board_at + OFF_READY;
+ pon = board_at + OFF_PON;
+ irqtop = board_at + OFF_IRQTOP;
+ irqtod = board_at + OFF_IRQTOD;
+
+ val = GET_WORD (ready);
+
+ if (val == (0xaaa0 | sigs[try].sw))
+ {
+ if (GET_WORD (pon) & 0xf)
+ {
+ SET_WORD (fa, 0);
+ SET_WORD (fb, 0);
+
+ SET_WORD (irqtop, 1); /* Disable interrupts from e7000 */
+ SET_WORD (ready, 1);
+ printf_filtered ("\nConnected to the E7000PC at address 0x%x\n",
+ sigs[try].addr);
+ return 1;
+ }
+ error ("The E7000 PC board is working, but the E7000 is turned off.\n");
+ return 0;
+ }
+ }
+
+ error ("GDB cannot connect to the E7000 PC board, check that it is installed\n\
+and that the switch settings are correct. Some other DOS programs can \n\
+stop the board from working. Try starting from a very minimal boot, \n\
+perhaps you need to disable EMM386 over the region where the board has\n\
+its I/O space, remove other unneeded cards, etc etc\n");
+ return 0;
+
+}
+
+static int pbuf_size;
+static int pbuf_index;
+
+/* Return next byte from cdp. If no more, then return -1. */
+
+static int
+e7000_get (void)
+{
+ static char pbuf[1000];
+ char tmp[1000];
+ int x;
+
+ if (pbuf_index < pbuf_size)
+ {
+ x = pbuf[pbuf_index++];
+ }
+ else if ((GET_WORD (fb) & 1))
+ {
+ int i;
+ pbuf_size = GET_WORD (cdp + 2);
+
+ dosmemget (cdp + 8, pbuf_size + 1, tmp);
+
+ /* Tell the E7000 we've eaten */
+ SET_WORD (fb, 0);
+ /* Swap it around */
+ for (i = 0; i < pbuf_size; i++)
+ {
+ pbuf[i] = tmp[i ^ 1];
+ }
+ pbuf_index = 0;
+ x = pbuf[pbuf_index++];
+ }
+ else
+ {
+ x = -1;
+ }
+ return x;
+}
+
+/* Works just like read(), except that it takes a TIMEOUT in seconds. Note
+ that TIMEOUT == 0 is a poll, and TIMEOUT == -1 means wait forever. */
+
+static int
+dosasync_read (int fd, char *buf, int len, int timeout)
+{
+ long now;
+ long then;
+ int i = 0;
+
+ /* Then look for some more if we're still hungry */
+ time (&now);
+ then = now + timeout;
+ while (i < len)
+ {
+ int ch = e7000_get ();
+
+ /* While there's room in the buffer, and we've already
+ read the stuff in, suck it over */
+ if (ch != -1)
+ {
+ buf[i++] = ch;
+ while (i < len && pbuf_index < pbuf_size)
+ {
+ ch = e7000_get ();
+ if (ch == -1)
+ break;
+ buf[i++] = ch;
+ }
+ }
+
+ time (&now);
+
+ if (timeout == 0)
+ return i;
+ if (now >= then && timeout > 0)
+ {
+ return i;
+ }
+ }
+ return len;
+}
+
+
+static int
+dosasync_write (int fd, const char *buf, int len)
+{
+ int i;
+ char dummy[1000];
+
+ /* Construct copy locally */
+ ((short *) dummy)[0] = CMD_CI;
+ ((short *) dummy)[1] = len;
+ ((short *) dummy)[2] = 0;
+ ((short *) dummy)[3] = 0;
+ for (i = 0; i < len; i++)
+ {
+ dummy[(8 + i) ^ 1] = buf[i];
+ }
+
+ /* Wait for the card to get ready */
+ while (GET_WORD (fa) & 1);
+
+ /* Blast onto the ISA card */
+ dosmemput (dummy, 8 + len + 1, cpd);
+
+ SET_WORD (fa, 1);
+ SET_WORD (irqtod, 1); /* Interrupt the E7000 */
+
+ return len;
+}
+
+static int
+e7000pc_open (struct serial *scb, const char *name)
+{
+ if (strncasecmp (name, "pc", 2) != 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ scb->fd = e7000pc_init ();
+
+ if (!scb->fd)
+ return -1;
+
+ return 0;
+}
+
+static int
+e7000pc_noop (struct serial *scb)
+{
+ return 0;
+}
+
+static void
+e7000pc_raw (struct serial *scb)
+{
+ /* Always in raw mode */
+}
+
+static int
+e7000pc_readchar (struct serial *scb, int timeout)
+{
+ char buf;
+
+top:
+
+ if (dosasync_read (scb->fd, &buf, 1, timeout))
+ {
+ if (buf == 0)
+ goto top;
+ return buf;
+ }
+ else
+ return SERIAL_TIMEOUT;
+}
+
+struct e7000pc_ttystate
+{
+ int dummy;
+};
+
+/* e7000pc_{get set}_tty_state() are both dummys to fill out the function
+ vector. Someday, they may do something real... */
+
+static serial_ttystate
+e7000pc_get_tty_state (struct serial *scb)
+{
+ struct e7000pc_ttystate *state;
+
+ state = (struct e7000pc_ttystate *) xmalloc (sizeof *state);
+
+ return (serial_ttystate) state;
+}
+
+static int
+e7000pc_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+ return 0;
+}
+
+static int
+e7000pc_noflush_set_tty_state (struct serial *scb,
+ serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
+{
+ return 0;
+}
+
+static void
+e7000pc_print_tty_state (struct serial *scb,
+ serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ /* Nothing to print. */
+ return;
+}
+
+static int
+e7000pc_setbaudrate (struct serial *scb, int rate)
+{
+ return 0;
+}
+
+static int
+e7000pc_setstopbits (struct serial *scb, int rate)
+{
+ return 0;
+}
+
+static int
+e7000pc_write (struct serial *scb, const char *str, int len)
+{
+ dosasync_write (scb->fd, str, len);
+
+ return 0;
+}
+
+static void
+e7000pc_close (struct serial *scb)
+{
+}
+
+static struct serial_ops e7000pc_ops =
+{
+ "pc",
+ 0,
+ e7000pc_open,
+ e7000pc_close,
+ e7000pc_readchar,
+ e7000pc_write,
+ e7000pc_noop, /* flush output */
+ e7000pc_noop, /* flush input */
+ e7000pc_noop, /* send break -- currently used only for nindy */
+ e7000pc_raw,
+ e7000pc_get_tty_state,
+ e7000pc_set_tty_state,
+ e7000pc_print_tty_state,
+ e7000pc_noflush_set_tty_state,
+ e7000pc_setbaudrate,
+ e7000pc_setstopbits,
+ e7000pc_noop, /* wait for output to drain */
+};
+
+#endif /*_WIN32 or __GO32__*/
+
+extern initialize_file_ftype _initialize_ser_e7000pc; /* -Wmissing-prototypes */
+
+void
+_initialize_ser_e7000pc (void)
+{
+#if defined __GO32__ || defined _WIN32
+ serial_add_interface (&e7000pc_ops);
+#endif
+}
diff --git a/contrib/gdb/gdb/ser-go32.c b/contrib/gdb/gdb/ser-go32.c
new file mode 100644
index 0000000..cea01cd
--- /dev/null
+++ b/contrib/gdb/gdb/ser-go32.c
@@ -0,0 +1,964 @@
+/* Remote serial interface for local (hardwired) serial ports for GO32.
+ Copyright 1992, 1993, 2000, 2001 Free Software Foundation, Inc.
+
+ Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
+
+ This version uses DPMI interrupts to handle buffered i/o
+ without the separate "asynctsr" program.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "serial.h"
+#include "gdb_string.h"
+
+
+/*
+ * NS16550 UART registers
+ */
+
+#define COM1ADDR 0x3f8
+#define COM2ADDR 0x2f8
+#define COM3ADDR 0x3e8
+#define COM4ADDR 0x3e0
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
+
+/*
+ * Constants for computing 16 bit baud rate divisor (lower byte
+ * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal. Divisor is
+ * 1.8432 MHz / (16 * X) for X bps. If the baud rate can't be set
+ * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
+ */
+#define COMTICK (1843200/16)
+#define SPEED_TOLERANCE 30 /* thousandths; real == desired +- 3.0% */
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1 /* int on rx ready */
+#define IER_ETXRDY 0x2 /* int on tx ready */
+#define IER_ERLS 0x4 /* int on line status change */
+#define IER_EMSC 0x8 /* int on modem status change */
+
+/* interrupt identification register */
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+#define IIR_IMASK 0xf /* interrupt cause mask */
+#define IIR_NOPEND 0x1 /* nothing pending */
+#define IIR_RLS 0x6 /* receive line status */
+#define IIR_RXRDY 0x4 /* receive ready */
+#define IIR_RXTOUT 0xc /* receive timeout */
+#define IIR_TXRDY 0x2 /* transmit ready */
+#define IIR_MLSC 0x0 /* modem status */
+
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01 /* enable fifo */
+#define FIFO_RCV_RST 0x02 /* reset receive fifo */
+#define FIFO_XMT_RST 0x04 /* reset transmit fifo */
+#define FIFO_DMA_MODE 0x08 /* enable dma mode */
+#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */
+#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */
+#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */
+#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */
+
+/* character format control register */
+#define CFCR_DLAB 0x80 /* divisor latch */
+#define CFCR_SBREAK 0x40 /* send break */
+#define CFCR_PZERO 0x30 /* zero parity */
+#define CFCR_PONE 0x20 /* one parity */
+#define CFCR_PEVEN 0x10 /* even parity */
+#define CFCR_PODD 0x00 /* odd parity */
+#define CFCR_PENAB 0x08 /* parity enable */
+#define CFCR_STOPB 0x04 /* 2 stop bits */
+#define CFCR_8BITS 0x03 /* 8 data bits */
+#define CFCR_7BITS 0x02 /* 7 data bits */
+#define CFCR_6BITS 0x01 /* 6 data bits */
+#define CFCR_5BITS 0x00 /* 5 data bits */
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10 /* loopback */
+#define MCR_IENABLE 0x08 /* output 2 = int enable */
+#define MCR_DRS 0x04 /* output 1 = xxx */
+#define MCR_RTS 0x02 /* enable RTS */
+#define MCR_DTR 0x01 /* enable DTR */
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80 /* error in receive fifo */
+#define LSR_TSRE 0x40 /* transmitter empty */
+#define LSR_TXRDY 0x20 /* transmitter ready */
+#define LSR_BI 0x10 /* break detected */
+#define LSR_FE 0x08 /* framing error */
+#define LSR_PE 0x04 /* parity error */
+#define LSR_OE 0x02 /* overrun error */
+#define LSR_RXRDY 0x01 /* receiver ready */
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+#include <time.h>
+#include <dos.h>
+#include <go32.h>
+#include <dpmi.h>
+typedef unsigned long u_long;
+
+/* 16550 rx fifo trigger point */
+#define FIFO_TRIGGER FIFO_TRIGGER_4
+
+/* input buffer size */
+#define CBSIZE 4096
+
+#define RAWHZ 18
+
+#ifdef DOS_STATS
+#define CNT_RX 16
+#define CNT_TX 17
+#define CNT_STRAY 18
+#define CNT_ORUN 19
+#define NCNT 20
+
+static int intrcnt;
+static int cnts[NCNT];
+static char *cntnames[NCNT] =
+{
+ /* h/w interrupt counts. */
+ "mlsc", "nopend", "txrdy", "?3",
+ "rxrdy", "?5", "rls", "?7",
+ "?8", "?9", "?a", "?b",
+ "rxtout", "?d", "?e", "?f",
+ /* s/w counts. */
+ "rxcnt", "txcnt", "stray", "swoflo"
+};
+
+#define COUNT(x) cnts[x]++
+#else
+#define COUNT(x)
+#endif
+
+/* Main interrupt controller port addresses. */
+#define ICU_BASE 0x20
+#define ICU_OCW2 (ICU_BASE + 0)
+#define ICU_MASK (ICU_BASE + 1)
+
+/* Original interrupt controller mask register. */
+unsigned char icu_oldmask;
+
+/* Maximum of 8 interrupts (we don't handle the slave icu yet). */
+#define NINTR 8
+
+static struct intrupt
+ {
+ char inuse;
+ struct dos_ttystate *port;
+ _go32_dpmi_seginfo old_rmhandler;
+ _go32_dpmi_seginfo old_pmhandler;
+ _go32_dpmi_seginfo new_rmhandler;
+ _go32_dpmi_seginfo new_pmhandler;
+ _go32_dpmi_registers regs;
+ }
+intrupts[NINTR];
+
+
+static struct dos_ttystate
+ {
+ int base;
+ int irq;
+ int refcnt;
+ struct intrupt *intrupt;
+ int fifo;
+ int baudrate;
+ unsigned char cbuf[CBSIZE];
+ unsigned int first;
+ unsigned int count;
+ int txbusy;
+ unsigned char old_mcr;
+ int ferr;
+ int perr;
+ int oflo;
+ int msr;
+ }
+ports[4] =
+{
+ {
+ COM1ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ ,
+ {
+ COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static int dos_open (struct serial *scb, const char *name);
+static void dos_raw (struct serial *scb);
+static int dos_readchar (struct serial *scb, int timeout);
+static int dos_setbaudrate (struct serial *scb, int rate);
+static int dos_write (struct serial *scb, const char *str, int len);
+static void dos_close (struct serial *scb);
+static serial_ttystate dos_get_tty_state (struct serial *scb);
+static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
+static int dos_baudconv (int rate);
+
+#define inb(p,a) inportb((p)->base + (a))
+#define outb(p,a,v) outportb((p)->base + (a), (v))
+#define disable() asm volatile ("cli");
+#define enable() asm volatile ("sti");
+
+
+static int
+dos_getc (volatile struct dos_ttystate *port)
+{
+ int c;
+
+ if (port->count == 0)
+ return -1;
+
+ c = port->cbuf[port->first];
+ disable ();
+ port->first = (port->first + 1) & (CBSIZE - 1);
+ port->count--;
+ enable ();
+ return c;
+}
+
+
+static int
+dos_putc (int c, struct dos_ttystate *port)
+{
+ if (port->count >= CBSIZE - 1)
+ return -1;
+ port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
+ port->count++;
+ return 0;
+}
+
+
+
+static void
+dos_comisr (int irq)
+{
+ struct dos_ttystate *port;
+ unsigned char iir, lsr, c;
+
+ disable (); /* Paranoia */
+ outportb (ICU_OCW2, 0x20); /* End-Of-Interrupt */
+#ifdef DOS_STATS
+ ++intrcnt;
+#endif
+
+ port = intrupts[irq].port;
+ if (!port)
+ {
+ COUNT (CNT_STRAY);
+ return; /* not open */
+ }
+
+ while (1)
+ {
+ iir = inb (port, com_iir) & IIR_IMASK;
+ switch (iir)
+ {
+
+ case IIR_RLS:
+ lsr = inb (port, com_lsr);
+ goto rx;
+
+ case IIR_RXTOUT:
+ case IIR_RXRDY:
+ lsr = 0;
+
+ rx:
+ do
+ {
+ c = inb (port, com_data);
+ if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
+ {
+ if (lsr & (LSR_BI | LSR_FE))
+ port->ferr++;
+ else if (lsr & LSR_PE)
+ port->perr++;
+ if (lsr & LSR_OE)
+ port->oflo++;
+ }
+
+ if (dos_putc (c, port) < 0)
+ {
+ COUNT (CNT_ORUN);
+ }
+ else
+ {
+ COUNT (CNT_RX);
+ }
+ }
+ while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
+ break;
+
+ case IIR_MLSC:
+ /* could be used to flowcontrol Tx */
+ port->msr = inb (port, com_msr);
+ break;
+
+ case IIR_TXRDY:
+ port->txbusy = 0;
+ break;
+
+ case IIR_NOPEND:
+ /* no more pending interrupts, all done */
+ return;
+
+ default:
+ /* unexpected interrupt, ignore */
+ break;
+ }
+ COUNT (iir);
+ }
+}
+
+#define ISRNAME(x) dos_comisr##x
+#define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
+
+ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
+ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
+
+typedef void (*isr_t) (void);
+
+static isr_t isrs[NINTR] =
+ {
+ ISRNAME (0), ISRNAME (1), ISRNAME (2), ISRNAME (3),
+ ISRNAME (4), ISRNAME (5), ISRNAME (6), ISRNAME (7)
+ };
+
+
+
+static struct intrupt *
+dos_hookirq (unsigned int irq)
+{
+ struct intrupt *intr;
+ unsigned int vec;
+ isr_t isr;
+
+ if (irq >= NINTR)
+ return 0;
+
+ intr = &intrupts[irq];
+ if (intr->inuse)
+ return 0;
+
+ vec = 0x08 + irq;
+ isr = isrs[irq];
+
+ /* setup real mode handler */
+ _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
+
+ intr->new_rmhandler.pm_selector = _go32_my_cs ();
+ intr->new_rmhandler.pm_offset = (u_long) isr;
+ if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
+ &intr->regs))
+ {
+ return 0;
+ }
+
+ if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
+ {
+ return 0;
+ }
+
+ /* setup protected mode handler */
+ _go32_dpmi_get_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
+
+ intr->new_pmhandler.pm_selector = _go32_my_cs ();
+ intr->new_pmhandler.pm_offset = (u_long) isr;
+ _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
+
+ if (_go32_dpmi_set_protected_mode_interrupt_vector (vec,
+ &intr->new_pmhandler))
+ {
+ return 0;
+ }
+
+ /* setup interrupt controller mask */
+ disable ();
+ outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
+ enable ();
+
+ intr->inuse = 1;
+ return intr;
+}
+
+
+static void
+dos_unhookirq (struct intrupt *intr)
+{
+ unsigned int irq, vec;
+ unsigned char mask;
+
+ irq = intr - intrupts;
+ vec = 0x08 + irq;
+
+ /* restore old interrupt mask bit */
+ mask = 1 << irq;
+ disable ();
+ outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
+ enable ();
+
+ /* remove real mode handler */
+ _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
+ _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
+
+ /* remove protected mode handler */
+ _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
+ _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
+ intr->inuse = 0;
+}
+
+
+
+static int
+dos_open (struct serial *scb, const char *name)
+{
+ struct dos_ttystate *port;
+ int fd, i;
+
+ if (strncasecmp (name, "/dev/", 5) == 0)
+ name += 5;
+ else if (strncasecmp (name, "\\dev\\", 5) == 0)
+ name += 5;
+
+ if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (name[3] < '1' || name[3] > '4')
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* FIXME: this is a Bad Idea (tm)! One should *never* invent file
+ handles, since they might be already used by other files/devices.
+ The Right Way to do this is to create a real handle by dup()'ing
+ some existing one. */
+ fd = name[3] - '1';
+ port = &ports[fd];
+ if (port->refcnt++ > 0)
+ {
+ /* Device already opened another user. Just point at it. */
+ scb->fd = fd;
+ return 0;
+ }
+
+ /* force access to ID reg */
+ outb (port, com_cfcr, 0);
+ outb (port, com_iir, 0);
+ for (i = 0; i < 17; i++)
+ {
+ if ((inb (port, com_iir) & 0x38) == 0)
+ goto ok;
+ (void) inb (port, com_data); /* clear recv */
+ }
+ errno = ENODEV;
+ return -1;
+
+ok:
+ /* disable all interrupts in chip */
+ outb (port, com_ier, 0);
+
+ /* tentatively enable 16550 fifo, and see if it responds */
+ outb (port, com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER);
+ sleep (1);
+ port->fifo = ((inb (port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
+
+ /* clear pending status reports. */
+ (void) inb (port, com_lsr);
+ (void) inb (port, com_msr);
+
+ /* enable external interrupt gate (to avoid floating IRQ) */
+ outb (port, com_mcr, MCR_IENABLE);
+
+ /* hook up interrupt handler and initialise icu */
+ port->intrupt = dos_hookirq (port->irq);
+ if (!port->intrupt)
+ {
+ outb (port, com_mcr, 0);
+ outb (port, com_fifo, 0);
+ errno = ENODEV;
+ return -1;
+ }
+
+ disable ();
+
+ /* record port */
+ port->intrupt->port = port;
+ scb->fd = fd;
+
+ /* clear rx buffer, tx busy flag and overflow count */
+ port->first = port->count = 0;
+ port->txbusy = 0;
+ port->oflo = 0;
+
+ /* set default baud rate and mode: 9600,8,n,1 */
+ i = dos_baudconv (port->baudrate = 9600);
+ outb (port, com_cfcr, CFCR_DLAB);
+ outb (port, com_dlbl, i & 0xff);
+ outb (port, com_dlbh, i >> 8);
+ outb (port, com_cfcr, CFCR_8BITS);
+
+ /* enable all interrupts */
+ outb (port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
+
+ /* enable DTR & RTS */
+ outb (port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
+
+ enable ();
+
+ return 0;
+}
+
+
+static void
+dos_close (struct serial *scb)
+{
+ struct dos_ttystate *port;
+ struct intrupt *intrupt;
+
+ if (!scb)
+ return;
+
+ port = &ports[scb->fd];
+
+ if (port->refcnt-- > 1)
+ return;
+
+ if (!(intrupt = port->intrupt))
+ return;
+
+ /* disable interrupts, fifo, flow control */
+ disable ();
+ port->intrupt = 0;
+ intrupt->port = 0;
+ outb (port, com_fifo, 0);
+ outb (port, com_ier, 0);
+ enable ();
+
+ /* unhook handler, and disable interrupt gate */
+ dos_unhookirq (intrupt);
+ outb (port, com_mcr, 0);
+
+ /* Check for overflow errors */
+ if (port->oflo)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "Serial input overruns occurred.\n");
+ fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
+ port->fifo ? "cannot" : "needs a 16550 to",
+ port->baudrate);
+ }
+}
+
+
+
+static int
+dos_noop (struct serial *scb)
+{
+ return 0;
+}
+
+static void
+dos_raw (struct serial *scb)
+{
+ /* Always in raw mode */
+}
+
+static int
+dos_readchar (struct serial *scb, int timeout)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+ long then;
+ int c;
+
+ then = rawclock () + (timeout * RAWHZ);
+ while ((c = dos_getc (port)) < 0)
+ {
+ if (timeout >= 0 && (rawclock () - then) >= 0)
+ return SERIAL_TIMEOUT;
+ }
+
+ return c;
+}
+
+
+static serial_ttystate
+dos_get_tty_state (struct serial *scb)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+ struct dos_ttystate *state;
+
+ /* Are they asking about a port we opened? */
+ if (port->refcnt <= 0)
+ {
+ /* We've never heard about this port. We should fail this call,
+ unless they are asking about one of the 3 standard handles,
+ in which case we pretend the handle was open by us if it is
+ connected to a terminal device. This is beacuse Unix
+ terminals use the serial interface, so GDB expects the
+ standard handles to go through here. */
+ if (scb->fd >= 3 || !isatty (scb->fd))
+ return NULL;
+ }
+
+ state = (struct dos_ttystate *) xmalloc (sizeof *state);
+ *state = *port;
+ return (serial_ttystate) state;
+}
+
+static int
+dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
+{
+ struct dos_ttystate *state;
+
+ state = (struct dos_ttystate *) ttystate;
+ dos_setbaudrate (scb, state->baudrate);
+ return 0;
+}
+
+static int
+dos_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate,
+ serial_ttystate old_ttystate)
+{
+ struct dos_ttystate *state;
+
+ state = (struct dos_ttystate *) new_ttystate;
+ dos_setbaudrate (scb, state->baudrate);
+ return 0;
+}
+
+static int
+dos_flush_input (struct serial *scb)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+ disable ();
+ port->first = port->count = 0;
+ if (port->fifo)
+ outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
+ enable ();
+ return 0;
+}
+
+static void
+dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
+ struct ui_file *stream)
+{
+ /* Nothing to print */
+ return;
+}
+
+static int
+dos_baudconv (int rate)
+{
+ long x, err;
+
+ if (rate <= 0)
+ return -1;
+
+#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* divide and round off */
+ x = divrnd (COMTICK, rate);
+ if (x <= 0)
+ return -1;
+
+ err = divrnd (1000 * COMTICK, x * rate) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > SPEED_TOLERANCE)
+ return -1;
+#undef divrnd
+ return x;
+}
+
+
+static int
+dos_setbaudrate (struct serial *scb, int rate)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+
+ if (port->baudrate != rate)
+ {
+ int x;
+ unsigned char cfcr;
+
+ x = dos_baudconv (rate);
+ if (x <= 0)
+ {
+ fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
+ errno = EINVAL;
+ return -1;
+ }
+
+ disable ();
+ cfcr = inb (port, com_cfcr);
+
+ outb (port, com_cfcr, CFCR_DLAB);
+ outb (port, com_dlbl, x & 0xff);
+ outb (port, com_dlbh, x >> 8);
+ outb (port, com_cfcr, cfcr);
+ port->baudrate = rate;
+ enable ();
+ }
+
+ return 0;
+}
+
+static int
+dos_setstopbits (struct serial *scb, int num)
+{
+ struct dos_ttystate *port = &ports[scb->fd];
+ unsigned char cfcr;
+
+ disable ();
+ cfcr = inb (port, com_cfcr);
+
+ switch (num)
+ {
+ case SERIAL_1_STOPBITS:
+ outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
+ break;
+ case SERIAL_1_AND_A_HALF_STOPBITS:
+ case SERIAL_2_STOPBITS:
+ outb (port, com_cfcr, cfcr | CFCR_STOPB);
+ break;
+ default:
+ enable ();
+ return 1;
+ }
+ enable ();
+
+ return 0;
+}
+
+static int
+dos_write (struct serial *scb, const char *str, int len)
+{
+ volatile struct dos_ttystate *port = &ports[scb->fd];
+ int fifosize = port->fifo ? 16 : 1;
+ long then;
+ int cnt;
+
+ while (len > 0)
+ {
+ /* send the data, fifosize bytes at a time */
+ cnt = fifosize > len ? len : fifosize;
+ port->txbusy = 1;
+ /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
+ up the communications with UARTs with FIFOs. */
+#ifdef UART_FIFO_WORKS
+ outportsb (port->base + com_data, str, cnt);
+ str += cnt;
+ len -= cnt;
+#else
+ for ( ; cnt > 0; cnt--, len--)
+ outportb (port->base + com_data, *str++);
+#endif
+#ifdef DOS_STATS
+ cnts[CNT_TX] += cnt;
+#endif
+ /* wait for transmission to complete (max 1 sec) */
+ then = rawclock () + RAWHZ;
+ while (port->txbusy)
+ {
+ if ((rawclock () - then) >= 0)
+ {
+ errno = EIO;
+ return SERIAL_ERROR;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int
+dos_sendbreak (struct serial *scb)
+{
+ volatile struct dos_ttystate *port = &ports[scb->fd];
+ unsigned char cfcr;
+ long then;
+
+ cfcr = inb (port, com_cfcr);
+ outb (port, com_cfcr, cfcr | CFCR_SBREAK);
+
+ /* 0.25 sec delay */
+ then = rawclock () + RAWHZ / 4;
+ while ((rawclock () - then) < 0)
+ continue;
+
+ outb (port, com_cfcr, cfcr);
+ return 0;
+}
+
+
+static struct serial_ops dos_ops =
+{
+ "hardwire",
+ 0,
+ dos_open,
+ dos_close,
+ dos_readchar,
+ dos_write,
+ dos_noop, /* flush output */
+ dos_flush_input,
+ dos_sendbreak,
+ dos_raw,
+ dos_get_tty_state,
+ dos_set_tty_state,
+ dos_print_tty_state,
+ dos_noflush_set_tty_state,
+ dos_setbaudrate,
+ dos_setstopbits,
+ dos_noop, /* wait for output to drain */
+ (void (*)(struct serial *, int))NULL /* change into async mode */
+};
+
+
+static void
+dos_info (char *arg, int from_tty)
+{
+ struct dos_ttystate *port;
+#ifdef DOS_STATS
+ int i;
+#endif
+
+ for (port = ports; port < &ports[4]; port++)
+ {
+ if (port->baudrate == 0)
+ continue;
+ printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
+ port->intrupt ? "" : "not ");
+ printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
+ printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
+ printf_filtered ("Speed:\t%d baud\n", port->baudrate);
+ printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
+ port->ferr, port->perr, port->oflo);
+ }
+
+#ifdef DOS_STATS
+ printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
+ for (i = 0; i < NCNT; i++)
+ if (cnts[i])
+ printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
+#endif
+}
+
+
+void
+_initialize_ser_dos (void)
+{
+ serial_add_interface (&dos_ops);
+
+ /* Save original interrupt mask register. */
+ icu_oldmask = inportb (ICU_MASK);
+
+ /* Mark fixed motherboard irqs as inuse. */
+ intrupts[0].inuse = /* timer tick */
+ intrupts[1].inuse = /* keyboard */
+ intrupts[2].inuse = 1; /* slave icu */
+
+ add_show_from_set (
+ add_set_cmd ("com1base", class_obscure, var_zinteger,
+ (char *) &ports[0].base,
+ "Set COM1 base i/o port address.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com1irq", class_obscure, var_zinteger,
+ (char *) &ports[0].irq,
+ "Set COM1 interrupt request.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com2base", class_obscure, var_zinteger,
+ (char *) &ports[1].base,
+ "Set COM2 base i/o port address.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com2irq", class_obscure, var_zinteger,
+ (char *) &ports[1].irq,
+ "Set COM2 interrupt request.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com3base", class_obscure, var_zinteger,
+ (char *) &ports[2].base,
+ "Set COM3 base i/o port address.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com3irq", class_obscure, var_zinteger,
+ (char *) &ports[2].irq,
+ "Set COM3 interrupt request.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com4base", class_obscure, var_zinteger,
+ (char *) &ports[3].base,
+ "Set COM4 base i/o port address.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set (
+ add_set_cmd ("com4irq", class_obscure, var_zinteger,
+ (char *) &ports[3].irq,
+ "Set COM4 interrupt request.",
+ &setlist),
+ &showlist);
+
+ add_info ("serial", dos_info,
+ "Print DOS serial port status.");
+}
diff --git a/contrib/gdb/gdb/somread.c b/contrib/gdb/gdb/somread.c
new file mode 100644
index 0000000..4ffa4c1
--- /dev/null
+++ b/contrib/gdb/gdb/somread.c
@@ -0,0 +1,736 @@
+/* Read HP PA/Risc object files for GDB.
+ Copyright 1991, 1992, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002,
+ 2004 Free Software Foundation, Inc.
+ Written by Fred Fish at Cygnus Support.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "bfd.h"
+#include <syms.h>
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "stabsread.h"
+#include "gdb-stabs.h"
+#include "complaints.h"
+#include "gdb_string.h"
+#include "demangle.h"
+#include "som.h"
+#include "libhppa.h"
+
+/* Various things we might complain about... */
+
+static int init_import_symbols (struct objfile *objfile);
+
+static void som_symfile_init (struct objfile *);
+
+static void som_new_init (struct objfile *);
+
+static void som_symfile_read (struct objfile *, int);
+
+static void som_symfile_finish (struct objfile *);
+
+static void som_symtab_read (bfd *, struct objfile *,
+ struct section_offsets *);
+
+static void som_symfile_offsets (struct objfile *, struct section_addr_info *);
+
+/* FIXME: These should really be in a common header somewhere */
+
+extern void hpread_build_psymtabs (struct objfile *, int);
+
+extern void hpread_symfile_finish (struct objfile *);
+
+extern void hpread_symfile_init (struct objfile *);
+
+extern void do_pxdb (bfd *);
+
+/*
+
+ LOCAL FUNCTION
+
+ som_symtab_read -- read the symbol table of a SOM file
+
+ SYNOPSIS
+
+ void som_symtab_read (bfd *abfd, struct objfile *objfile,
+ struct section_offsets *section_offsets)
+
+ DESCRIPTION
+
+ Given an open bfd, a base address to relocate symbols to, and a
+ flag that specifies whether or not this bfd is for an executable
+ or not (may be shared library for example), add all the global
+ function and data symbols to the minimal symbol table.
+ */
+
+static void
+som_symtab_read (bfd *abfd, struct objfile *objfile,
+ struct section_offsets *section_offsets)
+{
+ unsigned int number_of_symbols;
+ int val, dynamic;
+ char *stringtab;
+ asection *shlib_info;
+ struct symbol_dictionary_record *buf, *bufp, *endbufp;
+ char *symname;
+ CONST int symsize = sizeof (struct symbol_dictionary_record);
+ CORE_ADDR text_offset, data_offset;
+
+
+ text_offset = ANOFFSET (section_offsets, 0);
+ data_offset = ANOFFSET (section_offsets, 1);
+
+ number_of_symbols = bfd_get_symcount (abfd);
+
+ /* FIXME (alloca): could be quite large. */
+ buf = alloca (symsize * number_of_symbols);
+ bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
+ val = bfd_bread (buf, symsize * number_of_symbols, abfd);
+ if (val != symsize * number_of_symbols)
+ error ("Couldn't read symbol dictionary!");
+
+ /* FIXME (alloca): could be quite large. */
+ stringtab = alloca (obj_som_stringtab_size (abfd));
+ bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
+ val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd);
+ if (val != obj_som_stringtab_size (abfd))
+ error ("Can't read in HP string table.");
+
+ /* We need to determine if objfile is a dynamic executable (so we
+ can do the right thing for ST_ENTRY vs ST_CODE symbols).
+
+ There's nothing in the header which easily allows us to do
+ this.
+
+ This code used to rely upon the existence of a $SHLIB_INFO$
+ section to make this determination. HP claims that it is
+ more accurate to check for a nonzero text offset, but they
+ have not provided any information about why that test is
+ more accurate. */
+ dynamic = (text_offset != 0);
+
+ endbufp = buf + number_of_symbols;
+ for (bufp = buf; bufp < endbufp; ++bufp)
+ {
+ enum minimal_symbol_type ms_type;
+
+ QUIT;
+
+ switch (bufp->symbol_scope)
+ {
+ case SS_UNIVERSAL:
+ case SS_EXTERNAL:
+ switch (bufp->symbol_type)
+ {
+ case ST_SYM_EXT:
+ case ST_ARG_EXT:
+ continue;
+
+ case ST_CODE:
+ case ST_PRI_PROG:
+ case ST_SEC_PROG:
+ case ST_MILLICODE:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_ENTRY:
+ symname = bufp->name.n_strx + stringtab;
+ /* For a dynamic executable, ST_ENTRY symbols are
+ the stubs, while the ST_CODE symbol is the real
+ function. */
+ if (dynamic)
+ ms_type = mst_solib_trampoline;
+ else
+ ms_type = mst_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_STUB:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_solib_trampoline;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_DATA:
+ symname = bufp->name.n_strx + stringtab;
+ bufp->symbol_value += data_offset;
+ ms_type = mst_data;
+ break;
+ default:
+ continue;
+ }
+ break;
+
+#if 0
+ /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!). */
+ case SS_GLOBAL:
+#endif
+ case SS_LOCAL:
+ switch (bufp->symbol_type)
+ {
+ case ST_SYM_EXT:
+ case ST_ARG_EXT:
+ continue;
+
+ case ST_CODE:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_file_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+
+ check_strange_names:
+ /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
+ label prefixes for stabs, constant data, etc. So we need
+ only filter out L$ symbols which are left in due to
+ limitations in how GAS generates SOM relocations.
+
+ When linking in the HPUX C-library the HP linker has
+ the nasty habit of placing section symbols from the literal
+ subspaces in the middle of the program's text. Filter
+ those out as best we can. Check for first and last character
+ being '$'.
+
+ And finally, the newer HP compilers emit crud like $PIC_foo$N
+ in some circumstance (PIC code I guess). It's also claimed
+ that they emit D$ symbols too. What stupidity. */
+ if ((symname[0] == 'L' && symname[1] == '$')
+ || (symname[0] == '$' && symname[strlen (symname) - 1] == '$')
+ || (symname[0] == 'D' && symname[1] == '$')
+ || (strncmp (symname, "$PIC", 4) == 0))
+ continue;
+ break;
+
+ case ST_PRI_PROG:
+ case ST_SEC_PROG:
+ case ST_MILLICODE:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_file_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_ENTRY:
+ symname = bufp->name.n_strx + stringtab;
+ /* SS_LOCAL symbols in a shared library do not have
+ export stubs, so we do not have to worry about
+ using mst_file_text vs mst_solib_trampoline here like
+ we do for SS_UNIVERSAL and SS_EXTERNAL symbols above. */
+ ms_type = mst_file_text;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+ case ST_STUB:
+ symname = bufp->name.n_strx + stringtab;
+ ms_type = mst_solib_trampoline;
+ bufp->symbol_value += text_offset;
+ bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
+ break;
+
+
+ case ST_DATA:
+ symname = bufp->name.n_strx + stringtab;
+ bufp->symbol_value += data_offset;
+ ms_type = mst_file_data;
+ goto check_strange_names;
+
+ default:
+ continue;
+ }
+ break;
+
+ /* This can happen for common symbols when -E is passed to the
+ final link. No idea _why_ that would make the linker force
+ common symbols to have an SS_UNSAT scope, but it does.
+
+ This also happens for weak symbols, but their type is
+ ST_DATA. */
+ case SS_UNSAT:
+ switch (bufp->symbol_type)
+ {
+ case ST_STORAGE:
+ case ST_DATA:
+ symname = bufp->name.n_strx + stringtab;
+ bufp->symbol_value += data_offset;
+ ms_type = mst_data;
+ break;
+
+ default:
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ if (bufp->name.n_strx > obj_som_stringtab_size (abfd))
+ error ("Invalid symbol data; bad HP string table offset: %d",
+ bufp->name.n_strx);
+
+ prim_record_minimal_symbol (symname, bufp->symbol_value, ms_type,
+ objfile);
+ }
+}
+
+/* Scan and build partial symbols for a symbol file.
+ We have been initialized by a call to som_symfile_init, which
+ currently does nothing.
+
+ SECTION_OFFSETS is a set of offsets to apply to relocate the symbols
+ in each section. This is ignored, as it isn't needed for SOM.
+
+ MAINLINE is true if we are reading the main symbol
+ table (as opposed to a shared lib or dynamically loaded file).
+
+ This function only does the minimum work necessary for letting the
+ user "name" things symbolically; it does not read the entire symtab.
+ Instead, it reads the external and static symbols and puts them in partial
+ symbol tables. When more extensive information is requested of a
+ file, the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the symbols
+ for real.
+
+ We look for sections with specific names, to tell us what debug
+ format to look for: FIXME!!!
+
+ somstab_build_psymtabs() handles STABS symbols.
+
+ Note that SOM files have a "minimal" symbol table, which is vaguely
+ reminiscent of a COFF symbol table, but has only the minimal information
+ necessary for linking. We process this also, and use the information to
+ build gdb's minimal symbol table. This gives us some minimal debugging
+ capability even for files compiled without -g. */
+
+static void
+som_symfile_read (struct objfile *objfile, int mainline)
+{
+ bfd *abfd = objfile->obfd;
+ struct cleanup *back_to;
+
+ do_pxdb (symfile_bfd_open (objfile->name));
+
+ init_minimal_symbol_collection ();
+ back_to = make_cleanup_discard_minimal_symbols ();
+
+ /* Read in the import list and the export list. Currently
+ the export list isn't used; the import list is used in
+ hp-symtab-read.c to handle static vars declared in other
+ shared libraries. */
+ init_import_symbols (objfile);
+#if 0 /* Export symbols not used today 1997-08-05 */
+ init_export_symbols (objfile);
+#else
+ objfile->export_list = NULL;
+ objfile->export_list_size = 0;
+#endif
+
+ /* Process the normal SOM symbol table first.
+ This reads in the DNTT and string table, but doesn't
+ actually scan the DNTT. It does scan the linker symbol
+ table and thus build up a "minimal symbol table". */
+
+ som_symtab_read (abfd, objfile, objfile->section_offsets);
+
+ /* Install any minimal symbols that have been collected as the current
+ minimal symbols for this objfile.
+ Further symbol-reading is done incrementally, file-by-file,
+ in a step known as "psymtab-to-symtab" expansion. hp-symtab-read.c
+ contains the code to do the actual DNTT scanning and symtab building. */
+ install_minimal_symbols (objfile);
+ do_cleanups (back_to);
+
+ /* Now read information from the stabs debug sections.
+ This is a no-op for SOM.
+ Perhaps it is intended for some kind of mixed STABS/SOM
+ situation? */
+ stabsect_build_psymtabs (objfile, mainline,
+ "$GDB_SYMBOLS$", "$GDB_STRINGS$", "$TEXT$");
+
+ /* Now read the native debug information.
+ This builds the psymtab. This used to be done via a scan of
+ the DNTT, but is now done via the PXDB-built quick-lookup tables
+ together with a scan of the GNTT. See hp-psymtab-read.c. */
+ hpread_build_psymtabs (objfile, mainline);
+
+ /* Force hppa-tdep.c to re-read the unwind descriptors. */
+ objfile->obj_private = NULL;
+}
+
+/* Initialize anything that needs initializing when a completely new symbol
+ file is specified (not just adding some symbols from another file, e.g. a
+ shared library).
+
+ We reinitialize buildsym, since we may be reading stabs from a SOM file. */
+
+static void
+som_new_init (struct objfile *ignore)
+{
+ stabsread_new_init ();
+ buildsym_new_init ();
+}
+
+/* Perform any local cleanups required when we are done with a particular
+ objfile. I.E, we are in the process of discarding all symbol information
+ for an objfile, freeing up all memory held for it, and unlinking the
+ objfile struct from the global list of known objfiles. */
+
+static void
+som_symfile_finish (struct objfile *objfile)
+{
+ if (objfile->sym_stab_info != NULL)
+ {
+ xmfree (objfile->md, objfile->sym_stab_info);
+ }
+ hpread_symfile_finish (objfile);
+}
+
+/* SOM specific initialization routine for reading symbols. */
+
+static void
+som_symfile_init (struct objfile *objfile)
+{
+ /* SOM objects may be reordered, so set OBJF_REORDERED. If we
+ find this causes a significant slowdown in gdb then we could
+ set it in the debug symbol readers only when necessary. */
+ objfile->flags |= OBJF_REORDERED;
+ hpread_symfile_init (objfile);
+}
+
+/* SOM specific parsing routine for section offsets.
+
+ Plain and simple for now. */
+
+static void
+som_symfile_offsets (struct objfile *objfile, struct section_addr_info *addrs)
+{
+ int i;
+ CORE_ADDR text_addr;
+
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ /* FIXME: ezannoni 2000-04-20 The section names in SOM are not
+ .text, .data, etc, but $TEXT$, $DATA$,... We should initialize
+ SET_OFF_* from bfd. (See default_symfile_offsets()). But I don't
+ know the correspondence between SOM sections and GDB's idea of
+ section names. So for now we default to what is was before these
+ changes.*/
+ objfile->sect_index_text = 0;
+ objfile->sect_index_data = 1;
+ objfile->sect_index_bss = 2;
+ objfile->sect_index_rodata = 3;
+
+ /* First see if we're a shared library. If so, get the section
+ offsets from the library, else get them from addrs. */
+ if (!som_solib_section_offsets (objfile, objfile->section_offsets))
+ {
+ /* Note: Here is OK to compare with ".text" because this is the
+ name that gdb itself gives to that section, not the SOM
+ name. */
+ for (i = 0; i < objfile->num_sections && addrs->other[i].name; i++)
+ if (strcmp (addrs->other[i].name, ".text") == 0)
+ break;
+ text_addr = addrs->other[i].addr;
+
+ for (i = 0; i < objfile->num_sections; i++)
+ (objfile->section_offsets)->offsets[i] = text_addr;
+ }
+}
+
+/* Read in and initialize the SOM import list which is present
+ for all executables and shared libraries. The import list
+ consists of the symbols that are referenced in OBJFILE but
+ not defined there. (Variables that are imported are dealt
+ with as "loc_indirect" vars.)
+ Return value = number of import symbols read in. */
+static int
+init_import_symbols (struct objfile *objfile)
+{
+ unsigned int import_list;
+ unsigned int import_list_size;
+ unsigned int string_table;
+ unsigned int string_table_size;
+ char *string_buffer;
+ int i;
+ int j;
+ int k;
+ asection *text_section; /* section handle */
+ unsigned int dl_header[12]; /* SOM executable header */
+
+ /* A struct for an entry in the SOM import list */
+ typedef struct
+ {
+ int name; /* index into the string table */
+ short dont_care1; /* we don't use this */
+ unsigned char type; /* 0 = NULL, 2 = Data, 3 = Code, 7 = Storage, 13 = Plabel */
+ unsigned int reserved2:8; /* not used */
+ }
+ SomImportEntry;
+
+ /* We read 100 entries in at a time from the disk file. */
+#define SOM_READ_IMPORTS_NUM 100
+#define SOM_READ_IMPORTS_CHUNK_SIZE (sizeof (SomImportEntry) * SOM_READ_IMPORTS_NUM)
+ SomImportEntry buffer[SOM_READ_IMPORTS_NUM];
+
+ /* Initialize in case we error out */
+ objfile->import_list = NULL;
+ objfile->import_list_size = 0;
+
+ /* It doesn't work, for some reason, to read in space $TEXT$;
+ the subspace $SHLIB_INFO$ has to be used. Some BFD quirk? pai/1997-08-05 */
+ text_section = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$");
+ if (!text_section)
+ return 0;
+ /* Get the SOM executable header */
+ bfd_get_section_contents (objfile->obfd, text_section, dl_header, 0, 12 * sizeof (int));
+
+ /* Check header version number for 10.x HP-UX */
+ /* Currently we deal only with 10.x systems; on 9.x the version # is 89060912.
+ FIXME: Change for future HP-UX releases and mods to the SOM executable format */
+ if (dl_header[0] != 93092112)
+ return 0;
+
+ import_list = dl_header[4];
+ import_list_size = dl_header[5];
+ if (!import_list_size)
+ return 0;
+ string_table = dl_header[10];
+ string_table_size = dl_header[11];
+ if (!string_table_size)
+ return 0;
+
+ /* Suck in SOM string table */
+ string_buffer = (char *) xmalloc (string_table_size);
+ bfd_get_section_contents (objfile->obfd, text_section, string_buffer,
+ string_table, string_table_size);
+
+ /* Allocate import list in the psymbol obstack; this has nothing
+ to do with psymbols, just a matter of convenience. We want the
+ import list to be freed when the objfile is deallocated */
+ objfile->import_list
+ = (ImportEntry *) obstack_alloc (&objfile->objfile_obstack,
+ import_list_size * sizeof (ImportEntry));
+
+ /* Read in the import entries, a bunch at a time */
+ for (j = 0, k = 0;
+ j < (import_list_size / SOM_READ_IMPORTS_NUM);
+ j++)
+ {
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ import_list + j * SOM_READ_IMPORTS_CHUNK_SIZE,
+ SOM_READ_IMPORTS_CHUNK_SIZE);
+ for (i = 0; i < SOM_READ_IMPORTS_NUM; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->import_list[k]
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->import_list[k], string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ }
+ else /* null type */
+ objfile->import_list[k] = NULL;
+
+ }
+ }
+
+ /* Get the leftovers */
+ if (k < import_list_size)
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ import_list + k * sizeof (SomImportEntry),
+ (import_list_size - k) * sizeof (SomImportEntry));
+ for (i = 0; k < import_list_size; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->import_list[k]
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->import_list[k], string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ }
+ else
+ objfile->import_list[k] = NULL;
+ }
+
+ objfile->import_list_size = import_list_size;
+ xfree (string_buffer);
+ return import_list_size;
+}
+
+/* Read in and initialize the SOM export list which is present
+ for all executables and shared libraries. The import list
+ consists of the symbols that are referenced in OBJFILE but
+ not defined there. (Variables that are imported are dealt
+ with as "loc_indirect" vars.)
+ Return value = number of import symbols read in. */
+int
+init_export_symbols (struct objfile *objfile)
+{
+ unsigned int export_list;
+ unsigned int export_list_size;
+ unsigned int string_table;
+ unsigned int string_table_size;
+ char *string_buffer;
+ int i;
+ int j;
+ int k;
+ asection *text_section; /* section handle */
+ unsigned int dl_header[12]; /* SOM executable header */
+
+ /* A struct for an entry in the SOM export list */
+ typedef struct
+ {
+ int next; /* for hash table use -- we don't use this */
+ int name; /* index into string table */
+ int value; /* offset or plabel */
+ int dont_care1; /* not used */
+ unsigned char type; /* 0 = NULL, 2 = Data, 3 = Code, 7 = Storage, 13 = Plabel */
+ char dont_care2; /* not used */
+ short dont_care3; /* not used */
+ }
+ SomExportEntry;
+
+ /* We read 100 entries in at a time from the disk file. */
+#define SOM_READ_EXPORTS_NUM 100
+#define SOM_READ_EXPORTS_CHUNK_SIZE (sizeof (SomExportEntry) * SOM_READ_EXPORTS_NUM)
+ SomExportEntry buffer[SOM_READ_EXPORTS_NUM];
+
+ /* Initialize in case we error out */
+ objfile->export_list = NULL;
+ objfile->export_list_size = 0;
+
+ /* It doesn't work, for some reason, to read in space $TEXT$;
+ the subspace $SHLIB_INFO$ has to be used. Some BFD quirk? pai/1997-08-05 */
+ text_section = bfd_get_section_by_name (objfile->obfd, "$SHLIB_INFO$");
+ if (!text_section)
+ return 0;
+ /* Get the SOM executable header */
+ bfd_get_section_contents (objfile->obfd, text_section, dl_header, 0, 12 * sizeof (int));
+
+ /* Check header version number for 10.x HP-UX */
+ /* Currently we deal only with 10.x systems; on 9.x the version # is 89060912.
+ FIXME: Change for future HP-UX releases and mods to the SOM executable format */
+ if (dl_header[0] != 93092112)
+ return 0;
+
+ export_list = dl_header[8];
+ export_list_size = dl_header[9];
+ if (!export_list_size)
+ return 0;
+ string_table = dl_header[10];
+ string_table_size = dl_header[11];
+ if (!string_table_size)
+ return 0;
+
+ /* Suck in SOM string table */
+ string_buffer = (char *) xmalloc (string_table_size);
+ bfd_get_section_contents (objfile->obfd, text_section, string_buffer,
+ string_table, string_table_size);
+
+ /* Allocate export list in the psymbol obstack; this has nothing
+ to do with psymbols, just a matter of convenience. We want the
+ export list to be freed when the objfile is deallocated */
+ objfile->export_list
+ = (ExportEntry *) obstack_alloc (&objfile->objfile_obstack,
+ export_list_size * sizeof (ExportEntry));
+
+ /* Read in the export entries, a bunch at a time */
+ for (j = 0, k = 0;
+ j < (export_list_size / SOM_READ_EXPORTS_NUM);
+ j++)
+ {
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ export_list + j * SOM_READ_EXPORTS_CHUNK_SIZE,
+ SOM_READ_EXPORTS_CHUNK_SIZE);
+ for (i = 0; i < SOM_READ_EXPORTS_NUM; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->export_list[k].name
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->export_list[k].name, string_buffer + buffer[i].name);
+ objfile->export_list[k].address = buffer[i].value;
+ /* Some day we might want to record the type and other information too */
+ }
+ else
+ /* null type */
+ {
+ objfile->export_list[k].name = NULL;
+ objfile->export_list[k].address = 0;
+ }
+ }
+ }
+
+ /* Get the leftovers */
+ if (k < export_list_size)
+ bfd_get_section_contents (objfile->obfd, text_section, buffer,
+ export_list + k * sizeof (SomExportEntry),
+ (export_list_size - k) * sizeof (SomExportEntry));
+ for (i = 0; k < export_list_size; i++, k++)
+ {
+ if (buffer[i].type != (unsigned char) 0)
+ {
+ objfile->export_list[k].name
+ = (char *) obstack_alloc (&objfile->objfile_obstack, strlen (string_buffer + buffer[i].name) + 1);
+ strcpy (objfile->export_list[k].name, string_buffer + buffer[i].name);
+ /* Some day we might want to record the type and other information too */
+ objfile->export_list[k].address = buffer[i].value;
+ }
+ else
+ {
+ objfile->export_list[k].name = NULL;
+ objfile->export_list[k].address = 0;
+ }
+ }
+
+ objfile->export_list_size = export_list_size;
+ xfree (string_buffer);
+ return export_list_size;
+}
+
+
+
+/* Register that we are able to handle SOM object file formats. */
+
+static struct sym_fns som_sym_fns =
+{
+ bfd_target_som_flavour,
+ som_new_init, /* sym_new_init: init anything gbl to entire symtab */
+ som_symfile_init, /* sym_init: read initial info, setup for sym_read() */
+ som_symfile_read, /* sym_read: read a symbol file into symtab */
+ som_symfile_finish, /* sym_finish: finished with file, cleanup */
+ som_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
+ NULL /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_somread (void)
+{
+ add_symtab_fns (&som_sym_fns);
+}
diff --git a/contrib/gdb/gdb/somsolib.c b/contrib/gdb/gdb/somsolib.c
new file mode 100644
index 0000000..d8c971b
--- /dev/null
+++ b/contrib/gdb/gdb/somsolib.c
@@ -0,0 +1,1624 @@
+/* Handle HP SOM shared libraries for GDB, the GNU Debugger.
+
+ Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Written by the Center for Software Science at the Univerity of Utah
+ and by Cygnus Support. */
+
+
+#include "defs.h"
+
+#include "frame.h"
+#include "bfd.h"
+#include "som.h"
+#include "libhppa.h"
+#include "gdbcore.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "inferior.h"
+#include "gdb-stabs.h"
+#include "gdb_stat.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "regcache.h"
+#include "gdb_assert.h"
+#include "exec.h"
+
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Uncomment this to turn on some debugging output.
+ */
+
+/* #define SOLIB_DEBUG
+ */
+
+/* This lives in hppa-tdep.c. */
+extern struct unwind_table_entry *find_unwind_entry (CORE_ADDR pc);
+
+/* These ought to be defined in some public interface, but aren't. They
+ define the meaning of the various bits in the distinguished __dld_flags
+ variable that is declared in every debuggable a.out on HP-UX, and that
+ is shared between the debugger and the dynamic linker.
+ */
+#define DLD_FLAGS_MAPPRIVATE 0x1
+#define DLD_FLAGS_HOOKVALID 0x2
+#define DLD_FLAGS_LISTVALID 0x4
+#define DLD_FLAGS_BOR_ENABLE 0x8
+
+/* TODO:
+
+ * Support for hpux8 dynamic linker. */
+
+/* The basic structure which describes a dynamically loaded object. This
+ data structure is private to the dynamic linker and isn't found in
+ any HPUX include file. */
+
+struct som_solib_mapped_entry
+ {
+ /* The name of the library. */
+ char *name;
+
+ /* Version of this structure (it is expected to change again in hpux10). */
+ unsigned char struct_version;
+
+ /* Binding mode for this library. */
+ unsigned char bind_mode;
+
+ /* Version of this library. */
+ short library_version;
+
+ /* Start of text address,
+ * link-time text location (length of text area),
+ * end of text address. */
+ CORE_ADDR text_addr;
+ CORE_ADDR text_link_addr;
+ CORE_ADDR text_end;
+
+ /* Start of data, start of bss and end of data. */
+ CORE_ADDR data_start;
+ CORE_ADDR bss_start;
+ CORE_ADDR data_end;
+
+ /* Value of linkage pointer (%r19). */
+ CORE_ADDR got_value;
+
+ /* Next entry. */
+ struct som_solib_mapped_entry *next;
+
+ /* There are other fields, but I don't have information as to what is
+ contained in them. */
+
+ /* For versions from HPUX-10.30 and up */
+
+ /* Address in target of offset from thread-local register of
+ * start of this thread's data. I.e., the first thread-local
+ * variable in this shared library starts at *(tsd_start_addr)
+ * from that area pointed to by cr27 (mpsfu_hi).
+ *
+ * We do the indirection as soon as we read it, so from then
+ * on it's the offset itself.
+ */
+ CORE_ADDR tsd_start_addr;
+
+ /* Following this are longwords holding:
+
+ * ?, ?, ?, ptr to -1, ptr to-1, ptr to lib name (leaf name),
+ * ptr to __data_start, ptr to __data_end
+ */
+
+
+ };
+
+/* A structure to keep track of all the known shared objects. */
+struct so_list
+ {
+ struct som_solib_mapped_entry som_solib;
+ struct objfile *objfile;
+ bfd *abfd;
+ struct section_table *sections;
+ struct section_table *sections_end;
+/* elz: added this field to store the address in target space (in the
+ library) of the library descriptor (handle) which we read into
+ som_solib_mapped_entry structure */
+ CORE_ADDR solib_addr;
+ struct so_list *next;
+
+ };
+
+static struct so_list *so_list_head;
+
+
+/* This is the cumulative size in bytes of the symbol tables of all
+ shared objects on the so_list_head list. (When we say size, here
+ we mean of the information before it is brought into memory and
+ potentially expanded by GDB.) When adding a new shlib, this value
+ is compared against the threshold size, held by auto_solib_limit
+ (in megabytes). If adding symbols for the new shlib would cause
+ the total size to exceed the threshold, then the new shlib's
+ symbols are not loaded. */
+static LONGEST som_solib_total_st_size;
+
+/* When the threshold is reached for any shlib, we refuse to add
+ symbols for subsequent shlibs, even if those shlibs' symbols would
+ be small enough to fit under the threshold. (Although this may
+ result in one, early large shlib preventing the loading of later,
+ smalller shlibs' symbols, it allows us to issue one informational
+ message. The alternative, to issue a message for each shlib whose
+ symbols aren't loaded, could be a big annoyance where the threshold
+ is exceeded due to a very large number of shlibs.)
+ */
+static int som_solib_st_size_threshold_exceeded;
+
+/* These addresses should be filled in by som_solib_create_inferior_hook.
+ They are also used elsewhere in this module.
+ */
+typedef struct
+ {
+ CORE_ADDR address;
+ struct unwind_table_entry *unwind;
+ }
+addr_and_unwind_t;
+
+/* When adding fields, be sure to clear them in _initialize_som_solib. */
+static struct
+ {
+ int is_valid;
+ addr_and_unwind_t hook;
+ addr_and_unwind_t hook_stub;
+ addr_and_unwind_t load;
+ addr_and_unwind_t load_stub;
+ addr_and_unwind_t unload;
+ addr_and_unwind_t unload2;
+ addr_and_unwind_t unload_stub;
+ }
+dld_cache;
+
+
+
+static void som_sharedlibrary_info_command (char *, int);
+
+static void som_solib_sharedlibrary_command (char *, int);
+
+static LONGEST
+som_solib_sizeof_symbol_table (char *filename)
+{
+ bfd *abfd;
+ int desc;
+ char *absolute_name;
+ LONGEST st_size = (LONGEST) 0;
+ asection *sect;
+
+ /* We believe that filename was handed to us by the dynamic linker, and
+ is therefore always an absolute path.
+ */
+ desc = openp (getenv ("PATH"), 1, filename, O_RDONLY | O_BINARY, 0, &absolute_name);
+ if (desc < 0)
+ {
+ perror_with_name (filename);
+ }
+ filename = absolute_name;
+
+ abfd = bfd_fdopenr (filename, gnutarget, desc);
+ if (!abfd)
+ {
+ close (desc);
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't open to read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ if (!bfd_check_format (abfd, bfd_object)) /* Reads in section info */
+ {
+ bfd_close (abfd); /* This also closes desc */
+ make_cleanup (xfree, filename);
+ error ("\"%s\": can't read symbols: %s.", filename,
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ /* Sum the sizes of the various sections that compose debug info. */
+
+ /* This contains non-DOC information. */
+ sect = bfd_get_section_by_name (abfd, "$DEBUG$");
+ if (sect)
+ st_size += (LONGEST) bfd_section_size (abfd, sect);
+
+ /* This contains DOC information. */
+ sect = bfd_get_section_by_name (abfd, "$PINFO$");
+ if (sect)
+ st_size += (LONGEST) bfd_section_size (abfd, sect);
+
+ bfd_close (abfd); /* This also closes desc */
+ xfree (filename);
+
+ /* Unfortunately, just summing the sizes of various debug info
+ sections isn't a very accurate measurement of how much heap
+ space the debugger will need to hold them. It also doesn't
+ account for space needed by linker (aka "minimal") symbols.
+
+ Anecdotal evidence suggests that just summing the sizes of
+ debug-info-related sections understates the heap space needed
+ to represent it internally by about an order of magnitude.
+
+ Since it's not exactly brain surgery we're doing here, rather
+ than attempt to more accurately measure the size of a shlib's
+ symbol table in GDB's heap, we'll just apply a 10x fudge-
+ factor to the debug info sections' size-sum. No, this doesn't
+ account for minimal symbols in non-debuggable shlibs. But it
+ all roughly washes out in the end.
+ */
+ return st_size * (LONGEST) 10;
+}
+
+
+static void
+som_solib_add_solib_objfile (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr)
+{
+ obj_private_data_t *obj_private;
+ struct obj_section *s;
+
+ so->objfile = symbol_file_add (name, from_tty, NULL, 0, OBJF_SHARED);
+ so->abfd = so->objfile->obfd;
+
+ /* syms_from_objfile has bizarre section offset code,
+ so I do my own right here. */
+ for (s = so->objfile->sections; s < so->objfile->sections_end; s++)
+ {
+ flagword aflag = bfd_get_section_flags(so->abfd, s->the_bfd_section);
+ if (aflag & SEC_CODE)
+ {
+ s->addr += so->som_solib.text_addr - so->som_solib.text_link_addr;
+ s->endaddr += so->som_solib.text_addr - so->som_solib.text_link_addr;
+ }
+ else if (aflag & SEC_DATA)
+ {
+ s->addr += so->som_solib.data_start;
+ s->endaddr += so->som_solib.data_start;
+ }
+ else
+ ;
+ }
+
+ /* Mark this as a shared library and save private data.
+ */
+ so->objfile->flags |= OBJF_SHARED;
+
+ if (so->objfile->obj_private == NULL)
+ {
+ obj_private = (obj_private_data_t *)
+ obstack_alloc (&so->objfile->objfile_obstack,
+ sizeof (obj_private_data_t));
+ obj_private->unwind_info = NULL;
+ obj_private->so_info = NULL;
+ so->objfile->obj_private = obj_private;
+ }
+
+ obj_private = (obj_private_data_t *) so->objfile->obj_private;
+ obj_private->so_info = so;
+
+ if (!bfd_check_format (so->abfd, bfd_object))
+ {
+ error ("\"%s\": not in executable format: %s.",
+ name, bfd_errmsg (bfd_get_error ()));
+ }
+}
+
+
+static void
+som_solib_load_symbols (struct so_list *so, char *name, int from_tty,
+ CORE_ADDR text_addr, struct target_ops *target)
+{
+ struct section_table *p;
+ int status;
+ char buf[4];
+ CORE_ADDR presumed_data_start;
+
+#ifdef SOLIB_DEBUG
+ printf ("--Adding symbols for shared library \"%s\"\n", name);
+#endif
+
+ som_solib_add_solib_objfile (so, name, from_tty, text_addr);
+
+ /* Now we need to build a section table for this library since
+ we might be debugging a core file from a dynamically linked
+ executable in which the libraries were not privately mapped. */
+ if (build_section_table (so->abfd,
+ &so->sections,
+ &so->sections_end))
+ {
+ error ("Unable to build section table for shared library\n.");
+ return;
+ }
+
+ /* Relocate all the sections based on where they got loaded. */
+ for (p = so->sections; p < so->sections_end; p++)
+ {
+ if (p->the_bfd_section->flags & SEC_CODE)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_TEXT (so->objfile));
+ }
+ else if (p->the_bfd_section->flags & SEC_DATA)
+ {
+ p->addr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ p->endaddr += ANOFFSET (so->objfile->section_offsets, SECT_OFF_DATA (so->objfile));
+ }
+ }
+
+ /* Now see if we need to map in the text and data for this shared
+ library (for example debugging a core file which does not use
+ private shared libraries.).
+
+ Carefully peek at the first text address in the library. If the
+ read succeeds, then the libraries were privately mapped and were
+ included in the core dump file.
+
+ If the peek failed, then the libraries were not privately mapped
+ and are not in the core file, we'll have to read them in ourselves. */
+ status = target_read_memory (text_addr, buf, 4);
+ if (status != 0)
+ {
+ int old, new;
+
+ new = so->sections_end - so->sections;
+
+ old = target_resize_to_sections (target, new);
+
+ /* Copy over the old data before it gets clobbered. */
+ memcpy ((char *) (target->to_sections + old),
+ so->sections,
+ ((sizeof (struct section_table)) * new));
+ }
+}
+
+
+/* FIXME: cagney/2003-02-01: This just isn't right. Given an address
+ within the target's address space, this converts the value into an
+ address within the host's (i.e., GDB's) address space. Given that
+ the host/target address spaces are separate, this can't be right. */
+
+static void *
+hpux_address_to_host_pointer_hack (CORE_ADDR addr)
+{
+ void *ptr;
+
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
+ return ptr;
+}
+
+/* Add symbols from shared libraries into the symtab list, unless the
+ size threshold specified by auto_solib_limit (in megabytes) would
+ be exceeded. */
+
+void
+som_solib_add (char *arg_string, int from_tty, struct target_ops *target, int readsyms)
+{
+ struct minimal_symbol *msymbol;
+ struct so_list *so_list_tail;
+ CORE_ADDR addr;
+ asection *shlib_info;
+ int status;
+ unsigned int dld_flags;
+ char buf[4], *re_err;
+ int threshold_warning_given = 0;
+
+ /* First validate our arguments. */
+ re_err = re_comp (arg_string ? arg_string : ".");
+ if (re_err != NULL)
+ {
+ error ("Invalid regexp: %s", re_err);
+ }
+
+ /* If we're debugging a core file, or have attached to a running
+ process, then som_solib_create_inferior_hook will not have been
+ called.
+
+ We need to first determine if we're dealing with a dynamically
+ linked executable. If not, then return without an error or warning.
+
+ We also need to examine __dld_flags to determine if the shared library
+ list is valid and to determine if the libraries have been privately
+ mapped. */
+ if (symfile_objfile == NULL)
+ return;
+
+ /* First see if the objfile was dynamically linked. */
+ shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
+ if (!shlib_info)
+ return;
+
+ /* It's got a $SHLIB_INFO$ section, make sure it's not empty. */
+ if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
+ return;
+
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+ if (msymbol == NULL)
+ {
+ error ("Unable to find __dld_flags symbol in object file.\n");
+ return;
+ }
+
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ /* Read the current contents. */
+ status = target_read_memory (addr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to read __dld_flags\n");
+ return;
+ }
+ dld_flags = extract_unsigned_integer (buf, 4);
+
+ /* __dld_list may not be valid. If not, then we punt, warning the user if
+ we were called as a result of the add-symfile command.
+ */
+ if ((dld_flags & DLD_FLAGS_LISTVALID) == 0)
+ {
+ if (from_tty)
+ error ("__dld_list is not valid according to __dld_flags.\n");
+ return;
+ }
+
+ /* If the libraries were not mapped private, warn the user. */
+ if ((dld_flags & DLD_FLAGS_MAPPRIVATE) == 0)
+ warning ("The shared libraries were not privately mapped; setting a\nbreakpoint in a shared library will not work until you rerun the program.\n");
+
+ msymbol = lookup_minimal_symbol ("__dld_list", NULL, NULL);
+ if (!msymbol)
+ {
+ /* Older crt0.o files (hpux8) don't have __dld_list as a symbol,
+ but the data is still available if you know where to look. */
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+ if (!msymbol)
+ {
+ error ("Unable to find dynamic library list.\n");
+ return;
+ }
+ addr = SYMBOL_VALUE_ADDRESS (msymbol) - 8;
+ }
+ else
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ status = target_read_memory (addr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to find dynamic library list.\n");
+ return;
+ }
+
+ addr = extract_unsigned_integer (buf, 4);
+
+ /* If addr is zero, then we're using an old dynamic loader which
+ doesn't maintain __dld_list. We'll have to use a completely
+ different approach to get shared library information. */
+ if (addr == 0)
+ goto old_dld;
+
+ /* Using the information in __dld_list is the preferred method
+ to get at shared library information. It doesn't depend on
+ any functions in /opt/langtools/lib/end.o and has a chance of working
+ with hpux10 when it is released. */
+ status = target_read_memory (addr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to find dynamic library list.\n");
+ return;
+ }
+
+ /* addr now holds the address of the first entry in the dynamic
+ library list. */
+ addr = extract_unsigned_integer (buf, 4);
+
+ /* Now that we have a pointer to the dynamic library list, walk
+ through it and add the symbols for each library. */
+
+ so_list_tail = so_list_head;
+ /* Find the end of the list of shared objects. */
+ while (so_list_tail && so_list_tail->next)
+ so_list_tail = so_list_tail->next;
+
+#ifdef SOLIB_DEBUG
+ printf ("--About to read shared library list data\n");
+#endif
+
+ /* "addr" will always point to the base of the
+ * current data entry describing the current
+ * shared library.
+ */
+ while (1)
+ {
+ CORE_ADDR name_addr, text_addr;
+ unsigned int name_len;
+ char *name;
+ struct so_list *new_so;
+ struct so_list *so_list = so_list_head;
+ struct stat statbuf;
+ LONGEST st_size;
+ int is_main_program;
+
+ if (addr == 0)
+ break;
+
+ /* Get a pointer to the name of this library. */
+ status = target_read_memory (addr, buf, 4);
+ if (status != 0)
+ goto err;
+
+ name_addr = extract_unsigned_integer (buf, 4);
+ name_len = 0;
+ while (1)
+ {
+ target_read_memory (name_addr + name_len, buf, 1);
+ if (status != 0)
+ goto err;
+
+ name_len++;
+ if (*buf == '\0')
+ break;
+ }
+ name = alloca (name_len);
+ status = target_read_memory (name_addr, name, name_len);
+ if (status != 0)
+ goto err;
+
+ /* See if we've already loaded something with this name. */
+ while (so_list)
+ {
+ if (!strcmp (so_list->som_solib.name, name))
+ break;
+ so_list = so_list->next;
+ }
+
+ /* See if the file exists. If not, give a warning, but don't
+ die. */
+ status = stat (name, &statbuf);
+ if (status == -1)
+ {
+ warning ("Can't find file %s referenced in dld_list.", name);
+
+ status = target_read_memory (addr + 36, buf, 4);
+ if (status != 0)
+ goto err;
+
+ addr = (CORE_ADDR) extract_unsigned_integer (buf, 4);
+ continue;
+ }
+
+ /* If we've already loaded this one or it's the main program, skip it. */
+ is_main_program = (strcmp (name, symfile_objfile->name) == 0);
+ if (so_list || is_main_program)
+ {
+ /* This is the "next" pointer in the strcuture.
+ */
+ status = target_read_memory (addr + 36, buf, 4);
+ if (status != 0)
+ goto err;
+
+ addr = (CORE_ADDR) extract_unsigned_integer (buf, 4);
+
+ /* Record the main program's symbol table size. */
+ if (is_main_program && !so_list)
+ {
+ st_size = som_solib_sizeof_symbol_table (name);
+ som_solib_total_st_size += st_size;
+ }
+
+ /* Was this a shlib that we noted but didn't load the symbols for?
+ If so, were we invoked this time from the command-line, via
+ a 'sharedlibrary' or 'add-symbol-file' command? If yes to
+ both, we'd better load the symbols this time.
+ */
+ if (from_tty && so_list && !is_main_program && (so_list->objfile == NULL))
+ som_solib_load_symbols (so_list,
+ name,
+ from_tty,
+ so_list->som_solib.text_addr,
+ target);
+
+ continue;
+ }
+
+ name = obsavestring (name, name_len - 1,
+ &symfile_objfile->objfile_obstack);
+
+ status = target_read_memory (addr + 8, buf, 4);
+ if (status != 0)
+ goto err;
+
+ text_addr = extract_unsigned_integer (buf, 4);
+
+ new_so = (struct so_list *) xmalloc (sizeof (struct so_list));
+ memset ((char *) new_so, 0, sizeof (struct so_list));
+ if (so_list_head == NULL)
+ {
+ so_list_head = new_so;
+ so_list_tail = new_so;
+ }
+ else
+ {
+ so_list_tail->next = new_so;
+ so_list_tail = new_so;
+ }
+
+ /* Fill in all the entries in GDB's shared library list.
+ */
+
+ new_so->solib_addr = addr;
+ new_so->som_solib.name = name;
+ status = target_read_memory (addr + 4, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.struct_version = extract_unsigned_integer (buf + 3, 1);
+ new_so->som_solib.bind_mode = extract_unsigned_integer (buf + 2, 1);
+ /* Following is "high water mark", highest version number
+ * seen, rather than plain version number.
+ */
+ new_so->som_solib.library_version = extract_unsigned_integer (buf, 2);
+ new_so->som_solib.text_addr = text_addr;
+
+ /* Q: What about longword at "addr + 8"?
+ * A: It's read above, out of order, into "text_addr".
+ */
+
+ status = target_read_memory (addr + 12, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.text_link_addr = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 16, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.text_end = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 20, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.data_start = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 24, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.bss_start = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 28, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.data_end = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 32, buf, 4);
+ if (status != 0)
+ goto err;
+
+ new_so->som_solib.got_value = extract_unsigned_integer (buf, 4);
+
+ status = target_read_memory (addr + 36, buf, 4);
+ if (status != 0)
+ goto err;
+
+ /* FIXME: cagney/2003-02-01: I think som_solib.next should be a
+ CORE_ADDR. */
+ new_so->som_solib.next =
+ hpux_address_to_host_pointer_hack (extract_unsigned_integer (buf, 4));
+
+ /* Note that we don't re-set "addr" to the next pointer
+ * until after we've read the trailing data.
+ */
+
+ status = target_read_memory (addr + 40, buf, 4);
+ new_so->som_solib.tsd_start_addr = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ goto err;
+
+ /* Now indirect via that value!
+ */
+ status = target_read_memory (new_so->som_solib.tsd_start_addr, buf, 4);
+ new_so->som_solib.tsd_start_addr = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ goto err;
+#ifdef SOLIB_DEBUG
+ printf ("\n+ library \"%s\" is described at 0x%x\n", name, addr);
+ printf (" 'version' is %d\n", new_so->som_solib.struct_version);
+ printf (" 'bind_mode' is %d\n", new_so->som_solib.bind_mode);
+ printf (" 'library_version' is %d\n", new_so->som_solib.library_version);
+ printf (" 'text_addr' is 0x%x\n", new_so->som_solib.text_addr);
+ printf (" 'text_link_addr' is 0x%x\n", new_so->som_solib.text_link_addr);
+ printf (" 'text_end' is 0x%x\n", new_so->som_solib.text_end);
+ printf (" 'data_start' is 0x%x\n", new_so->som_solib.data_start);
+ printf (" 'bss_start' is 0x%x\n", new_so->som_solib.bss_start);
+ printf (" 'data_end' is 0x%x\n", new_so->som_solib.data_end);
+ printf (" 'got_value' is %x\n", new_so->som_solib.got_value);
+ printf (" 'next' is 0x%x\n", new_so->som_solib.next);
+ printf (" 'tsd_start_addr' is 0x%x\n", new_so->som_solib.tsd_start_addr);
+#endif
+
+ /* Go on to the next shared library descriptor.
+ */
+ addr = (CORE_ADDR) new_so->som_solib.next;
+
+
+
+ /* At this point, we have essentially hooked the shlib into the
+ "info share" command. However, we haven't yet loaded its
+ symbol table. We must now decide whether we ought to, i.e.,
+ whether doing so would exceed the symbol table size threshold.
+
+ If the threshold has just now been exceeded, then we'll issue
+ a warning message (which explains how to load symbols manually,
+ if the user so desires).
+
+ If the threshold has just now or previously been exceeded,
+ we'll just add the shlib to the list of object files, but won't
+ actually load its symbols. (This is more useful than it might
+ sound, for it allows us to e.g., still load and use the shlibs'
+ unwind information for stack tracebacks.)
+ */
+
+ /* Note that we DON'T want to preclude the user from using the
+ add-symbol-file command! Thus, we only worry about the threshold
+ when we're invoked for other reasons.
+ */
+ st_size = som_solib_sizeof_symbol_table (name);
+ som_solib_st_size_threshold_exceeded =
+ !from_tty &&
+ auto_solib_limit > 0 &&
+ readsyms &&
+ ((st_size + som_solib_total_st_size) > (auto_solib_limit * (LONGEST) (1024 * 1024)));
+
+ if (som_solib_st_size_threshold_exceeded)
+ {
+ if (!threshold_warning_given)
+ warning ("Symbols for some libraries have not been loaded, because\ndoing so would exceed the size threshold specified by auto-solib-limit.\nTo manually load symbols, use the 'sharedlibrary' command.\nTo raise the threshold, set auto-solib-limit to a larger value and rerun\nthe program.\n");
+ threshold_warning_given = 1;
+
+ /* We'll still make note of this shlib, even if we don't
+ read its symbols. This allows us to use its unwind
+ information well enough to know how to e.g., correctly
+ do a traceback from a PC within the shlib, even if we
+ can't symbolize those PCs...
+ */
+ som_solib_add_solib_objfile (new_so, name, from_tty, text_addr);
+ continue;
+ }
+
+ som_solib_total_st_size += st_size;
+
+ /* This fills in new_so->objfile, among others. */
+ som_solib_load_symbols (new_so, name, from_tty, text_addr, target);
+ }
+
+#ifdef SOLIB_DEBUG
+ printf ("--Done reading shared library data\n");
+#endif
+
+ /* Getting new symbols may change our opinion about what is
+ frameless. */
+ reinit_frame_cache ();
+ return;
+
+old_dld:
+ error ("Debugging dynamic executables loaded via the hpux8 dld.sl is not supported.\n");
+ return;
+
+err:
+ error ("Error while reading dynamic library list.\n");
+ return;
+}
+
+
+/* This hook gets called just before the first instruction in the
+ inferior process is executed.
+
+ This is our opportunity to set magic flags in the inferior so
+ that GDB can be notified when a shared library is mapped in and
+ to tell the dynamic linker that a private copy of the library is
+ needed (so GDB can set breakpoints in the library).
+
+ __dld_flags is the location of the magic flags; as of this implementation
+ there are 3 flags of interest:
+
+ bit 0 when set indicates that private copies of the libraries are needed
+ bit 1 when set indicates that the callback hook routine is valid
+ bit 2 when set indicates that the dynamic linker should maintain the
+ __dld_list structure when loading/unloading libraries.
+
+ Note that shared libraries are not mapped in at this time, so we have
+ run the inferior until the libraries are mapped in. Typically this
+ means running until the "_start" is called. */
+
+void
+som_solib_create_inferior_hook (void)
+{
+ struct minimal_symbol *msymbol;
+ unsigned int dld_flags, status, have_endo;
+ asection *shlib_info;
+ char buf[4];
+ struct objfile *objfile;
+ CORE_ADDR anaddr;
+
+ /* First, remove all the solib event breakpoints. Their addresses
+ may have changed since the last time we ran the program. */
+ remove_solib_event_breakpoints ();
+
+ if (symfile_objfile == NULL)
+ return;
+
+ /* First see if the objfile was dynamically linked. */
+ shlib_info = bfd_get_section_by_name (symfile_objfile->obfd, "$SHLIB_INFO$");
+ if (!shlib_info)
+ return;
+
+ /* It's got a $SHLIB_INFO$ section, make sure it's not empty. */
+ if (bfd_section_size (symfile_objfile->obfd, shlib_info) == 0)
+ return;
+
+ have_endo = 0;
+ /* Slam the pid of the process into __d_pid.
+
+ We used to warn when this failed, but that warning is only useful
+ on very old HP systems (hpux9 and older). The warnings are an
+ annoyance to users of modern systems and foul up the testsuite as
+ well. As a result, the warnings have been disabled. */
+ msymbol = lookup_minimal_symbol ("__d_pid", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ goto keep_going;
+
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ store_unsigned_integer (buf, 4, PIDGET (inferior_ptid));
+ status = target_write_memory (anaddr, buf, 4);
+ if (status != 0)
+ {
+ warning ("Unable to write __d_pid");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ goto keep_going;
+ }
+
+ /* Get the value of _DLD_HOOK (an export stub) and put it in __dld_hook;
+ This will force the dynamic linker to call __d_trap when significant
+ events occur.
+
+ Note that the above is the pre-HP-UX 9.0 behaviour. At 9.0 and above,
+ the dld provides an export stub named "__d_trap" as well as the
+ function named "__d_trap" itself, but doesn't provide "_DLD_HOOK".
+ We'll look first for the old flavor and then the new.
+ */
+ msymbol = lookup_minimal_symbol ("_DLD_HOOK", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ {
+ warning ("Unable to find _DLD_HOOK symbol in object file.");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ goto keep_going;
+ }
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ dld_cache.hook.address = anaddr;
+
+ /* Grrr, this might not be an export symbol! We have to find the
+ export stub. */
+ ALL_OBJFILES (objfile)
+ {
+ struct unwind_table_entry *u;
+ struct minimal_symbol *msymbol2;
+
+ /* What a crock. */
+ msymbol2 = lookup_minimal_symbol_solib_trampoline (DEPRECATED_SYMBOL_NAME (msymbol),
+ objfile);
+ /* Found a symbol with the right name. */
+ if (msymbol2)
+ {
+ struct unwind_table_entry *u;
+ /* It must be a shared library trampoline. */
+ if (SYMBOL_TYPE (msymbol2) != mst_solib_trampoline)
+ continue;
+
+ /* It must also be an export stub. */
+ u = find_unwind_entry (SYMBOL_VALUE (msymbol2));
+ if (!u || u->stub_unwind.stub_type != EXPORT)
+ continue;
+
+ /* OK. Looks like the correct import stub. */
+ anaddr = SYMBOL_VALUE (msymbol2);
+ dld_cache.hook_stub.address = anaddr;
+ }
+ }
+ store_unsigned_integer (buf, 4, anaddr);
+
+ msymbol = lookup_minimal_symbol ("__dld_hook", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ {
+ warning ("Unable to find __dld_hook symbol in object file.");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ goto keep_going;
+ }
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+ status = target_write_memory (anaddr, buf, 4);
+
+ /* Now set a shlib_event breakpoint at __d_trap so we can track
+ significant shared library events. */
+ msymbol = lookup_minimal_symbol ("__d_trap", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ {
+ warning ("Unable to find __dld_d_trap symbol in object file.");
+ warning ("Suggest linking with /opt/langtools/lib/end.o.");
+ warning ("GDB will be unable to track shl_load/shl_unload calls");
+ goto keep_going;
+ }
+ create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol));
+
+ /* We have all the support usually found in end.o, so we can track
+ shl_load and shl_unload calls. */
+ have_endo = 1;
+
+keep_going:
+
+ /* Get the address of __dld_flags, if no such symbol exists, then we can
+ not debug the shared code. */
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+ if (msymbol == NULL)
+ {
+ error ("Unable to find __dld_flags symbol in object file.\n");
+ }
+
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ /* Read the current contents. */
+ status = target_read_memory (anaddr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to read __dld_flags\n");
+ }
+ dld_flags = extract_unsigned_integer (buf, 4);
+
+ /* Turn on the flags we care about. */
+ dld_flags |= DLD_FLAGS_MAPPRIVATE;
+ if (have_endo)
+ dld_flags |= DLD_FLAGS_HOOKVALID;
+ store_unsigned_integer (buf, 4, dld_flags);
+ status = target_write_memory (anaddr, buf, 4);
+ if (status != 0)
+ {
+ error ("Unable to write __dld_flags\n");
+ }
+
+ /* Now find the address of _start and set a breakpoint there.
+ We still need this code for two reasons:
+
+ * Not all sites have /opt/langtools/lib/end.o, so it's not always
+ possible to track the dynamic linker's events.
+
+ * At this time no events are triggered for shared libraries
+ loaded at startup time (what a crock). */
+
+ msymbol = lookup_minimal_symbol ("_start", NULL, symfile_objfile);
+ if (msymbol == NULL)
+ {
+ error ("Unable to find _start symbol in object file.\n");
+ }
+
+ anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ /* Make the breakpoint at "_start" a shared library event breakpoint. */
+ create_solib_event_breakpoint (anaddr);
+
+ /* Wipe out all knowledge of old shared libraries since their
+ mapping can change from one exec to another! */
+ while (so_list_head)
+ {
+ struct so_list *temp;
+
+ temp = so_list_head;
+ xfree (so_list_head);
+ so_list_head = temp->next;
+ }
+ clear_symtab_users ();
+}
+
+/* This operation removes the "hook" between GDB and the dynamic linker,
+ which causes the dld to notify GDB of shared library events.
+
+ After this operation completes, the dld will no longer notify GDB of
+ shared library events. To resume notifications, GDB must call
+ som_solib_create_inferior_hook.
+
+ This operation does not remove any knowledge of shared libraries which
+ GDB may already have been notified of.
+ */
+void
+som_solib_remove_inferior_hook (int pid)
+{
+ CORE_ADDR addr;
+ struct minimal_symbol *msymbol;
+ int status;
+ char dld_flags_buffer[4];
+ unsigned int dld_flags_value;
+ struct cleanup *old_cleanups = save_inferior_ptid ();
+
+ /* Ensure that we're really operating on the specified process. */
+ inferior_ptid = pid_to_ptid (pid);
+
+ /* We won't bother to remove the solib breakpoints from this process.
+
+ In fact, on PA64 the breakpoint is hard-coded into the dld callback,
+ and thus we're not supposed to remove it.
+
+ Rather, we'll merely clear the dld_flags bit that enables callbacks.
+ */
+ msymbol = lookup_minimal_symbol ("__dld_flags", NULL, NULL);
+
+ addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ status = target_read_memory (addr, dld_flags_buffer, 4);
+
+ dld_flags_value = extract_unsigned_integer (dld_flags_buffer, 4);
+
+ dld_flags_value &= ~DLD_FLAGS_HOOKVALID;
+ store_unsigned_integer (dld_flags_buffer, 4, dld_flags_value);
+ status = target_write_memory (addr, dld_flags_buffer, 4);
+
+ do_cleanups (old_cleanups);
+}
+
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_load call is made.
+
+ If filename is NULL, then loads of any dll will be caught. Else,
+ only loads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_load_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_load_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+/* This function creates a breakpoint on the dynamic linker hook, which
+ is called when e.g., a shl_load or shl_unload call is made. This
+ breakpoint will only trigger when a shl_unload call is made.
+
+ If filename is NULL, then unloads of any dll will be caught. Else,
+ only unloads of the file whose pathname is the string contained by
+ filename will be caught.
+
+ Undefined behaviour is guaranteed if this function is called before
+ som_solib_create_inferior_hook.
+ */
+void
+som_solib_create_catch_unload_hook (int pid, int tempflag, char *filename,
+ char *cond_string)
+{
+ create_solib_unload_event_breakpoint ("__d_trap", tempflag, filename, cond_string);
+}
+
+int
+som_solib_have_load_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_LOAD);
+}
+
+int
+som_solib_have_unload_event (int pid)
+{
+ CORE_ADDR event_kind;
+
+ event_kind = read_register (ARG0_REGNUM);
+ return (event_kind == SHL_UNLOAD);
+}
+
+static char *
+som_solib_library_pathname (int pid)
+{
+ CORE_ADDR dll_handle_address;
+ CORE_ADDR dll_pathname_address;
+ struct som_solib_mapped_entry dll_descriptor;
+ char *p;
+ static char dll_pathname[1024];
+
+ /* Read the descriptor of this newly-loaded library. */
+ dll_handle_address = read_register (ARG1_REGNUM);
+ read_memory (dll_handle_address, (char *) &dll_descriptor, sizeof (dll_descriptor));
+
+ /* We can find a pointer to the dll's pathname within the descriptor. */
+ dll_pathname_address = (CORE_ADDR) dll_descriptor.name;
+
+ /* Read the pathname, one byte at a time. */
+ p = dll_pathname;
+ for (;;)
+ {
+ char b;
+ read_memory (dll_pathname_address++, (char *) &b, 1);
+ *p++ = b;
+ if (b == '\0')
+ break;
+ }
+
+ return dll_pathname;
+}
+
+char *
+som_solib_loaded_library_pathname (int pid)
+{
+ if (!som_solib_have_load_event (pid))
+ error ("Must have a load event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+char *
+som_solib_unloaded_library_pathname (int pid)
+{
+ if (!som_solib_have_unload_event (pid))
+ error ("Must have an unload event to use this query");
+
+ return som_solib_library_pathname (pid);
+}
+
+static void
+som_solib_desire_dynamic_linker_symbols (void)
+{
+ struct objfile *objfile;
+ struct unwind_table_entry *u;
+ struct minimal_symbol *dld_msymbol;
+
+ /* Do we already know the value of these symbols? If so, then
+ we've no work to do.
+
+ (If you add clauses to this test, be sure to likewise update the
+ test within the loop.)
+ */
+ if (dld_cache.is_valid)
+ return;
+
+ ALL_OBJFILES (objfile)
+ {
+ dld_msymbol = lookup_minimal_symbol ("shl_load", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.load.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load.unwind = find_unwind_entry (dld_cache.load.address);
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_load",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.load_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.load_stub.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol ("shl_unload", NULL, objfile);
+ if (dld_msymbol != NULL)
+ {
+ dld_cache.unload.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload.unwind = find_unwind_entry (dld_cache.unload.address);
+
+ /* ??rehrauer: I'm not sure exactly what this is, but it appears
+ that on some HPUX 10.x versions, there's two unwind regions to
+ cover the body of "shl_unload", the second being 4 bytes past
+ the end of the first. This is a large hack to handle that
+ case, but since I don't seem to have any legitimate way to
+ look for this thing via the symbol table...
+ */
+ if (dld_cache.unload.unwind != NULL)
+ {
+ u = find_unwind_entry (dld_cache.unload.unwind->region_end + 4);
+ if (u != NULL)
+ {
+ dld_cache.unload2.address = u->region_start;
+ dld_cache.unload2.unwind = u;
+ }
+ }
+ }
+
+ dld_msymbol = lookup_minimal_symbol_solib_trampoline ("shl_unload",
+ objfile);
+ if (dld_msymbol != NULL)
+ {
+ if (SYMBOL_TYPE (dld_msymbol) == mst_solib_trampoline)
+ {
+ u = find_unwind_entry (SYMBOL_VALUE (dld_msymbol));
+ if ((u != NULL) && (u->stub_unwind.stub_type == EXPORT))
+ {
+ dld_cache.unload_stub.address = SYMBOL_VALUE (dld_msymbol);
+ dld_cache.unload_stub.unwind = u;
+ }
+ }
+ }
+
+ /* Did we find everything we were looking for? If so, stop. */
+ if ((dld_cache.load.address != 0)
+ && (dld_cache.load_stub.address != 0)
+ && (dld_cache.unload.address != 0)
+ && (dld_cache.unload_stub.address != 0))
+ {
+ dld_cache.is_valid = 1;
+ break;
+ }
+ }
+
+ dld_cache.hook.unwind = find_unwind_entry (dld_cache.hook.address);
+ dld_cache.hook_stub.unwind = find_unwind_entry (dld_cache.hook_stub.address);
+
+ /* We're prepared not to find some of these symbols, which is why
+ this function is a "desire" operation, and not a "require".
+ */
+}
+
+int
+som_solib_in_dynamic_linker (int pid, CORE_ADDR pc)
+{
+ struct unwind_table_entry *u_pc;
+
+ /* Are we in the dld itself?
+
+ ??rehrauer: Large hack -- We'll assume that any address in a
+ shared text region is the dld's text. This would obviously
+ fall down if the user attached to a process, whose shlibs
+ weren't mapped to a (writeable) private region. However, in
+ that case the debugger probably isn't able to set the fundamental
+ breakpoint in the dld callback anyways, so this hack should be
+ safe.
+ */
+ if ((pc & (CORE_ADDR) 0xc0000000) == (CORE_ADDR) 0xc0000000)
+ return 1;
+
+ /* Cache the address of some symbols that are part of the dynamic
+ linker, if not already known.
+ */
+ som_solib_desire_dynamic_linker_symbols ();
+
+ /* Are we in the dld callback? Or its export stub? */
+ u_pc = find_unwind_entry (pc);
+ if (u_pc == NULL)
+ return 0;
+
+ if ((u_pc == dld_cache.hook.unwind) || (u_pc == dld_cache.hook_stub.unwind))
+ return 1;
+
+ /* Or the interface of the dld (i.e., "shl_load" or friends)? */
+ if ((u_pc == dld_cache.load.unwind)
+ || (u_pc == dld_cache.unload.unwind)
+ || (u_pc == dld_cache.unload2.unwind)
+ || (u_pc == dld_cache.load_stub.unwind)
+ || (u_pc == dld_cache.unload_stub.unwind))
+ return 1;
+
+ /* Apparently this address isn't part of the dld's text. */
+ return 0;
+}
+
+
+/* Return the GOT value for the shared library in which ADDR belongs. If
+ ADDR isn't in any known shared library, return zero. */
+
+CORE_ADDR
+som_solib_get_got_by_pc (CORE_ADDR addr)
+{
+ struct so_list *so_list = so_list_head;
+ CORE_ADDR got_value = 0;
+
+ while (so_list)
+ {
+ if (so_list->som_solib.text_addr <= addr
+ && so_list->som_solib.text_end > addr)
+ {
+ got_value = so_list->som_solib.got_value;
+ break;
+ }
+ so_list = so_list->next;
+ }
+ return got_value;
+}
+
+/* elz:
+ Return the address of the handle of the shared library
+ in which ADDR belongs. If
+ ADDR isn't in any known shared library, return zero. */
+/* this function is used in hppa_fix_call_dummy in hppa-tdep.c */
+
+CORE_ADDR
+som_solib_get_solib_by_pc (CORE_ADDR addr)
+{
+ struct so_list *so_list = so_list_head;
+
+ while (so_list)
+ {
+ if (so_list->som_solib.text_addr <= addr
+ && so_list->som_solib.text_end > addr)
+ {
+ break;
+ }
+ so_list = so_list->next;
+ }
+ if (so_list)
+ return so_list->solib_addr;
+ else
+ return 0;
+}
+
+
+int
+som_solib_section_offsets (struct objfile *objfile,
+ struct section_offsets *offsets)
+{
+ struct so_list *so_list = so_list_head;
+
+ while (so_list)
+ {
+ /* Oh what a pain! We need the offsets before so_list->objfile
+ is valid. The BFDs will never match. Make a best guess. */
+ if (strstr (objfile->name, so_list->som_solib.name))
+ {
+ asection *private_section;
+
+ /* The text offset is easy. */
+ offsets->offsets[SECT_OFF_TEXT (objfile)]
+ = (so_list->som_solib.text_addr
+ - so_list->som_solib.text_link_addr);
+ offsets->offsets[SECT_OFF_RODATA (objfile)]
+ = ANOFFSET (offsets, SECT_OFF_TEXT (objfile));
+
+ /* We should look at presumed_dp in the SOM header, but
+ that's not easily available. This should be OK though. */
+ private_section = bfd_get_section_by_name (objfile->obfd,
+ "$PRIVATE$");
+ if (!private_section)
+ {
+ warning ("Unable to find $PRIVATE$ in shared library!");
+ offsets->offsets[SECT_OFF_DATA (objfile)] = 0;
+ offsets->offsets[SECT_OFF_BSS (objfile)] = 0;
+ return 1;
+ }
+ offsets->offsets[SECT_OFF_DATA (objfile)]
+ = (so_list->som_solib.data_start - private_section->vma);
+ offsets->offsets[SECT_OFF_BSS (objfile)]
+ = ANOFFSET (offsets, SECT_OFF_DATA (objfile));
+ return 1;
+ }
+ so_list = so_list->next;
+ }
+ return 0;
+}
+
+/* Dump information about all the currently loaded shared libraries. */
+
+static void
+som_sharedlibrary_info_command (char *ignore, int from_tty)
+{
+ struct so_list *so_list = so_list_head;
+
+ if (exec_bfd == NULL)
+ {
+ printf_unfiltered ("No executable file.\n");
+ return;
+ }
+
+ if (so_list == NULL)
+ {
+ printf_unfiltered ("No shared libraries loaded at this time.\n");
+ return;
+ }
+
+ printf_unfiltered ("Shared Object Libraries\n");
+ printf_unfiltered (" %-12s%-12s%-12s%-12s%-12s%-12s\n",
+ " flags", " tstart", " tend", " dstart", " dend", " dlt");
+ while (so_list)
+ {
+ unsigned int flags;
+
+ flags = so_list->som_solib.struct_version << 24;
+ flags |= so_list->som_solib.bind_mode << 16;
+ flags |= so_list->som_solib.library_version;
+ printf_unfiltered ("%s", so_list->som_solib.name);
+ if (so_list->objfile == NULL)
+ printf_unfiltered (" (symbols not loaded)");
+ printf_unfiltered ("\n");
+ printf_unfiltered (" %-12s", local_hex_string_custom (flags, "08l"));
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom (so_list->som_solib.text_addr, "08l"));
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom (so_list->som_solib.text_end, "08l"));
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom (so_list->som_solib.data_start, "08l"));
+ printf_unfiltered ("%-12s",
+ local_hex_string_custom (so_list->som_solib.data_end, "08l"));
+ printf_unfiltered ("%-12s\n",
+ local_hex_string_custom (so_list->som_solib.got_value, "08l"));
+ so_list = so_list->next;
+ }
+}
+
+static void
+som_solib_sharedlibrary_command (char *args, int from_tty)
+{
+ dont_repeat ();
+ som_solib_add (args, from_tty, (struct target_ops *) 0, 1);
+}
+
+
+
+char *
+som_solib_address (CORE_ADDR addr)
+{
+ struct so_list *so = so_list_head;
+
+ while (so)
+ {
+ /* Is this address within this shlib's text range? If so,
+ return the shlib's name.
+ */
+ if ((addr >= so->som_solib.text_addr) && (addr <= so->som_solib.text_end))
+ return so->som_solib.name;
+
+ /* Nope, keep looking... */
+ so = so->next;
+ }
+
+ /* No, we couldn't prove that the address is within a shlib. */
+ return NULL;
+}
+
+
+void
+som_solib_restart (void)
+{
+ struct so_list *sl = so_list_head;
+
+ /* Before the shlib info vanishes, use it to disable any breakpoints
+ that may still be active in those shlibs.
+ */
+ disable_breakpoints_in_shlibs (0);
+
+ /* Discard all the shlib descriptors.
+ */
+ while (sl)
+ {
+ struct so_list *next_sl = sl->next;
+ xfree (sl);
+ sl = next_sl;
+ }
+ so_list_head = NULL;
+
+ som_solib_total_st_size = (LONGEST) 0;
+ som_solib_st_size_threshold_exceeded = 0;
+
+ dld_cache.is_valid = 0;
+
+ dld_cache.hook.address = 0;
+ dld_cache.hook.unwind = NULL;
+
+ dld_cache.hook_stub.address = 0;
+ dld_cache.hook_stub.unwind = NULL;
+
+ dld_cache.load.address = 0;
+ dld_cache.load.unwind = NULL;
+
+ dld_cache.load_stub.address = 0;
+ dld_cache.load_stub.unwind = NULL;
+
+ dld_cache.unload.address = 0;
+ dld_cache.unload.unwind = NULL;
+
+ dld_cache.unload2.address = 0;
+ dld_cache.unload2.unwind = NULL;
+
+ dld_cache.unload_stub.address = 0;
+ dld_cache.unload_stub.unwind = NULL;
+}
+
+
+/* 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_som_solib (void)
+{
+ add_com ("sharedlibrary", class_files, som_solib_sharedlibrary_command,
+ "Load shared object library symbols for files matching REGEXP.");
+ add_info ("sharedlibrary", som_sharedlibrary_info_command,
+ "Status of loaded shared object libraries.");
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-add", class_support, var_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);
+
+ add_show_from_set
+ (add_set_cmd ("auto-solib-limit", class_support, var_zinteger,
+ (char *) &auto_solib_limit,
+ "Set threshold (in Mb) for autoloading shared library symbols.\n\
+When shared library autoloading is enabled, new libraries will be loaded\n\
+only until the total size of shared library symbols exceeds this\n\
+threshold in megabytes. Is ignored when using `sharedlibrary'.",
+ &setlist),
+ &showlist);
+
+ /* ??rehrauer: On HP-UX, the kernel parameter MAXDSIZ limits how
+ much data space a process can use. We ought to be reading
+ MAXDSIZ and setting auto_solib_limit to some large fraction of
+ that value. If not that, we maybe ought to be setting it smaller
+ than the default for MAXDSIZ (that being 64Mb, I believe).
+ However, [1] this threshold is only crudely approximated rather
+ than actually measured, and [2] 50 Mbytes is too small for
+ debugging gdb itself. Thus, the arbitrary 100 figure. */
+ auto_solib_limit = 100; /* Megabytes */
+
+ som_solib_restart ();
+}
+
+/* Get some HPUX-specific data from a shared lib.
+ */
+CORE_ADDR
+so_lib_thread_start_addr (struct so_list *so)
+{
+ return so->som_solib.tsd_start_addr;
+}
diff --git a/contrib/gdb/gdb/somsolib.h b/contrib/gdb/gdb/somsolib.h
new file mode 100644
index 0000000..c241411
--- /dev/null
+++ b/contrib/gdb/gdb/somsolib.h
@@ -0,0 +1,178 @@
+/* HP SOM Shared library declarations for GDB, the GNU Debugger.
+
+ Copyright 1992, 1994, 1995, 1998, 1999, 2000, 2003 Free Software
+ Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Written by the Center for Software Science at the Univerity of Utah
+ and by Cygnus Support. */
+
+#ifndef SOMSOLIB_H
+#define SOMSOLIB_H
+
+/* Forward decl's for prototypes */
+struct target_ops;
+struct objfile;
+struct section_offsets;
+
+/* Called to add symbols from a shared library to gdb's symbol table. */
+
+#define SOLIB_ADD(filename, from_tty, targ, readsyms) \
+ som_solib_add (filename, from_tty, targ, readsyms)
+
+extern void som_solib_add (char *, int, struct target_ops *, int);
+
+extern CORE_ADDR som_solib_get_got_by_pc (CORE_ADDR);
+
+extern int som_solib_section_offsets (struct objfile *,
+ struct section_offsets *);
+
+/* Function to be called when the inferior starts up, to discover the names
+ of shared libraries that are dynamically linked, the base addresses to
+ which they are linked, and sufficient information to read in their symbols
+ at a later time. */
+
+#define SOLIB_CREATE_INFERIOR_HOOK(PID) som_solib_create_inferior_hook()
+
+extern void som_solib_create_inferior_hook (void);
+
+/* 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.)
+ */
+#define SOLIB_REMOVE_INFERIOR_HOOK(PID) som_solib_remove_inferior_hook(PID)
+
+extern void som_solib_remove_inferior_hook (int);
+
+/* 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.
+ */
+#define SOLIB_CREATE_CATCH_LOAD_HOOK(pid,tempflag, filename,cond_string) \
+ som_solib_create_catch_load_hook (pid, tempflag, filename, cond_string)
+
+extern void som_solib_create_catch_load_hook (int, int, char *, char *);
+
+/* 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.
+ */
+#define SOLIB_CREATE_CATCH_UNLOAD_HOOK(pid,tempflag,filename, cond_string) \
+ som_solib_create_catch_unload_hook (pid, tempflag, filename, cond_string)
+
+extern void som_solib_create_catch_unload_hook (int, int, char *, char *);
+
+/* 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.
+ */
+#define SOLIB_HAVE_LOAD_EVENT(pid) \
+ som_solib_have_load_event (pid)
+
+extern int som_solib_have_load_event (int);
+
+/* 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.
+ */
+#define SOLIB_LOADED_LIBRARY_PATHNAME(pid) \
+ som_solib_loaded_library_pathname (pid)
+
+extern char *som_solib_loaded_library_pathname (int);
+
+/* 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.
+ */
+#define SOLIB_HAVE_UNLOAD_EVENT(pid) \
+ som_solib_have_unload_event (pid)
+
+extern int som_solib_have_unload_event (int);
+
+/* 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.
+ */
+#define SOLIB_UNLOADED_LIBRARY_PATHNAME(pid) \
+ som_solib_unloaded_library_pathname (pid)
+
+extern char *som_solib_unloaded_library_pathname (int);
+
+/* 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.
+ */
+#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) \
+ som_solib_in_dynamic_linker (pid, pc)
+
+extern int som_solib_in_dynamic_linker (int, CORE_ADDR);
+
+/* 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() \
+ som_solib_restart ()
+
+extern void som_solib_restart (void);
+
+/* If we can't set a breakpoint, and it's in a shared library, just
+ disable it. */
+
+#define DISABLE_UNSETTABLE_BREAK(addr) (som_solib_address(addr) != NULL)
+
+extern char *som_solib_address (CORE_ADDR); /* somsolib.c */
+
+/* If ADDR lies in a shared library, return its name. */
+
+#define PC_SOLIB(addr) som_solib_address (addr)
+
+extern CORE_ADDR som_solib_get_solib_by_pc (CORE_ADDR addr);
+
+struct so_list;
+extern CORE_ADDR so_lib_thread_start_addr (struct so_list *so);
+
+extern void no_shared_libraries (char *ignored, int from_tty);
+
+#endif
diff --git a/contrib/gdb/gdb/srec.h b/contrib/gdb/gdb/srec.h
new file mode 100644
index 0000000..8189a9b
--- /dev/null
+++ b/contrib/gdb/gdb/srec.h
@@ -0,0 +1,39 @@
+/* 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. */
+
+struct serial;
+
+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
new file mode 100644
index 0000000..906e37a
--- /dev/null
+++ b/contrib/gdb/gdb/standalone.c
@@ -0,0 +1,580 @@
+/* Interface to bare machine for GDB running as kernel debugger.
+
+ Copyright 1986, 1989, 1991, 1992, 1993, 1995, 1996, 2000, 2001,
+ 2003 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)
+{
+ 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)
+{
+ int elts = min (numelts, sourceleft / eltsize);
+ 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 (char *buf, int numelts, int size, int stream)
+{
+ 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)
+{
+ 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/stop-gdb.c b/contrib/gdb/gdb/stop-gdb.c
new file mode 100644
index 0000000..ee84609
--- /dev/null
+++ b/contrib/gdb/gdb/stop-gdb.c
@@ -0,0 +1,109 @@
+/* A client to make GDB return to command level in Mach 3.
+ Copyright 1992, 1993, 1994, 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. */
+
+/* Authors: Jukka Virtanen <jtv@hut.fi> and Peter Stout <pds@cs.cmu.edu>.
+
+ A simple client to make GDB (versions 4.4 and later) on Mach 3 return
+ to the command level when it is waiting for the inferior to stop.
+
+ Actions: Lookup the send right to the GDB message port from the
+ NetMsgServer.
+
+ Send an asynchronous message with msgh_id
+ GDB_MESSAGE_ID_STOP to that port.
+ */
+
+#include <stdio.h>
+
+#include "defs.h"
+
+#include <mach.h>
+#include <mach/message.h>
+#include <mach_error.h>
+#include <servers/netname.h>
+#include <servers/netname_defs.h>
+
+void
+main (int argc, char **argv)
+{
+ kern_return_t kr;
+ mach_msg_header_t msg;
+ mach_port_t gdb_port;
+ char *host;
+ char *name;
+
+ if (argc == 1)
+ argv[argc++] = GDB_DEF_NAME;
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage : %s <GDB name>\n", argv[0]);
+ exit (1);
+ }
+
+ /* Allow the user to specify a remote host. */
+ host = strchr (argv[1], '@');
+ if (host)
+ *(host++) = '\0';
+ else
+ host = (char *) "";
+
+ name = malloc (strlen (argv[1]) + sizeof (GDB_NAME_PREFIX));
+ if (name == NULL)
+ {
+ fprintf (stderr, "Unable to allocate memory for name.");
+ exit (1);
+ }
+
+ strcpy (name, GDB_NAME_PREFIX);
+ strcat (name, argv[1]);
+
+ /* Look up the GDB service port. For convenience, add the
+ GDB_NAME_PREFIX the argument before looking up the name.
+ For backwards compatibility, do it without. */
+
+ kr = netname_look_up (name_server_port, host, name, &gdb_port);
+ if (kr == NETNAME_NOT_CHECKED_IN)
+ kr = netname_look_up (name_server_port, host, argv[1], &gdb_port);
+ if (kr != KERN_SUCCESS)
+ {
+ fprintf (stderr, "Unable to lookup the GDB service port: %s.\n",
+ mach_error_string (kr));
+ exit (1);
+ }
+
+ /* Code generated by mig stub generator, with minor cleanups :-)
+
+ simpleroutine stop_inferior(gdb_port : mach_port_t); */
+
+ msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+ msg.msgh_remote_port = gdb_port;
+ msg.msgh_local_port = MACH_PORT_NULL;
+ msg.msgh_size = sizeof (msg);
+ msg.msgh_seqno = 0;
+ msg.msgh_id = GDB_MESSAGE_ID_STOP;
+
+ kr = mach_msg_send (&msg);
+ if (kr != KERN_SUCCESS)
+ fprintf (stderr, "Message not sent, return code %d : %s\n", kr,
+ mach_error_string (kr));
+
+ exit (kr != KERN_SUCCESS);
+}
diff --git a/contrib/gdb/gdb/tui/tui.c b/contrib/gdb/gdb/tui/tui.c
new file mode 100644
index 0000000..d6f344f
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui.c
@@ -0,0 +1,590 @@
+/* General functions for the WDB TUI.
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "tui/tui.h"
+#include "tui/tui-hooks.h"
+#include "tui/tui-data.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-io.h"
+#include "tui/tui-regs.h"
+#include "tui/tui-stack.h"
+#include "tui/tui-win.h"
+#include "tui/tui-winsource.h"
+#include "tui/tui-windata.h"
+#include "target.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "source.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#if 0
+#include <termio.h>
+#endif
+#include <setjmp.h>
+
+#include "gdb_curses.h"
+
+/* This redefines CTRL if it is not already defined, so it must come
+ after terminal state releated include files like <term.h> and
+ "gdb_ncurses.h". */
+#include "readline/readline.h"
+
+/* Tells whether the TUI is active or not. */
+int tui_active = 0;
+static int tui_finish_init = 1;
+
+enum tui_key_mode tui_current_key_mode = TUI_COMMAND_MODE;
+
+struct tui_char_command
+{
+ unsigned char key;
+ const char* cmd;
+};
+
+/* Key mapping to gdb commands when the TUI is using the single key mode. */
+static const struct tui_char_command tui_commands[] = {
+ { 'c', "continue" },
+ { 'd', "down" },
+ { 'f', "finish" },
+ { 'n', "next" },
+ { 'r', "run" },
+ { 's', "step" },
+ { 'u', "up" },
+ { 'v', "info locals" },
+ { 'w', "where" },
+ { 0, 0 },
+};
+
+static Keymap tui_keymap;
+static Keymap tui_readline_standard_keymap;
+
+/* TUI readline command.
+ Switch the output mode between TUI/standard gdb. */
+static int
+tui_rl_switch_mode (int notused1, int notused2)
+{
+ if (tui_active)
+ {
+ tui_disable ();
+ rl_prep_terminal (0);
+ }
+ else
+ {
+ rl_deprep_terminal ();
+ tui_enable ();
+ }
+
+ /* Clear the readline in case switching occurred in middle of something. */
+ if (rl_end)
+ rl_kill_text (0, rl_end);
+
+ /* Since we left the curses mode, the terminal mode is restored to
+ some previous state. That state may not be suitable for readline
+ to work correctly (it may be restored in line mode). We force an
+ exit of the current readline so that readline is re-entered and it
+ will be able to setup the terminal for its needs. By re-entering
+ in readline, we also redisplay its prompt in the non-curses mode. */
+ rl_newline (1, '\n');
+
+ /* Make sure the \n we are returning does not repeat the last command. */
+ dont_repeat ();
+ return 0;
+}
+
+/* TUI readline command.
+ Change the TUI layout to show a next layout.
+ This function is bound to CTRL-X 2. It is intended to provide
+ a functionality close to the Emacs split-window command. We always
+ show two windows (src+asm), (src+regs) or (asm+regs). */
+static int
+tui_rl_change_windows (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ if (tui_active)
+ {
+ enum tui_layout_type new_layout;
+ enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
+
+ new_layout = tui_current_layout ();
+
+ /* Select a new layout to have a rolling layout behavior
+ with always two windows (except when undefined). */
+ switch (new_layout)
+ {
+ case SRC_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case DISASSEM_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case SRC_DATA_COMMAND:
+ new_layout = SRC_DISASSEM_COMMAND;
+ break;
+
+ case SRC_DISASSEM_COMMAND:
+ new_layout = DISASSEM_DATA_COMMAND;
+ break;
+
+ case DISASSEM_DATA_COMMAND:
+ new_layout = SRC_DATA_COMMAND;
+ break;
+
+ default:
+ new_layout = SRC_COMMAND;
+ break;
+ }
+ tui_set_layout (new_layout, regs_type);
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Delete the second TUI window to only show one. */
+static int
+tui_rl_delete_other_windows (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ if (tui_active)
+ {
+ enum tui_layout_type new_layout;
+ enum tui_register_display_type regs_type = TUI_UNDEFINED_REGS;
+
+ new_layout = tui_current_layout ();
+
+ /* Kill one window. */
+ switch (new_layout)
+ {
+ case SRC_COMMAND:
+ case SRC_DATA_COMMAND:
+ case SRC_DISASSEM_COMMAND:
+ default:
+ new_layout = SRC_COMMAND;
+ break;
+
+ case DISASSEM_COMMAND:
+ case DISASSEM_DATA_COMMAND:
+ new_layout = DISASSEM_COMMAND;
+ break;
+ }
+ tui_set_layout (new_layout, regs_type);
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Switch the active window to give the focus to a next window. */
+static int
+tui_rl_other_window (int count, int key)
+{
+ struct tui_win_info * win_info;
+
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ win_info = tui_next_win (tui_win_with_focus ());
+ if (win_info)
+ {
+ tui_set_win_focus_to (win_info);
+ if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
+ tui_refresh_data_win ();
+ keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Execute the gdb command bound to the specified key. */
+static int
+tui_rl_command_key (int count, int key)
+{
+ int i;
+
+ reinitialize_more_filter ();
+ for (i = 0; tui_commands[i].cmd; i++)
+ {
+ if (tui_commands[i].key == key)
+ {
+ /* Must save the command because it can be modified
+ by execute_command. */
+ char* cmd = alloca (strlen (tui_commands[i].cmd) + 1);
+ strcpy (cmd, tui_commands[i].cmd);
+ execute_command (cmd, TRUE);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* TUI readline command.
+ Temporarily leave the TUI SingleKey mode to allow editing
+ a gdb command with the normal readline. Once the command
+ is executed, the TUI SingleKey mode is installed back. */
+static int
+tui_rl_command_mode (int count, int key)
+{
+ tui_set_key_mode (TUI_ONE_COMMAND_MODE);
+ return rl_insert (count, key);
+}
+
+/* TUI readline command.
+ Switch between TUI SingleKey mode and gdb readline editing. */
+static int
+tui_rl_next_keymap (int notused1, int notused2)
+{
+ if (!tui_active)
+ tui_rl_switch_mode (0/*notused*/, 0/*notused*/);
+
+ tui_set_key_mode (tui_current_key_mode == TUI_COMMAND_MODE
+ ? TUI_SINGLE_KEY_MODE : TUI_COMMAND_MODE);
+ return 0;
+}
+
+/* Readline hook to redisplay ourself the gdb prompt.
+ In the SingleKey mode, the prompt is not printed so that
+ the command window is cleaner. It will be displayed if
+ we temporarily leave the SingleKey mode. */
+static int
+tui_rl_startup_hook (void)
+{
+ rl_already_prompted = 1;
+ if (tui_current_key_mode != TUI_COMMAND_MODE)
+ tui_set_key_mode (TUI_SINGLE_KEY_MODE);
+ tui_redisplay_readline ();
+ return 0;
+}
+
+/* Change the TUI key mode by installing the appropriate readline keymap. */
+void
+tui_set_key_mode (enum tui_key_mode mode)
+{
+ tui_current_key_mode = mode;
+ rl_set_keymap (mode == TUI_SINGLE_KEY_MODE
+ ? tui_keymap : tui_readline_standard_keymap);
+ tui_show_locator_content ();
+}
+
+/* Initialize readline and configure the keymap for the switching
+ key shortcut. */
+void
+tui_initialize_readline (void)
+{
+ int i;
+ Keymap tui_ctlx_keymap;
+
+ rl_initialize ();
+
+ rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1);
+ rl_add_defun ("gdb-command", tui_rl_command_key, -1);
+ rl_add_defun ("next-keymap", tui_rl_next_keymap, -1);
+
+ tui_keymap = rl_make_bare_keymap ();
+ tui_ctlx_keymap = rl_make_bare_keymap ();
+ tui_readline_standard_keymap = rl_get_keymap ();
+
+ for (i = 0; tui_commands[i].cmd; i++)
+ rl_bind_key_in_map (tui_commands[i].key, tui_rl_command_key, tui_keymap);
+
+ rl_generic_bind (ISKMAP, "\\C-x", (char*) tui_ctlx_keymap, tui_keymap);
+
+ /* Bind all other keys to tui_rl_command_mode so that we switch
+ temporarily from SingleKey mode and can enter a gdb command. */
+ for (i = ' '; i < 0x7f; i++)
+ {
+ int j;
+
+ for (j = 0; tui_commands[j].cmd; j++)
+ if (tui_commands[j].key == i)
+ break;
+
+ if (tui_commands[j].cmd)
+ continue;
+
+ rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap);
+ }
+
+ rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, emacs_ctlx_keymap);
+ rl_bind_key_in_map (CTRL ('A'), tui_rl_switch_mode, tui_ctlx_keymap);
+ rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap);
+ rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap);
+ rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap);
+ rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap);
+ rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap);
+ rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap);
+}
+
+/* Enter in the tui mode (curses).
+ When in normal mode, it installs the tui hooks in gdb, redirects
+ the gdb output, configures the readline to work in tui mode.
+ When in curses mode, it does nothing. */
+void
+tui_enable (void)
+{
+ if (tui_active)
+ return;
+
+ /* To avoid to initialize curses when gdb starts, there is a defered
+ curses initialization. This initialization is made only once
+ and the first time the curses mode is entered. */
+ if (tui_finish_init)
+ {
+ WINDOW *w;
+
+ w = initscr ();
+
+ cbreak ();
+ noecho ();
+ /*timeout (1);*/
+ nodelay(w, FALSE);
+ nl();
+ keypad (w, TRUE);
+ rl_initialize ();
+ tui_set_term_height_to (LINES);
+ tui_set_term_width_to (COLS);
+ def_prog_mode ();
+
+ tui_show_frame_info (0);
+ tui_set_layout (SRC_COMMAND, TUI_UNDEFINED_REGS);
+ tui_set_win_focus_to (TUI_SRC_WIN);
+ keypad (TUI_CMD_WIN->generic.handle, TRUE);
+ wrefresh (TUI_CMD_WIN->generic.handle);
+ tui_finish_init = 0;
+ }
+ else
+ {
+ /* Save the current gdb setting of the terminal.
+ Curses will restore this state when endwin() is called. */
+ def_shell_mode ();
+ clearok (stdscr, TRUE);
+ }
+
+ /* Install the TUI specific hooks. */
+ tui_install_hooks ();
+ rl_startup_hook = tui_rl_startup_hook;
+
+ tui_update_variables ();
+
+ tui_setup_io (1);
+
+ tui_active = 1;
+ if (deprecated_selected_frame)
+ tui_show_frame_info (deprecated_selected_frame);
+
+ /* Restore TUI keymap. */
+ tui_set_key_mode (tui_current_key_mode);
+ tui_refresh_all_win ();
+
+ /* Update gdb's knowledge of its terminal. */
+ target_terminal_save_ours ();
+ tui_update_gdb_sizes ();
+}
+
+/* Leave the tui mode.
+ Remove the tui hooks and configure the gdb output and readline
+ back to their original state. The curses mode is left so that
+ the terminal setting is restored to the point when we entered. */
+void
+tui_disable (void)
+{
+ if (!tui_active)
+ return;
+
+ /* Restore initial readline keymap. */
+ rl_set_keymap (tui_readline_standard_keymap);
+
+ /* Remove TUI hooks. */
+ tui_remove_hooks ();
+ rl_startup_hook = 0;
+ rl_already_prompted = 0;
+
+ /* Leave curses and restore previous gdb terminal setting. */
+ endwin ();
+
+ /* gdb terminal has changed, update gdb internal copy of it
+ so that terminal management with the inferior works. */
+ tui_setup_io (0);
+
+ /* Update gdb's knowledge of its terminal. */
+ target_terminal_save_ours ();
+
+ tui_active = 0;
+ tui_update_gdb_sizes ();
+}
+
+void
+strcat_to_buf (char *buf, int buflen, const char *item_to_add)
+{
+ if (item_to_add != (char *) NULL && buf != (char *) NULL)
+ {
+ if ((strlen (buf) + strlen (item_to_add)) <= buflen)
+ strcat (buf, item_to_add);
+ else
+ strncat (buf, item_to_add, (buflen - strlen (buf)));
+ }
+}
+
+#if 0
+/* Solaris <sys/termios.h> defines CTRL. */
+#ifndef CTRL
+#define CTRL(x) (x & ~0140)
+#endif
+
+#define FILEDES 2
+#define CHK(val, dft) (val<=0 ? dft : val)
+
+static void
+tui_reset (void)
+{
+ struct termio mode;
+
+ /*
+ ** reset the teletype mode bits to a sensible state.
+ ** Copied tset.c
+ */
+#if ! defined (USG) && defined (TIOCGETC)
+ struct tchars tbuf;
+#endif /* !USG && TIOCGETC */
+#ifdef UCB_NTTY
+ struct ltchars ltc;
+
+ if (ldisc == NTTYDISC)
+ {
+ ioctl (FILEDES, TIOCGLTC, &ltc);
+ ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
+ ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
+ ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
+ ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
+ ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
+ ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
+ ioctl (FILEDES, TIOCSLTC, &ltc);
+ }
+#endif /* UCB_NTTY */
+#ifndef USG
+#ifdef TIOCGETC
+ ioctl (FILEDES, TIOCGETC, &tbuf);
+ tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
+ tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
+ tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
+ tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
+ tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
+ /* brkc is left alone */
+ ioctl (FILEDES, TIOCSETC, &tbuf);
+#endif /* TIOCGETC */
+ mode.sg_flags &= ~(RAW
+#ifdef CBREAK
+ | CBREAK
+#endif /* CBREAK */
+ | VTDELAY | ALLDELAY);
+ mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
+#else /*USG */
+ ioctl (FILEDES, TCGETA, &mode);
+ mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
+ mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
+ mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
+
+ mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
+ mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
+ mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
+ NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
+ mode.c_oflag |= (OPOST | ONLCR);
+ mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
+#ifndef hp9000s800
+ mode.c_cflag |= (CS8 | CREAD);
+#else /*hp9000s800 */
+ mode.c_cflag |= (CS8 | CSTOPB | CREAD);
+#endif /* hp9000s800 */
+ mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
+ mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
+ ioctl (FILEDES, TCSETAW, &mode);
+#endif /* USG */
+
+ return;
+}
+#endif
+
+void
+tui_show_source (const char *file, int line)
+{
+ struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+ /* make sure that the source window is displayed */
+ tui_add_win_to_layout (SRC_WIN);
+
+ tui_update_source_windows_with_line (cursal.symtab, line);
+ tui_update_locator_filename (file);
+}
+
+void
+tui_show_assembly (CORE_ADDR addr)
+{
+ tui_add_win_to_layout (DISASSEM_WIN);
+ tui_update_source_windows_with_addr (addr);
+}
+
+int
+tui_is_window_visible (enum tui_win_type type)
+{
+ if (tui_active == 0)
+ return 0;
+
+ if (tui_win_list[type] == 0)
+ return 0;
+
+ return tui_win_list[type]->generic.is_visible;
+}
+
+int
+tui_get_command_dimension (int *width, int *height)
+{
+ if (!tui_active || (TUI_CMD_WIN == NULL))
+ {
+ return 0;
+ }
+
+ *width = TUI_CMD_WIN->generic.width;
+ *height = TUI_CMD_WIN->generic.height;
+ return 1;
+}
diff --git a/contrib/gdb/gdb/tui/tui.h b/contrib/gdb/gdb/tui/tui.h
new file mode 100644
index 0000000..d7b741c
--- /dev/null
+++ b/contrib/gdb/gdb/tui/tui.h
@@ -0,0 +1,100 @@
+/* External/Public TUI Header File.
+
+ Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation,
+ Inc.
+
+ Contributed by Hewlett-Packard Company.
+
+ 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 TUI_H
+#define TUI_H
+
+struct ui_file;
+
+extern void strcat_to_buf (char *, int, const char *);
+
+/* Types of error returns. */
+enum tui_status
+{
+ TUI_SUCCESS,
+ TUI_FAILURE
+};
+
+/* Types of windows */
+enum tui_win_type
+{
+ SRC_WIN = 0,
+ DISASSEM_WIN,
+ DATA_WIN,
+ CMD_WIN,
+ /* This must ALWAYS be AFTER the major windows last. */
+ MAX_MAJOR_WINDOWS,
+ /* Auxillary windows. */
+ LOCATOR_WIN,
+ EXEC_INFO_WIN,
+ DATA_ITEM_WIN,
+ /* This must ALWAYS be next to last. */
+ MAX_WINDOWS,
+ UNDEFINED_WIN /* LAST */
+};
+
+/* GENERAL TUI FUNCTIONS */
+/* tui.c */
+extern CORE_ADDR tui_get_low_disassembly_address (CORE_ADDR, CORE_ADDR);
+extern void tui_show_assembly (CORE_ADDR addr);
+extern int tui_is_window_visible (enum tui_win_type type);
+extern int tui_get_command_dimension (int *width, int *height);
+
+/* Initialize readline and configure the keymap for the switching
+ key shortcut. */
+extern void tui_initialize_readline (void);
+
+/* Enter in the tui mode (curses). */
+extern void tui_enable (void);
+
+/* Leave the tui mode. */
+extern void tui_disable (void);
+
+enum tui_key_mode
+{
+ /* Plain command mode to enter gdb commands. */
+ TUI_COMMAND_MODE,
+
+ /* SingleKey mode with some keys bound to gdb commands. */
+ TUI_SINGLE_KEY_MODE,
+
+ /* Read/edit one command and return to SingleKey after it's processed. */
+ TUI_ONE_COMMAND_MODE
+};
+
+extern enum tui_key_mode tui_current_key_mode;
+
+/* Change the TUI key mode by installing the appropriate readline keymap. */
+extern void tui_set_key_mode (enum tui_key_mode mode);
+
+extern int tui_active;
+
+extern void tui_show_source (const char *file, int line);
+
+extern struct ui_out *tui_out_new (struct ui_file *stream);
+
+/* tui-layout.c */
+extern enum tui_status tui_set_layout_for_display_command (const char *name);
+
+#endif
diff --git a/contrib/gdb/gdb/xcoffread.c b/contrib/gdb/gdb/xcoffread.c
new file mode 100644
index 0000000..759dfcb
--- /dev/null
+++ b/contrib/gdb/gdb/xcoffread.c
@@ -0,0 +1,3033 @@
+/* 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, 2002, 2003, 2004
+ 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/xcoff.h"
+#include "libxcoff.h"
+#include "coff/rs6000.h"
+
+#include "symtab.h"
+#include "gdbtypes.h"
+/* FIXME: ezannoni/2004-02-13 Verify if the include below is really needed. */
+#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 void
+bf_notfound_complaint (void)
+{
+ complaint (&symfile_complaints, "line numbers off, `.bf' symbol not found");
+}
+
+static void
+ef_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "Mismatched .ef symbol ignored starting at symnum %d", arg1);
+}
+
+static void
+eb_complaint (int arg1)
+{
+ complaint (&symfile_complaints,
+ "Mismatched .eb symbol ignored starting at symnum %d", arg1);
+}
+
+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 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, void *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 = &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 = &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. */
+ complaint (&symfile_complaints, "Nested C_BINCL symbols");
+ }
+ ++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)
+ {
+ complaint (&symfile_complaints, "Mismatched C_BINCL/C_EINCL pair");
+ }
+
+ 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)
+ {
+ complaint (&symfile_complaints,
+ "Bad line table offset in C_EINCL directive");
+ 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;
+ 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)
+ {
+ complaint (&symfile_complaints, "Unexpected symbol continuation");
+
+ /* 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
+ {
+ complaint (&symfile_complaints, "Unexpected symbol continuation");
+
+ /* 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 = bfd_xcoff_is_xcoff64 (abfd) ? "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->objfile_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 (DEPRECATED_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 (DEPRECATED_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 */
+ ef_complaint (cs->c_symnum);
+ within_function = 0;
+ break;
+ }
+ new = pop_context ();
+ /* Stack must be empty now. */
+ if (context_stack_depth > 0 || new == NULL)
+ {
+ 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:
+ {
+ complaint (&symfile_complaints, "Unrecognized storage class %d.",
+ 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 (DEPRECATED_STREQ (cs->c_name, ".bb"))
+ {
+ depth++;
+ new = push_context (depth,
+ (cs->c_value
+ + ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))));
+ }
+ else if (DEPRECATED_STREQ (cs->c_name, ".eb"))
+ {
+ if (context_stack_depth <= 0)
+ { /* We attempted to pop an empty context stack */
+ eb_complaint (cs->c_symnum);
+ break;
+ }
+ new = pop_context ();
+ if (depth-- != new->depth)
+ {
+ 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->objfile_obstack, sizeof (struct symbol)); \
+ *(SYMBOL2) = *(SYMBOL1);
+
+
+#define SYMNAME_ALLOC(NAME, ALLOCED) \
+ (ALLOCED) ? (NAME) : obsavestring ((NAME), strlen (NAME), &objfile->objfile_obstack);
+
+
+static struct type *func_symbol_type;
+static struct type *var_symbol_type;
+
+/* process one xcoff symbol. */
+
+static struct symbol *
+process_xcoff_symbol (struct coff_symbol *cs, struct objfile *objfile)
+{
+ struct symbol onesymbol;
+ 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_DOMAIN (sym) = VAR_DOMAIN;
+ 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. */
+
+ DEPRECATED_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:
+ complaint (&symfile_complaints, "Unexpected storage class: %d",
+ 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)
+ {
+ complaint (&symfile_complaints, "Invalid symbol offset");
+ 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;
+ int xcoff64 = bfd_xcoff_is_xcoff64 (objfile->obfd);
+
+ 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)
+ {
+ 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 (DEPRECATED_STREQ (name, ".bf"))
+ goto gotit;
+ }
+ symno += symbol->n_numaux + 1;
+ }
+
+ 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 (struct bfd *abfd, struct bfd_section *asect, void *vpinfo)
+{
+ struct coff_symfile_info *info;
+ int size, count;
+ file_ptr offset, maxoff;
+
+ count = asect->lineno_count;
+
+ if (!DEPRECATED_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);
+
+ 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 objfile_obstack. We will need this table
+ as long as we have its symbol table around. */
+
+ strtbl = (char *) obstack_alloc (&objfile->objfile_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->objfile_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->objfile_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->objfile_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->objfile_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->objfile_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
+function_outside_compilation_unit_complaint (const char *arg1)
+{
+ complaint (&symfile_complaints,
+ "function `%s' appears to be defined outside of all compilation units",
+ arg1);
+}
+
+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:
+ case XMC_TD:
+ /* 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:
+ {
+ complaint (&symfile_complaints,
+ "Storage class %d not recognized during scan", 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 && DEPRECATED_STREQ (namestring, pst->filename))
+ continue;
+ {
+ int i;
+ for (i = 0; i < includes_used; i++)
+ if (DEPRECATED_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 (psymtab_include_list, 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:
+ {
+ 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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_DOMAIN, LOC_TYPEDEF,
+ &objfile->static_psymbols,
+ symbol.n_value, 0,
+ psymtab_language, objfile);
+ p += 1;
+ }
+ }
+ goto check_enum;
+
+ case 't':
+ if (p != namestring) /* a name is there, not just :T... */
+ {
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, 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_DOMAIN, 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_DOMAIN, 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';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, 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';
+ function_outside_compilation_unit_complaint (name);
+ xfree (name);
+ }
+ symbol.n_value += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+ add_psymbol_to_list (namestring, p - namestring,
+ VAR_DOMAIN, 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) */
+ 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. */
+
+ complaint (&symfile_complaints,
+ "unknown symbol descriptor `%c'", 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. */
+ {
+ struct bfd_section *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->objfile_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->objfile_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 = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+
+ /* 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
new file mode 100644
index 0000000..99d2cc8
--- /dev/null
+++ b/contrib/gdb/gdb/xcoffsolib.c
@@ -0,0 +1,196 @@
+/* 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);
+}
diff --git a/contrib/gdb/gdb/xmodem.c b/contrib/gdb/gdb/xmodem.c
new file mode 100644
index 0000000..7b8d77d
--- /dev/null
+++ b/contrib/gdb/gdb/xmodem.c
@@ -0,0 +1,275 @@
+/* XMODEM support for GDB, the GNU debugger.
+ Copyright 1995, 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 "serial.h"
+#include "target.h"
+#include "xmodem.h"
+
+/* These definitions are for xmodem protocol. */
+
+#define SOH 0x01
+#define STX 0x02
+#define ACK 0x06
+#define NAK 0x15
+#define EOT 0x04
+#define CANCEL 0x18
+
+static int blknum; /* XMODEM block number */
+static int crcflag; /* Sez we are using CRC's instead of cksums */
+
+static int
+readchar (struct serial *desc, int timeout)
+{
+ int c;
+
+ c = serial_readchar (desc, timeout);
+
+ if (remote_debug > 0)
+ fputc_unfiltered (c, gdb_stdlog);
+
+ if (c >= 0)
+ return c;
+
+ if (c == SERIAL_TIMEOUT)
+ error ("Timeout reading from remote system.");
+
+ perror_with_name ("xmodem.c:readchar()");
+}
+
+#define CRC16 0x1021 /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
+
+static unsigned short *crctab;
+
+/* Call this to init the fast CRC-16 calculation table. */
+
+static void
+crcinit (void)
+{
+ static int crctab_inited = 0;
+ int val;
+
+ if (crctab_inited == 1)
+ return;
+
+ crctab = xmalloc (256 * sizeof (short));
+
+ for (val = 0; val <= 255; val++)
+ {
+ int i;
+ unsigned int crc;
+
+ crc = val << 8;
+
+ for (i = 0; i < 8; ++i)
+ {
+ crc <<= 1;
+
+ if (crc & 0x10000)
+ crc ^= CRC16;
+ }
+
+ crctab[val] = crc;
+ }
+
+ crctab_inited = 1;
+}
+
+/* Calculate a CRC-16 for the LEN byte message pointed at by P. */
+
+static unsigned short
+docrc (unsigned char *p, int len)
+{
+ unsigned short crc = 0;
+
+ while (len-- > 0)
+ crc = (crc << 8) ^ crctab[(crc >> 8) ^ *p++];
+
+ return crc;
+}
+
+/* Start up the transmit process. Reset state variables. Wait for receiver to
+ send NAK or CRC request. */
+
+int
+xmodem_init_xfer (struct serial *desc)
+{
+ int c;
+ int i;
+
+ blknum = 1;
+ crcflag = 0;
+ crcinit ();
+
+ for (i = 1; i <= 10; i++)
+ {
+ c = readchar (desc, 6);
+
+ switch (c)
+ {
+ case 'C':
+ crcflag = 1;
+ case NAK:
+ return 0;
+ default:
+ fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c);
+ continue;
+ case CANCEL: /* target aborted load */
+ fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n");
+ continue;
+ }
+ }
+ error ("xmodem_init_xfer: Too many unexpected characters.");
+}
+
+/* Take 128 bytes of data and make a packet out of it.
+
+ * Each packet looks like this:
+ * +-----+-------+-------+------+-----+
+ * | SOH | Seq1. | Seq2. | data | SUM |
+ * +-----+-------+-------+------+-----+
+ * SOH = 0x01
+ * Seq1 = The sequence number.
+ * Seq2 = The complement of the sequence number.
+ * Data = A 128 bytes of data.
+ * SUM = Add the contents of the 128 bytes and use the low-order
+ * 8 bits of the result.
+ *
+ * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
+ * remote system. PACKET must be XMODEM_PACKETSIZE bytes long. The data must
+ * start 3 bytes after the beginning of the packet to leave room for the
+ * XMODEM header. LEN is the length of the data portion of the packet (and
+ * must be <= 128 bytes). If it is < 128 bytes, ^Z padding will be added.
+ */
+
+void
+xmodem_send_packet (struct serial *desc, unsigned char *packet, int len, int hashmark)
+{
+ int i;
+ int retries;
+ int pktlen;
+ int datasize;
+
+ /* build the packet header */
+
+ packet[1] = blknum;
+ packet[2] = ~blknum;
+
+ blknum++;
+
+ if (len <= XMODEM_DATASIZE)
+ {
+ packet[0] = SOH;
+ datasize = XMODEM_DATASIZE;
+ }
+ else if (len <= XMODEM_1KDATASIZE)
+ {
+ packet[0] = STX;
+ datasize = XMODEM_1KDATASIZE;
+ }
+ else
+ internal_error (__FILE__, __LINE__, "failed internal consistency check"); /* Packet way too large */
+
+ /* Add ^Z padding if packet < 128 (or 1024) bytes */
+
+ memset (packet + 3 + len, '\026', datasize - len);
+
+ if (crcflag)
+ {
+ int crc;
+
+ crc = docrc (packet + 3, datasize);
+
+ packet[3 + datasize] = crc >> 8;
+ packet[3 + datasize + 1] = crc;
+ pktlen = datasize + 5;
+ }
+ else
+ {
+ int sum;
+
+ sum = 0;
+ for (i = 3; i < datasize + 3; i++)
+ sum += packet[i];
+
+ packet[3 + datasize] = sum; /* add the checksum */
+ pktlen = datasize + 4;
+ }
+
+ for (retries = 3; retries >= 0; retries--)
+ {
+ int c;
+
+ serial_write (desc, packet, pktlen);
+
+ c = readchar (desc, 3);
+ switch (c)
+ {
+ case ACK:
+ return;
+ case NAK:
+ if (!hashmark)
+ continue;
+ putchar_unfiltered ('-');
+ gdb_flush (gdb_stdout);
+ continue;
+ case CANCEL:
+ error ("xmodem_send_packet: Transfer aborted by receiver.");
+ default:
+ fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
+ continue;
+ }
+ }
+
+ serial_write (desc, "\004", 1); /* Send an EOT */
+
+ error ("xmodem_send_packet: Excessive retries.");
+}
+
+/* Finish off the transfer. Send out the EOT, and wait for an ACK. */
+
+void
+xmodem_finish_xfer (struct serial *desc)
+{
+ int retries;
+
+ for (retries = 10; retries >= 0; retries--)
+ {
+ int c;
+
+ serial_write (desc, "\004", 1); /* Send an EOT */
+
+ c = readchar (desc, 3);
+ switch (c)
+ {
+ case ACK:
+ return;
+ case NAK:
+ continue;
+ case CANCEL:
+ error ("xmodem_finish_xfer: Transfer aborted by receiver.");
+ default:
+ fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);
+ continue;
+ }
+ }
+
+ error ("xmodem_finish_xfer: Excessive retries.");
+}
diff --git a/contrib/gdb/gdb/xmodem.h b/contrib/gdb/gdb/xmodem.h
new file mode 100644
index 0000000..83aa24f
--- /dev/null
+++ b/contrib/gdb/gdb/xmodem.h
@@ -0,0 +1,32 @@
+/* XMODEM support for GDB, the GNU debugger.
+ Copyright 1995, 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. */
+
+struct serial;
+
+int xmodem_init_xfer (struct serial *desc);
+void send_xmodem_packet (struct serial *desc, unsigned char *packet, int len,
+ int hashmark);
+void xmodem_finish_xfer (struct serial *desc);
+
+#define XMODEM_DATASIZE 128 /* The data size is ALWAYS 128 */
+#define XMODEM_1KDATASIZE 1024 /* Unless it's 1024!!! */
+#define XMODEM_PACKETSIZE 133 /* data + packet headers and crc */
+#define XMODEM_1KPACKETSIZE 1024 + 5 /* data + packet headers and crc */
+#define XMODEM_DATAOFFSET 3 /* Offset to start of actual data */
diff --git a/contrib/gdb/include/COPYING b/contrib/gdb/include/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/contrib/gdb/include/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/gdb/include/ansidecl.h b/contrib/gdb/include/ansidecl.h
new file mode 100644
index 0000000..d2c8776
--- /dev/null
+++ b/contrib/gdb/include/ansidecl.h
@@ -0,0 +1,315 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+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. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macro ANSI C definition Traditional C definition
+ ----- ---- - ---------- ----------- - ----------
+ ANSI_PROTOTYPES 1 not defined
+ PTR `void *' `char *'
+ PTRCONST `void *const' `char *'
+ LONG_DOUBLE `long double' `double'
+ const not defined `'
+ volatile not defined `'
+ signed not defined `'
+ VA_START(ap, var) va_start(ap, var) va_start(ap)
+
+ Note that it is safe to write "void foo();" indicating a function
+ with no return value, in all K+R compilers we have been able to test.
+
+ For declaring functions with prototypes, we also provide these:
+
+ PARAMS ((prototype))
+ -- for functions which take a fixed number of arguments. Use this
+ when declaring the function. When defining the function, write a
+ K+R style argument list. For example:
+
+ char *strcpy PARAMS ((char *dest, char *source));
+ ...
+ char *
+ strcpy (dest, source)
+ char *dest;
+ char *source;
+ { ... }
+
+
+ VPARAMS ((prototype, ...))
+ -- for functions which take a variable number of arguments. Use
+ PARAMS to declare the function, VPARAMS to define it. For example:
+
+ int printf PARAMS ((const char *format, ...));
+ ...
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ ...
+ }
+
+ For writing functions which take variable numbers of arguments, we
+ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These
+ hide the differences between K+R <varargs.h> and C89 <stdarg.h> more
+ thoroughly than the simple VA_START() macro mentioned above.
+
+ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end.
+ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls
+ corresponding to the list of fixed arguments. Then use va_arg
+ normally to get the variable arguments, or pass your va_list object
+ around. You do not declare the va_list yourself; VA_OPEN does it
+ for you.
+
+ Here is a complete example:
+
+ int
+ printf VPARAMS ((const char *format, ...))
+ {
+ int result;
+
+ VA_OPEN (ap, format);
+ VA_FIXEDARG (ap, const char *, format);
+
+ result = vfprintf (stdout, format, ap);
+ VA_CLOSE (ap);
+
+ return result;
+ }
+
+
+ You can declare variables either before or after the VA_OPEN,
+ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning
+ and end of a block. They must appear at the same nesting level,
+ and any variables declared after VA_OPEN go out of scope at
+ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the
+ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE
+ pairs in a single function in case you need to traverse the
+ argument list more than once.
+
+ For ease of writing code which uses GCC extensions but needs to be
+ portable to other compilers, we provide the GCC_VERSION macro that
+ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
+ wrappers around __attribute__. Also, __extension__ will be #defined
+ to nothing if it doesn't work. See below.
+
+ This header also defines a lot of obsolete macros:
+ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID,
+ AND, DOTS, NOARGS. Don't use them. */
+
+#ifndef _ANSIDECL_H
+#define _ANSIDECL_H 1
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+/* Using MACRO(x,y) in cpp #if conditionals does not work with some
+ older preprocessors. Thus we can't define something like this:
+
+#define HAVE_GCC_VERSION(MAJOR, MINOR) \
+ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
+
+and then test "#if HAVE_GCC_VERSION(2,7)".
+
+So instead we use the macro below and test it against specific values. */
+
+/* This macro simplifies testing whether we are using gcc, and if it
+ is of a particular minimum version. (Both major & minor numbers are
+ significant.) This macro will evaluate to 0 if we are not using
+ gcc at all. */
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif /* GCC_VERSION */
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus))
+/* All known AIX compilers implement these things (but don't always
+ define __STDC__). The RISC/OS MIPS compiler defines these things
+ in SVR4 mode, but does not define __STDC__. */
+/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
+ C++ compilers, does not define __STDC__, though it acts as if this
+ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
+
+#define ANSI_PROTOTYPES 1
+#define PTR void *
+#define PTRCONST void *const
+#define LONG_DOUBLE long double
+
+#define PARAMS(ARGS) ARGS
+#define VPARAMS(ARGS) ARGS
+#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR)
+
+/* variadic function helper macros */
+/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's
+ use without inhibiting further decls and without declaring an
+ actual variable. */
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, T, N) struct Qdmy
+
+#undef const
+#undef volatile
+#undef signed
+
+/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
+ it too, but it's not in C89. */
+#undef inline
+#if __STDC_VERSION__ > 199901L
+/* it's a keyword */
+#else
+# if GCC_VERSION >= 2007
+# define inline __inline__ /* __inline__ prevents -pedantic warnings */
+# else
+# define inline /* nothing */
+# endif
+#endif
+
+/* These are obsolete. Do not use. */
+#ifndef IN_GCC
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+
+#define PROTO(type, name, arglist) type name arglist
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(void)
+#define AND ,
+#define DOTS , ...
+#define NOARGS void
+#endif /* ! IN_GCC */
+
+#else /* Not ANSI C. */
+
+#undef ANSI_PROTOTYPES
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define PARAMS(args) ()
+#define VPARAMS(args) (va_alist) va_dcl
+#define VA_START(va_list, var) va_start(va_list)
+
+#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy
+#define VA_CLOSE(AP) } va_end(AP); }
+#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE)
+
+/* some systems define these in header files for non-ansi mode */
+#undef const
+#undef volatile
+#undef signed
+#undef inline
+#define const
+#define volatile
+#define signed
+#define inline
+
+#ifndef IN_GCC
+#define CONST
+#define VOLATILE
+#define SIGNED
+
+#define PROTO(type, name, arglist) type name ()
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+#define AND ;
+#define DOTS
+#define NOARGS
+#endif /* ! IN_GCC */
+
+#endif /* ANSI C. */
+
+/* Define macros for some gcc attributes. This permits us to use the
+ macros freely, and know that they will come into play for the
+ version of gcc in which they are supported. */
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
+#ifndef ATTRIBUTE_MALLOC
+# if (GCC_VERSION >= 2096)
+# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+# define ATTRIBUTE_MALLOC
+# endif /* GNUC >= 2.96 */
+#endif /* ATTRIBUTE_MALLOC */
+
+/* Attributes on labels were valid as of gcc 2.93. */
+#ifndef ATTRIBUTE_UNUSED_LABEL
+# if (GCC_VERSION >= 2093)
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif /* GNUC >= 2.93 */
+#endif /* ATTRIBUTE_UNUSED_LABEL */
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+/* Attribute `nonnull' was valid as of gcc 3.3. */
+#ifndef ATTRIBUTE_NONNULL
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
+# else
+# define ATTRIBUTE_NONNULL(m)
+# endif /* GNUC >= 3.3 */
+#endif /* ATTRIBUTE_NONNULL */
+
+/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
+ This was the case for the `printf' format attribute by itself
+ before GCC 3.3, but as of 3.3 we need to add the `nonnull'
+ attribute to retain this behavior. */
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
+ NULL format specifier was allowed as of gcc 3.3. */
+#ifndef ATTRIBUTE_NULL_PRINTF
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
+# else
+# define ATTRIBUTE_NULL_PRINTF(m, n)
+# endif /* GNUC >= 3.3 */
+# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
+# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
+# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
+# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
+# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
+#endif /* ATTRIBUTE_NULL_PRINTF */
+
+/* We use __extension__ in some places to suppress -pedantic warnings
+ about GCC extensions. This feature didn't work properly before
+ gcc 2.8. */
+#if GCC_VERSION < 2008
+#define __extension__
+#endif
+
+#endif /* ansidecl.h */
diff --git a/contrib/gdb/include/bfdlink.h b/contrib/gdb/include/bfdlink.h
new file mode 100644
index 0000000..a989f64
--- /dev/null
+++ b/contrib/gdb/include/bfdlink.h
@@ -0,0 +1,686 @@
+/* bfdlink.h -- header file for BFD link routines
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003
+ Free Software Foundation, Inc.
+ Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ 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 BFDLINK_H
+#define BFDLINK_H
+
+/* Which symbols to strip during a link. */
+enum bfd_link_strip
+{
+ strip_none, /* Don't strip any symbols. */
+ strip_debugger, /* Strip debugging symbols. */
+ strip_some, /* keep_hash is the list of symbols to keep. */
+ strip_all /* Strip all symbols. */
+};
+
+/* Which local symbols to discard during a link. This is irrelevant
+ if strip_all is used. */
+enum bfd_link_discard
+{
+ discard_sec_merge, /* Discard local temporary symbols in SEC_MERGE
+ sections. */
+ discard_none, /* Don't discard any locals. */
+ discard_l, /* Discard local temporary symbols. */
+ discard_all /* Discard all locals. */
+};
+
+/* Describes the type of hash table entry structure being used.
+ Different hash table structure have different fields and so
+ support different linking features. */
+enum bfd_link_hash_table_type
+ {
+ bfd_link_generic_hash_table,
+ bfd_link_elf_hash_table
+ };
+
+/* These are the possible types of an entry in the BFD link hash
+ table. */
+
+enum bfd_link_hash_type
+{
+ bfd_link_hash_new, /* Symbol is new. */
+ bfd_link_hash_undefined, /* Symbol seen before, but undefined. */
+ bfd_link_hash_undefweak, /* Symbol is weak and undefined. */
+ bfd_link_hash_defined, /* Symbol is defined. */
+ bfd_link_hash_defweak, /* Symbol is weak and defined. */
+ bfd_link_hash_common, /* Symbol is common. */
+ bfd_link_hash_indirect, /* Symbol is an indirect link. */
+ bfd_link_hash_warning /* Like indirect, but warn if referenced. */
+};
+
+enum bfd_link_common_skip_ar_aymbols
+{
+ bfd_link_common_skip_none,
+ bfd_link_common_skip_text,
+ bfd_link_common_skip_data,
+ bfd_link_common_skip_all
+};
+
+/* The linking routines use a hash table which uses this structure for
+ its elements. */
+
+struct bfd_link_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+
+ /* Type of this entry. */
+ enum bfd_link_hash_type type;
+
+ /* Undefined and common symbols are kept in a linked list through
+ this field. This field is not in the union because that would
+ force us to remove entries from the list when we changed their
+ type, which would force the list to be doubly linked, which would
+ waste more memory. When an undefined or common symbol is
+ created, it should be added to this list, the head of which is in
+ the link hash table itself. As symbols are defined, they need
+ not be removed from the list; anything which reads the list must
+ doublecheck the symbol type.
+
+ Weak symbols are not kept on this list.
+
+ Defined and defweak symbols use this field as a reference marker.
+ If the field is not NULL, or this structure is the tail of the
+ undefined symbol list, the symbol has been referenced. If the
+ symbol is undefined and becomes defined, this field will
+ automatically be non-NULL since the symbol will have been on the
+ undefined symbol list. */
+ struct bfd_link_hash_entry *und_next;
+
+ /* A union of information depending upon the type. */
+ union
+ {
+ /* Nothing is kept for bfd_hash_new. */
+ /* bfd_link_hash_undefined, bfd_link_hash_undefweak. */
+ struct
+ {
+ bfd *abfd; /* BFD symbol was found in. */
+ } undef;
+ /* bfd_link_hash_defined, bfd_link_hash_defweak. */
+ struct
+ {
+ bfd_vma value; /* Symbol value. */
+ asection *section; /* Symbol section. */
+ } def;
+ /* bfd_link_hash_indirect, bfd_link_hash_warning. */
+ struct
+ {
+ struct bfd_link_hash_entry *link; /* Real symbol. */
+ const char *warning; /* Warning (bfd_link_hash_warning only). */
+ } i;
+ /* bfd_link_hash_common. */
+ struct
+ {
+ /* The linker needs to know three things about common
+ symbols: the size, the alignment, and the section in
+ which the symbol should be placed. We store the size
+ here, and we allocate a small structure to hold the
+ section and the alignment. The alignment is stored as a
+ power of two. We don't store all the information
+ directly because we don't want to increase the size of
+ the union; this structure is a major space user in the
+ linker. */
+ bfd_size_type size; /* Common symbol size. */
+ struct bfd_link_hash_common_entry
+ {
+ unsigned int alignment_power; /* Alignment. */
+ asection *section; /* Symbol section. */
+ } *p;
+ } c;
+ } u;
+};
+
+/* This is the link hash table. It is a derived class of
+ bfd_hash_table. */
+
+struct bfd_link_hash_table
+{
+ /* The hash table itself. */
+ struct bfd_hash_table table;
+ /* The back end which created this hash table. This indicates the
+ type of the entries in the hash table, which is sometimes
+ important information when linking object files of different
+ types together. */
+ const bfd_target *creator;
+ /* A linked list of undefined and common symbols, linked through the
+ next field in the bfd_link_hash_entry structure. */
+ struct bfd_link_hash_entry *undefs;
+ /* Entries are added to the tail of the undefs list. */
+ struct bfd_link_hash_entry *undefs_tail;
+ /* The type of the link hash table. */
+ enum bfd_link_hash_table_type type;
+};
+
+/* Look up an entry in a link hash table. If FOLLOW is TRUE, this
+ follows bfd_link_hash_indirect and bfd_link_hash_warning links to
+ the real symbol. */
+extern struct bfd_link_hash_entry *bfd_link_hash_lookup
+ (struct bfd_link_hash_table *, const char *, bfd_boolean create,
+ bfd_boolean copy, bfd_boolean follow);
+
+/* Look up an entry in the main linker hash table if the symbol might
+ be wrapped. This should only be used for references to an
+ undefined symbol, not for definitions of a symbol. */
+
+extern struct bfd_link_hash_entry *bfd_wrapped_link_hash_lookup
+ (bfd *, struct bfd_link_info *, const char *, bfd_boolean,
+ bfd_boolean, bfd_boolean);
+
+/* Traverse a link hash table. */
+extern void bfd_link_hash_traverse
+ (struct bfd_link_hash_table *,
+ bfd_boolean (*) (struct bfd_link_hash_entry *, void *),
+ void *);
+
+/* Add an entry to the undefs list. */
+extern void bfd_link_add_undef
+ (struct bfd_link_hash_table *, struct bfd_link_hash_entry *);
+
+struct bfd_sym_chain
+{
+ struct bfd_sym_chain *next;
+ const char *name;
+};
+
+/* How to handle unresolved symbols.
+ There are four possibilities which are enumerated below: */
+enum report_method
+{
+ /* This is the initial value when then link_info structure is created.
+ It allows the various stages of the linker to determine whether they
+ allowed to set the value. */
+ RM_NOT_YET_SET = 0,
+ RM_IGNORE,
+ RM_GENERATE_WARNING,
+ RM_GENERATE_ERROR
+};
+
+/* This structure holds all the information needed to communicate
+ between BFD and the linker when doing a link. */
+
+struct bfd_link_info
+{
+ /* TRUE if BFD should generate a relocatable object file. */
+ unsigned int relocatable: 1;
+
+ /* TRUE if BFD should generate relocation information in the final
+ executable. */
+ unsigned int emitrelocations: 1;
+
+ /* TRUE if BFD should generate a "task linked" object file,
+ similar to relocatable but also with globals converted to
+ statics. */
+ unsigned int task_link: 1;
+
+ /* TRUE if BFD should generate a shared object. */
+ unsigned int shared: 1;
+
+ /* TRUE if BFD should pre-bind symbols in a shared object. */
+ unsigned int symbolic: 1;
+
+ /* TRUE if BFD should export all symbols in the dynamic symbol table
+ of an executable, rather than only those used. */
+ unsigned int export_dynamic: 1;
+
+ /* TRUE if shared objects should be linked directly, not shared. */
+ unsigned int static_link: 1;
+
+ /* TRUE if the output file should be in a traditional format. This
+ is equivalent to the setting of the BFD_TRADITIONAL_FORMAT flag
+ on the output file, but may be checked when reading the input
+ files. */
+ unsigned int traditional_format: 1;
+
+ /* TRUE if we want to produced optimized output files. This might
+ need much more time and therefore must be explicitly selected. */
+ unsigned int optimize: 1;
+
+ /* TRUE if ok to have multiple definition. */
+ unsigned int allow_multiple_definition: 1;
+
+ /* TRUE if ok to have version with no definition. */
+ unsigned int allow_undefined_version: 1;
+
+ /* TRUE if symbols should be retained in memory, FALSE if they
+ should be freed and reread. */
+ unsigned int keep_memory: 1;
+
+ /* TRUE if every symbol should be reported back via the notice
+ callback. */
+ unsigned int notice_all: 1;
+
+ /* TRUE if executable should not contain copy relocs.
+ Setting this true may result in a non-sharable text segment. */
+ unsigned int nocopyreloc: 1;
+
+ /* TRUE if the new ELF dynamic tags are enabled. */
+ unsigned int new_dtags: 1;
+
+ /* TRUE if non-PLT relocs should be merged into one reloc section
+ and sorted so that relocs against the same symbol come together. */
+ unsigned int combreloc: 1;
+
+ /* TRUE if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment
+ should be created. */
+ unsigned int eh_frame_hdr: 1;
+
+ /* TRUE if global symbols in discarded sections should be stripped. */
+ unsigned int strip_discarded: 1;
+
+ /* TRUE if the final relax pass is needed. */
+ unsigned int need_relax_finalize: 1;
+
+ /* TRUE if generating a position independent executable. */
+ unsigned int pie: 1;
+
+ /* TRUE if generating an executable, position independent or not. */
+ unsigned int executable : 1;
+
+ /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X
+ flags. */
+ unsigned int execstack: 1;
+
+ /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W
+ flags. */
+ unsigned int noexecstack: 1;
+
+ /* What to do with unresolved symbols in an object file.
+ When producing static binaries the default is GENERATE_ERROR.
+ When producing dynamic binaries the default is IGNORE. The
+ assumption with dynamic binaries is that the reference will be
+ resolved at load/execution time. */
+ enum report_method unresolved_syms_in_objects;
+
+ /* What to do with unresolved symbols in a shared library.
+ The same defaults apply. */
+ enum report_method unresolved_syms_in_shared_libs;
+
+ /* Which symbols to strip. */
+ enum bfd_link_strip strip;
+
+ /* Which local symbols to discard. */
+ enum bfd_link_discard discard;
+
+ /* Criteria for skipping symbols when detemining
+ whether to include an object from an archive. */
+ enum bfd_link_common_skip_ar_aymbols common_skip_ar_aymbols;
+
+ /* Function callbacks. */
+ const struct bfd_link_callbacks *callbacks;
+
+ /* Hash table handled by BFD. */
+ struct bfd_link_hash_table *hash;
+
+ /* Hash table of symbols to keep. This is NULL unless strip is
+ strip_some. */
+ struct bfd_hash_table *keep_hash;
+
+ /* Hash table of symbols to report back via the notice callback. If
+ this is NULL, and notice_all is FALSE, then no symbols are
+ reported back. */
+ struct bfd_hash_table *notice_hash;
+
+ /* Hash table of symbols which are being wrapped (the --wrap linker
+ option). If this is NULL, no symbols are being wrapped. */
+ struct bfd_hash_table *wrap_hash;
+
+ /* The list of input BFD's involved in the link. These are chained
+ together via the link_next field. */
+ bfd *input_bfds;
+
+ /* If a symbol should be created for each input BFD, this is section
+ where those symbols should be placed. It must be a section in
+ the output BFD. It may be NULL, in which case no such symbols
+ will be created. This is to support CREATE_OBJECT_SYMBOLS in the
+ linker command language. */
+ asection *create_object_symbols_section;
+
+ /* List of global symbol names that are starting points for marking
+ sections against garbage collection. */
+ struct bfd_sym_chain *gc_sym_list;
+
+ /* If a base output file is wanted, then this points to it */
+ void *base_file;
+
+ /* The function to call when the executable or shared object is
+ loaded. */
+ const char *init_function;
+
+ /* The function to call when the executable or shared object is
+ unloaded. */
+ const char *fini_function;
+
+ /* Non-zero if auto-import thunks for DATA items in pei386 DLLs
+ should be generated/linked against. Set to 1 if this feature
+ is explicitly requested by the user, -1 if enabled by default. */
+ int pei386_auto_import;
+
+ /* Non-zero if runtime relocs for DATA items with non-zero addends
+ in pei386 DLLs should be generated. Set to 1 if this feature
+ is explicitly requested by the user, -1 if enabled by default. */
+ int pei386_runtime_pseudo_reloc;
+
+ /* How many spare .dynamic DT_NULL entries should be added? */
+ unsigned int spare_dynamic_tags;
+
+ /* May be used to set DT_FLAGS for ELF. */
+ bfd_vma flags;
+
+ /* May be used to set DT_FLAGS_1 for ELF. */
+ bfd_vma flags_1;
+};
+
+/* This structures holds a set of callback functions. These are
+ called by the BFD linker routines. The first argument to each
+ callback function is the bfd_link_info structure being used. Each
+ function returns a boolean value. If the function returns FALSE,
+ then the BFD function which called it will return with a failure
+ indication. */
+
+struct bfd_link_callbacks
+{
+ /* A function which is called when an object is added from an
+ archive. ABFD is the archive element being added. NAME is the
+ name of the symbol which caused the archive element to be pulled
+ in. */
+ bfd_boolean (*add_archive_element)
+ (struct bfd_link_info *, bfd *abfd, const char *name);
+ /* A function which is called when a symbol is found with multiple
+ definitions. NAME is the symbol which is defined multiple times.
+ OBFD is the old BFD, OSEC is the old section, OVAL is the old
+ value, NBFD is the new BFD, NSEC is the new section, and NVAL is
+ the new value. OBFD may be NULL. OSEC and NSEC may be
+ bfd_com_section or bfd_ind_section. */
+ bfd_boolean (*multiple_definition)
+ (struct bfd_link_info *, const char *name,
+ bfd *obfd, asection *osec, bfd_vma oval,
+ bfd *nbfd, asection *nsec, bfd_vma nval);
+ /* A function which is called when a common symbol is defined
+ multiple times. NAME is the symbol appearing multiple times.
+ OBFD is the BFD of the existing symbol; it may be NULL if this is
+ not known. OTYPE is the type of the existing symbol, which may
+ be bfd_link_hash_defined, bfd_link_hash_defweak,
+ bfd_link_hash_common, or bfd_link_hash_indirect. If OTYPE is
+ bfd_link_hash_common, OSIZE is the size of the existing symbol.
+ NBFD is the BFD of the new symbol. NTYPE is the type of the new
+ symbol, one of bfd_link_hash_defined, bfd_link_hash_common, or
+ bfd_link_hash_indirect. If NTYPE is bfd_link_hash_common, NSIZE
+ is the size of the new symbol. */
+ bfd_boolean (*multiple_common)
+ (struct bfd_link_info *, const char *name,
+ bfd *obfd, enum bfd_link_hash_type otype, bfd_vma osize,
+ bfd *nbfd, enum bfd_link_hash_type ntype, bfd_vma nsize);
+ /* A function which is called to add a symbol to a set. ENTRY is
+ the link hash table entry for the set itself (e.g.,
+ __CTOR_LIST__). RELOC is the relocation to use for an entry in
+ the set when generating a relocatable file, and is also used to
+ get the size of the entry when generating an executable file.
+ ABFD, SEC and VALUE identify the value to add to the set. */
+ bfd_boolean (*add_to_set)
+ (struct bfd_link_info *, struct bfd_link_hash_entry *entry,
+ bfd_reloc_code_real_type reloc, bfd *abfd, asection *sec, bfd_vma value);
+ /* A function which is called when the name of a g++ constructor or
+ destructor is found. This is only called by some object file
+ formats. CONSTRUCTOR is TRUE for a constructor, FALSE for a
+ destructor. This will use BFD_RELOC_CTOR when generating a
+ relocatable file. NAME is the name of the symbol found. ABFD,
+ SECTION and VALUE are the value of the symbol. */
+ bfd_boolean (*constructor)
+ (struct bfd_link_info *, bfd_boolean constructor, const char *name,
+ bfd *abfd, asection *sec, bfd_vma value);
+ /* A function which is called to issue a linker warning. For
+ example, this is called when there is a reference to a warning
+ symbol. WARNING is the warning to be issued. SYMBOL is the name
+ of the symbol which triggered the warning; it may be NULL if
+ there is none. ABFD, SECTION and ADDRESS identify the location
+ which trigerred the warning; either ABFD or SECTION or both may
+ be NULL if the location is not known. */
+ bfd_boolean (*warning)
+ (struct bfd_link_info *, const char *warning, const char *symbol,
+ bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called when a relocation is attempted against
+ an undefined symbol. NAME is the symbol which is undefined.
+ ABFD, SECTION and ADDRESS identify the location from which the
+ reference is made. FATAL indicates whether an undefined symbol is
+ a fatal error or not. In some cases SECTION may be NULL. */
+ bfd_boolean (*undefined_symbol)
+ (struct bfd_link_info *, const char *name, bfd *abfd,
+ asection *section, bfd_vma address, bfd_boolean fatal);
+ /* A function which is called when a reloc overflow occurs. NAME is
+ the name of the symbol or section the reloc is against,
+ RELOC_NAME is the name of the relocation, and ADDEND is any
+ addend that is used. ABFD, SECTION and ADDRESS identify the
+ location at which the overflow occurs; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ bfd_boolean (*reloc_overflow)
+ (struct bfd_link_info *, const char *name, const char *reloc_name,
+ bfd_vma addend, bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called when a dangerous reloc is performed.
+ The canonical example is an a29k IHCONST reloc which does not
+ follow an IHIHALF reloc. MESSAGE is an appropriate message.
+ ABFD, SECTION and ADDRESS identify the location at which the
+ problem occurred; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ bfd_boolean (*reloc_dangerous)
+ (struct bfd_link_info *, const char *message,
+ bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called when a reloc is found to be attached
+ to a symbol which is not being written out. NAME is the name of
+ the symbol. ABFD, SECTION and ADDRESS identify the location of
+ the reloc; if this is the result of a
+ bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then
+ ABFD will be NULL. */
+ bfd_boolean (*unattached_reloc)
+ (struct bfd_link_info *, const char *name,
+ bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called when a symbol in notice_hash is
+ defined or referenced. NAME is the symbol. ABFD, SECTION and
+ ADDRESS are the value of the symbol. If SECTION is
+ bfd_und_section, this is a reference. */
+ bfd_boolean (*notice)
+ (struct bfd_link_info *, const char *name,
+ bfd *abfd, asection *section, bfd_vma address);
+ /* A function which is called for reporting a linker error. ID is the
+ error identifier. The remaining input is the same as einfo () in
+ ld. */
+ bfd_boolean (*error_handler)
+ (int id, const char *fmt, ...);
+
+/* Identifiers of linker error messages used by error_handler. */
+#define LD_DEFINITION_IN_DISCARDED_SECTION 1
+};
+
+/* The linker builds link_order structures which tell the code how to
+ include input data in the output file. */
+
+/* These are the types of link_order structures. */
+
+enum bfd_link_order_type
+{
+ bfd_undefined_link_order, /* Undefined. */
+ bfd_indirect_link_order, /* Built from a section. */
+ bfd_data_link_order, /* Set to explicit data. */
+ bfd_section_reloc_link_order, /* Relocate against a section. */
+ bfd_symbol_reloc_link_order /* Relocate against a symbol. */
+};
+
+/* This is the link_order structure itself. These form a chain
+ attached to the section whose contents they are describing. */
+
+struct bfd_link_order
+{
+ /* Next link_order in chain. */
+ struct bfd_link_order *next;
+ /* Type of link_order. */
+ enum bfd_link_order_type type;
+ /* Offset within output section. */
+ bfd_vma offset;
+ /* Size within output section. */
+ bfd_size_type size;
+ /* Type specific information. */
+ union
+ {
+ struct
+ {
+ /* Section to include. If this is used, then
+ section->output_section must be the section the
+ link_order is attached to, section->output_offset must
+ equal the link_order offset field, and section->_raw_size
+ must equal the link_order size field. Maybe these
+ restrictions should be relaxed someday. */
+ asection *section;
+ } indirect;
+ struct
+ {
+ /* Size of contents, or zero when contents size == size
+ within output section.
+ A non-zero value allows filling of the output section
+ with an arbitrary repeated pattern. */
+ unsigned int size;
+ /* Data to put into file. */
+ bfd_byte *contents;
+ } data;
+ struct
+ {
+ /* Description of reloc to generate. Used for
+ bfd_section_reloc_link_order and
+ bfd_symbol_reloc_link_order. */
+ struct bfd_link_order_reloc *p;
+ } reloc;
+ } u;
+};
+
+/* A linker order of type bfd_section_reloc_link_order or
+ bfd_symbol_reloc_link_order means to create a reloc against a
+ section or symbol, respectively. This is used to implement -Ur to
+ generate relocs for the constructor tables. The
+ bfd_link_order_reloc structure describes the reloc that BFD should
+ create. It is similar to a arelent, but I didn't use arelent
+ because the linker does not know anything about most symbols, and
+ any asymbol structure it creates will be partially meaningless.
+ This information could logically be in the bfd_link_order struct,
+ but I didn't want to waste the space since these types of relocs
+ are relatively rare. */
+
+struct bfd_link_order_reloc
+{
+ /* Reloc type. */
+ bfd_reloc_code_real_type reloc;
+
+ union
+ {
+ /* For type bfd_section_reloc_link_order, this is the section
+ the reloc should be against. This must be a section in the
+ output BFD, not any of the input BFDs. */
+ asection *section;
+ /* For type bfd_symbol_reloc_link_order, this is the name of the
+ symbol the reloc should be against. */
+ const char *name;
+ } u;
+
+ /* Addend to use. The object file should contain zero. The BFD
+ backend is responsible for filling in the contents of the object
+ file correctly. For some object file formats (e.g., COFF) the
+ addend must be stored into in the object file, and for some
+ (e.g., SPARC a.out) it is kept in the reloc. */
+ bfd_vma addend;
+};
+
+/* Allocate a new link_order for a section. */
+extern struct bfd_link_order *bfd_new_link_order (bfd *, asection *);
+
+/* These structures are used to describe version information for the
+ ELF linker. These structures could be manipulated entirely inside
+ BFD, but it would be a pain. Instead, the regular linker sets up
+ these structures, and then passes them into BFD. */
+
+/* Glob pattern for a version. */
+
+struct bfd_elf_version_expr
+{
+ /* Next glob pattern for this version. */
+ struct bfd_elf_version_expr *next;
+ /* Glob pattern. */
+ const char *pattern;
+ /* NULL for a glob pattern, otherwise a straight symbol. */
+ const char *symbol;
+ /* Defined by ".symver". */
+ unsigned int symver : 1;
+ /* Defined by version script. */
+ unsigned int script : 1;
+ /* Pattern type. */
+#define BFD_ELF_VERSION_C_TYPE 1
+#define BFD_ELF_VERSION_CXX_TYPE 2
+#define BFD_ELF_VERSION_JAVA_TYPE 4
+ unsigned int mask : 3;
+};
+
+struct bfd_elf_version_expr_head
+{
+ /* List of all patterns, both wildcards and non-wildcards. */
+ struct bfd_elf_version_expr *list;
+ /* Hash table for non-wildcards. */
+ void *htab;
+ /* Remaining patterns. */
+ struct bfd_elf_version_expr *remaining;
+ /* What kind of pattern types are present in list (bitmask). */
+ unsigned int mask;
+};
+
+/* Version dependencies. */
+
+struct bfd_elf_version_deps
+{
+ /* Next dependency for this version. */
+ struct bfd_elf_version_deps *next;
+ /* The version which this version depends upon. */
+ struct bfd_elf_version_tree *version_needed;
+};
+
+/* A node in the version tree. */
+
+struct bfd_elf_version_tree
+{
+ /* Next version. */
+ struct bfd_elf_version_tree *next;
+ /* Name of this version. */
+ const char *name;
+ /* Version number. */
+ unsigned int vernum;
+ /* Regular expressions for global symbols in this version. */
+ struct bfd_elf_version_expr_head globals;
+ /* Regular expressions for local symbols in this version. */
+ struct bfd_elf_version_expr_head locals;
+ /* List of versions which this version depends upon. */
+ struct bfd_elf_version_deps *deps;
+ /* Index of the version name. This is used within BFD. */
+ unsigned int name_indx;
+ /* Whether this version tree was used. This is used within BFD. */
+ int used;
+ /* Matching hook. */
+ struct bfd_elf_version_expr *(*match)
+ (struct bfd_elf_version_expr_head *head,
+ struct bfd_elf_version_expr *prev, const char *sym);
+};
+
+#endif
diff --git a/contrib/gdb/include/bout.h b/contrib/gdb/include/bout.h
new file mode 100644
index 0000000..a69e280
--- /dev/null
+++ b/contrib/gdb/include/bout.h
@@ -0,0 +1,191 @@
+/* This file is a modified version of 'a.out.h'. It is to be used in all
+ GNU tools modified to support the i80960 (or tools that operate on
+ object files created by such tools).
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* All i80960 development is done in a CROSS-DEVELOPMENT environment. I.e.,
+ object code is generated on, and executed under the direction of a symbolic
+ debugger running on, a host system. We do not want to be subject to the
+ vagaries of which host it is or whether it supports COFF or a.out format,
+ or anything else. We DO want to:
+
+ o always generate the same format object files, regardless of host.
+
+ o have an 'a.out' header that we can modify for our own purposes
+ (the 80960 is typically an embedded processor and may require
+ enhanced linker support that the normal a.out.h header can't
+ accommodate).
+
+ As for byte-ordering, the following rules apply:
+
+ o Text and data that is actually downloaded to the target is always
+ in i80960 (little-endian) order.
+
+ o All other numbers (in the header, symbols, relocation directives)
+ are in host byte-order: object files CANNOT be lifted from a
+ little-end host and used on a big-endian (or vice versa) without
+ modification.
+ ==> THIS IS NO LONGER TRUE USING BFD. WE CAN GENERATE ANY BYTE ORDER
+ FOR THE HEADER, AND READ ANY BYTE ORDER. PREFERENCE WOULD BE TO
+ USE LITTLE-ENDIAN BYTE ORDER THROUGHOUT, REGARDLESS OF HOST. <==
+
+ o The downloader ('comm960') takes care to generate a pseudo-header
+ with correct (i80960) byte-ordering before shipping text and data
+ off to the NINDY monitor in the target systems. Symbols and
+ relocation info are never sent to the target. */
+
+#define BMAGIC 0415
+/* We don't accept the following (see N_BADMAG macro).
+ They're just here so GNU code will compile. */
+#define OMAGIC 0407 /* old impure format */
+#define NMAGIC 0410 /* read-only text */
+#define ZMAGIC 0413 /* demand load format */
+
+/* FILE HEADER
+ All 'lengths' are given as a number of bytes.
+ All 'alignments' are for relinkable files only; an alignment of
+ 'n' indicates the corresponding segment must begin at an
+ address that is a multiple of (2**n). */
+struct external_exec
+ {
+ /* Standard stuff */
+ unsigned char e_info[4]; /* Identifies this as a b.out file */
+ unsigned char e_text[4]; /* Length of text */
+ unsigned char e_data[4]; /* Length of data */
+ unsigned char e_bss[4]; /* Length of uninitialized data area */
+ unsigned char e_syms[4]; /* Length of symbol table */
+ unsigned char e_entry[4]; /* Runtime start address */
+ unsigned char e_trsize[4]; /* Length of text relocation info */
+ unsigned char e_drsize[4]; /* Length of data relocation info */
+
+ /* Added for i960 */
+ unsigned char e_tload[4]; /* Text runtime load address */
+ unsigned char e_dload[4]; /* Data runtime load address */
+ unsigned char e_talign[1]; /* Alignment of text segment */
+ unsigned char e_dalign[1]; /* Alignment of data segment */
+ unsigned char e_balign[1]; /* Alignment of bss segment */
+ unsigned char e_relaxable[1];/* Assembled with enough info to allow linker to relax */
+ };
+
+#define EXEC_BYTES_SIZE (sizeof (struct external_exec))
+
+/* These macros use the a_xxx field names, since they operate on the exec
+ structure after it's been byte-swapped and realigned on the host machine. */
+#define N_BADMAG(x) (((x).a_info)!=BMAGIC)
+#define N_TXTOFF(x) EXEC_BYTES_SIZE
+#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text )
+#define N_TROFF(x) ( N_DATOFF(x) + (x).a_data )
+#define N_TRELOFF N_TROFF
+#define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize )
+#define N_DRELOFF N_DROFF
+#define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize )
+#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
+#define N_DATADDR(x) ( (x).a_dload )
+
+/* Address of text segment in memory after it is loaded. */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* A single entry in the symbol table. */
+struct nlist
+ {
+ union
+ {
+ char* n_name;
+ struct nlist * n_next;
+ long n_strx; /* Index into string table */
+ } n_un;
+
+ unsigned char n_type; /* See below */
+ char n_other; /* Used in i80960 support -- see below */
+ short n_desc;
+ unsigned long n_value;
+ };
+
+
+/* Legal values of n_type. */
+#define N_UNDF 0 /* Undefined symbol */
+#define N_ABS 2 /* Absolute symbol */
+#define N_TEXT 4 /* Text symbol */
+#define N_DATA 6 /* Data symbol */
+#define N_BSS 8 /* BSS symbol */
+#define N_FN 31 /* Filename symbol */
+
+#define N_EXT 1 /* External symbol (OR'd in with one of above) */
+#define N_TYPE 036 /* Mask for all the type bits */
+#define N_STAB 0340 /* Mask for all bits used for SDB entries */
+
+/* MEANING OF 'n_other'
+
+ If non-zero, the 'n_other' fields indicates either a leaf procedure or
+ a system procedure, as follows:
+
+ 1 <= n_other <= 32 :
+ The symbol is the entry point to a system procedure.
+ 'n_value' is the address of the entry, as for any other
+ procedure. The system procedure number (which can be used in
+ a 'calls' instruction) is (n_other-1). These entries come from
+ '.sysproc' directives.
+
+ n_other == N_CALLNAME
+ the symbol is the 'call' entry point to a leaf procedure.
+ The *next* symbol in the symbol table must be the corresponding
+ 'bal' entry point to the procedure (see following). These
+ entries come from '.leafproc' directives in which two different
+ symbols are specified (the first one is represented here).
+
+
+ n_other == N_BALNAME
+ the symbol is the 'bal' entry point to a leaf procedure.
+ These entries result from '.leafproc' directives in which only
+ one symbol is specified, or in which the same symbol is
+ specified twice.
+
+ Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry,
+ but not every N_BALNAME entry must have an N_CALLNAME entry. */
+#define N_CALLNAME ((char)-1)
+#define N_BALNAME ((char)-2)
+#define IS_CALLNAME(x) (N_CALLNAME == (x))
+#define IS_BALNAME(x) (N_BALNAME == (x))
+#define IS_OTHER(x) ((x)>0 && (x) <=32)
+
+#define b_out_relocation_info relocation_info
+struct relocation_info
+ {
+ int r_address; /* File address of item to be relocated. */
+ unsigned
+#define r_index r_symbolnum
+ r_symbolnum:24, /* Index of symbol on which relocation is based,
+ if r_extern is set. Otherwise set to
+ either N_TEXT, N_DATA, or N_BSS to
+ indicate section on which relocation is
+ based. */
+ r_pcrel:1, /* 1 => relocate PC-relative; else absolute
+ On i960, pc-relative implies 24-bit
+ address, absolute implies 32-bit. */
+ r_length:2, /* Number of bytes to relocate:
+ 0 => 1 byte
+ 1 => 2 bytes -- used for 13 bit pcrel
+ 2 => 4 bytes. */
+ r_extern:1,
+ r_bsr:1, /* Something for the GNU NS32K assembler. */
+ r_disp:1, /* Something for the GNU NS32K assembler. */
+ r_callj:1, /* 1 if relocation target is an i960 'callj'. */
+ r_relaxable:1; /* 1 if enough info is left to relax the data. */
+};
diff --git a/contrib/gdb/include/demangle.h b/contrib/gdb/include/demangle.h
new file mode 100644
index 0000000..6e995e4
--- /dev/null
+++ b/contrib/gdb/include/demangle.h
@@ -0,0 +1,533 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
+ 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#include "libiberty.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
+#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler;
+ same as ARM except for
+ template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ no_demangling = -1,
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM,
+ hp_demangling = DMGL_HP,
+ edg_demangling = DMGL_EDG,
+ gnu_v3_demangling = DMGL_GNU_V3,
+ java_demangling = DMGL_JAVA,
+ gnat_demangling = DMGL_GNAT
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define NO_DEMANGLING_STYLE_STRING "none"
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+#define HP_DEMANGLING_STYLE_STRING "hp"
+#define EDG_DEMANGLING_STYLE_STRING "edg"
+#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
+#define JAVA_DEMANGLING_STYLE_STRING "java"
+#define GNAT_DEMANGLING_STYLE_STRING "gnat"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
+#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
+#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
+#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
+#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
+#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
+
+/* Provide information about the available demangle styles. This code is
+ pulled from gdb into libiberty because it is useful to binutils also. */
+
+extern const struct demangler_engine
+{
+ const char *const demangling_style_name;
+ const enum demangling_styles demangling_style;
+ const char *const demangling_style_doc;
+} libiberty_demanglers[];
+
+extern char *
+cplus_demangle PARAMS ((const char *mangled, int options));
+
+extern int
+cplus_demangle_opname PARAMS ((const char *opname, char *result, int options));
+
+extern const char *
+cplus_mangle_opname PARAMS ((const char *opname, int options));
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling PARAMS ((int ch));
+
+extern enum demangling_styles
+cplus_demangle_set_style PARAMS ((enum demangling_styles style));
+
+extern enum demangling_styles
+cplus_demangle_name_to_style PARAMS ((const char *name));
+
+/* V3 ABI demangling entry points, defined in cp-demangle.c. */
+extern char*
+cplus_demangle_v3 PARAMS ((const char* mangled, int options));
+
+extern char*
+java_demangle_v3 PARAMS ((const char* mangled));
+
+
+enum gnu_v3_ctor_kinds {
+ gnu_v3_complete_object_ctor = 1,
+ gnu_v3_base_object_ctor,
+ gnu_v3_complete_object_allocating_ctor
+};
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_ctor_kinds' value indicating what kind of constructor
+ it is. */
+extern enum gnu_v3_ctor_kinds
+ is_gnu_v3_mangled_ctor PARAMS ((const char *name));
+
+
+enum gnu_v3_dtor_kinds {
+ gnu_v3_deleting_dtor = 1,
+ gnu_v3_complete_object_dtor,
+ gnu_v3_base_object_dtor
+};
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_dtor_kinds' value, indicating what kind of destructor
+ it is. */
+extern enum gnu_v3_dtor_kinds
+ is_gnu_v3_mangled_dtor PARAMS ((const char *name));
+
+/* The V3 demangler works in two passes. The first pass builds a tree
+ representation of the mangled name, and the second pass turns the
+ tree representation into a demangled string. Here we define an
+ interface to permit a caller to build their own tree
+ representation, which they can pass to the demangler to get a
+ demangled string. This can be used to canonicalize user input into
+ something which the demangler might output. It could also be used
+ by other demanglers in the future. */
+
+/* These are the component types which may be found in the tree. Many
+ component types have one or two subtrees, referred to as left and
+ right (a component type with only one subtree puts it in the left
+ subtree). */
+
+enum demangle_component_type
+{
+ /* A name, with a length and a pointer to a string. */
+ DEMANGLE_COMPONENT_NAME,
+ /* A qualified name. The left subtree is a class or namespace or
+ some such thing, and the right subtree is a name qualified by
+ that class. */
+ DEMANGLE_COMPONENT_QUAL_NAME,
+ /* A local name. The left subtree describes a function, and the
+ right subtree is a name which is local to that function. */
+ DEMANGLE_COMPONENT_LOCAL_NAME,
+ /* A typed name. The left subtree is a name, and the right subtree
+ describes that name as a function. */
+ DEMANGLE_COMPONENT_TYPED_NAME,
+ /* A template. The left subtree is a template name, and the right
+ subtree is a template argument list. */
+ DEMANGLE_COMPONENT_TEMPLATE,
+ /* A template parameter. This holds a number, which is the template
+ parameter index. */
+ DEMANGLE_COMPONENT_TEMPLATE_PARAM,
+ /* A constructor. This holds a name and the kind of
+ constructor. */
+ DEMANGLE_COMPONENT_CTOR,
+ /* A destructor. This holds a name and the kind of destructor. */
+ DEMANGLE_COMPONENT_DTOR,
+ /* A vtable. This has one subtree, the type for which this is a
+ vtable. */
+ DEMANGLE_COMPONENT_VTABLE,
+ /* A VTT structure. This has one subtree, the type for which this
+ is a VTT. */
+ DEMANGLE_COMPONENT_VTT,
+ /* A construction vtable. The left subtree is the type for which
+ this is a vtable, and the right subtree is the derived type for
+ which this vtable is built. */
+ DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ /* A typeinfo structure. This has one subtree, the type for which
+ this is the tpeinfo structure. */
+ DEMANGLE_COMPONENT_TYPEINFO,
+ /* A typeinfo name. This has one subtree, the type for which this
+ is the typeinfo name. */
+ DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ /* A typeinfo function. This has one subtree, the type for which
+ this is the tpyeinfo function. */
+ DEMANGLE_COMPONENT_TYPEINFO_FN,
+ /* A thunk. This has one subtree, the name for which this is a
+ thunk. */
+ DEMANGLE_COMPONENT_THUNK,
+ /* A virtual thunk. This has one subtree, the name for which this
+ is a virtual thunk. */
+ DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ /* A covariant thunk. This has one subtree, the name for which this
+ is a covariant thunk. */
+ DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ /* A Java class. This has one subtree, the type. */
+ DEMANGLE_COMPONENT_JAVA_CLASS,
+ /* A guard variable. This has one subtree, the name for which this
+ is a guard variable. */
+ DEMANGLE_COMPONENT_GUARD,
+ /* A reference temporary. This has one subtree, the name for which
+ this is a temporary. */
+ DEMANGLE_COMPONENT_REFTEMP,
+ /* A standard substitution. This holds the name of the
+ substitution. */
+ DEMANGLE_COMPONENT_SUB_STD,
+ /* The restrict qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT,
+ /* The volatile qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE,
+ /* The const qualifier. The one subtree is the type which is being
+ qualified. */
+ DEMANGLE_COMPONENT_CONST,
+ /* The restrict qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT_THIS,
+ /* The volatile qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE_THIS,
+ /* The const qualifier modifying a member function. The one subtree
+ is the type which is being qualified. */
+ DEMANGLE_COMPONENT_CONST_THIS,
+ /* A vendor qualifier. The left subtree is the type which is being
+ qualified, and the right subtree is the name of the
+ qualifier. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ /* A pointer. The one subtree is the type which is being pointed
+ to. */
+ DEMANGLE_COMPONENT_POINTER,
+ /* A reference. The one subtree is the type which is being
+ referenced. */
+ DEMANGLE_COMPONENT_REFERENCE,
+ /* A complex type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_COMPLEX,
+ /* An imaginary type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_IMAGINARY,
+ /* A builtin type. This holds the builtin type information. */
+ DEMANGLE_COMPONENT_BUILTIN_TYPE,
+ /* A vendor's builtin type. This holds the name of the type. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE,
+ /* A function type. The left subtree is the return type. The right
+ subtree is a list of ARGLIST nodes. Either or both may be
+ NULL. */
+ DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ /* An array type. The left subtree is the dimension, which may be
+ NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
+ expression. The right subtree is the element type. */
+ DEMANGLE_COMPONENT_ARRAY_TYPE,
+ /* A pointer to member type. The left subtree is the class type,
+ and the right subtree is the member type. CV-qualifiers appear
+ on the latter. */
+ DEMANGLE_COMPONENT_PTRMEM_TYPE,
+ /* An argument list. The left subtree is the current argument, and
+ the right subtree is either NULL or another ARGLIST node. */
+ DEMANGLE_COMPONENT_ARGLIST,
+ /* A template argument list. The left subtree is the current
+ template argument, and the right subtree is either NULL or
+ another TEMPLATE_ARGLIST node. */
+ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+ /* An operator. This holds information about a standard
+ operator. */
+ DEMANGLE_COMPONENT_OPERATOR,
+ /* An extended operator. This holds the number of arguments, and
+ the name of the extended operator. */
+ DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
+ /* A typecast, represented as a unary operator. The one subtree is
+ the type to which the argument should be cast. */
+ DEMANGLE_COMPONENT_CAST,
+ /* A unary expression. The left subtree is the operator, and the
+ right subtree is the single argument. */
+ DEMANGLE_COMPONENT_UNARY,
+ /* A binary expression. The left subtree is the operator, and the
+ right subtree is a BINARY_ARGS. */
+ DEMANGLE_COMPONENT_BINARY,
+ /* Arguments to a binary expression. The left subtree is the first
+ argument, and the right subtree is the second argument. */
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ /* A trinary expression. The left subtree is the operator, and the
+ right subtree is a TRINARY_ARG1. */
+ DEMANGLE_COMPONENT_TRINARY,
+ /* Arguments to a trinary expression. The left subtree is the first
+ argument, and the right subtree is a TRINARY_ARG2. */
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ /* More arguments to a trinary expression. The left subtree is the
+ second argument, and the right subtree is the third argument. */
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ /* A literal. The left subtree is the type, and the right subtree
+ is the value, represented as a DEMANGLE_COMPONENT_NAME. */
+ DEMANGLE_COMPONENT_LITERAL,
+ /* A negative literal. Like LITERAL, but the value is negated.
+ This is a minor hack: the NAME used for LITERAL points directly
+ to the mangled string, but since negative numbers are mangled
+ using 'n' instead of '-', we want a way to indicate a negative
+ number which involves neither modifying the mangled string nor
+ allocating a new copy of the literal in memory. */
+ DEMANGLE_COMPONENT_LITERAL_NEG
+};
+
+/* Types which are only used internally. */
+
+struct demangle_operator_info;
+struct demangle_builtin_type_info;
+
+/* A node in the tree representation is an instance of a struct
+ demangle_component. Note that the field names of the struct are
+ not well protected against macros defined by the file including
+ this one. We can fix this if it ever becomes a problem. */
+
+struct demangle_component
+{
+ /* The type of this component. */
+ enum demangle_component_type type;
+
+ union
+ {
+ /* For DEMANGLE_COMPONENT_NAME. */
+ struct
+ {
+ /* A pointer to the name (which need not NULL terminated) and
+ its length. */
+ const char *s;
+ int len;
+ } s_name;
+
+ /* For DEMANGLE_COMPONENT_OPERATOR. */
+ struct
+ {
+ /* Operator. */
+ const struct demangle_operator_info *op;
+ } s_operator;
+
+ /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+ struct
+ {
+ /* Number of arguments. */
+ int args;
+ /* Name. */
+ struct demangle_component *name;
+ } s_extended_operator;
+
+ /* For DEMANGLE_COMPONENT_CTOR. */
+ struct
+ {
+ /* Kind of constructor. */
+ enum gnu_v3_ctor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_ctor;
+
+ /* For DEMANGLE_COMPONENT_DTOR. */
+ struct
+ {
+ /* Kind of destructor. */
+ enum gnu_v3_dtor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_dtor;
+
+ /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
+ struct
+ {
+ /* Builtin type. */
+ const struct demangle_builtin_type_info *type;
+ } s_builtin;
+
+ /* For DEMANGLE_COMPONENT_SUB_STD. */
+ struct
+ {
+ /* Standard substitution string. */
+ const char* string;
+ /* Length of string. */
+ int len;
+ } s_string;
+
+ /* For DEMANGLE_COMPONENT_TEMPLATE_PARAM. */
+ struct
+ {
+ /* Template parameter index. */
+ long number;
+ } s_number;
+
+ /* For other types. */
+ struct
+ {
+ /* Left (or only) subtree. */
+ struct demangle_component *left;
+ /* Right subtree. */
+ struct demangle_component *right;
+ } s_binary;
+
+ } u;
+};
+
+/* People building mangled trees are expected to allocate instances of
+ struct demangle_component themselves. They can then call one of
+ the following functions to fill them in. */
+
+/* Fill in most component types with a left subtree and a right
+ subtree. Returns non-zero on success, zero on failure, such as an
+ unrecognized or inappropriate component type. */
+
+extern int
+cplus_demangle_fill_component PARAMS ((struct demangle_component *fill,
+ enum demangle_component_type,
+ struct demangle_component *left,
+ struct demangle_component *right));
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_name PARAMS ((struct demangle_component *fill,
+ const char *, int));
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
+ builtin type (e.g., "int", etc.). Returns non-zero on success,
+ zero if the type is not recognized. */
+
+extern int
+cplus_demangle_fill_builtin_type PARAMS ((struct demangle_component *fill,
+ const char *typename));
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
+ operator and the number of arguments which it takes (the latter is
+ used to disambiguate operators which can be both binary and unary,
+ such as '-'). Returns non-zero on success, zero if the operator is
+ not recognized. */
+
+extern int
+cplus_demangle_fill_operator PARAMS ((struct demangle_component *fill,
+ const char *opname, int args));
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
+ number of arguments and the name. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_extended_operator PARAMS ((struct demangle_component *fill,
+ int numargs,
+ struct demangle_component *nm));
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_ctor PARAMS ((struct demangle_component *fill,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name));
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_dtor PARAMS ((struct demangle_component *fill,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name));
+
+/* This function translates a mangled name into a struct
+ demangle_component tree. The first argument is the mangled name.
+ The second argument is DMGL_* options. This returns a pointer to a
+ tree on success, or NULL on failure. On success, the third
+ argument is set to a block of memory allocated by malloc. This
+ block should be passed to free when the tree is no longer
+ needed. */
+
+extern struct demangle_component *
+cplus_demangle_v3_components PARAMS ((const char *mangled,
+ int options,
+ void **mem));
+
+/* This function takes a struct demangle_component tree and returns
+ the corresponding demangled string. The first argument is DMGL_*
+ options. The second is the tree to demangle. The third is a guess
+ at the length of the demangled string, used to initially allocate
+ the return buffer. The fourth is a pointer to a size_t. On
+ success, this function returns a buffer allocated by malloc(), and
+ sets the size_t pointed to by the fourth argument to the size of
+ the allocated buffer (not the length of the returned string). On
+ failure, this function returns NULL, and sets the size_t pointed to
+ by the fourth argument to 0 for an invalid tree, or to 1 for a
+ memory allocation error. */
+
+extern char *
+cplus_demangle_print PARAMS ((int options,
+ const struct demangle_component *tree,
+ int estimated_length,
+ size_t *p_allocated_size));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* DEMANGLE_H */
diff --git a/contrib/gdb/include/dis-asm.h b/contrib/gdb/include/dis-asm.h
new file mode 100644
index 0000000..3670c51
--- /dev/null
+++ b/contrib/gdb/include/dis-asm.h
@@ -0,0 +1,317 @@
+/* Interface between the opcode library and its callers.
+
+ Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Written by Cygnus Support, 1993.
+
+ The opcode library (libopcodes.a) provides instruction decoders for
+ a large variety of instruction sets, callable with an identical
+ interface, for making instruction-processing programs more independent
+ of the instruction set being processed. */
+
+#ifndef DIS_ASM_H
+#define DIS_ASM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "bfd.h"
+
+typedef int (*fprintf_ftype) (void *, const char*, ...);
+
+enum dis_insn_type {
+ dis_noninsn, /* Not a valid instruction */
+ dis_nonbranch, /* Not a branch instruction */
+ dis_branch, /* Unconditional branch */
+ dis_condbranch, /* Conditional branch */
+ dis_jsr, /* Jump to subroutine */
+ dis_condjsr, /* Conditional jump to subroutine */
+ dis_dref, /* Data reference instruction */
+ dis_dref2 /* Two data references in instruction */
+};
+
+/* This struct is passed into the instruction decoding routine,
+ and is passed back out into each callback. The various fields are used
+ for conveying information from your main routine into your callbacks,
+ for passing information into the instruction decoders (such as the
+ addresses of the callback functions), or for passing information
+ back from the instruction decoders to their callers.
+
+ It must be initialized before it is first passed; this can be done
+ by hand, or using one of the initialization macros below. */
+
+typedef struct disassemble_info {
+ fprintf_ftype fprintf_func;
+ void *stream;
+ void *application_data;
+
+ /* Target description. We could replace this with a pointer to the bfd,
+ but that would require one. There currently isn't any such requirement
+ so to avoid introducing one we record these explicitly. */
+ /* The bfd_flavour. This can be bfd_target_unknown_flavour. */
+ enum bfd_flavour flavour;
+ /* The bfd_arch value. */
+ enum bfd_architecture arch;
+ /* The bfd_mach value. */
+ unsigned long mach;
+ /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */
+ enum bfd_endian endian;
+ /* An arch/mach-specific bitmask of selected instruction subsets, mainly
+ for processors with run-time-switchable instruction sets. The default,
+ zero, means that there is no constraint. CGEN-based opcodes ports
+ may use ISA_foo masks. */
+ unsigned long insn_sets;
+
+ /* Some targets need information about the current section to accurately
+ display insns. If this is NULL, the target disassembler function
+ will have to make its best guess. */
+ asection *section;
+
+ /* An array of pointers to symbols either at the location being disassembled
+ or at the start of the function being disassembled. The array is sorted
+ so that the first symbol is intended to be the one used. The others are
+ present for any misc. purposes. This is not set reliably, but if it is
+ not NULL, it is correct. */
+ asymbol **symbols;
+ /* Number of symbols in array. */
+ int num_symbols;
+
+ /* For use by the disassembler.
+ The top 16 bits are reserved for public use (and are documented here).
+ The bottom 16 bits are for the internal use of the disassembler. */
+ unsigned long flags;
+#define INSN_HAS_RELOC 0x80000000
+ void *private_data;
+
+ /* Function used to get bytes to disassemble. MEMADDR is the
+ address of the stuff to be disassembled, MYADDR is the address to
+ put the bytes in, and LENGTH is the number of bytes to read.
+ INFO is a pointer to this struct.
+ Returns an errno value or 0 for success. */
+ int (*read_memory_func)
+ (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+ struct disassemble_info *info);
+
+ /* Function which should be called if we get an error that we can't
+ recover from. STATUS is the errno value from read_memory_func and
+ MEMADDR is the address that we were trying to read. INFO is a
+ pointer to this struct. */
+ void (*memory_error_func)
+ (int status, bfd_vma memaddr, struct disassemble_info *info);
+
+ /* Function called to print ADDR. */
+ void (*print_address_func)
+ (bfd_vma addr, struct disassemble_info *info);
+
+ /* Function called to determine if there is a symbol at the given ADDR.
+ If there is, the function returns 1, otherwise it returns 0.
+ This is used by ports which support an overlay manager where
+ the overlay number is held in the top part of an address. In
+ some circumstances we want to include the overlay number in the
+ address, (normally because there is a symbol associated with
+ that address), but sometimes we want to mask out the overlay bits. */
+ int (* symbol_at_address_func)
+ (bfd_vma addr, struct disassemble_info * info);
+
+ /* Function called to check if a SYMBOL is can be displayed to the user.
+ This is used by some ports that want to hide special symbols when
+ displaying debugging outout. */
+ bfd_boolean (* symbol_is_valid)
+ (asymbol *, struct disassemble_info * info);
+
+ /* These are for buffer_read_memory. */
+ bfd_byte *buffer;
+ bfd_vma buffer_vma;
+ unsigned int buffer_length;
+
+ /* This variable may be set by the instruction decoder. It suggests
+ the number of bytes objdump should display on a single line. If
+ the instruction decoder sets this, it should always set it to
+ the same value in order to get reasonable looking output. */
+ int bytes_per_line;
+
+ /* The next two variables control the way objdump displays the raw data. */
+ /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
+ /* output will look like this:
+ 00: 00000000 00000000
+ with the chunks displayed according to "display_endian". */
+ int bytes_per_chunk;
+ enum bfd_endian display_endian;
+
+ /* Number of octets per incremented target address
+ Normally one, but some DSPs have byte sizes of 16 or 32 bits. */
+ unsigned int octets_per_byte;
+
+ /* Results from instruction decoders. Not all decoders yet support
+ this information. This info is set each time an instruction is
+ decoded, and is only valid for the last such instruction.
+
+ To determine whether this decoder supports this information, set
+ insn_info_valid to 0, decode an instruction, then check it. */
+
+ char insn_info_valid; /* Branch info has been set. */
+ char branch_delay_insns; /* How many sequential insn's will run before
+ a branch takes effect. (0 = normal) */
+ char data_size; /* Size of data reference in insn, in bytes */
+ enum dis_insn_type insn_type; /* Type of instruction */
+ bfd_vma target; /* Target address of branch or dref, if known;
+ zero if unknown. */
+ bfd_vma target2; /* Second target address for dref2 */
+
+ /* Command line options specific to the target disassembler. */
+ char * disassembler_options;
+
+} disassemble_info;
+
+
+/* Standard disassemblers. Disassemble one instruction at the given
+ target address. Return number of octets processed. */
+typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
+
+extern int print_insn_big_mips (bfd_vma, disassemble_info *);
+extern int print_insn_little_mips (bfd_vma, disassemble_info *);
+extern int print_insn_i386 (bfd_vma, disassemble_info *);
+extern int print_insn_i386_att (bfd_vma, disassemble_info *);
+extern int print_insn_i386_intel (bfd_vma, disassemble_info *);
+extern int print_insn_ia64 (bfd_vma, disassemble_info *);
+extern int print_insn_i370 (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc11 (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc12 (bfd_vma, disassemble_info *);
+extern int print_insn_m68k (bfd_vma, disassemble_info *);
+extern int print_insn_z8001 (bfd_vma, disassemble_info *);
+extern int print_insn_z8002 (bfd_vma, disassemble_info *);
+extern int print_insn_h8300 (bfd_vma, disassemble_info *);
+extern int print_insn_h8300h (bfd_vma, disassemble_info *);
+extern int print_insn_h8300s (bfd_vma, disassemble_info *);
+extern int print_insn_h8500 (bfd_vma, disassemble_info *);
+extern int print_insn_alpha (bfd_vma, disassemble_info *);
+extern int print_insn_big_arm (bfd_vma, disassemble_info *);
+extern int print_insn_little_arm (bfd_vma, disassemble_info *);
+extern int print_insn_sparc (bfd_vma, disassemble_info *);
+extern int print_insn_big_a29k (bfd_vma, disassemble_info *);
+extern int print_insn_little_a29k (bfd_vma, disassemble_info *);
+extern int print_insn_avr (bfd_vma, disassemble_info *);
+extern int print_insn_d10v (bfd_vma, disassemble_info *);
+extern int print_insn_d30v (bfd_vma, disassemble_info *);
+extern int print_insn_dlx (bfd_vma, disassemble_info *);
+extern int print_insn_fr30 (bfd_vma, disassemble_info *);
+extern int print_insn_hppa (bfd_vma, disassemble_info *);
+extern int print_insn_i860 (bfd_vma, disassemble_info *);
+extern int print_insn_i960 (bfd_vma, disassemble_info *);
+extern int print_insn_ip2k (bfd_vma, disassemble_info *);
+extern int print_insn_m32r (bfd_vma, disassemble_info *);
+extern int print_insn_m88k (bfd_vma, disassemble_info *);
+extern int print_insn_mcore (bfd_vma, disassemble_info *);
+extern int print_insn_mmix (bfd_vma, disassemble_info *);
+extern int print_insn_mn10200 (bfd_vma, disassemble_info *);
+extern int print_insn_mn10300 (bfd_vma, disassemble_info *);
+extern int print_insn_msp430 (bfd_vma, disassemble_info *);
+extern int print_insn_ns32k (bfd_vma, disassemble_info *);
+extern int print_insn_openrisc (bfd_vma, disassemble_info *);
+extern int print_insn_big_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_little_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_pdp11 (bfd_vma, disassemble_info *);
+extern int print_insn_pj (bfd_vma, disassemble_info *);
+extern int print_insn_big_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_little_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_rs6000 (bfd_vma, disassemble_info *);
+extern int print_insn_s390 (bfd_vma, disassemble_info *);
+extern int print_insn_sh (bfd_vma, disassemble_info *);
+extern int print_insn_tic30 (bfd_vma, disassemble_info *);
+extern int print_insn_tic4x (bfd_vma, disassemble_info *);
+extern int print_insn_tic54x (bfd_vma, disassemble_info *);
+extern int print_insn_tic80 (bfd_vma, disassemble_info *);
+extern int print_insn_v850 (bfd_vma, disassemble_info *);
+extern int print_insn_vax (bfd_vma, disassemble_info *);
+extern int print_insn_w65 (bfd_vma, disassemble_info *);
+extern int print_insn_xstormy16 (bfd_vma, disassemble_info *);
+extern int print_insn_xtensa (bfd_vma, disassemble_info *);
+extern int print_insn_sh64 (bfd_vma, disassemble_info *);
+extern int print_insn_sh64x_media (bfd_vma, disassemble_info *);
+extern int print_insn_frv (bfd_vma, disassemble_info *);
+extern int print_insn_iq2000 (bfd_vma, disassemble_info *);
+
+extern disassembler_ftype arc_get_disassembler (void *);
+extern disassembler_ftype cris_get_disassembler (bfd *);
+
+extern void print_mips_disassembler_options (FILE *);
+extern void print_ppc_disassembler_options (FILE *);
+extern void print_arm_disassembler_options (FILE *);
+extern void parse_arm_disassembler_option (char *);
+extern int get_arm_regname_num_options (void);
+extern int set_arm_regname_option (int);
+extern int get_arm_regnames (int, const char **, const char **, const char ***);
+extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
+
+/* Fetch the disassembler for a given BFD, if that support is available. */
+extern disassembler_ftype disassembler (bfd *);
+
+/* Amend the disassemble_info structure as necessary for the target architecture.
+ Should only be called after initialising the info->arch field. */
+extern void disassemble_init_for_target (struct disassemble_info * info);
+
+/* Document any target specific options available from the disassembler. */
+extern void disassembler_usage (FILE *);
+
+
+/* This block of definitions is for particular callers who read instructions
+ into a buffer before calling the instruction decoder. */
+
+/* Here is a function which callers may wish to use for read_memory_func.
+ It gets bytes from a buffer. */
+extern int buffer_read_memory
+ (bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *);
+
+/* This function goes with buffer_read_memory.
+ It prints a message using info->fprintf_func and info->stream. */
+extern void perror_memory (int, bfd_vma, struct disassemble_info *);
+
+
+/* Just print the address in hex. This is included for completeness even
+ though both GDB and objdump provide their own (to print symbolic
+ addresses). */
+extern void generic_print_address
+ (bfd_vma, struct disassemble_info *);
+
+/* Always true. */
+extern int generic_symbol_at_address
+ (bfd_vma, struct disassemble_info *);
+
+/* Also always true. */
+extern bfd_boolean generic_symbol_is_valid
+ (asymbol *, struct disassemble_info *);
+
+/* Method to initialize a disassemble_info struct. This should be
+ called by all applications creating such a struct. */
+extern void init_disassemble_info (struct disassemble_info *info, void *stream,
+ fprintf_ftype fprintf_func);
+
+/* For compatibility with existing code. */
+#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \
+ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
+#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
+ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! defined (DIS_ASM_H) */
diff --git a/contrib/gdb/include/floatformat.h b/contrib/gdb/include/floatformat.h
new file mode 100644
index 0000000..a8244ad
--- /dev/null
+++ b/contrib/gdb/include/floatformat.h
@@ -0,0 +1,133 @@
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+ Copyright 1991, 1994, 1995, 1997, 2000, 2003 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. */
+
+#if !defined (FLOATFORMAT_H)
+#define FLOATFORMAT_H 1
+
+#include "ansidecl.h"
+
+/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the
+ bytes are concatenated according to the byteorder flag, then each of those
+ fields is contiguous. We number the bits with 0 being the most significant
+ (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field
+ contains with the *_start and *_len fields. */
+
+/* What is the order of the bytes. */
+
+enum floatformat_byteorders {
+
+ /* Standard little endian byte order.
+ EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */
+
+ floatformat_little,
+
+ /* Standard big endian byte order.
+ EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */
+
+ floatformat_big,
+
+ /* Little endian byte order but big endian word order.
+ EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */
+
+ floatformat_littlebyte_bigword
+
+};
+
+enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no };
+
+struct floatformat
+{
+ enum floatformat_byteorders byteorder;
+ unsigned int totalsize; /* Total size of number in bits */
+
+ /* Sign bit is always one bit long. 1 means negative, 0 means positive. */
+ unsigned int sign_start;
+
+ unsigned int exp_start;
+ unsigned int exp_len;
+ /* Bias added to a "true" exponent to form the biased exponent. It
+ is intentionally signed as, otherwize, -exp_bias can turn into a
+ very large number (e.g., given the exp_bias of 0x3fff and a 64
+ bit long, the equation (long)(1 - exp_bias) evaluates to
+ 4294950914) instead of -16382). */
+ int exp_bias;
+ /* Exponent value which indicates NaN. This is the actual value stored in
+ the float, not adjusted by the exp_bias. This usually consists of all
+ one bits. */
+ unsigned int exp_nan;
+
+ unsigned int man_start;
+ unsigned int man_len;
+
+ /* Is the integer bit explicit or implicit? */
+ enum floatformat_intbit intbit;
+
+ /* Internal name for debugging. */
+ const char *name;
+
+ /* Validator method. */
+ int (*is_valid) PARAMS ((const struct floatformat *fmt, const char *from));
+};
+
+/* floatformats for IEEE single and double, big and little endian. */
+
+extern const struct floatformat floatformat_ieee_single_big;
+extern const struct floatformat floatformat_ieee_single_little;
+extern const struct floatformat floatformat_ieee_double_big;
+extern const struct floatformat floatformat_ieee_double_little;
+
+/* floatformat for ARM IEEE double, little endian bytes and big endian words */
+
+extern const struct floatformat floatformat_ieee_double_littlebyte_bigword;
+
+/* floatformats for various extendeds. */
+
+extern const struct floatformat floatformat_i387_ext;
+extern const struct floatformat floatformat_m68881_ext;
+extern const struct floatformat floatformat_i960_ext;
+extern const struct floatformat floatformat_m88110_ext;
+extern const struct floatformat floatformat_m88110_harris_ext;
+extern const struct floatformat floatformat_arm_ext_big;
+extern const struct floatformat floatformat_arm_ext_littlebyte_bigword;
+/* IA-64 Floating Point register spilt into memory. */
+extern const struct floatformat floatformat_ia64_spill_big;
+extern const struct floatformat floatformat_ia64_spill_little;
+extern const struct floatformat floatformat_ia64_quad_big;
+extern const struct floatformat floatformat_ia64_quad_little;
+
+/* Convert from FMT to a double.
+ FROM is the address of the extended float.
+ Store the double in *TO. */
+
+extern void
+floatformat_to_double PARAMS ((const struct floatformat *, const char *, double *));
+
+/* The converse: convert the double *FROM to FMT
+ and store where TO points. */
+
+extern void
+floatformat_from_double PARAMS ((const struct floatformat *,
+ const double *, char *));
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT. */
+
+extern int
+floatformat_is_valid PARAMS ((const struct floatformat *fmt, const char *from));
+
+#endif /* defined (FLOATFORMAT_H) */
diff --git a/contrib/gdb/include/fopen-bin.h b/contrib/gdb/include/fopen-bin.h
new file mode 100644
index 0000000..b868f63
--- /dev/null
+++ b/contrib/gdb/include/fopen-bin.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for "binary" systems, where text and binary files are
+ different. An example is Mess-Dose. Many Unix systems could also
+ cope with a "b" in the string, indicating binary files, but some reject this
+ (and thereby don't conform to ANSI C, but what else is new?).
+
+ This file is designed for inclusion by host-dependent .h files. No
+ user application should include it directly, since that would make
+ the application unable to be configured for both "same" and "binary"
+ variant systems. */
+
+#define FOPEN_RB "rb"
+#define FOPEN_WB "wb"
+#define FOPEN_AB "ab"
+#define FOPEN_RUB "r+b"
+#define FOPEN_WUB "w+b"
+#define FOPEN_AUB "a+b"
+
+#define FOPEN_RT "r"
+#define FOPEN_WT "w"
+#define FOPEN_AT "a"
+#define FOPEN_RUT "r+"
+#define FOPEN_WUT "w+"
+#define FOPEN_AUT "a+"
diff --git a/contrib/gdb/include/fopen-same.h b/contrib/gdb/include/fopen-same.h
new file mode 100644
index 0000000..0f37529
--- /dev/null
+++ b/contrib/gdb/include/fopen-same.h
@@ -0,0 +1,27 @@
+/* Macros for the 'type' part of an fopen, freopen or fdopen.
+
+ <Read|Write>[Update]<Binary file|text file>
+
+ This version is for "same" systems, where text and binary files are
+ the same. An example is Unix. Many Unix systems could also add a
+ "b" to the string, indicating binary files, but some reject this
+ (and thereby don't conform to ANSI C, but what else is new?).
+
+ This file is designed for inclusion by host-dependent .h files. No
+ user application should include it directly, since that would make
+ the application unable to be configured for both "same" and "binary"
+ variant systems. */
+
+#define FOPEN_RB "r"
+#define FOPEN_WB "w"
+#define FOPEN_AB "a"
+#define FOPEN_RUB "r+"
+#define FOPEN_WUB "w+"
+#define FOPEN_AUB "a+"
+
+#define FOPEN_RT "r"
+#define FOPEN_WT "w"
+#define FOPEN_AT "a"
+#define FOPEN_RUT "r+"
+#define FOPEN_WUT "w+"
+#define FOPEN_AUT "a+"
diff --git a/contrib/gdb/include/gdbm.h b/contrib/gdb/include/gdbm.h
new file mode 100644
index 0000000..3ebc26d
--- /dev/null
+++ b/contrib/gdb/include/gdbm.h
@@ -0,0 +1,91 @@
+/* GNU DBM - DataBase Manager include file
+ Copyright 1989, 1991 Free Software Foundation, Inc.
+ Written by Philip A. Nelson.
+
+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. */
+
+/* You may contact the author by:
+ e-mail: phil@wwu.edu
+ us-mail: Philip A. Nelson
+ Computer Science Department
+ Western Washington University
+ Bellingham, WA 98226
+ phone: (206) 676-3035
+
+*************************************************************************/
+
+/* Parameters to gdbm_open for READERS, WRITERS, and WRITERS who
+ can create the database. */
+#define GDBM_READER 0
+#define GDBM_WRITER 1
+#define GDBM_WRCREAT 2
+#define GDBM_NEWDB 3
+
+/* Parameters to gdbm_store for simple insertion or replacement. */
+#define GDBM_INSERT 0
+#define GDBM_REPLACE 1
+
+
+/* The data and key structure. This structure is defined for compatibility. */
+typedef struct {
+ char *dptr;
+ int dsize;
+ } datum;
+
+
+/* The file information header. This is good enough for most applications. */
+typedef struct {int dummy[10];} *GDBM_FILE;
+
+
+/* These are the routines! */
+
+extern GDBM_FILE gdbm_open ();
+
+extern void gdbm_close ();
+
+extern datum gdbm_fetch ();
+
+extern int gdbm_store ();
+
+extern int gdbm_delete ();
+
+extern datum gdbm_firstkey ();
+
+extern datum gdbm_nextkey ();
+
+extern int gdbm_reorganize ();
+
+
+/* gdbm sends back the following error codes in the variable gdbm_errno. */
+typedef enum { NO_ERROR,
+ MALLOC_ERROR,
+ BLOCK_SIZE_ERROR,
+ FILE_OPEN_ERROR,
+ FILE_WRITE_ERROR,
+ FILE_SEEK_ERROR,
+ FILE_READ_ERROR,
+ BAD_MAGIC_NUMBER,
+ EMPTY_DATABASE,
+ CANT_BE_READER,
+ CANT_BE_WRITER,
+ READER_CANT_RECOVER,
+ READER_CANT_DELETE,
+ READER_CANT_STORE,
+ READER_CANT_REORGANIZE,
+ UNKNOWN_UPDATE,
+ ITEM_NOT_FOUND,
+ REORGANIZE_FAILED,
+ CANNOT_REPLACE}
+ gdbm_error;
diff --git a/contrib/gdb/include/getopt.h b/contrib/gdb/include/getopt.h
new file mode 100644
index 0000000..a99a229
--- /dev/null
+++ b/contrib/gdb/include/getopt.h
@@ -0,0 +1,144 @@
+/* Declarations for getopt.
+ Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000,
+ 2002 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
+
+ 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, 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 _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ to find the declaration so provide a fully prototyped one. If it
+ is 1, we found it so don't provide any declaration at all. */
+#if !HAVE_DECL_GETOPT
+#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in unistd.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else
+#ifndef __cplusplus
+extern int getopt ();
+#endif /* __cplusplus */
+#endif
+#endif /* !HAVE_DECL_GETOPT */
+
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* getopt.h */
diff --git a/contrib/gdb/include/hp-symtab.h b/contrib/gdb/include/hp-symtab.h
new file mode 100644
index 0000000..6267d55
--- /dev/null
+++ b/contrib/gdb/include/hp-symtab.h
@@ -0,0 +1,1866 @@
+/* Definitions and structures for reading debug symbols from the
+ native HP C compiler.
+
+ Written by the Center for Software Science at the University of Utah
+ and by Cygnus Support.
+
+ Copyright 1994, 1995, 1998, 1999, 2003 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef HP_SYMTAB_INCLUDED
+#define HP_SYMTAB_INCLUDED
+
+/* General information:
+
+ This header file defines and describes only the data structures
+ necessary to read debug symbols produced by the HP C compiler,
+ HP ANSI C++ compiler, and HP FORTRAN 90 compiler using the
+ SOM object file format.
+ (For a full description of the debug format, ftp hpux-symtab.h from
+ jaguar.cs.utah.edu:/dist).
+
+ Additional notes (Rich Title)
+ This file is a reverse-engineered version of a file called
+ "symtab.h" which exists internal to HP's Computer Languages Organization
+ in /CLO/Components/DDE/obj/som/symtab.h. Because HP's version of
+ the file is copyrighted and not distributed, it is necessary for
+ GDB to use the reverse-engineered version that follows.
+ Work was done by Cygnus to reverse-engineer the C subset of symtab.h.
+ The WDB project has extended this to also contain the C++
+ symbol definitions, the F90 symbol definitions,
+ and the DOC (debugging-optimized-code) symbol definitions.
+ In some cases (the C++ symbol definitions)
+ I have added internal documentation here that
+ goes beyond what is supplied in HP's symtab.h. If we someday
+ unify these files again, the extra comments should be merged back
+ into HP's symtab.h.
+
+ -------------------------------------------------------------------
+
+ Debug symbols are contained entirely within an unloadable space called
+ $DEBUG$. $DEBUG$ contains several subspaces which group related
+ debug symbols.
+
+ $GNTT$ contains information for global variables, types and contants.
+
+ $LNTT$ contains information for procedures (including nesting), scoping
+ information, local variables, types, and constants.
+
+ $SLT$ contains source line information so that code addresses may be
+ mapped to source lines.
+
+ $VT$ contains various strings and constants for named objects (variables,
+ typedefs, functions, etc). Strings are stored as null-terminated character
+ lists. Constants always begin on word boundaries. The first byte of
+ the VT must be zero (a null string).
+
+ $XT$ is not currently used by GDB.
+
+ Many structures within the subspaces point to other structures within
+ the same subspace, or to structures within a different subspace. These
+ pointers are represented as a structure index from the beginning of
+ the appropriate subspace. */
+
+/* Used to describe where a constant is stored. */
+enum location_type
+{
+ LOCATION_IMMEDIATE,
+ LOCATION_PTR,
+ LOCATION_VT,
+};
+
+/* Languages supported by this debug format. Within the data structures
+ this type is limited to 4 bits for a maximum of 16 languages. */
+enum hp_language
+{
+ HP_LANGUAGE_UNKNOWN,
+ HP_LANGUAGE_C,
+ HP_LANGUAGE_FORTRAN,
+ HP_LANGUAGE_F77 = HP_LANGUAGE_FORTRAN,
+ HP_LANGUAGE_PASCAL,
+ HP_LANGUAGE_MODCAL,
+ HP_LANGUAGE_COBOL,
+ HP_LANGUAGE_BASIC,
+ HP_LANGUAGE_ADA,
+ HP_LANGUAGE_CPLUSPLUS,
+ HP_LANGUAGE_DMPASCAL
+};
+
+
+/* Basic data types available in this debug format. Within the data
+ structures this type is limited to 5 bits for a maximum of 32 basic
+ data types. */
+enum hp_type
+{
+ HP_TYPE_UNDEFINED, /* 0 */
+ HP_TYPE_BOOLEAN, /* 1 */
+ HP_TYPE_CHAR, /* 2 */
+ HP_TYPE_INT, /* 3 */
+ HP_TYPE_UNSIGNED_INT, /* 4 */
+ HP_TYPE_REAL, /* 5 */
+ HP_TYPE_COMPLEX, /* 6 */
+ HP_TYPE_STRING200, /* 7 */
+ HP_TYPE_LONGSTRING200, /* 8 */
+ HP_TYPE_TEXT, /* 9 */
+ HP_TYPE_FLABEL, /* 10 */
+ HP_TYPE_FTN_STRING_SPEC, /* 11 */
+ HP_TYPE_MOD_STRING_SPEC, /* 12 */
+ HP_TYPE_PACKED_DECIMAL, /* 13 */
+ HP_TYPE_REAL_3000, /* 14 */
+ HP_TYPE_MOD_STRING_3000, /* 15 */
+ HP_TYPE_ANYPOINTER, /* 16 */
+ HP_TYPE_GLOBAL_ANYPOINTER, /* 17 */
+ HP_TYPE_LOCAL_ANYPOINTER, /* 18 */
+ HP_TYPE_COMPLEXS3000, /* 19 */
+ HP_TYPE_FTN_STRING_S300_COMPAT, /* 20 */
+ HP_TYPE_FTN_STRING_VAX_COMPAT, /* 21 */
+ HP_TYPE_BOOLEAN_S300_COMPAT, /* 22 */
+ HP_TYPE_BOOLEAN_VAX_COMPAT, /* 23 */
+ HP_TYPE_WIDE_CHAR, /* 24 */
+ HP_TYPE_LONG, /* 25 */
+ HP_TYPE_UNSIGNED_LONG, /* 26 */
+ HP_TYPE_DOUBLE, /* 27 */
+ HP_TYPE_TEMPLATE_ARG, /* 28 */
+ HP_TYPE_VOID /* 29 */
+};
+
+/* An immediate name and type table entry.
+
+ extension and immediate will always be one.
+ global will always be zero.
+ hp_type is the basic type this entry describes.
+ bitlength is the length in bits for the basic type. */
+struct dnttp_immediate
+{
+ unsigned int extension: 1;
+ unsigned int immediate: 1;
+ unsigned int global: 1;
+ unsigned int type: 5;
+ unsigned int bitlength: 24;
+};
+
+/* A nonimmediate name and type table entry.
+
+ extension will always be one.
+ immediate will always be zero.
+ if global is zero, this entry points into the LNTT
+ if global is one, this entry points into the GNTT
+ index is the index within the GNTT or LNTT for this entry. */
+struct dnttp_nonimmediate
+{
+ unsigned int extension: 1;
+ unsigned int immediate: 1;
+ unsigned int global: 1;
+ unsigned int index: 29;
+};
+
+/* A pointer to an entry in the GNTT and LNTT tables. It has two
+ forms depending on the type being described.
+
+ The immediate form is used for simple entries and is one
+ word.
+
+ The nonimmediate form is used for complex entries and contains
+ an index into the LNTT or GNTT which describes the entire type.
+
+ If a dnttpointer is -1, then it is a NIL entry. */
+
+#define DNTTNIL (-1)
+typedef union dnttpointer
+{
+ struct dnttp_immediate dntti;
+ struct dnttp_nonimmediate dnttp;
+ int word;
+} dnttpointer;
+
+/* An index into the source line table. As with dnttpointers, a sltpointer
+ of -1 indicates a NIL entry. */
+#define SLTNIL (-1)
+typedef int sltpointer;
+
+/* Index into DOC (= "Debugging Optimized Code") line table. */
+#define LTNIL (-1)
+typedef int ltpointer;
+
+/* Index into context table. */
+#define CTXTNIL (-1)
+typedef int ctxtpointer;
+
+/* Unsigned byte offset into the VT. */
+typedef unsigned int vtpointer;
+
+/* A DNTT entry (used within the GNTT and LNTT).
+
+ DNTT entries are variable sized objects, but are always a multiple
+ of 3 words (we call each group of 3 words a "block").
+
+ The first bit in each block is an extension bit. This bit is zero
+ for the first block of a DNTT entry. If the entry requires more
+ than one block, then this bit is set to one in all blocks after
+ the first one. */
+
+/* Each DNTT entry describes a particular debug symbol (beginning of
+ a source file, a function, variables, structures, etc.
+
+ The type of the DNTT entry is stored in the "kind" field within the
+ DNTT entry itself. */
+
+enum dntt_entry_type
+{
+ DNTT_TYPE_NIL = -1,
+ DNTT_TYPE_SRCFILE,
+ DNTT_TYPE_MODULE,
+ DNTT_TYPE_FUNCTION,
+ DNTT_TYPE_ENTRY,
+ DNTT_TYPE_BEGIN,
+ DNTT_TYPE_END,
+ DNTT_TYPE_IMPORT,
+ DNTT_TYPE_LABEL,
+ DNTT_TYPE_FPARAM,
+ DNTT_TYPE_SVAR,
+ DNTT_TYPE_DVAR,
+ DNTT_TYPE_HOLE1,
+ DNTT_TYPE_CONST,
+ DNTT_TYPE_TYPEDEF,
+ DNTT_TYPE_TAGDEF,
+ DNTT_TYPE_POINTER,
+ DNTT_TYPE_ENUM,
+ DNTT_TYPE_MEMENUM,
+ DNTT_TYPE_SET,
+ DNTT_TYPE_SUBRANGE,
+ DNTT_TYPE_ARRAY,
+ DNTT_TYPE_STRUCT,
+ DNTT_TYPE_UNION,
+ DNTT_TYPE_FIELD,
+ DNTT_TYPE_VARIANT,
+ DNTT_TYPE_FILE,
+ DNTT_TYPE_FUNCTYPE,
+ DNTT_TYPE_WITH,
+ DNTT_TYPE_COMMON,
+ DNTT_TYPE_COBSTRUCT,
+ DNTT_TYPE_XREF,
+ DNTT_TYPE_SA,
+ DNTT_TYPE_MACRO,
+ DNTT_TYPE_BLOCKDATA,
+ DNTT_TYPE_CLASS_SCOPE,
+ DNTT_TYPE_REFERENCE,
+ DNTT_TYPE_PTRMEM,
+ DNTT_TYPE_PTRMEMFUNC,
+ DNTT_TYPE_CLASS,
+ DNTT_TYPE_GENFIELD,
+ DNTT_TYPE_VFUNC,
+ DNTT_TYPE_MEMACCESS,
+ DNTT_TYPE_INHERITANCE,
+ DNTT_TYPE_FRIEND_CLASS,
+ DNTT_TYPE_FRIEND_FUNC,
+ DNTT_TYPE_MODIFIER,
+ DNTT_TYPE_OBJECT_ID,
+ DNTT_TYPE_MEMFUNC,
+ DNTT_TYPE_TEMPLATE,
+ DNTT_TYPE_TEMPLATE_ARG,
+ DNTT_TYPE_FUNC_TEMPLATE,
+ DNTT_TYPE_LINK,
+ DNTT_TYPE_DYN_ARRAY_DESC,
+ DNTT_TYPE_DESC_SUBRANGE,
+ DNTT_TYPE_BEGIN_EXT,
+ DNTT_TYPE_INLN,
+ DNTT_TYPE_INLN_LIST,
+ DNTT_TYPE_ALIAS,
+ DNTT_TYPE_DOC_FUNCTION,
+ DNTT_TYPE_DOC_MEMFUNC,
+ DNTT_TYPE_MAX
+};
+
+/* DNTT_TYPE_SRCFILE:
+
+ One DNTT_TYPE_SRCFILE symbol is output for the start of each source
+ file and at the begin and end of an included file. A DNTT_TYPE_SRCFILE
+ entry is also output before each DNTT_TYPE_FUNC symbol so that debuggers
+ can determine what file a function was defined in.
+
+ LANGUAGE describes the source file's language.
+
+ NAME points to an VT entry providing the source file's name.
+
+ Note the name used for DNTT_TYPE_SRCFILE entries are exactly as seen
+ by the compiler (ie they may be relative or absolute). C include files
+ via <> inclusion must use absolute paths.
+
+ ADDRESS points to an SLT entry from which line number and code locations
+ may be determined. */
+
+struct dntt_type_srcfile
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10; /* DNTT_TYPE_SRCFILE */
+ unsigned int language: 4;
+ unsigned int unused: 17;
+ vtpointer name;
+ sltpointer address;
+};
+
+/* DNTT_TYPE_MODULE:
+
+ A DNTT_TYPE_MODULE symbol is emitted for the start of a pascal
+ module or C source file. A module indicates a compilation unit
+ for name-scoping purposes; in that regard there should be
+ a 1-1 correspondence between GDB "symtab"'s and MODULE symbol records.
+
+ Each DNTT_TYPE_MODULE must have an associated DNTT_TYPE_END symbol.
+
+ NAME points to a VT entry providing the module's name. Note C
+ source files are considered nameless modules.
+
+ ALIAS point to a VT entry providing a secondary name.
+
+ ADDRESS points to an SLT entry from which line number and code locations
+ may be determined. */
+
+struct dntt_type_module
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10; /* DNTT_TYPE_MODULE */
+ unsigned int unused: 21;
+ vtpointer name;
+ vtpointer alias;
+ dnttpointer unused2;
+ sltpointer address;
+};
+
+/* DNTT_TYPE_FUNCTION,
+ DNTT_TYPE_ENTRY,
+ DNTT_TYPE_BLOCKDATA,
+ DNTT_TYPE_MEMFUNC:
+
+ A DNTT_TYPE_FUNCTION symbol is emitted for each function definition;
+ a DNTT_TYPE_ENTRY symbols is used for secondary entry points. Both
+ symbols used the dntt_type_function structure.
+ A DNTT_TYPE_BLOCKDATA symbol is emitted ...?
+ A DNTT_TYPE_MEMFUNC symbol is emitted for inlined member functions (C++).
+
+ Each of DNTT_TYPE_FUNCTION must have a matching DNTT_TYPE_END.
+
+ GLOBAL is nonzero if the function has global scope.
+
+ LANGUAGE describes the function's source language.
+
+ OPT_LEVEL describes the optimization level the function was compiled
+ with.
+
+ VARARGS is nonzero if the function uses varargs.
+
+ NAME points to a VT entry providing the function's name.
+
+ ALIAS points to a VT entry providing a secondary name for the function.
+
+ FIRSTPARAM points to a LNTT entry which describes the parameter list.
+
+ ADDRESS points to an SLT entry from which line number and code locations
+ may be determined.
+
+ ENTRYADDR is the memory address corresponding the function's entry point
+
+ RETVAL points to a LNTT entry describing the function's return value.
+
+ LOWADDR is the lowest memory address associated with this function.
+
+ HIADDR is the highest memory address associated with this function. */
+
+struct dntt_type_function
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10; /* DNTT_TYPE_FUNCTION,
+ DNTT_TYPE_ENTRY,
+ DNTT_TYPE_BLOCKDATA
+ or DNTT_TYPE_MEMFUNC */
+ unsigned int global: 1;
+ unsigned int language: 4;
+ unsigned int nest_level: 5;
+ unsigned int opt_level: 2;
+ unsigned int varargs: 1;
+ unsigned int lang_info: 4;
+ unsigned int inlined: 1;
+ unsigned int localalloc: 1;
+ unsigned int expansion: 1;
+ unsigned int unused: 1;
+ vtpointer name;
+ vtpointer alias;
+ dnttpointer firstparam;
+ sltpointer address;
+ CORE_ADDR entryaddr;
+ dnttpointer retval;
+ CORE_ADDR lowaddr;
+ CORE_ADDR hiaddr;
+};
+
+/* DNTT_TYPE_BEGIN:
+
+ A DNTT_TYPE_BEGIN symbol is emitted to begin a new nested scope.
+ Every DNTT_TYPE_BEGIN symbol must have a matching DNTT_TYPE_END symbol.
+
+ CLASSFLAG is nonzero if this is the beginning of a c++ class definition.
+
+ ADDRESS points to an SLT entry from which line number and code locations
+ may be determined. */
+
+struct dntt_type_begin
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int classflag: 1;
+ unsigned int unused: 20;
+ sltpointer address;
+};
+
+/* DNTT_TYPE_END:
+
+ A DNTT_TYPE_END symbol is emitted when closing a scope started by
+ a DNTT_TYPE_MODULE, DNTT_TYPE_FUNCTION, DNTT_TYPE_WITH,
+ DNTT_TYPE_COMMON, DNTT_TYPE_BEGIN, and DNTT_TYPE_CLASS_SCOPE symbols.
+
+ ENDKIND describes what type of scope the DNTT_TYPE_END is closing
+ (one of the above 6 kinds).
+
+ CLASSFLAG is nonzero if this is the end of a c++ class definition.
+
+ ADDRESS points to an SLT entry from which line number and code locations
+ may be determined.
+
+ BEGINSCOPE points to the LNTT entry which opened the scope. */
+
+struct dntt_type_end
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int endkind: 10;
+ unsigned int classflag: 1;
+ unsigned int unused: 10;
+ sltpointer address;
+ dnttpointer beginscope;
+};
+
+/* DNTT_TYPE_IMPORT is unused by GDB. */
+/* DNTT_TYPE_LABEL is unused by GDB. */
+
+/* DNTT_TYPE_FPARAM:
+
+ A DNTT_TYPE_FPARAM symbol is emitted for a function argument. When
+ chained together the symbols represent an argument list for a function.
+
+ REGPARAM is nonzero if this parameter was passed in a register.
+
+ INDIRECT is nonzero if this parameter is a pointer to the parameter
+ (pass by reference or pass by value for large items).
+
+ LONGADDR is nonzero if the parameter is a 64bit pointer.
+
+ NAME is a pointer into the VT for the parameter's name.
+
+ LOCATION describes where the parameter is stored. Depending on the
+ parameter type LOCATION could be a register number, or an offset
+ from the stack pointer.
+
+ TYPE points to a NTT entry describing the type of this parameter.
+
+ NEXTPARAM points to the LNTT entry describing the next parameter. */
+
+struct dntt_type_fparam
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int regparam: 1;
+ unsigned int indirect: 1;
+ unsigned int longaddr: 1;
+ unsigned int copyparam: 1;
+ unsigned int dflt: 1;
+ unsigned int doc_ranges: 1;
+ unsigned int misc_kind: 1;
+ unsigned int unused: 14;
+ vtpointer name;
+ CORE_ADDR location;
+ dnttpointer type;
+ dnttpointer nextparam;
+ int misc;
+};
+
+/* DNTT_TYPE_SVAR:
+
+ A DNTT_TYPE_SVAR is emitted to describe a variable in static storage.
+
+ GLOBAL is nonzero if the variable has global scope.
+
+ INDIRECT is nonzero if the variable is a pointer to an object.
+
+ LONGADDR is nonzero if the variable is in long pointer space.
+
+ STATICMEM is nonzero if the variable is a member of a class.
+
+ A_UNION is nonzero if the variable is an anonymous union member.
+
+ NAME is a pointer into the VT for the variable's name.
+
+ LOCATION provides the memory address for the variable.
+
+ TYPE is a pointer into either the GNTT or LNTT which describes
+ the type of this variable. */
+
+struct dntt_type_svar
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int global: 1;
+ unsigned int indirect: 1;
+ unsigned int longaddr: 1;
+ unsigned int staticmem: 1;
+ unsigned int a_union: 1;
+ unsigned int unused1: 1;
+ unsigned int thread_specific: 1;
+ unsigned int unused2: 14;
+ vtpointer name;
+ CORE_ADDR location;
+ dnttpointer type;
+ unsigned int offset;
+ unsigned int displacement;
+};
+
+/* DNTT_TYPE_DVAR:
+
+ A DNTT_TYPE_DVAR is emitted to describe automatic variables and variables
+ held in registers.
+
+ GLOBAL is nonzero if the variable has global scope.
+
+ INDIRECT is nonzero if the variable is a pointer to an object.
+
+ REGVAR is nonzero if the variable is in a register.
+
+ A_UNION is nonzero if the variable is an anonymous union member.
+
+ NAME is a pointer into the VT for the variable's name.
+
+ LOCATION provides the memory address or register number for the variable.
+
+ TYPE is a pointer into either the GNTT or LNTT which describes
+ the type of this variable. */
+
+struct dntt_type_dvar
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int global: 1;
+ unsigned int indirect: 1;
+ unsigned int regvar: 1;
+ unsigned int a_union: 1;
+ unsigned int unused: 17;
+ vtpointer name;
+ int location;
+ dnttpointer type;
+ unsigned int offset;
+};
+
+/* DNTT_TYPE_CONST:
+
+ A DNTT_TYPE_CONST symbol is emitted for program constants.
+
+ GLOBAL is nonzero if the constant has global scope.
+
+ INDIRECT is nonzero if the constant is a pointer to an object.
+
+ LOCATION_TYPE describes where to find the constant's value
+ (in the VT, memory, or embedded in an instruction).
+
+ CLASSMEM is nonzero if the constant is a member of a class.
+
+ NAME is a pointer into the VT for the constant's name.
+
+ LOCATION provides the memory address, register number or pointer
+ into the VT for the constant's value.
+
+ TYPE is a pointer into either the GNTT or LNTT which describes
+ the type of this variable. */
+
+struct dntt_type_const
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int global: 1;
+ unsigned int indirect: 1;
+ unsigned int location_type: 3;
+ unsigned int classmem: 1;
+ unsigned int unused: 15;
+ vtpointer name;
+ CORE_ADDR location;
+ dnttpointer type;
+ unsigned int offset;
+ unsigned int displacement;
+};
+
+/* DNTT_TYPE_TYPEDEF and DNTT_TYPE_TAGDEF:
+
+ The same structure is used to describe typedefs and tagdefs.
+
+ DNTT_TYPE_TYPEDEFS are associated with C "typedefs".
+
+ DNTT_TYPE_TAGDEFs are associated with C "struct", "union", and "enum"
+ tags, which may have the same name as a typedef in the same scope.
+ Also they are associated with C++ "class" tags, which implicitly have
+ the same name as the class type.
+
+ GLOBAL is nonzero if the typedef/tagdef has global scope.
+
+ TYPEINFO is used to determine if full type information is available
+ for a tag. (usually 1, but can be zero for opaque types in C).
+
+ NAME is a pointer into the VT for the constant's name.
+
+ TYPE points to the underlying type for the typedef/tagdef in the
+ GNTT or LNTT. */
+
+struct dntt_type_type
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10; /* DNTT_TYPE_TYPEDEF or
+ DNTT_TYPE_TAGDEF. */
+ unsigned int global: 1;
+ unsigned int typeinfo: 1;
+ unsigned int unused: 19;
+ vtpointer name;
+ dnttpointer type; /* Underlying type, which for TAGDEF's may be
+ DNTT_TYPE_STRUCT, DNTT_TYPE_UNION,
+ DNTT_TYPE_ENUM, or DNTT_TYPE_CLASS.
+ For TYPEDEF's other underlying types
+ are also possible. */
+};
+
+/* DNTT_TYPE_POINTER:
+
+ Used to describe a pointer to an underlying type.
+
+ POINTSTO is a pointer into the GNTT or LNTT for the type which this
+ pointer points to.
+
+ BITLENGTH is the length of the pointer (not the underlying type). */
+
+struct dntt_type_pointer
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int unused: 21;
+ dnttpointer pointsto;
+ unsigned int bitlength;
+};
+
+
+/* DNTT_TYPE_ENUM:
+
+ Used to describe enumerated types.
+
+ FIRSTMEM is a pointer to a DNTT_TYPE_MEMENUM in the GNTT/LNTT which
+ describes the first member (and contains a pointer to the chain of
+ members).
+
+ BITLENGTH is the number of bits used to hold the values of the enum's
+ members. */
+
+struct dntt_type_enum
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int unused: 21;
+ dnttpointer firstmem;
+ unsigned int bitlength;
+};
+
+/* DNTT_TYPE_MEMENUM
+
+ Used to describe members of an enumerated type.
+
+ CLASSMEM is nonzero if this member is part of a class.
+
+ NAME points into the VT for the name of this member.
+
+ VALUE is the value of this enumeration member.
+
+ NEXTMEM points to the next DNTT_TYPE_MEMENUM in the chain. */
+
+struct dntt_type_memenum
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int classmem: 1;
+ unsigned int unused: 20;
+ vtpointer name;
+ unsigned int value;
+ dnttpointer nextmem;
+};
+
+/* DNTT_TYPE_SET
+
+ Used to describe PASCAL "set" type.
+
+ DECLARATION describes the bitpacking of the set.
+
+ SUBTYPE points to a DNTT entry describing the type of the members.
+
+ BITLENGTH is the size of the set. */
+
+struct dntt_type_set
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int declaration: 2;
+ unsigned int unused: 19;
+ dnttpointer subtype;
+ unsigned int bitlength;
+};
+
+/* DNTT_TYPE_SUBRANGE
+
+ Used to describe subrange type.
+
+ DYN_LOW describes the lower bound of the subrange:
+
+ 00 for a constant lower bound (found in LOWBOUND).
+
+ 01 for a dynamic lower bound with the lower bound found in the
+ memory address pointed to by LOWBOUND.
+
+ 10 for a dynamic lower bound described by an variable found in the
+ DNTT/LNTT (LOWBOUND would be a pointer into the DNTT/LNTT).
+
+ DYN_HIGH is similar to DYN_LOW, except it describes the upper bound.
+
+ SUBTYPE points to the type of the subrange.
+
+ BITLENGTH is the length in bits needed to describe the subrange's
+ values. */
+
+struct dntt_type_subrange
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int dyn_low: 2;
+ unsigned int dyn_high: 2;
+ unsigned int unused: 17;
+ int lowbound;
+ int highbound;
+ dnttpointer subtype;
+ unsigned int bitlength;
+};
+
+/* DNTT_TYPE_ARRAY
+
+ Used to describe an array type.
+
+ DECLARATION describes the bit packing used in the array.
+
+ ARRAYISBYTES is nonzero if the field in arraylength describes the
+ length in bytes rather than in bits. A value of zero is used to
+ describe an array with size 2**32.
+
+ ELEMISBYTES is nonzero if the length if each element in the array
+ is describes in bytes rather than bits. A value of zero is used
+ to an element with size 2**32.
+
+ ELEMORDER is nonzero if the elements are indexed in increasing order.
+
+ JUSTIFIED if the elements are left justified to index zero.
+
+ ARRAYLENGTH is the length of the array.
+
+ INDEXTYPE is a DNTT pointer to the type used to index the array.
+
+ ELEMTYPE is a DNTT pointer to the type for the array elements.
+
+ ELEMLENGTH is the length of each element in the array (including
+ any padding).
+
+ Multi-dimensional arrays are represented by ELEMTYPE pointing to
+ another DNTT_TYPE_ARRAY. */
+
+struct dntt_type_array
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int declaration: 2;
+ unsigned int dyn_low: 2;
+ unsigned int dyn_high: 2;
+ unsigned int arrayisbytes: 1;
+ unsigned int elemisbytes: 1;
+ unsigned int elemorder: 1;
+ unsigned int justified: 1;
+ unsigned int unused: 11;
+ unsigned int arraylength;
+ dnttpointer indextype;
+ dnttpointer elemtype;
+ unsigned int elemlength;
+};
+
+/* DNTT_TYPE_STRUCT
+
+ DNTT_TYPE_STRUCT is used to describe a C structure.
+
+ DECLARATION describes the bitpacking used.
+
+ FIRSTFIELD is a DNTT pointer to the first field of the structure
+ (each field contains a pointer to the next field, walk the list
+ to access all fields of the structure).
+
+ VARTAGFIELD and VARLIST are used for Pascal variant records.
+
+ BITLENGTH is the size of the structure in bits. */
+
+struct dntt_type_struct
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int declaration: 2;
+ unsigned int unused: 19;
+ dnttpointer firstfield;
+ dnttpointer vartagfield;
+ dnttpointer varlist;
+ unsigned int bitlength;
+};
+
+/* DNTT_TYPE_UNION
+
+ DNTT_TYPE_UNION is used to describe a C union.
+
+ FIRSTFIELD is a DNTT pointer to the beginning of the field chain.
+
+ BITLENGTH is the size of the union in bits. */
+
+struct dntt_type_union
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int unused: 21;
+ dnttpointer firstfield;
+ unsigned int bitlength;
+};
+
+/* DNTT_TYPE_FIELD
+
+ DNTT_TYPE_FIELD describes one field in a structure or union
+ or C++ class.
+
+ VISIBILITY is used to describe the visibility of the field
+ (for c++. public = 0, protected = 1, private = 2).
+
+ A_UNION is nonzero if this field is a member of an anonymous union.
+
+ STATICMEM is nonzero if this field is a static member of a template.
+
+ NAME is a pointer into the VT for the name of the field.
+
+ BITOFFSET gives the offset of this field in bits from the beginning
+ of the structure or union this field is a member of.
+
+ TYPE is a DNTT pointer to the type describing this field.
+
+ BITLENGTH is the size of the entry in bits.
+
+ NEXTFIELD is a DNTT pointer to the next field in the chain. */
+
+struct dntt_type_field
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int visibility: 2;
+ unsigned int a_union: 1;
+ unsigned int staticmem: 1;
+ unsigned int unused: 17;
+ vtpointer name;
+ unsigned int bitoffset;
+ dnttpointer type;
+ unsigned int bitlength;
+ dnttpointer nextfield;
+};
+
+/* DNTT_TYPE_VARIANT is unused by GDB. */
+/* DNTT_TYPE_FILE is unused by GDB. */
+
+/* DNTT_TYPE_FUNCTYPE
+
+ I think this is used to describe a function type (e.g., would
+ be emitted as part of a function-pointer description).
+
+ VARARGS is nonzero if this function uses varargs.
+
+ FIRSTPARAM is a DNTT pointer to the first entry in the parameter
+ chain.
+
+ RETVAL is a DNTT pointer to the type of the return value. */
+
+struct dntt_type_functype
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int varargs: 1;
+ unsigned int info: 4;
+ unsigned int unused: 16;
+ unsigned int bitlength;
+ dnttpointer firstparam;
+ dnttpointer retval;
+};
+
+/* DNTT_TYPE_WITH is emitted by C++ to indicate "with" scoping semantics.
+ (Probably also emitted by PASCAL to support "with"...).
+
+ C++ example: Say "memfunc" is a method of class "c", and say
+ "m" is a data member of class "c". Then from within "memfunc",
+ it is legal to reference "m" directly (e.g. you don't have to
+ say "this->m". The symbol table indicates
+ this by emitting a DNTT_TYPE_WITH symbol within the function "memfunc",
+ pointing to the type symbol for class "c".
+
+ In GDB, this symbol record is unnecessary,
+ because GDB's symbol lookup algorithm
+ infers the "with" semantics when it sees a "this" argument to the member
+ function. So GDB can safely ignore the DNTT_TYPE_WITH record.
+
+ A DNTT_TYPE_WITH has a matching DNTT_TYPE_END symbol. */
+
+struct dntt_type_with
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_WITH */
+ unsigned int addrtype: 2; /* 0 => STATTYPE */
+ /* 1 => DYNTYPE */
+ /* 2 => REGTYPE */
+ unsigned int indirect: 1; /* 1 => pointer to object */
+ unsigned int longaddr: 1; /* 1 => in long pointer space */
+ unsigned int nestlevel: 6; /* # of nesting levels back */
+ unsigned int doc_ranges: 1; /* 1 => location is range list */
+ unsigned int unused: 10;
+ long location; /* where stored (allocated) */
+ sltpointer address;
+ dnttpointer type; /* type of with expression */
+ vtpointer name; /* name of with expression */
+ unsigned long offset; /* byte offset from location */
+};
+
+/* DNTT_TYPE_COMMON is unsupported by GDB. */
+/* A DNTT_TYPE_COMMON symbol must have a matching DNTT_TYPE_END symbol */
+
+/* DNTT_TYPE_COBSTRUCT is unsupported by GDB. */
+/* DNTT_TYPE_XREF is unsupported by GDB. */
+/* DNTT_TYPE_SA is unsupported by GDB. */
+/* DNTT_TYPE_MACRO is unsupported by GDB */
+
+/* DNTT_TYPE_BLOCKDATA has the same structure as DNTT_TYPE_FUNCTION */
+
+/* The following are the C++ specific SOM records */
+
+/* The purpose of the DNTT_TYPE_CLASS_SCOPE is to bracket C++ methods
+ and indicate the method name belongs in the "class scope" rather
+ than in the module they are being defined in. For example:
+
+ class c {
+ ...
+ void memfunc(); // member function
+ };
+
+ void c::memfunc() // definition of class c's "memfunc"
+ {
+ ...
+ }
+
+ main()
+ {
+ ...
+ }
+
+ In the above, the name "memfunc" is not directly visible from "main".
+ I.e., you have to say "break c::memfunc".
+ If it were a normal function (not a method), it would be visible
+ via the simple "break memfunc". Since "memfunc" otherwise looks
+ like a normal FUNCTION in the symbol table, the bracketing
+ CLASS_SCOPE is what is used to indicate it is really a method.
+
+
+ A DNTT_TYPE_CLASS_SCOPE symbol must have a matching DNTT_TYPE_END symbol. */
+
+struct dntt_type_class_scope
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_CLASS_SCOPE. */
+ unsigned int unused: 21;
+ sltpointer address ; /* Pointer to SLT entry. */
+ dnttpointer type ; /* Pointer to class type DNTT. */
+};
+
+/* C++ reference parameter.
+ The structure of this record is the same as DNTT_TYPE_POINTER -
+ refer to struct dntt_type_pointer. */
+
+/* The next two describe C++ pointer-to-data-member type, and
+ pointer-to-member-function type, respectively.
+ DNTT_TYPE_PTRMEM and DNTT_TYPE_PTRMEMFUNC have the same structure. */
+
+struct dntt_type_ptrmem
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_PTRMEM. */
+ unsigned int unused: 21;
+ dnttpointer pointsto ; /* Pointer to class DNTT. */
+ dnttpointer memtype ; /* Type of member. */
+};
+
+struct dntt_type_ptrmemfunc
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_PTRMEMFUNC. */
+ unsigned int unused: 21;
+ dnttpointer pointsto ; /* Pointer to class DNTT. */
+ dnttpointer memtype ; /* Type of member. */
+};
+
+/* The DNTT_TYPE_CLASS symbol is emitted to describe a class type.
+ "memberlist" points to a chained list of FIELD or GENFIELD records
+ indicating the class members. "parentlist" points to a chained list
+ of INHERITANCE records indicating classes from which we inherit
+ fields. */
+
+struct dntt_type_class
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_CLASS. */
+ unsigned int abstract: 1; /* Is this an abstract class? */
+ unsigned int class_decl: 2; /* 0=class,1=union,2=struct. */
+ unsigned int expansion: 1; /* 1=template expansion. */
+ unsigned int unused: 17;
+ dnttpointer memberlist ; /* Ptr to chain of [GEN]FIELDs. */
+ unsigned long vtbl_loc ; /* Offset in obj of ptr to vtbl. */
+ dnttpointer parentlist ; /* Ptr to K_INHERITANCE list. */
+ unsigned long bitlength ; /* Total at this level. */
+ dnttpointer identlist ; /* Ptr to chain of class ident's. */
+ dnttpointer friendlist ; /* Ptr to K_FRIEND list. */
+ dnttpointer templateptr ; /* Ptr to template. */
+ dnttpointer nextexp ; /* Ptr to next expansion. */
+};
+
+/* Class members are indicated via either the FIELD record (for
+ data members, same as for C struct fields), or by the GENFIELD record
+ (for member functions). */
+
+struct dntt_type_genfield
+{
+ unsigned int extension: 1; /* Always zero. */
+ unsigned int kind: 10; /* Always DNTT_TYPE_GENFIELD. */
+ unsigned int visibility: 2; /* Pub = 0, prot = 1, priv = 2. */
+ unsigned int a_union: 1; /* 1 => anonymous union member. */
+ unsigned int unused: 18;
+ dnttpointer field ; /* Pointer to field or qualifier. */
+ dnttpointer nextfield ; /* Pointer to next field. */
+};
+
+/* C++ virtual functions. */
+
+struct dntt_type_vfunc
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_VFUNC */
+ unsigned int pure: 1; /* pure virtual function ? */
+ unsigned int unused: 20;
+ dnttpointer funcptr ; /* points to FUNCTION symbol */
+ unsigned long vtbl_offset ; /* offset into vtbl for virtual */
+};
+
+/* Not precisely sure what this is intended for - DDE ignores it. */
+
+struct dntt_type_memaccess
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_MEMACCESS */
+ unsigned int unused: 21;
+ dnttpointer classptr ; /* pointer to base class */
+ dnttpointer field ; /* pointer field */
+};
+
+/* The DNTT_TYPE_INHERITANCE record describes derived classes.
+ In particular, the "parentlist" field of the CLASS record points
+ to a list of INHERITANCE records for classes from which we
+ inherit members. */
+
+struct dntt_type_inheritance
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_INHERITANCE */
+ unsigned int Virtual: 1; /* virtual base class ? */
+ unsigned int visibility: 2; /* pub = 0, prot = 1, priv = 2 */
+ unsigned int unused: 18;
+ dnttpointer classname ; /* first parent class, if any */
+ unsigned long offset ; /* offset to start of base class */
+ dnttpointer next ; /* pointer to next K_INHERITANCE */
+ unsigned long future[2] ; /* padding to 3-word block end */
+};
+
+/* C++ "friend" classes ... */
+
+struct dntt_type_friend_class
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FRIEND_CLASS */
+ unsigned int unused: 21;
+ dnttpointer classptr ; /* pointer to class DNTT */
+ dnttpointer next ; /* next DNTT_FRIEND */
+};
+
+struct dntt_type_friend_func
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FRIEND_FUNC */
+ unsigned int unused: 21;
+ dnttpointer funcptr ; /* pointer to function */
+ dnttpointer classptr ; /* pointer to class DNTT */
+ dnttpointer next ; /* next DNTT_FRIEND */
+ unsigned long future[2] ; /* padding to 3-word block end */
+};
+
+/* DDE appears to ignore the DNTT_TYPE_MODIFIER record.
+ It could perhaps be used to give better "ptype" output in GDB;
+ otherwise it is probably safe for GDB to ignore it also. */
+
+struct dntt_type_modifier
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_MODIFIER */
+ unsigned int m_const: 1; /* const */
+ unsigned int m_static: 1; /* static */
+ unsigned int m_void: 1; /* void */
+ unsigned int m_volatile: 1; /* volatile */
+ unsigned int m_duplicate: 1; /* duplicate */
+ unsigned int unused: 16;
+ dnttpointer type ; /* subtype */
+ unsigned long future ; /* padding to 3-word block end */
+};
+
+/* I'm not sure what this was intended for - DDE ignores it. */
+
+struct dntt_type_object_id
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_OBJECT_ID */
+ unsigned int indirect: 1; /* Is object_ident addr of addr? */
+ unsigned int unused: 20;
+ unsigned long object_ident ; /* object identifier */
+ unsigned long offset ; /* offset to start of base class */
+ dnttpointer next ; /* pointer to next K_OBJECT_ID */
+ unsigned long segoffset ; /* for linker fixup */
+ unsigned long future ; /* padding to 3-word block end */
+};
+
+/* No separate dntt_type_memfunc; same as dntt_type_func */
+
+/* Symbol records to support templates. These only get used
+ in DDE's "describe" output (like GDB's "ptype"). */
+
+/* The TEMPLATE record is the header for a template-class.
+ Like the CLASS record, a TEMPLATE record has a memberlist that
+ points to a list of template members. It also has an arglist
+ pointing to a list of TEMPLATE_ARG records. */
+
+struct dntt_type_template
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_TEMPLATE */
+ unsigned int abstract: 1; /* is this an abstract class? */
+ unsigned int class_decl: 2; /* 0=class,1=union,2=struct */
+ unsigned int unused: 18;
+ dnttpointer memberlist ; /* ptr to chain of K_[GEN]FIELDs */
+ long unused2 ; /* offset in obj of ptr to vtbl */
+ dnttpointer parentlist ; /* ptr to K_INHERITANCE list */
+ unsigned long bitlength ; /* total at this level */
+ dnttpointer identlist ; /* ptr to chain of class ident's */
+ dnttpointer friendlist ; /* ptr to K_FRIEND list */
+ dnttpointer arglist ; /* ptr to argument list */
+ dnttpointer expansions ; /* ptr to expansion list */
+};
+
+/* Template-class arguments are a list of TEMPL_ARG records
+ chained together. The "name" field is the name of the formal.
+ E.g.:
+
+ template <class T> class q { ... };
+
+ Then "T" is the name of the formal argument. */
+
+struct dntt_type_templ_arg
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_TEMPL_ARG */
+ unsigned int usagetype: 1; /* 0 type-name 1 expression */
+ unsigned int unused: 20;
+ vtpointer name ; /* name of argument */
+ dnttpointer type ; /* for non type arguments */
+ dnttpointer nextarg ; /* Next argument if any */
+ long future[2] ; /* padding to 3-word block end */
+};
+
+/* FUNC_TEMPLATE records are sort of like FUNCTION, but are emitted
+ for template member functions. E.g.,
+
+ template <class T> class q
+ {
+ ...
+ void f();
+ ...
+ };
+
+ Within the list of FIELDs/GENFIELDs defining the member list
+ of the template "q", "f" would appear as a FUNC_TEMPLATE.
+ We'll also see instances of FUNCTION "f" records for each
+ instantiation of the template. */
+
+struct dntt_type_func_template
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_FUNC_TEMPLATE */
+ unsigned int public: 1; /* 1 => globally visible */
+ unsigned int language: 4; /* type of language */
+ unsigned int level: 5; /* nesting level (top level = 0)*/
+ unsigned int optimize: 2; /* level of optimization */
+ unsigned int varargs: 1; /* ellipses. Pascal/800 later */
+ unsigned int info: 4; /* lang-specific stuff; F_xxxx */
+ unsigned int inlined: 1;
+ unsigned int localloc: 1; /* 0 at top, 1 at end of block */
+ unsigned int unused: 2;
+ vtpointer name ; /* name of function */
+ vtpointer alias ; /* alternate name, if any */
+ dnttpointer firstparam ; /* first FPARAM, if any */
+ dnttpointer retval ; /* return type, if any */
+ dnttpointer arglist ; /* ptr to argument list */
+};
+
+/* LINK is apparently intended to link together function template
+ definitions with their instantiations. However, it is not clear
+ why this would be needed, except to provide the information on
+ a "ptype" command. And as far as I can tell, aCC does not
+ generate this record. */
+
+struct dntt_type_link
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* always DNTT_TYPE_LINK */
+ unsigned int linkKind: 4; /* always LINK_UNKNOWN */
+ unsigned int unused: 17;
+ long future1 ; /* expansion */
+ dnttpointer ptr1 ; /* link from template */
+ dnttpointer ptr2 ; /* to expansion */
+ long future[2] ; /* padding to 3-word block end */
+};
+
+/* end of C++ specific SOM's. */
+
+/* DNTT_TYPE_DYN_ARRAY_DESC is unused by GDB */
+/* DNTT_TYPE_DESC_SUBRANGE is unused by GDB */
+/* DNTT_TYPE_BEGIN_EXT is unused by GDB */
+/* DNTT_TYPE_INLN is unused by GDB */
+/* DNTT_TYPE_INLN_LIST is unused by GDB */
+/* DNTT_TYPE_ALIAS is unused by GDB */
+
+struct dntt_type_doc_function
+{
+ unsigned int extension: 1; /* always zero */
+ unsigned int kind: 10; /* K_DOC_FUNCTION or */
+ /* K_DOC_MEMFUNC */
+ unsigned int global: 1; /* 1 => globally visible */
+ unsigned int language: 4; /* type of language */
+ unsigned int level: 5; /* nesting level (top level = 0)*/
+ unsigned int optimize: 2; /* level of optimization */
+ unsigned int varargs: 1; /* ellipses. Pascal/800 later */
+ unsigned int info: 4; /* lang-specific stuff; F_xxxx */
+ unsigned int inlined: 1;
+ unsigned int localloc: 1; /* 0 at top, 1 at end of block */
+ unsigned int expansion: 1; /* 1 = function expansion */
+ unsigned int doc_clone: 1;
+ vtpointer name; /* name of function */
+ vtpointer alias; /* alternate name, if any */
+ dnttpointer firstparam; /* first FPARAM, if any */
+ sltpointer address; /* code and text locations */
+ CORE_ADDR entryaddr; /* address of entry point */
+ dnttpointer retval; /* return type, if any */
+ CORE_ADDR lowaddr; /* lowest address of function */
+ CORE_ADDR hiaddr; /* highest address of function */
+ dnttpointer inline_list; /* pointer to first inline */
+ ltpointer lt_offset; /* start of frag/cp line table */
+ ctxtpointer ctxt_offset; /* start of context table for this routine */
+};
+
+/* DNTT_TYPE_DOC_MEMFUNC is unused by GDB */
+
+/* DNTT_TYPE_GENERIC and DNTT_TYPE_BLOCK are convience structures
+ so we can examine a DNTT entry in a generic fashion. */
+struct dntt_type_generic
+{
+ unsigned int word[9];
+};
+
+struct dntt_type_block
+{
+ unsigned int extension: 1;
+ unsigned int kind: 10;
+ unsigned int unused: 21;
+ unsigned int word[2];
+};
+
+/* One entry in a DNTT (either the LNTT or GNTT).
+ This is a union of the above 60 or so structure definitions. */
+
+union dnttentry
+{
+ struct dntt_type_srcfile dsfile;
+ struct dntt_type_module dmodule;
+ struct dntt_type_function dfunc;
+ struct dntt_type_function dentry;
+ struct dntt_type_begin dbegin;
+ struct dntt_type_end dend;
+ struct dntt_type_fparam dfparam;
+ struct dntt_type_svar dsvar;
+ struct dntt_type_dvar ddvar;
+ struct dntt_type_const dconst;
+ struct dntt_type_type dtype;
+ struct dntt_type_type dtag;
+ struct dntt_type_pointer dptr;
+ struct dntt_type_enum denum;
+ struct dntt_type_memenum dmember;
+ struct dntt_type_set dset;
+ struct dntt_type_subrange dsubr;
+ struct dntt_type_array darray;
+ struct dntt_type_struct dstruct;
+ struct dntt_type_union dunion;
+ struct dntt_type_field dfield;
+ struct dntt_type_functype dfunctype;
+ struct dntt_type_with dwith;
+ struct dntt_type_function dblockdata;
+ struct dntt_type_class_scope dclass_scope;
+ struct dntt_type_pointer dreference;
+ struct dntt_type_ptrmem dptrmem;
+ struct dntt_type_ptrmemfunc dptrmemfunc;
+ struct dntt_type_class dclass;
+ struct dntt_type_genfield dgenfield;
+ struct dntt_type_vfunc dvfunc;
+ struct dntt_type_memaccess dmemaccess;
+ struct dntt_type_inheritance dinheritance;
+ struct dntt_type_friend_class dfriend_class;
+ struct dntt_type_friend_func dfriend_func;
+ struct dntt_type_modifier dmodifier;
+ struct dntt_type_object_id dobject_id;
+ struct dntt_type_template dtemplate;
+ struct dntt_type_templ_arg dtempl_arg;
+ struct dntt_type_func_template dfunc_template;
+ struct dntt_type_link dlink;
+ struct dntt_type_doc_function ddocfunc;
+ struct dntt_type_generic dgeneric;
+ struct dntt_type_block dblock;
+};
+
+/* Source line entry types. */
+enum slttype
+{
+ SLT_NORMAL,
+ SLT_SRCFILE,
+ SLT_MODULE,
+ SLT_FUNCTION,
+ SLT_ENTRY,
+ SLT_BEGIN,
+ SLT_END,
+ SLT_WITH,
+ SLT_EXIT,
+ SLT_ASSIST,
+ SLT_MARKER,
+ SLT_CLASS_SCOPE,
+ SLT_INLN,
+ SLT_NORMAL_OFFSET,
+};
+
+/* A normal source line entry. Simply provides a mapping of a source
+ line number to a code address.
+
+ SLTDESC will always be SLT_NORMAL or SLT_EXIT. */
+
+struct slt_normal
+{
+ unsigned int sltdesc: 4;
+ unsigned int line: 28;
+ CORE_ADDR address;
+};
+
+struct slt_normal_off
+{
+ unsigned int sltdesc: 4;
+ unsigned int offset: 6;
+ unsigned int line: 22;
+ CORE_ADDR address;
+};
+
+/* A special source line entry. Provides a mapping of a declaration
+ to a line number. These entries point back into the DNTT which
+ references them. */
+
+struct slt_special
+{
+ unsigned int sltdesc: 4;
+ unsigned int line: 28;
+ dnttpointer backptr;
+};
+
+/* Used to describe nesting.
+
+ For nested languages, an slt_assist entry must follow each SLT_FUNC
+ entry in the SLT. The address field will point forward to the
+ first slt_normal entry within the function's scope. */
+
+struct slt_assist
+{
+ unsigned int sltdesc: 4;
+ unsigned int unused: 28;
+ sltpointer address;
+};
+
+struct slt_generic
+{
+ unsigned int word[2];
+};
+
+union sltentry
+{
+ struct slt_normal snorm;
+ struct slt_normal_off snormoff;
+ struct slt_special sspec;
+ struct slt_assist sasst;
+ struct slt_generic sgeneric;
+};
+
+/* $LINES$ declarations
+ This is the line table used for optimized code, which is only present
+ in the new $PROGRAM_INFO$ debug space. */
+
+#define DST_LN_ESCAPE_FLAG1 15
+#define DST_LN_ESCAPE_FLAG2 14
+#define DST_LN_CTX_SPEC1 13
+#define DST_LN_CTX_SPEC2 12
+
+/* Escape function codes: */
+
+typedef enum
+{
+ dst_ln_pad, /* pad byte */
+ dst_ln_escape_1, /* reserved */
+ dst_ln_dpc1_dln1, /* 1 byte line delta, 1 byte pc delta */
+ dst_ln_dpc2_dln2, /* 2 bytes line delta, 2 bytes pc delta */
+ dst_ln_pc4_ln4, /* 4 bytes ABSOLUTE line number, 4 bytes ABSOLUTE pc */
+ dst_ln_dpc0_dln1, /* 1 byte line delta, pc delta = 0 */
+ dst_ln_ln_off_1, /* statement escape, stmt # = 1 (2nd stmt on line) */
+ dst_ln_ln_off, /* statement escape, stmt # = next byte */
+ dst_ln_entry, /* entry escape, next byte is entry number */
+ dst_ln_exit, /* exit escape */
+ dst_ln_stmt_end, /* gap escape, 4 bytes pc delta */
+ dst_ln_stmt_cp, /* current stmt is a critical point */
+ dst_ln_escape_12, /* reserved */
+ dst_ln_escape_13, /* this is an exception site record */
+ dst_ln_nxt_byte, /* next byte contains the real escape code */
+ dst_ln_end, /* end escape, final entry follows */
+ dst_ln_escape1_END_OF_ENUM
+}
+dst_ln_escape1_t;
+
+typedef enum
+{
+ dst_ln_ctx_1, /* next byte describes context switch with 5-bit */
+ /* index into the image table and 3-bit run length. */
+ /* If run length is 0, end with another cxt specifier or ctx_end */
+ dst_ln_ctx_2, /* next 2 bytes switch context: 13 bit index, 3 bit run length */
+ dst_ln_ctx_4, /* next 4 bytes switch context: 29 bit index, 3 bit run length */
+ dst_ln_ctx_end, /* end current context */
+ dst_ln_col_run_1, /* next byte is column position of start of next statement, */
+ /* following byte is length of statement */
+ dst_ln_col_run_2, /* next 2 bytes is column position of start of next statement, */
+ /* following 2 bytes is length of statement */
+ dst_ln_init_base1, /* next 4 bytes are absolute PC, followed by 1 byte of line number */
+ dst_ln_init_base2, /* next 4 bytes are absolute PC, followed by 2 bytes of line number */
+ dst_ln_init_base3, /* next 4 bytes are absolute PC, followed by 3 bytes of line number */
+ dst_ln_escape2_END_OF_ENUM
+}
+dst_ln_escape2_t;
+
+typedef union
+{
+ struct
+ {
+ unsigned int pc_delta : 4; /* 4 bit pc delta */
+ int ln_delta : 4; /* 4 bit line number delta */
+ }
+ delta;
+
+ struct
+ {
+ unsigned int esc_flag : 4; /* alias for pc_delta */
+ unsigned int esc_code : 4; /* escape function code (dst_ln_escape1_t, or ...2_t */
+ }
+ esc;
+
+ struct
+ {
+ unsigned int esc_flag : 4; /* dst_ln_ctx_spec1, or dst_ln_ctx_spec2 */
+ unsigned int run_length : 2;
+ unsigned int ctx_index : 2; /* ...spec2 contains index; ...spec1, index - 4 */
+ }
+ ctx_spec;
+
+ char sdata; /* signed data byte */
+ unsigned char udata; /* unsigned data byte */
+}
+dst_ln_entry_t,
+ * dst_ln_entry_ptr_t;
+
+/* Warning: although the above union occupies only 1 byte the compiler treats
+ it as having size 2 (the minimum size of a struct). Therefore a sequence of
+ dst_ln_entry_t's cannot be described as an array, and walking through such a
+ sequence requires convoluted code such as
+ ln_ptr = (dst_ln_entry_ptr_t) (char*) ln_ptr + 1
+ We regret the inconvenience. */
+
+/* Structure for interpreting the byte following a dst_ln_ctx1 entry. */
+typedef struct
+{
+ unsigned int ctx1_index : 5; /* 5 bit index into context table */
+ unsigned int ctx1_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx1_t,
+ *dst_ln_ctx1_ptr_t;
+
+/* Structure for interpreting the bytes following a dst_ln_ctx2 entry. */
+typedef struct
+{
+ unsigned int ctx2_index : 13; /* 13 bit index into context table */
+ unsigned int ctx2_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx2_t,
+ *dst_ln_ctx2_ptr_t;
+
+/* Structure for interpreting the bytes following a dst_ln_ctx4 entry. */
+typedef struct
+{
+ unsigned int ctx4_index : 29; /* 29 bit index into context table */
+ unsigned int ctx4_run_length : 3; /* 3 bit run length */
+} dst_ln_ctx4_t,
+ *dst_ln_ctx4_ptr_t;
+
+
+/* PXDB definitions.
+
+ PXDB is a post-processor which takes the executable file
+ and massages the debug information so that the debugger may
+ start up and run more efficiently. Some of the tasks
+ performed by PXDB are:
+
+ o Remove duplicate global type and variable information
+ from the GNTT,
+
+ o Append the GNTT onto the end of the LNTT and place both
+ back in the LNTT section,
+
+ o Build quick look-up tables (description follows) for
+ files, procedures, modules, and paragraphs (for Cobol),
+ placing these in the GNTT section,
+
+ o Reconstruct the header appearing in the header section
+ to access this information.
+
+ The "quick look-up" tables are in the $GNTT$ sub-space, in
+ the following order:
+
+ Procedures -sorted by address
+ Source files -sorted by address (of the
+ generated code from routines)
+ Modules -sorted by address
+ Classes -<unsorted?>
+ Address Alias -sorted by index <?>
+ Object IDs -sorted by object identifier
+
+ Most quick entries have (0-based) indices into the LNTT tables to
+ the full entries for the item it describes.
+
+ The post-PXDB header is in the $HEADER$ sub-space. Alas, it
+ occurs in different forms, depending on the optimization level
+ in the compilation step and whether PXDB was run or not. The
+ worst part is the forms aren't self-describing, so we'll have
+ to grovel in the bits to figure out what kind we're looking at
+ (see hp_get_header in hp-psymtab-read.c). */
+
+/* PXDB versions. */
+
+#define PXDB_VERSION_CPLUSPLUS 1
+#define PXDB_VERSION_7_4 2
+#define PXDB_VERSION_CPP_30 3
+#define PXDB_VERSION_DDE_3_2A 4
+#define PXDB_VERSION_DDE_3_2 5
+#define PXDB_VERSION_DDE_4_0 6
+
+#define PXDB_VERSION_2_1 1
+
+/* Header version for the case that there is no DOC info
+ but the executable has been processed by pxdb (the easy
+ case, from "cc -g"). */
+
+typedef struct PXDB_struct
+{
+ int pd_entries; /* # of entries in function look-up table */
+ int fd_entries; /* # of entries in file look-up table */
+ int md_entries; /* # of entries in module look-up table */
+ unsigned int pxdbed : 1; /* 1 => file has been preprocessed */
+ unsigned int bighdr : 1; /* 1 => this header contains 'time' word */
+ unsigned int sa_header : 1;/* 1 => created by SA version of pxdb */
+ /* used for version check in xdb */
+ unsigned int inlined: 1; /* one or more functions have been inlined */
+ unsigned int spare:12;
+ short version; /* pxdb header version */
+ int globals; /* index into the DNTT where GNTT begins */
+ unsigned int time; /* modify time of file before being pxdbed */
+ int pg_entries; /* # of entries in label look-up table */
+ int functions; /* actual number of functions */
+ int files; /* actual number of files */
+ int cd_entries; /* # of entries in class look-up table */
+ int aa_entries; /* # of entries in addr alias look-up table */
+ int oi_entries; /* # of entries in object id look-up table */
+} PXDB_header, *PXDB_header_ptr;
+
+/* Header version for the case that there is no DOC info and the
+ executable has NOT been processed by pxdb. */
+
+typedef struct XDB_header_struct
+{
+ long gntt_length;
+ long lntt_length;
+ long slt_length;
+ long vt_length;
+ long xt_length;
+} XDB_header;
+
+/* Header version for the case that there is DOC info and the
+ executable has been processed by pxdb. */
+
+typedef struct DOC_info_PXDB_header_struct
+{
+ unsigned int xdb_header: 1; /* bit set if this is post-3.1 xdb */
+ unsigned int doc_header: 1; /* bit set if this is doc-style header */
+ unsigned int version: 8; /* version of pxdb see defines
+ PXDB_VERSION_* in this file. */
+ unsigned int reserved_for_flags: 16;/* for future use; -- must be
+ set to zero. */
+ unsigned int has_aux_pd_table: 1; /* $GNTT$ has aux PD table */
+ unsigned int has_expr_table: 1; /* space has $EXPR$ */
+ unsigned int has_range_table: 1; /* space has $RANGE$ */
+ unsigned int has_context_table: 1; /* space has $SRC_CTXT$ */
+ unsigned int has_lines_table: 1; /* space contains a $LINES$
+ subspace for line tables. */
+ unsigned int has_lt_offset_map: 1; /* space contains an lt_offset
+ subspace for line table mapping. */
+ /* The following fields are the same as those in the PXDB_header in $DEBUG$ */
+ int pd_entries; /* # of entries in function look-up table */
+ int fd_entries; /* # of entries in file look-up table */
+ int md_entries; /* # of entries in module look-up table */
+ unsigned int pxdbed : 1; /* 1 => file has been preprocessed */
+ unsigned int bighdr : 1; /* 1 => this header contains 'time' word */
+ unsigned int sa_header : 1;/* 1 => created by SA version of pxdb */
+ /* used for version check in xdb */
+ unsigned int inlined: 1; /* one or more functions have been inlined */
+ unsigned int spare : 28;
+ int globals; /* index into the DNTT where GNTT begins */
+ unsigned int time; /* modify time of file before being pxdbed */
+ int pg_entries; /* # of entries in label look-up table */
+ int functions; /* actual number of functions */
+ int files; /* actual number of files */
+ int cd_entries; /* # of entries in class look-up table */
+ int aa_entries; /* # of entries in addr alias look-up table */
+ int oi_entries; /* # of entries in object id look-up table */
+} DOC_info_PXDB_header;
+
+/* Header version for the case that there is DOC info and the
+ executable has NOT been processed by pxdb. */
+
+typedef struct DOC_info_header_struct
+{
+ unsigned int xdb_header: 1; /* bit set if this is post-3.1 xdb */
+ unsigned int doc_header: 1; /* bit set if this is doc-style header*/
+ unsigned int version: 8; /* version of debug/header
+ format. For 10.0 the value
+ will be 1. For "Davis" the value is 2. */
+ unsigned int reserved_for_flags: 18; /* for future use; -- must be set to zero. */
+ unsigned int has_range_table: 1; /* space contains a $RANGE$ subspace for variable ranges. */
+ unsigned int has_context_table: 1; /* space contains a $CTXT$ subspace for context/inline table. */
+ unsigned int has_lines_table: 1; /* space contains a $LINES$ subspace for line tables. */
+ unsigned int has_lt_offset_map: 1; /* space contains an lt_offset subspace for line table mapping. */
+
+ long gntt_length; /* same as old header */
+ long lntt_length; /* same as old header */
+ long slt_length; /* same as old header */
+ long vt_length; /* same as old header */
+ long xt_length; /* same as old header */
+ long ctxt_length; /* present only if version >= 2 */
+ long range_length; /* present only if version >= 2 */
+ long expr_length; /* present only if version >= 2 */
+
+} DOC_info_header;
+
+typedef union GenericDebugHeader_union
+{
+ PXDB_header no_doc;
+ DOC_info_PXDB_header doc;
+ XDB_header no_pxdb_no_doc;
+ DOC_info_header no_pxdb_doc;
+} GenericDebugHeader;
+
+
+/* Procedure Descriptor:
+ An element of the procedure quick look-up table. */
+
+typedef struct quick_procedure
+{
+ long isym; /* 0-based index of first symbol
+ for procedure in $LNTT$,
+ i.e. the procedure itself. */
+ CORE_ADDR adrStart; /* memory adr of start of proc */
+ CORE_ADDR adrEnd; /* memory adr of end of proc */
+ char *sbAlias; /* alias name of procedure */
+ char *sbProc; /* real name of procedure */
+ CORE_ADDR adrBp; /* address of entry breakpoint */
+ CORE_ADDR adrExitBp; /* address of exit breakpoint */
+ int icd; /* member of this class (index) */
+ unsigned int ipd; /* index of template for this */
+ /* function (index) */
+ unsigned int unused: 5;
+ unsigned int no_lt_offset: 1;/* no entry in lt_offset table */
+ unsigned int fTemplate: 1; /* function template */
+ unsigned int fExpansion: 1; /* function expansion */
+ unsigned int linked : 1; /* linked with other expansions */
+ unsigned int duplicate: 1; /* clone of another procedure */
+ unsigned int overloaded:1; /* overloaded function */
+ unsigned int member: 1; /* class member function */
+ unsigned int constructor:1; /* constructor function */
+ unsigned int destructor:1; /* destructor function */
+ unsigned int Static: 1; /* static function */
+ unsigned int Virtual: 1; /* virtual function */
+ unsigned int constant: 1; /* constant function */
+ unsigned int pure: 1; /* pure (virtual) function */
+ unsigned int language: 4; /* procedure's language */
+ unsigned int inlined: 1; /* function has been inlined */
+ unsigned int Operator: 1; /* operator function */
+ unsigned int stub: 1; /* bodyless function */
+ unsigned int optimize: 2; /* optimization level */
+ unsigned int level: 5; /* nesting level (top=0) */
+} quick_procedure_entry, *quick_procedure_entry_ptr;
+
+/* Source File Descriptor:
+ An element of the source file quick look-up table. */
+
+typedef struct quick_source
+{
+ long isym; /* 0-based index in $LNTT$ of
+ first symbol for this file. */
+ CORE_ADDR adrStart; /* mem adr of start of file's code */
+ CORE_ADDR adrEnd; /* mem adr of end of file's code */
+ char *sbFile; /* name of source file */
+ unsigned int fHasDecl: 1; /* do we have a .d file? */
+ unsigned int fWarned: 1; /* have warned about age problems? */
+ unsigned int fSrcfile: 1; /* 0 => include 1=> source */
+ unsigned short ilnMac; /* lines in file (0 if don't know) */
+ int ipd; /* 0-based index of first procedure
+ in this file, in the quick
+ look-up table of procedures. */
+ unsigned int *rgLn; /* line pointer array, if any */
+} quick_file_entry, *quick_file_entry_ptr;
+
+/* Module Descriptor:
+ An element of the module quick reference table. */
+
+typedef struct quick_module
+{
+ long isym; /* 0-based index of first
+ symbol for module. */
+ CORE_ADDR adrStart; /* adr of start of mod. */
+ CORE_ADDR adrEnd; /* adr of end of mod. */
+ char *sbAlias; /* alias name of module */
+ char *sbMod; /* real name of module */
+ unsigned int imports: 1; /* module have any imports? */
+ unsigned int vars_in_front: 1; /* module globals in front? */
+ unsigned int vars_in_gaps: 1; /* module globals in gaps? */
+ unsigned int language: 4; /* type of language */
+ unsigned int unused : 25;
+ unsigned int unused2; /* space for future stuff */
+} quick_module_entry, *quick_module_entry_ptr;
+
+/* Auxiliary Procedure Descriptor:
+ An element of the auxiliary procedure quick look-up table. */
+
+typedef struct quick_aux_procedure
+{
+ long isym_inln; /* start on inline list for proc */
+ long spare;
+} quick_aux_procedure_entry, *quick_aux_procedure_entry_ptr;
+
+/* Paragraph Descriptor:
+ An element of the paragraph quick look-up table. */
+
+typedef struct quick_paragraph
+{
+ long isym; /* first symbol for label (index) */
+ CORE_ADDR adrStart; /* memory adr of start of label */
+ CORE_ADDR adrEnd; /* memory adr of end of label */
+ char *sbLab; /* name of label */
+ unsigned int inst; /* Used in xdb to store inst @ bp */
+ unsigned int sect: 1; /* true = section, false = parag. */
+ unsigned int unused: 31; /* future use */
+} quick_paragraph_entry, *quick_paragraph_entry_ptr;
+
+/* Class Descriptor:
+ An element of the class quick look-up table. */
+
+typedef struct quick_class
+{
+ char *sbClass; /* name of class */
+ long isym; /* class symbol (tag) */
+ unsigned int type : 2; /* 0=class, 1=union, 2=struct */
+ unsigned int fTemplate : 1;/* class template */
+ unsigned int expansion : 1;/* template expansion */
+ unsigned int unused :28;
+ sltpointer lowscope; /* beginning of defined scope */
+ sltpointer hiscope; /* end of defined scope */
+} quick_class_entry, *quick_class_entry_ptr;
+
+/* Address Alias Entry
+ An element of the address alias quick look-up table. */
+
+typedef struct quick_alias
+{
+ CORE_ADDR low;
+ CORE_ADDR high;
+ int index;
+ unsigned int unused : 31;
+ unsigned int alternate : 1; /* alternate unnamed aliases? */
+} quick_alias_entry, *quick_alias_entry_ptr;
+
+/* Object Identification Entry
+ An element of the object identification quick look-up table. */
+
+typedef struct quick_obj_ID
+{
+ CORE_ADDR obj_ident; /* class identifier */
+ long isym; /* class symbol */
+ long offset; /* offset to object start */
+} quick_obj_ID_entry, *quick_obj_ID_entry_ptr;
+
+#endif /* HP_SYMTAB_INCLUDED */
diff --git a/contrib/gdb/include/ieee.h b/contrib/gdb/include/ieee.h
new file mode 100644
index 0000000..5abc32b
--- /dev/null
+++ b/contrib/gdb/include/ieee.h
@@ -0,0 +1,165 @@
+/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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.
+
+ Contributed by Cygnus Support. */
+
+#define N_W_VARIABLES 8
+#define Module_Beginning 0xe0
+
+typedef struct ieee_module
+ {
+ char *processor;
+ char *module_name;
+ }
+ieee_module_begin_type;
+
+#define Address_Descriptor 0xec
+typedef struct ieee_address
+ {
+ bfd_vma number_of_bits_mau;
+ bfd_vma number_of_maus_in_address;
+
+ unsigned char byte_order;
+#define IEEE_LITTLE 0xcc
+#define IEEE_BIG 0xcd
+ }
+ieee_address_descriptor_type;
+
+typedef union ieee_w_variable
+ {
+ file_ptr offset[N_W_VARIABLES];
+
+ struct
+ {
+ file_ptr extension_record;
+ file_ptr environmental_record;
+ file_ptr section_part;
+ file_ptr external_part;
+ file_ptr debug_information_part;
+ file_ptr data_part;
+ file_ptr trailer_part;
+ file_ptr me_record;
+ }
+ r;
+ }
+ieee_w_variable_type;
+
+typedef enum ieee_record
+ {
+ ieee_number_start_enum = 0x00,
+ ieee_number_end_enum=0x7f,
+ ieee_number_repeat_start_enum = 0x80,
+ ieee_number_repeat_end_enum = 0x88,
+ ieee_number_repeat_4_enum = 0x84,
+ ieee_number_repeat_3_enum = 0x83,
+ ieee_number_repeat_2_enum = 0x82,
+ ieee_number_repeat_1_enum = 0x81,
+ ieee_module_beginning_enum = 0xe0,
+ ieee_module_end_enum = 0xe1,
+ ieee_extension_length_1_enum = 0xde,
+ ieee_extension_length_2_enum = 0xdf,
+ ieee_section_type_enum = 0xe6,
+ ieee_section_alignment_enum = 0xe7,
+ ieee_external_symbol_enum = 0xe8,
+ ieee_comma = 0x90,
+ ieee_external_reference_enum = 0xe9,
+ ieee_set_current_section_enum = 0xe5,
+ ieee_address_descriptor_enum = 0xec,
+ ieee_load_constant_bytes_enum = 0xed,
+ ieee_load_with_relocation_enum = 0xe4,
+
+ ieee_variable_A_enum = 0xc1,
+ ieee_variable_B_enum = 0xc2,
+ ieee_variable_C_enum = 0xc3,
+ ieee_variable_D_enum = 0xc4,
+ ieee_variable_E_enum = 0xc5,
+ ieee_variable_F_enum = 0xc6,
+ ieee_variable_G_enum = 0xc7,
+ ieee_variable_H_enum = 0xc8,
+ ieee_variable_I_enum = 0xc9,
+ ieee_variable_J_enum = 0xca,
+ ieee_variable_K_enum = 0xcb,
+ ieee_variable_L_enum = 0xcc,
+ ieee_variable_M_enum = 0xcd,
+ ieee_variable_N_enum = 0xce,
+ ieee_variable_O_enum = 0xcf,
+ ieee_variable_P_enum = 0xd0,
+ ieee_variable_Q_enum = 0xd1,
+ ieee_variable_R_enum = 0xd2,
+ ieee_variable_S_enum = 0xd3,
+ ieee_variable_T_enum = 0xd4,
+ ieee_variable_U_enum = 0xd5,
+ ieee_variable_V_enum = 0xd6,
+ ieee_variable_W_enum = 0xd7,
+ ieee_variable_X_enum = 0xd8,
+ ieee_variable_Y_enum = 0xd9,
+ ieee_variable_Z_enum = 0xda,
+ ieee_function_plus_enum = 0xa5,
+ ieee_function_minus_enum = 0xa6,
+ ieee_function_signed_open_b_enum = 0xba,
+ ieee_function_signed_close_b_enum = 0xbb,
+
+ ieee_function_unsigned_open_b_enum = 0xbc,
+ ieee_function_unsigned_close_b_enum = 0xbd,
+
+ ieee_function_either_open_b_enum = 0xbe,
+ ieee_function_either_close_b_enum = 0xbf,
+ ieee_record_seperator_enum = 0xdb,
+
+ ieee_e2_first_byte_enum = 0xe2,
+ ieee_section_size_enum = 0xe2d3,
+ ieee_physical_region_size_enum = 0xe2c1,
+ ieee_region_base_address_enum = 0xe2c2,
+ ieee_mau_size_enum = 0xe2c6,
+ ieee_m_value_enum = 0xe2cd,
+ ieee_section_base_address_enum = 0xe2cc,
+ ieee_asn_record_enum = 0xe2ce,
+ ieee_section_offset_enum = 0xe2d2,
+ ieee_value_starting_address_enum = 0xe2c7,
+ ieee_assign_value_to_variable_enum = 0xe2d7,
+ ieee_set_current_pc_enum = 0xe2d0,
+ ieee_value_record_enum = 0xe2c9,
+ ieee_nn_record = 0xf0,
+ ieee_at_record_enum = 0xf1,
+ ieee_ty_record_enum = 0xf2,
+ ieee_attribute_record_enum = 0xf1c9,
+ ieee_atn_record_enum = 0xf1ce,
+ ieee_external_reference_info_record_enum = 0xf1d8,
+ ieee_weak_external_reference_enum= 0xf4,
+ ieee_repeat_data_enum = 0xf7,
+ ieee_bb_record_enum = 0xf8,
+ ieee_be_record_enum = 0xf9
+ }
+ieee_record_enum_type;
+
+typedef struct ieee_section
+ {
+ unsigned int section_index;
+ unsigned int section_type;
+ char * section_name;
+ unsigned int parent_section_index;
+ unsigned int sibling_section_index;
+ unsigned int context_index;
+ }
+ieee_section_type;
+
+#define IEEE_REFERENCE_BASE 11
+#define IEEE_PUBLIC_BASE 32
+#define IEEE_SECTION_NUMBER_BASE 1
+
diff --git a/contrib/gdb/include/libiberty.h b/contrib/gdb/include/libiberty.h
new file mode 100644
index 0000000..761b2cf
--- /dev/null
+++ b/contrib/gdb/include/libiberty.h
@@ -0,0 +1,335 @@
+/* Function declarations for libiberty.
+
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
+ Note - certain prototypes declared in this header file are for
+ functions whoes implementation copyright does not belong to the
+ FSF. Those prototypes are present in this file for reference
+ purposes only and their presence in this file should not construed
+ as an indication of ownership by the FSF of the implementation of
+ those functions in any way or form whatsoever.
+
+ 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty. */
+
+#ifndef LIBIBERTY_H
+#define LIBIBERTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+
+#ifdef ANSI_PROTOTYPES
+/* Get a definition for size_t. */
+#include <stddef.h>
+/* Get a definition for va_list. */
+#include <stdarg.h>
+#endif
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv PARAMS ((char **));
+
+/* Duplicate an argument vector. Allocates memory using malloc. Use
+ freeargv to free the vector. */
+
+extern char **dupargv PARAMS ((char **)) ATTRIBUTE_MALLOC;
+
+
+/* Return the last component of a path name. Note that we can't use a
+ prototype here because the parameter is declared inconsistently
+ across different systems, sometimes as "char *" and sometimes as
+ "const char *" */
+
+/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ to find the declaration so provide a fully prototyped one. If it
+ is 1, we found it so don't provide any declaration at all. */
+#if !HAVE_DECL_BASENAME
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (HAVE_DECL_BASENAME)
+extern char *basename PARAMS ((const char *));
+#else
+extern char *basename ();
+#endif
+#endif
+
+/* A well-defined basename () that is always compiled in. */
+
+extern const char *lbasename PARAMS ((const char *));
+
+/* A well-defined realpath () that is always compiled in. */
+
+extern char *lrealpath PARAMS ((const char *));
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. */
+
+extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. The first argument is
+ not one of the strings to be concatenated, but if not NULL is a
+ pointer to be freed after the new string is created, similar to the
+ way xrealloc works. */
+
+extern char *reconcat PARAMS ((char *, const char *, ...)) ATTRIBUTE_MALLOC;
+
+/* Determine the length of concatenating an arbitrary number of
+ strings. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. */
+
+extern unsigned long concat_length PARAMS ((const char *, ...));
+
+/* Concatenate an arbitrary number of strings into a SUPPLIED area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy PARAMS ((char *, const char *, ...));
+
+/* Concatenate an arbitrary number of strings into a GLOBAL area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy2 PARAMS ((const char *, ...));
+
+/* This is the global area used by concat_copy2. */
+
+extern char *libiberty_concat_ptr;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using alloca. The arguments are
+ evaluated twice! */
+#define ACONCAT(ACONCAT_PARAMS) \
+ (libiberty_concat_ptr = alloca (concat_length ACONCAT_PARAMS + 1), \
+ concat_copy2 ACONCAT_PARAMS)
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch PARAMS ((int fd1, int fd2));
+
+/* Get the working directory. The result is cached, so don't call
+ chdir() between calls to getpwd(). */
+
+extern char * getpwd PARAMS ((void));
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time PARAMS ((void));
+
+/* Generate a relocated path to some installation directory. Allocates
+ return value using malloc. */
+
+extern char *make_relative_prefix PARAMS ((const char *, const char *,
+ const char *));
+
+/* Choose a temporary directory to use for scratch files. */
+
+extern char *choose_temp_base PARAMS ((void)) ATTRIBUTE_MALLOC;
+
+/* Return a temporary file name or NULL if unable to create one. */
+
+extern char *make_temp_file PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* Allocate memory filled with spaces. Allocates using malloc. */
+
+extern const char *spaces PARAMS ((int count));
+
+/* Return the maximum error number for which strerror will return a
+ string. */
+
+extern int errno_max PARAMS ((void));
+
+/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
+ "EINVAL"). */
+
+extern const char *strerrno PARAMS ((int));
+
+/* Given the name of an errno value, return the value. */
+
+extern int strtoerrno PARAMS ((const char *));
+
+/* ANSI's strerror(), but more robust. */
+
+extern char *xstrerror PARAMS ((int));
+
+/* Return the maximum signal number for which strsignal will return a
+ string. */
+
+extern int signo_max PARAMS ((void));
+
+/* Return a signal message string for a signal number
+ (e.g., strsignal (SIGHUP) returns something like "Hangup"). */
+/* This is commented out as it can conflict with one in system headers.
+ We still document its existence though. */
+
+/*extern const char *strsignal PARAMS ((int));*/
+
+/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
+ "SIGHUP"). */
+
+extern const char *strsigno PARAMS ((int));
+
+/* Given the name of a signal, return its number. */
+
+extern int strtosigno PARAMS ((const char *));
+
+/* Register a function to be run by xexit. Returns 0 on success. */
+
+extern int xatexit PARAMS ((void (*fn) (void)));
+
+/* Exit, calling all the functions registered with xatexit. */
+
+extern void xexit PARAMS ((int status)) ATTRIBUTE_NORETURN;
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name PARAMS ((const char *));
+
+/* Report an allocation failure. */
+extern void xmalloc_failed PARAMS ((size_t)) ATTRIBUTE_NORETURN;
+
+/* Allocate memory without fail. If malloc fails, this will print a
+ message to stderr (using the name set by xmalloc_set_program_name,
+ if any) and then call xexit. */
+
+extern PTR xmalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+
+/* Reallocate memory without fail. This works like xmalloc. Note,
+ realloc type functions are not suitable for attribute malloc since
+ they may return the same address across multiple calls. */
+
+extern PTR xrealloc PARAMS ((PTR, size_t));
+
+/* Allocate memory without fail and set it to zero. This works like
+ xmalloc. */
+
+extern PTR xcalloc PARAMS ((size_t, size_t)) ATTRIBUTE_MALLOC;
+
+/* Copy a string into a memory buffer without fail. */
+
+extern char *xstrdup PARAMS ((const char *)) ATTRIBUTE_MALLOC;
+
+/* Copy an existing memory buffer to a new memory buffer without fail. */
+
+extern PTR xmemdup PARAMS ((const PTR, size_t, size_t)) ATTRIBUTE_MALLOC;
+
+/* Physical memory routines. Return values are in BYTES. */
+extern double physmem_total PARAMS ((void));
+extern double physmem_available PARAMS ((void));
+
+/* hex character manipulation routines */
+
+#define _hex_array_size 256
+#define _hex_bad 99
+extern const unsigned char _hex_value[_hex_array_size];
+extern void hex_init PARAMS ((void));
+#define hex_p(c) (hex_value (c) != _hex_bad)
+/* If you change this, note well: Some code relies on side effects in
+ the argument being performed exactly once. */
+#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)])
+
+/* Definitions used by the pexecute routine. */
+
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+/* Execute a program. */
+
+extern int pexecute PARAMS ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+
+/* Wait for pexecute to finish. */
+
+extern int pwait PARAMS ((int, int *, int));
+
+#if !HAVE_DECL_ASPRINTF
+/* Like sprintf but provides a pointer to malloc'd storage, which must
+ be freed by the caller. */
+
+extern int asprintf PARAMS ((char **, const char *, ...)) ATTRIBUTE_PRINTF_2;
+#endif
+
+#if !HAVE_DECL_VASPRINTF
+/* Like vsprintf but provides a pointer to malloc'd storage, which
+ must be freed by the caller. */
+
+extern int vasprintf PARAMS ((char **, const char *, va_list))
+ ATTRIBUTE_PRINTF(2,0);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Drastically simplified alloca configurator. If we're using GCC,
+ we use __builtin_alloca; otherwise we use the C alloca. The C
+ alloca is always available. You can override GCC by defining
+ USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is
+ also set/unset as it is often used to indicate whether code needs
+ to call alloca(0). */
+extern PTR C_alloca PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+#undef alloca
+#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA
+# define alloca(x) __builtin_alloca(x)
+# undef C_ALLOCA
+# define ASTRDUP(X) \
+ (__extension__ ({ const char *const libiberty_optr = (X); \
+ const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \
+ char *const libiberty_nptr = alloca (libiberty_len); \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); }))
+#else
+# define alloca(x) C_alloca(x)
+# undef USE_C_ALLOCA
+# define USE_C_ALLOCA 1
+# undef C_ALLOCA
+# define C_ALLOCA 1
+extern const char *libiberty_optr;
+extern char *libiberty_nptr;
+extern unsigned long libiberty_len;
+# define ASTRDUP(X) \
+ (libiberty_optr = (X), \
+ libiberty_len = strlen (libiberty_optr) + 1, \
+ libiberty_nptr = alloca (libiberty_len), \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/contrib/gdb/include/oasys.h b/contrib/gdb/include/oasys.h
new file mode 100644
index 0000000..c8f737a
--- /dev/null
+++ b/contrib/gdb/include/oasys.h
@@ -0,0 +1,192 @@
+/* Oasys object format header file for BFD.
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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.
+
+ Contributed by Cygnus Support. */
+
+#define OASYS_MAX_SEC_COUNT 16
+/* **** */
+
+typedef struct oasys_archive_header
+ {
+ unsigned int version;
+ char create_date[12];
+ char revision_date[12];
+ unsigned int mod_count;
+ file_ptr mod_tbl_offset;
+ unsigned int sym_tbl_size;
+ unsigned int sym_count;
+ file_ptr sym_tbl_offset;
+ unsigned int xref_count;
+ file_ptr xref_lst_offset;
+ }
+oasys_archive_header_type;
+
+typedef struct oasys_extarchive_header
+ {
+ bfd_byte version[4];
+ bfd_byte create_date[12];
+ bfd_byte revision_date[12];
+ bfd_byte mod_count[4];
+ bfd_byte mod_tbl_offset[4];
+ bfd_byte sym_tbl_size[4];
+ bfd_byte sym_count[4];
+ bfd_byte sym_tbl_offset[4];
+ bfd_byte xref_count[4];
+ bfd_byte xref_lst_offset[4];
+ }
+oasys_extarchive_header_type;
+
+typedef struct oasys_module_table
+ {
+ int mod_number;
+ char mod_date[12];
+ unsigned int mod_size;
+ unsigned int dep_count;
+ unsigned int depee_count;
+ file_ptr file_offset;
+ unsigned int sect_count;
+ char *module_name;
+ unsigned int module_name_size;
+ }
+oasys_module_table_type;
+
+typedef struct oasys_extmodule_table_a
+ {
+ bfd_byte mod_number[4];
+ bfd_byte mod_date[12];
+ bfd_byte mod_size[4];
+ bfd_byte dep_count[4];
+ bfd_byte depee_count[4];
+ bfd_byte sect_count[4];
+ bfd_byte file_offset[4];
+ bfd_byte mod_name[32];
+ }
+oasys_extmodule_table_type_a_type;
+
+typedef struct oasys_extmodule_table_b
+ {
+ bfd_byte mod_number[4];
+ bfd_byte mod_date[12];
+ bfd_byte mod_size[4];
+ bfd_byte dep_count[4];
+ bfd_byte depee_count[4];
+ bfd_byte sect_count[4];
+ bfd_byte file_offset[4];
+ bfd_byte mod_name_length[4];
+ }
+oasys_extmodule_table_type_b_type;
+
+typedef enum oasys_record
+ {
+ oasys_record_is_end_enum = 0,
+ oasys_record_is_data_enum = 1,
+ oasys_record_is_symbol_enum = 2,
+ oasys_record_is_header_enum = 3,
+ oasys_record_is_named_section_enum = 4,
+ oasys_record_is_com_enum = 5,
+ oasys_record_is_debug_enum = 6,
+ oasys_record_is_section_enum = 7,
+ oasys_record_is_debug_file_enum = 8,
+ oasys_record_is_module_enum = 9,
+ oasys_record_is_local_enum = 10
+ }
+oasys_record_enum_type;
+
+typedef struct oasys_record_header
+ {
+ unsigned char length;
+ unsigned char check_sum;
+ unsigned char type;
+ unsigned char fill;
+ }
+oasys_record_header_type;
+
+typedef struct oasys_data_record
+ {
+ oasys_record_header_type header;
+ unsigned char relb;
+ bfd_byte addr[4];
+ /* maximum total size of data record is 255 bytes */
+ bfd_byte data[246];
+ }
+oasys_data_record_type;
+
+typedef struct oasys_header_record
+ {
+ oasys_record_header_type header;
+ unsigned char version_number;
+ unsigned char rev_number;
+ char module_name[26-6];
+ char description[64-26];
+ }
+oasys_header_record_type;
+
+#define OASYS_VERSION_NUMBER 0
+#define OASYS_REV_NUMBER 0
+
+typedef struct oasys_symbol_record
+ {
+ oasys_record_header_type header;
+ unsigned char relb;
+ bfd_byte value[4];
+ bfd_byte refno[2];
+ char name[64];
+ }
+oasys_symbol_record_type;
+
+#define RELOCATION_PCREL_BIT 0x80
+#define RELOCATION_32BIT_BIT 0x40
+#define RELOCATION_TYPE_BITS 0x30
+#define RELOCATION_TYPE_ABS 0x00
+#define RELOCATION_TYPE_REL 0x10
+#define RELOCATION_TYPE_UND 0x20
+#define RELOCATION_TYPE_COM 0x30
+#define RELOCATION_SECT_BITS 0x0f
+
+typedef struct oasys_section_record
+ {
+ oasys_record_header_type header;
+ unsigned char relb;
+ bfd_byte value[4];
+ bfd_byte vma[4];
+ bfd_byte fill[3];
+ }
+oasys_section_record_type;
+
+typedef struct oasys_end_record
+ {
+ oasys_record_header_type header;
+ unsigned char relb;
+ bfd_byte entry[4];
+ bfd_byte fill[2];
+ bfd_byte zero;
+ }
+oasys_end_record_type;
+
+typedef union oasys_record_union
+ {
+ oasys_record_header_type header;
+ oasys_data_record_type data;
+ oasys_section_record_type section;
+ oasys_symbol_record_type symbol;
+ oasys_header_record_type first;
+ oasys_end_record_type end;
+ bfd_byte pad[256];
+ }
+oasys_record_union_type;
diff --git a/contrib/gdb/include/obstack.h b/contrib/gdb/include/obstack.h
new file mode 100644
index 0000000..5496ff2
--- /dev/null
+++ b/contrib/gdb/include/obstack.h
@@ -0,0 +1,611 @@
+/* obstack.h - object stack macros
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+ 1999, 2000
+ Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
+
+ 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, 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. */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' an obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We use subtraction of (char *) 0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+# define __PTR_TO_INT(P) ((P) - (char *) 0)
+#endif
+
+#ifndef __INT_TO_PTR
+# define __INT_TO_PTR(P) ((P) + (char *) 0)
+#endif
+
+/* We need the type of the resulting object. If __PTRDIFF_TYPE__ is
+ defined, as with GNU C, use that; that way we don't pollute the
+ namespace with <stddef.h>'s symbols. Otherwise, if <stddef.h> is
+ available, include it and use ptrdiff_t. In traditional C, long is
+ the best that we can do. */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# ifdef HAVE_STDDEF_H
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+# else
+# define PTR_INT_TYPE long
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+# if defined __STDC__ && __STDC__
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
+# else
+# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N))
+# endif
+#else
+# ifdef memcpy
+# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N))
+# else
+# define _obstack_memcpy(To, From, N) bcopy ((char *)(From), (To), (N))
+# endif
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ PTR_INT_TYPE temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+#if defined __STDC__ && __STDC__
+ /* These prototypes vary based on `use_extra_arg', and we use
+ casts to the prototypeless function type in all assignments,
+ but having prototypes here quiets -Wstrict-prototypes. */
+ struct _obstack_chunk *(*chunkfun) (void *, long);
+ void (*freefun) (void *, struct _obstack_chunk *);
+ void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#else
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#endif
+ unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
+ unsigned maybe_empty_object:1;/* There is a possibility that the current
+ chunk contains a zero-length object. This
+ prevents freeing the chunk if we allocate
+ a bigger chunk to replace it. */
+ unsigned alloc_failed:1; /* No longer used, as we now call the failed
+ handler on error, but retained for binary
+ compatibility. */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#if defined __STDC__ && __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern int _obstack_begin (struct obstack *, int, int,
+ void *(*) (long), void (*) (void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (void *, long),
+ void (*) (void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *);
+#else
+extern void _obstack_newchunk ();
+extern void _obstack_free ();
+extern int _obstack_begin ();
+extern int _obstack_begin_1 ();
+extern int _obstack_memory_used ();
+#endif
+
+#if defined __STDC__ && __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_make_room (struct obstack *obstack, int size);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+int obstack_memory_used (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+ more memory. This can be set to a user defined function. The
+ default action is to print a message and abort. */
+#if defined __STDC__ && __STDC__
+extern void (*obstack_alloc_failed_handler) (void);
+#else
+extern void (*obstack_alloc_failed_handler) ();
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+extern int obstack_exit_failure;
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list in
+ standard C version. */
+#if defined __STDC__ && __STDC__
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) (void *, long)) (chunkfun), \
+ (void (*) (void *, void *)) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#else
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)()) (newfreefun))
+
+#endif
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
+
+#if defined __GNUC__ && defined __STDC__ && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+ does not implement __extension__. But that compiler doesn't define
+ __GNUC_MINOR__. */
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+# define __extension__
+# endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+# define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+# define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+# define obstack_make_room(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ (void) 0; })
+
+# define obstack_empty_p(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); })
+
+# define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len); \
+ _obstack_memcpy (__o->next_free, (where), __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+# define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len + 1); \
+ _obstack_memcpy (__o->next_free, (where), __len); \
+ __o->next_free += __len; \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+# define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, 1); \
+ obstack_1grow_fast (__o, datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+# define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (void *)); \
+ obstack_ptr_grow_fast (__o, datum); })
+
+# define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (int) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (int)); \
+ obstack_int_grow_fast (__o, datum); })
+
+# define obstack_ptr_grow_fast(OBSTACK,aptr) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ *(const void **) __o1->next_free = (aptr); \
+ __o1->next_free += sizeof (const void *); \
+ (void) 0; })
+
+# define obstack_int_grow_fast(OBSTACK,aint) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ *(int *) __o1->next_free = (aint); \
+ __o1->next_free += sizeof (int); \
+ (void) 0; })
+
+# define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ obstack_blank_fast (__o, __len); \
+ (void) 0; })
+
+# define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+# define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+# define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+# define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value; \
+ value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ if (__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ __o1->next_free = __o1->chunk_limit; \
+ __o1->object_base = __o1->next_free; \
+ value; })
+
+# define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+# define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+# define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0)
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+
+# define obstack_make_room(h,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0))
+
+# define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ _obstack_memcpy ((h)->next_free, (where), (h)->temp), \
+ (h)->next_free += (h)->temp)
+
+# define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ _obstack_memcpy ((h)->next_free, (where), (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)
+
+# define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ obstack_1grow_fast (h, datum))
+
+# define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ obstack_ptr_grow_fast (h, datum))
+
+# define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ obstack_int_grow_fast (h, datum))
+
+# define obstack_ptr_grow_fast(h,aptr) \
+ (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+# define obstack_int_grow_fast(h,aint) \
+ (((int *) ((h)->next_free += sizeof (int)))[-1] = (aptr))
+
+# define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ obstack_blank_fast (h, (h)->temp))
+
+# define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+# define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *) (h)->chunk \
+ > (h)->chunk_limit - (char *) (h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp))
+
+# if defined __STDC__ && __STDC__
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+# else
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+# endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#ifdef __cplusplus
+} /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/contrib/gdb/include/os9k.h b/contrib/gdb/include/os9k.h
new file mode 100644
index 0000000..596f56d
--- /dev/null
+++ b/contrib/gdb/include/os9k.h
@@ -0,0 +1,181 @@
+/* os9k.h - OS-9000 i386 module header definitions
+ Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#if !defined(_MODULE_H)
+#define _MODULE_H
+
+#define _MPF386
+
+/* Size of common header less parity field. */
+#define N_M_PARITY (sizeof(mh_com)-sizeof(unisgned short))
+#define OLD_M_PARITY 46
+#define M_PARITY N_M_PARITY
+
+#ifdef _MPF68K
+#define MODSYNC 0x4afc /* Module header sync code for 680x0 processors. */
+#endif
+
+#ifdef _MPF386
+#define MODSYNC 0x4afc /* Module header sync code for 80386 processors. */
+#endif
+
+#define MODREV 1 /* Module format revision 1. */
+#define CRCCON 0x800063 /* CRC polynomial constant. */
+
+/* Module access permission values. */
+#define MP_OWNER_READ 0x0001
+#define MP_OWNER_WRITE 0x0002
+#define MP_OWNER_EXEC 0x0004
+#define MP_GROUP_READ 0x0010
+#define MP_GROUP_WRITE 0x0020
+#define MP_GROUP_EXEC 0x0040
+#define MP_WORLD_READ 0x0100
+#define MP_WORLD_WRITE 0x0200
+#define MP_WORLD_EXEC 0x0400
+#define MP_WORLD_ACCESS 0x0777
+#define MP_OWNER_MASK 0x000f
+#define MP_GROUP_MASK 0x00f0
+#define MP_WORLD_MASK 0x0f00
+#define MP_SYSTM_MASK 0xf000
+
+/* Module Type/Language values. */
+#define MT_ANY 0
+#define MT_PROGRAM 0x0001
+#define MT_SUBROUT 0x0002
+#define MT_MULTI 0x0003
+#define MT_DATA 0x0004
+#define MT_TRAPLIB 0x000b
+#define MT_SYSTEM 0x000c
+#define MT_FILEMAN 0x000d
+#define MT_DEVDRVR 0x000e
+#define MT_DEVDESC 0x000f
+#define MT_MASK 0xff00
+
+#define ML_ANY 0
+#define ML_OBJECT 1
+#define ML_ICODE 2
+#define ML_PCODE 3
+#define ML_CCODE 4
+#define ML_CBLCODE 5
+#define ML_FRTNCODE 6
+#define ML_MASK 0x00ff
+
+#define mktypelang(type, lang) (((type) << 8) | (lang))
+
+/* Module Attribute values. */
+#define MA_REENT 0x80
+#define MA_GHOST 0x40
+#define MA_SUPER 0x20
+#define MA_MASK 0xff00
+#define MR_MASK 0x00ff
+
+#define mkattrevs(attr, revs) (((attr) << 8) | (revs))
+
+#define m_user m_owner.grp_usr.usr
+#define m_group m_owner.grp_usr.grp
+#define m_group_user m_owner.group_user
+
+/* Macro definitions for accessing module header fields. */
+#define MODNAME(mod) ((u_char*)((u_char*)mod + ((Mh_com)mod)->m_name))
+#if 0
+/* Appears not to be used, and the u_int32 typedef is gone (because it
+ conflicted with a Mach header. */
+#define MODSIZE(mod) ((u_int32)((Mh_com)mod)->m_size)
+#endif /* 0 */
+#define MHCOM_BYTES_SIZE 80
+#define N_BADMAG(a) (((a).a_info) != MODSYNC)
+
+typedef struct mh_com
+{
+ /* Sync bytes ($4afc). */
+ unsigned char m_sync[2];
+ unsigned char m_sysrev[2]; /* System revision check value. */
+ unsigned char m_size[4]; /* Module size. */
+ unsigned char m_owner[4]; /* Group/user id. */
+ unsigned char m_name[4]; /* Offset to module name. */
+ unsigned char m_access[2]; /* Access permissions. */
+ unsigned char m_tylan[2]; /* Type/lang. */
+ unsigned char m_attrev[2]; /* Rev/attr. */
+ unsigned char m_edit[2]; /* Edition. */
+ unsigned char m_needs[4]; /* Module hardware requirements flags. (reserved). */
+ unsigned char m_usage[4]; /* Comment string offset. */
+ unsigned char m_symbol[4]; /* Symbol table offset. */
+ unsigned char m_exec[4]; /* Offset to execution entry point. */
+ unsigned char m_excpt[4]; /* Offset to exception entry point. */
+ unsigned char m_data[4]; /* Data storage requirement. */
+ unsigned char m_stack[4]; /* Stack size. */
+ unsigned char m_idata[4]; /* Offset to initialized data. */
+ unsigned char m_idref[4]; /* Offset to data reference lists. */
+ unsigned char m_init[4]; /* Initialization routine offset. */
+ unsigned char m_term[4]; /* Termination routine offset. */
+ unsigned char m_ident[2]; /* Ident code for ident program. */
+ char m_spare[8]; /* Reserved bytes. */
+ unsigned char m_parity[2]; /* Header parity. */
+} mh_com,*Mh_com;
+
+/* Executable memory module. */
+typedef mh_com *Mh_exec,mh_exec;
+
+/* Data memory module. */
+typedef mh_com *Mh_data,mh_data;
+
+/* File manager memory module. */
+typedef mh_com *Mh_fman,mh_fman;
+
+/* Device driver module. */
+typedef mh_com *Mh_drvr,mh_drvr;
+
+/* Trap handler module. */
+typedef mh_com mh_trap, *Mh_trap;
+
+/* Device descriptor module. */
+typedef mh_com *Mh_dev,mh_dev;
+
+/* Configuration module. */
+typedef mh_com *Mh_config, mh_config;
+
+#if 0
+
+#if !defined(_MODDIR_H)
+/* Go get _os_fmod (and others). */
+#include <moddir.h>
+#endif
+
+error_code _os_crc (void *, u_int32, int *);
+error_code _os_datmod (char *, u_int32, u_int16 *, u_int16 *, u_int32, void **, mh_data **);
+error_code _os_get_moddir (void *, u_int32 *);
+error_code _os_initdata (mh_com *, void *);
+error_code _os_link (char **, mh_com **, void **, u_int16 *, u_int16 *);
+error_code _os_linkm (mh_com *, void **, u_int16 *, u_int16 *);
+error_code _os_load (char *, mh_com **, void **, u_int32, u_int16 *, u_int16 *, u_int32);
+error_code _os_mkmodule (char *, u_int32, u_int16 *, u_int16 *, u_int32, void **, mh_com **, u_int32);
+error_code _os_modaddr (void *, mh_com **);
+error_code _os_setcrc (mh_com *);
+error_code _os_slink (u_int32, char *, void **, void **, mh_com **);
+error_code _os_slinkm (u_int32, mh_com *, void **, void **);
+error_code _os_unlink (mh_com *);
+error_code _os_unload (char *, u_int32);
+error_code _os_tlink (u_int32, char *, void **, mh_trap **, void *, u_int32);
+error_code _os_tlinkm (u_int32, mh_com *, void **, void *, u_int32);
+error_code _os_iodel (mh_com *);
+error_code _os_vmodul (mh_com *, mh_com *, u_int32);
+#endif /* 0 */
+
+#endif
diff --git a/contrib/gdb/include/progress.h b/contrib/gdb/include/progress.h
new file mode 100644
index 0000000..23b0960
--- /dev/null
+++ b/contrib/gdb/include/progress.h
@@ -0,0 +1,37 @@
+/* Default definitions for progress macros.
+ Copyright 1994 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* The default definitions below are intended to be replaced by real
+ definitions, if building the tools for an interactive programming
+ environment. */
+
+#ifndef _PROGRESS_H
+#define _PROGRESS_H
+
+#ifndef START_PROGRESS
+#define START_PROGRESS(STR,N)
+#endif
+
+#ifndef PROGRESS
+#define PROGRESS(X)
+#endif
+
+#ifndef END_PROGRESS
+#define END_PROGRESS(STR)
+#endif
+
+#endif /* _PROGRESS_H */
diff --git a/contrib/gdb/move-if-change b/contrib/gdb/move-if-change
new file mode 100755
index 0000000..ee1b348
--- /dev/null
+++ b/contrib/gdb/move-if-change
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+if
+test -r $2
+then
+if
+cmp $1 $2 > /dev/null
+then
+echo $2 is unchanged
+rm -f $1
+else
+mv -f $1 $2
+fi
+else
+mv -f $1 $2
+fi
OpenPOWER on IntegriCloud