OSDN Git Service

New interix-specific files:
authorJoel Brobecker <brobecker@gnat.com>
Fri, 1 Nov 2002 22:08:44 +0000 (22:08 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 1 Nov 2002 22:08:44 +0000 (22:08 +0000)
       * 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.

gdb/ChangeLog
gdb/config/i386/interix.mh [new file with mode: 0644]
gdb/config/i386/interix.mt [new file with mode: 0644]
gdb/config/i386/nm-interix.h [new file with mode: 0644]
gdb/i386-interix-nat.c [new file with mode: 0644]
gdb/i386-interix-tdep.c [new file with mode: 0644]

index f993edb..822cc04 100644 (file)
@@ -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 (file)
index 0000000..23311d6
--- /dev/null
@@ -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 (file)
index 0000000..8d60962
--- /dev/null
@@ -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 (file)
index 0000000..b8b003a
--- /dev/null
@@ -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 (file)
index 0000000..9c4daed
--- /dev/null
@@ -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 (file)
index 0000000..ff310ec
--- /dev/null
@@ -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);
+}