From 032a0a48e959fff809ccca419f189aa7c52b4502 Mon Sep 17 00:00:00 2001 From: nobody <> Date: Sat, 2 Nov 2002 15:13:35 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'kseitz_interps-20020528-branch'. Cherrypick from master 2002-11-02 15:13:34 UTC Andrew Cagney '2002-11-02 Andrew Cagney ': bfd/elf32-qnx.c bfd/simple.c gdb/config/i386/interix.mh gdb/config/i386/interix.mt gdb/config/i386/nm-interix.h gdb/i386-interix-nat.c gdb/i386-interix-tdep.c gdb/i386obsd-tdep.c gdb/reggroups.c gdb/reggroups.h gdb/testsuite/gdb.asm/mips.inc gdb/testsuite/gdb.c++/casts.cc gdb/testsuite/gdb.c++/casts.exp gdb/testsuite/gdb.mi/mi1-pthreads.exp --- bfd/elf32-qnx.c | 92 +++++++ bfd/simple.c | 197 ++++++++++++++ gdb/config/i386/interix.mh | 9 + gdb/config/i386/interix.mt | 3 + gdb/config/i386/nm-interix.h | 35 +++ gdb/i386-interix-nat.c | 190 ++++++++++++++ gdb/i386-interix-tdep.c | 365 ++++++++++++++++++++++++++ gdb/i386obsd-tdep.c | 122 +++++++++ gdb/reggroups.c | 268 +++++++++++++++++++ gdb/reggroups.h | 61 +++++ gdb/testsuite/gdb.asm/mips.inc | 64 +++++ gdb/testsuite/gdb.c++/casts.cc | 20 ++ gdb/testsuite/gdb.c++/casts.exp | 80 ++++++ gdb/testsuite/gdb.mi/mi1-pthreads.exp | 220 ++++++++++++++++ 14 files changed, 1726 insertions(+) create mode 100644 bfd/elf32-qnx.c create mode 100644 bfd/simple.c create mode 100644 gdb/config/i386/interix.mh create mode 100644 gdb/config/i386/interix.mt create mode 100644 gdb/config/i386/nm-interix.h create mode 100644 gdb/i386-interix-nat.c create mode 100644 gdb/i386-interix-tdep.c create mode 100644 gdb/i386obsd-tdep.c create mode 100644 gdb/reggroups.c create mode 100644 gdb/reggroups.h create mode 100644 gdb/testsuite/gdb.asm/mips.inc create mode 100644 gdb/testsuite/gdb.c++/casts.cc create mode 100644 gdb/testsuite/gdb.c++/casts.exp create mode 100644 gdb/testsuite/gdb.mi/mi1-pthreads.exp diff --git a/bfd/elf32-qnx.c b/bfd/elf32-qnx.c new file mode 100644 index 00000000000..b397c38f502 --- /dev/null +++ b/bfd/elf32-qnx.c @@ -0,0 +1,92 @@ +/* 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; +} diff --git a/bfd/simple.c b/bfd/simple.c new file mode 100644 index 00000000000..10178a40ad4 --- /dev/null +++ b/bfd/simple.c @@ -0,0 +1,197 @@ +/* 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; +} diff --git a/gdb/config/i386/interix.mh b/gdb/config/i386/interix.mh new file mode 100644 index 00000000000..23311d615fa --- /dev/null +++ b/gdb/config/i386/interix.mh @@ -0,0 +1,9 @@ +# Host: Intel 386 running Interix +XDEPFILES= +NATDEPFILES= corelow.o core-regset.o fork-child.o i386-interix-nat.o \ + procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o +NAT_FILE= nm-interix.h +XM_FILE= xm-interix.h +# The below may be temporary; mmalloc relies on sbrk() at the moment +MMALLOC= +MMALLOC_CFLAGS=-DNO_MMALLOC diff --git a/gdb/config/i386/interix.mt b/gdb/config/i386/interix.mt new file mode 100644 index 00000000000..8d609624757 --- /dev/null +++ b/gdb/config/i386/interix.mt @@ -0,0 +1,3 @@ +# Target: Intel 386 running Interix +TDEPFILES= i386-tdep.o i387-tdep.o i386-interix-tdep.o solib.o solib-pei.o +TM_FILE= tm-i386.h diff --git a/gdb/config/i386/nm-interix.h b/gdb/config/i386/nm-interix.h new file mode 100644 index 00000000000..b8b003a58d7 --- /dev/null +++ b/gdb/config/i386/nm-interix.h @@ -0,0 +1,35 @@ +/* Native-dependent definitions for Intel 386 running Interix, for GDB. + Copyright 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef NM_INTERIX_H +#define NM_INTERIX_H + +/* Be shared lib aware. */ +#include "solib.h" + +/* submodes of USE_PROC_FS. */ +#define UNIXWARE + +/* It's ALMOST coff; bfd does the same thing. Mostly used in coffread.c. */ +#define COFF_IMAGE_WITH_PE + +/* Turn on our own child_pid_to_exec_file. */ +#define CHILD_PID_TO_EXEC_FILE + +#endif /* NM_INTERIX_H */ diff --git a/gdb/i386-interix-nat.c b/gdb/i386-interix-nat.c new file mode 100644 index 00000000000..9c4daeda422 --- /dev/null +++ b/gdb/i386-interix-nat.c @@ -0,0 +1,190 @@ +/* Native-dependent code for Interix running on i386's, for GDB. + Copyright 2002 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +#include +#include +#include + +#include +#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 + +static struct core_fns interix_core_fns = +{ + bfd_target_coff_flavour, /* core_flavour (more or less) */ + default_check_format, /* check_format */ + default_core_sniffer, /* core_sniffer */ + fetch_core_registers, /* core_read_registers */ + NULL /* next */ +}; + +void +_initialize_core_interix (void) +{ + add_core_fns (&interix_core_fns); +} + +/* We don't have a /proc/pid/file or /proc/pid/exe to read a link from, + so read it from the same place ps gets the name. */ + +char * +child_pid_to_exec_file (int pid) +{ + char *path; + char *buf; + int fd, c; + char *p; + + xasprintf (&path, "/proc/%d/stat", pid); + buf = xcalloc (MAXPATHLEN + 1, sizeof (char)); + make_cleanup (xfree, path); + make_cleanup (xfree, buf); + + fd = open (path, O_RDONLY); + + if (fd < 0) + return NULL; + + /* Skip over "Argv0\t". */ + lseek (fd, 6, SEEK_SET); + + c = read (fd, buf, MAXPATHLEN); + close (fd); + + if (c < 0) + return NULL; + + buf[c] = '\0'; /* Ensure null termination. */ + p = strchr (buf, '\n'); + if (p != NULL) + *p = '\0'; + + return buf; +} diff --git a/gdb/i386-interix-tdep.c b/gdb/i386-interix-tdep.c new file mode 100644 index 00000000000..ff310ecad35 --- /dev/null +++ b/gdb/i386-interix-tdep.c @@ -0,0 +1,365 @@ +/* Target-dependent code for Interix running on i386's, for GDB. + Copyright 2002 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "arch-utils.h" + +#include "frame.h" +#include "gdb_string.h" +#include "gdb-stabs.h" +#include "gdbcore.h" +#include "gdbtypes.h" +#include "i386-tdep.h" +#include "inferior.h" +#include "libbfd.h" +#include "objfiles.h" +#include "osabi.h" +#include "regcache.h" + +/* offsetof (mcontext_t, gregs.gregs[EBP]) */ +static const int mcontext_EBP_greg_offset = 180; + +/* offsetof (mcontext_t, gregs.gregs[EIP]) */ +static const int mcontext_EIP_greg_offset = 184; + +/* offsetof (mcontext_t, gregs.gregs[UESP]) */ +static const int mcontext_UESP_greg_offset = 196; + +/* offsetof (mcontext_t, gregs.reserved[1]) */ +static const int mcontext_syscall_greg_offset = 4; + +/* offsetof (_JUMP_BUFFER, Eip) */ +static const int jump_buffer_Eip_offset = 20; + +/* See procfs.c and *interix*.h in config/[alpha,i386]. */ +/* ??? These should be static, but this needs a bit of work before this + can be done. */ +CORE_ADDR tramp_start; +CORE_ADDR tramp_end; +CORE_ADDR null_start; +CORE_ADDR null_end; +int winver; /* Windows NT version number */ + +/* Forward declarations. */ +extern void _initialize_i386_interix_tdep (void); +extern initialize_file_ftype _initialize_i386_interix_tdep; + +/* Adjust the section offsets in an objfile structure so that it's correct + for the type of symbols being read (or undo it with the _restore + arguments). + + If main programs ever start showing up at other than the default Image + Base, this is where that would likely be applied. */ + +void +pei_adjust_objfile_offsets (struct objfile *objfile, + enum objfile_adjusts type) +{ + int i; + CORE_ADDR symbols_offset; + + switch (type) + { + case adjust_for_symtab: + symbols_offset = NONZERO_LINK_BASE (objfile->obfd); + break; + case adjust_for_symtab_restore: + symbols_offset = -NONZERO_LINK_BASE (objfile->obfd); + break; + case adjust_for_stabs: + case adjust_for_stabs_restore: + case adjust_for_dwarf: + case adjust_for_dwarf_restore: + default: + return; + } + + for (i = 0; i < SECT_OFF_MAX; i++) + { + (objfile->section_offsets)->offsets[i] += symbols_offset; + } +} + +static int +i386_interix_pc_in_sigtramp (CORE_ADDR pc, char *name) +{ + /* This is sufficient, where used, but is NOT a complete test; There + is more in INIT_EXTRA_FRAME_INFO (a.k.a. interix_back_one_frame). */ + return ((pc >= tramp_start && pc < tramp_end) + || (pc >= null_start && pc < null_end)); +} + +static int +i386_interix_in_solib_call_trampoline (CORE_ADDR pc, char *name) +{ + return i386_pe_skip_trampoline_code (pc, name); +} + +static CORE_ADDR +i386_interix_skip_trampoline_code (CORE_ADDR pc) +{ + return i386_pe_skip_trampoline_code (pc, 0); +} + +static void +i386_interix_init_frame_pc (int fromleaf, struct frame_info *prev) +{ + /* Nothing to do on Interix. */ +} + +static int +i386_interix_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe) +{ + /* In the context where this is used, we get the saved PC before we've + successfully unwound far enough to be sure what we've got (it may + be a signal handler caller). If we're dealing with a signal + handler caller, this will return valid, which is fine. If not, + it'll make the correct test. */ + return (thisframe->signal_handler_caller + || (chain != 0 + && !inside_entry_file (read_memory_integer + (thisframe->frame + 4, 4)))); +} + +/* We want to find the previous frame, which on Interix is tricky when signals + are involved; set frame->frame appropriately, and also get the pc + and tweak signal_handler_caller; this replaces a boatload of nested + macros, as well. */ +static void +i386_interix_back_one_frame (int fromleaf, struct frame_info *frame) +{ + CORE_ADDR ra; + CORE_ADDR fm; + CORE_ADDR context; + long t; + + if (frame == NULL) + internal_error (__FILE__, __LINE__, "unexpected NULL frame"); + + if (fromleaf) + { + frame->pc = SAVED_PC_AFTER_CALL (frame->next); + return; + } + + if (!frame->next) + { + frame->pc = read_pc (); + + /* Part of the signal stuff... See below. */ + if (stopped_by_random_signal) + { + /* We know we're in a system call mini-frame; was it + NullApi or something else? */ + ra = SAVED_PC_AFTER_CALL (frame); + if (ra >= null_start && ra < null_end) + frame->signal_handler_caller = 1; + /* There might also be an indirect call to the mini-frame, + putting one more return address on the stack. (XP only, + I think?) This can't (reasonably) return the address of the + signal handler caller unless it's that situation, so this + is safe. */ + ra = read_memory_unsigned_integer (read_register (SP_REGNUM) + 4, 4); + if (ra >= null_start && ra < null_end) + frame->signal_handler_caller = 1; + } + return; + } + + if (!frame->next->signal_handler_caller) + { + frame->pc = read_memory_integer (frame->next->frame + 4, 4); + return; + } + + /* This is messy (actually AWFUL)... The "trampoline" might be 2, 3 + or all 5 entities on the frame. + + Chunk 1 will be present when we're actually in a signal handler. + Chunk 2 will be present when an asynchronous signal (one that + didn't come in with a system call) is present. + We may not (yet) be in the handler, if we're just returning + from the call. + When we're actually in a handler taken from an asynchronous + signal, both will be present. + + Chunk 1: + PdxSignalDeliverer's frame + + Context struct -- not accounted for in any frame + + Chunk 2: + + PdxNullPosixApi's frame + + PdxNullApiCaller's frame + + Context struct = 0x230 not accounted for in any frame + + The symbol names come from examining objdumps of psxdll.dll; + they don't appear in the runtime image. + + For gdb's purposes, we can pile all this into one frame. */ + + ra = frame->next->pc; + /* Are we already pointing at PdxNullPosixApi? We are if + this is a signal frame, we're at next-to-top, and were stopped + by a random signal (if it wasn't the right address under + these circumstances, we wouldn't be here at all by tests above + on the prior frame). */ + if (frame->next->next == NULL && stopped_by_random_signal) + { + /* We're pointing at the frame FOR PdxNullApi. */ + fm = frame->frame; + } + else + { + /* No... We must be pointing at the frame that was called + by PdxSignalDeliverer; back up across the whole mess. */ + + /* Extract the frame for PdxSignalDeliverer. + Note: FRAME_CHAIN used the "old" frame pointer because we were + a deliverer. Get the address of the context record that's on + here frameless. */ + context = read_memory_integer (frame->frame, 4); /* an Arg */ + + /* Now extract the frame pointer contained in the context. */ + fm = read_memory_integer (context + mcontext_EBP_greg_offset, 4); + + ra = read_memory_integer (context + mcontext_EIP_greg_offset, 4); + + /* We need to know if we're in a system call because we'll be + in a syscall mini-frame, if so, and the rules are different. */ + t = (long) read_memory_integer (context + mcontext_syscall_greg_offset, + 4); + /* t contains 0 if running free, 1 if blocked on a system call, + and 2 if blocked on an exception message (e.g. a trap); + we don't expect to get here with a 2. */ + if (t != 1) + { + /* Not at a system call, therefore it can't be NullApi. */ + frame->pc = ra; + frame->frame = fm; + return; + } + + /* It's a system call... Mini frame, then look for NullApi. */ + /* Get the RA (on the stack) associated with this... It's + a system call mini-frame. */ + ra = read_memory_integer (context + mcontext_UESP_greg_offset, 4); + + if (winver >= 51) + { + /* Newer versions of Windows NT interpose another return + address (but no other "stack frame" stuff) that we need + to simply ignore here. */ + ra += 4; + } + + ra = read_memory_integer (ra, 4); + + if (!(ra >= null_start && ra < null_end)) + { + /* No Null API present; we're done. */ + frame->pc = ra; + frame->frame = fm; + return; + } + } + + /* At this point, we're looking at the frame for PdxNullPosixApi, + in either case. + + PdxNullPosixApi is called by PdxNullApiCaller (which in turn + is called by _PdxNullApiCaller (note the _).) + PdxNullPosixApiCaller (no _) is a frameless function. + + The saved frame pointer is as fm, but it's not of interest + to us because it skips us over the saved context, which is + the wrong thing to do, because it skips the interrrupted + routine! PdxNullApiCaller takes as its only argument the + address of the context of the interrupded function (which + is really in no frame, but jammed on the stack by the system) + + So: fm+0: saved bp + fm+4: return address to _PdxNullApiCaller + fm+8: arg to PdxNullApiCaller pushed by _Pdx... */ + + fm = read_memory_integer (fm + 0x8, 4); + + /* Extract the second context record. */ + + ra = read_memory_integer (fm + mcontext_EIP_greg_offset, 4); + fm = read_memory_integer (fm + mcontext_EBP_greg_offset, 4); + + frame->frame = fm; + frame->pc = ra; + + return; +} + +static CORE_ADDR +i386_interix_frame_saved_pc (struct frame_info *fi) +{ + /* Assume that we've already unwound enough to have the caller's address + if we're dealing with a signal handler caller (And if that fails, + return 0). */ + if (fi->signal_handler_caller) + return fi->next ? fi->next->pc : 0; + else + return read_memory_integer (fi->frame + 4, 4); +} + +static void +i386_interix_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->struct_return = reg_struct_return; + tdep->jb_pc_offset = jump_buffer_Eip_offset; + + set_gdbarch_decr_pc_after_break (gdbarch, 0); + set_gdbarch_pc_in_sigtramp (gdbarch, i386_interix_pc_in_sigtramp); + set_gdbarch_in_solib_call_trampoline (gdbarch, + i386_interix_in_solib_call_trampoline); + set_gdbarch_skip_trampoline_code (gdbarch, + i386_interix_skip_trampoline_code); + set_gdbarch_init_extra_frame_info (gdbarch, i386_interix_back_one_frame); + set_gdbarch_init_frame_pc (gdbarch, i386_interix_init_frame_pc); + set_gdbarch_frame_chain_valid (gdbarch, i386_interix_frame_chain_valid); + set_gdbarch_frame_saved_pc (gdbarch, i386_interix_frame_saved_pc); + set_gdbarch_name_of_malloc (gdbarch, "_malloc"); +} + +static enum gdb_osabi +i386_interix_osabi_sniffer (bfd * abfd) +{ + char *target_name = bfd_get_target (abfd); + + if (strcmp (target_name, "pei-i386") == 0) + return GDB_OSABI_INTERIX; + + return GDB_OSABI_UNKNOWN; +} + +void +_initialize_i386_interix_tdep (void) +{ + gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour, + i386_interix_osabi_sniffer); + + gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_INTERIX, + i386_interix_init_abi); +} diff --git a/gdb/i386obsd-tdep.c b/gdb/i386obsd-tdep.c new file mode 100644 index 00000000000..7f162379a54 --- /dev/null +++ b/gdb/i386obsd-tdep.c @@ -0,0 +1,122 @@ +/* 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 */ +}; + + +CORE_ADDR i386obsd_sigtramp_start = 0xbfbfdf20; +CORE_ADDR i386obsd_sigtramp_end = 0xbfbfdff0; + +/* From . */ +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); +} diff --git a/gdb/reggroups.c b/gdb/reggroups.c new file mode 100644 index 00000000000..8c3cbb76128 --- /dev/null +++ b/gdb/reggroups.c @@ -0,0 +1,268 @@ +/* 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); + +} diff --git a/gdb/reggroups.h b/gdb/reggroups.h new file mode 100644 index 00000000000..0088a8520e3 --- /dev/null +++ b/gdb/reggroups.h @@ -0,0 +1,61 @@ +/* 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 diff --git a/gdb/testsuite/gdb.asm/mips.inc b/gdb/testsuite/gdb.asm/mips.inc new file mode 100644 index 00000000000..751f73f859b --- /dev/null +++ b/gdb/testsuite/gdb.asm/mips.inc @@ -0,0 +1,64 @@ + 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 diff --git a/gdb/testsuite/gdb.c++/casts.cc b/gdb/testsuite/gdb.c++/casts.cc new file mode 100644 index 00000000000..831add94418 --- /dev/null +++ b/gdb/testsuite/gdb.c++/casts.cc @@ -0,0 +1,20 @@ +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 */ +} diff --git a/gdb/testsuite/gdb.c++/casts.exp b/gdb/testsuite/gdb.c++/casts.exp new file mode 100644 index 00000000000..68ce704bc13 --- /dev/null +++ b/gdb/testsuite/gdb.c++/casts.exp @@ -0,0 +1,80 @@ +# 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 = 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 = 42}, b = 1729}" \ + "let compiler cast base class pointer to derived class pointer" diff --git a/gdb/testsuite/gdb.mi/mi1-pthreads.exp b/gdb/testsuite/gdb.mi/mi1-pthreads.exp new file mode 100644 index 00000000000..aea4f582836 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi1-pthreads.exp @@ -0,0 +1,220 @@ +# 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 + -- 2.47.2