summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@gnat.com>2002-11-01 22:08:44 +0000
committerJoel Brobecker <brobecker@gnat.com>2002-11-01 22:08:44 +0000
commit41c630384cfc3505a2279d6aa2946595fb6c5ce4 (patch)
treed6a9c162c6543fc1e3b99a5c24f7d00c6e839bd1
parentd12a9024ea853d2a9da1d8e5e0099cc382401070 (diff)
downloadgdb-41c630384cfc3505a2279d6aa2946595fb6c5ce4.tar.gz
New interix-specific files:
* config/i386/nm-interix.h: New file. * config/i386/interix.mh: New file. * config/i386/interix.mt: New file. * i386-interix-nat.c: New file. * i386-interix-tdep.c: New file.
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/config/i386/interix.mh9
-rw-r--r--gdb/config/i386/interix.mt3
-rw-r--r--gdb/config/i386/nm-interix.h35
-rw-r--r--gdb/i386-interix-nat.c190
-rw-r--r--gdb/i386-interix-tdep.c365
6 files changed, 611 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f993edbe389..822cc040a5f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2002-11-01 Joel Brobecker <brobecker@gnat.com>
+
+ New interix-specific files:
+ * config/i386/nm-interix.h: New file.
+ * config/i386/interix.mh: New file.
+ * config/i386/interix.mt: New file.
+ * i386-interix-nat.c: New file.
+ * i386-interix-tdep.c: New file.
+
2002-11-01 Andrew Cagney <cagney@redhat.com>
* frame.h (deprecated_generic_get_saved_register): Rename
diff --git a/gdb/config/i386/interix.mh b/gdb/config/i386/interix.mh
new file mode 100644
index 00000000000..23311d615fa
--- /dev/null
+++ b/gdb/config/i386/interix.mh
@@ -0,0 +1,9 @@
+# Host: Intel 386 running Interix
+XDEPFILES=
+NATDEPFILES= corelow.o core-regset.o fork-child.o i386-interix-nat.o \
+ procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
+NAT_FILE= nm-interix.h
+XM_FILE= xm-interix.h
+# The below may be temporary; mmalloc relies on sbrk() at the moment
+MMALLOC=
+MMALLOC_CFLAGS=-DNO_MMALLOC
diff --git a/gdb/config/i386/interix.mt b/gdb/config/i386/interix.mt
new file mode 100644
index 00000000000..8d609624757
--- /dev/null
+++ b/gdb/config/i386/interix.mt
@@ -0,0 +1,3 @@
+# Target: Intel 386 running Interix
+TDEPFILES= i386-tdep.o i387-tdep.o i386-interix-tdep.o solib.o solib-pei.o
+TM_FILE= tm-i386.h
diff --git a/gdb/config/i386/nm-interix.h b/gdb/config/i386/nm-interix.h
new file mode 100644
index 00000000000..b8b003a58d7
--- /dev/null
+++ b/gdb/config/i386/nm-interix.h
@@ -0,0 +1,35 @@
+/* Native-dependent definitions for Intel 386 running Interix, for GDB.
+ Copyright 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef NM_INTERIX_H
+#define NM_INTERIX_H
+
+/* Be shared lib aware. */
+#include "solib.h"
+
+/* submodes of USE_PROC_FS. */
+#define UNIXWARE
+
+/* It's ALMOST coff; bfd does the same thing. Mostly used in coffread.c. */
+#define COFF_IMAGE_WITH_PE
+
+/* Turn on our own child_pid_to_exec_file. */
+#define CHILD_PID_TO_EXEC_FILE
+
+#endif /* NM_INTERIX_H */
diff --git a/gdb/i386-interix-nat.c b/gdb/i386-interix-nat.c
new file mode 100644
index 00000000000..9c4daeda422
--- /dev/null
+++ b/gdb/i386-interix-nat.c
@@ -0,0 +1,190 @@
+/* Native-dependent code for Interix running on i386's, for GDB.
+ Copyright 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 <sys/procfs.h>
+#include <inferior.h>
+#include <fcntl.h>
+
+#include <i386-tdep.h>
+#include "gdb_string.h"
+#include "gdbcore.h"
+#include "gregset.h"
+#include "regcache.h"
+
+typedef unsigned long greg_t;
+
+/* This is a duplicate of the table in i386-linux-nat.c. */
+
+static int regmap[] = {
+ EAX, ECX, EDX, EBX,
+ UESP, EBP, ESI, EDI,
+ EIP, EFL, CS, SS,
+ DS, ES, FS, GS,
+};
+
+/* Forward declarations. */
+extern void _initialize_core_interix (void);
+extern initialize_file_ftype _initialize_core_interix;
+
+/* Given a pointer to a general register set in /proc format (gregset_t *),
+ unpack the register contents and supply them as gdb's idea of the current
+ register values. */
+
+void
+supply_gregset (gregset_t *gregsetp)
+{
+ int regi;
+ greg_t *regp = (greg_t *) & gregsetp->gregs;
+
+ for (regi = 0; regi < I386_NUM_GREGS; regi++)
+ {
+ supply_register (regi, (char *) (regp + regmap[regi]));
+ }
+}
+
+/* Store GDB's value for REGNO in *GREGSETP. If REGNO is -1, do all
+ of them. */
+
+void
+fill_gregset (gregset_t *gregsetp, int regno)
+{
+ int regi;
+ greg_t *regp = (greg_t *) gregsetp->gregs;
+
+ for (regi = 0; regi < I386_NUM_GREGS; regi++)
+ if (regno == -1 || regi == regno)
+ regcache_collect (regi, (void *) (regp + regmap[regi]));
+}
+
+/* Fill GDB's register file with the floating-point register values in
+ *FPREGSETP. */
+
+void
+supply_fpregset (fpregset_t *fpregsetp)
+{
+ i387_supply_fsave ((char *) fpregsetp);
+}
+
+/* Given a pointer to a floating point register set in (fpregset_t *)
+ format, update all of the registers from gdb's idea of the current
+ floating point register set. */
+
+void
+fill_fpregset (fpregset_t *fpregsetp, int regno)
+{
+ i387_fill_fsave ((char *) fpregsetp, regno);
+}
+
+/* Read the values of either the general register set (WHICH equals 0)
+ or the floating point register set (WHICH equals 2) from the core
+ file data (pointed to by CORE_REG_SECT), and update gdb's idea of
+ their current values. The CORE_REG_SIZE parameter is compared to
+ the size of the gregset or fpgregset structures (as appropriate) to
+ validate the size of the structure from the core file. The
+ REG_ADDR parameter is ignored. */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR reg_addr)
+{
+ gdb_gregset_t gregset;
+ gdb_fpregset_t fpregset;
+
+ if (which == 0)
+ {
+ if (core_reg_size != sizeof (gregset))
+ {
+ warning ("wrong size gregset struct in core file");
+ }
+ else
+ {
+ memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
+ supply_gregset (&gregset);
+ }
+ }
+ else if (which == 2)
+ {
+ if (core_reg_size != sizeof (fpregset))
+ {
+ warning ("wrong size fpregset struct in core file");
+ }
+ else
+ {
+ memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
+ supply_fpregset (&fpregset);
+ }
+ }
+}
+
+#include <setjmp.h>
+
+static struct core_fns interix_core_fns =
+{
+ bfd_target_coff_flavour, /* core_flavour (more or less) */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+
+void
+_initialize_core_interix (void)
+{
+ add_core_fns (&interix_core_fns);
+}
+
+/* We don't have a /proc/pid/file or /proc/pid/exe to read a link from,
+ so read it from the same place ps gets the name. */
+
+char *
+child_pid_to_exec_file (int pid)
+{
+ char *path;
+ char *buf;
+ int fd, c;
+ char *p;
+
+ xasprintf (&path, "/proc/%d/stat", pid);
+ buf = xcalloc (MAXPATHLEN + 1, sizeof (char));
+ make_cleanup (xfree, path);
+ make_cleanup (xfree, buf);
+
+ fd = open (path, O_RDONLY);
+
+ if (fd < 0)
+ return NULL;
+
+ /* Skip over "Argv0\t". */
+ lseek (fd, 6, SEEK_SET);
+
+ c = read (fd, buf, MAXPATHLEN);
+ close (fd);
+
+ if (c < 0)
+ return NULL;
+
+ buf[c] = '\0'; /* Ensure null termination. */
+ p = strchr (buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ return buf;
+}
diff --git a/gdb/i386-interix-tdep.c b/gdb/i386-interix-tdep.c
new file mode 100644
index 00000000000..ff310ecad35
--- /dev/null
+++ b/gdb/i386-interix-tdep.c
@@ -0,0 +1,365 @@
+/* Target-dependent code for Interix running on i386's, for GDB.
+ Copyright 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 "arch-utils.h"
+
+#include "frame.h"
+#include "gdb_string.h"
+#include "gdb-stabs.h"
+#include "gdbcore.h"
+#include "gdbtypes.h"
+#include "i386-tdep.h"
+#include "inferior.h"
+#include "libbfd.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "regcache.h"
+
+/* offsetof (mcontext_t, gregs.gregs[EBP]) */
+static const int mcontext_EBP_greg_offset = 180;
+
+/* offsetof (mcontext_t, gregs.gregs[EIP]) */
+static const int mcontext_EIP_greg_offset = 184;
+
+/* offsetof (mcontext_t, gregs.gregs[UESP]) */
+static const int mcontext_UESP_greg_offset = 196;
+
+/* offsetof (mcontext_t, gregs.reserved[1]) */
+static const int mcontext_syscall_greg_offset = 4;
+
+/* offsetof (_JUMP_BUFFER, Eip) */
+static const int jump_buffer_Eip_offset = 20;
+
+/* See procfs.c and *interix*.h in config/[alpha,i386]. */
+/* ??? These should be static, but this needs a bit of work before this
+ can be done. */
+CORE_ADDR tramp_start;
+CORE_ADDR tramp_end;
+CORE_ADDR null_start;
+CORE_ADDR null_end;
+int winver; /* Windows NT version number */
+
+/* Forward declarations. */
+extern void _initialize_i386_interix_tdep (void);
+extern initialize_file_ftype _initialize_i386_interix_tdep;
+
+/* Adjust the section offsets in an objfile structure so that it's correct
+ for the type of symbols being read (or undo it with the _restore
+ arguments).
+
+ If main programs ever start showing up at other than the default Image
+ Base, this is where that would likely be applied. */
+
+void
+pei_adjust_objfile_offsets (struct objfile *objfile,
+ enum objfile_adjusts type)
+{
+ int i;
+ CORE_ADDR symbols_offset;
+
+ switch (type)
+ {
+ case adjust_for_symtab:
+ symbols_offset = NONZERO_LINK_BASE (objfile->obfd);
+ break;
+ case adjust_for_symtab_restore:
+ symbols_offset = -NONZERO_LINK_BASE (objfile->obfd);
+ break;
+ case adjust_for_stabs:
+ case adjust_for_stabs_restore:
+ case adjust_for_dwarf:
+ case adjust_for_dwarf_restore:
+ default:
+ return;
+ }
+
+ for (i = 0; i < SECT_OFF_MAX; i++)
+ {
+ (objfile->section_offsets)->offsets[i] += symbols_offset;
+ }
+}
+
+static int
+i386_interix_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+ /* This is sufficient, where used, but is NOT a complete test; There
+ is more in INIT_EXTRA_FRAME_INFO (a.k.a. interix_back_one_frame). */
+ return ((pc >= tramp_start && pc < tramp_end)
+ || (pc >= null_start && pc < null_end));
+}
+
+static int
+i386_interix_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+ return i386_pe_skip_trampoline_code (pc, name);
+}
+
+static CORE_ADDR
+i386_interix_skip_trampoline_code (CORE_ADDR pc)
+{
+ return i386_pe_skip_trampoline_code (pc, 0);
+}
+
+static void
+i386_interix_init_frame_pc (int fromleaf, struct frame_info *prev)
+{
+ /* Nothing to do on Interix. */
+}
+
+static int
+i386_interix_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
+{
+ /* In the context where this is used, we get the saved PC before we've
+ successfully unwound far enough to be sure what we've got (it may
+ be a signal handler caller). If we're dealing with a signal
+ handler caller, this will return valid, which is fine. If not,
+ it'll make the correct test. */
+ return (thisframe->signal_handler_caller
+ || (chain != 0
+ && !inside_entry_file (read_memory_integer
+ (thisframe->frame + 4, 4))));
+}
+
+/* We want to find the previous frame, which on Interix is tricky when signals
+ are involved; set frame->frame appropriately, and also get the pc
+ and tweak signal_handler_caller; this replaces a boatload of nested
+ macros, as well. */
+static void
+i386_interix_back_one_frame (int fromleaf, struct frame_info *frame)
+{
+ CORE_ADDR ra;
+ CORE_ADDR fm;
+ CORE_ADDR context;
+ long t;
+
+ if (frame == NULL)
+ internal_error (__FILE__, __LINE__, "unexpected NULL frame");
+
+ if (fromleaf)
+ {
+ frame->pc = SAVED_PC_AFTER_CALL (frame->next);
+ return;
+ }
+
+ if (!frame->next)
+ {
+ frame->pc = read_pc ();
+
+ /* Part of the signal stuff... See below. */
+ if (stopped_by_random_signal)
+ {
+ /* We know we're in a system call mini-frame; was it
+ NullApi or something else? */
+ ra = SAVED_PC_AFTER_CALL (frame);
+ if (ra >= null_start && ra < null_end)
+ frame->signal_handler_caller = 1;
+ /* There might also be an indirect call to the mini-frame,
+ putting one more return address on the stack. (XP only,
+ I think?) This can't (reasonably) return the address of the
+ signal handler caller unless it's that situation, so this
+ is safe. */
+ ra = read_memory_unsigned_integer (read_register (SP_REGNUM) + 4, 4);
+ if (ra >= null_start && ra < null_end)
+ frame->signal_handler_caller = 1;
+ }
+ return;
+ }
+
+ if (!frame->next->signal_handler_caller)
+ {
+ frame->pc = read_memory_integer (frame->next->frame + 4, 4);
+ return;
+ }
+
+ /* This is messy (actually AWFUL)... The "trampoline" might be 2, 3
+ or all 5 entities on the frame.
+
+ Chunk 1 will be present when we're actually in a signal handler.
+ Chunk 2 will be present when an asynchronous signal (one that
+ didn't come in with a system call) is present.
+ We may not (yet) be in the handler, if we're just returning
+ from the call.
+ When we're actually in a handler taken from an asynchronous
+ signal, both will be present.
+
+ Chunk 1:
+ PdxSignalDeliverer's frame
+ + Context struct -- not accounted for in any frame
+
+ Chunk 2:
+ + PdxNullPosixApi's frame
+ + PdxNullApiCaller's frame
+ + Context struct = 0x230 not accounted for in any frame
+
+ The symbol names come from examining objdumps of psxdll.dll;
+ they don't appear in the runtime image.
+
+ For gdb's purposes, we can pile all this into one frame. */
+
+ ra = frame->next->pc;
+ /* Are we already pointing at PdxNullPosixApi? We are if
+ this is a signal frame, we're at next-to-top, and were stopped
+ by a random signal (if it wasn't the right address under
+ these circumstances, we wouldn't be here at all by tests above
+ on the prior frame). */
+ if (frame->next->next == NULL && stopped_by_random_signal)
+ {
+ /* We're pointing at the frame FOR PdxNullApi. */
+ fm = frame->frame;
+ }
+ else
+ {
+ /* No... We must be pointing at the frame that was called
+ by PdxSignalDeliverer; back up across the whole mess. */
+
+ /* Extract the frame for PdxSignalDeliverer.
+ Note: FRAME_CHAIN used the "old" frame pointer because we were
+ a deliverer. Get the address of the context record that's on
+ here frameless. */
+ context = read_memory_integer (frame->frame, 4); /* an Arg */
+
+ /* Now extract the frame pointer contained in the context. */
+ fm = read_memory_integer (context + mcontext_EBP_greg_offset, 4);
+
+ ra = read_memory_integer (context + mcontext_EIP_greg_offset, 4);
+
+ /* We need to know if we're in a system call because we'll be
+ in a syscall mini-frame, if so, and the rules are different. */
+ t = (long) read_memory_integer (context + mcontext_syscall_greg_offset,
+ 4);
+ /* t contains 0 if running free, 1 if blocked on a system call,
+ and 2 if blocked on an exception message (e.g. a trap);
+ we don't expect to get here with a 2. */
+ if (t != 1)
+ {
+ /* Not at a system call, therefore it can't be NullApi. */
+ frame->pc = ra;
+ frame->frame = fm;
+ return;
+ }
+
+ /* It's a system call... Mini frame, then look for NullApi. */
+ /* Get the RA (on the stack) associated with this... It's
+ a system call mini-frame. */
+ ra = read_memory_integer (context + mcontext_UESP_greg_offset, 4);
+
+ if (winver >= 51)
+ {
+ /* Newer versions of Windows NT interpose another return
+ address (but no other "stack frame" stuff) that we need
+ to simply ignore here. */
+ ra += 4;
+ }
+
+ ra = read_memory_integer (ra, 4);
+
+ if (!(ra >= null_start && ra < null_end))
+ {
+ /* No Null API present; we're done. */
+ frame->pc = ra;
+ frame->frame = fm;
+ return;
+ }
+ }
+
+ /* At this point, we're looking at the frame for PdxNullPosixApi,
+ in either case.
+
+ PdxNullPosixApi is called by PdxNullApiCaller (which in turn
+ is called by _PdxNullApiCaller (note the _).)
+ PdxNullPosixApiCaller (no _) is a frameless function.
+
+ The saved frame pointer is as fm, but it's not of interest
+ to us because it skips us over the saved context, which is
+ the wrong thing to do, because it skips the interrrupted
+ routine! PdxNullApiCaller takes as its only argument the
+ address of the context of the interrupded function (which
+ is really in no frame, but jammed on the stack by the system)
+
+ So: fm+0: saved bp
+ fm+4: return address to _PdxNullApiCaller
+ fm+8: arg to PdxNullApiCaller pushed by _Pdx... */
+
+ fm = read_memory_integer (fm + 0x8, 4);
+
+ /* Extract the second context record. */
+
+ ra = read_memory_integer (fm + mcontext_EIP_greg_offset, 4);
+ fm = read_memory_integer (fm + mcontext_EBP_greg_offset, 4);
+
+ frame->frame = fm;
+ frame->pc = ra;
+
+ return;
+}
+
+static CORE_ADDR
+i386_interix_frame_saved_pc (struct frame_info *fi)
+{
+ /* Assume that we've already unwound enough to have the caller's address
+ if we're dealing with a signal handler caller (And if that fails,
+ return 0). */
+ if (fi->signal_handler_caller)
+ return fi->next ? fi->next->pc : 0;
+ else
+ return read_memory_integer (fi->frame + 4, 4);
+}
+
+static void
+i386_interix_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->struct_return = reg_struct_return;
+ tdep->jb_pc_offset = jump_buffer_Eip_offset;
+
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_pc_in_sigtramp (gdbarch, i386_interix_pc_in_sigtramp);
+ set_gdbarch_in_solib_call_trampoline (gdbarch,
+ i386_interix_in_solib_call_trampoline);
+ set_gdbarch_skip_trampoline_code (gdbarch,
+ i386_interix_skip_trampoline_code);
+ set_gdbarch_init_extra_frame_info (gdbarch, i386_interix_back_one_frame);
+ set_gdbarch_init_frame_pc (gdbarch, i386_interix_init_frame_pc);
+ set_gdbarch_frame_chain_valid (gdbarch, i386_interix_frame_chain_valid);
+ set_gdbarch_frame_saved_pc (gdbarch, i386_interix_frame_saved_pc);
+ set_gdbarch_name_of_malloc (gdbarch, "_malloc");
+}
+
+static enum gdb_osabi
+i386_interix_osabi_sniffer (bfd * abfd)
+{
+ char *target_name = bfd_get_target (abfd);
+
+ if (strcmp (target_name, "pei-i386") == 0)
+ return GDB_OSABI_INTERIX;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_i386_interix_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
+ i386_interix_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_INTERIX,
+ i386_interix_init_abi);
+}