This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFC] Adding new files, for new port to Interix (Services For Unix)
- From: Mark Kettenis <kettenis at chello dot nl>
- To: Joel Brobecker <brobecker at gnat dot com>
- Cc: gdb-patches at sources dot redhat dot com
- Date: 24 Jul 2002 22:00:30 +0200
- Subject: Re: [RFC] Adding new files, for new port to Interix (Services For Unix)
- References: <20020724090730.GB1166@gnat.com>
[ Sorry Joel for the duplicate, I forgot to CC gdb-patches. ]
Joel Brobecker <brobecker@gnat.com> writes:
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Disposition: inline
>
> Hello,
>
> ACT is working on the integration of some changes that would allow GDB
> to be built on interix (Services For Unix). The port has been done by
> Donn Terry, with a bit of light rework here and there from myself.
Thanks for the contribution.
> The port was initially made some time ago so it was not multi-arched.
> I started the conversion, and part of it is done. I haven't finished the
> conversion, because I need a bit of help for the remaining part
> to avoid spending too much time going in the wrong direction.
Ok, I reviewed the new files. I hope my comments will be useful to you.
> I am attaching to this message some files that I'd like to add to the
> GDB trunk. These are only new files, and some other changes are still
> needed for GDB to first configure properly, and then build.
>
> My current plan regarding the inclusion of this new port is the
> following:
> - check-in the attached files, possibly (probably) with your comments
> incorporated
> - check-in the changes in the configury machinery in order for GDB to
> configure
> - check-in the minimal changes to allow GDB to build
> - And then finally check-in the remaining changes that make GDB work.
> For the curious, my regression testsuite results show about 6600
> passes, and 1200 failures.
Looks like a good strategy to me.
> Any comments on the attached files, as well as the strategy above would
> be greatly appreciated. I'd like to commit these new files as soon as
> acceptable, as it makes it easier for me to discuss new changes and also
> facilitate the management of these files.
A general remark: It looks like the port was started a while back, and
not all changes in coding conventions for GDB that we had in the
meantime have been followed:
* Comments should always be full sentences in the sense that they
start with a capital and end with a full stop (dot). After a full
stop we use two spaces.
* Don't use the keyword `register'.
* Use ISO C prototypes.
* Use spaces after every ',' and before and after '=', '+=' etc.
Success!
Mark
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: i386-interix-nat.c
> Content-Disposition: attachment; filename="i386-interix-nat.c"
>
> /* 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 <ucontext.h>
> #include <frame.h>
> #include <inferior.h>
> #include <fcntl.h>
>
> #include <i386-tdep.h>
> #include "symfile.h"
> #include "objfiles.h"
> #include "gdb-stabs.h"
> #include "gdbcore.h"
> #include "gregset.h"
>
>
> typedef unsigned long greg_t; /* Where should this be defined? */
It should be in <sys/reg.h> if Interix is trying too look like SVR4.
>
> /* See procfs.c and *interix*.h in config/[alpha,i386] */
>
> /* The /proc interface traditionally divides the target machine's register
> set up into two different sets, the general register set (gregset)
> and the floating point register set (fpregset). This is reflected
> in the data structures in <sys/regset.h>.
>
> However, the read/write /proc for interix treats them all as part
> of the status subfile.
>
> These routines provide the packing and unpacking of gregset_t and
> fpregset_t formatted data.
>
> */
>
> /* This is a duplicate of the table in i386-xdep.c. */
This statement is defenitely not true.
> static int regmap[] =
> {
> EAX, ECX, EDX, EBX,
> UESP, EBP, ESI, EDI,
> EIP, EFL, CS, SS,
> DS, ES, FS, GS,
> };
>
> /* 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 (gregsetp)
> gregset_t *gregsetp;
> {
> register int regi;
> register greg_t *regp = (greg_t *) &gregsetp->gregs;
>
> for (regi = 0; regi < I386_NUM_GREGS; regi++)
> {
> supply_register (regi, (char *) (regp + regmap[regi]));
> }
> }
>
> /* Fill in a gregset_t object with selected data from a gdb-format
> register file.
> - GREGSETP points to the gregset_t object to be filled.
> - GDB_REGS points to the GDB-style register file providing the data.
> - VALID is an array indicating which registers in GDB_REGS are
> valid; the parts of *GREGSETP that would hold registers marked
> invalid in GDB_REGS are left unchanged. If VALID is zero, all
> registers are assumed to be valid. */
> void
> convert_to_gregset (gregset_t *gregsetp,
> char *gdb_regs,
> signed char *valid)
> {
> int regi;
> register greg_t *regp = (greg_t *) gregsetp->gregs;
>
> for (regi = 0; regi < I386_NUM_GREGS; regi++)
> if (! valid || valid[regi])
> *(regp + regmap[regi]) = * (int *) ®isters[REGISTER_BYTE (regi)];
> }
Using `registers' is no longer allowed.
>
> /* Store GDB's value for REGNO in *GREGSETP. If REGNO is -1, do all
> of them. */
> void
> fill_gregset (gregset_t *gregsetp,
> int regno)
> {
> if (regno == -1)
> convert_to_gregset (gregsetp, registers, 0);
> else if (regno >= 0 && regno < I386_NUM_GREGS)
> {
> signed char valid[I386_NUM_GREGS];
> memset (valid, 0, sizeof (valid));
> valid[regno] = 1;
> convert_to_gregset (gregsetp, registers, valid);
> }
> }
Why this complicated stuff with two functions and an extra array necessary?
> /* Given a pointer to a floating point register set in /proc format
> (fpregset_t *), unpack the register contents and supply them as gdb's
> idea of the current floating point register values. */
>
> /* What is the address of st(N) within the fpregset_t structure F? */
> #define FPREGSET_T_FPREG_ADDR(f, n) \
> ((char *) &(f)->fpstate.fpregs + (n) * 10)
>
> /* Fill GDB's register file with the floating-point register values in
> *FPREGSETP. */
> void
> supply_fpregset (fpregset_t *fpregsetp)
> {
> int i;
> long l;
>
> /* Supply the floating-point registers. */
> for (i = 0; i < 8; i++)
> supply_register (FP0_REGNUM + i, FPREGSET_T_FPREG_ADDR (fpregsetp, i));
>
> l = fpregsetp->fpstate.control & 0xffff;
> supply_register (FCTRL_REGNUM, (char *) &l);
> l = fpregsetp->fpstate.status & 0xffff;
> supply_register (FSTAT_REGNUM, (char *) &l);
> l = fpregsetp->fpstate.tag & 0xffff;
> supply_register (FTAG_REGNUM, (char *) &l);
> supply_register (FCOFF_REGNUM, (char *) &fpregsetp->fpstate.erroroffset);
> l = fpregsetp->fpstate.dataselector & 0xffff;
> supply_register (FDS_REGNUM, (char *) &l);
> supply_register (FDOFF_REGNUM, (char *) &fpregsetp->fpstate.dataoffset);
>
> /* Extract the code segment and opcode from the "fcs" member. */
>
> l = fpregsetp->fpstate.errorselector & 0xffff;
> supply_register (FCS_REGNUM, (char *) &l);
>
> l = (fpregsetp->fpstate.errorselector >> 16) & ((1 << 11) - 1);
> supply_register (FOP_REGNUM, (char *) &l);
> }
>
>
> /* Fill in an fpregset_t structure with selected data from a
> gdb-format register file.
> - FPREGSETP points to the structure to be filled.
> - GDB_REGS points to the GDB-style register file providing the data.
> - VALID is an array indicating which registers in GDB_REGS are
> valid; the parts of *FPREGSETP that would hold registers marked
> invalid in GDB_REGS are left unchanged. If VALID is zero, all
> registers are assumed to be valid. */
> void
> convert_to_fpregset (fpregset_t *fpregsetp,
> char *gdb_regs,
> signed char *valid)
> {
> int i;
>
> /* Fill in the floating-point registers. */
> for (i = 0; i < 8; i++)
> if (!valid || valid[i])
> memcpy (FPREGSET_T_FPREG_ADDR (fpregsetp, i),
> ®isters[REGISTER_BYTE (FP0_REGNUM + i)],
> REGISTER_RAW_SIZE(FP0_REGNUM + i));
>
> #define fill(MEMBER, REGNO) \
> if (! valid || valid[(REGNO)]) \
> memcpy (&fpregsetp->fpstate.MEMBER, ®isters[REGISTER_BYTE (REGNO)], \
> sizeof (fpregsetp->fpstate.MEMBER))
>
> fill (control, FCTRL_REGNUM);
> fill (status, FSTAT_REGNUM);
> fill (tag, FTAG_REGNUM);
> fill (erroroffset, FCOFF_REGNUM);
> fill (dataoffset, FDOFF_REGNUM);
> fill (dataselector, FDS_REGNUM);
>
> #undef fill
>
> if (! valid || valid[FCS_REGNUM])
> fpregsetp->fpstate.errorselector
> = ((fpregsetp->fpstate.errorselector & ~0xffff)
> | (* (int *) ®isters[REGISTER_BYTE (FCS_REGNUM)] & 0xffff));
>
> if (! valid || valid[FOP_REGNUM])
> fpregsetp->fpstate.errorselector
> = ((fpregsetp->fpstate.errorselector & 0xffff)
> | ((*(int *) ®isters[REGISTER_BYTE (FOP_REGNUM)] & ((1 << 11) - 1))
> << 16));
> }
>
>
> /* 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)
> {
> convert_to_fpregset (fpregsetp, registers, 0);
> }
Is there any reason you can't use i387_supply_fsave and
i387_fill_fsave here? I would be seriously surprised if you couldn't.
That said, please consider using i386v4-nat.c for Interix. Apart from
the greg_t typedef issue that should work without problems, and I'm
certainly willing to add something like:
#ifndef HAVE_GREG_T
typedef unsigned long greg_t;
#endif
to that file together with a suitable autoconf check.
> /*
>
> GLOBAL FUNCTION
>
> fetch_core_registers -- fetch current registers from core file
>
> SYNOPSIS
>
> void fetch_core_registers (char *core_reg_sect,
> unsigned core_reg_size,
> int which, CORE_ADDR reg_addr)
>
> DESCRIPTION
>
> 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.
>
> */
Please change this comment to only the description.
>
> 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));
> if (FP0_REGNUM >= 0)
> supply_fpregset (&fpregset);
> }
> }
> }
If that check for FP0_REGNUM is really necessary (it is if there are
Interix sub-targets that don't include the floating point registers),
please change it to:
if (FP0_REGNUM > 0)
>
> /* the name of the proc status struct depends on the implementation */
> #ifdef HAVE_PSTATUS_T
> typedef pstatus_t gdb_prstatus_t;
> #else
> typedef prstatus_t gdb_prstatus_t;
> #endif
What's this doing here? These typedefs aren't used anywhere in this file.
> /* Figure out where the longjmp will land.
> We expect the first arg to be a pointer to the jmp_buf structure from which
> we extract the pc that we will land at. The pc is copied into PC.
> This routine returns true on success. */
>
> #include <setjmp.h>
>
> int
> get_longjmp_target (pc)
> CORE_ADDR *pc;
> {
> CORE_ADDR sp, jb_addr;
> char raw_buffer[MAX_REGISTER_RAW_SIZE];
>
> sp = read_register (SP_REGNUM);
>
> if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
> raw_buffer,
> TARGET_PTR_BIT / TARGET_CHAR_BIT))
> return 0;
>
> jb_addr = extract_address (raw_buffer, TARGET_PTR_BIT / TARGET_CHAR_BIT);
>
> if (target_read_memory(jb_addr + offsetof(_JUMP_BUFFER,Eip), raw_buffer,
> sizeof(CORE_ADDR)))
> return 0;
>
> *pc = extract_address (raw_buffer, sizeof(CORE_ADDR));
> return 1;
> }
This function does not beling in a *-nat.c file but in a *-tdep.c file.
Is there any reason why the new i386-tdep.c:i386_get_longjmp_target()
cannot be used? Just setting tdep->jb_pc_offset to the numeric value
of offsetof (_JMP_BUFFER, Eip) should work fine AFAICT.
> 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);
> if (TARGET_LONG_BIT != 32)
> printf_unfiltered ("ERROR: TARGET_LONG_BIT = %d /= 32!\n", TARGET_LONG_BIT);
> if (TARGET_LONG_LONG_BIT != 64)
> printf_unfiltered
> ("ERROR: TARGET_LONG_LONG_BIT = %d /= 64!\n", TARGET_LONG_LONG_BIT);
> }
What is the purpose for the TARGET_LONG_BIT and TARGET_LONG_LONG_BIT
checks here?
> /* 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;
> }
> }
Seems to me that this function doesn't belong in *-nat.c but in *-tdep.c.
> /* 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;
>
> asprintf (&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 termintion. */
> p = strchr(buf, '\n');
> if (p != NULL)
> *p = '\0';
>
> return buf;
> }
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: i386-interix-tdep.c
> Content-Disposition: attachment; filename="i386-interix-tdep.c"
>
> /* 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 "arch-utils.h"
>
> #include "frame.h"
> #include "gdb_string.h"
> #include "gdbcore.h"
> #include "gdbtypes.h"
> #include "inferior.h"
> #include "libbfd.h"
> #include "osabi.h"
>
> /* FIXME: This is not right, we should not be including this file in
> -tdep module. But this is needed by interix_back_one_frame. */
> #include <sys/procfs.h>
Yup that defenitely should be fixed before checking in this code. It
seems that this is neccessary since you use `offset (mcontext_t,
...)'. Can't you replace that by a constant, or does the value of
those expressions depend on the particular version of Interix or
Windhoos (Sorry that's the name we use for a particular OS we're not
too fond of at the company where I work; means something like
whirlwind).
> /* ??? Why do we need an extern here??? */
> extern CORE_ADDR skip_trampoline_code (CORE_ADDR pc, char *name);
Better add the prototype to i386-tdep.h.
> /* Some constants describing the i386 interix target */
> static const int i386_interix_long_bit = 32;
> static const int i386_interix_long_long_bit = 64;
> static const int i386_interix_ptr_bit = 32;
> static const CORE_ADDR i386_interix_decr_pc_after_break = 0;
What's the purpose of these constants? Apart from decr_pc_after_break
these are just the default values for the i386 target.
> /* 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 */
The fact that it needs some more work, isn't a problem for me. Can be
done after this code has been checked in.
> 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 skip_trampoline_code (pc, name);
> }
>
> static CORE_ADDR
> i386_interix_skip_trampoline_code (CORE_ADDR pc)
> {
> return 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 (fromleaf, frame)
> int fromleaf;
> struct frame_info *frame;
> {
> CORE_ADDR ra;
> CORE_ADDR fm;
> CORE_ADDR context;
> long t;
>
> if (frame == NULL)
> abort();
>
> 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 (
> (CORE_ADDR) 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 = (CORE_ADDR)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 = (CORE_ADDR)read_memory_integer
> (context + offsetof(mcontext_t, gregs.gregs[EBP]), 4);
>
> ra = (CORE_ADDR)read_memory_integer
> (context + offsetof(mcontext_t, gregs.gregs[EIP]), 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;
> reserved[1] 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. */
> t = (long)read_memory_integer
> (context + offsetof(mcontext_t, gregs.reserved[1]), 4);
> 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 = (CORE_ADDR)read_memory_integer
> (context + offsetof(mcontext_t, gregs.gregs[UESP]), 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 = (CORE_ADDR)read_memory_integer(ra,4);
>
> /* We might be done (no Null API if so) */
> 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 = (CORE_ADDR)read_memory_integer (fm+0x8, 4);
>
> /* Extract the second context record */
>
> ra = (CORE_ADDR)read_memory_integer
> (fm + offsetof(mcontext_t, gregs.gregs[EIP]), 4);
> fm = (CORE_ADDR)read_memory_integer
> (fm + offsetof(mcontext_t, gregs.gregs[EBP]), 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 (CORE_ADDR) read_memory_integer (fi->frame + 4, 4);
> }
>
> static int
> i386_interix_use_struct_convention (int gcc_p, struct type *type)
> {
> /* Directly copied from nbsd where this function is no longer defined,
> as a generic mechanism is used. Maybe we should take advantage of
> this mechanism too? */
> return !(TYPE_LENGTH (type) == 1
> || TYPE_LENGTH (type) == 2
> || TYPE_LENGTH (type) == 4
> || TYPE_LENGTH (type) == 8);
> }
Please use the generic mechanism. Just set tdep->struct_return to
reg_struct_return.
> void
> i386_interix_cache_trampoline_addresses_from_bfd (void)
> {
> /* This is painful, but there doesn't seem to be a better way.
> See interix tm.h, IN_SIGTRAMP, and procfs.c for more details. */
> asection *section;
> pstatus_t *p;
>
> section = bfd_get_section_by_name (core_bfd, ".pstatus");
> if (section == NULL)
> {
> /* This should never happen, we are just being extra cautious. */
> warning (".pstatus section not found.");
> return;
> }
>
> p = (pstatus_t *)section->contents;
> if (p == NULL)
> {
> p = (pstatus_t *)bfd_alloc(core_bfd, section->_raw_size);
> bfd_get_section_contents (core_bfd, section, p, 0, section->_raw_size);
> }
>
> tramp_start = (CORE_ADDR)p->pr_signaldeliverer;
> tramp_end = (CORE_ADDR)p->pr_endsignaldeliverer;
> null_start = (CORE_ADDR)p->pr_nullapi;
> null_end = (CORE_ADDR)p->pr_endnullapi;
> }
>
> void
> i386_interix_cache_trampoline_addresses (CORE_ADDR trampoline_start,
> CORE_ADDR trampoline_end,
> CORE_ADDR nullapi_start,
> CORE_ADDR nullapi_end)
> {
> /* On Interix, the location of the trampoline code can
> float, and it's not part of the symbol table (because
> it's internal to a DLL). However, the system knows where
> it is, and tells us, so we capture that info here. */
> /* While we're doing such ugly things, find out which
> version of NT this is, so we can change our unwind rules
> a bit.
> FIXME: If we move this, move the include of utsname.h, too.*/
>
> tramp_start = trampoline_start;
> tramp_end = trampoline_end;
> null_start = nullapi_start;
> null_end = nullapi_end;
> }
>
> static void
> i386_interix_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> {
> /* ??? Externs, temporarily defined */
> extern int get_longjmp_target (CORE_ADDR *pc);
>
> struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>
> set_gdbarch_long_bit (gdbarch, i386_interix_long_bit);
> set_gdbarch_long_long_bit (gdbarch, i386_interix_long_long_bit);
> set_gdbarch_use_struct_convention (gdbarch,
> i386_interix_use_struct_convention);
> set_gdbarch_ptr_bit (gdbarch, i386_interix_ptr_bit);
See earlier comments.
> set_gdbarch_decr_pc_after_break (gdbarch, i386_interix_decr_pc_after_break);
Just using 0 here is fine by me. It's obvious where to look for it.
> set_gdbarch_pc_in_sigtramp (gdbarch, i386_interix_pc_in_sigtramp);
> /* ??? The following may already be the default on i386 architecture */
> set_gdbarch_in_solib_call_trampoline (gdbarch,
> i386_interix_in_solib_call_trampoline);
It isn't the default on the i386 target, so removing this comment is fine.
> 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);
> /* ??? the following may already be the default for i386 architecture */
> set_gdbarch_get_longjmp_target (gdbarch, get_longjmp_target);
Yes, please use the generic mechanism as indicated by the comments in
the Interix *-nat.c file.
> }
>
> 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);
> }
>
>
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: config/i386/tm-i386interix.h
> Content-Disposition: attachment; filename="tm-i386interix.h"
>
> /* Macro definitions for i386 running under Interix
> 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. */
>
> #ifndef TM_INTERIX_H
> #define TM_INTERIX_H
>
> #include "i386/tm-i386.h"
>
> /* configure can't be expected to noodle out MS's alternate spelling for
> 64-bit integers, so we'll tell it. */
> #define PRINTF_HAS_LONG_LONG 1
> #ifdef __GNUC__
> #define BFD_HOST_64_BIT long long
> #define BFD_HOST_U_64_BIT unsigned long long
> #elif defined(_MSC_VER)
> #define BFD_HOST_64_BIT __int64
> #define BFD_HOST_U_64_BIT unsigned __int64
> #else
> #error... OK what compiler is this?
> #endif
>
> #undef LONGEST
> #define LONGEST BFD_HOST_64_BIT
>
> #undef ULONGEST
> #define ULONGEST BFD_HOST_U_64_BIT
Well, then configure should be taught about it. We might tolerate
some hacks like this but not in the tm-*.h files. Put it a xm-*.h
file, but bether yet avoid it if you can: Add an appropriate configure
check for PRINTF_HAS_LONG_LONG and fix the BFD_HOST_* handling in BFD.
See the *-*-windows*) case in bfd/configure.host.
> #define I386_FLOATS_RETURN_IN_ST0
What's the purpose of this? The standard i386 target already stores
floating point return values in $st(0), and I don't see any use of
this macro in these files.
> /* Interix has a minimal sbrk() (but not what's wanted for this usage),
> and it's relationship to environ[] is not what's usually expected
> (as in, there is no specific relationship at all). Just pretend we don't
> have an sbrk(). */
> #undef HAVE_SBRK
That defenitely belongs in an xm-*.h file.
> #define ADJUST_OBJFILE_OFFSETS(objfile, type) \
> pei_adjust_objfile_offsets(objfile, type)
What's the purpose of this. This macro is used nowhere in the entire
GDB tree.
> extern CORE_ADDR bfd_getImageBase(bfd *abfd);
> #define NONZERO_LINK_BASE(abfd) bfd_getImageBase(abfd)
Eventually you'll have to find another location for these defines.
Why not put them into *-tdep.c right from the start?
> #define NAME_OF_MALLOC "_malloc"
What's this for?
>
> #endif /* TM_INTERIX_H */
The bottom line seems to be that we don't need a special tm-*.h for
Interix. Please use tm-i386.h for this new target.
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: config/i386/nm-interix.h
> Content-Disposition: attachment; filename="nm-interix.h"
>
> /* Native-dependent definitions for Intel 386 running Interix, 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. */
>
> #ifndef NM_INTERIX_H
> #define NM_INTERIX_H
>
> #define USE_PROC_FS
>
> /* submodes of USE_PROC_FS */
> #define PROCFS_USE_READ_WRITE
> #define HAVE_MULTIPLE_PROC_FDS
> #define UNIXWARE
> #define HAVE_STRUCT_LWP
>
> #define ATTACH_DETACH
>
> /* Be shared lib aware */
> #include "solib.h"
>
> /* This is the amount to subtract from u.u_ar0
> to get the offset in the core file of the register values. */
>
> #if 0
> #include <machine/vmparam.h>
> #define KERNEL_U_ADDR USRSTACK
> #endif
>
> #define REGISTER_U_ADDR(addr, blockend, regno) \
> (addr) = i386_register_u_addr ((blockend),(regno));
>
> extern int
> i386_register_u_addr PARAMS ((int, int));
>
> #define PTRACE_ARG3_TYPE char*
>
> /* Return sizeof user struct to callers in less machine dependent routines */
>
> #define KERNEL_U_SIZE kernel_u_size()
> extern int kernel_u_size PARAMS ((void));
What's the purpose of all these Unix-specific defines on Interix?
> /* It's ALMOST coff; bfd does the same thing */
> #define COFF_WITH_PE
> #define COFF_IMAGE_WITH_PE
These are referenced nowhere in the entire GDB source tree.
> /* Turn on our own child_pid_to_exec_file. */
> #define CHILD_PID_TO_EXEC_FILE
>
> #endif /* NM_INTERIX_H */
>
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: config/i386/interix.mh
> Content-Disposition: attachment; filename="interix.mh"
>
> # 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
> # The below may be temporary; mmalloc relies on sbrk() at the moment
> MMALLOC=
> MMALLOC_CFLAGS=-DNO_MMALLOC
>
> --uQr8t48UFsdbeI+V
> Content-Type: text/plain; charset=us-ascii
> Content-Description: config/i386/interix.mt
> Content-Disposition: attachment; filename="interix.mt"
>
> # Target: Intel 386 running Interix
> TDEPFILES= i386-tdep.o i387-tdep.o i386-interix-tdep.o \
> solib.o solib-pei.o i386nbsd-tdep.o
i386nbsd-tdep.o ???
> TM_FILE= tm-i386interix.h
>
> --uQr8t48UFsdbeI+V--