--- /dev/null
+/* QNX specific support for 32-bit ELF
+ Copyright 2002 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "elf-bfd.h"
+#include "elf32-qnx.h"
+
+/* Returns the end address of the segment + 1. */
+#define SEGMENT_END(segment, start) \
+ (start + (segment->p_memsz > segment->p_filesz \
+ ? segment->p_memsz : segment->p_filesz))
+
+boolean
+elf_qnx_copy_private_bfd_data_p (ibfd, isec, obfd, osec)
+ bfd *ibfd ATTRIBUTE_UNUSED;
+ asection *isec;
+ bfd *obfd ATTRIBUTE_UNUSED;
+ asection *osec ATTRIBUTE_UNUSED;
+{
+ return isec->next == NULL;
+}
+
+boolean
+elf_qnx_is_contained_by_filepos (section, segment)
+ asection *section;
+ Elf_Internal_Phdr *segment;
+{
+ return ((bfd_vma) section->filepos >= segment->p_offset
+ && ((bfd_vma) section->filepos + section->_raw_size
+ <= SEGMENT_END (segment, segment->p_offset)));
+}
+
+void
+elf_qnx_set_nonloadable_filepos (abfd, phdrs)
+ bfd *abfd;
+ Elf_Internal_Phdr *phdrs;
+{
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+ file_ptr off = 0;
+
+ for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+ m != NULL;
+ m = m->next, p++)
+ {
+ unsigned int i;
+ asection **secpp;
+
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ asection *sec;
+
+ sec = *secpp;
+
+ if (p->p_type == PT_LOAD)
+ off = sec->filepos;
+ else
+ {
+ if (i == 0)
+ {
+ if (sec->filepos)
+ p->p_offset = sec->filepos;
+ else
+ p->p_offset = off;
+ }
+ if (!sec->filepos)
+ {
+ off += sec->_raw_size;
+ p->p_filesz += sec->_raw_size;
+ }
+ }
+ }
+ }
+ return;
+}
--- /dev/null
+/* simple.c -- BFD simple client routines
+ Copyright 2002
+ Free Software Foundation, Inc.
+ Contributed by MontaVista Software, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "bfdlink.h"
+
+static boolean simple_dummy_warning
+ PARAMS ((struct bfd_link_info *, const char *, const char *, bfd *,
+ asection *, bfd_vma));
+
+static boolean simple_dummy_undefined_symbol
+ PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *,
+ bfd_vma, boolean));
+
+static boolean simple_dummy_reloc_overflow
+ PARAMS ((struct bfd_link_info *, const char *, const char *, bfd_vma,
+ bfd *, asection *, bfd_vma));
+
+static boolean simple_dummy_reloc_dangerous
+ PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma));
+
+static boolean simple_dummy_unattached_reloc
+ PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma));
+
+bfd_byte * bfd_simple_get_relocated_section_contents
+ PARAMS ((bfd *, asection *, bfd_byte *));
+
+static boolean
+simple_dummy_warning (link_info, warning, symbol, abfd, section, address)
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+ const char *warning ATTRIBUTE_UNUSED;
+ const char *symbol ATTRIBUTE_UNUSED;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section ATTRIBUTE_UNUSED;
+ bfd_vma address ATTRIBUTE_UNUSED;
+{
+ return true;
+}
+
+static boolean
+simple_dummy_undefined_symbol (link_info, name, abfd, section, address, fatal)
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+ const char *name ATTRIBUTE_UNUSED;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section ATTRIBUTE_UNUSED;
+ bfd_vma address ATTRIBUTE_UNUSED;
+ boolean fatal ATTRIBUTE_UNUSED;
+{
+ return true;
+}
+
+static boolean
+simple_dummy_reloc_overflow (link_info, name, reloc_name, addend, abfd,
+ section, address)
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+ const char *name ATTRIBUTE_UNUSED;
+ const char *reloc_name ATTRIBUTE_UNUSED;
+ bfd_vma addend ATTRIBUTE_UNUSED;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section ATTRIBUTE_UNUSED;
+ bfd_vma address ATTRIBUTE_UNUSED;
+{
+ return true;
+}
+
+static boolean
+simple_dummy_reloc_dangerous (link_info, message, abfd, section, address)
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+ const char *message ATTRIBUTE_UNUSED;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section ATTRIBUTE_UNUSED;
+ bfd_vma address ATTRIBUTE_UNUSED;
+{
+ return true;
+}
+
+static boolean
+simple_dummy_unattached_reloc (link_info, name, abfd, section, address)
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED;
+ const char *name ATTRIBUTE_UNUSED;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *section ATTRIBUTE_UNUSED;
+ bfd_vma address ATTRIBUTE_UNUSED;
+{
+ return true;
+}
+
+/*
+FUNCTION
+ bfd_simple_relocate_secton
+
+SYNOPSIS
+ bfd_byte *bfd_simple_get_relocated_section_contents (bfd *abfd, asection *sec, bfd_byte *outbuf);
+
+DESCRIPTION
+ Returns the relocated contents of section @var{sec}. Only symbols
+ from @var{abfd} and the output offsets assigned to sections in
+ @var{abfd} are used. The result will be stored at @var{outbuf}
+ or allocated with @code{bfd_malloc} if @var{outbuf} is @code{NULL}.
+
+ Generally all sections in @var{abfd} should have their
+ @code{output_section} pointing back to the original section.
+
+ Returns @code{NULL} on a fatal error; ignores errors applying
+ particular relocations.
+*/
+
+bfd_byte *
+bfd_simple_get_relocated_section_contents (abfd, sec, outbuf)
+ bfd *abfd;
+ asection *sec;
+ bfd_byte *outbuf;
+{
+ struct bfd_link_info link_info;
+ struct bfd_link_order link_order;
+ struct bfd_link_callbacks callbacks;
+ bfd_byte *contents, *data;
+ int storage_needed, number_of_symbols;
+ asymbol **symbol_table;
+
+ /* In order to use bfd_get_relocated_section_contents, we need
+ to forge some data structures that it expects. */
+
+ /* Fill in the bare minimum number of fields for our purposes. */
+ memset (&link_info, 0, sizeof (link_info));
+ link_info.input_bfds = abfd;
+
+ link_info.hash = bfd_link_hash_table_create (abfd);
+ link_info.callbacks = &callbacks;
+ callbacks.warning = simple_dummy_warning;
+ callbacks.undefined_symbol = simple_dummy_undefined_symbol;
+ callbacks.reloc_overflow = simple_dummy_reloc_overflow;
+ callbacks.reloc_dangerous = simple_dummy_reloc_dangerous;
+ callbacks.unattached_reloc = simple_dummy_unattached_reloc;
+
+ memset (&link_order, 0, sizeof (link_order));
+ link_order.next = NULL;
+ link_order.type = bfd_indirect_link_order;
+ link_order.offset = 0;
+ link_order.size = bfd_section_size (abfd, sec);
+ link_order.u.indirect.section = sec;
+
+ data = NULL;
+ if (outbuf == NULL)
+ {
+ data = bfd_malloc (bfd_section_size (abfd, sec));
+ if (data == NULL)
+ return NULL;
+ outbuf = data;
+ }
+ bfd_link_add_symbols (abfd, &link_info);
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+ symbol_table = (asymbol **) bfd_malloc (storage_needed);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+ contents = bfd_get_relocated_section_contents (abfd,
+ &link_info,
+ &link_order,
+ outbuf,
+ 0,
+ symbol_table);
+ if (contents == NULL && data != NULL)
+ free (data);
+
+ /* Foul hack to prevent bfd_section_size aborts. This flag only controls
+ that macro (and the related size macros), selecting between _raw_size
+ and _cooked_size. Debug sections won't change size while we're only
+ relocating. There may be trouble here someday if it tries to run
+ relaxation unexpectedly, so make sure. */
+ BFD_ASSERT (sec->_raw_size == sec->_cooked_size);
+ sec->reloc_done = 0;
+
+ bfd_link_hash_table_free (abfd, link_info.hash);
+
+ return contents;
+}
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* Target-dependent code for OpenBSD/i386.
+ Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "regcache.h"
+
+#include "i386-tdep.h"
+#include "i387-tdep.h"
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386obsd_tdep (void);
+
+#define SIZEOF_STRUCT_REG (16 * 4)
+
+static void
+i386obsd_supply_reg (char *regs, int regno)
+{
+ int i;
+
+ for (i = 0; i <= 15; i++)
+ if (regno == i || regno == -1)
+ supply_register (i, regs + i * 4);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+ CORE_ADDR ignore)
+{
+ char *regs, *fsave;
+
+ /* We get everything from one section. */
+ if (which != 0)
+ return;
+
+ if (core_reg_size < (SIZEOF_STRUCT_REG + 108))
+ {
+ warning ("Wrong size register set in core file.");
+ return;
+ }
+
+ regs = core_reg_sect;
+ fsave = core_reg_sect + SIZEOF_STRUCT_REG;
+
+ /* Integer registers. */
+ i386obsd_supply_reg (regs, -1);
+
+ /* Floating point registers. */
+ i387_supply_fsave (fsave);
+}
+
+static struct core_fns i386obsd_core_fns =
+{
+ bfd_target_unknown_flavour, /* core_flavour */
+ default_check_format, /* check_format */
+ default_core_sniffer, /* core_sniffer */
+ fetch_core_registers, /* core_read_registers */
+ NULL /* next */
+};
+\f
+
+CORE_ADDR i386obsd_sigtramp_start = 0xbfbfdf20;
+CORE_ADDR i386obsd_sigtramp_end = 0xbfbfdff0;
+
+/* From <machine/signal.h>. */
+int i386obsd_sc_pc_offset = 44;
+int i386obsd_sc_sp_offset = 56;
+
+static void
+i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Obviously OpenBSD is BSD-based. */
+ i386bsd_init_abi (info, gdbarch);
+
+ /* OpenBSD uses -freg-struct-return by default. */
+ tdep->struct_return = reg_struct_return;
+
+ /* OpenBSD uses a different memory layout. */
+ tdep->sigtramp_start = i386obsd_sigtramp_start;
+ tdep->sigtramp_end = i386obsd_sigtramp_end;
+
+ /* OpenBSD has a `struct sigcontext' that's different from the
+ origional 4.3 BSD. */
+ tdep->sc_pc_offset = i386obsd_sc_pc_offset;
+ tdep->sc_sp_offset = i386obsd_sc_sp_offset;
+}
+
+void
+_initialize_i386obsd_tdep (void)
+{
+ add_core_fns (&i386obsd_core_fns);
+
+ /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
+ indistingushable from NetBSD/i386 a.out binaries, building a GDB
+ that should support both these targets will probably not work as
+ expected. */
+#define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
+
+ gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_OPENBSD_AOUT,
+ i386obsd_init_abi);
+}
--- /dev/null
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ 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 "reggroups.h"
+#include "gdbtypes.h"
+#include "gdb_assert.h"
+#include "regcache.h"
+#include "command.h"
+#include "gdbcmd.h" /* For maintenanceprintlist. */
+
+/* Individual register groups. */
+
+struct reggroup
+{
+ const char *name;
+ enum reggroup_type type;
+};
+
+struct reggroup *
+reggroup_new (const char *name, enum reggroup_type type)
+{
+ struct reggroup *group = XMALLOC (struct reggroup);
+ group->name = name;
+ group->type = type;
+ return group;
+}
+
+/* Register group attributes. */
+
+const char *
+reggroup_name (struct reggroup *group)
+{
+ return group->name;
+}
+
+enum reggroup_type
+reggroup_type (struct reggroup *group)
+{
+ return group->type;
+}
+
+/* All the groups for a given architecture. */
+
+struct reggroups
+{
+ int nr_group;
+ struct reggroup **group;
+};
+
+static struct gdbarch_data *reggroups_data;
+
+static void *
+reggroups_init (struct gdbarch *gdbarch)
+{
+ struct reggroups *groups = XMALLOC (struct reggroups);
+ groups->nr_group = 0;
+ groups->group = NULL;
+ return groups;
+}
+
+static void
+reggroups_free (struct gdbarch *gdbarch, void *data)
+{
+ struct reggroups *groups = data;
+ xfree (groups->group);
+ xfree (groups);
+}
+
+/* Add a register group (with attribute values) to the pre-defined
+ list. This function can be called during architecture
+ initialization and hence needs to handle NULL architecture groups. */
+
+static void
+add_group (struct reggroups *groups, struct reggroup *group)
+{
+ gdb_assert (group != NULL);
+ groups->nr_group++;
+ groups->group = xrealloc (groups->group, (sizeof (struct reggroup *)
+ * (groups->nr_group + 1)));
+ groups->group[groups->nr_group - 1] = group;
+ groups->group[groups->nr_group] = NULL;
+}
+
+void
+reggroup_add (struct gdbarch *gdbarch, struct reggroup *group)
+{
+ struct reggroups *groups = gdbarch_data (gdbarch, reggroups_data);
+ if (groups == NULL)
+ {
+ /* ULGH, called during architecture initialization. Patch
+ things up. */
+ groups = reggroups_init (gdbarch);
+ set_gdbarch_data (gdbarch, reggroups_data, groups);
+ }
+ add_group (groups, group);
+}
+
+/* The register groups for the current architecture. Mumble something
+ about the lifetime of the buffer.... */
+
+static struct reggroups *default_groups;
+
+struct reggroup * const*
+reggroups (struct gdbarch *gdbarch)
+{
+ struct reggroups *groups = gdbarch_data (gdbarch, reggroups_data);
+ /* Don't allow this function to be called during architecture
+ creation. */
+ gdb_assert (groups != NULL);
+ if (groups->group == NULL)
+ return default_groups->group;
+ else
+ return groups->group;
+}
+
+/* Is REGNUM a member of REGGROUP? */
+int
+default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
+{
+ int vector_p;
+ int float_p;
+ int raw_p;
+ if (REGISTER_NAME (regnum) == NULL
+ || *REGISTER_NAME (regnum) == '\0')
+ return 0;
+ if (group == all_reggroup)
+ return 1;
+ vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
+ float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
+ raw_p = regnum < gdbarch_num_regs (gdbarch);
+ if (group == float_reggroup)
+ return float_p;
+ if (group == vector_reggroup)
+ return vector_p;
+ if (group == general_reggroup)
+ return (!vector_p && !float_p);
+ if (group == save_reggroup || group == restore_reggroup)
+ return raw_p;
+ return 0;
+}
+
+/* Dump out a table of register groups for the current architecture. */
+
+static void
+reggroups_dump (struct gdbarch *gdbarch, struct ui_file *file)
+{
+ struct reggroup *const *groups = reggroups (gdbarch);
+ int i = -1;
+ do
+ {
+ /* Group name. */
+ {
+ const char *name;
+ if (i < 0)
+ name = "Group";
+ else
+ name = reggroup_name (groups[i]);
+ fprintf_unfiltered (file, " %-10s", name);
+ }
+
+ /* Group type. */
+ {
+ const char *type;
+ if (i < 0)
+ type = "Type";
+ else
+ {
+ switch (reggroup_type (groups[i]))
+ {
+ case USER_REGGROUP:
+ type = "user";
+ break;
+ case INTERNAL_REGGROUP:
+ type = "internal";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+ fprintf_unfiltered (file, " %-10s", type);
+ }
+
+ /* Note: If you change this, be sure to also update the
+ documentation. */
+
+ fprintf_unfiltered (file, "\n");
+ i++;
+ }
+ while (groups[i] != NULL);
+}
+
+static void
+maintenance_print_reggroups (char *args, int from_tty)
+{
+ if (args == NULL)
+ reggroups_dump (current_gdbarch, gdb_stdout);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print reggroups");
+ reggroups_dump (current_gdbarch, file);
+ ui_file_delete (file);
+ }
+}
+
+/* Pre-defined register groups. */
+static struct reggroup general_group = { "general", USER_REGGROUP };
+static struct reggroup float_group = { "float", USER_REGGROUP };
+static struct reggroup system_group = { "system", USER_REGGROUP };
+static struct reggroup vector_group = { "vector", USER_REGGROUP };
+static struct reggroup all_group = { "all", USER_REGGROUP };
+static struct reggroup save_group = { "save", INTERNAL_REGGROUP };
+static struct reggroup restore_group = { "restore", INTERNAL_REGGROUP };
+
+struct reggroup *const general_reggroup = &general_group;
+struct reggroup *const float_reggroup = &float_group;
+struct reggroup *const system_reggroup = &system_group;
+struct reggroup *const vector_reggroup = &vector_group;
+struct reggroup *const all_reggroup = &all_group;
+struct reggroup *const save_reggroup = &save_group;
+struct reggroup *const restore_reggroup = &restore_group;
+
+void
+_initialize_reggroup (void)
+{
+ reggroups_data = register_gdbarch_data (reggroups_init, reggroups_free);
+
+ /* The pre-defined list of groups. */
+ default_groups = reggroups_init (NULL);
+ add_group (default_groups, general_reggroup);
+ add_group (default_groups, float_reggroup);
+ add_group (default_groups, system_reggroup);
+ add_group (default_groups, vector_reggroup);
+ add_group (default_groups, all_reggroup);
+ add_group (default_groups, save_reggroup);
+ add_group (default_groups, restore_reggroup);
+
+
+ add_cmd ("reggroups", class_maintenance,
+ maintenance_print_reggroups, "\
+Print the internal register group names.\n\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
+}
--- /dev/null
+/* Register groupings for GDB, the GNU debugger.
+
+ Copyright 2002 Free Software Foundation, Inc.
+
+ Contributed by Red Hat.
+
+ 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 REGGROUPS_H
+#define REGGROUPS_H
+
+struct gdbarch;
+struct reggroup;
+
+enum reggroup_type { USER_REGGROUP, INTERNAL_REGGROUP };
+
+/* Pre-defined, user visible, register groups. */
+extern struct reggroup *const general_reggroup;
+extern struct reggroup *const float_reggroup;
+extern struct reggroup *const system_reggroup;
+extern struct reggroup *const vector_reggroup;
+extern struct reggroup *const all_reggroup;
+
+/* Pre-defined, internal, register groups. */
+extern struct reggroup *const save_reggroup;
+extern struct reggroup *const restore_reggroup;
+
+/* Create a new local register group. */
+extern struct reggroup *reggroup_new (const char *name,
+ enum reggroup_type type);
+
+/* Add a register group (with attribute values) to the pre-defined list. */
+extern void reggroup_add (struct gdbarch *gdbarch, struct reggroup *group);
+
+/* Register group attributes. */
+extern const char *reggroup_name (struct reggroup *reggroup);
+extern enum reggroup_type reggroup_type (struct reggroup *reggroup);
+
+/* The register groups for the current architecture. */
+extern struct reggroup *const *reggroups (struct gdbarch *gdbarch);
+
+/* Is REGNUM a member of REGGROUP? */
+extern int default_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *reggroup);
+
+#endif
--- /dev/null
+ comment "subroutine declare"
+ .macro gdbasm_declare name
+ .align 2
+ .ent \name
+ .type \name,@function
+\name:
+ .endm
+
+ comment "subroutine prologue"
+ .macro gdbasm_enter
+ .frame $fp, 32, $31
+ .mask 0xd0000000,-4
+ .set noreorder
+ .cpload $25
+ .set reorder
+ subu $sp, $sp, 32
+ .cprestore 16
+ sw $31, 28($sp)
+ sw $fp, 24($sp)
+ sw $28, 20($sp)
+ move $fp, $sp
+ .endm
+
+ comment "subroutine epilogue"
+ .macro gdbasm_leave
+ lw $31, 28($sp)
+ lw $fp, 24($sp)
+ .set noreorder
+ .set nomacro
+ j $31
+ addu $sp, $sp, 32
+ .set macro
+ .set reorder
+ .endm
+
+ comment "subroutine end"
+ .macro gdbasm_end name
+ .end \name
+ .endm
+
+ .macro gdbasm_call subr
+ la $25, \subr
+ jal $31, $25
+ .endm
+
+ .macro gdbasm_several_nops
+ nop
+ nop
+ nop
+ nop
+ .endm
+
+ comment "exit (0)"
+ .macro gdbasm_exit0
+ comment "Don't know how to exit, but this will certainly halt..."
+ lw $2, 0($0)
+ .endm
+
+ comment "crt0 startup"
+ .macro gdbasm_startup
+ .global __start
+__start:
+ move $fp, $sp
+ .endm
--- /dev/null
+struct A
+{
+ int a;
+ A (int aa): a (aa) {}
+};
+
+struct B: public A
+{
+ int b;
+ B (int aa, int bb): A (aa), b(bb) {}
+};
+
+int
+main (int argc, char **argv)
+{
+ A *a = new B(42, 1729);
+ B *b = (B *) a;
+
+ return 0; /* breakpoint spot: casts.exp: 1 */
+}
--- /dev/null
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# This file is part of the gdb testsuite
+
+# Test casting, especially between class types or pointer-to-class
+# types.
+
+# This file is part of the gdb testsuite
+
+if $tracelevel then {
+ strace $tracelevel
+ }
+
+#
+# test running programs
+#
+
+set prms_id 0
+set bug_id 0
+
+if { [skip_cplus_tests] } { continue }
+
+set testfile "casts"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if [get_compiler_info ${binfile} "c++"] {
+ return -1;
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "break [gdb_get_line_number "casts.exp: 1"]" \
+ "Breakpoint.*at.* file .*" \
+ ""
+
+gdb_test "run" "Breakpoint .* at casts.cc" ""
+
+# Casting a pointer to a base class to a pointer to a derived class
+# should yield the entire derived class. Until August 2002, GDB got
+# the enclosing type on `(B *) a' wrong: while the value's static type
+# was `B *', as it should be, the enclosing type (which is supposed to
+# be the dynamic type) was `A *'. It's senseless to have a static
+# type derived from the dynamic type; it should be the other way
+# 'round. Dereferencing this oddly typed pointer yielded a value in
+# which only the base class's members were initialized, since GDB uses
+# the enclosing type to decide how many bytes to read. Members from
+# the derived class were garbage, from GDB's address space.
+gdb_test "print * (B *) a" ".* = {<A> = {a = 42}, b = 1729}" \
+ "cast base class pointer to derived class pointer"
+
+# Check also that we get the same results from letting the compiler do
+# the dereference.
+gdb_test "print * b" ".* = {<A> = {a = 42}, b = 1729}" \
+ "let compiler cast base class pointer to derived class pointer"
--- /dev/null
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# This file tests MI thread commands.
+# Specifically, we are testing the MI command set and the console (in MI)
+# command set ("interpreter-exec") and that the commands that are executed
+# via these command pathways are properly executed. Console commands
+# executed via MI should use MI output wrappers, MI event handlers, etc.
+
+# This only works with native configurations
+if {![isnative]} {
+ return
+}
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi1"
+
+gdb_exit
+if {[mi_gdb_start]} {
+ continue
+}
+
+# The procs below dealing with parsing cli/mi output for the threadlist
+# is duplicated in gdb669.exp. Any changes here will probably need to
+# be made there as well.
+
+proc get_mi_thread_list {name} {
+ global expect_out
+
+ # MI will return a list of thread ids:
+ #
+ # -thread-list-ids
+ # ^done,thread-ids=[thread-id="1",thread-id="2",...],number-of-threads="N"
+ # (gdb)
+ mi_gdb_test "-thread-list-ids" \
+ {\^done,thread-ids={(thread-id="[0-9]+"(,)?)+},number-of-threads="[0-9]+"} \
+ "-thread_list_ids ($name)"
+
+ set output {}
+ if {[info exists expect_out(buffer)]} {
+ set output $expect_out(buffer)
+ }
+
+ set thread_list {}
+ if {![regexp {thread-ids=\{(thread-id="[0-9]+"(,)?)*\}} $output threads]} {
+ fail "finding threads in MI output ($name)"
+ } else {
+ pass "finding threads in MI output ($name)"
+
+ # Make list of console threads
+ set start [expr {[string first \{ $threads] + 1}]
+ set end [expr {[string first \} $threads] - 1}]
+ set threads [string range $threads $start $end]
+ foreach thread [split $threads ,] {
+ if {[scan $thread {thread-id="%d"} num]} {
+ lappend thread_list $num
+ }
+ }
+ }
+
+ return $thread_list
+}
+
+# Check that MI and the console know of the same threads.
+# Appends NAME to all test names.
+proc check_mi_and_console_threads {name} {
+ global expect_out
+
+ mi_gdb_test "-thread-list-ids" \
+ {\^done,thread-ids={(thread-id="[0-9]+"(,)*)+},number-of-threads="[0-9]+"} \
+ "-thread-list-ids ($name)"
+ set mi_output {}
+ if {[info exists expect_out(buffer)]} {
+ set mi_output $expect_out(buffer)
+ }
+
+ # GDB will return a list of thread ids and some more info:
+ #
+ # (gdb)
+ # -interpreter-exec console "info threads"
+ # ~" 4 Thread 2051 (LWP 7734) 0x401166b1 in __libc_nanosleep () at __libc_nanosleep:-1"
+ # ~" 3 Thread 1026 (LWP 7733) () at __libc_nanosleep:-1"
+ # ~" 2 Thread 2049 (LWP 7732) 0x401411f8 in __poll (fds=0x804bb24, nfds=1, timeout=2000) at ../sysdeps/unix/sysv/linux/poll.c:63"
+ # ~"* 1 Thread 1024 (LWP 7731) main (argc=1, argv=0xbfffdd94) at ../../../src/gdb/testsuite/gdb.mi/pthreads.c:160"
+ # FIXME: kseitz/2002-09-05: Don't use the hack-cli method.
+ mi_gdb_test "info threads" \
+ {.*(~".*"[\r\n]*)+.*} \
+ "info threads ($name)"
+ set console_output {}
+ if {[info exists $expect_out(buffer)]} {
+ set console_output $expect_out(buffer)
+ }
+
+ # Make a list of all known threads to console (gdb's thread IDs)
+ set console_thread_list {}
+ foreach line [split $console_output \n] {
+ if {[string index $line 0] == "~"} {
+ # This is a line from the console; trim off "~", " ", "*", and "\""
+ set line [string trim $line ~\ \"\*]
+ if {[scan $line "%d" id] == 1} {
+ lappend console_thread_list $id
+ }
+ }
+ }
+
+ # Now find the result string from MI
+ set mi_result ""
+ foreach line [split $mi_output \n] {
+ if {[string range $line 0 4] == "^done"} {
+ set mi_result $line
+ }
+ }
+ if {$mi_result == ""} {
+ fail "finding MI result string ($name)"
+ } else {
+ pass "finding MI result string ($name)"
+ }
+
+ # Finally, extract the thread ids and compare them to the console
+ set num_mi_threads_str ""
+ if {![regexp {number-of-threads="[0-9]+"} $mi_result num_mi_threads_str]} {
+ fail "finding number of threads in MI output ($name)"
+ } else {
+ pass "finding number of threads in MI output ($name)"
+
+ # Extract the number of threads from the MI result
+ if {![scan $num_mi_threads_str {number-of-threads="%d"} num_mi_threads]} {
+ fail "got number of threads from MI ($name)"
+ } else {
+ pass "got number of threads from MI ($name)"
+
+ # Check if MI and console have same number of threads
+ if {$num_mi_threads != [llength $console_thread_list]} {
+ fail "console and MI have same number of threads ($name)"
+ } else {
+ pass "console and MI have same number of threads ($name)"
+
+ # Get MI thread list
+ set mi_thread_list [get_mi_thread_list $name]
+
+ # Check if MI and console have the same threads
+ set fails 0
+ foreach ct [lsort $console_thread_list] mt [lsort $mi_thread_list] {
+ if {$ct != $mt} {
+ incr fails
+ }
+ }
+ if {$fails > 0} {
+ fail "MI and console have same threads ($name)"
+
+ # Send a list of failures to the log
+ send_log "Console has thread ids: $console_thread_list\n"
+ send_log "MI has thread ids: $mi_thread_list\n"
+ } else {
+ pass "MI and console have same threads ($name)"
+ }
+ }
+ }
+ }
+}
+
+# This procedure tests the various thread commands in MI.
+proc check_mi_thread_command_set {} {
+
+ mi_runto done_making_threads
+
+ set thread_list [get_mi_thread_list "in check_mi_thread_command_set"]
+
+ mi_gdb_test "-thread-select" \
+ {\^error,msg="mi_cmd_thread_select: USAGE: threadnum."} \
+ "check_mi_thread_command_set: -thread-select"
+
+ mi_gdb_test "-thread-select 123456789" \
+ {\^error,msg="Thread ID 123456789 not known\."} \
+ "check_mi_thread_command_set: -thread-select 123456789"
+
+ foreach thread $thread_list {
+ mi_gdb_test "-thread-select $thread" \
+ "\\^done,new-thread-id=\"$thread\",frame={.*},line=\"(-)?\[0-9\]+\",file=\".*\"" \
+ "check_mi_thread_command_set: -thread-select $thread"
+ }
+}
+
+#
+# Start here
+#
+set testfile "pthreads"
+set srcfile "$testfile.c"
+set binfile "$objdir/$subdir/$testfile"
+
+set options [list debug incdir=$subdir]
+if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" $binfile executable $options]
+ != "" } {
+ gdb_suppress_entire_file \
+ "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load $binfile
+
+check_mi_thread_command_set
+
+mi_gdb_exit
+