Index: gnu/gdb-4.17/bfd/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/bfd/ChangeLog.linux:1.1 --- /dev/null Sat Aug 21 11:58:48 1999 +++ gnu/gdb-4.17/bfd/ChangeLog.linux Tue Dec 1 21:52:00 1998 @@ -0,0 +1,12 @@ +Tue Dec 1 19:28:56 1998 H.J. Lu (hjl@gnu.org) + + From Jack Howarth : + + The following patch should fix things to use EM_SPARCV9 when + producing binaries while continuing to accept the old value. + + * elf64-sparc.c (ELF_MACHINE_CODE): Defined as EM_SPARCV9. + (ELF_MACHINE_ALT1): Defined as EM_OLD_SPARCV9. + + * elf.c (prep_headers): Change EM_SPARC64 to EM_SPARCV9. + Index: gnu/gdb-4.17/bfd/elf.c diff -u gnu/gdb-4.17/bfd/elf.c:1.1.1.1 gnu/gdb-4.17/bfd/elf.c:1.2 --- gnu/gdb-4.17/bfd/elf.c:1.1.1.1 Fri May 29 06:58:18 1998 +++ gnu/gdb-4.17/bfd/elf.c Tue Dec 1 21:52:00 1998 @@ -2851,7 +2851,7 @@ break; case bfd_arch_sparc: if (bed->s->arch_size == 64) - i_ehdrp->e_machine = EM_SPARC64; + i_ehdrp->e_machine = EM_SPARCV9; else i_ehdrp->e_machine = EM_SPARC; break; Index: gnu/gdb-4.17/bfd/elf64-sparc.c diff -u gnu/gdb-4.17/bfd/elf64-sparc.c:1.1.1.1 gnu/gdb-4.17/bfd/elf64-sparc.c:1.2 --- gnu/gdb-4.17/bfd/elf64-sparc.c:1.1.1.1 Fri May 29 06:58:19 1998 +++ gnu/gdb-4.17/bfd/elf64-sparc.c Tue Dec 1 21:52:00 1998 @@ -2224,8 +2224,14 @@ #define TARGET_BIG_SYM bfd_elf64_sparc_vec #define TARGET_BIG_NAME "elf64-sparc" #define ELF_ARCH bfd_arch_sparc -#define ELF_MACHINE_CODE EM_SPARC64 #define ELF_MAXPAGESIZE 0x100000 + +/* This is the official ABI value. */ +#define ELF_MACHINE_CODE EM_SPARCV9 + +/* This is what we used before we had the official ABI. This should + eventually go away. */ +#define ELF_MACHINE_ALT1 EM_OLD_SPARCV9 #define elf_info_to_howto \ sparc64_elf_info_to_howto Index: gnu/gdb-4.17/gdb/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/gdb/ChangeLog.linux:1.17 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/ChangeLog.linux Sun May 9 07:41:21 1999 @@ -0,0 +1,414 @@ +Wed May 5 16:36:36 1999 H.J. Lu + + * Makefile.in (VERSION): Updated to "4.17.0.12 with Linux + support". + + * config/i386/linux.mh (NATDEPFILES): Add lnx-thread.o and + lnx-nat.o. + + * config/powerpc/nm-linux.h: Include "nm-linux.h". + + * config/powerpc/tm-linux.h: Include "tm-linux.h". + +Wed Mar 17 19:49:22 1999 Sam Lantinga (slouken@devolution.com) + + * solib.h, solib.c, infrun.c: Added function check_solib_consistency() + to reload list of shared objects when they are added or deleted. + This fixed crashing when the program being debugged unloaded a + dynamic library and added a new library afterwards. + +Sat Feb 13 05:42:33 1999 H.J. Lu + + * Makefile.in (VERSION): Updated to "4.17.0.11 with Linux + support". + + * i386-tdep.c (i386_frame_chain, i386_linux_sigtramp_offset, + i386_linux_sigtramp_saved_pc): Moved to i386lnx-nat.c. + * i386lnx-nat.c: Get them. + + * lnx-thread.c (_NSIG, LINUXTHREAD_SIG_CANCEL, + LINUXTHREAD_SIG_EXIT, LINUXTHREAD_NSIG): Removed. + (linux_has_rtsig, linux_kernel_has_rtsig): New. + (linuxthreads_new_objfile): Don't call __libc_allocate_rtsig (). + + * config/i386/nm-linux.h (target_new_objfile, target_pid_to_str, + PREPARE_TO_PROCEED): Moved to config/nm-linux.h. + + * config/i386/tm-i386.h (FRAME_CHAIN): Moved to + config/i386/tm-linux.h. + * config/i386/tm-linux.h: Get it. + + * sol-thread.c: Fix function prototype for Solaris 2.7/x86. + * config/i386/nm-i386sol2.h: Likewise. + + * lnx-nat.c: New. + * config/i386/linux.mh (NATDEPFILES): Add lnx-nat.o. + * config/i386/linuxlibc1.mh: Likewise. + * config/alpha/alpha-linux.mh: Likewise. + + * config/nm-linux.h: New. + * config/i386/nm-linux.h: Include "nm-linux.h". + * config/alpha/nm-alphalinux.h: Likewise. + + * config/tm-linux.h: New. + * config/i386/tm-linux.h: Include "tm-linux.h". + * config/alpha/tm-linux.h: Likewise. + +Wed Feb 10 02:39:07 1999 Hannes Reinecke + + * config/alpha/alpha-linux.mh (NATDEPFILES): Add lnx-thread.o. + +Wed Feb 3 07:17:41 1999 H.J. Lu + + * Makefile.in (VERSION): Updated to "4.17.0.10 with Linux + support". + + * lnx-thread.c (stop_thread): Send linuxthreads_sig_restart + to the suspended thread if linuxthreads_sig_debug > 0. + (update_stop_threads): Likewise. + (linuxthreads_wait): Allocate wstatus only once. + (linuxthreads_kill): Wait for all threads to exit after killing + them. + + * i386lnx-nat.c (i386_delete_watchpoint): Remove all hardware + watchpoints with the matching watchpoint number. + +Sun Jan 24 18:32:22 1999 H.J. Lu + + * Makefile.in (VERSION): Updated to "4.17.0.9 with Linux + support". + + * breakpoint.c (insert_breakpoints): Also pass b->number to + target_insert_watchpoint () if NEED_WATCHPOINT_NUMBER is + defined. + (remove_breakpoint): Also pass b->number to + target_remove_watchpoint () if NEED_WATCHPOINT_NUMBER is + defined. + (delete_breakpoint): Call target_delete_watchpoint () for + watchpoint if NEED_WATCHPOINT_NUMBER is defined. + + * i386lnx-nat.c (address_lookup): Add a new field for the + watchpoint number. + (i386_insert_aligned_watchpoint): Handle it. + (i386_remove_watchpoint): Likewise. + (i386_stopped_by_watchpoint): Likewise. + + * i386lnx-nat.c (i386_insert_aligned_watchpoint): Handle + large "len". + + * i386lnx-nat.c (i386_insert_aligned_watchpoint): Add "num" to + the argument. + (i386_insert_nonaligned_watchpoint): Likewise. + (i386_insert_watchpoint): Likewise. + (i386_remove_watchpoint): Likewise. + * config/i386/nm-linux.h (target_insert_watchpoint): Likewise. + (target_remove_watchpoint): Likewise. + (i386_insert_watchpoint): Likewise. + (i386_remove_watchpoint): Likewise. + + * i386lnx-nat.c (i386_delete_watchpoint): New. + + * lnx-thread.c (linuxthreads_sig_debug, + linuxthreads_sig_debug_stop, linuxthreads_sig_debug_print): New. + (linuxthreads_signal_update): Handle them. + + * lnx-thread.c (linuxthreads_new_objfile): For glibc 2.1, get + linuxthreads_sig_restart, linuxthreads_sig_cancel and + linuxthreads_sig_debug from __libc_allocate_rtsig (). They have + to be the same order as in glibc 2.1. + Check linuxthreads_sig_cancel instead of linuxthreads_sig_restart + if linuxthreads_sig_debug > 0. + + * lnx-thread.c (linuxthreads_attach): Check NULL arg. + (linuxthreads_create_inferior): Check for file to run. + (iterate_active_threads): Skip the linuxthreads manager. + +Tue Jan 12 00:01:05 1999 + + * i387-tdep.c (i387_print_register): Don't print a register + if the register number is -1. + +Sun Dec 20 11:23:40 1998 H.J. Lu + + * Makefile.in (VERSION): Updated to "4.17.0.8 with Linux + support". + + * config/alpha/alpha-linux.mh (REGEX, REGEX1): Clear. + * config/i386/linux.mh: Likewise. + * config/powerpc/linux.mh: Likewise. + * config/sparc/linux.mh: Likewise. + + * config/alpha/alpha-linuxlibc1.mh: New. + * config/i386/linuxlibc1.mh: New. + * config/powerpc/linuxlibc1.mh: New. + * config/sparc/linuxlibc1.mh: New. + + * configure.host (alpha*-*-linux*libc1): New host. + (i[3456]86-*-linux*libc1): Likewise. + (i[3456]86-*-linux*libc5): Likewise. + (powerpc-*-linux*libc1): Likewise. + (sparc-*-linux*libc1): Likewise. + (sparc-*-linux*libc5): Likewise. + + * irix5-nat.c: Include instead of "gnu-regex.h" for + glibc 2. + * monitor.c: Likewise. + * osfsolib.c: Likewise. + * solib.c: Likewise. + * source.c: Likewise. + * symtab.c: Likewise. + +Sat Dec 19 17:31:08 1998 H.J. Lu + + * Makefile.in (VERSION): Changed to "4.17.0.7 with Linux + support". + (lnx-thread.o): Add dependency. + (ppclnx-nat.o): Likewise. + (ppclnx-tdep.o): Likewise. + + * i386-tdep.c (JB_PC): Defined if not defined. + * i386-tdep.c (PT_CONTINUE): Likewise. + (PT_STEP): Likewise. + * lnx-thread.c (PT_ATTACH): Likewise. + (PT_KILL): Likewise. + (PT_READ_U): Likewise. + (_NSIG): Likewise. + + * i386lnx-nat.c: Handle debugreg.h right. + + * gdbcmd.h (doing_quit_force): New, delared. + + * corefile.c (memory_error): Don't call return_to_top_level if + doing_quit_force is non-zero. + + * lnx-thread.c: Include "gdbcmd.h". + (stop_thread): Call perror_with_name if ptrace fails. + (linuxthreads_new_objfile): Call __libc_allocate_rtsig if + linuxthreads_sig_restart and linuxthreads_sig_cancel are zero. + (linuxthreads_kill): Wait on children if doing_quit_force >= 0. + + * top.c (doing_quit_force): Defined. Set to 0. + (quit_force): Set doing_quit_force to 1. + +Wed Dec 2 18:06:04 1998 H.J. Lu + + * Makefile.in (VERSION): Changed to "4.17.0.6 with Linux + support". + + * config/i386/tm-linux.h (REALTIME_LO, REALTIME_HI): Defined + if __SIGRTMIN is defined. + + * target.h (target_signal): Add TARGET_SIGNAL_REALTIME_32. + + * target.c (signals): Add SIG32. + (target_signal_from_host): Change the base for real time signal + from TARGET_SIGNAL_REALTIME_33 to TARGET_SIGNAL_REALTIME_32. + (target_signal_to_host): Use 32 for TARGET_SIGNAL_REALTIME_32 + during conversion. + +Tue Dec 1 19:56:41 1998 H.J. Lu + + * config/i386/linux.mt (MT_CFLAGS): Set to -D_GNU_SOURCE. + + From Eric Paire : + + * lnx-thread.c: New. + + * config/i386/linux.mh (NATDEPFILES): Add lnx-thread.o. + + * breakpoint.c: Add the support for linuxthreads. + * i386-tdep.c: Likewise. + * inferior.h: Likewise. + * infrun.c: Likewise. + * target.h: Likewise. + * config/i386/nm-linux.h: Likewise. + * config/i386/tm-linux.h: Likewise. + * config/i386/tm-i386.h: Likewise. + + * config/nm-m3.h (PREPARE_TO_PROCEED): Minor change. + + * m3-nat.c (mach3_prepare_to_proceed): Fix a bug. + +Sat Nov 21 15:03:10 1998 Jack Howarth + + * config/sparc/nm-linux.h: Clean up. + + * infptrace.c: Add support for Linux/Sparc. + * sparc-nat.c: Likewise. + * sparc-tdep.c: Likewise. + + * config/sparc/linux.mh (NATDEPFILES): Add sparc-nat.o. + + * config/sparc/tm-linux.h (prgreg_t): Defined as greg_t. + (prgregset_t): Defined as gregset_t. + (prfpregset_t): Defined as fpregset_t. + (R_I7): Defined 31. + (R_PS): Defined 32. + (R_PC): Defined 33. + (R_nPC): Defined 34. + (R_Y): Defined 35. + + * config/powerpc/linux.mh (NATDEPFILES): Add ppclnx-nat.o. + (NAT_FILE): Set to nm-linux.h. + + * configure.tgt: Set gdb_target to linux for powerpc-*-linux*. + + * infrun.c (AT_SUBROUTINE_CALL_INSTRUCTION_TARGET): New. + (wait_for_inferior): Use it. + + * ppclnx-nat.c: New file for Linux/PPC. + * ppclnx-tdep.c: Likewise. + * config/powerpc/linux.mt: Likewise. + * config/powerpc/nm-linux.h: Likewise. + * config/powerpc/tm-linux.h: Likewise. + +Thu Nov 19 08:17:43 1998 H.J. Lu + + * infptrace.c (detach): Handle errno == ESRCH gracefully. + + * target.c (print_waitstatus): New function. + (debug_to_wait): Use it. + * target.h (print_waitstatus): Add prototype. + +Wed Nov 18 08:01:36 1998 H.J. Lu + + * Makefile.in (VERSION): Changed to "4.17.0.5 with Linux/x86 + hardware watchpoint and FPU support". + + * i387-tdep.c (i387_print_register): Fix the tag code handling. + +Thu Jun 25 19:09:56 1998 H.J. Lu + + * Makefile.in (VERSION): Changed to "4.17.0.4 with Linux/x86 + hardware watchpoint and FPU support". + + * i386lnx-nat.c (i386_insert_aligned_watchpoint): Reuse the + old lookup address. Ignore large variable. + +Mon Jun 1 08:05:07 1998 H.J. Lu + + * Makefile.in (VERSION): Changed to "4.17.0.3 with Linux/x86 FPU + support". + + * i386lnx-nat.c (old_fetch_inferior_registers, + old_store_inferior_registers): Fake FP registers. + +Fri May 29 07:33:08 1998 H.J. Lu + + * Makefile.in (i386lnx-nat.o): Add dependency. + (VERSION): Changed to 4.17.0.2. + + * c-exp.y (parse_number): Fix comment. + + * findvar.c (read_register_bytes): Use ARCH_NUM_REGS instead of + NUM_REGS. + (write_register_bytes): Likewise. + * i386-tdep.c (i386_frame_find_saved_regs): Likewise. + (i386_push_dummy_frame): Likewise. + + * i386-tdep.c (i386_do_registers_info): Use RUNTIME_NUM_REGS + instead of DO_REGISTERS_INFO_NUM_REGS. + * i387-tdep.c (i387_float_info): Likewise. + * config/i386/tm-i386.h: Likewise. + * config/i386/tm-linux.h: Likewise. + + * i386-tdep.c (i386_do_registers_info): Use INFO_REGMAP for + read_relative_register_raw_bytes and i387_print_register. + * i387-tdep.c (i387_float_info): Likewise. + + * i386-tdep.c (i386_print_register): Fix a typo. + + * i386lnx-nat.c (fetch_register, old_fetch_inferior_registers, + store_register, old_store_inferior_registers, + new_fetch_inferior_registers, new_store_inferior_registers, + i386_register_u_addr, supply_gregset, fill_gregset, + supply_fpregset, fill_fpregset, fetch_core_registers): Rewrite. + (get_runtime_num_regs): Renamed from get_reg_info_num_regs. + + * config/i386/tm-linux.h (REGISTER_NAMES): Fixed according to + gcc register numbering scheme. + (SP_REGNUM, PS_REGNUM, FP0_REGNUM, FPC_REGNUM, FPSWD_REGNUM, + FPTWD_REGNUM, FPIPO_REGNUM, FPIPS_REGNUM, FPOOS_REGNUM, + FPOPS_REGNUM): Rearranged according to REGISTER_NAMES. + (REGISTER_CONVERTIBLE, REGISTER_BYTE, REGISTER_RAW_SIZE, + REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW): Updated. + (GREGISTER, GREGISTER_BYTE, FPREGISTER_BYTE): New. + +Mon May 25 22:18:03 1998 H.J. Lu + + * breakpoint.c (VALUE_FIT_IN_REG): New. + (can_use_hardware_watchpoint): Use it. + + * config/i386/linux.mh (NATDEPFILES): Remove i386v-nat.o + i386v4-nat.o and add i386lnx-nat.o. + + * config/i386/nm-linux.h (FETCH_INFERIOR_REGISTERS): Defined. + (NO_SYS_REG_H): Removed. + (NO_PTRACE_H): undefined. + Include if HAVE_SYS_REG_H is not defined. + + * config/i386/tm-i386.h (FPC_REGNUM): Defined as -1. + (FPCWD_REGNUM, FPSWD_REGNUM, FPTWD_REGNUM, FPIPO_REGNUM, + FPIPS_REGNUM, FPOOS_REGNUM, FPOPS_REGNUM): New. + (INFO_REGMAP): New. + (DO_REGISTERS_INFO_NUM_REGS): new. + + * config/i386/tm-linux.h (NUM_FREGS, NUM_REGS: New. + (INFO_REGMAP): New. + (DO_REGISTERS_INFO_NUM_REGS): New. + (REGISTER_NAMES): New. + (FP_REGNUM, SP_REGNUM, PS_REGNUM, PC_REGNUM, FP0_REGNUM, + FPC_REGNUM, FPCWD_REGNUM, FPSWD_REGNUM, FPTWD_REGNUM, + FPIPO_REGNUM, FPIPS_REGNUM, FPOOS_REGNUM, FPOPS_REGNUM): New. + (GREGISTER_BYTES, gregister_set): New. + (FPEGISTER_BYTES, fpregister_set): New. + (REGISTER_BYTES): New. + (REGISTER_BYTE): New. + (VALUE_FIT_IN_REG): New. + + * configure.in (AC_CHECK_HEADERS): Add sys/reg.h. + * configure: Regenerated. + * config.in: Likewise. + + * i386-tdep.c (i386_print_status_word): New. + + * i386lnx-nat.c: New. + + * target.c (target_read_string): Handle partial read. + + Based on patch from Bill Metzenthen : + * config/i386/tm-linux.h (I386_LINUX_TARGET): New. + (MAX_REGISTER_RAW_SIZE, MAX_REGISTER_VIRTUAL_SIZE): New. + (TARGET_LONG_DOUBLE_BIT): New. + (HEX_LONG_DOUBLE_INPUT): new. + (REGISTER_CONVERTIBLE): New. + (REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW): New. + (REGISTER_VIRTUAL_TYPE): New. + (FLOAT_INFO): New. + (DO_REGISTERS_INFO): New. + + * findvar.c (extract_floating): Also check + TARGET_LONG_DOUBLE_BIT for long double. + + * i386-tdep.c (i386_extract_return_value): On Linux floating + point values are returned in floating registers. + (i386_do_registers_info): New. + (i386_print_register): New. + + * i387-tdep.c (print_387_control_bits): Renamed from + print_387_control_word. + (print_387_status_bits: Renamed from print_387_status_word. + (print_387_control_word): New. + (print_387_status_word): New. + (i387_print_register): New. + (i387_float_info): New. + (i387_hex_long_double_input): New. + + * valprint.c (print_floating): Handle TARGET_LONG_DOUBLE_BIT == + 80. + +Wed Feb 18 17:11:38 1998 Bill Metzenthen + + * c-exp.y (parse_number): Add long double support. + + * config/i386/xm-linux.h (HOST_I386): New. Index: gnu/gdb-4.17/gdb/Makefile.in diff -u gnu/gdb-4.17/gdb/Makefile.in:1.1.1.1 gnu/gdb-4.17/gdb/Makefile.in:1.15 --- gnu/gdb-4.17/gdb/Makefile.in:1.1.1.1 Fri May 29 06:57:32 1998 +++ gnu/gdb-4.17/gdb/Makefile.in Sat Aug 21 11:31:19 1999 @@ -187,7 +187,7 @@ ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) -VERSION=4.17 +VERSION=4.17.0.13 with Linux support DIST=gdb LINT=/usr/5bin/lint @@ -1098,6 +1098,9 @@ i386b-nat.o: i386b-nat.c $(defs_h) +i386lnx-nat.o: i386lnx-nat.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ + $(inferior_h) language.h target.h + i386ly-nat.o: i386ly-nat.c $(defs_h) $(frame_h) $(inferior_h) target.h i386ly-tdep.o: i386ly-tdep.c $(defs_h) $(inferior_h) target.h $(gdbcore_h) @@ -1143,6 +1146,9 @@ $(gdbcmd_h) $(gdbtypes_h) language.h parser-defs.h $(symtab_h) \ target.h $(value_h) gdb_string.h +lnx-thread.o: lnx-thread.c $(breakpoint_h) $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ + gdbthread.h $(inferior_h) target.h language.h $(wait_h) + lynx-nat.o: lynx-nat.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcore_h) \ target.h @@ -1258,6 +1264,13 @@ ppcbug-rom.o: ppcbug-rom.c monitor.h $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ $(inferior_h) target.h serial.h terminal.h + +ppclnx-nat.o: ppclnx-nat.c $(defs_h) $(bfd_h) $(inferior_h) $(gdbcore_h) target.h \ + $(symtab_h) symfile.h objfiles.h $(frame_h) language.h gdb-stabs.h \ + gdb_string.h + +ppclnx-tdep.o: ppclnx-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) target.h \ + $(symtab_h) symfile.h objfiles.h $(frame_h) language.h printcmd.o: printcmd.c $(breakpoint_h) $(defs_h) $(expression_h) \ $(gdbcmd_h) $(gdbcore_h) $(gdbtypes_h) language.h objfiles.h \ Index: gnu/gdb-4.17/gdb/breakpoint.c diff -u gnu/gdb-4.17/gdb/breakpoint.c:1.1.1.1 gnu/gdb-4.17/gdb/breakpoint.c:1.4 --- gnu/gdb-4.17/gdb/breakpoint.c:1.1.1.1 Fri May 29 06:57:32 1998 +++ gnu/gdb-4.17/gdb/breakpoint.c Sun Jan 24 18:48:01 1999 @@ -1,6 +1,6 @@ /* Everything about breakpoints, for GDB. - Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 - Free Software Foundation, Inc. + Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998 Free Software Foundation, Inc. This file is part of GDB. @@ -641,7 +641,12 @@ else if (b->type == bp_access_watchpoint) type = 2; +#ifdef NEED_WATCHPOINT_NUMBER + val = target_insert_watchpoint (b->number, addr, + len, type); +#else val = target_insert_watchpoint (addr, len, type); +#endif if (val == -1) { b->inserted = 0; @@ -762,7 +767,12 @@ else if (b->type == bp_access_watchpoint) type = 2; +#ifdef NEED_WATCHPOINT_NUMBER + val = target_remove_watchpoint (b->number, addr, len, + type); +#else val = target_remove_watchpoint (addr, len, type); +#endif if (val == -1) b->inserted = 1; val = 0; @@ -2165,12 +2175,19 @@ struct minimal_symbol *m; m = lookup_minimal_symbol_text (func_name, NULL, (struct objfile *)NULL); - if (m) - sal.pc = SYMBOL_VALUE_ADDRESS (m); - else + if (!m) return; + + sal.pc = SYMBOL_VALUE_ADDRESS (m); + sal.section = find_pc_overlay (sal.pc); + + /* Don't insert twice a bp_longjmp breakpoint at the same address */ + ALL_BREAKPOINTS (b) + if (b->type == bp_longjmp + && b->address == sal.pc + && (overlay_debugging == 0 || b->section == sal.section)) + return; } - sal.section = find_pc_overlay (sal.pc); b = set_raw_breakpoint (sal); if (!b) return; @@ -2828,6 +2845,11 @@ mention (b); } +#ifndef VALUE_FIT_IN_REG +#define VALUE_FIT_IN_REG(v) \ + (TYPE_LENGTH (VALUE_TYPE (v)) <= REGISTER_SIZE) +#endif + /* Return count of locations need to be watched and can be handled in hardware. If the watchpoint can not be handled in hardware return zero. */ @@ -2846,7 +2868,7 @@ { if (v->lval == lval_memory) { - if (TYPE_LENGTH (VALUE_TYPE (v)) <= REGISTER_SIZE) + if (VALUE_FIT_IN_REG (v)) found_memory_cnt++; } else if (v->lval != not_lval && v->modifiable == 0) @@ -3412,6 +3434,11 @@ if (bpt->inserted) remove_breakpoint (bpt); +#ifdef NEED_WATCHPOINT_NUMBER + if (bpt->type == bp_hardware_watchpoint) + target_delete_watchpoint (bpt->number); +#endif + if (breakpoint_chain == bpt) breakpoint_chain = bpt->next; @@ -3675,6 +3702,7 @@ #ifdef GET_LONGJMP_TARGET create_longjmp_breakpoint ("longjmp"); create_longjmp_breakpoint ("_longjmp"); + create_longjmp_breakpoint ("__longjmp"); create_longjmp_breakpoint ("siglongjmp"); create_longjmp_breakpoint ("_siglongjmp"); create_longjmp_breakpoint (NULL); Index: gnu/gdb-4.17/gdb/c-exp.y diff -u gnu/gdb-4.17/gdb/c-exp.y:1.1.1.1 gnu/gdb-4.17/gdb/c-exp.y:1.3 --- gnu/gdb-4.17/gdb/c-exp.y:1.1.1.1 Fri May 29 06:57:32 1998 +++ gnu/gdb-4.17/gdb/c-exp.y Fri May 29 11:50:22 1998 @@ -997,6 +997,18 @@ break; } +#ifdef HEX_LONG_DOUBLE_INPUT + { + long double val; + if (HEX_LONG_DOUBLE_INPUT(base, p, len, &val)) + { + putithere->typed_val_float.dval = val; + putithere->typed_val_float.type = builtin_type_long_double; + return FLOAT; + } + } +#endif /* HEX_LONG_DOUBLE_INPUT */ + while (len-- > 0) { c = *p++; Index: gnu/gdb-4.17/gdb/config.in diff -u gnu/gdb-4.17/gdb/config.in:1.1.1.1 gnu/gdb-4.17/gdb/config.in:1.2 --- gnu/gdb-4.17/gdb/config.in:1.1.1.1 Fri May 29 06:57:33 1998 +++ gnu/gdb-4.17/gdb/config.in Fri May 29 07:03:30 1998 @@ -135,6 +135,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_PROCFS_H +/* Define if you have the header file. */ +#undef HAVE_SYS_REG_H + /* Define if you have the header file. */ #undef HAVE_TERMIO_H Index: gnu/gdb-4.17/gdb/configure diff -u gnu/gdb-4.17/gdb/configure:1.1.1.1 gnu/gdb-4.17/gdb/configure:1.2 --- gnu/gdb-4.17/gdb/configure:1.1.1.1 Fri May 29 06:57:33 1998 +++ gnu/gdb-4.17/gdb/configure Fri May 29 07:03:31 1998 @@ -1376,7 +1376,7 @@ fi -for ac_hdr in limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h stdlib.h sys/procfs.h link.h endian.h objlist.h +for ac_hdr in limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h stdlib.h sys/procfs.h link.h endian.h objlist.h sys/reg.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 Index: gnu/gdb-4.17/gdb/configure.host diff -u gnu/gdb-4.17/gdb/configure.host:1.1.1.1 gnu/gdb-4.17/gdb/configure.host:1.2 --- gnu/gdb-4.17/gdb/configure.host:1.1.1.1 Fri May 29 06:57:33 1998 +++ gnu/gdb-4.17/gdb/configure.host Sun Dec 20 11:25:27 1998 @@ -33,6 +33,7 @@ alpha*-*-osf1*) gdb_host=alpha-osf1 ;; alpha*-*-osf2*) gdb_host=alpha-osf2 ;; alpha*-*-osf[3456789]*) gdb_host=alpha-osf3 ;; +alpha*-*-linux*libc1) gdb_host=alpha-linuxlibc1 ;; alpha*-*-linux*) gdb_host=alpha-linux ;; arm-*-*) gdb_host=arm ;; @@ -54,6 +55,8 @@ i[3456]86-*-freebsd*) gdb_host=fbsd ;; i[3456]86-*-netbsd*) gdb_host=nbsd ;; i[3456]86-*-go32*) gdb_host=go32 ;; +i[3456]86-*-linux*libc1|i[3456]86-*-linux*libc5) + gdb_host=linuxlibc1 ;; i[3456]86-*-linux*) gdb_host=linux ;; i[3456]86-*-lynxos*) gdb_host=i386lynx ;; i[3456]86-*-mach3*) gdb_host=i386m3 ;; @@ -131,6 +134,7 @@ powerpc-*-aix*) gdb_host=aix ;; powerpcle-*-cygwin32) gdb_host=cygwin32 ;; powerpcle-*-solaris*) gdb_host=solaris ;; +powerpc-*-linux*libc1) gdb_host=linuxlibc1 ;; powerpc-*-linux*) gdb_host=linux ;; pn-*-*) gdb_host=pn ;; @@ -143,6 +147,8 @@ rs6000-*-aix4*) gdb_host=aix4 ;; rs6000-*-*) gdb_host=rs6000 ;; +sparc-*-linux*libc1|sparc-*-linux*libc5) + gdb_host=linuxlibc1 ;; sparc-*-linux*) gdb_host=linux ;; sparc-*-lynxos*) gdb_host=sparclynx ;; sparc-*-netbsd*) gdb_host=nbsd ;; Index: gnu/gdb-4.17/gdb/configure.in diff -u gnu/gdb-4.17/gdb/configure.in:1.1.1.1 gnu/gdb-4.17/gdb/configure.in:1.2 --- gnu/gdb-4.17/gdb/configure.in:1.1.1.1 Fri May 29 06:57:33 1998 +++ gnu/gdb-4.17/gdb/configure.in Fri May 29 07:03:32 1998 @@ -63,7 +63,7 @@ AC_TYPE_SIGNAL AC_HEADER_STDC -AC_CHECK_HEADERS(limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h stdlib.h sys/procfs.h link.h endian.h objlist.h) +AC_CHECK_HEADERS(limits.h memory.h string.h strings.h unistd.h termios.h termio.h sgtty.h stddef.h stdlib.h sys/procfs.h link.h endian.h objlist.h sys/reg.h) AC_HEADER_STAT AC_C_CONST Index: gnu/gdb-4.17/gdb/configure.tgt diff -u gnu/gdb-4.17/gdb/configure.tgt:1.1.1.1 gnu/gdb-4.17/gdb/configure.tgt:1.2 --- gnu/gdb-4.17/gdb/configure.tgt:1.1.1.1 Fri May 29 06:57:30 1998 +++ gnu/gdb-4.17/gdb/configure.tgt Tue Dec 1 21:52:01 1998 @@ -213,7 +213,8 @@ powerpc-*-aix*) gdb_target=aix ;; powerpcle-*-cygwin32) gdb_target=cygwin32 ;; powerpcle-*-solaris*) gdb_target=solaris ;; -powerpc-*-eabi* | powerpc-*-linux* | powerpc-*-sysv* | powerpc-*-elf*) +powerpc-*-linux*) gdb_target=linux ;; +powerpc-*-eabi* | powerpc-*-sysv* | powerpc-*-elf*) if test -f ../sim/ppc/Makefile; then gdb_target=ppc-sim else Index: gnu/gdb-4.17/gdb/corefile.c diff -u gnu/gdb-4.17/gdb/corefile.c:1.1.1.1 gnu/gdb-4.17/gdb/corefile.c:1.2 --- gnu/gdb-4.17/gdb/corefile.c:1.1.1.1 Fri May 29 06:57:33 1998 +++ gnu/gdb-4.17/gdb/corefile.c Sat Dec 19 18:21:08 1998 @@ -199,7 +199,6 @@ printf_filtered ("Cannot access memory at address "); print_address_numeric (memaddr, 1, gdb_stdout); printf_filtered (".\n"); - return_to_top_level (RETURN_ERROR); } else { @@ -208,8 +207,11 @@ print_address_numeric (memaddr, 1, gdb_stdout); printf_filtered (": %s.\n", safe_strerror (status)); - return_to_top_level (RETURN_ERROR); } + if (doing_quit_force) + doing_quit_force = -status; + else + return_to_top_level (RETURN_ERROR); } /* Same as target_read_memory, but report an error if can't read. */ Index: gnu/gdb-4.17/gdb/findvar.c diff -u gnu/gdb-4.17/gdb/findvar.c:1.1.1.1 gnu/gdb-4.17/gdb/findvar.c:1.3 --- gnu/gdb-4.17/gdb/findvar.c:1.1.1.1 Fri May 29 06:57:34 1998 +++ gnu/gdb-4.17/gdb/findvar.c Fri May 29 11:50:25 1998 @@ -312,7 +312,8 @@ else floatformat_to_doublest (TARGET_DOUBLE_FORMAT, addr, &dretval); } - else if (len == sizeof (DOUBLEST)) + else if (len == sizeof (DOUBLEST) + || len == (TARGET_LONG_DOUBLE_BIT / 8)) { if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) { @@ -360,7 +361,8 @@ else floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &val, addr); } - else if (len == sizeof (DOUBLEST)) + else if (len == sizeof (DOUBLEST) + || len == (TARGET_LONG_DOUBLE_BIT / 8)) { if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) memcpy (addr, &val, sizeof (val)); @@ -660,7 +662,7 @@ /* See if we are trying to read bytes from out-of-date registers. If so, update just those registers. */ - for (regno = 0; regno < NUM_REGS; regno++) + for (regno = 0; regno < ARCH_NUM_REGS; regno++) { int regstart, regend; int startin, endin; @@ -772,7 +774,7 @@ like handling threads, and avoiding updates when the new and old contents are the same. */ - for (regno = 0; regno < NUM_REGS; regno++) + for (regno = 0; regno < ARCH_NUM_REGS; regno++) { int regstart, regend; int startin, endin; Index: gnu/gdb-4.17/gdb/gdbcmd.h diff -u gnu/gdb-4.17/gdb/gdbcmd.h:1.1.1.1 gnu/gdb-4.17/gdb/gdbcmd.h:1.2 --- gnu/gdb-4.17/gdb/gdbcmd.h:1.1.1.1 Fri May 29 06:57:34 1998 +++ gnu/gdb-4.17/gdb/gdbcmd.h Sat Dec 19 18:21:08 1998 @@ -103,4 +103,6 @@ extern char **filename_completer PARAMS ((char *, char *)); +extern int doing_quit_force; + #endif /* !defined (GDBCMD_H) */ Index: gnu/gdb-4.17/gdb/i386-tdep.c diff -u gnu/gdb-4.17/gdb/i386-tdep.c:1.1.1.1 gnu/gdb-4.17/gdb/i386-tdep.c:1.6 --- gnu/gdb-4.17/gdb/i386-tdep.c:1.1.1.1 Fri May 29 06:57:34 1998 +++ gnu/gdb-4.17/gdb/i386-tdep.c Tue Feb 16 15:51:07 1999 @@ -28,6 +28,10 @@ #include "symtab.h" #include "gdbcmd.h" +#ifndef JB_PC +#define JB_PC 5 +#endif + static long i386_get_frame_setup PARAMS ((CORE_ADDR)); static void i386_follow_jump PARAMS ((void)); @@ -38,6 +42,10 @@ static unsigned char codestream_fill PARAMS ((int)); +static void i386_print_register PARAMS ((char *, int, int)); + +static void i386_print_status_word PARAMS ((char *, char *, long)); + /* Stdio style buffering was used to minimize calls to ptrace, but this buffering did not take into account that the code section being accessed may not be an even number of buffers long (even if the buffer is only @@ -411,7 +419,7 @@ { /* all regs were saved by push_call_dummy () */ adr = fip->frame; - for (i = 0; i < NUM_REGS; i++) + for (i = 0; i < ARCH_NUM_REGS; i++) { adr -= REGISTER_RAW_SIZE (i); fsrp->regs[i] = adr; @@ -538,7 +546,7 @@ sp = push_word (sp, read_register (PC_REGNUM)); sp = push_word (sp, read_register (FP_REGNUM)); write_register (FP_REGNUM, sp); - for (regnum = 0; regnum < NUM_REGS; regnum++) + for (regnum = 0; regnum < ARCH_NUM_REGS; regnum++) { read_register_gen (regnum, regbuf); sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum)); @@ -557,7 +565,7 @@ fp = FRAME_FP (frame); get_frame_saved_regs (frame, &fsr); - for (regnum = 0; regnum < NUM_REGS; regnum++) + for (regnum = 0; regnum < ARCH_NUM_REGS; regnum++) { CORE_ADDR adr; adr = fsr.regs[regnum]; @@ -575,6 +583,7 @@ } #ifdef GET_LONGJMP_TARGET +#include /* Figure out where the longjmp will land. Slurp the args out of the stack. We expect the first arg to be a pointer to the jmp_buf structure from which @@ -614,8 +623,9 @@ char regbuf[REGISTER_BYTES]; char *valbuf; { -/* On AIX, floating point values are returned in floating point registers. */ -#ifdef I386_AIX_TARGET + /* On AIX and Linux, floating point values are returned in floating + point registers. */ +#if defined(I386_AIX_TARGET) || defined(I386_LINUX_TARGET) if (TYPE_CODE_FLT == TYPE_CODE(type)) { double d; @@ -626,7 +636,7 @@ store_floating (valbuf, TYPE_LENGTH (type), d); } else -#endif /* I386_AIX_TARGET */ +#endif /* I386_AIX_TARGET || I386_LINUX_TARGET*/ { memcpy (valbuf, regbuf, TYPE_LENGTH (type)); } @@ -712,10 +722,174 @@ return 0; /* not a trampoline */ } +#ifdef CHILD_RESUME +#include +#ifndef PT_CONTINUE +#define PT_CONTINUE PTRACE_CONT +#endif +#ifndef PT_STEP +#define PT_STEP PTRACE_SINGLESTEP +#endif +#ifndef PT_SYSCALL +#define PT_SYSCALL PTRACE_SYSCALL +#endif + void +child_resume(pid, step, signal) + int pid; + int step; + enum target_signal signal; +{ + int request; + unsigned char code; + CORE_ADDR pc; + int i; + + errno = 0; + + if (pid == -1) + /* Resume all threads. */ + /* I think this only gets used in the non-threaded case, where "resume + all threads" and "resume inferior_pid" are the same. */ + pid = inferior_pid; + + if (!step) + request = PT_CONTINUE; + else + { + pc = read_pc_pid (pid); + for (i = 0; i < SYSCALL_TRAP_SIZE; i++) + if (read_memory_nobpt(pc + i, (char *) &code, 1) != 0 + || code != ((SYSCALL_TRAP >> ((SYSCALL_TRAP_SIZE - 1 - i) * 8)) + & 0xFF)) + break; + + if (i < SYSCALL_TRAP_SIZE) + request = PT_STEP; + else if (!IN_SIGTRAMP (pc, (char *)NULL)) + { + /* Single-step over the syscall in order to avoid being blocked + inside the kernel waiting for the thread to be unblocked. */ + request = PT_SYSCALL; + } + else + { + /* Put TF in the eflags from the frame set up by the signal handler */ + unsigned long eflags; + CORE_ADDR addr = read_sp () + SIGCONTEXT_EFLAGS_OFFSET; + if (target_read_memory (addr, (char *) &eflags, 4) == 0) + { + eflags |= 0x100; /* Trap Flag */ + write_memory (addr, (char *) &eflags, 4); + } + request = PT_STEP; + } + } + call_ptrace (request, pid, (PTRACE_ARG3_TYPE) 0, + target_signal_to_host (signal)); + + if (errno) + perror_with_name ("ptrace"); +} +#endif + +void _initialize_i386_tdep () { tm_print_insn = print_insn_i386; tm_print_insn_info.mach = bfd_lookup_arch (bfd_arch_i386, 0)->mach; +} + +/* Print the register regnum, or all registers if regnum is -1 */ + +void +i386_do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + char raw_regs [REGISTER_BYTES]; + int numregs = RUNTIME_NUM_REGS (fpregs); + int i; + + for (i = 0; i < numregs; i++) + read_relative_register_raw_bytes (INFO_REGMAP (i), + raw_regs + REGISTER_BYTE (INFO_REGMAP (i))); + + i386_print_register (raw_regs, regnum, NUM_REGS - NUM_FREGS); + + if ((regnum == -1) && fpregs) + for (i = NUM_REGS - NUM_FREGS; i < numregs; i++) + i387_print_register (raw_regs, INFO_REGMAP (i)); +} + +static void +i386_print_status_word (regname, string, status) + char *regname; + char *string; + long status; +{ + printf_filtered ("%8.8s: %10.10s IOPL: %d; flags:", regname, string, + (status >> 12) & 0x3); + if (status & 0x1) + printf_unfiltered (" CF"); + if (status & 0x4) + printf_unfiltered (" PF"); + if (status & 0x10) + printf_unfiltered (" AF"); + if (status & 0x40) + printf_unfiltered (" ZF"); + if (status & 0x80) + printf_unfiltered (" SF"); + if (status & 0x100) + printf_unfiltered (" TF"); + if (status & 0x200) + printf_unfiltered (" IF"); + if (status & 0x400) + printf_unfiltered (" DF"); + if (status & 0x800) + printf_unfiltered (" OF"); + if (status & 0x4000) + printf_unfiltered (" NT"); + if (status & 0x10000) + printf_unfiltered (" RF"); + if (status & 0x20000) + printf_unfiltered (" VM"); + if (status & 0x40000) + printf_unfiltered (" AC"); + if (status & 0x80000) + printf_unfiltered (" VIF"); + if (status & 0x100000) + printf_unfiltered (" VIP"); + if (status & 0x200000) + printf_unfiltered (" ID"); + printf_unfiltered ("\n"); +} + +static void +i386_print_register (raw_regs, regnum, numregs) + char *raw_regs; + int regnum; + int numregs; +{ + int i, j; + long val; + char string[24]; + + for (i = 0; i < numregs; i++) + { + j = INFO_REGMAP (i); + + if ((regnum != -1) && (j != regnum)) + continue; + + val = extract_signed_integer (raw_regs + REGISTER_BYTE (j), 4); + + sprintf(string, "0x%x", val); + if (j == PS_REGNUM) + i386_print_status_word (reg_names[j], string, val); + else + printf_filtered ("%8.8s: %10.10s %11d\n", reg_names[j], + string, val); + } } Index: gnu/gdb-4.17/gdb/i386lnx-nat.c diff -u /dev/null gnu/gdb-4.17/gdb/i386lnx-nat.c:1.9 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/i386lnx-nat.c Wed May 5 16:32:59 1999 @@ -0,0 +1,997 @@ +/* Intel 386 native support for Linux + Copyright (C) 1999 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 "inferior.h" +#include "target.h" +#include "gdb_string.h" + +#include +#include +#include + +#include "gdbcore.h" + +#ifdef HAVE_SYS_REG_H +#include +#endif + +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include +#if defined LINUX_VERSION_CODE && LINUX_VERSION_CODE >= 131441 +#include +#else +#include +#endif +#endif +#endif + +#if !defined (PT_READ_I) +#define PT_READ_I 1 /* Read word from text space */ +#endif +#if !defined (PT_READ_D) +#define PT_READ_D 2 /* Read word from data space */ +#endif +#if !defined (PT_READ_U) +#define PT_READ_U 3 /* Read word from kernel user struct */ +#endif +#if !defined (PT_WRITE_I) +#define PT_WRITE_I 4 /* Write word to text space */ +#endif +#if !defined (PT_WRITE_D) +#define PT_WRITE_D 5 /* Write word to data space */ +#endif +#if !defined (PT_WRITE_U) +#define PT_WRITE_U 6 /* Write word to kernel user struct */ +#endif +#if !defined (PT_CONTINUE) +#define PT_CONTINUE 7 /* Continue after signal */ +#endif +#if !defined (PT_STEP) +#define PT_STEP 9 /* Set flag for single stepping */ +#endif +#if !defined (PT_KILL) +#define PT_KILL 8 /* Send child a SIGKILL signal */ +#endif + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_DETACH +#define PT_DETACH PTRACE_DETACH +#endif + +#if !defined(PT_GETREGS) && defined(PTRACE_GETREGS) +#define PT_GETREGS PTRACE_GETREGS +#endif +#if !defined(PT_SETREGS) && defined(PTRACE_SETREGS) +#define PT_SETREGS PTRACE_SETREGS +#endif +#if !defined(PT_GETFPREGS) && defined(PTRACE_GETFPREGS) +#define PT_GETFPREGS PTRACE_GETFPREGS +#endif +#if !defined(PT_SETFPREGS) && defined(PTRACE_SETFPREGS) +#define PT_SETFPREGS PTRACE_SETFPREGS +#endif + +static void fetch_register PARAMS ((int)); +static void store_register PARAMS ((int)); + +static void old_fetch_inferior_registers PARAMS ((int)); +static void old_store_inferior_registers PARAMS ((int)); + +#ifdef PT_GETREGS +static void new_fetch_inferior_registers PARAMS ((int)); +static void new_store_inferior_registers PARAMS ((int)); +static void init_fetch_inferior_registers PARAMS ((int)); +static void init_store_inferior_registers PARAMS ((int)); + +static void (*fetch_inferior_registers_p) PARAMS ((int)) + = init_fetch_inferior_registers; +static void (*store_inferior_registers_p) PARAMS ((int)) + = init_store_inferior_registers; + +static void set_inferior_registers_p PARAMS ((void)); +#else +static void (*fetch_inferior_registers_p) PARAMS ((int)) + = old_fetch_inferior_registers; +static void (*store_inferior_registers_p) PARAMS ((int)) + = old_store_inferior_registers; +#endif + +/* Default the type of the ptrace transfer to int. */ +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif + +#ifndef PTRACE_ARG4_TYPE +#define PTRACE_ARG4_TYPE int +#endif + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +/* symbols like 'EAX' come from or . */ +#ifndef ORIG_EAX +#define ORIG_EAX 11 +#endif + +#ifndef ST0 +#define ST0 7 +#endif + +#ifndef ST1 +#define ST1 8 +#endif + +#ifndef ST2 +#define ST2 9 +#endif + +#ifndef ST3 +#define ST3 10 +#endif + +#ifndef ST4 +#define ST4 11 +#endif + +#ifndef ST5 +#define ST5 12 +#endif + +#ifndef ST6 +#define ST6 13 +#endif + +#ifndef ST7 +#define ST7 14 +#endif + +#ifndef CWD +#define CWD 0 +#endif + +#ifndef SWD +#define SWD 1 +#endif + +#ifndef TWD +#define TWD 2 +#endif + +#ifndef FIP +#define FIP 3 +#endif + +#ifndef FCS +#define FCS 4 +#endif + +#ifndef FOO +#define FOO 5 +#endif + +#ifndef FOS +#define FOS 6 +#endif + +/* Used for register mapping in system calls. */ +static int syscall_regmap [] = +{ + EAX, + ECX, + EDX, + EBX, + UESP, + EBP, + ESI, + EDI, + EIP, + EFL, + ORIG_EAX, + ST0, + ST1, + ST2, + ST3, + ST4, + ST5, + ST6, + ST7, + CWD, + SWD, + TWD, + FIP, + FCS, + FOO, + FOS, + CS, + SS, + DS, + ES, + FS, + GS, +}; + +/* Used for register infomation mapping. */ +int info_regmap [] = +{ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 26, + 27, + 28, + 29, + 30, + 31, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 +}; + +/* Fetch one register. */ +static void +fetch_register (regno) + int regno; +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + CORE_ADDR regaddr; + char mess[128]; /* For messages */ + register int i; + unsigned int offset; /* Offset of registers within the u area. */ + char buf[MAX_REGISTER_RAW_SIZE]; + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) &buf[i] = ptrace (PT_READ_U, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + + +/* Fetch register values from the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +static void +old_fetch_inferior_registers (regno) + int regno; +{ + if (regno >= 0) + { + if (GREGISTER (regno)) + fetch_register (regno); + else + supply_register (regno, ®isters[REGISTER_BYTE (regno)]); + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + if (GREGISTER (regno)) + fetch_register (regno); + else + supply_register (regno, ®isters[REGISTER_BYTE (regno)]); + } + } +} + +/* Store one register. */ + +static void +store_register (regno) + int regno; +{ + /* This isn't really an address. But ptrace thinks of it as one. */ + CORE_ADDR regaddr; + char mess[128]; /* For messages */ + register int i; + unsigned int offset; /* Offset of registers within the u area. */ + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(PTRACE_XFER_TYPE)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(PTRACE_XFER_TYPE *) ®isters[REGISTER_BYTE (regno) + i]); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + { + sprintf (mess, "writing register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } +} + +/* Store our register values back into the inferior. + If REGNO is negative, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +static void +old_store_inferior_registers (regno) + int regno; +{ + if (regno >= 0) + { + if (GREGISTER (regno)) + store_register (regno); + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + if (GREGISTER (regno)) + store_register (regno); + } + } +} + +#ifdef PT_GETREGS +static void +new_fetch_inferior_registers(regno) + int regno; +{ + char inferior_gregisters [GREGISTER_BYTES]; + char inferior_fpregisters [FPREGISTER_BYTES]; + int i; + + ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) 0, + (PTRACE_ARG4_TYPE) &inferior_gregisters [0]); + ptrace (PT_GETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) 0, + (PTRACE_ARG4_TYPE) &inferior_fpregisters [0]); + for (i = 0; i < NUM_REGS; i++) + if (GREGISTER (i)) + memcpy (®isters[REGISTER_BYTE (i)], + &inferior_gregisters [GREGISTER_BYTE (syscall_regmap [i])], + REGISTER_RAW_SIZE (i)); + else + memcpy (®isters[REGISTER_BYTE (i)], + &inferior_fpregisters [FPREGISTER_BYTE (syscall_regmap [i])], + REGISTER_RAW_SIZE (i)); + registers_fetched (); +} + +static void +new_store_inferior_registers(regno) + int regno; +{ + char inferior_gregisters [GREGISTER_BYTES]; + char inferior_fpregisters [FPREGISTER_BYTES]; + int i; + + for (i = 0; i < NUM_REGS; i++) + if (GREGISTER (i)) + memcpy (&inferior_gregisters [GREGISTER_BYTE (syscall_regmap [i])], + ®isters[REGISTER_BYTE (i)], + REGISTER_RAW_SIZE (i)); + else + memcpy (&inferior_fpregisters [FPREGISTER_BYTE (syscall_regmap [i])], + ®isters[REGISTER_BYTE (i)], + REGISTER_RAW_SIZE (i)); + ptrace (PT_SETREGS, inferior_pid, (PTRACE_ARG3_TYPE) 0, + (PTRACE_ARG4_TYPE) &inferior_gregisters [0]); + ptrace (PT_SETFPREGS, inferior_pid, (PTRACE_ARG3_TYPE) 0, + (PTRACE_ARG4_TYPE) &inferior_fpregisters [0]); +} + +static void +set_inferior_registers_p () +{ + char inferior_registers [GREGISTER_BYTES]; + + if (ptrace (PT_GETREGS, inferior_pid, (PTRACE_ARG3_TYPE) 0, + (PTRACE_ARG4_TYPE) &inferior_registers) < 0) + { + if (errno == EIO) + { + fetch_inferior_registers_p = old_fetch_inferior_registers; + store_inferior_registers_p = old_store_inferior_registers; + } + } + else + { + fetch_inferior_registers_p = new_fetch_inferior_registers; + store_inferior_registers_p = new_store_inferior_registers; + } +} + +void +init_fetch_inferior_registers (regno) + int regno; +{ + set_inferior_registers_p (); + (*fetch_inferior_registers_p) (regno); +} + +void +init_store_inferior_registers (regno) + int regno; +{ + set_inferior_registers_p (); + (*store_inferior_registers_p) (regno); +} +#endif + +void +fetch_inferior_registers(regno) +{ + (*fetch_inferior_registers_p) (regno); +} + +void +store_inferior_registers(regno) +{ + (*store_inferior_registers_p) (regno); +} + +int +get_runtime_num_regs (int fpregs) +{ +#ifdef PT_GETREGS + if (fetch_inferior_registers_p == init_fetch_inferior_registers) + set_inferior_registers_p (); + if (!fpregs + || fetch_inferior_registers_p == old_fetch_inferior_registers) + return NUM_REGS - NUM_FREGS; + else + return NUM_REGS; +#else + return NUM_REGS - NUM_FREGS; +#endif +} + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ + +int +i386_register_u_addr (blockend, regnum) + int blockend; + int regnum; +{ + return GREGISTER (regnum) + ? (blockend + GREGISTER_BYTE (syscall_regmap [regnum])) : -1; +} + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +#ifdef TARGET_HAS_HARDWARE_WATCHPOINTS + +/* Record the value of the debug control register. */ +static int debug_control_mirror; + +static struct +{ + /* Record which address associates with which register. */ + CORE_ADDR address; + /* Number assigned to distinguish watchpoints. */ + int number; +} address_lookup [DR_LASTADDR - DR_FIRSTADDR + 1]; + +static int +i386_insert_aligned_watchpoint PARAMS ((int, int, CORE_ADDR, CORE_ADDR, + int, int)); + +static int +i386_insert_nonaligned_watchpoint PARAMS ((int, int, CORE_ADDR, + CORE_ADDR, int, int)); + +/* Insert a watchpoint. */ + +int +i386_insert_watchpoint (pid, num, addr, len, rw) + int pid; + int num; + CORE_ADDR addr; + int len; + int rw; +{ + return i386_insert_aligned_watchpoint (pid, num, addr, addr, len, rw); +} + +static int +i386_insert_aligned_watchpoint (pid, num, waddr, addr, len, rw) + int pid; + int num; + CORE_ADDR waddr; + CORE_ADDR addr; + int len; + int rw; +{ + int i; + int read_write_bits, len_bits; + int free_debug_register; + int register_number; + + switch (len) + { + case 1: case 2: case 4: case 8: case 10: case 12: + break; + + default: + /* This is a kludge. x86 only has limited number of hardware + waitpoint registers. If LEN is too big, we will check + + 1. If we have seen the same watch point number in + address_lookup, we just return 0 to save the hardware + waitpoint registers for others. We fake it to make gdb + happy. + 2. Otherwise, return -1. + */ + for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR + 1; i++) + if (address_lookup[i].number == num + && address_lookup[i].address != 0) + return 0; + + return -1; + break; + } + + /* Look for a free debug register. */ + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + if (address_lookup[i - DR_FIRSTADDR].address == 0 + || address_lookup[i - DR_FIRSTADDR].address == addr) + break; + } + + /* No more debug registers! */ + if (i > DR_LASTADDR) + return -1; + + read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE; + + if (len == 1) + len_bits = DR_LEN_1; + else if (len == 2) + { + if (addr % 2) + return i386_insert_nonaligned_watchpoint (pid, num, waddr, + addr, len, rw); + len_bits = DR_LEN_2; + } + + else if (len == 4) + { + if (addr % 4) + return i386_insert_nonaligned_watchpoint (pid, num, waddr, + addr, len, rw); + len_bits = DR_LEN_4; + } + else if (len == 8 || len == 10 || len == 12) + { + /* It should only happen with long long, double or long double. + All should be updated at the same time. We just watch the + first 4 bytes. */ + len = 4; + if (addr % 4) + return i386_insert_nonaligned_watchpoint (pid, num, waddr, + addr, len, rw); + len_bits = DR_LEN_4; + } + else + return i386_insert_nonaligned_watchpoint (pid, num, waddr, addr, + len, rw); + + free_debug_register = i; + register_number = free_debug_register - DR_FIRSTADDR; + debug_control_mirror |= + ((read_write_bits | len_bits) + << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number)); + debug_control_mirror |= + (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); + debug_control_mirror |= DR_LOCAL_SLOWDOWN; + debug_control_mirror &= ~DR_CONTROL_RESERVED; + + ptrace (PT_WRITE_U, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), + debug_control_mirror); + ptrace (PT_WRITE_U, pid, offsetof (struct user, u_debugreg[free_debug_register]), + addr); + + /* Record where we came from. */ + address_lookup[register_number].address = addr; + address_lookup[register_number].number = num; + return 0; +} + +static int +i386_insert_nonaligned_watchpoint (pid, num, waddr, addr, len, rw) + int pid; + int num; + CORE_ADDR waddr; + CORE_ADDR addr; + int len; + int rw; +{ + int align; + int size; + int rv; + + static int size_try_array[16] = { + 1, 1, 1, 1, /* trying size one */ + 2, 1, 2, 1, /* trying size two */ + 2, 1, 2, 1, /* trying size three */ + 4, 1, 2, 1 /* trying size four */ + }; + + rv = 0; + while (len > 0) + { + align = addr % 4; + /* Four is the maximum length for 386. */ + size = (len > 4) ? 3 : len - 1; + size = size_try_array[size * 4 + align]; + + rv = i386_insert_aligned_watchpoint (pid, num, waddr, addr, + size, rw); + if (rv) + { + i386_remove_watchpoint (pid, num, waddr, size); + return rv; + } + addr += size; + len -= size; + } + return rv; +} + +/* Remove a watchpoint. */ + +int +i386_remove_watchpoint (pid, num, addr, len) + int pid; + int num; + CORE_ADDR addr; + int len; +{ + int i; + int register_number; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + register_number = i - DR_FIRSTADDR; + if (address_lookup[register_number].address == addr) + { + debug_control_mirror &= + ~(1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number)); + address_lookup[register_number].address = 0; + address_lookup[register_number].number = 0; + } + } + ptrace (PT_WRITE_U, pid, offsetof (struct user, u_debugreg[DR_CONTROL]), + debug_control_mirror); + ptrace (PT_WRITE_U, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + + return 0; +} + +/* Delete a watchpoint. */ + +int +i386_delete_watchpoint (pid, num) + int pid; + int num; +{ + int i; + int retval = -1; + + for (i = 0; i < DR_LASTADDR - DR_FIRSTADDR + 1; i++) + if (address_lookup[i].number == num + && address_lookup[i].address != 0) + { + i386_remove_watchpoint (pid, num, address_lookup[i].address, 0); + retval = 0; + } + + return retval; +} + +/* Check if stopped by a watchpoint. */ + +CORE_ADDR +i386_stopped_by_watchpoint (pid) + int pid; +{ + int i; + int status; + + status = ptrace (PT_READ_U, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + ptrace (PT_WRITE_U, pid, offsetof (struct user, u_debugreg[DR_STATUS]), 0); + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + { + if (status & (1 << (i - DR_FIRSTADDR))) + return address_lookup[i - DR_FIRSTADDR].address; + } + + return 0; +} + +#endif /* TARGET_HAS_HARDWARE_WATCHPOINTS */ + +#ifdef HAVE_SYS_PROCFS_H + +#include + +#ifdef HAVE_GREGSET_T + +/* Given a pointer to a general register set in /proc format (gregset_t *), + unpack the register contents and supply them as gdb's idea of the current + register values. */ + +void +supply_gregset (gregsetp) + gregset_t *gregsetp; +{ + char *g = (char *) gregsetp; + int i; + + for (i = 0; i < NUM_REGS; i++) + if (GREGISTER (i)) + *(greg_t *) ®isters[REGISTER_BYTE (i)] + = *(greg_t *) &g [GREGISTER_BYTE (syscall_regmap [i])]; +} + +void +fill_gregset (gregsetp, regno) + gregset_t *gregsetp; + int regno; +{ + char *g = (char *) gregsetp; + + if (regno == -1) + { + int i; + for (i = 0; i < NUM_REGS; i++) + if (GREGISTER (i)) + *(greg_t *) &g [GREGISTER_BYTE (syscall_regmap [i])] + = *(greg_t *) ®isters[REGISTER_BYTE (i)]; + } + else + { + *(greg_t *) &g [GREGISTER_BYTE (syscall_regmap [regno])] + = *(greg_t *) ®isters[REGISTER_BYTE (regno)]; + } +} + +#endif /* HAVE_GREGSET_T */ + +#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), unpack the register contents and supply them as gdb's + idea of the current floating point register values. */ + +void +supply_fpregset (fpregsetp) + fpregset_t *fpregsetp; +{ + char *fp = (char *) fpregsetp; + int i; + + for (i = 0; i < NUM_REGS; i++) + if (!GREGISTER (i)) + memcpy (®isters[REGISTER_BYTE (i)], + &fp [FPREGISTER_BYTE (syscall_regmap [i])], + REGISTER_RAW_SIZE (i)); +} + +/* Given a pointer to a floating point register set in /proc format + (fpregset_t *), update the register specified by REGNO from gdb's idea + of the current floating point register set. If REGNO is -1, update + them all. */ + +void +fill_fpregset (fpregsetp, regno) + fpregset_t *fpregsetp; + int regno; +{ + char *fp = (char *) fpregsetp; + + if (regno == -1) + { + int i; + + for (i = 0; i < NUM_REGS; i++) + if (!GREGISTER (i)) + memcpy (&fp [FPREGISTER_BYTE (syscall_regmap [i])], + ®isters[REGISTER_BYTE (i)], + REGISTER_RAW_SIZE (i)); + } + else + { + memcpy (&fp [FPREGISTER_BYTE (syscall_regmap [regno])], + ®isters[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE (regno)); + } +} + +#endif /* defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) */ + +static void +fetch_core_registers (core_reg_sect, core_reg_size, which, ignored) + char *core_reg_sect; + unsigned core_reg_size; + int which; + CORE_ADDR ignored; +{ + if (core_reg_size == GREGISTER_BYTES) + supply_gregset (core_reg_sect); +#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) + else if (core_reg_size == FPREGISTER_BYTES) + supply_fpregset (core_reg_sect); +#endif + else + fprintf_unfiltered (gdb_stderr, "Unknown core size: %d", + core_reg_size); +} + +static struct core_fns elf_core_fns = +{ + bfd_target_elf_flavour, + fetch_core_registers, + NULL +}; + +void +_initialize_i386linux_nat () +{ + add_core_fns (&elf_core_fns); +} + +#endif /* HAVE_SYS_PROCFS_H */ + +#ifdef SIGCONTEXT_ADDR + +/* i386_frame_chain() takes a frame's nominal address and produces the frame's + chain-pointer. In the case of the i386, the frame's nominal address is + the address of a 4-byte word containing the calling frame's address. */ + +CORE_ADDR +i386_frame_chain (frame) + struct frame_info *frame; +{ + char buf[4]; + + if (frame->signal_handler_caller) + return frame->frame; + + if (!inside_entry_file (frame->pc) && + target_read_memory (frame->frame, buf, 4) == 0) + return extract_address (buf, 4); + + return 0; +} + +/* Under Linux, signal handler invocations can be identified by the + designated code sequence that is used to return from a signal + handler. In particular, the return address of a signal handler + points to the following sequence: + + 0x58 popl %eax + 0xb877000000 movl $0x77,%eax + 0xcd80 int $0x80 + + Each instruction has a unique encoding, so we simply attempt to + match the instruction the pc is pointing to with any of the above + instructions. If there is a hit, we know the offset to the start + of the designated sequence and can then check whether we really are + executing in a designated sequence. If not, -1 is returned, + otherwise the offset from the start of the desingated sequence is + returned. + + There is a slight chance of false hits: code could jump into the + middle of the designated sequence, in which case there is no + guarantee that we are in the middle of a sigreturn syscall. Don't + think this will be a problem in praxis, though. +*/ +int +i386_linux_sigtramp_offset (pc) + CORE_ADDR pc; +{ + unsigned char code[8]; + unsigned char sigtramp[] = { 0x58, 0xb8, 0x77, 0x00, 0x00, 0x00, 0xcd, 0x80 }; + int off, i; + + if (read_memory_nobpt(pc, (char *) code, 1) != 0) + return -1; + + switch (code[0]) + { + case 0x58: off = 0; break; /* popl %eax */ + case 0xb8: off = 1; break; /* movl $0x77,%eax */ + case 0xcd: off = 6; break; /* int $0x80 */ + default: return -1; + } + pc -= off; + + for (i = 0; i < sizeof (code); i++) + if (read_memory_nobpt(pc + i, (char *) &code[i], 1) != 0) + return -1; + + return memcmp (sigtramp, code, sizeof (code)) == 0 ? off : -1; +} + +/* Get saved user PC for sigtramp from sigcontext for Linux style sigtramp. */ + +CORE_ADDR +i386_linux_sigtramp_saved_pc (frame) + struct frame_info *frame; +{ + char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT]; + int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT; + + /* Don't cause a memory_error when accessing sigcontext in case the stack + layout has changed or the stack is corrupt. */ + target_read_memory (SIGCONTEXT_ADDR (frame) + SIGCONTEXT_PC_OFFSET, + buf, ptrbytes); + return extract_unsigned_integer (buf, ptrbytes); +} + +#endif /* SIGCONTEXT_ADDR */ Index: gnu/gdb-4.17/gdb/i387-tdep.c diff -u gnu/gdb-4.17/gdb/i387-tdep.c:1.1.1.1 gnu/gdb-4.17/gdb/i387-tdep.c:1.5 --- gnu/gdb-4.17/gdb/i387-tdep.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/i387-tdep.c Sun Jan 24 18:48:01 1999 @@ -1,5 +1,5 @@ /* Intel 387 floating point stuff. - Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + Copyright (C) 1988, 1989, 1991-98 Free Software Foundation, Inc. This file is part of GDB. @@ -43,65 +43,260 @@ floatformat_from_double (&floatformat_i387_ext, (double *)from, to); } -void -print_387_control_word (control) +static void +print_387_control_bits (control) unsigned int control; { - printf_unfiltered ("control %s: ", local_hex_string(control)); - printf_unfiltered ("compute to "); switch ((control >> 8) & 3) { - case 0: printf_unfiltered ("24 bits; "); break; - case 1: printf_unfiltered ("(bad); "); break; - case 2: printf_unfiltered ("53 bits; "); break; - case 3: printf_unfiltered ("64 bits; "); break; + case 0: puts_unfiltered (" 24 bit; "); break; + case 1: puts_unfiltered (" (bad); "); break; + case 2: puts_unfiltered (" 53 bit; "); break; + case 3: puts_unfiltered (" 64 bit; "); break; } - printf_unfiltered ("round "); switch ((control >> 10) & 3) { - case 0: printf_unfiltered ("NEAREST; "); break; - case 1: printf_unfiltered ("DOWN; "); break; - case 2: printf_unfiltered ("UP; "); break; - case 3: printf_unfiltered ("CHOP; "); break; + case 0: puts_unfiltered ("NEAR; "); break; + case 1: puts_unfiltered ("DOWN; "); break; + case 2: puts_unfiltered ("UP; "); break; + case 3: puts_unfiltered ("CHOP; "); break; } if (control & 0x3f) { - printf_unfiltered ("mask:"); - if (control & 0x0001) printf_unfiltered (" INVALID"); - if (control & 0x0002) printf_unfiltered (" DENORM"); - if (control & 0x0004) printf_unfiltered (" DIVZ"); - if (control & 0x0008) printf_unfiltered (" OVERF"); - if (control & 0x0010) printf_unfiltered (" UNDERF"); - if (control & 0x0020) printf_unfiltered (" LOS"); - printf_unfiltered (";"); + puts_unfiltered ("mask"); + if (control & 0x0001) puts_unfiltered (" INVAL"); + if (control & 0x0002) puts_unfiltered (" DENOR"); + if (control & 0x0004) puts_unfiltered (" DIVZ"); + if (control & 0x0008) puts_unfiltered (" OVERF"); + if (control & 0x0010) puts_unfiltered (" UNDER"); + if (control & 0x0020) puts_unfiltered (" LOS"); + puts_unfiltered (";"); } - printf_unfiltered ("\n"); - if (control & 0xe080) warning ("reserved bits on: %s\n", + if (control & 0xe080) warning ("\nreserved bits on: %s", local_hex_string(control & 0xe080)); } void -print_387_status_word (status) +print_387_control_word (control) + unsigned int control; +{ + printf_filtered ("control %s:", local_hex_string(control & 0xffff)); + print_387_control_bits (control); + puts_unfiltered ("\n"); +} + +static void +print_387_status_bits (status) unsigned int status; { - printf_unfiltered ("status %s: ", local_hex_string (status)); - if (status & 0xff) - { - printf_unfiltered ("exceptions:"); - if (status & 0x0001) printf_unfiltered (" INVALID"); - if (status & 0x0002) printf_unfiltered (" DENORM"); - if (status & 0x0004) printf_unfiltered (" DIVZ"); - if (status & 0x0008) printf_unfiltered (" OVERF"); - if (status & 0x0010) printf_unfiltered (" UNDERF"); - if (status & 0x0020) printf_unfiltered (" LOS"); - if (status & 0x0040) printf_unfiltered (" FPSTACK"); - printf_unfiltered ("; "); - } - printf_unfiltered ("flags: %d%d%d%d; ", + printf_unfiltered (" flags %d%d%d%d; ", (status & 0x4000) != 0, (status & 0x0400) != 0, (status & 0x0200) != 0, (status & 0x0100) != 0); + printf_unfiltered ("top %d; ", (status >> 11) & 7); + if (status & 0xff) + { + puts_unfiltered ("excep"); + if (status & 0x0001) puts_unfiltered (" INVAL"); + if (status & 0x0002) puts_unfiltered (" DENOR"); + if (status & 0x0004) puts_unfiltered (" DIVZ"); + if (status & 0x0008) puts_unfiltered (" OVERF"); + if (status & 0x0010) puts_unfiltered (" UNDER"); + if (status & 0x0020) puts_unfiltered (" LOS"); + if (status & 0x0040) puts_unfiltered (" STACK"); + } +} - printf_unfiltered ("top %d\n", (status >> 11) & 7); +void +print_387_status_word (status) + unsigned int status; +{ + printf_filtered ("status %s:", local_hex_string (status & 0xffff)); + print_387_status_bits (status); + puts_unfiltered ("\n"); +} + + +void +i387_print_register (raw_regs, regnum) + char *raw_regs; + int regnum; +{ + unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + unsigned long val; + int j, sign; + unsigned swd, tags, expon, top, norm, ls, ms; + char string[12]; + + printf_filtered ("%8.8s: ", reg_names[regnum]); + if (REGISTER_RAW_SIZE (regnum) == 4) + { + val = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum), 4); + switch (regnum) + { + case FPCWD_REGNUM: +#if FPSWD_REGNUM != -1 + case FPSWD_REGNUM: +#endif +#if FPTWD_REGNUM != -1 + case FPTWD_REGNUM: +#endif +#if FPOPS_REGNUM != -1 + case FPOPS_REGNUM: +#endif + /* Don't print the un-modifiable bytes. */ + sprintf(string, "0x%04x", val & 0xffff); + break; + + default: + sprintf(string, "0x%08x", val); + break; + } + + printf_unfiltered ("%10.10s", string); + + if ( regnum == FPCWD_REGNUM) + print_387_control_bits (val); + else if ( regnum == FPSWD_REGNUM) + print_387_status_bits (val); + } + else + { + /* Put the data in the buffer. No conversions are ever necessary. */ + memcpy (virtual_buffer, raw_regs + REGISTER_BYTE (regnum), 10); + + swd = extract_signed_integer (raw_regs + REGISTER_BYTE (FPSWD_REGNUM), + 4); + top = (swd >> 11) & 7; + tags = extract_signed_integer (raw_regs + REGISTER_BYTE (FPTWD_REGNUM), + 4); + + puts_unfiltered ("0x"); + for (j = 0; j < 10; j++) + printf_unfiltered ("%02x", + (unsigned char)raw_regs[REGISTER_BYTE (regnum) + + 9 - j]); + + puts_unfiltered (" "); + switch ((tags >> (((regnum - FP0_REGNUM + top) & 7) * 2)) & 3) + { + case 0: puts_unfiltered ("Valid "); break; + case 1: puts_unfiltered ("Zero "); break; + case 2: puts_unfiltered ("Spec "); break; + case 3: puts_unfiltered ("Empty "); break; + } + + expon = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum) + + 8, 2); + sign = expon & 0x8000; + expon &= 0x7fff; + ms = extract_unsigned_integer (raw_regs + REGISTER_BYTE (regnum) + 4, 4); + ls = extract_signed_integer (raw_regs + REGISTER_BYTE (regnum), 4); + norm = ms & 0x80000000; + + if ( expon == 0 ) + { + if ( ms | ls ) + { + /* Denormal or Pseudodenormal. */ + if ( norm ) + puts_unfiltered ("Pseudo "); + else + puts_unfiltered ("Denorm "); + } + else + { + /* Zero. */ + puts_unfiltered ("Zero "); + } + } + else if ( expon == 0x7fff ) + { + /* Infinity, NaN or unsupported. */ + if ( (ms == 0x80000000) && + (ls == 0) ) + { + puts_unfiltered ("Infty "); + } + else if ( norm ) + { + if ( ms & 0x40000000 ) + puts_unfiltered ("QNaN "); + else + puts_unfiltered ("SNaN "); + } + else + { + puts_unfiltered ("Unsupp "); + } + } + else + { + /* Normal or unsupported. */ + if ( norm ) + puts_unfiltered ("Normal "); + else + puts_unfiltered ("Unsupp "); + } + + val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0, + gdb_stdout, 0, + 1, 0, Val_pretty_default); + } + puts_filtered ("\n"); +} + +void +i387_float_info () +{ + char raw_regs [REGISTER_BYTES]; + int numregs = RUNTIME_NUM_REGS (1); + int i; + + if (numregs != NUM_REGS) + { + printf_filtered ("No floating point info available for this run-time environment.\n"); + return; + } + + for (i = NUM_REGS - NUM_FREGS; i < numregs; i++) + read_relative_register_raw_bytes (INFO_REGMAP (i), + raw_regs + REGISTER_BYTE (INFO_REGMAP (i))); + + for (i = NUM_REGS - NUM_FREGS; i < numregs; i++) + i387_print_register (raw_regs, INFO_REGMAP (i)); +} + +int +i387_hex_long_double_input(p, val) + char *p; + DOUBLEST *val; +{ + int c, n, len = 20; + + n = 0; + for (len = 20-1; len >= 0; len--) + { + c = *p++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + n *= 16; + if (c >= '0' && c <= '9') + { + n += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + n += c - 'a' + 10; + } + else + return 0; /* Char not a digit */ + if ( ! (len & 1) ) + { + ((unsigned char *)val)[len/2] = n; + n = 0; + } + } + return 1; } Index: gnu/gdb-4.17/gdb/inferior.h diff -u gnu/gdb-4.17/gdb/inferior.h:1.1.1.1 gnu/gdb-4.17/gdb/inferior.h:1.2 --- gnu/gdb-4.17/gdb/inferior.h:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/inferior.h Tue Dec 1 21:52:01 1998 @@ -213,6 +213,12 @@ extern int signal_pass_state PARAMS ((int)); +extern int signal_stop_update PARAMS ((int, int)); + +extern int signal_print_update PARAMS ((int, int)); + +extern int signal_pass_update PARAMS ((int, int)); + /* From infcmd.c */ extern void tty_command PARAMS ((char *, int)); Index: gnu/gdb-4.17/gdb/infptrace.c diff -u gnu/gdb-4.17/gdb/infptrace.c:1.1.1.1 gnu/gdb-4.17/gdb/infptrace.c:1.2 --- gnu/gdb-4.17/gdb/infptrace.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/infptrace.c Tue Dec 1 21:52:01 1998 @@ -37,9 +37,27 @@ #ifndef NO_PTRACE_H #ifdef PTRACE_IN_WRONG_PLACE #include -#else +#else /* PTRACE_IN_WRONG_PLACE */ + +#if defined(__sparc__) && defined(__linux__) +#undef PTRACE_GETREGS /* XXX noise from */ +#undef PTRACE_SETREGS +#undef PTRACE_GETFPREGS +#undef PTRACE_SETFPREGS +#undef PT_ATTACH +#undef PT_DETACH +#endif + #include + +#if defined(__sparc__) && defined(__linux__) +#undef PT_ATTACH +#undef PT_DETACH +#define PT_ATTACH PTRACE_SUNATTACH /* XXX reestablish "nm.h" vals */ +#define PT_DETACH PTRACE_SUNDETACH #endif + +#endif /* PTRACE_IN_WRONG_PLACE */ #endif /* NO_PTRACE_H */ #if !defined (PT_READ_I) @@ -221,7 +239,26 @@ errno = 0; ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); if (errno) - perror_with_name ("ptrace"); + { + if (errno == ESRCH) + { + /* When we detach from a process, it may be killed and no + longer exists. We should not go into an infinite loop. */ + print_sys_errmsg ("ptrace", errno); + + if (current_target.to_wait) + { + /* Let the process go. */ + int retval; + struct target_waitstatus status; + + retval = current_target.to_wait (inferior_pid, &status); + print_waitstatus (inferior_pid, &status, retval); + } + } + else + perror_with_name ("ptrace"); + } attach_flag = 0; } #endif /* ATTACH_DETACH */ Index: gnu/gdb-4.17/gdb/infrun.c diff -u gnu/gdb-4.17/gdb/infrun.c:1.1.1.1 gnu/gdb-4.17/gdb/infrun.c:1.3 --- gnu/gdb-4.17/gdb/infrun.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/infrun.c Sun May 9 07:41:21 1999 @@ -59,6 +59,14 @@ #define GET_LONGJMP_TARGET(PC_ADDR) 0 #endif +/* Determine whether a pc is pointing to the first instruction of a signal + handler. This can be difficult to compute on some systems (like Linux) + where the sigreturn trampoline is only used on return and not on call. */ + +#ifndef START_SIGHANDLER +#define START_SIGHANDLER(pc, func_start, func_name) \ + ((pc) == (func_start) && IN_SIGTRAMP((pc), (func_name))) +#endif /* Some machines have trampoline code that sits between function callers and the actual functions themselves. If this machine doesn't have @@ -125,6 +133,16 @@ #define INSTRUCTION_NULLIFIED 0 #endif +/* Hook for determining whether we've performed a subroutine call while + debugging assembly language code about which little is known. + (I.e, no symbols are available for determining starting addresses + of subroutines.) Defining this hook properly will make "nexti" + behave better in such code. */ + +#ifndef AT_SUBROUTINE_CALL_INSTRUCTION_TARGET +#define AT_SUBROUTINE_CALL_INSTRUCTION_TARGET(prevpc,stoppc) 1 +#endif + /* Tables of how to react to signals; the user sets them. */ static unsigned char *signal_stop; @@ -210,6 +228,14 @@ static int stop_print_frame; +#ifdef PREPARE_TO_PROCEED +/* When a pid must be single-stepped for going over a breakpoint at + proceed (), it should be implicitely stepped by target_resume() in + resume (), implicitely waited for in target_wait() and switched to + in wait_for_inferior(). */ + +static int proceeded_pid; +#endif /* PREPARE_TO_PROCEED */ /* Things to clean up if we QUIT out of resume (). */ /* ARGSUSED */ @@ -259,7 +285,7 @@ /* Install inferior's terminal modes. */ target_terminal_inferior (); - target_resume (-1, step, sig); + target_resume (step && !breakpoints_inserted ? inferior_pid : -1, step, sig); discard_cleanups (old_cleanups); } @@ -336,15 +362,9 @@ In this case the thread that stopped at a breakpoint will immediately cause another stop, if it is not stepped over first. On the other hand, if (ADDR != -1) we only want to single step over the breakpoint if we did - switch to another thread. - - If we are single stepping, don't do any of the above. - (Note that in the current implementation single stepping another - thread after a breakpoint and then continuing will cause the original - breakpoint to be hit again, but you can always continue, so it's not - a big deal.) */ + switch to another thread. */ - if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ())) + if (!oneproc && (proceeded_pid = PREPARE_TO_PROCEED (step))) oneproc = 1; #endif /* PREPARE_TO_PROCEED */ @@ -440,6 +460,10 @@ /* Don't confuse first call to proceed(). */ stop_signal = TARGET_SIGNAL_0; + +#ifdef PREPARE_TO_PROCEED + proceeded_pid = 0; +#endif } static void @@ -511,10 +535,48 @@ registers_changed (); if (target_wait_hook) - pid = target_wait_hook (-1, &w); + pid = target_wait_hook (!breakpoints_inserted ? inferior_pid : -1, &w); else - pid = target_wait (-1, &w); + pid = target_wait (!breakpoints_inserted ? inferior_pid : -1, &w); + +#ifdef PREPARE_TO_PROCEED + /* Switch to the thread selected by the last PREPARE_TO_PROCEED (). + As a side effect, the trap_expected value should be switched. */ + + if (proceeded_pid) + { + if (proceeded_pid != inferior_pid) + { + trap_expected = 0; + + /* Save infrun state for the old thread. */ + save_infrun_state (inferior_pid, prev_pc, + prev_func_start, prev_func_name, + trap_expected, step_resume_breakpoint, + through_sigtramp_breakpoint, + step_range_start, step_range_end, + step_frame_address, handling_longjmp, + another_trap); + + inferior_pid = proceeded_pid; + + /* Load infrun state for the new thread. */ + load_infrun_state (inferior_pid, &prev_pc, + &prev_func_start, &prev_func_name, + &trap_expected, &step_resume_breakpoint, + &through_sigtramp_breakpoint, + &step_range_start, &step_range_end, + &step_frame_address, &handling_longjmp, + &another_trap); + printf_filtered ("[Switching to %s]\n", + target_pid_to_str (inferior_pid)); + trap_expected = 1; + } + proceeded_pid = 0; + } +#endif /* PREPARE_TO_PROCEED */ + /* Gross. We goto this label from elsewhere in wait_for_inferior when we want @@ -669,8 +731,8 @@ remove_breakpoints (); target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ - /* FIXME: What if a signal arrives instead of the single-step - happening? */ + /* FIXME: What if a signal arrives instead of the + single-step happening? */ if (target_wait_hook) target_wait_hook (pid, &w); @@ -678,6 +740,9 @@ target_wait (pid, &w); insert_breakpoints (); + if (inferior_pid == pid && CURRENTLY_STEPPING()) + goto have_waited; + /* We need to restart all the threads now. */ target_resume (-1, 0, TARGET_SIGNAL_0); continue; @@ -777,7 +842,6 @@ else target_wait (pid, &tmpstatus); - goto have_waited; } @@ -1124,6 +1188,9 @@ /* Switch terminal for any messages produced by breakpoint_re_set. */ target_terminal_ours_for_output (); +#ifdef CHECK_SOLIB_CONSISTENCY + CHECK_SOLIB_CONSISTENCY(); +#endif SOLIB_ADD (NULL, 0, NULL); target_terminal_inferior (); } @@ -1239,9 +1306,7 @@ update_step_sp = 1; /* Did we just take a signal? */ - if (IN_SIGTRAMP (stop_pc, stop_func_name) - && !IN_SIGTRAMP (prev_pc, prev_func_name) - && read_sp () INNER_THAN step_sp) + if (START_SIGHANDLER (stop_pc, stop_func_start, stop_func_name)) { /* We've just taken a signal; go until we are back to the point where we took it and one more. */ @@ -1366,7 +1431,9 @@ { /* It's a subroutine call. */ - if (step_over_calls == 0) + if (step_over_calls == 0 + || (step_range_end == 1 + && !AT_SUBROUTINE_CALL_INSTRUCTION_TARGET (prev_pc, stop_pc))) { /* I presume that step_over_calls is only 0 when we're supposed to be stepping at the assembly language level @@ -1432,8 +1499,19 @@ step_resume_breakpoint = set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume); - if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc)) + if (!IN_SOLIB_DYNSYM_RESOLVE_CODE (sr_sal.pc) + && !IN_SIGTRAMP (stop_pc, NULL)) step_resume_breakpoint->frame = step_frame_address; + + if (sr_sal.pc < step_range_start + || sr_sal.pc >= step_range_end) + { + /* If the return function is out_of stepping range, then + update stepping range to match the return address. This + code deals with jumps to functions that did not return + to the current function. */ + step_range_start = step_range_end = sr_sal.pc; + } if (breakpoints_inserted) insert_breakpoints (); } @@ -1583,9 +1661,7 @@ check_sigtramp2: if (trap_expected - && IN_SIGTRAMP (stop_pc, stop_func_name) - && !IN_SIGTRAMP (prev_pc, prev_func_name) - && read_sp () INNER_THAN step_sp) + && START_SIGHANDLER (stop_pc, stop_func_start, stop_func_name)) { /* What has happened here is that we have just stepped the inferior with a signal (because it is a signal which shouldn't make @@ -1847,6 +1923,33 @@ int signo; { return signal_program[signo]; +} + +int signal_stop_update (signo, state) + int signo; + int state; +{ + int ret = signal_stop[signo]; + signal_stop[signo] = state; + return ret; +} + +int signal_print_update (signo, state) + int signo; + int state; +{ + int ret = signal_print[signo]; + signal_print[signo] = state; + return ret; +} + +int signal_pass_update (signo, state) + int signo; + int state; +{ + int ret = signal_program[signo]; + signal_program[signo] = state; + return ret; } static void Index: gnu/gdb-4.17/gdb/irix5-nat.c diff -u gnu/gdb-4.17/gdb/irix5-nat.c:1.1.1.1 gnu/gdb-4.17/gdb/irix5-nat.c:1.2 --- gnu/gdb-4.17/gdb/irix5-nat.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/irix5-nat.c Sun Dec 20 11:25:27 1998 @@ -261,10 +261,14 @@ #include "objfiles.h" #include "command.h" #include "frame.h" -#include "gnu-regex.h" #include "inferior.h" #include "language.h" #include "gdbcmd.h" +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif /* The symbol which starts off the list of shared libraries. */ #define DEBUG_BASE "__rld_obj_head" Index: gnu/gdb-4.17/gdb/lnx-nat.c diff -u /dev/null gnu/gdb-4.17/gdb/lnx-nat.c:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/lnx-nat.c Tue Feb 16 15:51:07 1999 @@ -0,0 +1,44 @@ +/* Generic ative support for Linux + Copyright (C) 1999 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 + +extern int linux_has_rtsig; +extern const char *linux_kernel_has_rtsig; + +void +_initialize_linux_nat () +{ + struct utsname name; + + linux_kernel_has_rtsig = "2.1.70"; +#if defined __GLIBC__ && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ > 2) + + linux_has_rtsig = uname (&name) == 0 + && strverscmp (name.release, + linux_kernel_has_rtsig) >= 0; +#else + /* This is a kludge. It won't work very well. Use glibc 2.1 or newer + instead. */ + linux_has_rtsig = uname (&name) == 0 + && name.release [0] >= '2' + && name.release [1] == '.' + && name.release [2] >= '2'; +#endif +} Index: gnu/gdb-4.17/gdb/lnx-thread.c diff -u /dev/null gnu/gdb-4.17/gdb/lnx-thread.c:1.6 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/lnx-thread.c Tue Feb 16 15:51:07 1999 @@ -0,0 +1,1467 @@ +/* Low level interface for debugging GNU/Linux threads for GDB, + the GNU debugger. + Copyright 1998, 1999 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. */ + +/* This module implements the debugging interface of the linuxthreads package + of the glibc. This package implements a simple clone()-based implementation + of Posix threads for Linux. To use this module, be sure that you have at + least the version of the linuxthreads package that holds the support of + GDB (currently 0.8 included in the glibc-2.0.7). + + Right now, the linuxthreads package does not care of priority scheduling, + so, neither this module does; In particular, the threads are resumed + in any order, which could lead to different scheduling than the one + happening when GDB does not control the execution. + + The latest point is that ptrace(PT_ATTACH, ...) is intrusive in Linux: + When a process is attached, then the attaching process becomes the current + parent of the attached process, and the old parent has lost this child. + If the old parent does a wait[...](), then this child is no longer + considered by the kernel as a child of the old parent, thus leading to + results of the call different when the child is attached and when it's not. + + A fix has been submitted to the Linux community to solve this problem, + which consequences are not visible to the application itself, but on the + process which may wait() for the completion of the application (mostly, + it may consider that the application no longer exists (errno == ECHILD), + although it does, and thus being unable to get the exit status and resource + usage of the child. If by chance, it is able to wait() for the application + after it has died (by receiving first a SIGCHILD, and then doing a wait(), + then the exit status and resource usage may be wrong, because the + linuxthreads package heavily relies on wait() synchronization to keep + them correct. */ + +#include /* for pid_t */ +#include /* for PT_* flags */ +#include /* for WUNTRACED and __WCLONE flags */ +#include /* for struct sigaction and NSIG */ + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_KILL +#define PT_KILL PTRACE_KILL +#endif +#ifndef PT_READ_U +#define PT_READ_U PTRACE_PEEKUSR +#endif + +#include "defs.h" +#include "target.h" +#include "inferior.h" +#include "gdbcore.h" +#include "gdbthread.h" +#include "wait.h" +#include "gdbcmd.h" + +#include "breakpoint.h" + +extern int child_suppress_run; /* make inftarg.c non-runnable */ +struct target_ops linuxthreads_ops; /* Forward declaration */ +extern struct target_ops child_ops; /* target vector for inftarg.c */ + +static CORE_ADDR linuxthreads_handles; /* array of linuxthreads handles */ +static CORE_ADDR linuxthreads_manager; /* pid of linuxthreads manager thread */ +static CORE_ADDR linuxthreads_initial; /* pid of linuxthreads initial thread */ +static CORE_ADDR linuxthreads_debug; /* linuxthreads internal debug flag */ +static CORE_ADDR linuxthreads_num; /* number of valid handle entries */ + +static int linuxthreads_max; /* maximum number of linuxthreads */ + +static int linuxthreads_sizeof_handle; /* size of a linuxthreads handle */ +static int linuxthreads_offset_descr; /* h_descr offset of the linuxthreads + handle */ +static int linuxthreads_offset_pid; /* p_pid offset of the linuxthreads + descr */ + +static int linuxthreads_manager_pid; /* manager pid */ +static int linuxthreads_initial_pid; /* initial pid */ + +static int *linuxthreads_wait_pid; /* wait array of pid */ +static int *linuxthreads_wait_status; /* wait array of status */ +static int linuxthreads_wait_last; /* last status to be reported */ +static sigset_t linuxthreads_wait_mask; /* sigset with SIGCHLD */ + +static int linuxthreads_step_pid; /* current stepped pid */ +static int linuxthreads_step_signo; /* current stepped target signal */ +static int linuxthreads_exit_status; /* exit status of initial thread */ + +static int linuxthreads_inferior_pid; /* temporary internal inferior pid */ +static int linuxthreads_breakpoint_pid; /* last pid that hit a breakpoint */ +static int linuxthreads_attach_pending; /* attach command without wait */ + +static int linuxthreads_breakpoints_inserted; /* any breakpoints inserted */ + +static int linuxthreads_sig_restart; /* SIG_RESTART target value */ +static int linuxthreads_sig_restart_stop; /* SIG_RESTART stop */ +static int linuxthreads_sig_restart_print; /* SIG_RESTART print */ + +static int linuxthreads_sig_cancel; /* SIG_CANCEL target value */ +static int linuxthreads_sig_cancel_stop; /* SIG_CANCEL stop */ +static int linuxthreads_sig_cancel_print; /* SIG_CANCEL print */ + +static int linuxthreads_sig_debug = 0; /* SIG_DEBUG target value */ +static int linuxthreads_sig_debug_stop; /* SIG_DEBUG stop */ +static int linuxthreads_sig_debug_print; /* SIG_DEBUG print */ + +static struct linuxthreads_breakpoint { + CORE_ADDR pc; /* PC of breakpoint */ + int pid; /* pid of breakpoint */ + int step; /* whether the pc has been reached after sstep */ +} *linuxthreads_breakpoint_zombie; /* Zombie breakpoints array */ +static int linuxthreads_breakpoint_last; /* Last zombie breakpoint */ +static CORE_ADDR linuxthreads_breakpoint_addr; /* Zombie breapoint address */ + +#define REMOVE_BREAKPOINT_ZOMBIE(_i) \ +{ \ + if ((_i) < linuxthreads_breakpoint_last) \ + linuxthreads_breakpoint_zombie[(_i)] = \ + linuxthreads_breakpoint_zombie[linuxthreads_breakpoint_last]; \ + linuxthreads_breakpoint_last--; \ +} + +/* Inidicate if the kernel supports the real-time signal. */ +int linux_has_rtsig = 0; + +/* The minimal kernel version which supports the real-time signal. */ +const char *linux_kernel_has_rtsig = NULL; + + +#ifndef PTRACE_XFER_TYPE +#define PTRACE_XFER_TYPE int +#endif +/* Check to see if the given thread is alive. */ +static int +linuxthreads_thread_alive (pid) + int pid; +{ + errno = 0; + return ptrace (PT_READ_U, pid, (PTRACE_ARG3_TYPE)0, 0) >= 0 || errno == 0; +} + +/* On detach(), find a SIGTRAP status and optionally a SIGSTOP one. */ +static int +linuxthreads_find_trap (pid, stop) + int pid; + int stop; +{ + int i; + int rpid; + int status; + int found_stop = 0; + int found_trap = 0; + int last = 0; + int *wstatus = alloca (LINUXTHREAD_NSIG * sizeof (int)); + + /* Look at the pending status */ + for (i = linuxthreads_wait_last; i >= 0; i--) + if (linuxthreads_wait_pid[i] == pid) + { + status = linuxthreads_wait_status[i]; + if (i < linuxthreads_wait_last) + { + linuxthreads_wait_status[i] = + linuxthreads_wait_status[linuxthreads_wait_last]; + linuxthreads_wait_pid[i] = + linuxthreads_wait_pid[linuxthreads_wait_last]; + } + linuxthreads_wait_last--; + + if (!WIFSTOPPED(status)) /* Thread has died */ + return 0; + + if (WSTOPSIG(status) == SIGTRAP) + if (stop) + found_trap = 1; + else + return 1; + else if (WSTOPSIG(status) != SIGSTOP) + { + wstatus[0] = status; + last = 1; + } + else if (stop) + found_stop = 1; + + break; + } + + if (stop) + { + if (!found_trap) + kill (pid, SIGTRAP); + if (!found_stop) + kill (pid, SIGSTOP); + } + + /* Catch all status until SIGTRAP and optionally SIGSTOP show up. */ + for (;;) + { + child_resume (pid, 1, TARGET_SIGNAL_0); + + for (;;) + { + rpid = waitpid (pid, &status, __WCLONE); + if (rpid > 0) + break; + if (errno == EINTR) + continue; + + /* manager has died or pid is initial thread. */ + rpid = waitpid (pid, &status, 0); + if (rpid > 0) + break; + if (errno != EINTR) + perror_with_name ("waitpid"); + } + + if (!WIFSTOPPED(status)) /* Thread has died */ + return 0; + + if (WSTOPSIG(status) == SIGTRAP) + if (!stop || found_stop) + break; + else + found_trap = 1; + else if (WSTOPSIG(status) != SIGSTOP) + wstatus[last++] = status; + else if (stop) + if (found_trap) + break; + else + found_stop = 1; + } + + /* Resend all signals to the thread */ + while (--last >= 0) + kill (pid, WSTOPSIG(wstatus[last])); + + return 1; +} + +static void +restore_inferior_pid (pid) + int pid; +{ + inferior_pid = pid; +} + +static struct cleanup * +save_inferior_pid () +{ + return make_cleanup (restore_inferior_pid, inferior_pid); +} + +/* SIGCHLD handler */ +static void +sigchld_handler(signo) + int signo; +{ + /* This handler is used to get an EINTR while doing waitpid() + when an event is received */ +} + +/* Does the process currently have a pending status ? */ +static int +linuxthreads_pending_status (pid) + int pid; +{ + int i; + for (i = linuxthreads_wait_last; i >= 0; i--) + if (linuxthreads_wait_pid[i] == pid) + return 1; + return 0; +} + +/* Walk through the linuxthreads handles in order to execute a function */ +static void +iterate_active_threads (func, all) + void (*func)(int); + int all; +{ + CORE_ADDR descr; + int pid; + int i; + int num; + + read_memory (linuxthreads_num, (char *)&num, sizeof (int)); + + for (i = 0; i < linuxthreads_max && num > 0; i++) + { + read_memory (linuxthreads_handles + + linuxthreads_sizeof_handle * i + linuxthreads_offset_descr, + (char *)&descr, sizeof (void *)); + if (descr) + { + num--; + read_memory (descr + linuxthreads_offset_pid, + (char *)&pid, sizeof (pid_t)); + if (pid > 0 && pid != linuxthreads_manager_pid + && (all || (!linuxthreads_pending_status (pid)))) + (*func)(pid); + } + } + +} + +/* Insert a thread breakpoint */ +static void +insert_breakpoint (pid) + int pid; +{ + int j; + + /* Remove (if any) the positive zombie breakpoint. */ + for (j = linuxthreads_breakpoint_last; j >= 0; j--) + if (linuxthreads_breakpoint_zombie[j].pid == pid) + { + if ((linuxthreads_breakpoint_zombie[j].pc - DECR_PC_AFTER_BREAK + == linuxthreads_breakpoint_addr) + && !linuxthreads_breakpoint_zombie[j].step) + REMOVE_BREAKPOINT_ZOMBIE(j); + break; + } +} + +/* Remove a thread breakpoint */ +static void +remove_breakpoint (pid) + int pid; +{ + int j; + + /* Insert a positive zombie breakpoint (if needed). */ + for (j = 0; j <= linuxthreads_breakpoint_last; j++) + if (linuxthreads_breakpoint_zombie[j].pid == pid) + break; + + if (in_thread_list (pid) && linuxthreads_thread_alive (pid)) + { + CORE_ADDR pc = read_pc_pid (pid); + if (linuxthreads_breakpoint_addr == pc - DECR_PC_AFTER_BREAK + && j > linuxthreads_breakpoint_last) + { + linuxthreads_breakpoint_zombie[j].pid = pid; + linuxthreads_breakpoint_zombie[j].pc = pc; + linuxthreads_breakpoint_zombie[j].step = 0; + linuxthreads_breakpoint_last++; + } + } +} + +/* Kill a thread */ +static void +kill_thread (pid) + int pid; +{ + if (in_thread_list (pid)) + ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0); + else + kill (pid, SIGKILL); +} + +/* Resume a thread */ +static void +resume_thread (pid) + int pid; +{ + if (pid != inferior_pid + && in_thread_list (pid) + && linuxthreads_thread_alive (pid)) + if (pid == linuxthreads_step_pid) + child_resume (pid, 1, linuxthreads_step_signo); + else + child_resume (pid, 0, TARGET_SIGNAL_0); +} + +/* Detach a thread */ +static void +detach_thread (pid) + int pid; +{ + if (in_thread_list (pid) && linuxthreads_thread_alive (pid)) + { + /* Remove pending SIGTRAP and SIGSTOP */ + linuxthreads_find_trap (pid, 1); + + inferior_pid = pid; + detach (TARGET_SIGNAL_0); + inferior_pid = linuxthreads_manager_pid; + } +} + +/* Stop a thread */ +static void +stop_thread (pid) + int pid; +{ + if (pid != inferior_pid) + if (in_thread_list (pid)) + kill (pid, SIGSTOP); + else if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) == 0) + { + if (!linuxthreads_attach_pending) + printf_unfiltered ("[New %s]\n", target_pid_to_str (pid)); + add_thread (pid); + if (linuxthreads_sig_debug) + /* After a new thread in glibc 2.1 signals gdb its existence, + it suspends itself and wait for linuxthreads_sig_restart, + now we can wake up it. */ + kill (pid, linuxthreads_sig_restart); + } + else + perror_with_name ("ptrace in stop_thread"); +} + +/* Wait for a thread */ +static void +wait_thread (pid) + int pid; +{ + int status; + int rpid; + + if (pid != inferior_pid && in_thread_list (pid)) + { + for (;;) + { + /* Get first pid status. */ + rpid = waitpid(pid, &status, __WCLONE); + if (rpid > 0) + break; + if (errno == EINTR) + continue; + + /* manager has died or pid is initial thread. */ + rpid = waitpid(pid, &status, 0); + if (rpid > 0) + break; + if (errno != EINTR && linuxthreads_thread_alive (pid)) + perror_with_name ("waitpid"); + + /* the thread is dead. */ + return; + } + if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) + { + linuxthreads_wait_pid[++linuxthreads_wait_last] = pid; + linuxthreads_wait_status[linuxthreads_wait_last] = status; + } + } +} + +/* Walk through the linuxthreads handles in order to detect all + threads and stop them */ +static void +update_stop_threads (test_pid) + int test_pid; +{ + struct cleanup *old_chain = NULL; + + if (linuxthreads_manager_pid == 0) + { + if (linuxthreads_manager) + { + if (test_pid > 0 && test_pid != inferior_pid) + { + old_chain = save_inferior_pid (); + inferior_pid = test_pid; + } + read_memory (linuxthreads_manager, + (char *)&linuxthreads_manager_pid, sizeof (pid_t)); + } + if (linuxthreads_initial) + { + if (test_pid > 0 && test_pid != inferior_pid) + { + old_chain = save_inferior_pid (); + inferior_pid = test_pid; + } + read_memory(linuxthreads_initial, + (char *)&linuxthreads_initial_pid, sizeof (pid_t)); + } + } + + if (linuxthreads_manager_pid != 0) + { + if (old_chain == NULL && test_pid > 0 && + test_pid != inferior_pid && linuxthreads_thread_alive (test_pid)) + { + old_chain = save_inferior_pid (); + inferior_pid = test_pid; + } + + if (linuxthreads_thread_alive (inferior_pid)) + { + if (test_pid > 0) + { + if (test_pid != linuxthreads_manager_pid + && !linuxthreads_pending_status (linuxthreads_manager_pid)) + { + stop_thread (linuxthreads_manager_pid); + wait_thread (linuxthreads_manager_pid); + } + if (!in_thread_list (test_pid)) + { + if (!linuxthreads_attach_pending) + printf_unfiltered ("[New %s]\n", + target_pid_to_str (test_pid)); + add_thread (test_pid); + if (linuxthreads_sig_debug + && inferior_pid == test_pid) + /* After a new thread in glibc 2.1 signals gdb its + existence, it suspends itself and wait for + linuxthreads_sig_restart, now we can wake up + it. */ + kill (test_pid, linuxthreads_sig_restart); + } + } + iterate_active_threads (stop_thread, 0); + iterate_active_threads (wait_thread, 0); + } + } + + if (old_chain != NULL) + do_cleanups (old_chain); +} + +/* Internal linuxthreads signal management */ + +static void +linuxthreads_signal_update (on) + int on; +{ + int sig_restart = target_signal_from_host(linuxthreads_sig_restart); + int sig_cancel = target_signal_from_host(linuxthreads_sig_cancel); + int sig_debug = target_signal_from_host(linuxthreads_sig_debug); + + if (on) + { + linuxthreads_sig_restart_stop = signal_stop_update(sig_restart, 0); + linuxthreads_sig_restart_print = signal_print_update(sig_restart, 0); + if (linuxthreads_sig_restart_stop != 1 || + linuxthreads_sig_restart_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has modified %s handling\n", + target_signal_to_string(sig_restart)); + + linuxthreads_sig_cancel_stop = signal_stop_update(sig_cancel, 0); + linuxthreads_sig_cancel_print = signal_print_update(sig_cancel, 0); + if (linuxthreads_sig_cancel_stop != 1 || + linuxthreads_sig_cancel_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has modified %s handling\n", + target_signal_to_string(sig_cancel)); + + if (linuxthreads_sig_debug) + { + linuxthreads_sig_debug_stop = signal_stop_update(sig_debug, 0); + linuxthreads_sig_debug_print = signal_print_update(sig_debug, 0); + if (linuxthreads_sig_debug_stop != 1 || + linuxthreads_sig_debug_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has modified %s handling\n", + target_signal_to_string(sig_debug)); + } + } + else + { + signal_stop_update(sig_restart, linuxthreads_sig_restart_stop); + signal_print_update(sig_restart, linuxthreads_sig_restart_print); + if (linuxthreads_sig_restart_stop != 1 || + linuxthreads_sig_restart_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has restored %s handling\n", + target_signal_to_string(sig_restart)); + + signal_stop_update(sig_cancel, linuxthreads_sig_cancel_stop); + signal_print_update(sig_cancel, linuxthreads_sig_cancel_print); + if (linuxthreads_sig_cancel_stop != 1 || + linuxthreads_sig_cancel_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has restored %s handling\n", + target_signal_to_string(sig_cancel)); + + if (linuxthreads_sig_debug) + { + signal_stop_update(sig_debug, linuxthreads_sig_debug_stop); + signal_print_update(sig_debug, linuxthreads_sig_debug_print); + if (linuxthreads_sig_debug_stop != 1 || + linuxthreads_sig_debug_print != 1) + fprintf_unfiltered (gdb_stderr, + "Linux thread target has restored %s handling\n", + target_signal_to_string(sig_debug)); + } + } +} + +/* This routine is called whenever a new symbol table is read in, or when all + symbol tables are removed. libpthread can only be initialized when it + finds the right variables in libpthread.so. Since it's a shared library, + those variables don't show up until the library gets mapped and the symbol + table is read in. */ + +void +linuxthreads_new_objfile (objfile) + struct objfile *objfile; +{ + struct minimal_symbol *ms; + struct sigaction sact; + + if (!objfile || linuxthreads_max) + return; + + if ((ms = lookup_minimal_symbol ("__pthread_threads_debug", + NULL, objfile)) == NULL) + { + /* The debugging-aware libpthreads is not present in this objfile */ + return; + } + linuxthreads_debug = SYMBOL_VALUE_ADDRESS (ms); + + /* Read internal structures configuration */ + if ((ms = lookup_minimal_symbol ("__pthread_sizeof_handle", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_sizeof_handle, + sizeof (linuxthreads_sizeof_handle)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_sizeof_handle"); + return; + } + + if ((ms = lookup_minimal_symbol ("__pthread_offsetof_descr", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_offset_descr, + sizeof (linuxthreads_offset_descr)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_offsetof_descr"); + return; + } + + if ((ms = lookup_minimal_symbol ("__pthread_offsetof_pid", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_offset_pid, + sizeof (linuxthreads_offset_pid)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_offsetof_pid"); + return; + } + + if ((ms = lookup_minimal_symbol ("__pthread_sig_restart", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_sig_restart, + sizeof (linuxthreads_sig_restart)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_sig_restart"); + return; + } + + if ((ms = lookup_minimal_symbol ("__pthread_sig_cancel", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_sig_cancel, + sizeof (linuxthreads_sig_cancel)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_sig_cancel"); + return; + } + + if ((ms = lookup_minimal_symbol ("__pthread_sig_debug", NULL, + objfile)) + && target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_sig_debug, + sizeof (linuxthreads_sig_debug)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to read linuxthreads symbol \"%s\"\n", + "__pthread_sig_debug"); + return; + } + + if (!linuxthreads_sig_restart || !linuxthreads_sig_cancel) + fatal ("Your LinuxThread library is not compatible with this gdb.\n"); + + if (!linux_has_rtsig + && (linuxthreads_sig_restart >= REALTIME_LO + || linuxthreads_sig_cancel >= REALTIME_LO + || linuxthreads_sig_debug >= REALTIME_LO)) + { + if (linux_kernel_has_rtsig) + fatal ("Kernel doesn't support real-time signals. Need kernel %s or newer.\n", + linux_kernel_has_rtsig); + else + fatal ("Kernel doesn't support real-time signals\n"); + } + + if ((ms = lookup_minimal_symbol ("__pthread_threads_max", + NULL, objfile)) == NULL + || target_read_memory (SYMBOL_VALUE_ADDRESS (ms), + (char *)&linuxthreads_max, + sizeof (linuxthreads_max)) != 0) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_threads_max"); + return; + } + + /* Read adresses of internal structures to access */ + if ((ms = lookup_minimal_symbol ("__pthread_handles", + NULL, objfile)) == NULL) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_handles"); + return; + } + linuxthreads_handles = SYMBOL_VALUE_ADDRESS (ms); + + if ((ms = lookup_minimal_symbol ("__pthread_handles_num", + NULL, objfile)) == NULL) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_handles_num"); + return; + } + linuxthreads_num = SYMBOL_VALUE_ADDRESS (ms); + + if ((ms = lookup_minimal_symbol ("__pthread_manager_thread", + NULL, objfile)) == NULL) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_manager_thread"); + return; + } + linuxthreads_manager = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid; + + if ((ms = lookup_minimal_symbol ("__pthread_initial_thread", + NULL, objfile)) == NULL) + { + fprintf_unfiltered (gdb_stderr, + "Unable to find linuxthreads symbol \"%s\"\n", + "__pthread_initial_thread"); + return; + } + linuxthreads_initial = SYMBOL_VALUE_ADDRESS (ms) + linuxthreads_offset_pid; + + /* Allocate gdb internal structures */ + linuxthreads_wait_pid = + (int *)xmalloc (sizeof (int) * (linuxthreads_max + 1)); + linuxthreads_wait_status = + (int *)xmalloc (sizeof (int) * (linuxthreads_max + 1)); + linuxthreads_breakpoint_zombie = (struct linuxthreads_breakpoint *) + xmalloc (sizeof (struct linuxthreads_breakpoint) * (linuxthreads_max + 1)); + + /* handle linuxthread exit */ + sact.sa_handler = sigchld_handler; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; + if (linuxthreads_sig_debug > 0) + sigaction(linuxthreads_sig_cancel, &sact, NULL); + else + sigaction(linuxthreads_sig_restart, &sact, NULL); + + if (inferior_pid && !linuxthreads_attach_pending) + { + int on = 1; + target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on)); + linuxthreads_attach_pending = 1; + linuxthreads_signal_update (1); + update_stop_threads (inferior_pid); + linuxthreads_attach_pending = 0; + } +} + +/* If we have switched threads from a one that stopped at breakpoint, + return 1 otherwise 0. */ + +int +linuxthreads_prepare_to_proceed (step) + int step; +{ + if (!linuxthreads_max + || !linuxthreads_manager_pid + || !linuxthreads_breakpoint_pid + || !breakpoint_here_p (read_pc_pid (linuxthreads_breakpoint_pid))) + return 0; + + if (step) + { + /* Mark the current inferior as single stepping process. */ + linuxthreads_step_pid = inferior_pid; + } + + linuxthreads_inferior_pid = linuxthreads_breakpoint_pid; + return linuxthreads_breakpoint_pid; +} + +/* Convert a pid to printable form. */ + +char * +linuxthreads_pid_to_str (pid) + int pid; +{ + static char buf[100]; + + sprintf (buf, "%s %d", linuxthreads_max ? "Thread" : "Pid", pid); + + return buf; +} + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +static void +linuxthreads_attach (args, from_tty) + char *args; + int from_tty; +{ + if (!args) + error_no_arg ("process-id to attach"); + + push_target (&linuxthreads_ops); + linuxthreads_breakpoints_inserted = 1; + linuxthreads_breakpoint_last = -1; + linuxthreads_wait_last = -1; + linuxthreads_exit_status = __W_STOPCODE(0); + + child_ops.to_attach (args, from_tty); + + if (linuxthreads_max) + linuxthreads_attach_pending = 1; +} + +/* Take a program previously attached to and detaches it. + The program resumes execution and will no longer stop + on signals, etc. We'd better not have left any breakpoints + in the program or it'll die when it hits one. For this + to work, it may be necessary for the process to have been + previously attached. It *might* work if the program was + started via the normal ptrace (PTRACE_TRACEME). */ + +static void +linuxthreads_detach (args, from_tty) + char *args; + int from_tty; +{ + if (linuxthreads_max) + { + int i; + int pid; + int off = 0; + target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off)); + + /* Walk through linuxthreads array in order to detach known threads. */ + if (linuxthreads_manager_pid != 0) + { + /* Get rid of all positive zombie breakpoints. */ + for (i = 0; i <= linuxthreads_breakpoint_last; i++) + { + if (linuxthreads_breakpoint_zombie[i].step) + continue; + + pid = linuxthreads_breakpoint_zombie[i].pid; + if (!linuxthreads_thread_alive (pid)) + continue; + + if (linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (pid)) + continue; + + /* Continue in STEP mode until the thread pc has moved or + until SIGTRAP is found on the same PC. */ + if (linuxthreads_find_trap (pid, 0) + && linuxthreads_breakpoint_zombie[i].pc == read_pc_pid (pid)) + write_pc_pid (linuxthreads_breakpoint_zombie[i].pc + - DECR_PC_AFTER_BREAK, pid); + } + + /* Detach thread after thread. */ + inferior_pid = linuxthreads_manager_pid; + iterate_active_threads (detach_thread, 1); + + /* Remove pending SIGTRAP and SIGSTOP */ + linuxthreads_find_trap (inferior_pid, 1); + + linuxthreads_wait_last = -1; + linuxthreads_exit_status = __W_STOPCODE(0); + } + + linuxthreads_inferior_pid = 0; + linuxthreads_breakpoint_pid = 0; + linuxthreads_step_pid = 0; + linuxthreads_step_signo = TARGET_SIGNAL_0; + linuxthreads_manager_pid = 0; + linuxthreads_initial_pid = 0; + linuxthreads_attach_pending = 0; + linuxthreads_signal_update (0); + init_thread_list (); /* Destroy thread info */ + } + + child_ops.to_detach (args, from_tty); + + unpush_target (&linuxthreads_ops); +} + +/* Resume execution of process PID. If STEP is nozero, then + just single step it. If SIGNAL is nonzero, restart it with that + signal activated. */ + +static void +linuxthreads_resume (pid, step, signo) + int pid; + int step; + enum target_signal signo; +{ + if (!linuxthreads_max || stop_soon_quietly || linuxthreads_manager_pid == 0) + child_ops.to_resume (pid, step, signo); + else + { + int rpid; + if (linuxthreads_inferior_pid) + { + /* Prepare resume of the last thread that hit a breakpoint */ + linuxthreads_breakpoints_inserted = 0; + rpid = linuxthreads_inferior_pid; + linuxthreads_step_signo = signo; + } + else + { + struct cleanup *old_chain = NULL; + int i; + + if (pid < 0) + { + linuxthreads_step_pid = step ? inferior_pid : 0; + linuxthreads_step_signo = signo; + rpid = inferior_pid; + } + else + rpid = pid; + + if (pid < 0 || !step) + { + linuxthreads_breakpoints_inserted = 1; + + /* Walk through linuxthreads array in order to resume threads */ + if (pid >= 0 && inferior_pid != pid) + { + old_chain = save_inferior_pid (); + inferior_pid = pid; + } + + iterate_active_threads (resume_thread, 0); + if (linuxthreads_manager_pid != inferior_pid + && !linuxthreads_pending_status (linuxthreads_manager_pid)) + resume_thread (linuxthreads_manager_pid); + } + else + linuxthreads_breakpoints_inserted = 0; + + /* Deal with zombie breakpoint */ + for (i = 0; i <= linuxthreads_breakpoint_last; i++) + if (linuxthreads_breakpoint_zombie[i].pid == rpid) + { + if (linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (rpid)) + { + /* The current pc is out of zombie breakpoint. */ + REMOVE_BREAKPOINT_ZOMBIE(i); + } + break; + } + + if (old_chain != NULL) + do_cleanups (old_chain); + } + + /* Resume initial thread. */ + if (!linuxthreads_pending_status (rpid)) + child_ops.to_resume (rpid, step, signo); + } +} + +/* Wait for any threads to stop. We may have to convert PID from a thread id + to a LWP id, and vice versa on the way out. */ + +static int +linuxthreads_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + int status; + int rpid; + int i; + int last; + int *wstatus; + + if (linuxthreads_max && !linuxthreads_breakpoints_inserted) + wstatus = alloca (LINUXTHREAD_NSIG * sizeof (int)); + + for (;;) + { + if (!linuxthreads_max) + rpid = 0; + else if (!linuxthreads_breakpoints_inserted) + { + if (linuxthreads_inferior_pid) + pid = linuxthreads_inferior_pid; + else if (pid < 0) + pid = inferior_pid; + last = rpid = 0; + } + else if (pid < 0 && linuxthreads_wait_last >= 0) + { + status = linuxthreads_wait_status[linuxthreads_wait_last]; + rpid = linuxthreads_wait_pid[linuxthreads_wait_last--]; + } + else if (pid > 0 && linuxthreads_pending_status (pid)) + { + for (i = linuxthreads_wait_last; i >= 0; i--) + if (linuxthreads_wait_pid[i] == pid) + break; + if (i < 0) + rpid = 0; + else + { + status = linuxthreads_wait_status[i]; + rpid = pid; + if (i < linuxthreads_wait_last) + { + linuxthreads_wait_status[i] = + linuxthreads_wait_status[linuxthreads_wait_last]; + linuxthreads_wait_pid[i] = + linuxthreads_wait_pid[linuxthreads_wait_last]; + } + linuxthreads_wait_last--; + } + } + else + rpid = 0; + + if (rpid == 0) + { + int save_errno; + sigset_t omask; + + set_sigint_trap(); /* Causes SIGINT to be passed on to the + attached process. */ + set_sigio_trap (); + + sigprocmask(SIG_BLOCK, &linuxthreads_wait_mask, &omask); + for (;;) + { + rpid = waitpid (pid, &status, __WCLONE | WNOHANG); + if (rpid > 0) + break; + if (rpid == 0) + save_errno = 0; + else if (errno != EINTR) + save_errno = errno; + else + continue; + + rpid = waitpid (pid, &status, WNOHANG); + if (rpid > 0) + break; + if (rpid < 0) + if (errno == EINTR) + continue; + else if (save_errno != 0) + break; + + sigsuspend(&omask); + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + save_errno = errno; + clear_sigio_trap (); + + clear_sigint_trap(); + + if (rpid == -1) + { + if (WIFEXITED(linuxthreads_exit_status)) + { + store_waitstatus (ourstatus, linuxthreads_exit_status); + return inferior_pid; + } + else + { + fprintf_unfiltered + (gdb_stderr, "Child process unexpectedly missing: %s.\n", + safe_strerror (save_errno)); + /* Claim it exited with unknown signal. */ + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + return -1; + } + } + + /* Signals arrive in any order. So get all signals until SIGTRAP + and resend previous ones to be held after. */ + if (linuxthreads_max + && !linuxthreads_breakpoints_inserted + && WIFSTOPPED(status)) + if (WSTOPSIG(status) == SIGTRAP) + { + while (--last >= 0) + kill (rpid, WSTOPSIG(wstatus[last])); + + /* insert negative zombie breakpoint */ + for (i = 0; i <= linuxthreads_breakpoint_last; i++) + if (linuxthreads_breakpoint_zombie[i].pid == rpid) + break; + if (i > linuxthreads_breakpoint_last) + { + linuxthreads_breakpoint_zombie[i].pid = rpid; + linuxthreads_breakpoint_last++; + } + linuxthreads_breakpoint_zombie[i].pc = read_pc_pid (rpid); + linuxthreads_breakpoint_zombie[i].step = 1; + } + else + { + if (WSTOPSIG(status) != SIGSTOP) + { + for (i = 0; i < last; i++) + if (wstatus[i] == status) + break; + if (i >= last) + wstatus[last++] = status; + } + child_resume (rpid, 1, TARGET_SIGNAL_0); + continue; + } + if (linuxthreads_inferior_pid) + linuxthreads_inferior_pid = 0; + } + + if (linuxthreads_max && !stop_soon_quietly) + { + if (linuxthreads_max + && WIFSTOPPED(status) + && WSTOPSIG(status) == SIGSTOP) + { + /* Skip SIGSTOP signals. */ + if (!linuxthreads_pending_status (rpid)) + if (linuxthreads_step_pid == rpid) + child_resume (rpid, 1, linuxthreads_step_signo); + else + child_resume (rpid, 0, TARGET_SIGNAL_0); + continue; + } + + /* Do no report exit status of cloned threads. */ + if (WIFEXITED(status)) + { + if (rpid == linuxthreads_initial_pid) + linuxthreads_exit_status = status; + + /* Remove any zombie breakpoint. */ + for (i = 0; i <= linuxthreads_breakpoint_last; i++) + if (linuxthreads_breakpoint_zombie[i].pid == rpid) + { + REMOVE_BREAKPOINT_ZOMBIE(i); + break; + } + if (pid > 0) + pid = -1; + continue; + } + + /* Deal with zombie breakpoint */ + for (i = 0; i <= linuxthreads_breakpoint_last; i++) + if (linuxthreads_breakpoint_zombie[i].pid == rpid) + break; + + if (i <= linuxthreads_breakpoint_last) + { + /* There is a potential zombie breakpoint */ + if (WIFEXITED(status) + || linuxthreads_breakpoint_zombie[i].pc != read_pc_pid (rpid)) + { + /* The current pc is out of zombie breakpoint. */ + REMOVE_BREAKPOINT_ZOMBIE(i); + } + else if (!linuxthreads_breakpoint_zombie[i].step + && WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) + { + /* This is a real one ==> decrement PC and restart. */ + write_pc_pid (linuxthreads_breakpoint_zombie[i].pc + - DECR_PC_AFTER_BREAK, rpid); + if (linuxthreads_step_pid == rpid) + child_resume (rpid, 1, linuxthreads_step_signo); + else + child_resume (rpid, 0, TARGET_SIGNAL_0); + continue; + } + } + + /* Walk through linuxthreads array in order to stop them */ + if (linuxthreads_breakpoints_inserted) + update_stop_threads (rpid); + + } + else if (rpid != inferior_pid) + continue; + + store_waitstatus (ourstatus, status); + + if (linuxthreads_attach_pending && !stop_soon_quietly) + { + int on = 1; + target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on)); + update_stop_threads (rpid); + linuxthreads_signal_update (1); + linuxthreads_attach_pending = 0; + } + + if (linuxthreads_breakpoints_inserted + && WIFSTOPPED(status) + && WSTOPSIG(status) == SIGTRAP) + linuxthreads_breakpoint_pid = rpid; + else if (linuxthreads_breakpoint_pid) + linuxthreads_breakpoint_pid = 0; + + return rpid; + } +} + +/* Fork an inferior process, and start debugging it with ptrace. */ + +static void +linuxthreads_create_inferior (exec_file, allargs, env) + char *exec_file; + char *allargs; + char **env; +{ + if (!exec_file && !exec_bfd) + { + error ("No executable file specified.\n\ +Use the \"file\" or \"exec-file\" command."); + return; + } + + push_target (&linuxthreads_ops); + linuxthreads_breakpoints_inserted = 1; + linuxthreads_breakpoint_last = -1; + linuxthreads_wait_last = -1; + linuxthreads_exit_status = __W_STOPCODE(0); + + if (linuxthreads_max) + linuxthreads_attach_pending = 1; + + child_ops.to_create_inferior (exec_file, allargs, env); +} + +/* Clean up after the inferior dies. */ + +static void +linuxthreads_mourn_inferior () +{ + if (linuxthreads_max) + { + int off = 0; + target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off)); + + linuxthreads_inferior_pid = 0; + linuxthreads_breakpoint_pid = 0; + linuxthreads_step_pid = 0; + linuxthreads_step_signo = TARGET_SIGNAL_0; + linuxthreads_manager_pid = 0; + linuxthreads_initial_pid = 0; + linuxthreads_attach_pending = 0; + init_thread_list(); /* Destroy thread info */ + linuxthreads_signal_update (0); + } + + child_ops.to_mourn_inferior (); + + unpush_target (&linuxthreads_ops); +} + +/* Kill the inferior process */ + +static void +linuxthreads_kill () +{ + int rpid; + int status; + + if (inferior_pid == 0) + return; + + if (linuxthreads_max && linuxthreads_manager_pid != 0) + { + /* Remove all threads status. */ + inferior_pid = linuxthreads_manager_pid; + iterate_active_threads (kill_thread, 1); + } + + kill_thread (inferior_pid); + + if (doing_quit_force >= 0) + { + if (linuxthreads_max && linuxthreads_manager_pid != 0) + { + /* Wait for thread to complete */ + while ((rpid = waitpid (-1, &status, __WCLONE)) > 0) + if (!WIFEXITED(status)) + kill_thread (rpid); + + while ((rpid = waitpid (-1, &status, 0)) > 0) + if (!WIFEXITED(status)) + kill_thread (rpid); + } + else + while ((rpid = waitpid (inferior_pid, &status, 0)) > 0) + if (!WIFEXITED(status)) + ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0); + } + + /* Wait for all threads. */ + do + rpid = waitpid (-1, &status, __WCLONE | WNOHANG); + while (rpid > 0 || errno == EINTR); + + do + rpid = waitpid (-1, &status, WNOHANG); + while (rpid > 0 || errno == EINTR); + + linuxthreads_mourn_inferior (); +} + +/* Insert a breakpoint */ + +static int +linuxthreads_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + if (linuxthreads_max && linuxthreads_manager_pid != 0) + { + linuxthreads_breakpoint_addr = addr; + iterate_active_threads (insert_breakpoint, 1); + insert_breakpoint (linuxthreads_manager_pid); + } + + return child_ops.to_insert_breakpoint (addr, contents_cache); +} + +/* Remove a breakpoint */ + +static int +linuxthreads_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + if (linuxthreads_max && linuxthreads_manager_pid != 0) + { + linuxthreads_breakpoint_addr = addr; + iterate_active_threads (remove_breakpoint, 1); + remove_breakpoint (linuxthreads_manager_pid); + } + + return child_ops.to_remove_breakpoint (addr, contents_cache); +} + +/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ + +static int +linuxthreads_can_run () +{ + return child_suppress_run; +} + +struct target_ops linuxthreads_ops = { + "linuxthreads", /* to_shortname */ + "LINUX threads and pthread.", /* to_longname */ + "LINUX threads and pthread support.", /* to_doc */ + 0, /* to_open */ + 0, /* to_close */ + linuxthreads_attach, /* to_attach */ + linuxthreads_detach, /* to_detach */ + linuxthreads_resume, /* to_resume */ + linuxthreads_wait, /* to_wait */ + 0, /* to_fetch_registers */ + 0, /* to_store_registers */ + 0, /* to_prepare_to_store */ + 0, /* to_xfer_memory */ + 0, /* to_files_info */ + linuxthreads_insert_breakpoint, /* to_insert_breakpoint */ + linuxthreads_remove_breakpoint, /* to_remove_breakpoint */ + 0, /* to_terminal_init */ + 0, /* to_terminal_inferior */ + 0, /* to_terminal_ours_for_output */ + 0, /* to_terminal_ours */ + 0, /* to_terminal_info */ + linuxthreads_kill, /* to_kill */ + 0, /* to_load */ + 0, /* to_lookup_symbol */ + linuxthreads_create_inferior, /* to_create_inferior */ + linuxthreads_mourn_inferior, /* to_mourn_inferior */ + linuxthreads_can_run, /* to_can_run */ + 0, /* to_notice_signals */ + linuxthreads_thread_alive, /* to_thread_alive */ + 0, /* to_stop */ + thread_stratum, /* to_stratum */ + 0, /* to_next */ + 0, /* to_has_all_memory */ + 0, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + 0, /* sections */ + 0, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_linuxthreads () +{ + struct sigaction sact; + + add_target (&linuxthreads_ops); + child_suppress_run = 1; + + /* Attach SIGCHLD handler */ + sact.sa_handler = sigchld_handler; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; + sigaction(SIGCHLD, &sact, NULL); + + /* initialize SIGCHLD mask */ + sigemptyset(&linuxthreads_wait_mask); + sigaddset(&linuxthreads_wait_mask, SIGCHLD); +} Index: gnu/gdb-4.17/gdb/m3-nat.c diff -u gnu/gdb-4.17/gdb/m3-nat.c:1.1.1.1 gnu/gdb-4.17/gdb/m3-nat.c:1.2 --- gnu/gdb-4.17/gdb/m3-nat.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/m3-nat.c Tue Dec 1 21:52:01 1998 @@ -1,7 +1,7 @@ /* Interface GDB to Mach 3.0 operating systems. (Most) Mach 3.0 related routines live in this file. - Copyright (C) 1992, 1996 Free Software Foundation, Inc. + Copyright (C) 1992, 1996, 1998 Free Software Foundation, Inc. This file is part of GDB. @@ -1576,26 +1576,23 @@ * * If we have switched threads and stopped at breakpoint return 1 otherwise 0. * - * if SELECT_IT is nonzero, reselect the thread that was active when - * we stopped at a breakpoint. - * + * If we are single stepping, don't do anything since in the current + * implementation single stepping another thread after a breakpoint and + * then continuing will cause the original breakpoint to be hit again, + * but you can always continue, so it's not a big deal. */ -mach3_prepare_to_proceed (select_it) - int select_it; +mach3_prepare_to_proceed (step) + int step; { - if (stop_thread && + if (!step && + stop_thread && stop_thread != current_thread && stop_exception == EXC_BREAKPOINT) { - int mid; - - if (! select_it) - return 1; - - mid = switch_to_thread (stop_thread); - - return 1; + switch_to_thread (stop_thread); + if (breakpoint_here_p (read_pc ())) + return inferior_pid; } return 0; Index: gnu/gdb-4.17/gdb/monitor.c diff -u gnu/gdb-4.17/gdb/monitor.c:1.1.1.1 gnu/gdb-4.17/gdb/monitor.c:1.2 --- gnu/gdb-4.17/gdb/monitor.c:1.1.1.1 Fri May 29 06:57:35 1998 +++ gnu/gdb-4.17/gdb/monitor.c Sun Dec 20 11:25:27 1998 @@ -55,9 +55,13 @@ #include "monitor.h" #include "gdbcmd.h" #include "inferior.h" -#include "gnu-regex.h" #include "dcache.h" #include "srec.h" +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif static char *dev_name; static struct target_ops *targ_ops; Index: gnu/gdb-4.17/gdb/osfsolib.c diff -u gnu/gdb-4.17/gdb/osfsolib.c:1.1.1.1 gnu/gdb-4.17/gdb/osfsolib.c:1.2 --- gnu/gdb-4.17/gdb/osfsolib.c:1.1.1.1 Fri May 29 06:57:36 1998 +++ gnu/gdb-4.17/gdb/osfsolib.c Sun Dec 20 11:25:27 1998 @@ -35,10 +35,14 @@ #include "command.h" #include "target.h" #include "frame.h" -#include "gnu-regex.h" #include "inferior.h" #include "language.h" #include "gdbcmd.h" +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif #define MAX_PATH_SIZE 1024 /* FIXME: Should be dynamic */ Index: gnu/gdb-4.17/gdb/ppclnx-nat.c diff -u /dev/null gnu/gdb-4.17/gdb/ppclnx-nat.c:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/ppclnx-nat.c Tue Dec 1 21:52:01 1998 @@ -0,0 +1,88 @@ +/* PPC linux native support. + Copyright (C) 1988, 1989, 1991, 1992, 1994, 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. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "language.h" +#include "gdbcore.h" + +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb-stabs.h" +#include "target.h" + +#include "gdb_stat.h" +#include "obstack.h" +#include "gdb_string.h" + + +#include +#include +#include +#include +#include +#include +#include +#include + +int +kernel_u_size () +{ + return (sizeof (struct user)); +} + +static int regmap[] = + {PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, + PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15, + PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23, + PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31, + PT_FPR0, PT_FPR0+2, PT_FPR0+4, PT_FPR0+6, PT_FPR0+8, PT_FPR0+10,PT_FPR0+12,PT_FPR0+14, + PT_FPR0+16,PT_FPR0+18,PT_FPR0+20,PT_FPR0+22,PT_FPR0+24,PT_FPR0+26,PT_FPR0+28,PT_FPR0+30, + PT_FPR0+32,PT_FPR0+34,PT_FPR0+36,PT_FPR0+38,PT_FPR0+40,PT_FPR0+42,PT_FPR0+44,PT_FPR0+46, + PT_FPR0+48,PT_FPR0+50,PT_FPR0+52,PT_FPR0+54,PT_FPR0+56,PT_FPR0+58,PT_FPR0+60,PT_FPR0+62, + PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ }; + + +int ppc_register_u_addr(int ustart, int regnum) +{ + return (ustart + 4 * regmap[regnum]); +} + +supply_gregset(gregset_t *gregsetp) +{ + int regi; + register greg_t *regp = (greg_t *) gregsetp; + + for (regi=0; regi < 32; regi++) + supply_register (regi, (char *) (regp + regi)); + + for (regi = FIRST_SP_REGNUM; regi <= LAST_SP_REGNUM; regi++) + supply_register (regi, (char *) (regp + regmap[regi])); +} + +supply_fpregset(fpregset_t *fpregsetp) +{ + int regi; + for (regi=0; regi < 32; regi++) { + supply_register(FP0_REGNUM+regi, (char *) (*fpregsetp + regi)); + } +} Index: gnu/gdb-4.17/gdb/ppclnx-tdep.c diff -u /dev/null gnu/gdb-4.17/gdb/ppclnx-tdep.c:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/ppclnx-tdep.c Tue Dec 1 21:52:01 1998 @@ -0,0 +1,1350 @@ +/* Target-dependent code for GDB, the GNU debugger. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995 + 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 "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "target.h" +#include "language.h" +#include "gdbcore.h" +#include "symfile.h" +#include "objfiles.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for struct pt_regs */ +#include /* for struct sigcontext_struct */ + +#ifndef __SIGNAL_FRAMESIZE +/* On linux-pmac, this is in */ +#define __SIGNAL_FRAMESIZE 64 +#endif + +#define REGS_PTR_OFFSET \ + (__SIGNAL_FRAMESIZE + offsetof(struct sigcontext_struct, regs)) + +#define INSTR_LI_R0_0x7777 0x38007777 +#define INSTR_SC 0x44000002 + +extern struct obstack frame_cache_obstack; + +/* Static function prototypes */ + +static void frame_get_cache_fsr PARAMS ((struct frame_info *fi, + struct rs6000_framedata *fdatap)); + + +/* Determine whether or not instruction at prevpc was a subroutine + branch and if so whether or not stoppc is the subroutine branch + target. */ + +int +at_subroutine_call_instruction_target(prevpc,stoppc) + CORE_ADDR prevpc; + CORE_ADDR stoppc; +{ + int instr; + int opcode, ext_op, lk; + + instr = read_memory_integer (prevpc, 4); + + opcode = (instr >> 26) & 0x1f; + ext_op = (instr >> 1) & 0x3ff; + lk = instr & 1; + + /* All the following does is check to make sure that we were on + a branch instruction and that stoppc is not immediately after + the instruction which we were just at. We are not really checking + the branch target, but that isn't really necessary for this + subroutine to work. I guess this could be a possible FIXME. */ + + return ((prevpc+4 != stoppc) + && lk == 1 + && (opcode == 18 + || opcode == 16 + || (opcode == 19 && (ext_op == 16 || ext_op == 528)))); +} + + +/* return pc value after skipping a function prologue and also return + information about a function frame. + + in struct rs6000_frameinfo fdata: + - frameless is TRUE, if function does not have a frame. + - nosavedpc is TRUE, if function does not save %pc value in its frame. + - offset is the number of bytes used in the frame to save registers. + - saved_gpr is the number of the first saved gpr. + - saved_fpr is the number of the first saved fpr. + - alloca_reg is the number of the register used for alloca() handling. + Otherwise -1. + - gpr_offset is the offset of the saved gprs + - fpr_offset is the offset of the saved fprs + - lr_offset is the offset of the saved lr + - cr_offset is the offset of the saved cr + */ + +#define SIGNED_SHORT(x) \ + ((sizeof (short) == 2) \ + ? ((int)(short)(x)) \ + : ((int)((((x) & 0xffff) ^ 0x8000) - 0x8000))) + +#define GET_SRC_REG(x) (((x) >> 21) & 0x1f) + +CORE_ADDR +skip_prologue (pc, fdata) + CORE_ADDR pc; + struct rs6000_framedata *fdata; +{ + CORE_ADDR orig_pc = pc; + char buf[4]; + unsigned long op; + long offset = 0; + int lr_reg = 0; + int cr_reg = 0; + int reg; + int framep = 0; + int minimal_toc_loaded = 0; + static struct rs6000_framedata zero_frame; + + *fdata = zero_frame; + fdata->saved_gpr = -1; + fdata->saved_fpr = -1; + fdata->alloca_reg = -1; + fdata->frameless = 1; + fdata->nosavedpc = 1; + + if (target_read_memory (pc, buf, 4)) + return pc; /* Can't access it -- assume no prologue. */ + + /* Assume that subsequent fetches can fail with low probability. */ + pc -= 4; + for (;;) + { + pc += 4; + op = read_memory_integer (pc, 4); + + if ((op & 0xfc1fffff) == 0x7c0802a6) { /* mflr Rx */ + lr_reg = (op & 0x03e00000) | 0x90010000; + continue; + + } else if ((op & 0xfc1fffff) == 0x7c000026) { /* mfcr Rx */ + cr_reg = (op & 0x03e00000) | 0x90010000; + continue; + + } else if ((op & 0xfc1f0000) == 0xd8010000) { /* stfd Rx,NUM(r1) */ + reg = GET_SRC_REG (op); + if (fdata->saved_fpr == -1 || fdata->saved_fpr > reg) { + fdata->saved_fpr = reg; + fdata->fpr_offset = SIGNED_SHORT (op) + offset; + } + continue; + + } else if (((op & 0xfc1f0000) == 0xbc010000) || /* stm Rx, NUM(r1) */ + ((op & 0xfc1f0000) == 0x90010000 && /* st rx,NUM(r1), rx >= r13 */ + (op & 0x03e00000) >= 0x01a00000)) { + + reg = GET_SRC_REG (op); + if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg) { + fdata->saved_gpr = reg; + fdata->gpr_offset = SIGNED_SHORT (op) + offset; + } + continue; + + } else if ((op & 0xffff0000) == 0x3c000000) { /* addis 0,0,NUM, used for >= 32k frames */ + fdata->offset = (op & 0x0000ffff) << 16; + fdata->frameless = 0; + continue; + + } else if ((op & 0xffff0000) == 0x60000000) { /* ori 0,0,NUM, 2nd half of >= 32k frames */ + fdata->offset |= (op & 0x0000ffff); + fdata->frameless = 0; + continue; + + } else if (lr_reg && (op & 0xffff0000) == lr_reg) { /* st Rx,NUM(r1) where Rx == lr */ + fdata->lr_offset = SIGNED_SHORT (op) + offset; + fdata->nosavedpc = 0; + lr_reg = 0; + continue; + + } else if (cr_reg && (op & 0xffff0000) == cr_reg) { /* st Rx,NUM(r1) where Rx == cr */ + fdata->cr_offset = SIGNED_SHORT (op) + offset; + cr_reg = 0; + continue; + + } else if (op == 0x48000005) { /* bl .+4 used in -mrelocatable */ + continue; + + } else if (op == 0x48000004) { /* b .+4 (xlc) */ + break; + + } else if (((op & 0xffff0000) == 0x801e0000 || /* lwz 0,NUM(r30), used in V.4 -mrelocatable */ + op == 0x7fc0f214) && /* add r30,r0,r30, used in V.4 -mrelocatable */ + lr_reg == 0x901e0000) { + continue; + + } else if ((op & 0xffff0000) == 0x3fc00000 || /* addis 30,0,foo@ha, used in V.4 -mminimal-toc */ + (op & 0xffff0000) == 0x3bde0000) { /* addi 30,30,foo@l */ + continue; + + } else if ((op & 0xfc000000) == 0x48000000 /* bl foo, to get the GOT */ + && read_memory_integer(pc+(((((long) op)<<6)>>6) & ~3), 4) + == 0x4e800021 /* blrl */ + && (read_memory_integer(pc+4,4) & 0xfc1fffff) == 0x7c0802a6 /* mflr */) { + pc += 4; /* skip the mflr instruction */ + continue; + + } else if ((op & 0xfc000000) == 0x48000000) { /* bl foo, to save fprs??? */ + + fdata->frameless = 0; + /* Don't skip over the subroutine call if it is not within the first + three instructions of the prologue. */ + if ((pc - orig_pc) > 8) + break; + + op = read_memory_integer (pc+4, 4); + + /* At this point, make sure this is not a trampoline function + (a function that simply calls another functions, and nothing else). + If the next is not a nop, this branch was part of the function + prologue. */ + + if (op == 0x4def7b82 || op == 0) /* crorc 15, 15, 15 */ + break; /* don't skip over this branch */ + + continue; + + /* update stack pointer */ + } else if ((op & 0xffff0000) == 0x94210000) { /* stu r1,NUM(r1) */ + fdata->frameless = 0; + fdata->offset = SIGNED_SHORT (op); + offset = fdata->offset; + continue; + + } else if (op == 0x7c21016e) { /* stwux 1,1,0 */ + fdata->frameless = 0; + offset = fdata->offset; + continue; + + /* Load up minimal toc pointer */ + } else if ((op >> 22) == 0x20f + && ! minimal_toc_loaded) { /* l r31,... or l r30,... */ + minimal_toc_loaded = 1; + continue; + + /* store parameters in stack */ + } else if ((op & 0xfc1f0000) == 0x90010000 || /* st rx,NUM(r1) */ + (op & 0xfc1f0000) == 0xd8010000 || /* stfd Rx,NUM(r1) */ + (op & 0xfc1f0000) == 0xfc010000) { /* frsp, fp?,NUM(r1) */ + continue; + + /* store parameters in stack via frame pointer */ + } else if (framep && + (op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r1) */ + (op & 0xfc1f0000) == 0xd81f0000 || /* stfd Rx,NUM(r1) */ + (op & 0xfc1f0000) == 0xfc1f0000) { /* frsp, fp?,NUM(r1) */ + continue; + + /* Set up frame pointer */ + } else if (op == 0x603f0000 /* oril r31, r1, 0x0 */ + || op == 0x7c3f0b78) { /* mr r31, r1 */ + fdata->frameless = 0; + framep = 1; + fdata->alloca_reg = 31; + continue; + + /* Another way to set up the frame pointer. */ + } else if ((op & 0xfc1fffff) == 0x38010000) { /* addi rX, r1, 0x0 */ + fdata->frameless = 0; + framep = 1; + fdata->alloca_reg = (op & ~0x38010000) >> 21; + continue; + + } else { + break; + } + } + + fdata->offset = - fdata->offset; + return fdata->frameless ? orig_pc : pc; +} + + +/************************************************************************* + Support for creating pushing a dummy frame into the stack, and popping + frames, etc. +*************************************************************************/ + +/* The total size of dummy frame is 436, which is; + + 32 gpr's - 128 bytes + 32 fpr's - 256 " + 7 the rest - 28 " +*/ + +#define DUMMY_FRAME_SIZE 412 + +extern int stop_stack_dummy; + +/* sp_before_dummy is used to communicate the value of the stack + pointer for backchaining purposes to push_arguments. Its value + is not (and must not be) relied on in pop_dummy_frame(). */ + +static CORE_ADDR sp_before_dummy; + +/* push a dummy frame into stack, save all register. Currently we are saving + only gpr's and fpr's, which is not good enough! FIXMEmgo */ + +void +push_dummy_frame () +{ + /* stack pointer. */ + CORE_ADDR sp; + /* Same thing, target byte order. */ + char sp_targ[4]; + + /* link register. */ + CORE_ADDR pc; + /* Same thing, target byte order. */ + char pc_targ[4]; + + int ii; + + target_fetch_registers (-1); + + + sp_before_dummy = sp = read_register(SP_REGNUM); + pc = read_register(PC_REGNUM); + store_address (pc_targ, 4, pc); + + /* Be careful! If the stack pointer is not decremented first, then kernel + thinks he is free to use the space underneath it. And kernel actually + uses that area for IPC purposes when executing ptrace(2) calls. So + before writing register values into the new frame, decrement and update + %sp first in order to secure your frame. */ + + /* FIXME: We don't check if the stack really has this much space. + This is a problem on the ppc simulator (which only grants one page + (4096 bytes) by default. */ + + write_register (SP_REGNUM, sp-DUMMY_FRAME_SIZE); + + /* gdb relies on the state of current_frame. We'd better update it, + otherwise things like do_registers_info() wouldn't work properly! */ + + flush_cached_frames (); + + /* save program counter in link register's space. */ + write_memory (sp + DEFAULT_LR_SAVE, pc_targ, 4); + + /* save all floating point and general purpose registers here. */ + + /* fpr's, f0..f31 */ + for (ii = 0; ii < 32; ++ii) + write_memory (sp-8-(ii*8), ®isters[REGISTER_BYTE (31-ii+FP0_REGNUM)], 8); + + /* gpr's r0..r31 */ + for (ii=1; ii <=32; ++ii) + write_memory (sp-256-(ii*4), ®isters[REGISTER_BYTE (32-ii)], 4); + + /* so far, 32*2 + 32 words = 384 bytes have been written. + 7 extra registers in our register set: pc, ps, cnd, lr, cnt, xer, mq */ + + for (ii=1; ii <= (LAST_SP_REGNUM-FIRST_SP_REGNUM+1); ++ii) { + write_memory (sp-384-(ii*4), + ®isters[REGISTER_BYTE (FPLAST_REGNUM + ii)], 4); + } + + /* Save sp or so called back chain right here. */ + store_address (sp_targ, 4, sp); + write_memory (sp-DUMMY_FRAME_SIZE, sp_targ, 4); + sp -= DUMMY_FRAME_SIZE; + +} + + +/* Pop a dummy frame. + + With the SYSV PPC ABI, when we push a dummy frame, we save all of the + registers. This is usually done before user calls a function explicitly. + + After a dummy frame is pushed, some instructions are copied into stack, + and stack pointer is decremented even more. +*/ + +pop_dummy_frame () +{ + CORE_ADDR sp, pc; + int ii; + + sp = read_memory_integer(read_register(SP_REGNUM), 4); + + /* restore all fpr's. */ + for (ii = 1; ii <= 32; ++ii) + read_memory (sp-(ii*8), ®isters[REGISTER_BYTE (32-ii+FP0_REGNUM)], 8); + + /* restore all gpr's */ + for (ii=1; ii <= 32; ++ii) { + read_memory (sp-256-(ii*4), ®isters[REGISTER_BYTE (32-ii)], 4); + } + + /* restore the rest of the registers. */ + for (ii=1; ii <=(LAST_SP_REGNUM-FIRST_SP_REGNUM+1); ++ii) + read_memory (sp-384-(ii*4), + ®isters[REGISTER_BYTE (FPLAST_REGNUM + ii)], 4); + + /* when a dummy frame was being pushed, we had to decrement %sp first, in + order to secure astack space. Thus, saved %sp (or %r1) value, is not the + one we should restore. Change it with the one we need. */ + + *(int*)®isters [REGISTER_BYTE(FP_REGNUM)] = sp; + + /* Now we can restore all registers. */ + + target_store_registers (-1); + pc = read_pc (); + flush_cached_frames (); +} + + +/* pop the innermost frame, go back to the caller. */ + +void +pop_frame () +{ + CORE_ADDR pc, lr, sp, prev_sp; /* %pc, %lr, %sp */ + struct rs6000_framedata fdata; + struct frame_info *frame = get_current_frame (); + int addr, ii; + + pc = read_pc (); + sp = FRAME_FP (frame); + + if (stop_stack_dummy) { + pop_dummy_frame (); + return; + } + + /* Make sure that all registers are valid. */ + read_register_bytes (0, NULL, REGISTER_BYTES); + + /* figure out previous %pc value. If the function is frameless, it is + still in the link register, otherwise walk the frames and retrieve the + saved %pc value in the previous frame. */ + + addr = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET; + (void) skip_prologue (addr, &fdata); + + if (fdata.frameless) + prev_sp = sp; + else + prev_sp = read_memory_integer (sp, 4); + if (fdata.lr_offset == 0) + lr = read_register (LR_REGNUM); + else + lr = read_memory_integer (prev_sp + fdata.lr_offset, 4); + + /* reset %pc value. */ + write_register (PC_REGNUM, lr); + + /* reset register values if any was saved earlier. */ + addr = prev_sp - fdata.offset; + + if (fdata.saved_gpr != -1) + for (ii = fdata.saved_gpr; ii <= 31; ++ii) { + read_memory (addr, ®isters [REGISTER_BYTE (ii)], 4); + addr += 4; + } + + if (fdata.saved_fpr != -1) + for (ii = fdata.saved_fpr; ii <= 31; ++ii) { + read_memory (addr, ®isters [REGISTER_BYTE (ii+FP0_REGNUM)], 8); + addr += 8; + } + + write_register (SP_REGNUM, prev_sp); + target_store_registers (-1); + flush_cached_frames (); +} + +/* fixup the call sequence of a dummy function, with the real function address. + its argumets will be passed by gdb. */ + +void +ppclinux_fix_call_dummy (dummyname, pc, fun, nargs, args, type, gcc_p) + char *dummyname; + CORE_ADDR pc; + CORE_ADDR fun; + int nargs; /* not used */ + value_ptr *args; + struct type *type; + int gcc_p; +{ +#define TARGET_ADDR_OFFSET 16 + + int ii; + CORE_ADDR target_addr; + + target_addr = fun; + + ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET); + ii = (ii & 0xffff0000) | (target_addr >> 16); + *(int*)((char*)dummyname + TARGET_ADDR_OFFSET) = ii; + + ii = *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4); + ii = (ii & 0xffff0000) | (target_addr & 0x0000ffff); + *(int*)((char*)dummyname + TARGET_ADDR_OFFSET+4) = ii; +} + + +/* round2 rounds x up to the nearest multiple of s assuming that s is a + power of 2 */ + +#undef round2 +#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s)) + +/* Pass the arguments in either registers, or in the stack. Using the + ppc sysv ABI, the first eight words of the argument list (that might + be less than eight parameters if some parameters occupy more than one + word) are passed in r3..r10 registers. float and double parameters are + passed in fpr's, in addition to that. Rest of the parameters if any + are passed in user stack. + + If the function is returning a structure, then the return address is passed + in r3, then the first 7 words of the parametes can be passed in registers, + starting from r4. */ + +CORE_ADDR +push_arguments (nargs, args, sp, struct_return, struct_addr) + int nargs; + value_ptr *args; + CORE_ADDR sp; + int struct_return; + CORE_ADDR struct_addr; +{ + int argno; + int greg, freg; + int argstkspace; + int structstkspace; + int argoffset; + int structoffset; + value_ptr arg; + struct type *type; + int len; + char old_sp_buf[4]; + + greg = struct_return ? 4 : 3; + freg = 1; + argstkspace = 0; + structstkspace = 0; + + /* Figure out how much new stack space is required for arguments + which don't fit in registers. Unlike the PowerOpen ABI, the + SysV ABI doesn't reserve any extra space for parameters which + are put in registers. */ + for (argno = 0; argno < nargs; argno++) { + arg = args[argno]; + type = check_typedef(VALUE_TYPE(arg)); + len = TYPE_LENGTH(type); + + if (TYPE_CODE(type) == TYPE_CODE_FLT) { + if (freg <= 8) + freg++; + else { + /* SysV ABI converts floats to doubles when placed in + memory and requires 8 byte alignment */ + if (argstkspace & 0x4) + argstkspace += 4; + argstkspace += 8; + } + } + else if (TYPE_CODE(type) == TYPE_CODE_INT && len == 8) { /* long long */ + if (greg > 9) { + greg = 11; + if (argstkspace & 0x4) + argstkspace += 4; + argstkspace += 8; + } + else { + if ((greg & 1) == 0) + greg++; + greg += 2; + } + + } + else { + if ( len > 4 + || TYPE_CODE(type) == TYPE_CODE_STRUCT + || TYPE_CODE(type) == TYPE_CODE_UNION ) { + /* Rounding to the nearest multiple of 8 may not be necessary, + but it is safe. Particularly since we don't know the + field types of the structure */ + structstkspace += round2(len,8); + } + if (greg <= 10) { + greg++; + } + else { + argstkspace += 4; + } + } + } + + sp -= argstkspace + structstkspace; + + /* Allocate space for backchain and callee's saved lr */ + sp -= 8; + + /* Make sure that we maintain 16 byte alignment */ + sp &= ~0x0f; + + /* Update %sp before proceeding any further */ + write_register (SP_REGNUM, sp); + + /* write the backchain */ + store_address(old_sp_buf, 4, sp_before_dummy); + write_memory(sp, old_sp_buf, 4); + + argoffset = 8; + structoffset = argoffset + argstkspace; + freg = 1; + greg = 3; + /* Now fill in the registers and stack... */ + for (argno = 0; argno < nargs; argno++) { + arg = args[argno]; + type = check_typedef(VALUE_TYPE(arg)); + len = TYPE_LENGTH(type); + + if (TYPE_CODE(type) == TYPE_CODE_FLT) { + if (freg <= 8) { + if (len > 8) + printf_unfiltered ( +"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno); + memcpy(®isters[REGISTER_BYTE(FP0_REGNUM + freg)], + VALUE_CONTENTS (arg), len); + freg++; + } + else { + /* SysV ABI converts floats to doubles when placed in + memory and requires 8 byte alignment */ + /* FIXME: Convert floats to doubles */ + if (argoffset & 0x4) + argoffset += 4; + write_memory (sp+argoffset, (char *) VALUE_CONTENTS (arg), len); + argoffset += 8; + } + } + else if (TYPE_CODE(type) == TYPE_CODE_INT && len == 8) { /* long long */ + if (greg > 9) { + greg = 11; + if (argoffset & 0x4) + argoffset += 4; + write_memory (sp+argoffset, (char *) VALUE_CONTENTS (arg), len); + argoffset += 8; + } + else { + if ((greg & 1) == 0) + greg++; + + memcpy (®isters[REGISTER_BYTE(greg)], + VALUE_CONTENTS (arg), 4); + memcpy (®isters[REGISTER_BYTE(greg+1)], + VALUE_CONTENTS (arg) + 4, 4); + greg += 2; + } + } + else { + char val_buf[4]; + if ( len > 4 + || TYPE_CODE(type) == TYPE_CODE_STRUCT + || TYPE_CODE(type) == TYPE_CODE_UNION ) { + + write_memory(sp+structoffset, VALUE_CONTENTS(arg), len); + store_address(val_buf, 4, sp+structoffset); + structoffset += round2(len,8); + } + else { + memset(val_buf, 0, 4); + memcpy(val_buf, VALUE_CONTENTS(arg), len); + } + if (greg <= 10) { + *(int*)®isters[REGISTER_BYTE(greg)] = 0; + memcpy (®isters[REGISTER_BYTE(greg)], val_buf, 4); + greg++; + } + else { + write_memory(sp+argoffset, val_buf, 4); + argoffset += 4; + } + } + } + + target_store_registers (-1); + return sp; +} + + +/* a given return value in `regbuf' with a type `valtype', extract and copy its + value into `valbuf' */ + +void +extract_return_value (valtype, regbuf, valbuf) + struct type *valtype; + char regbuf[REGISTER_BYTES]; + char *valbuf; +{ + int offset = 0; + + if (TYPE_CODE (valtype) == TYPE_CODE_FLT) { + + double dd; float ff; + /* floats and doubles are returned in fpr1. fpr's have a size of 8 bytes. + We need to truncate the return value into float size (4 byte) if + necessary. */ + + if (TYPE_LENGTH (valtype) > 4) /* this is a double */ + memcpy (valbuf, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)], + TYPE_LENGTH (valtype)); + else { /* float */ + memcpy (&dd, ®buf[REGISTER_BYTE (FP0_REGNUM + 1)], 8); + ff = (float)dd; + memcpy (valbuf, &ff, sizeof(float)); + } + } + else { + /* return value is copied starting from r3. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN + && TYPE_LENGTH (valtype) < REGISTER_RAW_SIZE (3)) + offset = REGISTER_RAW_SIZE (3) - TYPE_LENGTH (valtype); + + memcpy (valbuf, regbuf + REGISTER_BYTE (3) + offset, + TYPE_LENGTH (valtype)); + } +} + + +/* keep structure return address in this variable. + FIXME: This is a horrid kludge which should not be allowed to continue + living. This only allows a single nested call to a structure-returning + function. Come on, guys! -- gnu@cygnus.com, Aug 92 */ + +CORE_ADDR rs6000_struct_return_address; + +/* Determines whether the function FI has a frame on the stack or not. */ + +int +frameless_function_invocation (fi) + struct frame_info *fi; +{ + CORE_ADDR func_start; + struct rs6000_framedata fdata; + + if (fi->next != NULL && !fi->next->signal_handler_caller) + /* Don't even think about framelessness except on the innermost frame. + or in a frame previous to a signal handler caller */ + return 0; + + if (in_sigtramp2(fi->pc, "")) + /* We'll find the wrong thing below if we search for a signal trampoline */ + return 0; + + func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET; + + /* If we failed to find the start of the function, it is a mistake + to inspect the instructions. */ + + if (!func_start) + return 0; + + (void) skip_prologue (func_start, &fdata); + return fdata.frameless; +} + +/* Return the PC saved in a frame */ + +unsigned long +frame_saved_pc (fi) + struct frame_info *fi; +{ + CORE_ADDR func_start; + struct rs6000_framedata fdata; + int frameless; + + if (fi->signal_handler_caller) + { + CORE_ADDR regs_addr = read_memory_integer (fi->frame + REGS_PTR_OFFSET, 4); + /* return the NIP in the regs array */ + return read_memory_integer(regs_addr + 4 * PT_NIP, 4); + } + + func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET; + + /* If we failed to find the start of the function, it is a mistake + to inspect the instructions. */ + if (!func_start) + return 0; + + (void) skip_prologue (func_start, &fdata); + + if (fdata.lr_offset == 0 && fi->next != NULL) + return read_memory_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE, 4); + + if (fdata.lr_offset == 0) + return read_register (LR_REGNUM); + + return read_memory_integer (rs6000_frame_chain (fi) + fdata.lr_offset, 4); +} + +/* If saved registers of frame FI are not known yet, read and cache them. + &FDATAP contains rs6000_framedata; TDATAP can be NULL, + in which case the framedata are read. */ + +static void +frame_get_cache_fsr (fi, fdatap) + struct frame_info *fi; + struct rs6000_framedata *fdatap; +{ + int ii; + CORE_ADDR frame_addr; + struct rs6000_framedata work_fdata; + + if (fi->cache_fsr) + return; + + if (fdatap == NULL) { + fdatap = &work_fdata; + (void) skip_prologue (get_pc_function_start (fi->pc), fdatap); + } + + fi->cache_fsr = (struct frame_saved_regs *) + obstack_alloc (&frame_cache_obstack, sizeof (struct frame_saved_regs)); + memset (fi->cache_fsr, '\0', sizeof (struct frame_saved_regs)); + + if (fi->prev && fi->prev->frame) + frame_addr = fi->prev->frame; + else + frame_addr = read_memory_integer (fi->frame, 4); + + /* if != -1, fdatap->saved_fpr is the smallest number of saved_fpr. + All fpr's from saved_fpr to fp31 are saved. */ + + if (fdatap->saved_fpr >= 0) { + int fpr_offset = frame_addr + fdatap->fpr_offset; + for (ii = fdatap->saved_fpr; ii < 32; ii++) { + fi->cache_fsr->regs [FP0_REGNUM + ii] = fpr_offset; + fpr_offset += 8; + } + } + + /* if != -1, fdatap->saved_gpr is the smallest number of saved_gpr. + All gpr's from saved_gpr to gpr31 are saved. */ + + if (fdatap->saved_gpr >= 0) { + int gpr_offset = frame_addr + fdatap->gpr_offset; + for (ii = fdatap->saved_gpr; ii < 32; ii++) { + fi->cache_fsr->regs [ii] = gpr_offset; + gpr_offset += 4; + } + } + + /* If != 0, fdatap->cr_offset is the offset from the frame that holds + the CR. */ + if (fdatap->cr_offset != 0) + fi->cache_fsr->regs [CR_REGNUM] = frame_addr + fdatap->cr_offset; + + /* If != 0, fdatap->lr_offset is the offset from the frame that holds + the LR. */ + if (fdatap->lr_offset != 0) + fi->cache_fsr->regs [LR_REGNUM] = frame_addr + fdatap->lr_offset; +} + +/* Return the address of a frame. This is the inital %sp value when the frame + was first allocated. For functions calling alloca(), it might be saved in + an alloca register. */ + +CORE_ADDR +frame_initial_stack_address (fi) + struct frame_info *fi; +{ + CORE_ADDR tmpaddr; + struct rs6000_framedata fdata; + struct frame_info *callee_fi; + + /* if the initial stack pointer (frame address) of this frame is known, + just return it. */ + + if (fi->initial_sp) + return fi->initial_sp; + + /* If we're in a signal handler caller, fi->frame is fine */ + if (fi->signal_handler_caller) { + fi->initial_sp = fi->frame; + return fi->initial_sp; + } + + /* find out if this function is using an alloca register.. */ + + (void) skip_prologue (get_pc_function_start (fi->pc), &fdata); + + /* if saved registers of this frame are not known yet, read and cache them. */ + + if (!fi->cache_fsr) + frame_get_cache_fsr (fi, &fdata); + + /* If no alloca register used, then fi->frame is the value of the %sp for + this frame, and it is good enough. */ + + if (fdata.alloca_reg < 0) { + fi->initial_sp = fi->frame; + return fi->initial_sp; + } + + /* This function has an alloca register. If this is the top-most frame + (with the lowest address), the value in alloca register is good. */ + + if (!fi->next) + return fi->initial_sp = read_register (fdata.alloca_reg); + + /* Otherwise, this is a caller frame. Callee has usually already saved + registers, but there are exceptions (such as when the callee + has no parameters). Find the address in which caller's alloca + register is saved. */ + + for (callee_fi = fi->next; callee_fi; callee_fi = callee_fi->next) { + + if (!callee_fi->cache_fsr) + frame_get_cache_fsr (callee_fi, NULL); + + /* this is the address in which alloca register is saved. */ + + tmpaddr = callee_fi->cache_fsr->regs [fdata.alloca_reg]; + if (tmpaddr) { + fi->initial_sp = read_memory_integer (tmpaddr, 4); + return fi->initial_sp; + } + + /* Go look into deeper levels of the frame chain to see if any one of + the callees has saved alloca register. */ + } + + /* If alloca register was not saved, by the callee (or any of its callees) + then the value in the register is still good. */ + + return fi->initial_sp = read_register (fdata.alloca_reg); +} + + +CORE_ADDR +rs6000_frame_chain (thisframe) + struct frame_info *thisframe; +{ + CORE_ADDR fp; + if (inside_entry_file ((thisframe)->pc)) + return 0; + /* The following #if 0 code should not be needed any longer because the + kernel now properly constructs the chain for the signal frame */ +#if 0 + if (thisframe->signal_handler_caller) + { + CORE_ADDR regs_addr; + regs_addr = read_memory_integer (thisframe->frame + REGS_PTR_OFFSET, 4); + /* fetch address of saved r1 from the regs array */ + fp = read_memory_integer(regs_addr + 4 * PT_R1, 4); + } + else +#endif + fp = read_memory_integer ((thisframe)->frame, 4); + + return fp; +} + +int +gdb_print_insn_powerpc (memaddr, info) + bfd_vma memaddr; + disassemble_info *info; +{ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + return print_insn_big_powerpc (memaddr, info); + else + return print_insn_little_powerpc (memaddr, info); +} + +void +init_extra_frame_info (fromleaf, fi) + int fromleaf; + struct frame_info *fi; +{ + fi->initial_sp = 0; + fi->cache_fsr = 0; + if (fi->next != 0) { + /* We're called from get_prev_frame_info; check to see if + this is a signal frame by looking to see if the pc points + at trampoline code */ + char buf[8]; + if (target_read_memory(fi->pc, buf, sizeof(buf)) != 0) + return; + if ( extract_unsigned_integer(buf,4) == INSTR_LI_R0_0x7777 + || extract_unsigned_integer(buf+4,4) == INSTR_SC ) + fi->signal_handler_caller = 1; + else + fi->signal_handler_caller = 0; + } +} + +/* Some of the following code was swiped from tm-rs6000.h. */ + +void +frame_find_saved_regs(struct frame_info *fi, struct frame_saved_regs *fsr) +{ + int ii; + CORE_ADDR frame_addr, func_start; + struct rs6000_framedata fdata; + + if (fi->signal_handler_caller) { + CORE_ADDR regs_addr = read_memory_integer (fi->frame + REGS_PTR_OFFSET, 4); + memset (fsr, '\0', sizeof (*fsr)); + fsr->regs[PC_REGNUM] = regs_addr + 4 * PT_NIP; + fsr->regs[PS_REGNUM] = regs_addr + 4 * PT_MSR; + fsr->regs[CR_REGNUM] = regs_addr + 4 * PT_CCR; + fsr->regs[LR_REGNUM] = regs_addr + 4 * PT_LNK; + fsr->regs[CTR_REGNUM] = regs_addr + 4 * PT_CTR; + fsr->regs[XER_REGNUM] = regs_addr + 4 * PT_XER; + fsr->regs[MQ_REGNUM] = regs_addr + 4 * PT_MQ; + for (ii=0; ii<32; ii++) { + fsr->regs[GP0_REGNUM+ii] = regs_addr + 4*ii; + } + for (ii=0; ii<32; ii++) { + fsr->regs[FP0_REGNUM+ii] = regs_addr + 4*ELF_NGREG + 8*ii; + } + return; + } + + /* find the start of the function and collect info about its frame. */ + + func_start = get_pc_function_start (fi->pc) + FUNCTION_START_OFFSET; + (void) skip_prologue (func_start, &fdata); + memset (fsr, '\0', sizeof (*fsr)); + + /* if there were any saved registers, figure out parent's stack pointer. */ + /* the following is true only if the frame doesn't have a call to alloca(), + FIXME. */ + if (fdata.saved_fpr == 0 && fdata.saved_gpr == 0 && + fdata.lr_offset == 0 && fdata.cr_offset == 0) { + frame_addr = 0; + + } else if (fi->prev && fi->prev->frame) { + frame_addr = fi->prev->frame; + + } else { + frame_addr = read_memory_integer (fi->frame, 4); + } + + /* if != -1, fdata.saved_fpr is the smallest number of saved_fpr. All + fpr's from saved_fpr to f31 are saved. */ + if (fdata.saved_fpr >= 0) { + int fpr_offset = frame_addr + fdata.fpr_offset; + for (ii = fdata.saved_fpr; ii < 32; ii++) { + fsr->regs [FP0_REGNUM + ii] = fpr_offset; + fpr_offset += 8; + } + } + + /* if != -1, fdata.saved_gpr is the smallest number of saved_gpr. All + gpr's from saved_gpr to r31 are saved. */ + if (fdata.saved_gpr >= 0) { + int gpr_offset = frame_addr + fdata.gpr_offset; + for (ii = fdata.saved_gpr; ii < 32; ii++) { + fsr->regs [ii] = gpr_offset; + gpr_offset += 4; + } + } + + /* If != 0, fdata.cr_offset is the offset from the frame that holds + the CR */ + if (fdata.cr_offset != 0) { + fsr->regs [CR_REGNUM] = frame_addr + fdata.cr_offset; + } + + /* If != 0, fdata.cr_offset is the offset from the frame that holds + the LR */ + if (fdata.lr_offset != 0) { + fsr->regs [LR_REGNUM] = frame_addr + fdata.lr_offset; + } +} + +void +init_frame_pc_first(int fromleaf, struct frame_info *fi) +{ + if (fromleaf) { + if ( fi->next + && fi->next->next + && fi->next->next->signal_handler_caller) { + /* next next frame is a signal handler caller... + This is a bit confusing, so an explanation is in order. + fi is the frame set we are determining pc for. fi->next + is the frameless callee of fi. And fi->next->next is the + frame of the signal trampoline code. */ + CORE_ADDR regs_addr = + read_memory_integer (fi->next->next->frame + REGS_PTR_OFFSET, 4); + fi->pc = read_memory_integer(regs_addr + 4 * PT_LNK, 4); + } + else { + /* normal leaf case; frame is at the top */ + fi->pc = SAVED_PC_AFTER_CALL(fi->next); + } + } + else { + if (fi->next) { + /* not top-most frame */ + fi->pc = FRAME_SAVED_PC(fi->next); + } + else { + /* top-most frame; just fetch current pc value */ + fi->pc = read_pc(); + } + } +} + +CORE_ADDR +skip_trampoline_code (CORE_ADDR pc) +{ + char buf[4]; + struct obj_section *sect; + struct objfile *objfile; + unsigned long insn; + CORE_ADDR plt_start = 0; + CORE_ADDR symtab = 0; + CORE_ADDR strtab = 0; + int num_slots = -1; + int reloc_index = -1; + CORE_ADDR plt_table; + CORE_ADDR reloc; + CORE_ADDR sym; + Elf32_Word symidx; + char symname[1024]; + struct minimal_symbol *msymbol; + + /* Find the section pc is in; return if not in .plt */ + sect = find_pc_section(pc); + if (!sect || strcmp(sect->the_bfd_section->name, ".plt") != 0) + return 0; + + objfile = sect->objfile; + + /* Pick up the instruction at pc. It had better be of the + form + li r11, IDX + + where IDX is an index into the plt_table. */ + + if (target_read_memory(pc, buf, 4) != 0) + return 0; + insn = extract_unsigned_integer(buf, 4); + + if ( (insn & 0xffff0000) != 0x39600000 /* li r11, VAL */ ) + return 0; + + reloc_index = (insn << 16) >> 16; + + /* Find the objfile that pc is in and obtain the information + necessary for finding the symbol name. */ + for (sect = objfile->sections; sect < objfile->sections_end; ++sect) { + const char *secname = sect->the_bfd_section->name; + if (strcmp(secname, ".plt") == 0) { + plt_start = sect->addr; + } + else if (strcmp(secname, ".rela.plt") == 0) { + num_slots = ((int) sect->endaddr - (int) sect->addr) / 12; + } + else if (strcmp(secname, ".dynsym") == 0) { + symtab = sect->addr; + } + else if (strcmp(secname, ".dynstr") == 0) { + strtab = sect->addr; + } + } + + /* Make sure we have all the information we need. */ + if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0) + return 0; + + /* Compute the value of the plt table */ + plt_table = plt_start + 72 + 8*num_slots; + + /* Get address of the relocation entry (Elf32_Rela) */ + if (target_read_memory(plt_table + reloc_index, buf, 4) != 0) + return 0; + reloc = extract_address(buf, 4); + + sect = find_pc_section(reloc); + if (!sect) + return 0; + + if (strcmp(sect->the_bfd_section->name, ".text") == 0) { + return reloc; + } + + /* Now get the r_info field which is the relocation type and symbol + index. */ + if (target_read_memory(reloc+4, buf, 4) != 0) + return 0; + symidx = extract_unsigned_integer(buf, 4); + + /* Shift out the relocation type leaving just the symbol index */ + symidx = ELF32_R_SYM(symidx); + + /* compute the address of the symbol */ + sym = symtab + symidx * sizeof(Elf32_Sym); + + /* Fetch the string table index */ + if (target_read_memory(sym, buf, 4) != 0) + return 0; + symidx = extract_unsigned_integer(buf, 4); + + /* Fetch the string; we don't know how long it is. Is it possible + that the following will fail because we're trying to fetch too + much? */ + if (target_read_memory(strtab+symidx, symname, sizeof(symname)) != 0) + return 0; + + /* This might not work right if we have multiple symbols with the + same name; the only way to really get it right is to perform + the same sort of lookup as the dynamic linker. */ + msymbol = lookup_minimal_symbol_text(symname, NULL, NULL); + if (!msymbol) + return 0; + + return SYMBOL_VALUE_ADDRESS (msymbol); +} + +/* + * Determine if pc is in a signal trampoline... + * + * Ha! That's not what this does at all. wait_for_inferior in infrun.c + * calls IN_SIGTRAMP in order to detect entry into a signal trampoline + * just after delivery of a signal. But on linux, signal trampolines + * are used for the return path only. The kernel sets things up so that + * the signal handler is called directly. + * + * If we use in_sigtramp2() in place of in_sigtramp() (see below) + * we'll (often) end up with stop_pc in the trampoline and prev_pc in + * the (now exited) handler. The code there will cause a temporary + * breakpoint to be set on prev_pc which is not very likely to get hit + * again. + * + * If this is confusing, think of it this way... the code in + * wait_for_inferior() needs to be able to detect entry into a signal + * trampoline just after a signal is delivered, not after the handler + * has been run. + * + * So, we define in_sigtramp() below to return 1 if the following is + * true: + * + * 1) The previous frame is a real signal trampoline. + * + * - and - + * + * 2) pc is at the second instruction of the corresponding handler. + * + * Why the second instruction? It seems that wait_for_inferior() + * never sees the first instruction when single stepping. When a + * signal is delivered while stepping, the next instruction that + * would've been stepped over isn't, instead a signal is delivered and + * the first instruction of the handler is stepped over instead. That + * puts us on the second instruction. + * + * IN_SIGTRAMP is called from blockframe.c as well in order to set + * the signal_handler_caller flag. Because of our strange definition + * of in_sigtramp below, we can't rely on signal_handler_caller getting + * set correctly from within blockframe.c. This is why we take pains + * to set it in init_extra_frame_info(). + */ + +int in_sigtramp(CORE_ADDR pc, char *func_name) +{ + CORE_ADDR lr; + CORE_ADDR sp; + CORE_ADDR tramp_sp; + char buf[4]; + CORE_ADDR handler; + + lr = read_register(LR_REGNUM); + if (!in_sigtramp2(lr,0)) + return 0; + + sp = read_register(SP_REGNUM); + + if (target_read_memory(sp, buf, sizeof(buf)) != 0) + return 0; + + tramp_sp = extract_unsigned_integer(buf, 4); + + if (target_read_memory(tramp_sp + __SIGNAL_FRAMESIZE + + offsetof(struct sigcontext_struct, handler), + buf, sizeof(buf)) != 0) + return 0; + + handler = extract_unsigned_integer(buf, 4); + + return (pc == handler + 4); +} + +/* + * in_sigtramp2 is how I think in_sigtramp ought to be written on this + * platform. (See above for why it is not.) I actually call it from + * a few places, so here it is. + * + * The signal handler trampoline is on the stack and consists of exactly + * two instructions. The easiest and most accurate way of determining + * whether the pc is in one of these trampolines is by inspecting the + * instructions. It'd be faster if we could find a way to do this by + * some simple address comparisons. + */ +int in_sigtramp2(CORE_ADDR pc, char *func_name) +{ + char buf[12]; + unsigned long pcinsn; + if (target_read_memory(pc-4, buf, sizeof(buf)) != 0) + return 0; + + /* extract the instruction at the pc */ + pcinsn = extract_unsigned_integer(buf+4,4); + + return ( + ( pcinsn == INSTR_LI_R0_0x7777 + && extract_unsigned_integer(buf+8,4) == INSTR_SC) + || + ( pcinsn == INSTR_SC + && extract_unsigned_integer(buf,4) == INSTR_LI_R0_0x7777) ); +} + +void +_initialize_ppclinux_tdep () +{ + tm_print_insn = gdb_print_insn_powerpc; +} Index: gnu/gdb-4.17/gdb/sol-thread.c diff -u gnu/gdb-4.17/gdb/sol-thread.c:1.1.1.1 gnu/gdb-4.17/gdb/sol-thread.c:1.2 --- gnu/gdb-4.17/gdb/sol-thread.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/sol-thread.c Tue Feb 16 15:51:07 1999 @@ -69,6 +69,22 @@ #include #include "gdbcmd.h" +#ifndef PS_CONST +#define PS_CONST const +#endif + +#ifndef PS_R_PTR +#define PS_R_PTR char * +#endif + +#ifndef PS_W_PTR +#define PS_W_PTR char * +#endif + +#ifndef PS_SIZE_T +#define PS_SIZE_T int +#endif + extern struct target_ops sol_thread_ops; /* Forward declaration */ extern struct target_ops sol_core_ops; /* Forward declaration */ @@ -962,31 +978,31 @@ nothing. */ ps_err_e -ps_pstop (const struct ps_prochandle *ph) +ps_pstop (PS_CONST struct ps_prochandle *ph) { return PS_OK; } ps_err_e -ps_pcontinue (const struct ps_prochandle *ph) +ps_pcontinue (PS_CONST struct ps_prochandle *ph) { return PS_OK; } ps_err_e -ps_lstop (const struct ps_prochandle *ph, lwpid_t lwpid) +ps_lstop (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid) { return PS_OK; } ps_err_e -ps_lcontinue (const struct ps_prochandle *ph, lwpid_t lwpid) +ps_lcontinue (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid) { return PS_OK; } ps_err_e -ps_pglobal_lookup (const struct ps_prochandle *ph, const char *ld_object_name, +ps_pglobal_lookup (PS_CONST struct ps_prochandle *ph, const char *ld_object_name, const char *ld_symbol_name, paddr_t *ld_symbol_addr) { struct minimal_symbol *ms; @@ -1046,33 +1062,37 @@ } ps_err_e -ps_pdread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) +ps_pdread (PS_CONST struct ps_prochandle *ph, paddr_t addr, + PS_R_PTR buf, PS_SIZE_T size) { - return rw_common (0, ph, addr, buf, size); + return rw_common (0, ph, addr, (char *) buf, size); } ps_err_e -ps_pdwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) +ps_pdwrite (PS_CONST struct ps_prochandle *ph, paddr_t addr, + PS_W_PTR buf, PS_SIZE_T size) { - return rw_common (1, ph, addr, buf, size); + return rw_common (1, ph, addr, (char *) buf, size); } ps_err_e -ps_ptread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) +ps_ptread (PS_CONST struct ps_prochandle *ph, paddr_t addr, + PS_R_PTR buf, PS_SIZE_T size) { - return rw_common (0, ph, addr, buf, size); + return rw_common (0, ph, addr, (char *) buf, size); } ps_err_e -ps_ptwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) +ps_ptwrite (PS_CONST struct ps_prochandle *ph, paddr_t addr, + PS_W_PTR buf, PS_SIZE_T size) { - return rw_common (1, ph, addr, buf, size); + return rw_common (1, ph, addr, (char *) buf, size); } /* Get integer regs */ ps_err_e -ps_lgetregs (const struct ps_prochandle *ph, lwpid_t lwpid, +ps_lgetregs (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset) { struct cleanup *old_chain; @@ -1095,7 +1115,7 @@ /* Set integer regs */ ps_err_e -ps_lsetregs (const struct ps_prochandle *ph, lwpid_t lwpid, +ps_lsetregs (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t gregset) { struct cleanup *old_chain; @@ -1202,7 +1222,7 @@ /* Get floating-point regs. */ ps_err_e -ps_lgetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid, +ps_lgetfpregs (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset) { struct cleanup *old_chain; @@ -1225,7 +1245,7 @@ /* Set floating-point regs. */ ps_err_e -ps_lsetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid, +ps_lsetfpregs (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid, const prfpregset_t *fpregset) { struct cleanup *old_chain; @@ -1257,8 +1277,8 @@ static struct ssd *ldt_bufp = NULL; ps_err_e -ps_lgetLDT (const struct ps_prochandle *ph, lwpid_t lwpid, - struct ssd *pldt) +ps_lgetLDT (PS_CONST struct ps_prochandle *ph, lwpid_t lwpid, + struct ssd *pldt) { gregset_t gregset; int lwp_fd; Index: gnu/gdb-4.17/gdb/solib.c diff -u gnu/gdb-4.17/gdb/solib.c:1.1.1.1 gnu/gdb-4.17/gdb/solib.c:1.3 --- gnu/gdb-4.17/gdb/solib.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/solib.c Sun May 9 07:41:21 1999 @@ -49,11 +49,15 @@ #include "command.h" #include "target.h" #include "frame.h" -#include "gnu-regex.h" #include "inferior.h" #include "environ.h" #include "language.h" #include "gdbcmd.h" +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif #define MAX_PATH_SIZE 512 /* FIXME: Should be dynamic */ @@ -876,6 +880,40 @@ #endif /* !SVR4_SHARED_LIBS */ return (lm); +} + +/* + +GLOBAL FUNCTION + + check_solib_consistency -- check solib list consistency + +SYNOPSIS + + void check_solib_consistency (void) + +DESCRIPTION + + This module is called whenever we hit a dynamic linker breakpoint + and allows us to check the consistency of our shared object list. + Without this, dynamic unlinking of objects could crash us. + */ + +void +check_solib_consistency (void) +{ + +#ifdef SVR4_SHARED_LIBS + + if ( debug_base ) { + read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug)); + /* If the shared object state is consistent, we can reload our list */ + if ( debug_copy.r_state == RT_CONSISTENT ) + clear_solib(); + } + +#endif /* SVR4_SHARED_LIBS */ + } /* Index: gnu/gdb-4.17/gdb/solib.h diff -u gnu/gdb-4.17/gdb/solib.h:1.1.1.1 gnu/gdb-4.17/gdb/solib.h:1.2 --- gnu/gdb-4.17/gdb/solib.h:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/solib.h Sun May 9 07:41:21 1999 @@ -55,6 +55,10 @@ extern char * solib_address PARAMS ((CORE_ADDR)); /* solib.c */ +/* Check shared library consistency */ + +#define CHECK_SOLIB_CONSISTENCY() check_solib_consistency() + /* If ADDR lies in a shared library, return its name. */ #define PC_SOLIB(addr) solib_address (addr) Index: gnu/gdb-4.17/gdb/source.c diff -u gnu/gdb-4.17/gdb/source.c:1.1.1.1 gnu/gdb-4.17/gdb/source.c:1.2 --- gnu/gdb-4.17/gdb/source.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/source.c Sun Dec 20 11:25:27 1998 @@ -35,11 +35,15 @@ #include #endif #include "gdbcore.h" -#include "gnu-regex.h" #include "symfile.h" #include "objfiles.h" #include "annotate.h" #include "gdbtypes.h" +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif #ifdef CRLF_SOURCE_FILES Index: gnu/gdb-4.17/gdb/sparc-nat.c diff -u gnu/gdb-4.17/gdb/sparc-nat.c:1.1.1.1 gnu/gdb-4.17/gdb/sparc-nat.c:1.2 --- gnu/gdb-4.17/gdb/sparc-nat.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/sparc-nat.c Tue Dec 1 21:52:01 1998 @@ -23,7 +23,25 @@ #include "gdbcore.h" #include + +#if defined(__sparc__) && defined(__linux__) +#undef PTRACE_GETREGS /* XXX noise from */ +#undef PTRACE_SETREGS +#undef PTRACE_GETFPREGS +#undef PTRACE_SETFPREGS +#undef PT_ATTACH +#undef PT_DETACH +#endif + #include + +#if defined(__sparc__) && defined(__linux__) +#undef PT_ATTACH +#undef PT_DETACH +#define PT_ATTACH PTRACE_SUNATTACH /* XXX reestablish "nm.h" vals */ +#define PT_DETACH PTRACE_SUNDETACH +#endif + #include #ifdef __linux__ #include Index: gnu/gdb-4.17/gdb/sparc-tdep.c diff -u gnu/gdb-4.17/gdb/sparc-tdep.c:1.1.1.1 gnu/gdb-4.17/gdb/sparc-tdep.c:1.2 --- gnu/gdb-4.17/gdb/sparc-tdep.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/sparc-tdep.c Tue Dec 1 21:52:01 1998 @@ -29,10 +29,6 @@ #include "bfd.h" #include "gdb_string.h" -#ifdef USE_PROC_FS -#include -#endif - #include "gdbcore.h" #ifdef GDB_TARGET_IS_SPARC64 @@ -1178,9 +1174,12 @@ } return find_solib_trampoline_target (pc); } + -#ifdef USE_PROC_FS /* Target dependent support for /proc */ +#if defined (USE_PROC_FS) || defined (HAVE_SYS_PROCFS_H) +#include + /* The /proc interface divides the target machine's register set up into two different sets, the general register set (gregset) and the floating point register set (fpregset). For each set, there is an ioctl to get @@ -1217,6 +1216,8 @@ */ +#if defined (HAVE_GREGSET_T) + /* 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. */ @@ -1279,8 +1280,27 @@ *(regp + R_Y) = *(int *) ®isters[REGISTER_BYTE (Y_REGNUM)]; } } +#endif /* HAVE_GREGSET_T */ -#if defined (FP0_REGNUM) +#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) + +/* XXX retrofit 2.1.x structures */ +#if !defined(ELF_CORE_COPY_REGS) +typedef struct { + union { + unsigned long pr_regs[32]; + double pr_dregs[16]; + } pr_fr; + unsigned long __unused; + unsigned long pr_fsr; + unsigned char pr_qcnt; + unsigned char pr_q_entrysize; + unsigned char pr_en; + unsigned int pr_q[64]; +} my_elf_fpregset_t; +#undef prfpregset_t +#define prfpregset_t my_elf_fpregset_t +#endif /* Given a pointer to a floating point register set in /proc format (fpregset_t *), unpack the register contents and supply them as gdb's @@ -1331,9 +1351,9 @@ } } -#endif /* defined (FP0_REGNUM) */ +#endif /* defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) */ -#endif /* USE_PROC_FS */ +#endif /* USE_PROC_FS || HAVE_FPREGSET_T */ #ifdef GET_LONGJMP_TARGET Index: gnu/gdb-4.17/gdb/symtab.c diff -u gnu/gdb-4.17/gdb/symtab.c:1.1.1.1 gnu/gdb-4.17/gdb/symtab.c:1.2 --- gnu/gdb-4.17/gdb/symtab.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/symtab.c Sun Dec 20 11:25:27 1998 @@ -29,7 +29,6 @@ #include "objfiles.h" #include "gdbcmd.h" #include "call-cmds.h" -#include "gnu-regex.h" #include "expression.h" #include "language.h" #include "demangle.h" @@ -42,6 +41,11 @@ #include "gdb_string.h" #include "gdb_stat.h" #include +#if defined __GLIBC__ && __GLIBC__ >= 2 +#include +#else +#include "gnu-regex.h" +#endif /* Prototypes for local functions */ Index: gnu/gdb-4.17/gdb/target.c diff -u gnu/gdb-4.17/gdb/target.c:1.1.1.1 gnu/gdb-4.17/gdb/target.c:1.4 --- gnu/gdb-4.17/gdb/target.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/target.c Wed Dec 2 17:07:42 1998 @@ -656,11 +656,11 @@ while (len > 0) { - tlen = MIN (len, 4 - (memaddr & 3)); offset = memaddr & 3; - errcode = target_xfer_memory (memaddr & ~3, buf, 4, 0, NULL); - if (errcode != 0) + tlen = target_read_memory_partial (memaddr & ~3, buf, 4, + &errcode); + if (tlen == 0 && errcode != 0) goto done; if (bufptr - buffer + tlen > buffer_allocated) @@ -678,6 +678,7 @@ if (buf[i + offset] == '\000') { nbytes_read += i + 1; + errcode = 0; goto done; } } @@ -1108,6 +1109,7 @@ {"SIGSOUND", "Sound completed"}, {"SIGSAK", "Secure attention"}, {"SIGPRIO", "SIGPRIO"}, + {"SIG32", "Real-time event 32"}, {"SIG33", "Real-time event 33"}, {"SIG34", "Real-time event 34"}, {"SIG35", "Real-time event 35"}, @@ -1370,7 +1372,7 @@ #if defined (REALTIME_LO) if (hostsig >= REALTIME_LO && hostsig < REALTIME_HI) return (enum target_signal) - (hostsig - 33 + (int) TARGET_SIGNAL_REALTIME_33); + (hostsig - 32 + (int) TARGET_SIGNAL_REALTIME_32); #endif return TARGET_SIGNAL_UNKNOWN; } @@ -1543,11 +1545,11 @@ default: #if defined (REALTIME_LO) - if (oursig >= TARGET_SIGNAL_REALTIME_33 + if (oursig >= TARGET_SIGNAL_REALTIME_32 && oursig <= TARGET_SIGNAL_REALTIME_63) { int retsig = - (int)oursig - (int)TARGET_SIGNAL_REALTIME_33 + REALTIME_LO; + (int)oursig - (int)TARGET_SIGNAL_REALTIME_32 + 32; if (retsig < REALTIME_HI) return retsig; } @@ -1695,6 +1697,17 @@ retval = debug_target.to_wait (pid, status); + print_waitstatus (pid, status, retval); + + return retval; +} + +void +print_waitstatus (pid, status, retval) + int pid; + struct target_waitstatus *status; + int retval; +{ fprintf_unfiltered (stderr, "target_wait (%d, status) = %d, ", pid, retval); fprintf_unfiltered (stderr, "status->kind = "); switch (status->kind) @@ -1720,8 +1733,6 @@ fprintf_unfiltered (stderr, "unknown???\n"); break; } - - return retval; } static void Index: gnu/gdb-4.17/gdb/target.h diff -u gnu/gdb-4.17/gdb/target.h:1.1.1.1 gnu/gdb-4.17/gdb/target.h:1.3 --- gnu/gdb-4.17/gdb/target.h:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/target.h Wed Dec 2 17:07:42 1998 @@ -1,5 +1,5 @@ /* Interface between GDB and target environments, including files and processes - Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1993, 1994, 1998 Free Software Foundation, Inc. Contributed by Cygnus Support. Written by John Gilmore. This file is part of GDB. @@ -47,7 +47,8 @@ file_stratum, /* Executable files, etc */ core_stratum, /* Core dump files */ download_stratum, /* Downloading of remote targets */ - process_stratum /* Executing processes */ + process_stratum, /* Executing processes */ + thread_stratum /* Executing threads */ }; /* Stuff for target_wait. */ @@ -146,45 +147,46 @@ TARGET_SIGNAL_SOUND = 42, TARGET_SIGNAL_SAK = 43, TARGET_SIGNAL_PRIO = 44, - TARGET_SIGNAL_REALTIME_33 = 45, - TARGET_SIGNAL_REALTIME_34 = 46, - TARGET_SIGNAL_REALTIME_35 = 47, - TARGET_SIGNAL_REALTIME_36 = 48, - TARGET_SIGNAL_REALTIME_37 = 49, - TARGET_SIGNAL_REALTIME_38 = 50, - TARGET_SIGNAL_REALTIME_39 = 51, - TARGET_SIGNAL_REALTIME_40 = 52, - TARGET_SIGNAL_REALTIME_41 = 53, - TARGET_SIGNAL_REALTIME_42 = 54, - TARGET_SIGNAL_REALTIME_43 = 55, - TARGET_SIGNAL_REALTIME_44 = 56, - TARGET_SIGNAL_REALTIME_45 = 57, - TARGET_SIGNAL_REALTIME_46 = 58, - TARGET_SIGNAL_REALTIME_47 = 59, - TARGET_SIGNAL_REALTIME_48 = 60, - TARGET_SIGNAL_REALTIME_49 = 61, - TARGET_SIGNAL_REALTIME_50 = 62, - TARGET_SIGNAL_REALTIME_51 = 63, - TARGET_SIGNAL_REALTIME_52 = 64, - TARGET_SIGNAL_REALTIME_53 = 65, - TARGET_SIGNAL_REALTIME_54 = 66, - TARGET_SIGNAL_REALTIME_55 = 67, - TARGET_SIGNAL_REALTIME_56 = 68, - TARGET_SIGNAL_REALTIME_57 = 69, - TARGET_SIGNAL_REALTIME_58 = 70, - TARGET_SIGNAL_REALTIME_59 = 71, - TARGET_SIGNAL_REALTIME_60 = 72, - TARGET_SIGNAL_REALTIME_61 = 73, - TARGET_SIGNAL_REALTIME_62 = 74, - TARGET_SIGNAL_REALTIME_63 = 75, + TARGET_SIGNAL_REALTIME_32 = 45, + TARGET_SIGNAL_REALTIME_33 = 46, + TARGET_SIGNAL_REALTIME_34 = 47, + TARGET_SIGNAL_REALTIME_35 = 48, + TARGET_SIGNAL_REALTIME_36 = 49, + TARGET_SIGNAL_REALTIME_37 = 50, + TARGET_SIGNAL_REALTIME_38 = 51, + TARGET_SIGNAL_REALTIME_39 = 52, + TARGET_SIGNAL_REALTIME_40 = 53, + TARGET_SIGNAL_REALTIME_41 = 54, + TARGET_SIGNAL_REALTIME_42 = 55, + TARGET_SIGNAL_REALTIME_43 = 56, + TARGET_SIGNAL_REALTIME_44 = 57, + TARGET_SIGNAL_REALTIME_45 = 58, + TARGET_SIGNAL_REALTIME_46 = 59, + TARGET_SIGNAL_REALTIME_47 = 60, + TARGET_SIGNAL_REALTIME_48 = 61, + TARGET_SIGNAL_REALTIME_49 = 62, + TARGET_SIGNAL_REALTIME_50 = 63, + TARGET_SIGNAL_REALTIME_51 = 64, + TARGET_SIGNAL_REALTIME_52 = 65, + TARGET_SIGNAL_REALTIME_53 = 66, + TARGET_SIGNAL_REALTIME_54 = 67, + TARGET_SIGNAL_REALTIME_55 = 68, + TARGET_SIGNAL_REALTIME_56 = 69, + TARGET_SIGNAL_REALTIME_57 = 70, + TARGET_SIGNAL_REALTIME_58 = 71, + TARGET_SIGNAL_REALTIME_59 = 72, + TARGET_SIGNAL_REALTIME_60 = 73, + TARGET_SIGNAL_REALTIME_61 = 74, + TARGET_SIGNAL_REALTIME_62 = 75, + TARGET_SIGNAL_REALTIME_63 = 76, #if defined(MACH) || defined(__MACH__) /* Mach exceptions */ - TARGET_EXC_BAD_ACCESS = 76, - TARGET_EXC_BAD_INSTRUCTION = 77, - TARGET_EXC_ARITHMETIC = 78, - TARGET_EXC_EMULATION = 79, - TARGET_EXC_SOFTWARE = 80, - TARGET_EXC_BREAKPOINT = 81, + TARGET_EXC_BAD_ACCESS = 77, + TARGET_EXC_BAD_INSTRUCTION = 78, + TARGET_EXC_ARITHMETIC = 79, + TARGET_EXC_EMULATION = 80, + TARGET_EXC_SOFTWARE = 81, + TARGET_EXC_BREAKPOINT = 82, #endif /* Some signal we don't know about. */ TARGET_SIGNAL_UNKNOWN, @@ -770,8 +772,10 @@ /* Functions for helping to write a native target. */ -/* This is for native targets which use a unix/POSIX-style waitstatus. */ +/* These are for native targets which use a unix/POSIX-style waitstatus. */ extern void store_waitstatus PARAMS ((struct target_waitstatus *, int)); +extern void print_waitstatus PARAMS ((int, struct target_waitstatus *, + int)); /* Convert between host signal numbers and enum target_signal's. */ extern enum target_signal target_signal_from_host PARAMS ((int)); Index: gnu/gdb-4.17/gdb/top.c diff -u gnu/gdb-4.17/gdb/top.c:1.1.1.1 gnu/gdb-4.17/gdb/top.c:1.2 --- gnu/gdb-4.17/gdb/top.c:1.1.1.1 Fri May 29 06:57:38 1998 +++ gnu/gdb-4.17/gdb/top.c Sat Dec 19 18:21:08 1998 @@ -178,6 +178,9 @@ int inhibit_gdbinit = 0; +/* If nonzero, and GDB is quitting without asking for confirmation. */ +int doing_quit_force = 0; + /* If nonzero, and GDB has been configured to be able to use windows, attempt to open them upon startup. */ @@ -2897,6 +2900,8 @@ int from_tty; { int exit_code = 0; + + doing_quit_force = 1; /* An optional expression may be used to cause gdb to terminate with the value of that expression. */ Index: gnu/gdb-4.17/gdb/valprint.c diff -u gnu/gdb-4.17/gdb/valprint.c:1.1.1.1 gnu/gdb-4.17/gdb/valprint.c:1.2 --- gnu/gdb-4.17/gdb/valprint.c:1.1.1.1 Fri May 29 06:57:39 1998 +++ gnu/gdb-4.17/gdb/valprint.c Fri May 29 07:03:39 1998 @@ -517,10 +517,25 @@ high &= 0xfffff; } else - /* Extended. We can't detect NaNs for extendeds yet. Also note - that currently extendeds get nuked to double in - REGISTER_CONVERTIBLE. */ - is_nan = 0; + { +#if TARGET_LONG_DOUBLE_BIT == 80 + unsigned expon; + + low = extract_unsigned_integer (valaddr, 4); + high = extract_unsigned_integer (valaddr + 4, 4); + expon = extract_unsigned_integer (valaddr + 8, 2); + + nonnegative = ((expon & 0x8000) == 0); + is_nan = ((expon & 0x7fff) == 0x7fff) + && ((high & 0x80000000) == 0x80000000) + && (((high & 0x7fffffff) | low) != 0); +#else + /* Extended. We can't detect NaNs for extendeds yet. Also note + that currently extendeds get nuked to double in + REGISTER_CONVERTIBLE. */ + is_nan = 0; +#endif + } if (is_nan) { @@ -551,7 +566,12 @@ fprintf_filtered (stream, "%.17g", (double) doub); else #ifdef PRINTF_HAS_LONG_DOUBLE +#if TARGET_LONG_DOUBLE_BIT == 80 + /* Looks like it is a 10 byte long double */ + fprintf_filtered (stream, "%.22Lg", doub); +#else fprintf_filtered (stream, "%.35Lg", doub); +#endif #else /* This at least wins with values that are representable as doubles */ fprintf_filtered (stream, "%.17g", (double) doub); Index: gnu/gdb-4.17/gdb/config/nm-linux.h diff -u /dev/null gnu/gdb-4.17/gdb/config/nm-linux.h:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/nm-linux.h Tue Feb 16 15:51:08 1999 @@ -0,0 +1,36 @@ +/* Native-dependent definitions for Linux. + Copyright 1999 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. */ + +/* Support for the glibc linuxthreads package. */ + +#ifdef __STDC__ +struct objfile; +#endif + +extern void +linuxthreads_new_objfile PARAMS ((struct objfile *objfile)); +#define target_new_objfile(OBJFILE) linuxthreads_new_objfile (OBJFILE) + +extern char * +linuxthreads_pid_to_str PARAMS ((int pid)); +#define target_pid_to_str(PID) linuxthreads_pid_to_str (PID) + +extern int +linuxthreads_prepare_to_proceed PARAMS ((int step)); +#define PREPARE_TO_PROCEED(STEP) linuxthreads_prepare_to_proceed (STEP) Index: gnu/gdb-4.17/gdb/config/nm-m3.h diff -u gnu/gdb-4.17/gdb/config/nm-m3.h:1.1.1.1 gnu/gdb-4.17/gdb/config/nm-m3.h:1.2 --- gnu/gdb-4.17/gdb/config/nm-m3.h:1.1.1.1 Fri May 29 06:57:40 1998 +++ gnu/gdb-4.17/gdb/config/nm-m3.h Tue Dec 1 21:52:02 1998 @@ -1,6 +1,6 @@ /* Mach 3.0 common definitions and global vars. - Copyright (C) 1992 Free Software Foundation, Inc. + Copyright (C) 1992, 1998 Free Software Foundation, Inc. This file is part of GDB. @@ -39,7 +39,7 @@ */ extern int must_suspend_thread; -#define PREPARE_TO_PROCEED(select_it) mach3_prepare_to_proceed(select_it) +#define PREPARE_TO_PROCEED(step) mach3_prepare_to_proceed(step) /* Try to get the privileged host port for authentication to machid * Index: gnu/gdb-4.17/gdb/config/tm-linux.h diff -u /dev/null gnu/gdb-4.17/gdb/config/tm-linux.h:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/tm-linux.h Tue Feb 16 15:51:08 1999 @@ -0,0 +1,36 @@ +/* Macro definitions for Linux targets. + Copyright 1999 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. */ + +/* Get __SIGRTMIN and __SIGRTMAX. Only works with glibc 2.1. */ +#include + +#ifdef __SIGRTMIN +#define REALTIME_LO __SIGRTMIN +#define REALTIME_HI (__SIGRTMAX + 1) +#else +/* Make a best guess. */ +#define REALTIME_LO 32 +#define REALTIME_HI 64 +#undef NSIG +#define NSIG 64 +#undef _NSIG +#define _NSIG 64 +#endif + +#define LINUXTHREAD_NSIG _NSIG Index: gnu/gdb-4.17/gdb/config/alpha/alpha-linux.mh diff -u gnu/gdb-4.17/gdb/config/alpha/alpha-linux.mh:1.1.1.1 gnu/gdb-4.17/gdb/config/alpha/alpha-linux.mh:1.3 --- gnu/gdb-4.17/gdb/config/alpha/alpha-linux.mh:1.1.1.1 Fri May 29 06:57:41 1998 +++ gnu/gdb-4.17/gdb/config/alpha/alpha-linux.mh Tue Feb 16 15:51:09 1999 @@ -1,9 +1,14 @@ -# Host: Little-endian Alpha running Linux +# Host: Little-endian Alpha running Linux with the GNU C library 2. + +# We have to use the one in glibc 2. +REGEX= +REGEX1= + XDEPFILES= XM_FILE= xm-alphalinux.h NAT_FILE= nm-linux.h NATDEPFILES= infptrace.o inftarg.o corelow.o core-regset.o alpha-nat.o \ - fork-child.o solib.o + fork-child.o solib.o lnx-thread.o lnx-nat.o MMALLOC = MMALLOC_CFLAGS = -DNO_MMALLOC Index: gnu/gdb-4.17/gdb/config/alpha/alpha-linuxlibc1.mh diff -u /dev/null gnu/gdb-4.17/gdb/config/alpha/alpha-linuxlibc1.mh:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/alpha/alpha-linuxlibc1.mh Sun Dec 20 11:25:28 1998 @@ -0,0 +1,10 @@ +# Host: Little-endian Alpha running Linux with the GNU C library 1. + +XDEPFILES= +XM_FILE= xm-alphalinux.h +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o inftarg.o corelow.o core-regset.o alpha-nat.o \ + fork-child.o solib.o + +MMALLOC = +MMALLOC_CFLAGS = -DNO_MMALLOC Index: gnu/gdb-4.17/gdb/config/alpha/nm-linux.h diff -u gnu/gdb-4.17/gdb/config/alpha/nm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/alpha/nm-linux.h:1.2 --- gnu/gdb-4.17/gdb/config/alpha/nm-linux.h:1.1.1.1 Fri May 29 06:57:41 1998 +++ gnu/gdb-4.17/gdb/config/alpha/nm-linux.h Tue Feb 16 15:51:09 1999 @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "nm-linux.h" + /* Figure out where the longjmp will land. We expect that we have just entered longjmp and haven't yet setup the stack frame, so the args are still in the argument regs. A0_REGNUM points at the jmp_buf structure from which we Index: gnu/gdb-4.17/gdb/config/alpha/tm-alphalinux.h diff -u gnu/gdb-4.17/gdb/config/alpha/tm-alphalinux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/alpha/tm-alphalinux.h:1.2 --- gnu/gdb-4.17/gdb/config/alpha/tm-alphalinux.h:1.1.1.1 Fri May 29 06:57:41 1998 +++ gnu/gdb-4.17/gdb/config/alpha/tm-alphalinux.h Tue Feb 16 15:51:09 1999 @@ -22,6 +22,7 @@ #define TM_LINUXALPHA_H #include "alpha/tm-alpha.h" +#include "tm-linux.h" /* Are we currently handling a signal ? */ Index: gnu/gdb-4.17/gdb/config/i386/linux.mh diff -u gnu/gdb-4.17/gdb/config/i386/linux.mh:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/linux.mh:1.5 --- gnu/gdb-4.17/gdb/config/i386/linux.mh:1.1.1.1 Fri May 29 06:57:44 1998 +++ gnu/gdb-4.17/gdb/config/i386/linux.mh Tue Feb 16 15:51:09 1999 @@ -1,7 +1,12 @@ -# Host: Intel 386 running GNU/Linux +# Host: Intel 386 running GNU/Linux with the GNU C library 2. +# We have to use the one in glibc 2. +REGEX= +REGEX1= + XM_FILE= xm-linux.h XDEPFILES= ser-tcp.o NAT_FILE= nm-linux.h -NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o core-aout.o core-regset.o i386v-nat.o i386v4-nat.o +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \ + core-aout.o core-regset.o i386lnx-nat.o lnx-thread.o lnx-nat.o Index: gnu/gdb-4.17/gdb/config/i386/linux.mt diff -u gnu/gdb-4.17/gdb/config/i386/linux.mt:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/linux.mt:1.2 --- gnu/gdb-4.17/gdb/config/i386/linux.mt:1.1.1.1 Fri May 29 06:57:44 1998 +++ gnu/gdb-4.17/gdb/config/i386/linux.mt Tue Dec 1 21:52:02 1998 @@ -3,3 +3,6 @@ TM_FILE= tm-linux.h GDBSERVER_DEPFILES= low-linux.o + +# The following define is used to get the JB_PC #define from +MT_CFLAGS= -D_GNU_SOURCE Index: gnu/gdb-4.17/gdb/config/i386/linuxlibc1.mh diff -u /dev/null gnu/gdb-4.17/gdb/config/i386/linuxlibc1.mh:1.2 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/i386/linuxlibc1.mh Tue Feb 16 15:51:09 1999 @@ -0,0 +1,8 @@ +# Host: Intel 386 running GNU/Linux with the Linux C library 5. + +XM_FILE= xm-linux.h +XDEPFILES= ser-tcp.o + +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \ + core-aout.o core-regset.o i386lnx-nat.o lnx-thread.o lnx-nat.o Index: gnu/gdb-4.17/gdb/config/i386/nm-i386sol2.h diff -u gnu/gdb-4.17/gdb/config/i386/nm-i386sol2.h:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/nm-i386sol2.h:1.2 --- gnu/gdb-4.17/gdb/config/i386/nm-i386sol2.h:1.1.1.1 Fri May 29 06:57:45 1998 +++ gnu/gdb-4.17/gdb/config/i386/nm-i386sol2.h Tue Feb 16 15:51:09 1999 @@ -21,6 +21,15 @@ #ifdef HAVE_THREAD_DB_LIB +/* ps_xxx functions in sol-thread.c have "const" which their prototypes + in doesn't have. */ +#define PS_CONST + +#define PS_R_PTR void * +#define PS_W_PTR const void * + +#define PS_SIZE_T size_t + #ifdef __STDC__ struct objfile; #endif Index: gnu/gdb-4.17/gdb/config/i386/nm-linux.h diff -u gnu/gdb-4.17/gdb/config/i386/nm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/nm-linux.h:1.5 --- gnu/gdb-4.17/gdb/config/i386/nm-linux.h:1.1.1.1 Fri May 29 06:57:44 1998 +++ gnu/gdb-4.17/gdb/config/i386/nm-linux.h Tue Feb 16 15:51:09 1999 @@ -22,6 +22,7 @@ #define NM_LINUX_H #include "i386/nm-i386v.h" +#include "nm-linux.h" /* Return sizeof user struct to callers in less machine dependent routines */ @@ -31,12 +32,10 @@ /* Tell gdb that we can attach and detach other processes */ #define ATTACH_DETACH -#define U_REGS_OFFSET 0 +#define FETCH_INFERIOR_REGISTERS -/* GNU/Linux uses the SYSV i386v-nat.c support, but doesn't have */ +#define U_REGS_OFFSET 0 -#define NO_SYS_REG_H - /* GNU/Linux supports the 386 hardware debugging registers. */ #define TARGET_HAS_HARDWARE_WATCHPOINTS @@ -50,14 +49,18 @@ #define STOPPED_BY_WATCHPOINT(W) \ i386_stopped_by_watchpoint (inferior_pid) + +/* Use these macros for watchpoint insertion/removal/deletion. */ +#define NEED_WATCHPOINT_NUMBER -/* Use these macros for watchpoint insertion/removal. */ +#define target_insert_watchpoint(num, addr, len, type) \ + i386_insert_watchpoint (inferior_pid, num, addr, len, type) -#define target_insert_watchpoint(addr, len, type) \ - i386_insert_watchpoint (inferior_pid, addr, len, type) +#define target_remove_watchpoint(num, addr, len, type) \ + i386_remove_watchpoint (inferior_pid, num, addr, len) -#define target_remove_watchpoint(addr, len, type) \ - i386_remove_watchpoint (inferior_pid, addr, len) +#define target_delete_watchpoint(num) \ + i386_delete_watchpoint (inferior_pid, num) /* We define this if link.h is available, because with ELF we use SVR4 style shared libraries. */ @@ -70,8 +73,19 @@ extern CORE_ADDR i386_stopped_by_watchpoint PARAMS ((int)); extern int -i386_insert_watchpoint PARAMS ((int pid, CORE_ADDR addr, int len, int rw)); +i386_insert_watchpoint PARAMS ((int pid, int num, CORE_ADDR addr, int len, int rw)); +extern int +i386_remove_watchpoint PARAMS ((int pid, int num, CORE_ADDR addr, int len)); + extern int -i386_remove_watchpoint PARAMS ((int pid, CORE_ADDR addr, int len)); +i386_delete_watchpoint PARAMS ((int pid, int num)); + +/* That is a kludge to work around a bug in glibc header files. */ + +#ifndef HAVE_SYS_REG_H +#include +#endif + +#undef NO_PTRACE_H #endif /* #ifndef NM_LINUX_H */ Index: gnu/gdb-4.17/gdb/config/i386/tm-i386.h diff -u gnu/gdb-4.17/gdb/config/i386/tm-i386.h:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/tm-i386.h:1.5 --- gnu/gdb-4.17/gdb/config/i386/tm-i386.h:1.1.1.1 Fri May 29 06:57:44 1998 +++ gnu/gdb-4.17/gdb/config/i386/tm-i386.h Tue Feb 16 15:51:09 1999 @@ -112,7 +112,19 @@ #define PS_REGNUM 9 /* (ps) Contains processor status */ #define FP0_REGNUM 16 /* (st0) 387 register */ -#define FPC_REGNUM 25 /* 80387 control register */ +#define FPC_REGNUM -1 /* 80387 control register */ + +#define FPCWD_REGNUM FPC_REGNUM +#define FPSWD_REGNUM -1 /* 80387 status register */ +#define FPTWD_REGNUM -1 /* 80387 tag register */ +#define FPIPO_REGNUM -1 /* 80387 instruction pointer offset register */ +#define FPIPS_REGNUM -1 /* 80387 instruction pointer selector egister */ +#define FPOOS_REGNUM -1 /* 80387 operand pointer offset register */ +#define FPOPS_REGNUM -1 /* 80387 operand pointer selector register */ + +#define INFO_REGMAP(regno) regno + +#define RUNTIME_NUM_REGS(fp) NUM_REGS /* Total amount of space needed to store our copies of the machine's register state, the array `registers'. */ Index: gnu/gdb-4.17/gdb/config/i386/tm-linux.h diff -u gnu/gdb-4.17/gdb/config/i386/tm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/tm-linux.h:1.5 --- gnu/gdb-4.17/gdb/config/i386/tm-linux.h:1.1.1.1 Fri May 29 06:57:45 1998 +++ gnu/gdb-4.17/gdb/config/i386/tm-linux.h Tue Feb 16 15:51:09 1999 @@ -1,5 +1,5 @@ /* Definitions to target GDB to GNU/Linux on 386. - Copyright 1992, 1993 Free Software Foundation, Inc. + Copyright 1992, 1993, 1998 Free Software Foundation, Inc. This file is part of GDB. @@ -20,19 +20,325 @@ #ifndef TM_LINUX_H #define TM_LINUX_H -/* FIXME: If nothing else gets added to this file, it could be removed - and configure could just use tm-i386.h instead. -fnf */ +#define I386_LINUX_TARGET #include "i386/tm-i386.h" +#include "tm-linux.h" -/* Offset to saved PC in sigcontext, from . */ -#define SIGCONTEXT_PC_OFFSET 38 +#undef NUM_FREGS +#define NUM_FREGS 15 +#undef NUM_REGS +#define NUM_REGS 32 + +extern int info_regmap []; + +#undef INFO_REGMAP +#define INFO_REGMAP(regno) info_regmap [(regno)] + +extern int get_runtime_num_regs PARAMS ((int)); + +#undef RUNTIME_NUM_REGS +#define RUNTIME_NUM_REGS(fp) get_runtime_num_regs ((fp)) + +/* Initializer for an array of names of registers. The order of the + first 19 registers, 8 general purpose registers, %eip, %eflags, + dummy, and 8 floating point registers, must match the compiler's + numbering scheme. There should be NUM_REGS strings in this + initializer. */ + +#undef REGISTER_NAMES +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "eflags", "orig_eax", \ + "st0", "st1", "st2", "st3", \ + "st4", "st5", "st6", "st7", \ + "fctrl", "fstat", "ftag", "fip", \ + "fcs", "fopoff", "fopsel", \ + "cs", "ss", "ds", "es", "fs", "gs" \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#undef FP_REGNUM +#define FP_REGNUM 5 /* (ebp) Contains address of executing stack frame */ +#undef SP_REGNUM +#define SP_REGNUM 4 /* (usp) Contains address of top of stack */ +#undef PS_REGNUM +#define PS_REGNUM 9 /* (ps) Contains processor status */ +#undef PC_REGNUM +#define PC_REGNUM 8 /* (eip) Contains program counter */ +#undef FP0_REGNUM +#define FP0_REGNUM 11 /* Floating point register 0 */ +#undef FPC_REGNUM +#define FPC_REGNUM 19 /* 80387 control register */ +#undef FPCWD_REGNUM +#define FPCWD_REGNUM FPC_REGNUM +#undef FPSWD_REGNUM +#define FPSWD_REGNUM 20 /* 80387 status register */ +#undef FPTWD_REGNUM +#define FPTWD_REGNUM 21 /* 80387 tag register */ +#undef FPIPO_REGNUM +#define FPIPO_REGNUM 22 /* 80387 instruction pointer offset register */ +#undef FPIPS_REGNUM +#define FPIPS_REGNUM 23 /* 80387 instruction pointer selector egister */ +#undef FPOOS_REGNUM +#define FPOOS_REGNUM 24 /* 80387 operand pointer offset register */ +#undef FPOPS_REGNUM +#define FPOPS_REGNUM 25 /* 80387 operand pointer selector register */ + +/* Nonzero if register N requires conversion from raw format to virtual + format. */ +#undef REGISTER_CONVERTIBLE +#define REGISTER_CONVERTIBLE(N) (((unsigned)((N) - FP0_REGNUM)) < 8) + +/* Amount of bytes needed for general purpose registers. */ +#undef GREGISTER_BYTES +#define GREGISTER_BYTES (17*4) + +/* Amount of bytes needed for floating point registers. */ +#undef FPREGISTER_BYTES +#define FPREGISTER_BYTES (7*4 + 8*10) + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + +#undef REGISTER_BYTES +#define REGISTER_BYTES (GREGISTER_BYTES + FPREGISTER_BYTES) + +/* Is register N a general purpose register? */ + +#undef GREGISTER +#define GREGISTER(N) ((N) < FP0_REGNUM || (N) >= FP0_REGNUM + NUM_FREGS) + +/* Index for general purpose register in system calls. */ + +#undef GREGISTER_BYTE +#define GREGISTER_BYTE(N) ((N) * 4) + +/* Index for floating point register in system calls. */ + +#undef FPREGISTER_BYTE +#define FPREGISTER_BYTE(N) \ + ((N) < 7 ? (N) * 4 : (((N) - 7) * 10) + 28) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#undef REGISTER_BYTE +#define REGISTER_BYTE(N) \ + ((N) < FP0_REGNUM ? (N) * 4 : REGISTER_CONVERTIBLE (N) \ + ? (((N) - FP0_REGNUM) * 10) + 44 : (((N) - FP0_REGNUM - 8) * 4) + 124) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#undef REGISTER_RAW_SIZE +#define REGISTER_RAW_SIZE(N) (REGISTER_CONVERTIBLE (N) ? 10 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ +#undef MAX_REGISTER_RAW_SIZE +#define MAX_REGISTER_RAW_SIZE 10 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ +#undef MAX_REGISTER_VIRTUAL_SIZE +#define MAX_REGISTER_VIRTUAL_SIZE 10 + +#undef TARGET_LONG_DOUBLE_BIT +#define TARGET_LONG_DOUBLE_BIT 80 + +/* Does a value fit in a register? Although a long long, double or long + double doesn't fit in a register, since x86 has to update all bytes + at once, it should be ok to just watch the first few bytes. */ +#undef VALUE_FIT_IN_REG +#define VALUE_FIT_IN_REG(v) \ + (TYPE_LENGTH (VALUE_TYPE (v)) <= REGISTER_SIZE \ + || TYPE_CODE (VALUE_TYPE (v)) == TYPE_CODE_INT \ + || TYPE_CODE (VALUE_TYPE (v)) == TYPE_CODE_FLT) + +#if defined(HAVE_LONG_DOUBLE) && defined(HOST_I386) +/* The host and target are i386 machines and the compiler supports + long doubles. Long doubles on the host therefore have the same + layout as a 387 FPU stack register. */ +#undef LD_I387 +#define LD_I387 +#endif + +#ifdef LD_I387 +/* Allow floating point numbers to be specified by + a raw long double 10 hex bytes number, + e.g. 1.0 can be input as 0x3fff8000000000000000 + */ +extern int i387_hex_long_double_input(char *p, long double *putithere); +#define HEX_LONG_DOUBLE_INPUT(base,p,len,target) \ + ((base) == 16 && (len) == 20 \ + && i387_hex_long_double_input ((p), (target))) +#endif + +#undef REGISTER_CONVERT_TO_VIRTUAL +#ifdef LD_I387 +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + if (TYPE == REGISTER_VIRTUAL_TYPE (REGNUM)) \ + { \ + memcpy (TO, FROM, TYPE_LENGTH (TYPE)); \ + } \ + else \ + { \ + long double val = *((long double *)FROM); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ + } \ +} +#else +/* Convert data from raw format for register REGNUM in buffer FROM + to virtual format with type TYPE in buffer TO. */ +extern void i387_to_double PARAMS ((char *, char *)); + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \ +{ \ + double val; \ + i387_to_double ((FROM), (char *)&val); \ + store_floating ((TO), TYPE_LENGTH (TYPE), val); \ +} +#endif + +#undef REGISTER_CONVERT_TO_RAW +#ifdef LD_I387 +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + if (TYPE == REGISTER_VIRTUAL_TYPE (REGNUM)) \ + { \ + memcpy (TO, FROM, TYPE_LENGTH (TYPE)); \ + } \ + else \ + { \ + long double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + *((long double *)TO) = val; \ + } \ +} +#else +extern void double_to_i387 PARAMS ((char *, char *)); + +#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \ +{ \ + double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \ + double_to_i387((char *)&val, (TO)); \ +} +#endif + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#undef REGISTER_VIRTUAL_TYPE +#ifdef LD_I387 +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N < FP0_REGNUM) ? builtin_type_int : builtin_type_long_double) +#else +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N < FP0_REGNUM) ? builtin_type_int : builtin_type_double) +#endif + +#define FLOAT_INFO { i387_float_info (); } + +/* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + +#define DO_REGISTERS_INFO(_regnum, fp) i386_do_registers_info(_regnum, fp) +extern void i386_do_registers_info PARAMS ((int, int)); + +extern void i387_print_register PARAMS ((char *, int)); + +extern void i387_float_info PARAMS ((void)); + +/* Size of an element of the jmp_buf. */ + +#define JB_ELEMENT_SIZE sizeof (int) + +/* Figure out where the longjmp will land. Slurp the args out of the stack. + We expect the first arg to be a pointer to the jmp_buf structure from which + we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. + This routine returns true on success */ + +extern int +get_longjmp_target PARAMS ((CORE_ADDR *)); +#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) + +/* Offset to saved PC and EFLAGS in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET (14 * 4) +#define SIGCONTEXT_EFLAGS_OFFSET (16 * 4) + +/* Size of sigcontext, from . */ +#define SIGCONTEXT_SIZE (22 * 4) + +/* Address of sigcontext given the sigtramp frame */ + +#define SIGCONTEXT_ADDR(frame) (SIGTRAMP_START((frame)->pc) - SIGCONTEXT_SIZE) + +extern CORE_ADDR i386_frame_chain PARAMS ((struct frame_info *)); + +#undef FRAME_CHAIN +#define FRAME_CHAIN(FRAME) (i386_frame_chain (FRAME)) + +/* Are we currently handling a signal ? */ + +extern int i386_linux_sigtramp_offset PARAMS ((CORE_ADDR)); +#undef IN_SIGTRAMP +#define IN_SIGTRAMP(pc, name) (i386_linux_sigtramp_offset (pc) >= 0) + +/* Get start and end address of sigtramp handler. */ + +#define SIGTRAMP_START(pc) ((pc) - i386_linux_sigtramp_offset (pc)) +#define SIGTRAMP_END(pc) (SIGTRAMP_START(pc) + 8) + +/* Determine whether a pc is the first instruction of a signal handler. */ + +#define START_SIGHANDLER(pc, func_start, func_name) \ + ((pc) == (func_start) && i386_linux_sigtramp_offset (read_sp()) == 0) + +/* Need to redefine child_resume for the step/next action in signal handlers */ + +#define CHILD_RESUME + +/* If PC contains this instruction, then we know that next instruction + will be a system call. */ + +#define SYSCALL_TRAP 0xcd80 /* int $0x80 */ +#define SYSCALL_TRAP_SIZE 2 /* SYSCALL_TRAP instruction size */ + +/* Immediately after a function call, return the saved pc. Can't always go + through the frames for this because on some machines the new frame is not + set up until the new function executes some instructions. */ + +#undef SAVED_PC_AFTER_CALL +#define SAVED_PC_AFTER_CALL(_frame) \ + (read_memory_integer (read_register (SP_REGNUM) \ + + ((_frame)->signal_handler_caller \ + ? SIGCONTEXT_PC_OFFSET + 4 : 0), 4)) + +/* Saved PC. Get it from sigcontext if within sigtramp. */ + +extern CORE_ADDR i386_linux_sigtramp_saved_pc PARAMS ((struct frame_info *)); + +#undef FRAME_SAVED_PC +#define FRAME_SAVED_PC(_frame) \ + (((_frame)->signal_handler_caller \ + ? i386_linux_sigtramp_saved_pc (_frame) \ + : read_memory_integer ((_frame)->frame + 4, 4))) + /* We need this file for the SOLIB_TRAMPOLINE stuff. */ #include "tm-sysv4.h" /* The following works around a problem with /usr/include/sys/procfs.h */ #define sys_quotactl 1 + +/* The compiler/loader puts out 0 instead of the address in N_SO symbols, + and in N_FUN symbols too. */ +#define SOFUN_ADDRESS_MAYBE_MISSING #endif /* #ifndef TM_LINUX_H */ Index: gnu/gdb-4.17/gdb/config/i386/xm-linux.h diff -u gnu/gdb-4.17/gdb/config/i386/xm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/i386/xm-linux.h:1.2 --- gnu/gdb-4.17/gdb/config/i386/xm-linux.h:1.1.1.1 Fri May 29 06:57:45 1998 +++ gnu/gdb-4.17/gdb/config/i386/xm-linux.h Fri May 29 07:03:48 1998 @@ -20,6 +20,8 @@ #ifndef XM_LINUX_H #define XM_LINUX_H +#define HOST_I386 + #define HOST_BYTE_ORDER LITTLE_ENDIAN #define HAVE_TERMIOS Index: gnu/gdb-4.17/gdb/config/powerpc/linux.mh diff -u gnu/gdb-4.17/gdb/config/powerpc/linux.mh:1.1.1.1 gnu/gdb-4.17/gdb/config/powerpc/linux.mh:1.4 --- gnu/gdb-4.17/gdb/config/powerpc/linux.mh:1.1.1.1 Fri May 29 06:57:53 1998 +++ gnu/gdb-4.17/gdb/config/powerpc/linux.mh Wed May 5 16:32:59 1999 @@ -1,11 +1,16 @@ -# Host: PowerPC, running Linux +# Host: PowerPC, running Linux with the GNU C library 2. +# We have to use the one in glibc 2. +REGEX= +REGEX1= + XM_FILE= xm-linux.h XDEPFILES= ser-tcp.o XM_CLIBS= -NAT_FILE= ../nm-sysv4.h -NATDEPFILES= solib.o corelow.o # infptrace.o inftarg.o fork-child.o core-aout.o core-regset.o +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \ + core-aout.o core-regset.o ppclnx-nat.o lnx-thread.o lnx-nat.o GDBSERVER_DEPFILES= low-linux.o Index: gnu/gdb-4.17/gdb/config/powerpc/linux.mt diff -u /dev/null gnu/gdb-4.17/gdb/config/powerpc/linux.mt:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/powerpc/linux.mt Tue Dec 1 21:52:02 1998 @@ -0,0 +1,3 @@ +# Target: Motorola PPC w/ ELF +TDEPFILES= ppclnx-tdep.o +TM_FILE= tm-linux.h Index: gnu/gdb-4.17/gdb/config/powerpc/linuxlibc1.mh diff -u /dev/null gnu/gdb-4.17/gdb/config/powerpc/linuxlibc1.mh:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/powerpc/linuxlibc1.mh Sun Dec 20 11:25:28 1998 @@ -0,0 +1,16 @@ +# Host: PowerPC, running Linux with the GNU C library 1. + +XM_FILE= xm-linux.h +XDEPFILES= ser-tcp.o +XM_CLIBS= + +NAT_FILE= nm-linux.h +NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \ + core-aout.o core-regset.o ppclnx-nat.o + +GDBSERVER_DEPFILES= low-linux.o + +# SVR4 comes standard with terminfo, and in some implementations, the +# old termcap descriptions are incomplete. So ensure that we use the +# new terminfo interface and latest terminal descriptions. +TERMCAP=-lncurses Index: gnu/gdb-4.17/gdb/config/powerpc/nm-linux.h diff -u /dev/null gnu/gdb-4.17/gdb/config/powerpc/nm-linux.h:1.2 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/powerpc/nm-linux.h Wed May 5 16:32:59 1999 @@ -0,0 +1,47 @@ +/* IBM PowerPC native-dependent macros for GDB, the GNU debugger. + Copyright 1995 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef NM_LINUX_H +#define NM_LINUX_H + +#include "nm-linux.h" + +/* Return sizeof user struct to callers in less machine dependent routines */ + +#define KERNEL_U_SIZE kernel_u_size() +extern int kernel_u_size PARAMS ((void)); + +/* Tell gdb that we can attach and detach other processes */ +#define ATTACH_DETACH + +#define U_REGS_OFFSET 0 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = ppc_register_u_addr ((blockend),(regno)); + +/* No */ + +#define NO_SYS_REG_H + +#ifdef HAVE_LINK_H +#include "solib.h" /* Support for shared libraries. */ +#define SVR4_SHARED_LIBS +#endif + +#endif /* #ifndef NM_LINUX_H */ Index: gnu/gdb-4.17/gdb/config/powerpc/tm-linux.h diff -u /dev/null gnu/gdb-4.17/gdb/config/powerpc/tm-linux.h:1.2 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/powerpc/tm-linux.h Wed May 5 16:32:59 1999 @@ -0,0 +1,136 @@ +/* Definitions to target GDB to Linux on 386. + Copyright 1992, 1993 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef TM_LINUX_H +#define TM_LINUX_H + +#include "powerpc/tm-ppc-eabi.h" +#include "tm-linux.h" + +/* We can single step on linux */ +#undef NO_SINGLE_STEP + +/* Make sure nexti gets the help it needs for debugging assembly code + without symbols */ + +#define AT_SUBROUTINE_CALL_INSTRUCTION_TARGET(prevpc,stoppc) \ + at_subroutine_call_instruction_target(prevpc,stoppc) +extern int at_subroutine_call_instruction_target(); + +/* We _want_ the SVR4 section offset calculations (see syms_from_objfile() + in symfile.c) */ +#undef IBM6000_TARGET + +/* Offset to saved PC in sigcontext, from . */ +#define SIGCONTEXT_PC_OFFSET 184 + +/* Avoid warning from redefinition in tm-sysv4.h */ +#undef SKIP_TRAMPOLINE_CODE + +/* We need this file for the SOLIB_TRAMPOLINE stuff. */ +#include "tm-sysv4.h" + +#undef SKIP_TRAMPOLINE_CODE +extern CORE_ADDR skip_trampoline_code (CORE_ADDR pc); +#define SKIP_TRAMPOLINE_CODE(pc) skip_trampoline_code (pc) + +#undef IN_SIGTRAMP +extern int in_sigtramp (CORE_ADDR pc, char *func_name); +#define IN_SIGTRAMP(pc,func_name) in_sigtramp(pc,func_name) + +#define CANNOT_FETCH_REGISTER(regno) ((regno) == MQ_REGNUM) +#define CANNOT_STORE_REGISTER(regno) ((regno) == MQ_REGNUM) + +/* Linux doesn't use the PowerOpen ABI for function pointer representation */ +#undef CONVERT_FROM_FUNC_PTR_ADDR + +#undef INIT_EXTRA_FRAME_INFO(fromleaf, fi) +#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \ + init_extra_frame_info (fromleaf, fi) +extern void init_extra_frame_info (); + +#undef FRAME_FIND_SAVED_REGS +struct frame_saved_regs; +struct frame_info; +void frame_find_saved_regs PARAMS((struct frame_info *fi, + struct frame_saved_regs *fsr)); +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ + frame_find_saved_regs (frame_info, &frame_saved_regs) + +#undef INIT_FRAME_PC_FIRST +#define INIT_FRAME_PC_FIRST(fromleaf, prev) \ + init_frame_pc_first(fromleaf, prev) + +#if 0 /* If skip_prologue() isn't too greedy, we don't need this */ +/* There is some problem with the debugging symbols generated by the + compiler such that the debugging symbol for the first line of a + function overlap with the function prologue. */ +#define PROLOGUE_FIRSTLINE_OVERLAP +#endif + + +/* CALL_DUMMY: This sequence of words is the instructions: + + mflr r0 // 0x7c0802a6 + // save fpr's + stfd r?, num(r1) // 0xd8010000 there should be 32 of this?? + // save gpr's + stm r0, num(r1) // 0xbc010000 + stu r1, num(r1) // 0x94210000 + + // load absolute address 0x12345678 to r0 + liu r0, 0x1234 // 0x3c001234 + oril r0, r0,0x5678 // 0x60005678 + mtctr r0 // 0x7c0903a6 ctr <- r0 + bctrl // 0x4e800421 jump subroutine 0x12345678 (%ctr) + cror 0xf, 0xf, 0xf // 0x4def7b82 + brpt // 0x7d821008, breakpoint + cror 0xf, 0xf, 0xf // 0x4def7b82 (for 8 byte alignment) + + + We actually start executing by loading function address first, since + the pushing of the registers is done by PUSH_DUMMY_FRAME. If this + were real code, the arguments for the function called by the `bctrl' + would be pushed between the `stu' and the `bctrl', and we could + allow it to execute through. But the arguments have to be pushed by + GDB after the PUSH_DUMMY_FRAME is done, and we cannot allow to push + the registers again. +*/ + +#undef CALL_DUMMY +#define CALL_DUMMY {0x7c0802a6, 0xd8010000, 0xbc010000, 0x94210000, \ + 0x3c001234, 0x60005678, 0x7c0903a6, 0x4e800421, \ + 0x4def7b82, 0x7d821008, 0x4def7b82 } + + +/* keep this as multiple of 8 (%sp requires 8 byte alignment) */ +#undef CALL_DUMMY_LENGTH +#define CALL_DUMMY_LENGTH 44 + +#undef CALL_DUMMY_START_OFFSET +#define CALL_DUMMY_START_OFFSET 16 + +#undef FIX_CALL_DUMMY +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ + ppclinux_fix_call_dummy (dummyname, pc, fun, nargs, args, type, gcc_p) +extern void ppclinux_fix_call_dummy PARAMS ((char *, CORE_ADDR, CORE_ADDR, + int, struct value **, + struct type *, int)); + +#endif /* #ifndef TM_LINUX_H */ Index: gnu/gdb-4.17/gdb/config/powerpc/xm-linux.h diff -u gnu/gdb-4.17/gdb/config/powerpc/xm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/powerpc/xm-linux.h:1.2 --- gnu/gdb-4.17/gdb/config/powerpc/xm-linux.h:1.1.1.1 Fri May 29 06:57:53 1998 +++ gnu/gdb-4.17/gdb/config/powerpc/xm-linux.h Tue Dec 1 21:52:02 1998 @@ -1,3 +1,49 @@ +/* Native support for linux, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989, 1992 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 XM_LINUX_H +#define XM_LINUX_H + +#define HOST_BYTE_ORDER BIG_ENDIAN + +#define HAVE_TERMIOS + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#define KERNEL_U_ADDR 0x0 + +#define NEED_POSIX_SETPGID + +/* Need R_OK etc, but USG isn't defined. */ +#include + +/* If you expect to use the mmalloc package to obtain mapped symbol files, + for now you have to specify some parameters that determine how gdb places + the mappings in it's address space. See the comments in map_to_address() + for details. This is expected to only be a short term solution. Yes it + is a kludge. + FIXME: Make this more automatic. */ + +#define MMAP_BASE_ADDRESS 0x20000000 /* First mapping here */ +#define MMAP_INCREMENT 0x01000000 /* Increment to next mapping */ + +#endif /* #ifndef XM_LINUX_H */ /* Host definitions for a Sun 4, for GDB, the GNU debugger. Copyright 1996 Free Software Foundation, Inc. Index: gnu/gdb-4.17/gdb/config/sparc/linux.mh diff -u gnu/gdb-4.17/gdb/config/sparc/linux.mh:1.1.1.1 gnu/gdb-4.17/gdb/config/sparc/linux.mh:1.3 --- gnu/gdb-4.17/gdb/config/sparc/linux.mh:1.1.1.1 Fri May 29 06:57:55 1998 +++ gnu/gdb-4.17/gdb/config/sparc/linux.mh Sun Dec 20 11:25:28 1998 @@ -1,7 +1,13 @@ -# Host: Sparcstation, running Linux +# Host: Sparcstation, running Linux with the GNU C library 2. + +# We have to use the one in glibc 2. +REGEX= +REGEX1= + XDEPFILES= ser-tcp.o XM_FILE= xm-linux.h NAT_FILE= nm-linux.h -NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o sparc-nat.o +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o \ + core-regset.o sparc-nat.o HOST_IPC=-DBSD_IPC GDBSERVER_DEPFILES= low-sparc.o Index: gnu/gdb-4.17/gdb/config/sparc/linuxlibc1.mh diff -u /dev/null gnu/gdb-4.17/gdb/config/sparc/linuxlibc1.mh:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/config/sparc/linuxlibc1.mh Sun Dec 20 11:25:29 1998 @@ -0,0 +1,9 @@ +# Host: Sparcstation, running Linux with the Linux C library 5. + +XDEPFILES= ser-tcp.o +XM_FILE= xm-linux.h +NAT_FILE= nm-linux.h +NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o \ + core-regset.o sparc-nat.o +HOST_IPC=-DBSD_IPC +GDBSERVER_DEPFILES= low-sparc.o Index: gnu/gdb-4.17/gdb/config/sparc/nm-linux.h diff -u gnu/gdb-4.17/gdb/config/sparc/nm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/sparc/nm-linux.h:1.2 --- gnu/gdb-4.17/gdb/config/sparc/nm-linux.h:1.1.1.1 Fri May 29 06:57:55 1998 +++ gnu/gdb-4.17/gdb/config/sparc/nm-linux.h Tue Dec 1 21:52:02 1998 @@ -17,18 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include "solib.h" - -#define FETCH_INFERIOR_REGISTERS - /* Return sizeof user struct to callers in less machine dependent routines */ #define KERNEL_U_SIZE kernel_u_size() extern int kernel_u_size PARAMS ((void)); + +/* Tell gdb that we can attach and detach other processes */ +#define ATTACH_DETACH + +#define FETCH_INFERIOR_REGISTERS -/* Linux is svr4ish but not that much */ -#undef USE_PROC_FS +#ifdef HAVE_LINK_H +#define SVR4_SHARED_LIBS +#include "solib.h" /* Support for shared libraries */ +#endif #define PT_ATTACH PTRACE_SUNATTACH #define PT_DETACH PTRACE_SUNDETACH Index: gnu/gdb-4.17/gdb/config/sparc/tm-linux.h diff -u gnu/gdb-4.17/gdb/config/sparc/tm-linux.h:1.1.1.1 gnu/gdb-4.17/gdb/config/sparc/tm-linux.h:1.2 --- gnu/gdb-4.17/gdb/config/sparc/tm-linux.h:1.1.1.1 Fri May 29 06:57:55 1998 +++ gnu/gdb-4.17/gdb/config/sparc/tm-linux.h Tue Dec 1 21:52:02 1998 @@ -26,4 +26,13 @@ #include "tm-sysv4.h" +#define prgreg_t greg_t +#define prgregset_t gregset_t +#define prfpregset_t fpregset_t +#define R_I7 31 +#define R_PS 32 +#define R_PC 33 +#define R_nPC 34 +#define R_Y 35 + #endif /* TM_SPARCLINUX_H */ Index: gnu/gdb-4.17/gdb/doc/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/gdb/doc/ChangeLog.linux:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/doc/ChangeLog.linux Sun Jan 24 18:48:02 1999 @@ -0,0 +1,4 @@ +Sat Jan 16 23:41:18 1999 H.J. Lu + + * Makefile.in (install-info): Handle the info files location + right. Index: gnu/gdb-4.17/gdb/doc/Makefile.in diff -u gnu/gdb-4.17/gdb/doc/Makefile.in:1.1.1.1 gnu/gdb-4.17/gdb/doc/Makefile.in:1.2 --- gnu/gdb-4.17/gdb/doc/Makefile.in:1.1.1.1 Fri May 29 06:57:55 1998 +++ gnu/gdb-4.17/gdb/doc/Makefile.in Sun Jan 24 18:48:02 1999 @@ -98,10 +98,16 @@ ps: gdb.ps gdbint.ps stabs.ps refcard.ps all-doc: info dvi ps -install-info: - for i in `cd $(srcdir) && echo *.info*` ; do \ +install-info: info + if [ -f gdb.info ]; then \ + for i in *.info* ; do \ + $(INSTALL_DATA) $$i $(infodir)/$$i ; \ + done; \ + else \ + for i in `cd $(srcdir) && echo *.info*` ; do \ $(INSTALL_DATA) $(srcdir)/$$i $(infodir)/$$i ; \ - done + done; \ + fi STAGESTUFF = *.info* gdb-all.texi GDBvn.texi *.ps *.dvi Index: gnu/gdb-4.17/gdb/testsuite/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/gdb/testsuite/ChangeLog.linux:1.2 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/gdb/testsuite/ChangeLog.linux Sun Jan 24 18:48:02 1999 @@ -0,0 +1,15 @@ +Sun Jan 10 08:23:21 1999 H.J. Lu + + * gdb.c++/cplusfuncs.cc (foofunc): Add return type. + * gdb.c++/misc.cc (small::method): Likewise. + * gdb.c++/virtfunc.cc (vvb): Likewise. + + * gdb.base/break.exp: *linux* may fail on + + "Delete all breakpoints when none" + + due to the Linux threads support. + +Thu Jun 25 19:09:56 1998 H.J. Lu + + * default.exp: Check "No registers." for "info float". Index: gnu/gdb-4.17/gdb/testsuite/gdb.base/break.exp diff -u gnu/gdb-4.17/gdb/testsuite/gdb.base/break.exp:1.1.1.1 gnu/gdb-4.17/gdb/testsuite/gdb.base/break.exp:1.2 --- gnu/gdb-4.17/gdb/testsuite/gdb.base/break.exp:1.1.1.1 Fri May 29 06:58:01 1998 +++ gnu/gdb-4.17/gdb/testsuite/gdb.base/break.exp Sun Jan 24 18:48:02 1999 @@ -61,7 +61,7 @@ send_gdb "y\n" gdb_expect { -re "$gdb_prompt $" { - setup_xfail "i*86-*-sysv4*" "sparc-sun-sunos4*" "alpha-dec-osf*" "mips-dec-ultrix*" + setup_xfail "*linux*" "i*86-*-sysv4*" "sparc-sun-sunos4*" "alpha-dec-osf*" "mips-dec-ultrix*" fail "Delete all breakpoints when none (unexpected prompt)" } timeout { fail "Delete all breakpoints when none (timeout after unexpected prompt)" } Index: gnu/gdb-4.17/gdb/testsuite/gdb.base/default.exp diff -u gnu/gdb-4.17/gdb/testsuite/gdb.base/default.exp:1.1.1.1 gnu/gdb-4.17/gdb/testsuite/gdb.base/default.exp:1.2 --- gnu/gdb-4.17/gdb/testsuite/gdb.base/default.exp:1.1.1.1 Fri May 29 06:58:01 1998 +++ gnu/gdb-4.17/gdb/testsuite/gdb.base/default.exp Thu Jun 25 13:58:31 1998 @@ -274,7 +274,7 @@ if [istarget "arm-*-coff"] then { gdb_test "info float" "Software FPU type.*mask:.*flags:.*" "info float" } else { - gdb_test "info float" "No floating point info available for this processor." "info float" + gdb_test "info float" "No registers.|No floating point info available for this processor." "info float" } #test info functions gdb_test "info functions" "All defined functions:" "info functions" Index: gnu/gdb-4.17/gdb/testsuite/gdb.c++/cplusfuncs.cc diff -u gnu/gdb-4.17/gdb/testsuite/gdb.c++/cplusfuncs.cc:1.1.1.1 gnu/gdb-4.17/gdb/testsuite/gdb.c++/cplusfuncs.cc:1.2 --- gnu/gdb-4.17/gdb/testsuite/gdb.c++/cplusfuncs.cc:1.1.1.1 Fri May 29 06:58:07 1998 +++ gnu/gdb-4.17/gdb/testsuite/gdb.c++/cplusfuncs.cc Sun Jan 24 18:48:03 1999 @@ -50,8 +50,8 @@ /**/ operator int (); /**/ operator char* (); - foofunc (int); - foofunc (int, signed char *); + int foofunc (int); + int foofunc (int, signed char *); int ifoo; const char *ccpfoo; }; Index: gnu/gdb-4.17/gdb/testsuite/gdb.c++/misc.cc diff -u gnu/gdb-4.17/gdb/testsuite/gdb.c++/misc.cc:1.1.1.1 gnu/gdb-4.17/gdb/testsuite/gdb.c++/misc.cc:1.2 --- gnu/gdb-4.17/gdb/testsuite/gdb.c++/misc.cc:1.1.1.1 Fri May 29 06:58:07 1998 +++ gnu/gdb-4.17/gdb/testsuite/gdb.c++/misc.cc Sun Jan 24 18:48:03 1999 @@ -418,6 +418,7 @@ int x; int method (); }; +int small::method () { return x + 5; Index: gnu/gdb-4.17/gdb/testsuite/gdb.c++/virtfunc.cc diff -u gnu/gdb-4.17/gdb/testsuite/gdb.c++/virtfunc.cc:1.1.1.1 gnu/gdb-4.17/gdb/testsuite/gdb.c++/virtfunc.cc:1.2 --- gnu/gdb-4.17/gdb/testsuite/gdb.c++/virtfunc.cc:1.1.1.1 Fri May 29 06:58:07 1998 +++ gnu/gdb-4.17/gdb/testsuite/gdb.c++/virtfunc.cc Sun Jan 24 18:48:03 1999 @@ -23,7 +23,7 @@ public: int vb; int fvb(); - virtual vvb(); + virtual int vvb(); }; class V : public VA, public VB Index: gnu/gdb-4.17/include/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/include/ChangeLog.linux:1.1 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/include/ChangeLog.linux Sun Jan 24 18:48:03 1999 @@ -0,0 +1,3 @@ +Wed Jan 13 07:26:44 1999 H.J. Lu (hjl@gnu.org) + + * demangle.h: Updated from egcs 1999-01-12. Index: gnu/gdb-4.17/include/demangle.h diff -u gnu/gdb-4.17/include/demangle.h:1.1.1.1 gnu/gdb-4.17/include/demangle.h:1.2 --- gnu/gdb-4.17/include/demangle.h:1.1.1.1 Fri May 29 06:58:39 1998 +++ gnu/gdb-4.17/include/demangle.h Sun Jan 24 18:48:03 1999 @@ -20,12 +20,7 @@ #if !defined (DEMANGLE_H) #define DEMANGLE_H -#ifdef IN_GCC -#include "gansidecl.h" -#define PARAMS(ARGS) PROTO(ARGS) -#else /* ! IN_GCC */ #include -#endif /* IN_GCC */ /* Options passed to cplus_demangle (in 2nd parameter). */ @@ -38,8 +33,12 @@ #define DMGL_GNU (1 << 9) #define DMGL_LUCID (1 << 10) #define DMGL_ARM (1 << 11) +#define DMGL_HP (1 << 12) /* For the HP aCC compiler; same as ARM + except for template arguments, etc. */ +#define DMGL_EDG (1 << 13) + /* If none of these are set, use 'current_demangling_style' as the default. */ -#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM) +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG) /* Enumeration of possible demangling styles. @@ -55,7 +54,9 @@ auto_demangling = DMGL_AUTO, gnu_demangling = DMGL_GNU, lucid_demangling = DMGL_LUCID, - arm_demangling = DMGL_ARM + arm_demangling = DMGL_ARM, + hp_demangling = DMGL_HP, + edg_demangling = DMGL_EDG } current_demangling_style; /* Define string names for the various demangling styles. */ @@ -64,6 +65,8 @@ #define GNU_DEMANGLING_STYLE_STRING "gnu" #define LUCID_DEMANGLING_STYLE_STRING "lucid" #define ARM_DEMANGLING_STYLE_STRING "arm" +#define HP_DEMANGLING_STYLE_STRING "hp" +#define EDG_DEMANGLING_STYLE_STRING "edg" /* Some macros to test what demangling style is active. */ @@ -71,7 +74,9 @@ #define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) #define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) #define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) -#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM) +#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) extern char * cplus_demangle PARAMS ((const char *mangled, int options)); Index: gnu/gdb-4.17/include/elf/common.h diff -u gnu/gdb-4.17/include/elf/common.h:1.1.1.1 gnu/gdb-4.17/include/elf/common.h:1.2 --- gnu/gdb-4.17/include/elf/common.h:1.1.1.1 Fri May 29 06:58:42 1998 +++ gnu/gdb-4.17/include/elf/common.h Tue Dec 1 21:52:03 1998 @@ -82,8 +82,6 @@ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ -#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ - #define EM_PARISC 15 /* HPPA */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ @@ -92,6 +90,8 @@ #define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ + /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. @@ -102,6 +102,10 @@ /* Cygnus PowerPC ELF backend. Written in the absence of an ABI. */ #define EM_CYGNUS_POWERPC 0x9025 + +/* Old version of Sparc v9, from before the ABI; this should be + removed shortly. */ +#define EM_OLD_SPARCV9 11 /* Old version of PowerPC, this should be removed shortly. */ #define EM_PPC_OLD 17 Index: gnu/gdb-4.17/libiberty/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/libiberty/ChangeLog.linux:1.2 --- /dev/null Sat Aug 21 11:58:49 1999 +++ gnu/gdb-4.17/libiberty/ChangeLog.linux Sat Aug 21 11:31:20 1999 @@ -0,0 +1,8 @@ + Sat Aug 21 11:21:38 1999 H.J. Lu (hjl@gnu.org) + + * cplus-dem.c: Updated from gcc 2.95.1. + + Wed Jan 13 07:26:44 1999 H.J. Lu (hjl@gnu.org) + + * cplus-dem.c: Updated from egcs 1999-01-12. + (mop_up): Set work->previous_argument to NULL after freeing it. Index: gnu/gdb-4.17/libiberty/cplus-dem.c diff -u gnu/gdb-4.17/libiberty/cplus-dem.c:1.1.1.1 gnu/gdb-4.17/libiberty/cplus-dem.c:1.3 --- gnu/gdb-4.17/libiberty/cplus-dem.c:1.1.1.1 Fri May 29 06:58:36 1998 +++ gnu/gdb-4.17/libiberty/cplus-dem.c Sat Aug 21 11:57:48 1999 @@ -1,8 +1,9 @@ -/* Demangler for GNU C++ - Copyright 1989, 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. +/* Demangler for GNU C++ + Copyright 1989, 91, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.uucp) Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling - + Modified by Satish Pai (pai@apollo.hp.com) for HP demangling + This file is part of the libiberty library. Libiberty is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -28,16 +29,29 @@ /* This file lives in both GCC and libiberty. When making changes, please try not to break either. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include +#include #include #include +#ifdef HAVE_STDLIB_H +#include +#else +char * malloc (); +char * realloc (); +#endif + #include #undef CURRENT_DEMANGLING_STYLE #define CURRENT_DEMANGLING_STYLE work->options + +#include "libiberty.h" -extern char *xmalloc PARAMS((unsigned)); -extern char *xrealloc PARAMS((char *, unsigned)); +#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) static const char *mystrstr PARAMS ((const char *, const char *)); @@ -82,6 +96,8 @@ static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; +static char char_str[2] = { '\000', '\000' }; + void set_cplus_marker_for_demangling (ch) int ch; @@ -89,6 +105,13 @@ cplus_markers[0] = ch; } +typedef struct string /* Beware: these aren't required to be */ +{ /* '\0' terminated. */ + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + /* Stuff that is shared between sub-routines. Using a shared structure allows cplus_demangle to be reentrant. */ @@ -96,14 +119,27 @@ { int options; char **typevec; + char **ktypevec; + char **btypevec; + int numk; + int numb; + int ksize; + int bsize; int ntypes; int typevec_size; int constructor; int destructor; int static_type; /* A static member function */ - int const_type; /* A const member function */ + int temp_start; /* index in demangled to start of template args */ + int type_quals; /* The type qualifiers. */ + int dllimported; /* Symbol imported from a PE DLL */ char **tmpl_argvec; /* Template function arguments. */ int ntmpl_args; /* The number of template function arguments. */ + int forgetting_types; /* Nonzero if we are not remembering the types + we see. */ + string* previous_argument; /* The last function argument demangled. */ + int nrepeats; /* The number of times to repeat the previous + argument. */ }; #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) @@ -192,23 +228,35 @@ {"min", "*", DMGL_ANSI} /* ansi */ + {"rm", "->*", DMGL_ANSI}, /* ansi */ + {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ }; - -typedef struct string /* Beware: these aren't required to be */ -{ /* '\0' terminated. */ - char *b; /* pointer to start of string */ - char *p; /* pointer after last character */ - char *e; /* pointer after end of allocated space */ -} string; +/* These values are used to indicate the various type varieties. + They are all non-zero so that they can be used as `success' + values. */ +typedef enum type_kind_t +{ + tk_none, + tk_pointer, + tk_reference, + tk_integral, + tk_bool, + tk_char, + tk_real +} type_kind_t; #define STRING_EMPTY(str) ((str) -> b == (str) -> p) #define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ string_prepend(str, " ");} #define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ string_append(str, " ");} +#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) + +/* The scope separator appropriate for the language being demangled. */ +#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") + #define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ #define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ @@ -217,22 +265,29 @@ static char * mop_up PARAMS ((struct work_stuff *, string *, int)); +static void +squangle_mop_up PARAMS ((struct work_stuff *)); + #if 0 static int -demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *)); +demangle_method_args PARAMS ((struct work_stuff *, const char **, string *)); #endif +static char * +internal_cplus_demangle PARAMS ((struct work_stuff *, const char *)); + +static int +demangle_template_template_parm PARAMS ((struct work_stuff *work, + const char **, string *)); + static int demangle_template PARAMS ((struct work_stuff *work, const char **, string *, - string *, int)); + string *, int, int)); static int arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **, const char **)); -static void -demangle_arm_pt PARAMS ((struct work_stuff *, const char **, int, string *)); - static int demangle_class_name PARAMS ((struct work_stuff *, const char **, string *)); @@ -256,7 +311,7 @@ gnu_special PARAMS ((struct work_stuff *, const char **, string *)); static int -arm_special PARAMS ((struct work_stuff *, const char **, string *)); +arm_special PARAMS ((const char **, string *)); static void string_need PARAMS ((string *, int)); @@ -296,13 +351,16 @@ static int consume_count PARAMS ((const char **)); -static int +static int consume_count_with_underscores PARAMS ((const char**)); static int demangle_args PARAMS ((struct work_stuff *, const char **, string *)); static int +demangle_nested_args PARAMS ((struct work_stuff*, const char**, string*)); + +static int do_type PARAMS ((struct work_stuff *, const char **, string *)); static int @@ -316,15 +374,61 @@ remember_type PARAMS ((struct work_stuff *, const char *, int)); static void +remember_Btype PARAMS ((struct work_stuff *, const char *, int, int)); + +static int +register_Btype PARAMS ((struct work_stuff *)); + +static void +remember_Ktype PARAMS ((struct work_stuff *, const char *, int)); + +static void forget_types PARAMS ((struct work_stuff *)); static void +forget_B_and_K_types PARAMS ((struct work_stuff *)); + +static void string_prepends PARAMS ((string *, string *)); + +static int +demangle_template_value_parm PARAMS ((struct work_stuff*, const char**, + string*, type_kind_t)); + +static int +do_hpacc_template_const_value PARAMS ((struct work_stuff *, const char **, string *)); + +static int +do_hpacc_template_literal PARAMS ((struct work_stuff *, const char **, string *)); + +static int +snarf_numeric_literal PARAMS ((const char **, string *)); + +/* There is a TYPE_QUAL value for each type qualifier. They can be + combined by bitwise-or to form the complete set of qualifiers for a + type. */ + +#define TYPE_UNQUALIFIED 0x0 +#define TYPE_QUAL_CONST 0x1 +#define TYPE_QUAL_VOLATILE 0x2 +#define TYPE_QUAL_RESTRICT 0x4 + +static int +code_for_qualifier PARAMS ((int)); + +static const char* +qualifier_string PARAMS ((int)); + +static const char* +demangle_qualifier PARAMS ((int)); + +/* Translate count to integer, consuming tokens in the process. + Conversion terminates on the first non-digit character. + + Trying to consume something that isn't a count results in no + consumption of input and a return of -1. -/* Translate count to integer, consuming tokens in the process. - Conversion terminates on the first non-digit character. - Trying to consume something that isn't a count results in - no consumption of input and a return of 0. */ + Overflow consumes the rest of the digits, and returns -1. */ static int consume_count (type) @@ -332,17 +436,34 @@ { int count = 0; - while (isdigit (**type)) + if (! isdigit ((unsigned char)**type)) + return -1; + + while (isdigit ((unsigned char)**type)) { count *= 10; + + /* Check for overflow. + We assume that count is represented using two's-complement; + no power of two is divisible by ten, so if an overflow occurs + when multiplying by ten, the result will not be a multiple of + ten. */ + if ((count % 10) != 0) + { + while (isdigit ((unsigned char) **type)) + (*type)++; + return -1; + } + count += **type - '0'; (*type)++; } + return (count); } -/* Like consume_count, but for counts that are preceeded and followed +/* Like consume_count, but for counts that are preceded and followed by '_' if they are greater than 10. Also, -1 is returned for failure, since 0 can be a valid value. */ @@ -355,21 +476,21 @@ if (**mangled == '_') { (*mangled)++; - if (!isdigit (**mangled)) + if (!isdigit ((unsigned char)**mangled)) return -1; idx = consume_count (mangled); if (**mangled != '_') /* The trailing underscore was missing. */ return -1; - + (*mangled)++; } else { if (**mangled < '0' || **mangled > '9') return -1; - + idx = **mangled - '0'; (*mangled)++; } @@ -377,13 +498,91 @@ return idx; } +/* C is the code for a type-qualifier. Return the TYPE_QUAL + corresponding to this qualifier. */ + +static int +code_for_qualifier (c) + int c; +{ + switch (c) + { + case 'C': + return TYPE_QUAL_CONST; + + case 'V': + return TYPE_QUAL_VOLATILE; + + case 'u': + return TYPE_QUAL_RESTRICT; + + default: + break; + } + + /* C was an invalid qualifier. */ + abort (); +} + +/* Return the string corresponding to the qualifiers given by + TYPE_QUALS. */ + +static const char* +qualifier_string (type_quals) + int type_quals; +{ + switch (type_quals) + { + case TYPE_UNQUALIFIED: + return ""; + + case TYPE_QUAL_CONST: + return "const"; + + case TYPE_QUAL_VOLATILE: + return "volatile"; + + case TYPE_QUAL_RESTRICT: + return "__restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: + return "const volatile"; + + case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: + return "const __restrict"; + + case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "volatile __restrict"; + + case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: + return "const volatile __restrict"; + + default: + break; + } + + /* TYPE_QUALS was an invalid qualifier set. */ + abort (); +} + +/* C is the code for a type-qualifier. Return the string + corresponding to this qualifier. This function should only be + called with a valid qualifier code. */ + +static const char* +demangle_qualifier (c) + int c; +{ + return qualifier_string (code_for_qualifier (c)); +} + int cplus_demangle_opname (opname, result, options) const char *opname; char *result; int options; { - int len, i, len1, ret; + int len, len1, ret; string type; struct work_stuff work[1]; const char *tem; @@ -391,8 +590,9 @@ len = strlen(opname); result[0] = '\0'; ret = 0; + memset ((char *) work, 0, sizeof (work)); work->options = options; - + if (opname[0] == '_' && opname[1] == '_' && opname[2] == 'o' && opname[3] == 'p') { @@ -414,6 +614,7 @@ if (opname[4] == '\0') { /* Operator. */ + size_t i; for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { if (strlen (optable[i].in) == 2 @@ -431,6 +632,7 @@ if (opname[2] == 'a' && opname[5] == '\0') { /* Assignment. */ + size_t i; for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { if (strlen (optable[i].in) == 3 @@ -440,12 +642,12 @@ strcat (result, optable[i].out); ret = 1; break; - } + } } } } } - else if (len >= 3 + else if (len >= 3 && opname[0] == 'o' && opname[1] == 'p' && strchr (cplus_markers, opname[2]) != NULL) @@ -454,10 +656,11 @@ if (len >= 10 /* op$assign_ */ && memcmp (opname + 3, "assign_", 7) == 0) { + size_t i; for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { len1 = len - 10; - if (strlen (optable[i].in) == len1 + if ((int) strlen (optable[i].in) == len1 && memcmp (optable[i].in, opname + 10, len1) == 0) { strcat (result, "operator"); @@ -470,10 +673,11 @@ } else { + size_t i; for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { len1 = len - 3; - if (strlen (optable[i].in) == len1 + if ((int) strlen (optable[i].in) == len1 && memcmp (optable[i].in, opname + 3, len1) == 0) { strcat (result, "operator"); @@ -497,6 +701,7 @@ ret = 1; } } + squangle_mop_up (work); return ret; } @@ -511,13 +716,13 @@ const char *opname; int options; { - int i; + size_t i; int len; len = strlen (opname); for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { - if (strlen (optable[i].out) == len + if ((int) strlen (optable[i].out) == len && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) && memcmp (optable[i].out, opname, len) == 0) return optable[i].in; @@ -540,7 +745,7 @@ DMGL_PARAMS Function parameters are included. For example, - + cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" cplus_demangle ("foo__1Ai", 0) => "A::foo" @@ -558,18 +763,45 @@ const char *mangled; int options; { + char *ret; + struct work_stuff work[1]; + memset ((char *) work, 0, sizeof (work)); + work -> options = options; + if ((work -> options & DMGL_STYLE_MASK) == 0) + work -> options |= (int) current_demangling_style & DMGL_STYLE_MASK; + + ret = internal_cplus_demangle (work, mangled); + squangle_mop_up (work); + return (ret); +} + + +/* This function performs most of what cplus_demangle use to do, but + to be able to demangle a name with a B, K or n code, we need to + have a longer term memory of what types have been seen. The original + now intializes and cleans up the squangle code info, while internal + calls go directly to this routine to avoid resetting that info. */ + +static char * +internal_cplus_demangle (work, mangled) + struct work_stuff *work; + const char *mangled; +{ + string decl; int success = 0; - struct work_stuff work[1]; char *demangled = NULL; + int s1,s2,s3,s4; + s1 = work->constructor; + s2 = work->destructor; + s3 = work->static_type; + s4 = work->type_quals; + work->constructor = work->destructor = 0; + work->type_quals = TYPE_UNQUALIFIED; + work->dllimported = 0; if ((mangled != NULL) && (*mangled != '\0')) { - memset ((char *) work, 0, sizeof (work)); - work -> options = options; - if ((work->options & DMGL_STYLE_MASK) == 0) - work->options |= (int)current_demangling_style & DMGL_STYLE_MASK; - string_init (&decl); /* First check to see if gnu style demangling is active and if the @@ -593,19 +825,48 @@ } if (work->constructor == 2) { - string_prepend(&decl, "global constructors keyed to "); + string_prepend (&decl, "global constructors keyed to "); work->constructor = 0; } else if (work->destructor == 2) { - string_prepend(&decl, "global destructors keyed to "); + string_prepend (&decl, "global destructors keyed to "); work->destructor = 0; } + else if (work->dllimported == 1) + { + string_prepend (&decl, "import stub for "); + work->dllimported = 0; + } demangled = mop_up (work, &decl, success); } + work->constructor = s1; + work->destructor = s2; + work->static_type = s3; + work->type_quals = s4; return (demangled); } + +/* Clear out and squangling related storage */ +static void +squangle_mop_up (work) + struct work_stuff *work; +{ + /* clean up the B and K type mangling types. */ + forget_B_and_K_types (work); + if (work -> btypevec != NULL) + { + free ((char *) work -> btypevec); + } + if (work -> ktypevec != NULL) + { + free ((char *) work -> ktypevec); + } +} + +/* Clear out any mangled storage */ + static char * mop_up (work, declp, success) struct work_stuff *work; @@ -615,11 +876,13 @@ char *demangled = NULL; /* Discard the remembered types, if any. */ - + forget_types (work); if (work -> typevec != NULL) { free ((char *) work -> typevec); + work -> typevec = NULL; + work -> typevec_size = 0; } if (work->tmpl_argvec) { @@ -628,13 +891,20 @@ for (i = 0; i < work->ntmpl_args; i++) if (work->tmpl_argvec[i]) free ((char*) work->tmpl_argvec[i]); - + free ((char*) work->tmpl_argvec); + work->tmpl_argvec = NULL; + } + if (work->previous_argument) + { + string_delete (work->previous_argument); + free ((char*) work->previous_argument); + work->previous_argument = NULL; } /* If demangling was successful, ensure that the demangled string is null terminated and return it. Otherwise, free the demangling decl. */ - + if (!success) { string_delete (declp); @@ -699,16 +969,22 @@ oldmangled = *mangled; success = demangle_qualified (work, mangled, declp, 1, 0); if (success) - { - remember_type (work, oldmangled, *mangled - oldmangled); - } + remember_type (work, oldmangled, *mangled - oldmangled); + if (AUTO_DEMANGLING || GNU_DEMANGLING) + expect_func = 1; + oldmangled = NULL; + break; + + case 'K': + oldmangled = *mangled; + success = demangle_qualified (work, mangled, declp, 1, 0); if (AUTO_DEMANGLING || GNU_DEMANGLING) { expect_func = 1; } oldmangled = NULL; break; - + case 'S': /* Static member function */ if (oldmangled == NULL) @@ -720,36 +996,70 @@ break; case 'C': - /* a const member function */ + case 'V': + case 'u': + work->type_quals |= code_for_qualifier (**mangled); + + /* a qualified member function */ if (oldmangled == NULL) - { - oldmangled = *mangled; - } + oldmangled = *mangled; (*mangled)++; - work -> const_type = 1; + break; + + case 'L': + /* Local class name follows after "Lnnn_" */ + if (HP_DEMANGLING) + { + while (**mangled && (**mangled != '_')) + (*mangled)++; + if (!**mangled) + success = 0; + else + (*mangled)++; + } + else + success = 0; break; - + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (oldmangled == NULL) { oldmangled = *mangled; } + work->temp_start = -1; /* uppermost call to demangle_class */ success = demangle_class (work, mangled, declp); if (success) { remember_type (work, oldmangled, *mangled - oldmangled); } - if (AUTO_DEMANGLING || GNU_DEMANGLING) + if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) { - expect_func = 1; + /* EDG and others will have the "F", so we let the loop cycle + if we are looking at one. */ + if (**mangled != 'F') + expect_func = 1; } oldmangled = NULL; break; - + + case 'B': + { + string s; + success = do_type (work, mangled, &s); + if (success) + { + string_append (&s, SCOPE_STRING (work)); + string_prepends (declp, &s); + } + oldmangled = NULL; + expect_func = 1; + } + break; + case 'F': /* Function */ - /* ARM style demangling includes a specific 'F' character after + /* ARM/HP style demangling includes a specific 'F' character after the class name. For GNU style, it is just implied. So we can safely just consume any 'F' at this point and be compatible with either style. */ @@ -758,32 +1068,45 @@ func_done = 1; (*mangled)++; - /* For lucid/ARM style we have to forget any types we might + /* For lucid/ARM/HP style we have to forget any types we might have remembered up to this point, since they were not argument types. GNU style considers all types seen as available for back references. See comment in demangle_args() */ - if (LUCID_DEMANGLING || ARM_DEMANGLING) + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) { forget_types (work); } success = demangle_args (work, mangled, declp); + /* After picking off the function args, we expect to either + find the function return type (preceded by an '_') or the + end of the string. */ + if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') + { + ++(*mangled); + /* At this level, we do not care about the return type. */ + success = do_type (work, mangled, &tname); + string_delete (&tname); + } + break; - + case 't': /* G++ Template */ - string_init(&trawname); + string_init(&trawname); string_init(&tname); if (oldmangled == NULL) { oldmangled = *mangled; } - success = demangle_template (work, mangled, &tname, &trawname, 1); + success = demangle_template (work, mangled, &tname, + &trawname, 1, 1); if (success) { remember_type (work, oldmangled, *mangled - oldmangled); } - string_append(&tname, (work -> options & DMGL_JAVA) ? "." : "::"); + string_append (&tname, SCOPE_STRING (work)); + string_prepends(declp, &tname); if (work -> destructor & 1) { @@ -803,7 +1126,7 @@ break; case '_': - if (GNU_DEMANGLING && expect_return_type) + if (GNU_DEMANGLING && expect_return_type) { /* Read the return type. */ string return_type; @@ -823,14 +1146,25 @@ a mangled name that is either bogus, or has been mangled by some algorithm we don't know how to deal with. So just reject the entire demangling. */ - success = 0; + /* However, "_nnn" is an expected suffix for alternate entry point + numbered nnn for a function, with HP aCC, so skip over that + without reporting failure. pai/1997-09-04 */ + if (HP_DEMANGLING) + { + (*mangled)++; + while (**mangled && isdigit ((unsigned char)**mangled)) + (*mangled)++; + } + else + success = 0; break; case 'H': - if (GNU_DEMANGLING) + if (GNU_DEMANGLING) { /* A G++ template function. Read the template arguments. */ - success = demangle_template (work, mangled, declp, 0, 0); + success = demangle_template (work, mangled, declp, 0, 0, + 0); if (!(work->constructor & 1)) expect_return_type = 1; (*mangled)++; @@ -838,7 +1172,7 @@ } else /* fall through */ - ; + {;} default: if (AUTO_DEMANGLING || GNU_DEMANGLING) @@ -852,7 +1186,7 @@ { /* Non-GNU demanglers use a specific token to mark the start of the outermost function argument tokens. Typically 'F', - for ARM-demangling, for example. So if we find something + for ARM/HP-demangling, for example. So if we find something we are not prepared for, it must be an error. */ success = 0; } @@ -865,6 +1199,10 @@ if (success && expect_func) { func_done = 1; + if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) + { + forget_types (work); + } success = demangle_args (work, mangled, declp); /* Since template include the mangling of their return types, we must set expect_func to 0 so that we don't try do @@ -880,20 +1218,23 @@ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and bar__3fooi is 'foo::bar(int)'. We get here when we find the first case, and need to ensure that the '(void)' gets added to - the current declp. Note that with ARM, the first case + the current declp. Note that with ARM/HP, the first case represents the name of a static data member 'foo::bar', which is in the current declp, so we leave it alone. */ success = demangle_args (work, mangled, declp); } - } - if (success && work -> static_type && PRINT_ARG_TYPES) - { - string_append (declp, " static"); } - if (success && work -> const_type && PRINT_ARG_TYPES) + if (success && PRINT_ARG_TYPES) { - string_append (declp, " const"); + if (work->static_type) + string_append (declp, " static"); + if (work->type_quals != TYPE_UNQUALIFIED) + { + APPEND_BLANK (declp); + string_append (declp, qualifier_string (work->type_quals)); + } } + return (success); } @@ -923,47 +1264,369 @@ #endif static int -demangle_template (work, mangled, tname, trawname, is_type) +demangle_template_template_parm (work, mangled, tname) struct work_stuff *work; const char **mangled; string *tname; +{ + int i; + int r; + int need_comma = 0; + int success = 1; + string temp; + + string_append (tname, "template <"); + /* get size of template parameter list */ + if (get_count (mangled, &r)) + { + for (i = 0; i < r; i++) + { + if (need_comma) + { + string_append (tname, ", "); + } + + /* Z for type parameters */ + if (**mangled == 'Z') + { + (*mangled)++; + string_append (tname, "class"); + } + /* z for template parameters */ + else if (**mangled == 'z') + { + (*mangled)++; + success = + demangle_template_template_parm (work, mangled, tname); + if (!success) + { + break; + } + } + else + { + /* temp is initialized in do_type */ + success = do_type (work, mangled, &temp); + if (success) + { + string_appends (tname, &temp); + } + string_delete(&temp); + if (!success) + { + break; + } + } + need_comma = 1; + } + + } + if (tname->p[-1] == '>') + string_append (tname, " "); + string_append (tname, "> class"); + return (success); +} + +static int +demangle_integral_value (work, mangled, s) + struct work_stuff *work; + const char** mangled; + string* s; +{ + int success; + + if (**mangled == 'E') + { + int need_operator = 0; + + success = 1; + string_appendn (s, "(", 1); + (*mangled)++; + while (success && **mangled != 'W' && **mangled != '\0') + { + if (need_operator) + { + size_t i; + size_t len; + + success = 0; + + len = strlen (*mangled); + + for (i = 0; + i < sizeof (optable) / sizeof (optable [0]); + ++i) + { + size_t l = strlen (optable[i].in); + + if (l <= len + && memcmp (optable[i].in, *mangled, l) == 0) + { + string_appendn (s, " ", 1); + string_append (s, optable[i].out); + string_appendn (s, " ", 1); + success = 1; + (*mangled) += l; + break; + } + } + + if (!success) + break; + } + else + need_operator = 1; + + success = demangle_template_value_parm (work, mangled, s, + tk_integral); + } + + if (**mangled != 'W') + success = 0; + else + { + string_appendn (s, ")", 1); + (*mangled)++; + } + } + else if (**mangled == 'Q' || **mangled == 'K') + success = demangle_qualified (work, mangled, s, 0, 1); + else + { + success = 0; + + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + while (isdigit ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + success = 1; + } + } + + return success; +} + +static int +demangle_template_value_parm (work, mangled, s, tk) + struct work_stuff *work; + const char **mangled; + string* s; + type_kind_t tk; +{ + int success = 1; + + if (**mangled == 'Y') + { + /* The next argument is a template parameter. */ + int idx; + + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return -1; + if (work->tmpl_argvec) + string_append (s, work->tmpl_argvec[idx]); + else + { + char buf[10]; + sprintf(buf, "T%d", idx); + string_append (s, buf); + } + } + else if (tk == tk_integral) + success = demangle_integral_value (work, mangled, s); + else if (tk == tk_char) + { + char tmp[2]; + int val; + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + string_appendn (s, "'", 1); + val = consume_count(mangled); + if (val <= 0) + success = 0; + else + { + tmp[0] = (char)val; + tmp[1] = '\0'; + string_appendn (s, &tmp[0], 1); + string_appendn (s, "'", 1); + } + } + else if (tk == tk_bool) + { + int val = consume_count (mangled); + if (val == 0) + string_appendn (s, "false", 5); + else if (val == 1) + string_appendn (s, "true", 4); + else + success = 0; + } + else if (tk == tk_real) + { + if (**mangled == 'm') + { + string_appendn (s, "-", 1); + (*mangled)++; + } + while (isdigit ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + if (**mangled == '.') /* fraction */ + { + string_appendn (s, ".", 1); + (*mangled)++; + while (isdigit ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + if (**mangled == 'e') /* exponent */ + { + string_appendn (s, "e", 1); + (*mangled)++; + while (isdigit ((unsigned char)**mangled)) + { + string_appendn (s, *mangled, 1); + (*mangled)++; + } + } + } + else if (tk == tk_pointer || tk == tk_reference) + { + if (**mangled == 'Q') + success = demangle_qualified (work, mangled, s, + /*isfuncname=*/0, + /*append=*/1); + else + { + int symbol_len = consume_count (mangled); + if (symbol_len == -1) + return -1; + if (symbol_len == 0) + string_appendn (s, "0", 1); + else + { + char *p = xmalloc (symbol_len + 1), *q; + strncpy (p, *mangled, symbol_len); + p [symbol_len] = '\0'; + /* We use cplus_demangle here, rather than + internal_cplus_demangle, because the name of the entity + mangled here does not make use of any of the squangling + or type-code information we have built up thus far; it is + mangled independently. */ + q = cplus_demangle (p, work->options); + if (tk == tk_pointer) + string_appendn (s, "&", 1); + /* FIXME: Pointer-to-member constants should get a + qualifying class name here. */ + if (q) + { + string_append (s, q); + free (q); + } + else + string_append (s, p); + free (p); + } + *mangled += symbol_len; + } + } + + return success; +} + +/* Demangle the template name in MANGLED. The full name of the + template (e.g., S) is placed in TNAME. The name without the + template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is + non-NULL. If IS_TYPE is nonzero, this template is a type template, + not a function template. If both IS_TYPE and REMEMBER are nonzero, + the tmeplate is remembered in the list of back-referenceable + types. */ + +static int +demangle_template (work, mangled, tname, trawname, is_type, remember) + struct work_stuff *work; + const char **mangled; + string *tname; string *trawname; int is_type; + int remember; { int i; - int is_pointer; - int is_real; - int is_integral; - int is_char; - int is_bool; int r; int need_comma = 0; int success = 0; - int done; - const char *old_p; const char *start; - int symbol_len; int is_java_array = 0; string temp; + int bindex = 0; (*mangled)++; if (is_type) { + if (remember) + bindex = register_Btype (work); start = *mangled; /* get template name */ - if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r) + if (**mangled == 'z') { - return (0); + int idx; + (*mangled)++; + (*mangled)++; + + idx = consume_count_with_underscores (mangled); + if (idx == -1 + || (work->tmpl_argvec && idx >= work->ntmpl_args) + || consume_count_with_underscores (mangled) == -1) + return (0); + + if (work->tmpl_argvec) + { + string_append (tname, work->tmpl_argvec[idx]); + if (trawname) + string_append (trawname, work->tmpl_argvec[idx]); + } + else + { + char buf[10]; + sprintf(buf, "T%d", idx); + string_append (tname, buf); + if (trawname) + string_append (trawname, buf); + } } - if (trawname) - string_appendn (trawname, *mangled, r); - is_java_array = (work -> options & DMGL_JAVA) - && strncmp (*mangled, "JArray1Z", 8) == 0; - if (! is_java_array) + else { - string_appendn (tname, *mangled, r); + if ((r = consume_count (mangled)) <= 0 + || (int) strlen (*mangled) < r) + { + return (0); + } + is_java_array = (work -> options & DMGL_JAVA) + && strncmp (*mangled, "JArray1Z", 8) == 0; + if (! is_java_array) + { + string_appendn (tname, *mangled, r); + } + if (trawname) + string_appendn (trawname, *mangled, r); + *mangled += r; } - *mangled += r; } if (!is_java_array) string_append (tname, "<"); @@ -1011,35 +1674,46 @@ break; } } + /* z for template parameters */ + else if (**mangled == 'z') + { + int r2; + (*mangled)++; + success = demangle_template_template_parm (work, mangled, tname); + + if (success + && (r2 = consume_count (mangled)) > 0 + && (int) strlen (*mangled) >= r2) + { + string_append (tname, " "); + string_appendn (tname, *mangled, r2); + if (!is_type) + { + /* Save the template argument. */ + int len = r2; + work->tmpl_argvec[i] = xmalloc (len + 1); + memcpy (work->tmpl_argvec[i], *mangled, len); + work->tmpl_argvec[i][len] = '\0'; + } + *mangled += r2; + } + if (!success) + { + break; + } + } else { string param; string* s; /* otherwise, value parameter */ - old_p = *mangled; - is_pointer = 0; - is_real = 0; - is_integral = 0; - is_char = 0; - is_bool = 0; - done = 0; + /* temp is initialized in do_type */ success = do_type (work, mangled, &temp); - /* - if (success) - { - string_appends (s, &temp); - } - */ string_delete(&temp); if (!success) - { - break; - } - /* - string_append (s, "="); - */ + break; if (!is_type) { @@ -1049,200 +1723,24 @@ else s = tname; - while (*old_p && !done) - { - switch (*old_p) - { - case 'P': - case 'p': - case 'R': - done = is_pointer = 1; - break; - case 'C': /* const */ - case 'S': /* explicitly signed [char] */ - case 'U': /* unsigned */ - case 'V': /* volatile */ - case 'F': /* function */ - case 'M': /* member function */ - case 'O': /* ??? */ - case 'J': /* complex */ - old_p++; - continue; - case 'Q': /* qualified name */ - done = is_integral = 1; - break; - case 'T': /* remembered type */ - abort (); - break; - case 'v': /* void */ - abort (); - break; - case 'x': /* long long */ - case 'l': /* long */ - case 'i': /* int */ - case 's': /* short */ - case 'w': /* wchar_t */ - done = is_integral = 1; - break; - case 'b': /* bool */ - done = is_bool = 1; - break; - case 'c': /* char */ - done = is_char = 1; - break; - case 'r': /* long double */ - case 'd': /* double */ - case 'f': /* float */ - done = is_real = 1; - break; - default: - /* it's probably user defined type, let's assume - it's integral, it seems hard to figure out - what it really is */ - done = is_integral = 1; - } - } - if (**mangled == 'Y') - { - /* The next argument is a template parameter. */ - int idx; + success = demangle_template_value_parm (work, mangled, s, + (type_kind_t) success); - (*mangled)++; - idx = consume_count_with_underscores (mangled); - if (idx == -1 - || (work->tmpl_argvec && idx >= work->ntmpl_args) - || consume_count_with_underscores (mangled) == -1) - { - success = 0; - if (!is_type) - string_delete (s); - break; - } - if (work->tmpl_argvec) - string_append (s, work->tmpl_argvec[idx]); - else - { - char buf[10]; - sprintf(buf, "T%d", idx); - string_append (s, buf); - } - } - else if (is_integral) - { - if (**mangled == 'm') - { - string_appendn (s, "-", 1); - (*mangled)++; - } - while (isdigit (**mangled)) - { - string_appendn (s, *mangled, 1); - (*mangled)++; - } - } - else if (is_char) - { - char tmp[2]; - int val; - if (**mangled == 'm') - { - string_appendn (s, "-", 1); - (*mangled)++; - } - string_appendn (s, "'", 1); - val = consume_count(mangled); - if (val == 0) - { - success = 0; - if (!is_type) - string_delete (s); - break; - } - tmp[0] = (char)val; - tmp[1] = '\0'; - string_appendn (s, &tmp[0], 1); - string_appendn (s, "'", 1); - } - else if (is_bool) - { - int val = consume_count (mangled); - if (val == 0) - string_appendn (s, "false", 5); - else if (val == 1) - string_appendn (s, "true", 4); - else - success = 0; - } - else if (is_real) - { - if (**mangled == 'm') - { - string_appendn (s, "-", 1); - (*mangled)++; - } - while (isdigit (**mangled)) - { - string_appendn (s, *mangled, 1); - (*mangled)++; - } - if (**mangled == '.') /* fraction */ - { - string_appendn (s, ".", 1); - (*mangled)++; - while (isdigit (**mangled)) - { - string_appendn (s, *mangled, 1); - (*mangled)++; - } - } - if (**mangled == 'e') /* exponent */ - { - string_appendn (s, "e", 1); - (*mangled)++; - while (isdigit (**mangled)) - { - string_appendn (s, *mangled, 1); - (*mangled)++; - } - } - } - else if (is_pointer) + if (!success) { - symbol_len = consume_count (mangled); - if (symbol_len == 0) - { - success = 0; - if (!is_type) - string_delete (s); - break; - } - if (symbol_len == 0) - string_appendn (s, "0", 1); - else - { - char *p = xmalloc (symbol_len + 1), *q; - strncpy (p, *mangled, symbol_len); - p [symbol_len] = '\0'; - q = cplus_demangle (p, work->options); - string_appendn (s, "&", 1); - if (q) - { - string_append (s, q); - free (q); - } - else - string_append (s, p); - free (p); - } - *mangled += symbol_len; + if (!is_type) + string_delete (s); + success = 0; + break; } + if (!is_type) { int len = s->p - s->b; work->tmpl_argvec[i] = xmalloc (len + 1); memcpy (work->tmpl_argvec[i], s->b, len); work->tmpl_argvec[i][len] = '\0'; - + string_appends (tname, s); string_delete (s); } @@ -1259,7 +1757,10 @@ string_append (tname, " "); string_append (tname, ">"); } - + + if (is_type && remember) + remember_Btype (work, tname->b, LEN_STRING (tname), bindex); + /* if (work -> static_type) { @@ -1283,23 +1784,58 @@ int n; const char **anchor, **args; { - /* ARM template? */ - if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__"))) + /* Check if ARM template with "__pt__" in it ("parameterized type") */ + /* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ + if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = mystrstr (mangled, "__pt__"))) { int len; *args = *anchor + 6; len = consume_count (args); + if (len == -1) + return 0; if (*args + len == mangled + n && **args == '_') { ++*args; return 1; } } + if (AUTO_DEMANGLING || EDG_DEMANGLING) + { + if ((*anchor = mystrstr (mangled, "__tm__")) + || (*anchor = mystrstr (mangled, "__ps__")) + || (*anchor = mystrstr (mangled, "__pt__"))) + { + int len; + *args = *anchor + 6; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + else if ((*anchor = mystrstr (mangled, "__S"))) + { + int len; + *args = *anchor + 3; + len = consume_count (args); + if (len == -1) + return 0; + if (*args + len == mangled + n && **args == '_') + { + ++*args; + return 1; + } + } + } + return 0; } static void -demangle_arm_pt (work, mangled, n, declp) +demangle_arm_hp_template (work, mangled, n, declp) struct work_stuff *work; const char **mangled; int n; @@ -1308,32 +1844,150 @@ const char *p; const char *args; const char *e = *mangled + n; + string arg; - /* ARM template? */ - if (arm_pt (work, *mangled, n, &p, &args)) + /* Check for HP aCC template spec: classXt1t2 where t1, t2 are + template args */ + if (HP_DEMANGLING && ((*mangled)[n] == 'X')) + { + char *start_spec_args = NULL; + + /* First check for and omit template specialization pseudo-arguments, + such as in "Spec<#1,#1.*>" */ + start_spec_args = strchr (*mangled, '<'); + if (start_spec_args && (start_spec_args - *mangled < n)) + string_appendn (declp, *mangled, start_spec_args - *mangled); + else + string_appendn (declp, *mangled, n); + (*mangled) += n + 1; + string_init (&arg); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; + string_append (declp, "<"); + while (1) + { + string_clear (&arg); + switch (**mangled) + { + case 'T': + /* 'T' signals a type parameter */ + (*mangled)++; + if (!do_type (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'U': + case 'S': + /* 'U' or 'S' signals an integral value */ + if (!do_hpacc_template_const_value (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + case 'A': + /* 'A' signals a named constant expression (literal) */ + if (!do_hpacc_template_literal (work, mangled, &arg)) + goto hpacc_template_args_done; + break; + + default: + /* Today, 1997-09-03, we have only the above types + of template parameters */ + /* FIXME: maybe this should fail and return null */ + goto hpacc_template_args_done; + } + string_appends (declp, &arg); + /* Check if we're at the end of template args. + 0 if at end of static member of template class, + _ if done with template args for a function */ + if ((**mangled == '\000') || (**mangled == '_')) + break; + else + string_append (declp, ","); + } + hpacc_template_args_done: + string_append (declp, ">"); + string_delete (&arg); + if (**mangled == '_') + (*mangled)++; + return; + } + /* ARM template? (Also handles HP cfront extensions) */ + else if (arm_pt (work, *mangled, n, &p, &args)) { - string arg; + string type_str; + string_init (&arg); string_appendn (declp, *mangled, p - *mangled); + if (work->temp_start == -1) /* non-recursive call */ + work->temp_start = declp->p - declp->b; string_append (declp, "<"); /* should do error checking here */ while (args < e) { string_clear (&arg); - do_type (work, &args, &arg); + + /* Check for type or literal here */ + switch (*args) + { + /* HP cfront extensions to ARM for template args */ + /* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ + /* FIXME: We handle only numeric literals for HP cfront */ + case 'X': + /* A typed constant value follows */ + args++; + if (!do_type (work, &args, &type_str)) + goto cfront_template_args_done; + string_append (&arg, "("); + string_appends (&arg, &type_str); + string_append (&arg, ")"); + if (*args != 'L') + goto cfront_template_args_done; + args++; + /* Now snarf a literal value following 'L' */ + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + + case 'L': + /* Snarf a literal following 'L' */ + args++; + if (!snarf_numeric_literal (&args, &arg)) + goto cfront_template_args_done; + break; + default: + /* Not handling other HP cfront stuff */ + if (!do_type (work, &args, &arg)) + goto cfront_template_args_done; + } string_appends (declp, &arg); string_append (declp, ","); } + cfront_template_args_done: string_delete (&arg); - --declp->p; + if (args >= e) + --declp->p; /* remove extra comma */ string_append (declp, ">"); } + else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 + && (*mangled)[9] == 'N' + && (*mangled)[8] == (*mangled)[10] + && strchr (cplus_markers, (*mangled)[8])) + { + /* A member of the anonymous namespace. */ + string_append (declp, "{anonymous}"); + } else { + if (work->temp_start == -1) /* non-recursive call only */ + work->temp_start = 0; /* disable in recursive calls */ string_appendn (declp, *mangled, n); } *mangled += n; } +/* Extract a class name, possibly a template with arguments, from the + mangled string; qualifiers, local class indicators, etc. have + already been dealt with */ + static int demangle_class_name (work, mangled, declp) struct work_stuff *work; @@ -1344,9 +1998,11 @@ int success = 0; n = consume_count (mangled); - if (strlen (*mangled) >= n) + if (n == -1) + return 0; + if ((int) strlen (*mangled) >= n) { - demangle_arm_pt (work, mangled, n, declp); + demangle_arm_hp_template (work, mangled, n, declp); success = 1; } @@ -1395,13 +2051,22 @@ string *declp; { int success = 0; + int btype; string class_name; + char *save_class_name_end = 0; string_init (&class_name); + btype = register_Btype (work); if (demangle_class_name (work, mangled, &class_name)) { + save_class_name_end = class_name.p; if ((work->constructor & 1) || (work->destructor & 1)) { + /* adjust so we don't include template args */ + if (work->temp_start && (work->temp_start != -1)) + { + class_name.p = class_name.b + work->temp_start; + } string_prepends (declp, &class_name); if (work -> destructor & 1) { @@ -1410,10 +2075,13 @@ } else { - work -> constructor -= 1; + work -> constructor -= 1; } } - string_prepend (declp, (work -> options & DMGL_JAVA) ? "." : "::"); + class_name.p = save_class_name_end; + remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); + remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); + string_prepend (declp, SCOPE_STRING (work)); string_prepends (declp, &class_name); success = 1; } @@ -1448,7 +2116,7 @@ the mangled name. Upon exit, it should point to the first character of the signature if demangling was successful, or to the first unconsumed character if demangling of the prefix was unsuccessful. - + Returns 1 on success, 0 otherwise. */ @@ -1462,7 +2130,17 @@ const char *scan; int i; - if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) + if (strlen(*mangled) > 6 + && (strncmp(*mangled, "_imp__", 6) == 0 + || strncmp(*mangled, "__imp_", 6) == 0)) + { + /* it's a symbol imported from a PE dynamic library. Check for both + new style prefix _imp__ and legacy __imp_ used by older versions + of dlltool. */ + (*mangled) += 6; + work->dllimported = 1; + } + else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) { char *marker = strchr (cplus_markers, (*mangled)[8]); if (marker != NULL && *marker == (*mangled)[10]) @@ -1485,13 +2163,13 @@ } } } - else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0) + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) { /* it's a ARM global destructor to be executed at program exit */ (*mangled) += 7; work->destructor = 2; } - else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0) + else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) { /* it's a ARM global constructor to be executed at program initial */ (*mangled) += 7; @@ -1519,35 +2197,36 @@ i = strspn (scan, "_"); if (i > 2) { - scan += (i - 2); + scan += (i - 2); } } - + if (scan == NULL) { success = 0; } else if (work -> static_type) { - if (!isdigit (scan[0]) && (scan[0] != 't')) + if (!isdigit ((unsigned char)scan[0]) && (scan[0] != 't')) { success = 0; } } else if ((scan == *mangled) - && (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't') - || (scan[2] == 'H'))) + && (isdigit ((unsigned char)scan[2]) || (scan[2] == 'Q') + || (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) { /* The ARM says nothing about the mangling of local variables. But cfront mangles local variables by prepending __ to them. As an extension to ARM demangling we handle this case. */ - if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2])) + if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) + && isdigit ((unsigned char)scan[2])) { *mangled = scan + 2; consume_count (mangled); string_append (declp, *mangled); *mangled += strlen (*mangled); - success = 1; + success = 1; } else { @@ -1555,18 +2234,37 @@ names like __Q2_3foo3bar for nested type names. So don't accept this style of constructor for cfront demangling. A GNU style member-template constructor starts with 'H'. */ - if (!(LUCID_DEMANGLING || ARM_DEMANGLING)) + if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) work -> constructor += 1; *mangled = scan + 2; } + } + else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') + { + /* Cfront-style parameterized type. Handled later as a signature. */ + success = 1; + + /* ARM template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); + } + else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') + || (scan[2] == 'p' && scan[3] == 's') + || (scan[2] == 'p' && scan[3] == 't'))) + { + /* EDG-style parameterized type. Handled later as a signature. */ + success = 1; + + /* EDG template? */ + demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); } - else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't')) + else if ((scan == *mangled) && !isdigit ((unsigned char)scan[2]) + && (scan[2] != 't')) { /* Mangled name starts with "__". Skip over any leading '_' characters, then find the next "__" that separates the prefix from the signature. */ - if (!(ARM_DEMANGLING || LUCID_DEMANGLING) - || (arm_special (work, mangled, declp) == 0)) + if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) + || (arm_special (mangled, declp) == 0)) { while (*scan == '_') { @@ -1580,18 +2278,22 @@ } else { - demangle_function_name (work, mangled, declp, scan); + const char *tmp; + + /* Look for the LAST occurrence of __, allowing names to + have the '__' sequence embedded in them. */ + if (!(ARM_DEMANGLING || HP_DEMANGLING)) + { + while ((tmp = mystrstr (scan + 2, "__")) != NULL) + scan = tmp; + } + if (*(scan + 2) == '\0') + success = 0; + else + demangle_function_name (work, mangled, declp, scan); } } } - else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') - { - /* Cfront-style parameterized type. Handled later as a signature. */ - success = 1; - - /* ARM template? */ - demangle_arm_pt (work, mangled, strlen (*mangled), declp); - } else if (*(scan + 2) != '\0') { /* Mangled name does not start with "__" but does have one somewhere @@ -1610,7 +2312,7 @@ string_append (declp, *mangled); *mangled += strlen (*mangled); success = 1; - } + } return (success); } @@ -1679,19 +2381,29 @@ (*mangled) += 4; /* Old style, no thunks: "_vt" */ while (**mangled != '\0') { - p = strpbrk (*mangled, cplus_markers); switch (**mangled) { case 'Q': + case 'K': success = demangle_qualified (work, mangled, declp, 0, 1); break; case 't': - success = demangle_template (work, mangled, declp, 0, 1); + success = demangle_template (work, mangled, declp, 0, 1, + 1); break; default: - if (isdigit(*mangled[0])) + if (isdigit((unsigned char)*mangled[0])) { n = consume_count(mangled); + /* We may be seeing a too-large size, or else a + "." indicating a static local symbol. In + any case, declare victory and move on; *don't* try + to use n to allocate. */ + if (n > (int) strlen (*mangled)) + { + success = 1; + break; + } } else { @@ -1701,12 +2413,12 @@ (*mangled) += n; } + p = strpbrk (*mangled, cplus_markers); if (success && ((p == NULL) || (p == *mangled))) { if (p != NULL) { - string_append (declp, - (work -> options & DMGL_JAVA) ? "." : "::"); + string_append (declp, SCOPE_STRING (work)); (*mangled)++; } } @@ -1728,13 +2440,19 @@ switch (**mangled) { case 'Q': + case 'K': success = demangle_qualified (work, mangled, declp, 0, 1); break; case 't': - success = demangle_template (work, mangled, declp, 0, 1); + success = demangle_template (work, mangled, declp, 0, 1, 1); break; default: n = consume_count (mangled); + if (n < 0 || n > strlen (*mangled)) + { + success = 0; + break; + } string_appendn (declp, *mangled, n); (*mangled) += n; } @@ -1743,7 +2461,7 @@ /* Consumed everything up to the cplus_marker, append the variable name. */ (*mangled)++; - string_append (declp, (work -> options & DMGL_JAVA) ? "." : "::"); + string_append (declp, SCOPE_STRING (work)); n = strlen (*mangled); string_appendn (declp, *mangled, n); (*mangled) += n; @@ -1755,21 +2473,30 @@ } else if (strncmp (*mangled, "__thunk_", 8) == 0) { - int delta = ((*mangled) += 8, consume_count (mangled)); - char *method = cplus_demangle (++*mangled, work->options); - if (method) - { - char buf[50]; - sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); - string_append (declp, buf); - string_append (declp, method); - free (method); - n = strlen (*mangled); - (*mangled) += n; - } + int delta; + + (*mangled) += 8; + delta = consume_count (mangled); + if (delta == -1) + success = 0; else { - success = 0; + char *method = internal_cplus_demangle (work, ++*mangled); + + if (method) + { + char buf[50]; + sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); + string_append (declp, buf); + string_append (declp, method); + free (method); + n = strlen (*mangled); + (*mangled) += n; + } + else + { + success = 0; + } } } else if (strncmp (*mangled, "__t", 3) == 0 @@ -1780,10 +2507,11 @@ switch (**mangled) { case 'Q': + case 'K': success = demangle_qualified (work, mangled, declp, 0, 1); break; case 't': - success = demangle_template (work, mangled, declp, 0, 1); + success = demangle_template (work, mangled, declp, 0, 1, 1); break; default: success = demangle_fund_type (work, mangled, declp); @@ -1801,6 +2529,35 @@ return (success); } +static void +recursively_demangle(work, mangled, result, namelength) + struct work_stuff *work; + const char **mangled; + string *result; + int namelength; +{ + char * recurse = (char *)NULL; + char * recurse_dem = (char *)NULL; + + recurse = (char *) xmalloc (namelength + 1); + memcpy (recurse, *mangled, namelength); + recurse[namelength] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, namelength); + } + free (recurse); + *mangled += namelength; +} + /* LOCAL FUNCTION @@ -1810,8 +2567,8 @@ SYNOPSIS static int - arm_special (struct work_stuff *work, const char **mangled, - string *declp); + arm_special (const char **mangled, + string *declp); DESCRIPTION @@ -1825,8 +2582,7 @@ */ static int -arm_special (work, mangled, declp) - struct work_stuff *work; +arm_special (mangled, declp) const char **mangled; string *declp; { @@ -1844,7 +2600,7 @@ while (*scan != '\0') /* first check it can be demangled */ { n = consume_count (&scan); - if (n==0) + if (n == -1) { return (0); /* no good */ } @@ -1858,6 +2614,9 @@ while (**mangled != '\0') { n = consume_count (mangled); + if (n == -1 + || n > strlen (*mangled)) + return 0; string_prependn (declp, *mangled, n); (*mangled) += n; if ((*mangled)[0] == '_' && (*mangled)[1] == '_') @@ -1915,15 +2674,35 @@ int isfuncname; int append; { - int qualifiers; - int namelength; + int qualifiers = 0; int success = 1; const char *p; char num[2]; string temp; + string last_name; + int bindex = register_Btype (work); + /* We only make use of ISFUNCNAME if the entity is a constructor or + destructor. */ + isfuncname = (isfuncname + && ((work->constructor & 1) || (work->destructor & 1))); + string_init (&temp); - switch ((*mangled)[1]) + string_init (&last_name); + + if ((*mangled)[0] == 'K') + { + /* Squangling qualified name reuse */ + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work -> numk) + success = 0; + else + string_append (&temp, work -> ktypevec[idx]); + } + else + switch ((*mangled)[1]) { case '_': /* GNU mangled name with more than 9 classes. The count is preceded @@ -1931,11 +2710,11 @@ by an underscore. */ p = *mangled + 2; qualifiers = atoi (p); - if (!isdigit (*p) || *p == '0') + if (!isdigit ((unsigned char)*p) || *p == '0') success = 0; /* Skip the digits. */ - while (isdigit (*p)) + while (isdigit ((unsigned char)*p)) ++p; if (*p != '_') @@ -1981,67 +2760,98 @@ while (qualifiers-- > 0) { - if (*mangled[0] == '_') - *mangled = *mangled + 1; + int remember_K = 1; + string_clear (&last_name); + + if (*mangled[0] == '_') + (*mangled)++; + if (*mangled[0] == 't') { - success = demangle_template(work, mangled, &temp, 0, 1); - if (!success) break; + /* Here we always append to TEMP since we will want to use + the template name without the template parameters as a + constructor or destructor name. The appropriate + (parameter-less) value is returned by demangle_template + in LAST_NAME. We do not remember the template type here, + in order to match the G++ mangling algorithm. */ + success = demangle_template(work, mangled, &temp, + &last_name, 1, 0); + if (!success) + break; } - else if (*mangled[0] == 'X') + else if (*mangled[0] == 'K') { - success = do_type (work, mangled, &temp); + int idx; + (*mangled)++; + idx = consume_count_with_underscores (mangled); + if (idx == -1 || idx >= work->numk) + success = 0; + else + string_append (&temp, work->ktypevec[idx]); + remember_K = 0; + if (!success) break; } else - { - namelength = consume_count (mangled); - if (strlen (*mangled) < namelength) - { - /* Simple sanity check failed */ - success = 0; - break; - } - string_appendn (&temp, *mangled, namelength); - *mangled += namelength; + { + if (EDG_DEMANGLING) + { + int namelength; + /* Now recursively demangle the qualifier + * This is necessary to deal with templates in + * mangling styles like EDG */ + namelength = consume_count (mangled); + if (namelength == -1) + { + success = 0; + break; + } + recursively_demangle(work, mangled, &temp, namelength); + } + else + { + success = do_type (work, mangled, &last_name); + if (!success) + break; + string_appends (&temp, &last_name); + } } + + if (remember_K) + remember_Ktype (work, temp.b, LEN_STRING (&temp)); + if (qualifiers > 0) - { - string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::"); - } + string_append (&temp, SCOPE_STRING (work)); } + remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); + /* If we are using the result as a function name, we need to append the appropriate '::' separated constructor or destructor name. We do this here because this is the most convenient place, where we already have a pointer to the name and the length of the name. */ - if (isfuncname && (work->constructor & 1 || work->destructor & 1)) + if (isfuncname) { - string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::"); + string_append (&temp, SCOPE_STRING (work)); if (work -> destructor & 1) - { - string_append (&temp, "~"); - } - string_appendn (&temp, (*mangled) - namelength, namelength); + string_append (&temp, "~"); + string_appends (&temp, &last_name); } - /* Now either prepend the temp buffer to the result, or append it, + /* Now either prepend the temp buffer to the result, or append it, depending upon the state of the append flag. */ if (append) - { - string_appends (result, &temp); - } + string_appends (result, &temp); else { if (!STRING_EMPTY (result)) - { - string_append (&temp, (work -> options & DMGL_JAVA) ? "." : "::"); - } + string_append (&temp, SCOPE_STRING (work)); string_prepends (result, &temp); } + string_delete (&last_name); string_delete (&temp); return (success); } @@ -2059,7 +2869,37 @@ DESCRIPTION - Return 0 if no conversion is performed, 1 if a string is converted. + Assume that *type points at a count in a mangled name; set + *count to its value, and set *type to the next character after + the count. There are some weird rules in effect here. + + If *type does not point at a string of digits, return zero. + + If *type points at a string of digits followed by an + underscore, set *count to their value as an integer, advance + *type to point *after the underscore, and return 1. + + If *type points at a string of digits not followed by an + underscore, consume only the first digit. Set *count to its + value as an integer, leave *type pointing after that digit, + and return 1. + + The excuse for this odd behavior: in the ARM and HP demangling + styles, a type can be followed by a repeat count of the form + `Nxy', where: + + `x' is a single digit specifying how many additional copies + of the type to append to the argument list, and + + `y' is one or more digits, specifying the zero-based index of + the first repeated argument in the list. Yes, as you're + unmangling the name you can figure this out yourself, but + it's there anyway. + + So, for example, in `bar__3fooFPiN51', the first argument is a + pointer to an integer (`Pi'), and then the next five arguments + are the same (`N5'), and the first repeat is the function's + second argument (`1'). */ static int @@ -2070,7 +2910,7 @@ const char *p; int n; - if (!isdigit (**type)) + if (!isdigit ((unsigned char)**type)) { return (0); } @@ -2078,17 +2918,17 @@ { *count = **type - '0'; (*type)++; - if (isdigit (**type)) + if (isdigit ((unsigned char)**type)) { p = *type; n = *count; - do + do { n *= 10; n += *p - '0'; p++; - } - while (isdigit (*p)); + } + while (isdigit ((unsigned char)*p)); if (*p == '_') { *type = p + 1; @@ -2099,7 +2939,8 @@ return (1); } -/* result will be initialised here; it will be freed on failure */ +/* RESULT will be initialised here; it will be freed on failure. The + value returned is really a type_kind_t. */ static int do_type (work, mangled, result) @@ -2112,9 +2953,11 @@ int success; string decl; const char *remembered_type; - int constp; - int volatilep; + int type_quals; + string btype; + type_kind_t tk = tk_none; + string_init (&btype); string_init (&decl); string_init (result); @@ -2132,33 +2975,35 @@ (*mangled)++; if (! (work -> options & DMGL_JAVA)) string_prepend (&decl, "*"); + if (tk == tk_none) + tk = tk_pointer; break; /* A reference type */ case 'R': (*mangled)++; string_prepend (&decl, "&"); + if (tk == tk_none) + tk = tk_reference; break; /* An array */ case 'A': { - const char *p = ++(*mangled); - - string_prepend (&decl, "("); - string_append (&decl, ")["); - /* Copy anything up until the next underscore (the size of the - array). */ - while (**mangled && **mangled != '_') - ++(*mangled); - if (**mangled == '_') + ++(*mangled); + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) { - string_appendn (&decl, p, *mangled - p); - string_append (&decl, "]"); - *mangled += 1; + string_prepend (&decl, "("); + string_append (&decl, ")"); } - else - success = 0; + string_append (&decl, "["); + if (**mangled != '_') + success = demangle_template_value_parm (work, mangled, &decl, + tk_integral); + if (**mangled == '_') + ++(*mangled); + string_append (&decl, "]"); break; } @@ -2179,7 +3024,8 @@ /* A function */ case 'F': (*mangled)++; - if (!STRING_EMPTY (&decl) && decl.b[0] == '*') + if (!STRING_EMPTY (&decl) + && (decl.b[0] == '*' || decl.b[0] == '&')) { string_prepend (&decl, "("); string_append (&decl, ")"); @@ -2187,37 +3033,31 @@ /* After picking off the function args, we expect to either find the function return type (preceded by an '_') or the end of the string. */ - if (!demangle_args (work, mangled, &decl) + if (!demangle_nested_args (work, mangled, &decl) || (**mangled != '_' && **mangled != '\0')) { success = 0; + break; } if (success && (**mangled == '_')) - { - (*mangled)++; - } + (*mangled)++; break; case 'M': case 'O': { - constp = 0; - volatilep = 0; + type_quals = TYPE_UNQUALIFIED; member = **mangled == 'M'; (*mangled)++; - if (!isdigit (**mangled) && **mangled != 't') - { - success = 0; - break; - } string_append (&decl, ")"); - string_prepend (&decl, (work -> options & DMGL_JAVA) ? "." : "::"); - if (isdigit (**mangled)) + string_prepend (&decl, SCOPE_STRING (work)); + if (isdigit ((unsigned char)**mangled)) { n = consume_count (mangled); - if (strlen (*mangled) < n) + if (n == -1 + || (int) strlen (*mangled) < n) { success = 0; break; @@ -2225,11 +3065,18 @@ string_prependn (&decl, *mangled, n); *mangled += n; } - else + else if (**mangled == 'X' || **mangled == 'Y') + { + string temp; + do_type (work, mangled, &temp); + string_prepends (&decl, &temp); + } + else if (**mangled == 't') { string temp; string_init (&temp); - success = demangle_template (work, mangled, &temp, NULL, 1); + success = demangle_template (work, mangled, &temp, + NULL, 1, 1); if (success) { string_prependn (&decl, temp.b, temp.p - temp.b); @@ -2238,26 +3085,35 @@ else break; } + else + { + success = 0; + break; + } + string_prepend (&decl, "("); if (member) { - if (**mangled == 'C') - { - (*mangled)++; - constp = 1; - } - if (**mangled == 'V') + switch (**mangled) { + case 'C': + case 'V': + case 'u': + type_quals |= code_for_qualifier (**mangled); (*mangled)++; - volatilep = 1; + break; + + default: + break; } + if (*(*mangled)++ != 'F') { success = 0; break; } } - if ((member && !demangle_args (work, mangled, &decl)) + if ((member && !demangle_nested_args (work, mangled, &decl)) || **mangled != '_') { success = 0; @@ -2267,37 +3123,29 @@ if (! PRINT_ANSI_QUALIFIERS) { break; - } - if (constp) - { - APPEND_BLANK (&decl); - string_append (&decl, "const"); } - if (volatilep) + if (type_quals != TYPE_UNQUALIFIED) { APPEND_BLANK (&decl); - string_append (&decl, "volatile"); + string_append (&decl, qualifier_string (type_quals)); } break; } case 'G': - (*mangled)++; - break; - - case 'C': (*mangled)++; - /* - if ((*mangled)[1] == 'P') - { - */ + break; + + case 'C': + case 'V': + case 'u': if (PRINT_ANSI_QUALIFIERS) { if (!STRING_EMPTY (&decl)) - { - string_prepend (&decl, " "); - } - string_prepend (&decl, "const"); + string_prepend (&decl, " "); + + string_prepend (&decl, demangle_qualifier (**mangled)); } + (*mangled)++; break; /* } @@ -2310,11 +3158,23 @@ } } - switch (**mangled) + if (success) switch (**mangled) { /* A qualified name, such as "Outer::Inner". */ case 'Q': - success = demangle_qualified (work, mangled, result, 0, 1); + case 'K': + { + success = demangle_qualified (work, mangled, result, 0, 1); + break; + } + + /* A back reference to a previously seen squangled type */ + case 'B': + (*mangled)++; + if (!get_count (mangled, &n) || n >= work -> numb) + success = 0; + else + string_append (result, work->btypevec[n]); break; case 'X': @@ -2322,12 +3182,11 @@ /* A template parm. We substitute the corresponding argument. */ { int idx; - int lvl; (*mangled)++; idx = consume_count_with_underscores (mangled); - if (idx == -1 + if (idx == -1 || (work->tmpl_argvec && idx >= work->ntmpl_args) || consume_count_with_underscores (mangled) == -1) { @@ -2350,6 +3209,8 @@ default: success = demangle_fund_type (work, mangled, result); + if (tk == tk_none) + tk = (type_kind_t) success; break; } @@ -2362,11 +3223,14 @@ } } else - { - string_delete (result); - } + string_delete (result); string_delete (&decl); - return (success); + + if (success) + /* Assume an integral type, if we're not sure. */ + return (int) ((tk == tk_none) ? tk_integral : tk); + else + return 0; } /* Given a pointer to a type string that represents a fundamental type @@ -2380,7 +3244,7 @@ "Sl" => "signed long" "CUs" => "const unsigned short" - */ + The value returned is really a type_kind_t. */ static int demangle_fund_type (work, mangled, result) @@ -2390,6 +3254,12 @@ { int done = 0; int success = 1; + char buf[10]; + int dec = 0; + string btype; + type_kind_t tk = tk_integral; + + string_init (&btype); /* First pick off any type qualifiers. There can be more than one. */ @@ -2398,12 +3268,15 @@ switch (**mangled) { case 'C': - (*mangled)++; + case 'V': + case 'u': if (PRINT_ANSI_QUALIFIERS) { - APPEND_BLANK (result); - string_append (result, "const"); + if (!STRING_EMPTY (result)) + string_prepend (result, " "); + string_prepend (result, demangle_qualifier (**mangled)); } + (*mangled)++; break; case 'U': (*mangled)++; @@ -2415,14 +3288,6 @@ APPEND_BLANK (result); string_append (result, "signed"); break; - case 'V': - (*mangled)++; - if (PRINT_ANSI_QUALIFIERS) - { - APPEND_BLANK (result); - string_append (result, "volatile"); - } - break; case 'J': (*mangled)++; APPEND_BLANK (result); @@ -2470,39 +3335,75 @@ (*mangled)++; APPEND_BLANK (result); string_append (result, "bool"); + tk = tk_bool; break; case 'c': (*mangled)++; APPEND_BLANK (result); string_append (result, "char"); + tk = tk_char; break; case 'w': (*mangled)++; APPEND_BLANK (result); string_append (result, "wchar_t"); + tk = tk_char; break; case 'r': (*mangled)++; APPEND_BLANK (result); string_append (result, "long double"); + tk = tk_real; break; case 'd': (*mangled)++; APPEND_BLANK (result); string_append (result, "double"); + tk = tk_real; break; case 'f': (*mangled)++; APPEND_BLANK (result); string_append (result, "float"); + tk = tk_real; break; case 'G': (*mangled)++; - if (!isdigit (**mangled)) + if (!isdigit ((unsigned char)**mangled)) { success = 0; break; } + case 'I': + (*mangled)++; + if (**mangled == '_') + { + int i; + (*mangled)++; + for (i = 0; + i < sizeof (buf) - 1 && **mangled && **mangled != '_'; + (*mangled)++, i++) + buf[i] = **mangled; + if (**mangled != '_') + { + success = 0; + break; + } + buf[i] = '\0'; + (*mangled)++; + } + else + { + strncpy (buf, *mangled, 2); + buf[2] = '\0'; + *mangled += min (strlen (*mangled), 2); + } + sscanf (buf, "%x", &dec); + sprintf (buf, "int%i_t", dec); + APPEND_BLANK (result); + string_append (result, buf); + break; + /* fall through */ /* An explicit type, such as "6mytype" or "7integer" */ case '0': @@ -2515,24 +3416,171 @@ case '7': case '8': case '9': - APPEND_BLANK (result); - if (!demangle_class_name (work, mangled, result)) { - --result->p; - success = 0; + { + int bindex = register_Btype (work); + string btype; + string_init (&btype); + if (demangle_class_name (work, mangled, &btype)) { + remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); + APPEND_BLANK (result); + string_appends (result, &btype); + } + else + success = 0; + string_delete (&btype); + break; } - break; case 't': - success = demangle_template(work,mangled, result, 0, 1); - break; + { + success = demangle_template (work, mangled, &btype, 0, 1, 1); + string_appends (result, &btype); + break; + } default: success = 0; break; } - return (success); + return success ? ((int) tk) : 0; +} + + +/* Handle a template's value parameter for HP aCC (extension from ARM) + **mangled points to 'S' or 'U' */ + +static int +do_hpacc_template_const_value (work, mangled, result) + struct work_stuff *work; + const char **mangled; + string *result; +{ + int unsigned_const; + + if (**mangled != 'U' && **mangled != 'S') + return 0; + + unsigned_const = (**mangled == 'U'); + + (*mangled)++; + + switch (**mangled) + { + case 'N': + string_append (result, "-"); + /* fall through */ + case 'P': + (*mangled)++; + break; + case 'M': + /* special case for -2^31 */ + string_append (result, "-2147483648"); + (*mangled)++; + return 1; + default: + return 0; + } + + /* We have to be looking at an integer now */ + if (!(isdigit ((unsigned char)**mangled))) + return 0; + + /* We only deal with integral values for template + parameters -- so it's OK to look only for digits */ + while (isdigit ((unsigned char)**mangled)) + { + char_str[0] = **mangled; + string_append (result, char_str); + (*mangled)++; + } + + if (unsigned_const) + string_append (result, "U"); + + /* FIXME? Some day we may have 64-bit (or larger :-) ) constants + with L or LL suffixes. pai/1997-09-03 */ + + return 1; /* success */ +} + +/* Handle a template's literal parameter for HP aCC (extension from ARM) + **mangled is pointing to the 'A' */ + +static int +do_hpacc_template_literal (work, mangled, result) + struct work_stuff *work; + const char **mangled; + string *result; +{ + int literal_len = 0; + char * recurse; + char * recurse_dem; + + if (**mangled != 'A') + return 0; + + (*mangled)++; + + literal_len = consume_count (mangled); + + if (literal_len <= 0) + return 0; + + /* Literal parameters are names of arrays, functions, etc. and the + canonical representation uses the address operator */ + string_append (result, "&"); + + /* Now recursively demangle the literal name */ + recurse = (char *) xmalloc (literal_len + 1); + memcpy (recurse, *mangled, literal_len); + recurse[literal_len] = '\000'; + + recurse_dem = cplus_demangle (recurse, work->options); + + if (recurse_dem) + { + string_append (result, recurse_dem); + free (recurse_dem); + } + else + { + string_appendn (result, *mangled, literal_len); + } + (*mangled) += literal_len; + free (recurse); + + return 1; +} + +static int +snarf_numeric_literal (args, arg) + const char ** args; + string * arg; +{ + if (**args == '-') + { + char_str[0] = '-'; + string_append (arg, char_str); + (*args)++; + } + else if (**args == '+') + (*args)++; + + if (!isdigit ((unsigned char)**args)) + return 0; + + while (isdigit ((unsigned char)**args)) + { + char_str[0] = **args; + string_append (arg, char_str); + (*args)++; + } + + return 1; } -/* `result' will be initialized in do_type; it will be freed on failure */ +/* Demangle the next argument, given by MANGLED into RESULT, which + *should be an uninitialized* string. It will be initialized here, + and free'd should anything go wrong. */ static int do_arg (work, mangled, result) @@ -2540,17 +3588,67 @@ const char **mangled; string *result; { + /* Remember where we started so that we can record the type, for + non-squangling type remembering. */ const char *start = *mangled; + + string_init (result); - if (!do_type (work, mangled, result)) + if (work->nrepeats > 0) { - return (0); + --work->nrepeats; + + if (work->previous_argument == 0) + return 0; + + /* We want to reissue the previous type in this argument list. */ + string_appends (result, work->previous_argument); + return 1; + } + + if (**mangled == 'n') + { + /* A squangling-style repeat. */ + (*mangled)++; + work->nrepeats = consume_count(mangled); + + if (work->nrepeats <= 0) + /* This was not a repeat count after all. */ + return 0; + + if (work->nrepeats > 9) + { + if (**mangled != '_') + /* The repeat count should be followed by an '_' in this + case. */ + return 0; + else + (*mangled)++; + } + + /* Now, the repeat is all set up. */ + return do_arg (work, mangled, result); } + + /* Save the result in WORK->previous_argument so that we can find it + if it's repeated. Note that saving START is not good enough: we + do not want to add additional types to the back-referenceable + type vector when processing a repeated type. */ + if (work->previous_argument) + string_clear (work->previous_argument); else { - remember_type (work, start, *mangled - start); - return (1); + work->previous_argument = (string*) xmalloc (sizeof (string)); + string_init (work->previous_argument); } + + if (!do_type (work, mangled, work->previous_argument)) + return 0; + + string_appends (result, work->previous_argument); + + remember_type (work, start, *mangled - start); + return 1; } static void @@ -2561,6 +3659,9 @@ { char *tem; + if (work->forgetting_types) + return; + if (work -> ntypes >= work -> typevec_size) { if (work -> typevec_size == 0) @@ -2583,6 +3684,112 @@ work -> typevec[work -> ntypes++] = tem; } + +/* Remember a K type class qualifier. */ +static void +remember_Ktype (work, start, len) + struct work_stuff *work; + const char *start; + int len; +{ + char *tem; + + if (work -> numk >= work -> ksize) + { + if (work -> ksize == 0) + { + work -> ksize = 5; + work -> ktypevec + = (char **) xmalloc (sizeof (char *) * work -> ksize); + } + else + { + work -> ksize *= 2; + work -> ktypevec + = (char **) xrealloc ((char *)work -> ktypevec, + sizeof (char *) * work -> ksize); + } + } + tem = xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> ktypevec[work -> numk++] = tem; +} + +/* Register a B code, and get an index for it. B codes are registered + as they are seen, rather than as they are completed, so map > + registers map > as B0, and temp as B1 */ + +static int +register_Btype (work) + struct work_stuff *work; +{ + int ret; + + if (work -> numb >= work -> bsize) + { + if (work -> bsize == 0) + { + work -> bsize = 5; + work -> btypevec + = (char **) xmalloc (sizeof (char *) * work -> bsize); + } + else + { + work -> bsize *= 2; + work -> btypevec + = (char **) xrealloc ((char *)work -> btypevec, + sizeof (char *) * work -> bsize); + } + } + ret = work -> numb++; + work -> btypevec[ret] = NULL; + return(ret); +} + +/* Store a value into a previously registered B code type. */ + +static void +remember_Btype (work, start, len, index) + struct work_stuff *work; + const char *start; + int len, index; +{ + char *tem; + + tem = xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + work -> btypevec[index] = tem; +} + +/* Lose all the info related to B and K type codes. */ +static void +forget_B_and_K_types (work) + struct work_stuff *work; +{ + int i; + + while (work -> numk > 0) + { + i = --(work -> numk); + if (work -> ktypevec[i] != NULL) + { + free (work -> ktypevec[i]); + work -> ktypevec[i] = NULL; + } + } + + while (work -> numb > 0) + { + i = --(work -> numb); + if (work -> btypevec[i] != NULL) + { + free (work -> btypevec[i]); + work -> btypevec[i] = NULL; + } + } +} /* Forget the remembered types, but not the type vector itself. */ static void @@ -2634,8 +3841,8 @@ foo__FiR3fooT1T2T1T2 __ct__3fooFiR3fooT1T2T1T2 - Note that g++ bases it's type numbers starting at zero and counts all - previously seen types, while lucid/ARM bases it's type numbers starting + Note that g++ bases its type numbers starting at zero and counts all + previously seen types, while lucid/ARM bases its type numbers starting at one and only considers types after it has seen the 'F' character indicating the start of the function args. For lucid/ARM style, we account for this difference by discarding any previously seen types when @@ -2666,12 +3873,13 @@ } } - while (**mangled != '_' && **mangled != '\0' && **mangled != 'e') + while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') + || work->nrepeats > 0) { if ((**mangled == 'N') || (**mangled == 'T')) { temptype = *(*mangled)++; - + if (temptype == 'N') { if (!get_count (mangled, &r)) @@ -2683,7 +3891,7 @@ { r = 1; } - if (ARM_DEMANGLING && work -> ntypes >= 10) + if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) { /* If we have 10 or more types we might have more than a 1 digit index so we'll have to consume the whole count here. This @@ -2691,7 +3899,7 @@ count but it's impossible to demangle that case properly anyway. Eg if we already have 12 types is T12Pc "(..., type1, Pc, ...)" or "(..., type12, char *, ...)" */ - if ((t = consume_count(mangled)) == 0) + if ((t = consume_count(mangled)) <= 0) { return (0); } @@ -2703,7 +3911,7 @@ return (0); } } - if (LUCID_DEMANGLING || ARM_DEMANGLING) + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) { t--; } @@ -2713,7 +3921,7 @@ { return (0); } - while (--r >= 0) + while (work->nrepeats > 0 || --r >= 0) { tem = work -> typevec[t]; if (need_comma && PRINT_ARG_TYPES) @@ -2734,18 +3942,12 @@ } else { - if (need_comma & PRINT_ARG_TYPES) - { - string_append (declp, ", "); - } + if (need_comma && PRINT_ARG_TYPES) + string_append (declp, ", "); if (!do_arg (work, mangled, &arg)) - { - return (0); - } + return (0); if (PRINT_ARG_TYPES) - { - string_appends (declp, &arg); - } + string_appends (declp, &arg); string_delete (&arg); need_comma = 1; } @@ -2771,6 +3973,45 @@ return (1); } +/* Like demangle_args, but for demangling the argument lists of function + and method pointers or references, not top-level declarations. */ + +static int +demangle_nested_args (work, mangled, declp) + struct work_stuff *work; + const char **mangled; + string *declp; +{ + string* saved_previous_argument; + int result; + int saved_nrepeats; + + /* The G++ name-mangling algorithm does not remember types on nested + argument lists, unless -fsquangling is used, and in that case the + type vector updated by remember_type is not used. So, we turn + off remembering of types here. */ + ++work->forgetting_types; + + /* For the repeat codes used with -fsquangling, we must keep track of + the last argument. */ + saved_previous_argument = work->previous_argument; + saved_nrepeats = work->nrepeats; + work->previous_argument = 0; + work->nrepeats = 0; + + /* Actually demangle the arguments. */ + result = demangle_args (work, mangled, declp); + + /* Restore the previous_argument field. */ + if (work->previous_argument) + string_delete (work->previous_argument); + work->previous_argument = saved_previous_argument; + --work->forgetting_types; + work->nrepeats = saved_nrepeats; + + return result; +} + static void demangle_function_name (work, mangled, declp, scan) struct work_stuff *work; @@ -2778,8 +4019,7 @@ string *declp; const char *scan; { - int i; - int len; + size_t i; string type; const char *tem; @@ -2792,8 +4032,18 @@ separator. */ (*mangled) = scan + 2; + /* We may be looking at an instantiation of a template function: + foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a + following _F marks the start of the function arguments. Handle + the template arguments first. */ + + if (HP_DEMANGLING && (**mangled == 'X')) + { + demangle_arm_hp_template (work, mangled, 0, declp); + /* This leaves MANGLED pointing to the 'F' marking func args */ + } - if (LUCID_DEMANGLING || ARM_DEMANGLING) + if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) { /* See if we have an ARM style constructor or destructor operator. @@ -2815,7 +4065,7 @@ } } - if (declp->p - declp->b >= 3 + if (declp->p - declp->b >= 3 && declp->b[0] == 'o' && declp->b[1] == 'p' && strchr (cplus_markers, declp->b[2]) != NULL) @@ -2826,8 +4076,8 @@ { for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { - len = declp->p - declp->b - 10; - if (strlen (optable[i].in) == len + int len = declp->p - declp->b - 10; + if ((int) strlen (optable[i].in) == len && memcmp (optable[i].in, declp->b + 10, len) == 0) { string_clear (declp); @@ -2843,7 +4093,7 @@ for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++) { int len = declp->p - declp->b - 3; - if (strlen (optable[i].in) == len + if ((int) strlen (optable[i].in) == len && memcmp (optable[i].in, declp->b + 3, len) == 0) { string_clear (declp); @@ -2914,7 +4164,7 @@ string_append (declp, "operator"); string_append (declp, optable[i].out); break; - } + } } } } @@ -2968,7 +4218,7 @@ s->b = s->p = s->e = NULL; } -static void +static void string_clear (s) string *s; { @@ -3109,16 +4359,16 @@ usage (stream, status) FILE *stream; int status; -{ +{ fprintf (stream, "\ -Usage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\ - [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\ +Usage: %s [-_] [-n] [-s {gnu,lucid,arm,hp,edg}] [--strip-underscores]\n\ + [--no-strip-underscores] [--format={gnu,lucid,arm,hp,edg}]\n\ [--help] [--version] [arg...]\n", program_name); exit (status); } -#define MBUF_SIZE 512 +#define MBUF_SIZE 32767 char mbuffer[MBUF_SIZE]; /* Defined in the automatically-generated underscore.c. */ @@ -3136,6 +4386,64 @@ {0, no_argument, 0, 0} }; +/* More 'friendly' abort that prints the line and file. + config.h can #define abort fancy_abort if you like that sort of thing. */ + +void +fancy_abort () +{ + fatal ("Internal gcc abort."); +} + + +/* Return the string of non-alnum characters that may occur + as a valid symbol component, in the standard assembler symbol + syntax. */ + +static const char * +standard_symbol_characters () +{ + return "_$."; +} + + +/* Return the string of non-alnum characters that may occur + as a valid symbol name component in an HP object file. + + Note that, since HP's compiler generates object code straight from + C++ source, without going through an assembler, its mangled + identifiers can use all sorts of characters that no assembler would + tolerate, so the alphabet this function creates is a little odd. + Here are some sample mangled identifiers offered by HP: + + typeid*__XT24AddressIndExpClassMember_ + [Vftptr]key:__dt__32OrdinaryCompareIndExpClassMemberFv + __ct__Q2_9Elf64_Dyn18{unnamed.union.#1}Fv + + This still seems really weird to me, since nowhere else in this + file is there anything to recognize curly brackets, parens, etc. + I've talked with Srikanth , and he assures me + this is right, but I still strongly suspect that there's a + misunderstanding here. + + If we decide it's better for c++filt to use HP's assembler syntax + to scrape identifiers out of its input, here's the definition of + the symbol name syntax from the HP assembler manual: + + Symbols are composed of uppercase and lowercase letters, decimal + digits, dollar symbol, period (.), ampersand (&), pound sign(#) and + underscore (_). A symbol can begin with a letter, digit underscore or + dollar sign. If a symbol begins with a digit, it must contain a + non-digit character. + + So have fun. */ +static const char * +hp_symbol_characters () +{ + return "_$.<>#,*&[]:(){}"; +} + + int main (argc, argv) int argc; @@ -3143,6 +4451,7 @@ { char *result; int c; + char *valid_symbols; program_name = argv[0]; @@ -3161,7 +4470,7 @@ strip_underscore = 0; break; case 'v': - printf ("GNU %s version %s\n", program_name, program_version); + printf ("GNU %s (C++ demangler), version %s\n", program_name, program_version); exit (0); case '_': strip_underscore = 1; @@ -3182,6 +4491,14 @@ { current_demangling_style = arm_demangling; } + else if (strcmp (optarg, "hp") == 0) + { + current_demangling_style = hp_demangling; + } + else if (strcmp (optarg, "edg") == 0) + { + current_demangling_style = edg_demangling; + } else { fprintf (stderr, "%s: unknown demangling style `%s'\n", @@ -3201,12 +4518,30 @@ } else { + switch (current_demangling_style) + { + case gnu_demangling: + case lucid_demangling: + case arm_demangling: + case edg_demangling: + valid_symbols = standard_symbol_characters (); + break; + case hp_demangling: + valid_symbols = hp_symbol_characters (); + break; + default: + /* Folks should explicitly indicate the appropriate alphabet for + each demangling. Providing a default would allow the + question to go unconsidered. */ + abort (); + } + for (;;) { int i = 0; c = getchar (); /* Try to read a label. */ - while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.')) + while (c != EOF && (isalnum (c) || strchr (valid_symbols, c))) { if (i >= MBUF_SIZE-1) break; @@ -3226,7 +4561,7 @@ skip_first = i; mbuffer[i] = 0; - + result = cplus_demangle (mbuffer + skip_first, flags); if (result) { @@ -3256,26 +4591,23 @@ fprintf (stderr, "%s: %s\n", program_name, str); exit (1); } - -char * malloc (); -char * realloc (); -char * +PTR xmalloc (size) - unsigned size; + size_t size; { - register char *value = (char *) malloc (size); + register PTR value = (PTR) malloc (size); if (value == 0) fatal ("virtual memory exhausted"); return value; } -char * +PTR xrealloc (ptr, size) - char *ptr; - unsigned size; + PTR ptr; + size_t size; { - register char *value = (char *) realloc (ptr, size); + register PTR value = (PTR) realloc (ptr, size); if (value == 0) fatal ("virtual memory exhausted"); return value; Index: gnu/gdb-4.17/opcodes/ChangeLog.linux diff -u /dev/null gnu/gdb-4.17/opcodes/ChangeLog.linux:1.2 --- /dev/null Sat Aug 21 11:58:50 1999 +++ gnu/gdb-4.17/opcodes/ChangeLog.linux Wed May 5 16:32:59 1999 @@ -0,0 +1,10 @@ +Mon Apr 26 17:25:49 1999 H.J. Lu (hjl@gnu.org) + + * i386-dis.c (print_insn_x86): Update from binutils 2.9.1.0.24 + for Pentium/III and AMD 3DNow!. + +Tue Dec 1 19:24:37 1998 H.J. Lu (hjl@gnu.org) + + From Jack Howarth : + + * sparc-opc.c: Space change. Index: gnu/gdb-4.17/opcodes/i386-dis.c diff -u gnu/gdb-4.17/opcodes/i386-dis.c:1.1.1.1 gnu/gdb-4.17/opcodes/i386-dis.c:1.2 --- gnu/gdb-4.17/opcodes/i386-dis.c:1.1.1.1 Fri May 29 06:58:29 1998 +++ gnu/gdb-4.17/opcodes/i386-dis.c Wed May 5 16:32:59 1999 @@ -1,5 +1,5 @@ /* Print i386 instructions for GDB, the GNU debugger. - Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 1997 + Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. This file is part of GDB. @@ -39,6 +39,7 @@ #define MAXLEN 20 #include +#include static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); @@ -51,6 +52,22 @@ jmp_buf bailout; }; +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 +#define INSN_FWAIT 0x1000 + +static int prefixes; + /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) to ADDR (exclusive) are valid. Returns 1 for success, longjmps on error. */ @@ -73,8 +90,17 @@ info); if (status != 0) { - (*info->memory_error_func) (status, start, info); - longjmp (priv->bailout, 1); + if ((prefixes & PREFIX_FWAIT) == PREFIX_FWAIT && status == EIO) + { + /* It is possible that fwait is the last instruction. We make + it an instruction. */ + prefixes = INSN_FWAIT; + return 0; + } + else { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } } else priv->max_fetched = addr; @@ -129,7 +155,9 @@ #define Sw OP_SEG, w_mode #define Ap OP_DIR, lptr +#if 0 #define Av OP_DIR, v_mode +#endif #define Ob OP_OFF, b_mode #define Ov OP_OFF, v_mode #define Xb OP_DSSI, b_mode @@ -145,8 +173,14 @@ #define gs OP_REG, gs_reg #define MX OP_MMX, 0 +#define XM OP_XMM, 0 #define EM OP_EM, v_mode +#define EX OP_EX, v_mode #define MS OP_MS, b_mode +#define None OP_None, 0 +#define TD OP_3DNow, 0 +#define SUF OP_3DNowSuffix, 0 +#define PF OP_PREFETCH, b_mode typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag)); @@ -172,8 +206,14 @@ static int OP_ONE PARAMS ((int, int, int)); #endif static int OP_MMX PARAMS ((int, int, int)); +static int OP_XMM PARAMS ((int, int, int)); static int OP_EM PARAMS ((int, int, int)); +static int OP_EX PARAMS ((int, int, int)); static int OP_MS PARAMS ((int, int, int)); +static int OP_None PARAMS ((int, int, int)); +static int OP_3DNow PARAMS ((int, int, int)); +static int OP_3DNowSuffix PARAMS ((int, int, int)); +static int OP_PREFETCH PARAMS ((int, int, int)); static void append_prefix PARAMS ((void)); static void set_op PARAMS ((int op)); @@ -225,27 +265,48 @@ #define indir_dx_reg 150 -#define GRP1b NULL, NULL, 0 -#define GRP1S NULL, NULL, 1 -#define GRP1Ss NULL, NULL, 2 -#define GRP2b NULL, NULL, 3 -#define GRP2S NULL, NULL, 4 -#define GRP2b_one NULL, NULL, 5 -#define GRP2S_one NULL, NULL, 6 -#define GRP2b_cl NULL, NULL, 7 -#define GRP2S_cl NULL, NULL, 8 -#define GRP3b NULL, NULL, 9 -#define GRP3S NULL, NULL, 10 -#define GRP4 NULL, NULL, 11 -#define GRP5 NULL, NULL, 12 -#define GRP6 NULL, NULL, 13 -#define GRP7 NULL, NULL, 14 -#define GRP8 NULL, NULL, 15 -#define GRP9 NULL, NULL, 16 -#define GRP10 NULL, NULL, 17 -#define GRP11 NULL, NULL, 18 -#define GRP12 NULL, NULL, 19 +#define USE_GROUPS 1 +#define USE_PREFIX_USER_TABLE 2 +#define GRP1b NULL, NULL, 0, NULL, USE_GROUPS +#define GRP1S NULL, NULL, 1, NULL, USE_GROUPS +#define GRP1Ss NULL, NULL, 2, NULL, USE_GROUPS +#define GRP2b NULL, NULL, 3, NULL, USE_GROUPS +#define GRP2S NULL, NULL, 4, NULL, USE_GROUPS +#define GRP2b_one NULL, NULL, 5, NULL, USE_GROUPS +#define GRP2S_one NULL, NULL, 6, NULL, USE_GROUPS +#define GRP2b_cl NULL, NULL, 7, NULL, USE_GROUPS +#define GRP2S_cl NULL, NULL, 8, NULL, USE_GROUPS +#define GRP3b NULL, NULL, 9, NULL, USE_GROUPS +#define GRP3S NULL, NULL, 10, NULL, USE_GROUPS +#define GRP4 NULL, NULL, 11, NULL, USE_GROUPS +#define GRP5 NULL, NULL, 12, NULL, USE_GROUPS +#define GRP6 NULL, NULL, 13, NULL, USE_GROUPS +#define GRP7 NULL, NULL, 14, NULL, USE_GROUPS +#define GRP8 NULL, NULL, 15, NULL, USE_GROUPS +#define GRP9 NULL, NULL, 16, NULL, USE_GROUPS +#define GRP10 NULL, NULL, 17, NULL, USE_GROUPS +#define GRP11 NULL, NULL, 18, NULL, USE_GROUPS +#define GRP12 NULL, NULL, 19, NULL, USE_GROUPS +#define GRP13 NULL, NULL, 20, NULL, USE_GROUPS +#define GRP14 NULL, NULL, 21, NULL, USE_GROUPS + +#define PREGRP0 NULL, NULL, 0, NULL, USE_PREFIX_USER_TABLE +#define PREGRP1 NULL, NULL, 1, NULL, USE_PREFIX_USER_TABLE +#define PREGRP2 NULL, NULL, 2, NULL, USE_PREFIX_USER_TABLE +#define PREGRP3 NULL, NULL, 3, NULL, USE_PREFIX_USER_TABLE +#define PREGRP4 NULL, NULL, 4, NULL, USE_PREFIX_USER_TABLE +#define PREGRP5 NULL, NULL, 5, NULL, USE_PREFIX_USER_TABLE +#define PREGRP6 NULL, NULL, 6, NULL, USE_PREFIX_USER_TABLE +#define PREGRP7 NULL, NULL, 7, NULL, USE_PREFIX_USER_TABLE +#define PREGRP8 NULL, NULL, 8, NULL, USE_PREFIX_USER_TABLE +#define PREGRP9 NULL, NULL, 9, NULL, USE_PREFIX_USER_TABLE +#define PREGRP10 NULL, NULL, 10, NULL, USE_PREFIX_USER_TABLE +#define PREGRP11 NULL, NULL, 11, NULL, USE_PREFIX_USER_TABLE +#define PREGRP12 NULL, NULL, 12, NULL, USE_PREFIX_USER_TABLE +#define PREGRP13 NULL, NULL, 13, NULL, USE_PREFIX_USER_TABLE +#define PREGRP14 NULL, NULL, 14, NULL, USE_PREFIX_USER_TABLE + #define FLOATCODE 50 #define FLOAT NULL, NULL, FLOATCODE @@ -369,8 +430,8 @@ { "popS", eSI }, { "popS", eDI }, /* 60 */ - { "pusha" }, - { "popa" }, + { "pushaS" }, + { "popaS" }, { "boundS", Gv, Ma }, { "arpl", Ew, Gw }, { "(bad)" }, /* seg fs */ @@ -418,9 +479,9 @@ { "movS", Ev, Gv }, { "movb", Gb, Eb }, { "movS", Gv, Ev }, - { "movw", Ew, Sw }, + { "movS", Ev, Sw }, { "leaS", Gv, M }, - { "movw", Sw, Ew }, + { "movS", Sw, Ev }, { "popS", Ev }, /* 90 */ { "nop" }, @@ -522,7 +583,7 @@ { "outb", Ib, AL }, { "outS", Ib, eAX }, /* e8 */ - { "call", Av }, + { "call", Jv }, { "jmp", Jv }, { "ljmp", Ap }, { "jmp", Jb }, @@ -564,12 +625,19 @@ { "invd" }, { "wbinvd" }, { "(bad)" }, { "ud2a" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "prefetch", PF }, { "femms" }, { "3dnow", TD, EM, SUF }, /* 10 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP8 }, + { PREGRP9 }, + { "movlps", XM, Ev }, + { "movlps", Ev, XM }, + { "unpcklps", XM, EX }, + { "unpckhps", XM, EX }, + { "movhps", XM, Ev }, + { "movhps", Ev, XM }, /* 18 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { GRP14 }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, /* 20 */ /* these are all backward in appendix A of the intel book */ @@ -582,11 +650,17 @@ { "movl", Td, Rd }, { "(bad)" }, /* 28 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movaps", XM, EX }, + { "movaps", EX, XM }, + { PREGRP2 }, + { "movntps", Ev, XM }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomiss", XM, EX }, + { "comiss", XM, EX }, /* 30 */ { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "sysenter" }, { "sysexit" }, { "(bad)" }, { "(bad)" }, /* 38 */ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, @@ -597,11 +671,23 @@ { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, /* 50 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movmskps", Ev, XM }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andps", XM, EX }, + { "andnps", XM, EX }, + { "orps", XM, EX }, + { "xorps", XM, EX }, /* 58 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP0 }, + { PREGRP10 }, + { "(bad)" }, + { "(bad)" }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, /* 60 */ { "punpcklbw", MX, EM }, { "punpcklwd", MX, EM }, @@ -620,7 +706,7 @@ { "movd", MX, Ev }, { "movq", MX, EM }, /* 70 */ - { "(bad)" }, + { "pshufw", MX, EM, Ib }, { GRP10 }, { GRP11 }, { GRP12 }, @@ -685,7 +771,7 @@ { "btsS", Ev, Gv }, { "shrdS", Ev, Gv, Ib }, { "shrdS", Ev, Gv, CL }, - { "(bad)" }, + { GRP13 }, { "imulS", Gv, Ev }, /* b0 */ { "cmpxchgb", Eb, Gb }, @@ -708,11 +794,11 @@ /* c0 */ { "xaddb", Eb, Gb }, { "xaddS", Ev, Gv }, - { "(bad)" }, + { PREGRP1 }, { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "pinsrw", MX, Ev, Ib }, + { "pextrw", Ev, MX, Ib }, + { "shufps", XM, EX, Ib }, { GRP9 }, /* c8 */ { "bswap", eAX }, @@ -730,32 +816,34 @@ { "psrlq", MX, EM }, { "(bad)" }, { "pmullw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)" }, + { "pmovmskb", Ev, MX }, /* d8 */ { "psubusb", MX, EM }, { "psubusw", MX, EM }, - { "(bad)" }, + { "pminub", MX, EM }, { "pand", MX, EM }, { "paddusb", MX, EM }, { "paddusw", MX, EM }, - { "(bad)" }, + { "pmaxub", MX, EM }, { "pandn", MX, EM }, /* e0 */ - { "(bad)" }, + { "pavgb", MX, EM }, { "psraw", MX, EM }, { "psrad", MX, EM }, - { "(bad)" }, - { "(bad)" }, + { "pavgw", MX, EM }, + { "pmulhuw", MX, EM }, { "pmulhw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)" }, + { "movntq", Ev, MX }, /* e8 */ { "psubsb", MX, EM }, { "psubsw", MX, EM }, - { "(bad)" }, + { "pminsw", MX, EM }, { "por", MX, EM }, { "paddsb", MX, EM }, { "paddsw", MX, EM }, - { "(bad)" }, + { "pmaxsw", MX, EM }, { "pxor", MX, EM }, /* f0 */ { "(bad)" }, @@ -764,7 +852,8 @@ { "psllq", MX, EM }, { "(bad)" }, { "pmaddwd", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "psadbw", MX, EM }, + { "maskmovq", MX, EM }, /* f8 */ { "psubb", MX, EM }, { "psubw", MX, EM }, @@ -796,22 +885,49 @@ }; static const unsigned char twobyte_has_modrm[256] = { - /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 2f */ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1, /* 5f */ /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ - /* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */ - /* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */ - /* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0 /* ff */ + /* d0 */ 0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_f3_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; static char obuf[100]; @@ -1061,29 +1177,125 @@ { "(bad)" }, { "psllq", MS, Ib }, { "(bad)" }, + }, + /* GRP13 */ + { + { "fxsave", Ev }, + { "fxrstor", Ev }, + { "ldmxcsr", Ev }, + { "stmxcsr", Ev }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "sfence", None }, + }, + /* GRP14 */ + { + { "prefetchnta", Ev }, + { "prefetcht0", Ev }, + { "prefetcht1", Ev }, + { "prefetcht2", Ev }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, } }; -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADR 0x400 -#define PREFIX_FWAIT 0x800 +static const char *simd_cmp_op [] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; -static int prefixes; +static struct dis386 prefix_user_table[][2] = { + /* PREGRP0 */ + { + { "addps", XM, EX }, + { "addss", XM, EX }, + }, + /* PREGRP1 */ + { + { "cmp%sps", XM, EX, Ib }, + { "cmp%sss", XM, EX, Ib }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM }, + { "cvtsi2ss", XM, Ev }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX }, + { "cvtss2si", Gv, EX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX }, + { "cvttss2si", Gv, EX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX }, + { "divss", XM, EX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX }, + { "maxss", XM, EX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX }, + { "minss", XM, EX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX }, + { "movss", XM, EX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM }, + { "movss", EX, XM }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX }, + { "mulss", XM, EX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX }, + { "rcpss", XM, EX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX }, + { "rsqrtss", XM, EX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX }, + { "sqrtss", XM, EX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX }, + { "subss", XM, EX }, + } +}; static void ckprefix () { prefixes = 0; - while (1) + while (prefixes != INSN_FWAIT) { FETCH_DATA (the_info, codep + 1); switch (*codep) @@ -1164,6 +1376,8 @@ print_insn_x86 (pc, info, aflag, dflag) bfd_vma pc; disassemble_info *info; + int aflag; + int dflag; { struct dis386 *dp; int i; @@ -1171,13 +1385,16 @@ char *first, *second, *third; int needcomma; unsigned char need_modrm; + unsigned char uses_f3_prefix; + unsigned char opcode; + int simd_cmp = 0; struct dis_private priv; bfd_byte *inbuf = priv.the_buffer; - /* The output looks better if we put 5 bytes on a line, since that + /* The output looks better if we put 7 bytes on a line, since that puts long word instructions on a single line. */ - info->bytes_per_line = 5; + info->bytes_per_line = 7; info->private_data = (PTR) &priv; priv.max_fetched = priv.the_buffer; @@ -1200,6 +1417,13 @@ ckprefix (); + if (prefixes == INSN_FWAIT) + { + /* fwait not followed by any instructions */ + (*info->fprintf_func) (info->stream, "fwait"); + return (1); + } + FETCH_DATA (info, codep + 1); if (*codep == 0xc8) enter_instruction = 1; @@ -1207,9 +1431,7 @@ enter_instruction = 0; obufp = obuf; - - if (prefixes & PREFIX_REPZ) - oappend ("repz "); + if (prefixes & PREFIX_REPNZ) oappend ("repnz "); if (prefixes & PREFIX_LOCK) @@ -1240,13 +1462,19 @@ FETCH_DATA (info, codep + 2); dp = &dis386_twobyte[*++codep]; need_modrm = twobyte_has_modrm[*codep]; + uses_f3_prefix = twobyte_uses_f3_prefix[*codep]; } else { dp = &dis386[*codep]; need_modrm = onebyte_has_modrm[*codep]; + uses_f3_prefix = 0; } + opcode = *codep; codep++; + + if (!uses_f3_prefix && (prefixes & PREFIX_REPZ)) + oappend ("repz "); if (need_modrm) { @@ -1263,7 +1491,20 @@ else { if (dp->name == NULL) - dp = &grps[dp->bytemode1][reg]; + { + switch(dp->bytemode2) + { + case USE_GROUPS: + dp = &grps[dp->bytemode1][reg]; + break; + case USE_PREFIX_USER_TABLE: + simd_cmp = dp->bytemode1 == 1; + dp = &prefix_user_table[dp->bytemode1][prefixes & 0x01]; + break; + default: + return(1); + } + } putop (dp->name, aflag, dflag); @@ -1277,10 +1518,19 @@ if (dp->op2) (*dp->op2)(dp->bytemode2, aflag, dflag); - obufp = op3out; - op_ad = 0; - if (dp->op3) - (*dp->op3)(dp->bytemode3, aflag, dflag); + if (simd_cmp) + { + FETCH_DATA (the_info, codep + 1); + sprintf (scratchbuf, obuf, simd_cmp_op [*codep++ & 0xff]); + strcpy (obuf, scratchbuf); + } + else + { + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3, aflag, dflag); + } } obufp = obuf + strlen (obuf); @@ -1641,6 +1891,14 @@ { char *p; + if ((prefixes & PREFIX_FWAIT) && !strchr (template, 'N')) + { + /* We print out fwait if it is not the part of the instuctions. */ +#define FWAIT_STRING "fwait; " + strcat (obufp, FWAIT_STRING); + obufp += sizeof (FWAIT_STRING) - 1; + } + for (p = template; *p; p++) { switch (*p) @@ -1711,6 +1969,20 @@ return OP_E (bytemode, aflag, dflag); } +static int OP_PREFETCH(bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + switch(reg) { + case 1: + obufp=obuf; oappend("prefetchw "); + break; + default: + } + return OP_E (bytemode, aflag, dflag); +} + static int OP_E (bytemode, aflag, dflag) int bytemode; @@ -1753,8 +2025,8 @@ int havesib; int havebase; int base; - int index; - int scale; + int index = 0; + int scale = 0; havesib = 0; havebase = 1; @@ -2095,7 +2367,7 @@ switch (size) { case lptr: - if (aflag) + if (dflag) { offset = get32 (); seg = get16 (); @@ -2108,8 +2380,9 @@ sprintf (scratchbuf, "0x%x,0x%x", seg, offset); oappend (scratchbuf); break; +#if 0 case v_mode: - if (aflag) + if (dflag) offset = get32 (); else { @@ -2123,6 +2396,7 @@ sprintf (scratchbuf, "0x%x", offset); oappend (scratchbuf); break; +#endif default: oappend (""); break; @@ -2171,7 +2445,16 @@ int aflag; int dflag; { - oappend ("%ds:("); + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_prefix (); + oappend ("("); oappend (aflag ? "%esi" : "%si"); oappend (")"); return (0); @@ -2262,6 +2545,17 @@ } static int +OP_XMM (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%xmm%d", reg); + oappend (scratchbuf); + return 0; +} + +static int OP_EM (bytemode, aflag, dflag) int bytemode; int aflag; @@ -2277,6 +2571,21 @@ } static int +OP_EX (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + if (mod != 3) + return OP_E (bytemode, aflag, dflag); + + codep++; + sprintf (scratchbuf, "%%xmm%d", rm); + oappend (scratchbuf); + return 0; +} + +static int OP_MS (bytemode, aflag, dflag) int bytemode; int aflag; @@ -2285,5 +2594,112 @@ ++codep; sprintf (scratchbuf, "%%mm%d", rm); oappend (scratchbuf); + return 0; +} + +static int +OP_None (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + ++codep; + return 0; +} + +static int +OP_3DNow (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%mm%d", reg); + oappend (scratchbuf); + return 0; +} + +static char *_3DNowSuffixes[]= { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ NULL, "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ NULL, "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, NULL, NULL, +/* 8C */ NULL, NULL, NULL, NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, NULL, +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static int +OP_3DNowSuffix (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + FETCH_DATA (the_info, codep + 1); + if (_3DNowSuffixes[*codep]) { + /* HACK */ + obufp=obuf; + oappend(_3DNowSuffixes[*codep++]); + oappend(" "); + } else { + sprintf (scratchbuf, "0x%x", *codep++); + oappend (scratchbuf); + } return 0; } Index: gnu/gdb-4.17/opcodes/sparc-opc.c diff -u gnu/gdb-4.17/opcodes/sparc-opc.c:1.1.1.1 gnu/gdb-4.17/opcodes/sparc-opc.c:1.2 --- gnu/gdb-4.17/opcodes/sparc-opc.c:1.1.1.1 Fri May 29 06:58:31 1998 +++ gnu/gdb-4.17/opcodes/sparc-opc.c Tue Dec 1 21:52:03 1998 @@ -1317,7 +1317,7 @@ { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G", flags|F_DELAYED|F_FBR, v9 }, \ { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED|F_FBR, v9 }, \ - { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 } + { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 } /* v9: We must put `FBRX' before `FBR', to ensure that we never match v9: something against an expression unless it is an expression. Otherwise,