diff options
-rw-r--r-- | gdb/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/config/i386/interix.mh | 9 | ||||
-rw-r--r-- | gdb/config/i386/interix.mt | 3 | ||||
-rw-r--r-- | gdb/config/i386/nm-interix.h | 35 | ||||
-rw-r--r-- | gdb/i386-interix-nat.c | 190 | ||||
-rw-r--r-- | gdb/i386-interix-tdep.c | 365 |
6 files changed, 611 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f993edb..822cc04 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 0000000..23311d6 --- /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 0000000..8d60962 --- /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 0000000..b8b003a --- /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 0000000..9c4daed --- /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 0000000..ff310ec --- /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); +} |