From c4f35dd8e1037d2a8e1aa11894cb67de96279bfa Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Sat, 31 May 2003 08:15:38 +0000 Subject: [PATCH] * x86-64-tdep.h (x86_64_num_regs, x86_64_num_gregs): Remove variable declarations. (x86_64_register_number, x86_64_register_name): Remove prototypes. (x86_64_linux_frame_saved_pc, x86_64_linux+saved_pc_after_call, x86_64_linux_in_sigtramp, x86_64_linux_frame_chain, x86_64_init_frame_pc, x86_64_init_frame_pc, x86_64_function_has_prologue): Remove prototypes. (X86_64_NUM_GREGS): New define. (x86_64_supply_fxsave, x86_64_fill_fxsave): New prototypes. * x86-64-tdep.c: Don't include "dwarf2cfi.h". Include "dummy_frame.h", "frame.h", "frame-base.h", "frame-unwind.h". (RAX_REGNUM, RDX_REGNUM, RDI_REGNUM, EFLAGS_REGNUM, ST0_REGNUM, XMM1_REGNUM): Remove defines. (X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, X86_64_RDI_REGNUM, X86_64_RBP_REGNUM, X86_64_RSP_REGNUM, X86_64_RIP_REGNUM, X86_64_EFLAGS_REGNUM, X86_64_ST0_REGNUM, X86_64_XMM0_REGNUM, X86_64_XMM1_REGNUM): New defines. (struct x86_64_register_info): Renamed from `struct register_info'. Remove `size' member. (x86_64_register_info_table): Remove variable. (x86_64_register_info): New variable. (X86_64_NUM_REGS): New define. (X86_64_NUM_GREGS): Remove define. (x86_64_num_regs, x86_64_num_gregs): Remove variables. (x86_64_dwarf2gdb_regno_map, x86_64_dwarf2gdb_regno_map_length): Remove variables. (x86_54_dwarf2_reg_to_regnum): Remove function. (x86_64_dwarf_regmap, x86_64_dwarf_regmap_len): New variables. (x86_64_dwarf_reg_to_regnum): New function. (x86_64_register_name): Rewrite. (x86_64_register_raw_size): Remove function. (x86_64_register_byte_table): Remove variable. (x86_64_register_byte): Remove function. (x86_64_register_virtual_type): Remove function. (x86_64_register_type): New function. (x86_64_register_convertible, x86_64_register_convert_to_virtual, x86_64_register_convert_to_raw): Remove functions. (x86_64_push_return_address, x86_64_pop_frame): Remove functon. (x86_64_use_struct_convention): Make static. Adjust for renamed defines. (x86_64_frame_init_saved_regs): Remove function. (x86_64_push_arguments): Make static. Change to accept a regcache as argument. (x86_64_store_return_value, x86_64_extract_return_value): Make static. Rewrite based on i386 counterparts. (x86_64_push_dummy_call): New function. (X86_64_NUM_SAVED_REGS): New define. (x86_64_register_number): Remove function. (x86_64_store_struct_return): Remove function. (x86_64_frameless_function_invocation, x86_64_function_has_prologue): Remove functions. (PROLOG_BUFSIZE): Remove define. (struct x86_64_frame_cache): New structure. (x86_64_alloc_frame_cache, x86_64_analyze_prologue, x86_64_frame_cache, x86_64_frame_this_id, x86_64_frame_prev_register, x86_64_frame_p, x86_64_sigtramp_frame_cache, x86_64_sigtramp_frame_this_id, x86_64_sigtramp_frame_prev_register, x86_sigtramp_frame_p): New functions. (x86_64_frame_unwind, x86_64_sigtramp_frame_unwind): New variables. (x86_64_skip_prologue): Rewrite in terms of x86_64_analyze_prologue. (x86_64_frame_base_address): New function. (x86_64_frame_base): New variable. (x86_64_save_dummy_frame_tos, x86_64_unwind_dummy_id): Rewrite. (x86_64_init_abi): Set register_type and push_dummy_call. Don't set deprecated_fp_regnum, deprecated_register_size, deprecated_register_bytes, register_raw_size, register_byte, register_virtual_type, register_convertiable, register_convert_to_virtual, convert_to_raw, deprecated_get_saved_register, deprecated_target_read_fp, deprecated_push_arguments, deprecated_push_return_address, deprecated_pop_frame, deprecated_store_struct_return, deprecated_frame_init_saved_regs, deprecated_frame_chain, frameless_function_invocation, deprecated_frame_saved_pc, deprecated_saved_pc_after_call, frame_num_args, pc_in_sigtramp, dwarf2_build_frame_info, deprecated_init_extra_frame_info, deprecated_init_frame_pc and virtual_frame_pointer. Call frame_unwind_append_predicate to register x86_64_sigtramp_frame_p and x86_64_frame_p. Call frame_base_set_default to register x86_64_frame_base. (I387_FISEG_REGNUM, I387_FOSEG_REGNUM): New defines. (x86_64_supply_fxsave, x86_64_fill_fxsave): New functions. (_initialize_x86_64_tdep): Remove function. * x86-64-linux-tdep.c: Don't include "dwarf2cfi.h". (LINUX_SIGINFO_SIZE, LINUX_UCONTEXT_SIGCONTEXT_OFFSET, LINUX_SIGCONTEXT_PC_OFFSET, LINUX_SIGCONTEXT_FP_OFFSET): Don't define. (X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Define. (x86_64_linux_sigcontext_addr): Rewrite. (x86_64_linux_sigtramp_saved_pc, x86_64_linux_saved_pc_after_call, x86_64_linux_frame_saved_pc): Remove functions. (x86_64_linux_pc_in_sigtramp): Renamed from x86_64_linux_in_sigtramp. Try harder to recognize a signal trampoline. (x86_64_linux_frame_chain, x86_64_init_frame_pc): Remove_functions. (x86_64_linux_init_abi): Set pc_in_sigtramp. Initialize TDEP->sigcontext_addr, TDEP->sc_pc_offset and TDEP->sc_sp_offset. * x86-64-linux-nat.c: Sync with i386-linux-tdep.c. (x86_64_regmap): Rename to regmap. (GETREGS_SUPPLIES): Use X86_64_NUM_GREGS instead of x86_64_num_gregs. (supply_gregset, fill_gregset): Likewise. Use regmap instead of x86_64_regmap. (x86_64_fxsave_offset): Remove function. (supply_fpregset): Simply call x86_64_supply_fxsave. (fill_fpregset): Simply call x86_64_fill_fxsave. (fetch_inferior_registers, store_inferior_registers): Avoid asignment in if-statement. (LINUX_SYSCALL_LEN, LINUX_SYSCALL_REGNUM, SYS_Sigreturn, SYS_rt_sigreturn, LINUX_SIGCONTEXT_EFLAGS_OFFSET, LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Remove defines. (fetch_core_registers): Remove function. (linux_elf_core_fns): Remove. (offsetoff): Don't define. (_initialize_x86_64_linux_nat, kernel_u_size): Remove functions. * config/i386/x86-64linux.mt (TDEPFILES): Add i386-linux-tdep.o. * config/i386/x86-64linux.mh (NATDEPFILES): Remove core-aout.o, add core-regset.o. * config/i386/nm-x86-64linux.h: Use NM_X86_64_LINUX_H for protection against multiple includes instead of NM_X86_64_h. Add various comments. Include "config/nm-linux.h". Don't include . (REGISTER_U_ADDR, KERNEL_U_SIZE, U_REGS_OFFSET, KERN_U_ADDR, GET_THREAD_SIGNALS): Remove defines. (x86_64_register_u_addr, kernel_u_size, lin_thread_get_thread_signals): Remove prototypes. (PTRACE_ARG3_TYPE, PTRACE_XFER_TYPE): Define to `long'. [HAVE_LINK_H]: Don't include "solib.h". [HAVE_LINK_H] (SVR4_SHARED_LIBS): Remove define. * config/i386/tm-x86-64linux.h: Fix comments. * Makefile.in (x86-64-linux-nat.o, x86_64-linux-tdep.o, x86-64-tdep.o): Update dependencies. --- gdb/ChangeLog | 138 +++++ gdb/Makefile.in | 14 +- gdb/config/i386/nm-x86-64linux.h | 54 +- gdb/config/i386/tm-x86-64linux.h | 10 +- gdb/config/i386/x86-64linux.mh | 7 +- gdb/config/i386/x86-64linux.mt | 4 +- gdb/x86-64-linux-nat.c | 342 ++++-------- gdb/x86-64-linux-tdep.c | 178 ++----- gdb/x86-64-tdep.c | 1075 ++++++++++++++++++++++---------------- gdb/x86-64-tdep.h | 33 +- 10 files changed, 978 insertions(+), 877 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c42772f..7e40903 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,141 @@ +2003-05-31 Mark Kettenis + + * x86-64-tdep.h (x86_64_num_regs, x86_64_num_gregs): Remove + variable declarations. + (x86_64_register_number, x86_64_register_name): Remove prototypes. + (x86_64_linux_frame_saved_pc, x86_64_linux+saved_pc_after_call, + x86_64_linux_in_sigtramp, x86_64_linux_frame_chain, + x86_64_init_frame_pc, x86_64_init_frame_pc, + x86_64_function_has_prologue): Remove prototypes. + (X86_64_NUM_GREGS): New define. + (x86_64_supply_fxsave, x86_64_fill_fxsave): New prototypes. + * x86-64-tdep.c: Don't include "dwarf2cfi.h". Include + "dummy_frame.h", "frame.h", "frame-base.h", "frame-unwind.h". + (RAX_REGNUM, RDX_REGNUM, RDI_REGNUM, EFLAGS_REGNUM, ST0_REGNUM, + XMM1_REGNUM): Remove defines. + (X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, X86_64_RDI_REGNUM, + X86_64_RBP_REGNUM, X86_64_RSP_REGNUM, X86_64_RIP_REGNUM, + X86_64_EFLAGS_REGNUM, X86_64_ST0_REGNUM, X86_64_XMM0_REGNUM, + X86_64_XMM1_REGNUM): New defines. + (struct x86_64_register_info): Renamed from `struct + register_info'. Remove `size' member. + (x86_64_register_info_table): Remove variable. + (x86_64_register_info): New variable. + (X86_64_NUM_REGS): New define. + (X86_64_NUM_GREGS): Remove define. + (x86_64_num_regs, x86_64_num_gregs): Remove variables. + (x86_64_dwarf2gdb_regno_map, x86_64_dwarf2gdb_regno_map_length): + Remove variables. + (x86_54_dwarf2_reg_to_regnum): Remove function. + (x86_64_dwarf_regmap, x86_64_dwarf_regmap_len): New variables. + (x86_64_dwarf_reg_to_regnum): New function. + (x86_64_register_name): Rewrite. + (x86_64_register_raw_size): Remove function. + (x86_64_register_byte_table): Remove variable. + (x86_64_register_byte): Remove function. + (x86_64_register_virtual_type): Remove function. + (x86_64_register_type): New function. + (x86_64_register_convertible, x86_64_register_convert_to_virtual, + x86_64_register_convert_to_raw): Remove functions. + (x86_64_push_return_address, x86_64_pop_frame): Remove functon. + (x86_64_use_struct_convention): Make static. Adjust for renamed + defines. + (x86_64_frame_init_saved_regs): Remove function. + (x86_64_push_arguments): Make static. Change to accept a regcache + as argument. + (x86_64_store_return_value, x86_64_extract_return_value): Make + static. Rewrite based on i386 counterparts. + (x86_64_push_dummy_call): New function. + (X86_64_NUM_SAVED_REGS): New define. + (x86_64_register_number): Remove function. + (x86_64_store_struct_return): Remove function. + (x86_64_frameless_function_invocation, + x86_64_function_has_prologue): Remove functions. + (PROLOG_BUFSIZE): Remove define. + (struct x86_64_frame_cache): New structure. + (x86_64_alloc_frame_cache, x86_64_analyze_prologue, + x86_64_frame_cache, x86_64_frame_this_id, + x86_64_frame_prev_register, x86_64_frame_p, + x86_64_sigtramp_frame_cache, x86_64_sigtramp_frame_this_id, + x86_64_sigtramp_frame_prev_register, x86_sigtramp_frame_p): New + functions. + (x86_64_frame_unwind, x86_64_sigtramp_frame_unwind): New + variables. + (x86_64_skip_prologue): Rewrite in terms of + x86_64_analyze_prologue. + (x86_64_frame_base_address): New function. + (x86_64_frame_base): New variable. + (x86_64_save_dummy_frame_tos, x86_64_unwind_dummy_id): Rewrite. + (x86_64_init_abi): Set register_type and push_dummy_call. Don't + set deprecated_fp_regnum, deprecated_register_size, + deprecated_register_bytes, register_raw_size, register_byte, + register_virtual_type, register_convertiable, + register_convert_to_virtual, convert_to_raw, + deprecated_get_saved_register, deprecated_target_read_fp, + deprecated_push_arguments, deprecated_push_return_address, + deprecated_pop_frame, deprecated_store_struct_return, + deprecated_frame_init_saved_regs, deprecated_frame_chain, + frameless_function_invocation, deprecated_frame_saved_pc, + deprecated_saved_pc_after_call, frame_num_args, pc_in_sigtramp, + dwarf2_build_frame_info, deprecated_init_extra_frame_info, + deprecated_init_frame_pc and virtual_frame_pointer. Call + frame_unwind_append_predicate to register x86_64_sigtramp_frame_p + and x86_64_frame_p. Call frame_base_set_default to register + x86_64_frame_base. + (I387_FISEG_REGNUM, I387_FOSEG_REGNUM): New defines. + (x86_64_supply_fxsave, x86_64_fill_fxsave): New functions. + (_initialize_x86_64_tdep): Remove function. + * x86-64-linux-tdep.c: Don't include "dwarf2cfi.h". + (LINUX_SIGINFO_SIZE, LINUX_UCONTEXT_SIGCONTEXT_OFFSET, + LINUX_SIGCONTEXT_PC_OFFSET, LINUX_SIGCONTEXT_FP_OFFSET): Don't + define. + (X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Define. + (x86_64_linux_sigcontext_addr): Rewrite. + (x86_64_linux_sigtramp_saved_pc, x86_64_linux_saved_pc_after_call, + x86_64_linux_frame_saved_pc): Remove functions. + (x86_64_linux_pc_in_sigtramp): Renamed from + x86_64_linux_in_sigtramp. Try harder to recognize a signal + trampoline. + (x86_64_linux_frame_chain, x86_64_init_frame_pc): + Remove_functions. + (x86_64_linux_init_abi): Set pc_in_sigtramp. Initialize + TDEP->sigcontext_addr, TDEP->sc_pc_offset and TDEP->sc_sp_offset. + * x86-64-linux-nat.c: Sync with i386-linux-tdep.c. + (x86_64_regmap): Rename to regmap. + (GETREGS_SUPPLIES): Use X86_64_NUM_GREGS instead of + x86_64_num_gregs. + (supply_gregset, fill_gregset): Likewise. Use regmap instead of + x86_64_regmap. + (x86_64_fxsave_offset): Remove function. + (supply_fpregset): Simply call x86_64_supply_fxsave. + (fill_fpregset): Simply call x86_64_fill_fxsave. + (fetch_inferior_registers, store_inferior_registers): Avoid + asignment in if-statement. + (LINUX_SYSCALL_LEN, LINUX_SYSCALL_REGNUM, SYS_Sigreturn, + SYS_rt_sigreturn, LINUX_SIGCONTEXT_EFLAGS_OFFSET, + LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Remove defines. + (fetch_core_registers): Remove function. + (linux_elf_core_fns): Remove. + (offsetoff): Don't define. + (_initialize_x86_64_linux_nat, kernel_u_size): Remove functions. + * config/i386/x86-64linux.mt (TDEPFILES): Add i386-linux-tdep.o. + * config/i386/x86-64linux.mh (NATDEPFILES): Remove core-aout.o, + add core-regset.o. + * config/i386/nm-x86-64linux.h: Use NM_X86_64_LINUX_H for + protection against multiple includes instead of NM_X86_64_h. Add + various comments. Include "config/nm-linux.h". Don't include + . + (REGISTER_U_ADDR, KERNEL_U_SIZE, U_REGS_OFFSET, KERN_U_ADDR, + GET_THREAD_SIGNALS): Remove defines. + (x86_64_register_u_addr, kernel_u_size, + lin_thread_get_thread_signals): Remove prototypes. + (PTRACE_ARG3_TYPE, PTRACE_XFER_TYPE): Define to `long'. + [HAVE_LINK_H]: Don't include "solib.h". + [HAVE_LINK_H] (SVR4_SHARED_LIBS): Remove define. + * config/i386/tm-x86-64linux.h: Fix comments. + * Makefile.in (x86-64-linux-nat.o, x86_64-linux-tdep.o, + x86-64-tdep.o): Update dependencies. + 2003-05-30 Andrew Cagney * config/sparc/tm-sparc.h (sparc_extract_struct_value_address): diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 35125d9..166fb23 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2350,13 +2350,15 @@ wince.o: wince.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) $(gdbcore_h) \ $(regcache_h) wrapper.o: wrapper.c $(defs_h) $(value_h) $(wrapper_h) x86-64-linux-nat.o: x86-64-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ - $(regcache_h) $(gdb_assert_h) $(x86_64_tdep_h) + $(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(gregset_h) \ + $(x86_64_tdep_h) x86-64-linux-tdep.o: x86-64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ - $(gdb_string_h) $(regcache_h) $(x86_64_tdep_h) $(dwarf2cfi_h) \ - $(osabi_h) -x86-64-tdep.o: x86-64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ - $(gdbcmd_h) $(arch_utils_h) $(regcache_h) $(symfile_h) $(objfiles_h) \ - $(x86_64_tdep_h) $(dwarf2cfi_h) $(gdb_assert_h) $(block_h) + $(regcache_h) $(osabi_h) $(gdb_string_h) $(x86_64_tdep_h) +x86-64-tdep.o: x86-64-tdep.c $(defs_h) \ + $(inferior_h) $(gdbcore_h) $(arch_utils_h) $(block_h) \ + $(dummy_frame_h) $(frame_h) $(frame_base_h) $(frame_unwind_h) \ + $(inferior_h) $(gdbcmd_h) $(gdbcode_h) $(objfiles_h) $(regcache_h) \ + $(symfile_h) $(gdb_assert_h) $(x86_64_tdep_h) $(i387_tdep_h) xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \ $(coff_internal_h) $(libcoff_h) $(coff_xcoff_h) $(libxcoff_h) \ $(coff_rs6000_h) $(symtab_h) $(gdbtypes_h) $(symfile_h) \ diff --git a/gdb/config/i386/nm-x86-64linux.h b/gdb/config/i386/nm-x86-64linux.h index 4430fcb..4df2f5d 100644 --- a/gdb/config/i386/nm-x86-64linux.h +++ b/gdb/config/i386/nm-x86-64linux.h @@ -1,7 +1,8 @@ /* Native support for GNU/Linux x86-64. - Copyright 2001, 2002 Free Software Foundation, Inc. Contributed by - Jiri Smid, SuSE Labs. + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + + Contributed by Jiri Smid, SuSE Labs. This file is part of GDB. @@ -20,15 +21,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef NM_X86_64_H -#define NM_X86_64_H - -#include "config/nm-linux.h" +#ifndef NM_X86_64_LINUX_H +#define NM_X86_64_LINUX_H +/* GNU/Linux supports the i386 hardware debugging registers. */ #define I386_USE_GENERIC_WATCHPOINTS + #include "i386/nm-i386.h" +#include "config/nm-linux.h" -/* Support for 8-byte wide hw watchpoints. */ +/* Support for 8-byte wide hardware watchpoints. */ #define TARGET_HAS_DR_LEN_8 1 /* Provide access to the i386 hardware debugging registers. */ @@ -50,41 +52,17 @@ extern unsigned long x86_64_linux_dr_get_status (void); x86_64_linux_dr_get_status () -#define REGISTER_U_ADDR(addr, blockend, regno) \ - (addr) = x86_64_register_u_addr ((blockend),(regno)); -CORE_ADDR x86_64_register_u_addr (CORE_ADDR, int); - -/* Return the size of the user struct. */ -#define KERNEL_U_SIZE kernel_u_size() -extern int kernel_u_size (void); - -/* Offset of the registers within the user area. */ -#define U_REGS_OFFSET 0 - -/* 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 PTRACE_ARG3_TYPE void* -#define PTRACE_XFER_TYPE unsigned long - - -/* We define this if link.h is available, because with ELF we use SVR4 style - shared libraries. */ +/* Type of the third argument to the `ptrace' system call. */ +#define PTRACE_ARG3_TYPE long -#ifdef HAVE_LINK_H -#define SVR4_SHARED_LIBS -#include "solib.h" /* Support for shared libraries. */ -#endif +/* Type of the fourth argument to the `ptrace' system call. */ +#define PTRACE_XFER_TYPE long /* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */ #define FETCH_INFERIOR_REGISTERS + +/* FIXME: kettenis/20030416: Why? */ #undef PREPARE_TO_PROCEED -#include - -extern void lin_thread_get_thread_signals (sigset_t * mask); -#define GET_THREAD_SIGNALS(mask) lin_thread_get_thread_signals (mask) - -#endif /* NM_X86_64.h */ +#endif /* NM_X86_64_LINUX_H */ diff --git a/gdb/config/i386/tm-x86-64linux.h b/gdb/config/i386/tm-x86-64linux.h index 11eea93..4c16766 100644 --- a/gdb/config/i386/tm-x86-64linux.h +++ b/gdb/config/i386/tm-x86-64linux.h @@ -1,6 +1,6 @@ /* Definitions to target GDB to GNU/Linux on x86-64. - Copyright 2002 Free Software Foundation, Inc. + Copyright 2002, 2003 Free Software Foundation, Inc. Contributed by Michal Ludvig, SuSE Labs. @@ -25,10 +25,10 @@ #define TM_X86_64LINUX_H /* We define SVR4_SHARED_LIBS unconditionally, on the assumption that - * link.h is available on all linux platforms. For I386 and SH3/4, - * we hard-code the information rather than use link.h anyway (for - * the benefit of cross-debugging). We may move to doing that for - * other architectures as well. */ + link.h is available on all linux platforms. For I386 and SH3/4, we + hard-code the information rather than use link.h anyway (for the + benefit of cross-debugging). We may move to doing that for other + architectures as well. */ #define SVR4_SHARED_LIBS #include "solib.h" /* Support for shared libraries. */ diff --git a/gdb/config/i386/x86-64linux.mh b/gdb/config/i386/x86-64linux.mh index 7c221eb..895d1fb 100644 --- a/gdb/config/i386/x86-64linux.mh +++ b/gdb/config/i386/x86-64linux.mh @@ -4,8 +4,9 @@ XM_FILE= xm-i386.h NAT_FILE= nm-x86-64linux.h NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \ - core-aout.o i386-nat.o x86-64-linux-nat.o \ - proc-service.o thread-db.o lin-lwp.o \ - linux-proc.o gcore.o + core-regset.o i386-nat.o x86-64-linux-nat.o \ + proc-service.o thread-db.o lin-lwp.o linux-proc.o gcore.o +# The dynamically loaded libthread_db needs access to symbols in the +# gdb executable. LOADLIBES = -ldl -rdynamic diff --git a/gdb/config/i386/x86-64linux.mt b/gdb/config/i386/x86-64linux.mt index d0ffb34..d448452 100644 --- a/gdb/config/i386/x86-64linux.mt +++ b/gdb/config/i386/x86-64linux.mt @@ -1,6 +1,6 @@ # Target: AMD x86-64 running GNU/Linux -TDEPFILES= x86-64-tdep.o x86-64-linux-tdep.o dwarf2cfi.o \ - i386-tdep.o i387-tdep.o \ +TDEPFILES= x86-64-tdep.o x86-64-linux-tdep.o \ + i386-tdep.o i387-tdep.o i386-linux-tdep.o \ solib.o solib-svr4.o solib-legacy.o GDB_MULTI_ARCH=GDB_MULTI_ARCH_TM diff --git a/gdb/x86-64-linux-nat.c b/gdb/x86-64-linux-nat.c index 044236c..1200b08 100644 --- a/gdb/x86-64-linux-nat.c +++ b/gdb/x86-64-linux-nat.c @@ -25,20 +25,30 @@ #include "inferior.h" #include "gdbcore.h" #include "regcache.h" + #include "gdb_assert.h" #include "gdb_string.h" -#include "x86-64-tdep.h" - #include #include #include #include #include +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" + +#include "x86-64-tdep.h" + +/* The register sets used in GNU/Linux ELF core-dumps are identical to + the register sets used by `ptrace'. The corresponding types are + `elf_gregset_t' for the general-purpose registers (with + `elf_greg_t' the type of a single GP register) and `elf_fpregset_t' + for the floating-point registers. + /* Mapping between the general-purpose registers in `struct user' format and GDB's register array layout. */ - -static int x86_64_regmap[] = { +static int regmap[] = +{ RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, @@ -47,85 +57,12 @@ static int x86_64_regmap[] = { DS, ES, FS, GS }; -static unsigned long -x86_64_linux_dr_get (int regnum) -{ - int tid; - unsigned long value; - - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); - - /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the - ptrace call fails breaks debugging remote targets. The correct - way to fix this is to add the hardware breakpoint and watchpoint - stuff to the target vectore. For now, just return zero if the - ptrace call fails. */ - errno = 0; - value = ptrace (PT_READ_U, tid, - offsetof (struct user, u_debugreg[regnum]), 0); - if (errno != 0) -#if 0 - perror_with_name ("Couldn't read debug register"); -#else - return 0; -#endif - - return value; -} - -static void -x86_64_linux_dr_set (int regnum, unsigned long value) -{ - int tid; - - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); - - errno = 0; - ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); - if (errno != 0) - perror_with_name ("Couldn't write debug register"); -} - -void -x86_64_linux_dr_set_control (unsigned long control) -{ - x86_64_linux_dr_set (DR_CONTROL, control); -} - -void -x86_64_linux_dr_set_addr (int regnum, CORE_ADDR addr) -{ - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - x86_64_linux_dr_set (DR_FIRSTADDR + regnum, addr); -} - -void -x86_64_linux_dr_reset_addr (int regnum) -{ - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - x86_64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); -} - -unsigned long -x86_64_linux_dr_get_status (void) -{ - return x86_64_linux_dr_get (DR_STATUS); -} - - -/* The register sets used in GNU/Linux ELF core-dumps are identical to - the register sets used by `ptrace'. */ +/* Which ptrace request retrieves which registers? + These apply to the corresponding SET requests as well. */ #define GETREGS_SUPPLIES(regno) \ - (0 <= (regno) && (regno) < x86_64_num_gregs) + (0 <= (regno) && (regno) < X86_64_NUM_GREGS) + #define GETFPREGS_SUPPLIES(regno) \ (FP0_REGNUM <= (regno) && (regno) <= MXCSR_REGNUM) @@ -137,13 +74,13 @@ x86_64_linux_dr_get_status (void) in *GREGSETP. */ void -supply_gregset (elf_gregset_t * gregsetp) +supply_gregset (elf_gregset_t *gregsetp) { elf_greg_t *regp = (elf_greg_t *) gregsetp; int i; - for (i = 0; i < x86_64_num_gregs; i++) - supply_register (i, (char *) (regp + x86_64_regmap[i])); + for (i = 0; i < X86_64_NUM_GREGS; i++) + supply_register (i, regp + regmap[i]); } /* Fill register REGNO (if it is a general-purpose register) in @@ -151,14 +88,14 @@ supply_gregset (elf_gregset_t * gregsetp) do this for all registers. */ void -fill_gregset (elf_gregset_t * gregsetp, int regno) +fill_gregset (elf_gregset_t *gregsetp, int regno) { elf_greg_t *regp = (elf_greg_t *) gregsetp; int i; - for (i = 0; i < x86_64_num_gregs; i++) - if ((regno == -1 || regno == i)) - regcache_collect (i, (char *) (regp + x86_64_regmap[i])); + for (i = 0; i < X86_64_NUM_GREGS; i++) + if (regno == -1 || regno == i) + regcache_collect (i, regp + regmap[i]); } /* Fetch all general-purpose registers from process/thread TID and @@ -195,73 +132,23 @@ store_regs (int tid, int regno) /* Transfering floating-point registers between GDB, inferiors and cores. */ -static void * -x86_64_fxsave_offset (elf_fpregset_t * fxsave, int regnum) -{ - const char *reg_name; - int reg_index; - - gdb_assert (x86_64_num_gregs - 1 < regnum && regnum < x86_64_num_regs); - - reg_name = x86_64_register_name (regnum); - - if (reg_name[0] == 's' && reg_name[1] == 't') - { - reg_index = reg_name[2] - '0'; - return &fxsave->st_space[reg_index * 2]; - } - - if (reg_name[0] == 'x' && reg_name[1] == 'm' && reg_name[2] == 'm') - { - reg_index = reg_name[3] - '0'; - return &fxsave->xmm_space[reg_index * 4]; - } - - if (strcmp (reg_name, "mxcsr") == 0) - return &fxsave->mxcsr; - - return NULL; -} - /* Fill GDB's register array with the floating-point and SSE register - values in *FXSAVE. This function masks off any of the reserved - bits in *FXSAVE. */ + values in *FPREGSETP. */ void -supply_fpregset (elf_fpregset_t * fxsave) +supply_fpregset (elf_fpregset_t *fpregsetp) { - int i, reg_st0, reg_mxcsr; - - reg_st0 = x86_64_register_number ("st0"); - reg_mxcsr = x86_64_register_number ("mxcsr"); - - gdb_assert (reg_st0 > 0 && reg_mxcsr > reg_st0); - - for (i = reg_st0; i <= reg_mxcsr; i++) - supply_register (i, x86_64_fxsave_offset (fxsave, i)); + x86_64_supply_fxsave ((char *) fpregsetp); } /* Fill register REGNUM (if it is a floating-point or SSE register) in - *FXSAVE with the value in GDB's register array. If REGNUM is -1, do - this for all registers. This function doesn't touch any of the - reserved bits in *FXSAVE. */ + *FPREGSETP with the value in GDB's register array. If REGNUM is + -1, do this for all registers. */ void -fill_fpregset (elf_fpregset_t * fxsave, int regnum) +fill_fpregset (elf_fpregset_t *fpregsetp, int regnum) { - int i, last_regnum = MXCSR_REGNUM; - void *ptr; - - if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0) - last_regnum = FOP_REGNUM; - - for (i = FP0_REGNUM; i <= last_regnum; i++) - if (regnum == -1 || regnum == i) - { - ptr = x86_64_fxsave_offset (fxsave, i); - if (ptr) - regcache_collect (i, ptr); - } + x86_64_fill_fxsave ((char *) fpregsetp, regnum); } /* Fetch all floating-point registers from process/thread TID and store @@ -308,8 +195,9 @@ fetch_inferior_registers (int regno) int tid; /* GNU/Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_ptid)) == 0) - tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ if (regno == -1) { @@ -335,16 +223,18 @@ fetch_inferior_registers (int regno) } /* Store register REGNO back into the child process. If REGNO is -1, - do this for all registers (including the floating point and SSE + do this for all registers (including the floating-point and SSE registers). */ + void store_inferior_registers (int regno) { int tid; /* GNU/Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_ptid)) == 0) - tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ if (regno == -1) { @@ -370,123 +260,75 @@ store_inferior_registers (int regno) } -static const unsigned char linux_syscall[] = { 0x0f, 0x05 }; - -#define LINUX_SYSCALL_LEN (sizeof linux_syscall) - -/* The system call number is stored in the %rax register. */ -#define LINUX_SYSCALL_REGNUM 0 /* %rax */ +static unsigned long +x86_64_linux_dr_get (int regnum) +{ + int tid; + unsigned long value; -/* We are specifically interested in the sigreturn and rt_sigreturn - system calls. */ + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); -#ifndef SYS_sigreturn -#define SYS_sigreturn __NR_sigreturn -#endif -#ifndef SYS_rt_sigreturn -#define SYS_rt_sigreturn __NR_rt_sigreturn + /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the + ptrace call fails breaks debugging remote targets. The correct + way to fix this is to add the hardware breakpoint and watchpoint + stuff to the target vectore. For now, just return zero if the + ptrace call fails. */ + errno = 0; + value = ptrace (PT_READ_U, tid, + offsetof (struct user, u_debugreg[regnum]), 0); + if (errno != 0) +#if 0 + perror_with_name ("Couldn't read debug register"); +#else + return 0; #endif -/* Offset to saved processor flags, from . */ -#define LINUX_SIGCONTEXT_EFLAGS_OFFSET (152) -/* Offset to saved processor registers from */ -#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36) - -/* Interpreting register set info found in core files. */ -/* Provide registers to GDB from a core file. - - CORE_REG_SECT points to an array of bytes, which are the contents - of a `note' from a core file which BFD thinks might contain - register contents. CORE_REG_SIZE is its size. - - WHICH says which register set corelow suspects this is: - 0 --- the general-purpose register set, in elf_gregset_t format - 2 --- the floating-point register set, in elf_fpregset_t format - - REG_ADDR isn't used on GNU/Linux. */ + return value; +} static void -fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, - int which, CORE_ADDR reg_addr) +x86_64_linux_dr_set (int regnum, unsigned long value) { - elf_gregset_t gregset; - elf_fpregset_t fpregset; - switch (which) - { - case 0: - if (core_reg_size != sizeof (gregset)) - warning ("Wrong size gregset in core file."); - else - { - memcpy (&gregset, core_reg_sect, sizeof (gregset)); - supply_gregset (&gregset); - } - break; - - case 2: - if (core_reg_size != sizeof (fpregset)) - warning ("Wrong size fpregset in core file."); - else - { - memcpy (&fpregset, core_reg_sect, sizeof (fpregset)); - supply_fpregset (&fpregset); - } - break; - - default: - /* We've covered all the kinds of registers we know about here, - so this must be something we wouldn't know what to do with - anyway. Just ignore it. */ - break; - } -} + int tid; -/* Register that we are able to handle GNU/Linux ELF core file formats. */ + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); -static struct core_fns linux_elf_core_fns = { - bfd_target_elf_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_core_registers, /* core_read_registers */ - NULL /* next */ -}; - + errno = 0; + ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); + if (errno != 0) + perror_with_name ("Couldn't write debug register"); +} -#if !defined (offsetof) -#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) -#endif +void +x86_64_linux_dr_set_control (unsigned long control) +{ + x86_64_linux_dr_set (DR_CONTROL, control); +} -/* Return the address of register REGNUM. BLOCKEND is the value of - u.u_ar0, which should point to the registers. */ -CORE_ADDR -x86_64_register_u_addr (CORE_ADDR blockend, int regnum) +void +x86_64_linux_dr_set_addr (int regnum, CORE_ADDR addr) { - struct user u; - CORE_ADDR fpstate; - CORE_ADDR ubase; - ubase = blockend; - if (IS_FP_REGNUM (regnum)) - { - fpstate = ubase + ((char *) &u.i387.st_space - (char *) &u); - return (fpstate + 16 * (regnum - FP0_REGNUM)); - } - else if (IS_SSE_REGNUM (regnum)) - { - fpstate = ubase + ((char *) &u.i387.xmm_space - (char *) &u); - return (fpstate + 16 * (regnum - XMM0_REGNUM)); - } - else - return (ubase + 8 * x86_64_regmap[regnum]); + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + x86_64_linux_dr_set (DR_FIRSTADDR + regnum, addr); } void -_initialize_x86_64_linux_nat (void) +x86_64_linux_dr_reset_addr (int regnum) { - add_core_fns (&linux_elf_core_fns); + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + x86_64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); } -int -kernel_u_size (void) +unsigned long +x86_64_linux_dr_get_status (void) { - return (sizeof (struct user)); + return x86_64_linux_dr_get (DR_STATUS); } diff --git a/gdb/x86-64-linux-tdep.c b/gdb/x86-64-linux-tdep.c index 932e6d6..5615ebd 100644 --- a/gdb/x86-64-linux-tdep.c +++ b/gdb/x86-64-linux-tdep.c @@ -24,19 +24,21 @@ #include "defs.h" #include "inferior.h" #include "gdbcore.h" -#include "gdb_string.h" #include "regcache.h" -#include "x86-64-tdep.h" -#include "dwarf2cfi.h" #include "osabi.h" -#define LINUX_SIGTRAMP_INSN0 (0x48) /* mov $NNNNNNNN,%rax */ -#define LINUX_SIGTRAMP_OFFSET0 (0) -#define LINUX_SIGTRAMP_INSN1 (0x0f) /* syscall */ -#define LINUX_SIGTRAMP_OFFSET1 (7) +#include "gdb_string.h" -static const unsigned char linux_sigtramp_code[] = { - /* mov $__NR_rt_sigreturn,%rax */ +#include "x86-64-tdep.h" + +#define LINUX_SIGTRAMP_INSN0 0x48 /* mov $NNNNNNNN, %rax */ +#define LINUX_SIGTRAMP_OFFSET0 0 +#define LINUX_SIGTRAMP_INSN1 0x0f /* syscall */ +#define LINUX_SIGTRAMP_OFFSET1 7 + +static const unsigned char linux_sigtramp_code[] = +{ + /* mov $__NR_rt_sigreturn, %rax */ LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00, /* syscall */ LINUX_SIGTRAMP_INSN1, 0x05 @@ -51,6 +53,14 @@ static CORE_ADDR x86_64_linux_sigtramp_start (CORE_ADDR pc) { unsigned char buf[LINUX_SIGTRAMP_LEN]; + + /* We only recognize a signal trampoline if PC is at the start of + one of the two instructions. We optimize for finding the PC at + the start, as will be the case when the trampoline is not the + first frame on the stack. We assume that in the case where the + PC is not at the start of the instruction sequence, there will be + a few trailing readable bytes on the stack. */ + if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0) return 0; @@ -71,133 +81,61 @@ x86_64_linux_sigtramp_start (CORE_ADDR pc) return pc; } -#define LINUX_SIGINFO_SIZE 0 - -/* Offset to struct sigcontext in ucontext, from . */ -#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 - -/* Offset to saved PC in sigcontext, from . */ -#define LINUX_SIGCONTEXT_PC_OFFSET 128 -#define LINUX_SIGCONTEXT_FP_OFFSET 120 - -/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the - address of the associated sigcontext structure. */ -static CORE_ADDR -x86_64_linux_sigcontext_addr (struct frame_info *frame) -{ - CORE_ADDR pc; - ULONGEST rsp; - - pc = x86_64_linux_sigtramp_start (get_frame_pc (frame)); - if (pc) - { - if (get_next_frame (frame)) - /* If this isn't the top frame, the next frame must be for the - signal handler itself. The sigcontext structure is part of - the user context. */ - return get_frame_base (get_next_frame (frame)) + LINUX_SIGINFO_SIZE + - LINUX_UCONTEXT_SIGCONTEXT_OFFSET; - - - /* This is the top frame. */ - rsp = read_register (SP_REGNUM); - return rsp + LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET; - - } - - error ("Couldn't recognize signal trampoline."); - return 0; -} - -/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the - saved program counter. */ - -static CORE_ADDR -x86_64_linux_sigtramp_saved_pc (struct frame_info *frame) -{ - CORE_ADDR addr; - - addr = x86_64_linux_sigcontext_addr (frame); - return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 8); -} - -/* Immediately after a function call, return the saved pc. */ - -CORE_ADDR -x86_64_linux_saved_pc_after_call (struct frame_info *frame) -{ - if ((get_frame_type (frame) == SIGTRAMP_FRAME)) - return x86_64_linux_sigtramp_saved_pc (frame); - - return read_memory_integer (read_register (SP_REGNUM), 8); -} - -/* Saved Pc. Get it from sigcontext if within sigtramp. */ -CORE_ADDR -x86_64_linux_frame_saved_pc (struct frame_info *frame) -{ - if ((get_frame_type (frame) == SIGTRAMP_FRAME)) - return x86_64_linux_sigtramp_saved_pc (frame); - return cfi_get_ra (frame); -} - /* Return whether PC is in a GNU/Linux sigtramp routine. */ -int -x86_64_linux_in_sigtramp (CORE_ADDR pc, char *name) +static int +x86_64_linux_pc_in_sigtramp (CORE_ADDR pc, char *name) { - if (name) - return strcmp ("__restore_rt", name) == 0; - - return (x86_64_linux_sigtramp_start (pc) != 0); + /* If we have NAME, we can optimize the search. The trampoline is + named __restore_rt. However, it isn't dynamically exported from + the shared C library, so the trampoline may appear to be part of + the preceding function. This should always be sigaction, + __sigaction, or __libc_sigaction (all aliases to the same + function). */ + if (name == NULL || strstr (name, "sigaction") != NULL) + return (x86_64_linux_sigtramp_start (pc) != 0); + + return (strcmp ("__restore_rt", name) == 0); } -CORE_ADDR -x86_64_linux_frame_chain (struct frame_info *fi) -{ - ULONGEST addr; - CORE_ADDR fp, pc; - - if (!(get_frame_type (fi) == SIGTRAMP_FRAME)) - { - fp = cfi_frame_chain (fi); - if (fp) - return fp; - else - addr = get_frame_base (fi); - } - else - addr = get_frame_base (get_next_frame (fi)); - - addr += LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET; - - fp = read_memory_integer (addr + LINUX_SIGCONTEXT_FP_OFFSET, 8) + 8; +/* Offset to struct sigcontext in ucontext, from . */ +#define X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 - return fp; -} +/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp + routine, return the address of the associated sigcontext structure. */ -CORE_ADDR -x86_64_init_frame_pc (int fromleaf, struct frame_info *fi) +static CORE_ADDR +x86_64_linux_sigcontext_addr (struct frame_info *next_frame) { - CORE_ADDR addr; - - if (get_next_frame (fi) - && (get_frame_type (get_next_frame (fi)) == SIGTRAMP_FRAME)) - { - addr = get_frame_base (get_next_frame (get_next_frame (fi))) - + LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET; - return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 8); - } - else - return cfi_init_frame_pc (fromleaf, fi); + CORE_ADDR sp; + char buf[8]; + + frame_unwind_register (next_frame, SP_REGNUM, buf); + sp = extract_unsigned_integer (buf, 8); + + /* The sigcontext structure is part of the user context. A pointer + to the user context is passed as the third argument to the signal + handler, i.e. in %rdx. Unfortunately %rdx isn't preserved across + function calls so we can't use it. Fortunately the user context + is part of the signal frame and the unwound %rsp directly points + at it. */ + return sp + X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; } static void x86_64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); x86_64_init_abi (info, gdbarch); + + set_gdbarch_pc_in_sigtramp (gdbarch, x86_64_linux_pc_in_sigtramp); + + tdep->sigcontext_addr = x86_64_linux_sigcontext_addr; + tdep->sc_pc_offset = 16 * 8; /* From . */ + tdep->sc_sp_offset = 15 * 8; } + /* Provide a prototype to silence -Wmissing-prototypes. */ extern void _initialize_x86_64_linux_tdep (void); diff --git a/gdb/x86-64-tdep.c b/gdb/x86-64-tdep.c index 121c85e..560fe98 100644 --- a/gdb/x86-64-tdep.c +++ b/gdb/x86-64-tdep.c @@ -21,249 +21,198 @@ Boston, MA 02111-1307, USA. */ #include "defs.h" +#include "arch-utils.h" +#include "block.h" +#include "dummy-frame.h" +#include "frame.h" +#include "frame-base.h" +#include "frame-unwind.h" #include "inferior.h" -#include "gdbcore.h" #include "gdbcmd.h" -#include "arch-utils.h" +#include "gdbcore.h" +#include "objfiles.h" #include "regcache.h" #include "symfile.h" -#include "objfiles.h" -#include "x86-64-tdep.h" -#include "dwarf2cfi.h" + #include "gdb_assert.h" -#include "block.h" + +#include "x86-64-tdep.h" +#include "i387-tdep.h" /* Register numbers of various important registers. */ -#define RAX_REGNUM 0 -#define RDX_REGNUM 3 -#define RDI_REGNUM 5 -#define EFLAGS_REGNUM 17 -#define ST0_REGNUM 22 -#define XMM1_REGNUM 39 - -struct register_info + +#define X86_64_RAX_REGNUM 0 /* %rax */ +#define X86_64_RDX_REGNUM 3 /* %rdx */ +#define X86_64_RDI_REGNUM 5 /* %rdi */ +#define X86_64_RBP_REGNUM 6 /* %rbp */ +#define X86_64_RSP_REGNUM 7 /* %rsp */ +#define X86_64_RIP_REGNUM 16 /* %rip */ +#define X86_64_EFLAGS_REGNUM 17 /* %eflags */ +#define X86_64_ST0_REGNUM 22 /* %st0 */ +#define X86_64_XMM0_REGNUM 38 /* %xmm0 */ +#define X86_64_XMM1_REGNUM 39 /* %xmm1 */ + +struct x86_64_register_info { - int size; char *name; struct type **type; }; -/* x86_64_register_raw_size_table[i] is the number of bytes of storage in - GDB's register array occupied by register i. */ -static struct register_info x86_64_register_info_table[] = { - /* 0 */ {8, "rax", &builtin_type_int64}, - /* 1 */ {8, "rbx", &builtin_type_int64}, - /* 2 */ {8, "rcx", &builtin_type_int64}, - /* 3 */ {8, "rdx", &builtin_type_int64}, - /* 4 */ {8, "rsi", &builtin_type_int64}, - /* 5 */ {8, "rdi", &builtin_type_int64}, - /* 6 */ {8, "rbp", &builtin_type_void_func_ptr}, - /* 7 */ {8, "rsp", &builtin_type_void_func_ptr}, - /* 8 */ {8, "r8", &builtin_type_int64}, - /* 9 */ {8, "r9", &builtin_type_int64}, - /* 10 */ {8, "r10", &builtin_type_int64}, - /* 11 */ {8, "r11", &builtin_type_int64}, - /* 12 */ {8, "r12", &builtin_type_int64}, - /* 13 */ {8, "r13", &builtin_type_int64}, - /* 14 */ {8, "r14", &builtin_type_int64}, - /* 15 */ {8, "r15", &builtin_type_int64}, - /* 16 */ {8, "rip", &builtin_type_void_func_ptr}, - /* 17 */ {4, "eflags", &builtin_type_int32}, - /* 18 */ {4, "ds", &builtin_type_int32}, - /* 19 */ {4, "es", &builtin_type_int32}, - /* 20 */ {4, "fs", &builtin_type_int32}, - /* 21 */ {4, "gs", &builtin_type_int32}, - /* 22 */ {10, "st0", &builtin_type_i387_ext}, - /* 23 */ {10, "st1", &builtin_type_i387_ext}, - /* 24 */ {10, "st2", &builtin_type_i387_ext}, - /* 25 */ {10, "st3", &builtin_type_i387_ext}, - /* 26 */ {10, "st4", &builtin_type_i387_ext}, - /* 27 */ {10, "st5", &builtin_type_i387_ext}, - /* 28 */ {10, "st6", &builtin_type_i387_ext}, - /* 29 */ {10, "st7", &builtin_type_i387_ext}, - /* 30 */ {4, "fctrl", &builtin_type_int32}, - /* 31 */ {4, "fstat", &builtin_type_int32}, - /* 32 */ {4, "ftag", &builtin_type_int32}, - /* 33 */ {4, "fiseg", &builtin_type_int32}, - /* 34 */ {4, "fioff", &builtin_type_int32}, - /* 35 */ {4, "foseg", &builtin_type_int32}, - /* 36 */ {4, "fooff", &builtin_type_int32}, - /* 37 */ {4, "fop", &builtin_type_int32}, - /* 38 */ {16, "xmm0", &builtin_type_v4sf}, - /* 39 */ {16, "xmm1", &builtin_type_v4sf}, - /* 40 */ {16, "xmm2", &builtin_type_v4sf}, - /* 41 */ {16, "xmm3", &builtin_type_v4sf}, - /* 42 */ {16, "xmm4", &builtin_type_v4sf}, - /* 43 */ {16, "xmm5", &builtin_type_v4sf}, - /* 44 */ {16, "xmm6", &builtin_type_v4sf}, - /* 45 */ {16, "xmm7", &builtin_type_v4sf}, - /* 46 */ {16, "xmm8", &builtin_type_v4sf}, - /* 47 */ {16, "xmm9", &builtin_type_v4sf}, - /* 48 */ {16, "xmm10", &builtin_type_v4sf}, - /* 49 */ {16, "xmm11", &builtin_type_v4sf}, - /* 50 */ {16, "xmm12", &builtin_type_v4sf}, - /* 51 */ {16, "xmm13", &builtin_type_v4sf}, - /* 52 */ {16, "xmm14", &builtin_type_v4sf}, - /* 53 */ {16, "xmm15", &builtin_type_v4sf}, - /* 54 */ {4, "mxcsr", &builtin_type_int32} -}; - -/* This array is a mapping from Dwarf-2 register - numbering to GDB's one. Dwarf-2 numbering is - defined in x86-64 ABI, section 3.6. */ -static int x86_64_dwarf2gdb_regno_map[] = { - 0, 3, 2, 1, /* RAX, RDX, RCX, RBX */ - 4, 5, 6, 7, /* RSI, RDI, RBP, RSP */ - 8, 9, 10, 11, /* R8 - R11 */ - 12, 13, 14, 15, /* R12 - R15 */ - -1, /* RA - not mapped */ - XMM1_REGNUM - 1, XMM1_REGNUM, /* XMM0 ... */ - XMM1_REGNUM + 1, XMM1_REGNUM + 2, - XMM1_REGNUM + 3, XMM1_REGNUM + 4, - XMM1_REGNUM + 5, XMM1_REGNUM + 6, - XMM1_REGNUM + 7, XMM1_REGNUM + 8, - XMM1_REGNUM + 9, XMM1_REGNUM + 10, - XMM1_REGNUM + 11, XMM1_REGNUM + 12, - XMM1_REGNUM + 13, XMM1_REGNUM + 14, /* ... XMM15 */ - ST0_REGNUM + 0, ST0_REGNUM + 1, /* ST0 ... */ - ST0_REGNUM + 2, ST0_REGNUM + 3, - ST0_REGNUM + 4, ST0_REGNUM + 5, - ST0_REGNUM + 6, ST0_REGNUM + 7 /* ... ST7 */ +static struct x86_64_register_info x86_64_register_info[] = +{ + { "rax", &builtin_type_int64 }, + { "rbx", &builtin_type_int64 }, + { "rcx", &builtin_type_int64 }, + { "rdx", &builtin_type_int64 }, + { "rsi", &builtin_type_int64 }, + { "rdi", &builtin_type_int64 }, + { "rbp", &builtin_type_void_data_ptr }, + { "rsp", &builtin_type_void_data_ptr }, + + /* %r8 is indeed register number 8. */ + { "r8", &builtin_type_int64 }, + { "r9", &builtin_type_int64 }, + { "r10", &builtin_type_int64 }, + { "r11", &builtin_type_int64 }, + { "r12", &builtin_type_int64 }, + { "r13", &builtin_type_int64 }, + { "r14", &builtin_type_int64 }, + { "r15", &builtin_type_int64 }, + { "rip", &builtin_type_void_func_ptr }, + { "eflags", &builtin_type_int32 }, + { "ds", &builtin_type_int32 }, + { "es", &builtin_type_int32 }, + { "fs", &builtin_type_int32 }, + { "gs", &builtin_type_int32 }, + + /* %st0 is register number 22. */ + { "st0", &builtin_type_i387_ext }, + { "st1", &builtin_type_i387_ext }, + { "st2", &builtin_type_i387_ext }, + { "st3", &builtin_type_i387_ext }, + { "st4", &builtin_type_i387_ext }, + { "st5", &builtin_type_i387_ext }, + { "st6", &builtin_type_i387_ext }, + { "st7", &builtin_type_i387_ext }, + { "fctrl", &builtin_type_int32 }, + { "fstat", &builtin_type_int32 }, + { "ftag", &builtin_type_int32 }, + { "fiseg", &builtin_type_int32 }, + { "fioff", &builtin_type_int32 }, + { "foseg", &builtin_type_int32 }, + { "fooff", &builtin_type_int32 }, + { "fop", &builtin_type_int32 }, + + /* %xmm0 is register number 38. */ + { "xmm0", &builtin_type_v4sf }, + { "xmm1", &builtin_type_v4sf }, + { "xmm2", &builtin_type_v4sf }, + { "xmm3", &builtin_type_v4sf }, + { "xmm4", &builtin_type_v4sf }, + { "xmm5", &builtin_type_v4sf }, + { "xmm6", &builtin_type_v4sf }, + { "xmm7", &builtin_type_v4sf }, + { "xmm8", &builtin_type_v4sf }, + { "xmm9", &builtin_type_v4sf }, + { "xmm10", &builtin_type_v4sf }, + { "xmm11", &builtin_type_v4sf }, + { "xmm12", &builtin_type_v4sf }, + { "xmm13", &builtin_type_v4sf }, + { "xmm14", &builtin_type_v4sf }, + { "xmm15", &builtin_type_v4sf }, + { "mxcsr", &builtin_type_int32 } }; -static int x86_64_dwarf2gdb_regno_map_length = - sizeof (x86_64_dwarf2gdb_regno_map) / - sizeof (x86_64_dwarf2gdb_regno_map[0]); - -/* Number of all registers */ -#define X86_64_NUM_REGS (sizeof (x86_64_register_info_table) / \ - sizeof (x86_64_register_info_table[0])) - -/* Number of general registers. */ -#define X86_64_NUM_GREGS (22) - -int x86_64_num_regs = X86_64_NUM_REGS; -int x86_64_num_gregs = X86_64_NUM_GREGS; +/* Total number of registers. */ +#define X86_64_NUM_REGS \ + (sizeof (x86_64_register_info) / sizeof (x86_64_register_info[0])) -/* Did we already print a note about frame pointer? */ -int omit_fp_note_printed = 0; +/* Return the name of register REGNUM. */ -/* Number of bytes of storage in the actual machine representation for - register REGNO. */ -int -x86_64_register_raw_size (int regno) +static const char * +x86_64_register_name (int regnum) { - return x86_64_register_info_table[regno].size; -} - -/* x86_64_register_byte_table[i] is the offset into the register file of the - start of register number i. We initialize this from - x86_64_register_info_table. */ -int x86_64_register_byte_table[X86_64_NUM_REGS]; + if (regnum >= 0 && regnum < X86_64_NUM_REGS) + return x86_64_register_info[regnum].name; -/* Index within `registers' of the first byte of the space for register REGNO. */ -int -x86_64_register_byte (int regno) -{ - return x86_64_register_byte_table[regno]; + return NULL; } /* Return the GDB type object for the "standard" data type of data in - register N. */ -static struct type * -x86_64_register_virtual_type (int regno) -{ - return *x86_64_register_info_table[regno].type; -} + register REGNUM. */ -/* x86_64_register_convertible is true if register N's virtual format is - different from its raw format. Note that this definition assumes - that the host supports IEEE 32-bit floats, since it doesn't say - that SSE registers need conversion. Even if we can't find a - counterexample, this is still sloppy. */ -int -x86_64_register_convertible (int regno) -{ - return IS_FP_REGNUM (regno); -} - -/* Convert data from raw format for register REGNUM in buffer FROM to - virtual format with type TYPE in buffer TO. In principle both - formats are identical except that the virtual format has two extra - bytes appended that aren't used. We set these to zero. */ -void -x86_64_register_convert_to_virtual (int regnum, struct type *type, - char *from, char *to) +static struct type * +x86_64_register_type (struct gdbarch *gdbarch, int regnum) { - char buf[12]; + gdb_assert (regnum >= 0 && regnum < X86_64_NUM_REGS); - /* We only support floating-point values. */ - if (TYPE_CODE (type) != TYPE_CODE_FLT) - { - warning ("Cannot convert floating-point register value " - "to non-floating-point type."); - memset (to, 0, TYPE_LENGTH (type)); - return; - } - /* First add the necessary padding. */ - memcpy (buf, from, FPU_REG_RAW_SIZE); - memset (buf + FPU_REG_RAW_SIZE, 0, sizeof buf - FPU_REG_RAW_SIZE); - /* Convert to TYPE. This should be a no-op, if TYPE is equivalent - to the extended floating-point format used by the FPU. */ - convert_typed_floating (to, type, buf, - x86_64_register_virtual_type (regnum)); + return *x86_64_register_info[regnum].type; } -/* Convert data from virtual format with type TYPE in buffer FROM to - raw format for register REGNUM in buffer TO. Simply omit the two - unused bytes. */ - -void -x86_64_register_convert_to_raw (struct type *type, int regnum, - char *from, char *to) -{ - gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 12); - /* Simply omit the two unused bytes. */ - memcpy (to, from, FPU_REG_RAW_SIZE); -} +/* DWARF Register Number Mapping as defined in the System V psABI, + section 3.6. */ -/* Dwarf-2 <-> GDB register numbers mapping. */ -int -x86_64_dwarf2_reg_to_regnum (int dw_reg) +static int x86_64_dwarf_regmap[] = { - if (dw_reg < 0 || dw_reg > x86_64_dwarf2gdb_regno_map_length) - { - warning ("Dwarf-2 uses unmapped register #%d\n", dw_reg); - return dw_reg; - } + /* General Purpose Registers RAX, RDX, RCX, RBX, RSI, RDI. */ + X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, 3, 2, + 4, X86_64_RDI_REGNUM, + + /* Frame Pointer Register RBP. */ + X86_64_RBP_REGNUM, + + /* Stack Pointer Register RSP. */ + X86_64_RSP_REGNUM, + + /* Extended Integer Registers 8 - 15. */ + 8, 9, 10, 11, 12, 13, 14, 15, + + /* Return Address RA. Not mapped. */ + -1, + + /* SSE Registers 0 - 7. */ + X86_64_XMM0_REGNUM + 0, X86_64_XMM1_REGNUM, + X86_64_XMM0_REGNUM + 2, X86_64_XMM0_REGNUM + 3, + X86_64_XMM0_REGNUM + 4, X86_64_XMM0_REGNUM + 5, + X86_64_XMM0_REGNUM + 6, X86_64_XMM0_REGNUM + 7, + + /* Extended SSE Registers 8 - 15. */ + X86_64_XMM0_REGNUM + 8, X86_64_XMM0_REGNUM + 9, + X86_64_XMM0_REGNUM + 10, X86_64_XMM0_REGNUM + 11, + X86_64_XMM0_REGNUM + 12, X86_64_XMM0_REGNUM + 13, + X86_64_XMM0_REGNUM + 14, X86_64_XMM0_REGNUM + 15, + + /* Floating Point Registers 0-7. */ + X86_64_ST0_REGNUM + 0, X86_64_ST0_REGNUM + 1, + X86_64_ST0_REGNUM + 2, X86_64_ST0_REGNUM + 3, + X86_64_ST0_REGNUM + 4, X86_64_ST0_REGNUM + 5, + X86_64_ST0_REGNUM + 6, X86_64_ST0_REGNUM + 7 +}; - return x86_64_dwarf2gdb_regno_map[dw_reg]; -} +static const int x86_64_dwarf_regmap_len = + (sizeof (x86_64_dwarf_regmap) / sizeof (x86_64_dwarf_regmap[0])); -/* Push the return address (pointing to the call dummy) onto the stack - and return the new value for the stack pointer. */ +/* Convert DWARF register number REG to the appropriate register + number used by GDB. */ -static CORE_ADDR -x86_64_push_return_address (CORE_ADDR pc, CORE_ADDR sp) +static int +x86_64_dwarf_reg_to_regnum (int reg) { - char buf[8]; + int regnum = -1; - store_unsigned_integer (buf, 8, CALL_DUMMY_ADDRESS ()); - write_memory (sp - 8, buf, 8); - return sp - 8; -} + if (reg >= 0 || reg < x86_64_dwarf_regmap_len) + regnum = x86_64_dwarf_regmap[reg]; -static void -x86_64_pop_frame (void) -{ - generic_pop_current_frame (cfi_pop_frame); + if (regnum == -1) + warning ("Unmapped DWARF Register #%d encountered\n", reg); + + return regnum; } /* The returning of values is done according to the special algorithm. - Some types are returned in registers an some (big structures) in memory. - See ABI for details. - */ + Some types are returned in registers an some (big structures) in + memory. See the System V psABI for details. */ #define MAX_CLASSES 4 @@ -282,27 +231,27 @@ enum x86_64_reg_class }; /* Return the union class of CLASS1 and CLASS2. - See the x86-64 ABI for details. */ + See the System V psABI for details. */ static enum x86_64_reg_class merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) { - /* Rule #1: If both classes are equal, this is the resulting class. */ + /* Rule (a): If both classes are equal, this is the resulting class. */ if (class1 == class2) return class1; - /* Rule #2: If one of the classes is NO_CLASS, the resulting class + /* Rule (b): If one of the classes is NO_CLASS, the resulting class is the other class. */ if (class1 == X86_64_NO_CLASS) return class2; if (class2 == X86_64_NO_CLASS) return class1; - /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + /* Rule (c): If one of the classes is MEMORY, the result is MEMORY. */ if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) return X86_64_MEMORY_CLASS; - /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + /* Rule (d): If one of the classes is INTEGER, the result is INTEGER. */ if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) return X86_64_INTEGERSI_CLASS; @@ -310,12 +259,13 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) return X86_64_INTEGER_CLASS; - /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ + /* Rule (e): If one of the classes is X87 or X87UP class, MEMORY is + used as class. */ if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) return X86_64_MEMORY_CLASS; - /* Rule #6: Otherwise class SSE is used. */ + /* Rule (f): Otherwise class SSE is used. */ return X86_64_SSE_CLASS; } @@ -325,7 +275,7 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) is returned. As a special case for zero sized containers, classes[0] will be NO_CLASS and 1 is returned. - See the x86-64 psABI for details. */ + See the System V psABI for details. */ static int classify_argument (struct type *type, @@ -533,7 +483,8 @@ examine_argument (enum x86_64_reg_class classes[MAX_CLASSES], memory. If this function returns 1, GDB will call STORE_STRUCT_RETURN and EXTRACT_STRUCT_VALUE_ADDRESS else STORE_RETURN_VALUE and EXTRACT_RETURN_VALUE will be used. */ -int + +static int x86_64_use_struct_convention (int gcc_p, struct type *value_type) { enum x86_64_reg_class class[MAX_CLASSES]; @@ -550,7 +501,7 @@ x86_64_use_struct_convention (int gcc_p, struct type *value_type) function return value of TYPE, and copy that, in virtual format, into VALBUF. */ -void +static void x86_64_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf) { @@ -561,15 +512,15 @@ x86_64_extract_return_value (struct type *type, struct regcache *regcache, int intreg = 0; int ssereg = 0; int offset = 0; - int ret_int_r[RET_INT_REGS] = { RAX_REGNUM, RDX_REGNUM }; - int ret_sse_r[RET_SSE_REGS] = { XMM0_REGNUM, XMM1_REGNUM }; + int ret_int_r[RET_INT_REGS] = { X86_64_RAX_REGNUM, X86_64_RDX_REGNUM }; + int ret_sse_r[RET_SSE_REGS] = { X86_64_XMM0_REGNUM, X86_64_XMM1_REGNUM }; if (!n || !examine_argument (class, n, &needed_intregs, &needed_sseregs) || needed_intregs > RET_INT_REGS || needed_sseregs > RET_SSE_REGS) { /* memory class */ CORE_ADDR addr; - regcache_cooked_read (regcache, RAX_REGNUM, &addr); + regcache_cooked_read (regcache, X86_64_RAX_REGNUM, &addr); read_memory (addr, valbuf, TYPE_LENGTH (type)); return; } @@ -610,12 +561,12 @@ x86_64_extract_return_value (struct type *type, struct regcache *regcache, ssereg++; break; case X86_64_X87_CLASS: - regcache_cooked_read_part (regcache, FP0_REGNUM, + regcache_cooked_read_part (regcache, X86_64_ST0_REGNUM, 0, 8, (char *) valbuf + offset); offset += 8; break; case X86_64_X87UP_CLASS: - regcache_cooked_read_part (regcache, FP0_REGNUM, + regcache_cooked_read_part (regcache, X86_64_ST0_REGNUM, 8, 2, (char *) valbuf + offset); offset += 8; break; @@ -628,33 +579,29 @@ x86_64_extract_return_value (struct type *type, struct regcache *regcache, } } -static void -x86_64_frame_init_saved_regs (struct frame_info *fi) -{ - /* Do nothing. Everything is handled by the stack unwinding code. */ -} - #define INT_REGS 6 -#define SSE_REGS 16 +#define SSE_REGS 8 -CORE_ADDR -x86_64_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) +static CORE_ADDR +x86_64_push_arguments (struct regcache *regcache, int nargs, + struct value **args, CORE_ADDR sp) { int intreg = 0; int ssereg = 0; int i; - static int int_parameter_registers[INT_REGS] = { - 5 /* RDI */ , 4 /* RSI */ , - 3 /* RDX */ , 2 /* RCX */ , - 8 /* R8 */ , 9 /* R9 */ + static int int_parameter_registers[INT_REGS] = + { + X86_64_RDI_REGNUM, 4, /* %rdi, %rsi */ + X86_64_RDX_REGNUM, 2, /* %rdx, %rcx */ + 8, 9 /* %r8, %r9 */ }; - /* XMM0 - XMM15 */ - static int sse_parameter_registers[SSE_REGS] = { - XMM1_REGNUM - 1, XMM1_REGNUM, XMM1_REGNUM + 1, XMM1_REGNUM + 2, - XMM1_REGNUM + 3, XMM1_REGNUM + 4, XMM1_REGNUM + 5, XMM1_REGNUM + 6, - XMM1_REGNUM + 7, XMM1_REGNUM + 8, XMM1_REGNUM + 9, XMM1_REGNUM + 10, - XMM1_REGNUM + 11, XMM1_REGNUM + 12, XMM1_REGNUM + 13, XMM1_REGNUM + 14 + /* %xmm0 - %xmm7 */ + static int sse_parameter_registers[SSE_REGS] = + { + X86_64_XMM0_REGNUM + 0, X86_64_XMM1_REGNUM, + X86_64_XMM0_REGNUM + 2, X86_64_XMM0_REGNUM + 3, + X86_64_XMM0_REGNUM + 4, X86_64_XMM0_REGNUM + 5, + X86_64_XMM0_REGNUM + 6, X86_64_XMM0_REGNUM + 7, }; int stack_values_count = 0; int *stack_values; @@ -684,19 +631,18 @@ x86_64_push_arguments (int nargs, struct value **args, CORE_ADDR sp, case X86_64_NO_CLASS: break; case X86_64_INTEGER_CLASS: - deprecated_write_register_gen (int_parameter_registers - [(intreg + 1) / 2], - VALUE_CONTENTS_ALL (args[i]) + offset); + regcache_cooked_write + (regcache, int_parameter_registers[(intreg + 1) / 2], + VALUE_CONTENTS_ALL (args[i]) + offset); offset += 8; intreg += 2; break; case X86_64_INTEGERSI_CLASS: { - LONGEST num - = extract_signed_integer (VALUE_CONTENTS_ALL (args[i]) - + offset, 4); - regcache_raw_write_signed (current_regcache, - int_parameter_registers[intreg / 2], num); + LONGEST val = extract_signed_integer + (VALUE_CONTENTS_ALL (args[i]) + offset, 4); + regcache_cooked_write_signed + (regcache, int_parameter_registers[intreg / 2], val); offset += 8; intreg++; @@ -705,15 +651,16 @@ x86_64_push_arguments (int nargs, struct value **args, CORE_ADDR sp, case X86_64_SSEDF_CLASS: case X86_64_SSESF_CLASS: case X86_64_SSE_CLASS: - deprecated_write_register_gen (sse_parameter_registers - [(ssereg + 1) / 2], - VALUE_CONTENTS_ALL (args[i]) + offset); + regcache_cooked_write + (regcache, sse_parameter_registers[(ssereg + 1) / 2], + VALUE_CONTENTS_ALL (args[i]) + offset); offset += 8; ssereg += 2; break; case X86_64_SSEUP_CLASS: - deprecated_write_register_gen (sse_parameter_registers[ssereg / 2], - VALUE_CONTENTS_ALL (args[i]) + offset); + regcache_cooked_write + (regcache, sse_parameter_registers[ssereg / 2], + VALUE_CONTENTS_ALL (args[i]) + offset); offset += 8; ssereg++; break; @@ -732,21 +679,25 @@ x86_64_push_arguments (int nargs, struct value **args, CORE_ADDR sp, } } } + + /* Push any remaining arguments onto the stack. */ while (--stack_values_count >= 0) { struct value *arg = args[stack_values[stack_values_count]]; int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg)); - len += 7; - len -= len % 8; - sp -= len; + + /* Make sure the stack stays eightbyte-aligned. */ + sp -= (len + 7) & ~7; write_memory (sp, VALUE_CONTENTS_ALL (arg), len); } + return sp; } /* Write into the appropriate registers a function return value stored in VALBUF of type TYPE, given in virtual format. */ -void + +static void x86_64_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf) { @@ -754,27 +705,32 @@ x86_64_store_return_value (struct type *type, struct regcache *regcache, if (TYPE_CODE_FLT == TYPE_CODE (type)) { - /* Floating-point return values can be found in %st(0). */ - if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT - && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext) - { - /* Copy straight over. */ - regcache_cooked_write (regcache, FP0_REGNUM, valbuf); - } - else - { - char buf[FPU_REG_RAW_SIZE]; - DOUBLEST val; - - /* Convert the value found in VALBUF to the extended - floating point format used by the FPU. This is probably - not exactly how it would happen on the target itself, but - it is the best we can do. */ - val = deprecated_extract_floating (valbuf, TYPE_LENGTH (type)); - floatformat_from_doublest (&floatformat_i387_ext, &val, buf); - regcache_cooked_write_part (regcache, FP0_REGNUM, - 0, FPU_REG_RAW_SIZE, buf); - } + ULONGEST fstat; + char buf[FPU_REG_RAW_SIZE]; + + /* Returning floating-point values is a bit tricky. Apart from + storing the return value in %st(0), we have to simulate the + state of the FPU at function return point. */ + + /* Convert the value found in VALBUF to the extended + floating-point format used by the FPU. This is probably + not exactly how it would happen on the target itself, but + it is the best we can do. */ + convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext); + regcache_raw_write (regcache, X86_64_ST0_REGNUM, buf); + + /* Set the top of the floating-point register stack to 7. The + actual value doesn't really matter, but 7 is what a normal + function return would end up with if the program started out + with a freshly initialized FPU. */ + regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat); + fstat |= (7 << 11); + regcache_raw_write_unsigned (regcache, FSTAT_REGNUM, fstat); + + /* Mark %st(1) through %st(7) as empty. Since we set the top of + the floating-point register stack to 7, the appropriate value + for the tag word is 0x3fff. */ + regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff); } else { @@ -797,126 +753,388 @@ x86_64_store_return_value (struct type *type, struct regcache *regcache, } -const char * -x86_64_register_name (int reg_nr) +static CORE_ADDR +x86_64_push_dummy_call (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR dummy_addr, int nargs, struct value **args, + CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { - if (reg_nr < 0 || reg_nr >= X86_64_NUM_REGS) - return NULL; - return x86_64_register_info_table[reg_nr].name; + char buf[8]; + + /* Pass arguments. */ + sp = x86_64_push_arguments (regcache, nargs, args, sp); + + /* Pass "hidden" argument". */ + if (struct_return) + { + store_unsigned_integer (buf, 8, struct_addr); + regcache_cooked_write (regcache, X86_64_RDI_REGNUM, buf); + } + + /* Store return address. */ + sp -= 8; + store_unsigned_integer (buf, 8, dummy_addr); + write_memory (sp, buf, 8); + + /* Finally, update the stack pointer... */ + store_unsigned_integer (buf, 8, sp); + regcache_cooked_write (regcache, X86_64_RSP_REGNUM, buf); + + /* ...and fake a frame pointer. */ + regcache_cooked_write (regcache, X86_64_RBP_REGNUM, buf); + + return sp; } + + +/* The maximum number of saved registers. This should include %rip. */ +#define X86_64_NUM_SAVED_REGS 17 + +struct x86_64_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + CORE_ADDR sp_offset; + CORE_ADDR pc; + + /* Saved registers. */ + CORE_ADDR saved_regs[X86_64_NUM_SAVED_REGS]; + CORE_ADDR saved_sp; + + /* Do we have a frame? */ + int frameless_p; +}; -int -x86_64_register_number (const char *name) +/* Allocate and initialize a frame cache. */ + +static struct x86_64_frame_cache * +x86_64_alloc_frame_cache (void) { - int reg_nr; + struct x86_64_frame_cache *cache; + int i; + + cache = FRAME_OBSTACK_ZALLOC (struct x86_64_frame_cache); - for (reg_nr = 0; reg_nr < X86_64_NUM_REGS; reg_nr++) - if (strcmp (name, x86_64_register_info_table[reg_nr].name) == 0) - return reg_nr; - return -1; + /* Base address. */ + cache->base = 0; + cache->sp_offset = -8; + cache->pc = 0; + + /* Saved registers. We initialize these to -1 since zero is a valid + offset (that's where %rbp is supposed to be stored). */ + for (i = 0; i < X86_64_NUM_SAVED_REGS; i++) + cache->saved_regs[i] = -1; + cache->saved_sp = 0; + + /* Frameless until proven otherwise. */ + cache->frameless_p = 1; + + return cache; } - -/* Store the address of the place in which to copy the structure the - subroutine will return. This is called from call_function. */ -void -x86_64_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) +/* Do a limited analysis of the prologue at PC and update CACHE + accordingly. Bail out early if CURRENT_PC is reached. Return the + address where the analysis stopped. + + We will handle only functions beginning with: + + pushq %rbp 0x55 + movq %rsp, %rbp 0x48 0x89 0xe5 + + Any function that doesn't start with this sequence will be assumed + to have no prologue and thus no valid frame pointer in %rbp. */ + +static CORE_ADDR +x86_64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc, + struct x86_64_frame_cache *cache) { - write_register (RDI_REGNUM, addr); + static unsigned char proto[3] = { 0x48, 0x89, 0xe5 }; + unsigned char buf[3]; + unsigned char op; + + if (current_pc <= pc) + return current_pc; + + op = read_memory_unsigned_integer (pc, 1); + + if (op == 0x55) /* pushq %rbp */ + { + /* Take into account that we've executed the `pushq %rbp' that + starts this instruction sequence. */ + cache->saved_regs[X86_64_RBP_REGNUM] = 0; + cache->sp_offset += 8; + + /* If that's all, return now. */ + if (current_pc <= pc + 1) + return current_pc; + + /* Check for `movq %rsp, %rbp'. */ + read_memory (pc + 1, buf, 3); + if (memcmp (buf, proto, 3) != 0) + return pc + 1; + + /* OK, we actually have a frame. */ + cache->frameless_p = 0; + return pc + 4; + } + + return pc; } -int -x86_64_frameless_function_invocation (struct frame_info *frame) +/* Return PC of first real instruction. */ + +static CORE_ADDR +x86_64_skip_prologue (CORE_ADDR start_pc) { - return 0; + struct x86_64_frame_cache cache; + CORE_ADDR pc; + + pc = x86_64_analyze_prologue (start_pc, 0xffffffffffffffff, &cache); + if (cache.frameless_p) + return start_pc; + + return pc; } + -/* We will handle only functions beginning with: - 55 pushq %rbp - 48 89 e5 movq %rsp,%rbp - Any function that doesn't start with this sequence - will be assumed to have no prologue and thus no valid - frame pointer in %rbp. */ -#define PROLOG_BUFSIZE 4 -int -x86_64_function_has_prologue (CORE_ADDR pc) +/* Normal frames. */ + +static struct x86_64_frame_cache * +x86_64_frame_cache (struct frame_info *next_frame, void **this_cache) { + struct x86_64_frame_cache *cache; + char buf[8]; int i; - unsigned char prolog_expect[PROLOG_BUFSIZE] = { 0x55, 0x48, 0x89, 0xe5 }, - prolog_buf[PROLOG_BUFSIZE]; - read_memory (pc, (char *) prolog_buf, PROLOG_BUFSIZE); + if (*this_cache) + return *this_cache; - /* First check, whether pc points to pushq %rbp, movq %rsp,%rbp. */ - for (i = 0; i < PROLOG_BUFSIZE; i++) - if (prolog_expect[i] != prolog_buf[i]) - return 0; /* ... no, it doesn't. Nothing to skip. */ - - return 1; + cache = x86_64_alloc_frame_cache (); + *this_cache = cache; + + frame_unwind_register (next_frame, X86_64_RBP_REGNUM, buf); + cache->base = extract_unsigned_integer (buf, 8); + if (cache->base == 0) + return cache; + + /* For normal frames, %rip is stored at 8(%rbp). */ + cache->saved_regs[X86_64_RIP_REGNUM] = 8; + + cache->pc = frame_func_unwind (next_frame); + if (cache->pc != 0) + x86_64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache); + + if (cache->frameless_p) + { + /* We didn't find a valid frame, which means that CACHE->base + currently holds the frame pointer for our calling frame. If + we're at the start of a function, or somewhere half-way its + prologue, the function's frame probably hasn't been fully + setup yet. Try to reconstruct the base address for the stack + frame by looking at the stack pointer. For truly "frameless" + functions this might work too. */ + + frame_unwind_register (next_frame, X86_64_RSP_REGNUM, buf); + cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset; + } + + /* Now that we have the base address for the stack frame we can + calculate the value of %rsp in the calling frame. */ + cache->saved_sp = cache->base + 16; + + /* Adjust all the saved registers such that they contain addresses + instead of offsets. */ + for (i = 0; i < X86_64_NUM_SAVED_REGS; i++) + if (cache->saved_regs[i] != -1) + cache->saved_regs[i] += cache->base; + + return cache; } -/* If a function with debugging information and known beginning - is detected, we will return pc of the next line in the source - code. With this approach we effectively skip the prolog. */ +static void +x86_64_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + struct x86_64_frame_cache *cache = + x86_64_frame_cache (next_frame, this_cache); + + /* This marks the outermost frame. */ + if (cache->base == 0) + return; + + (*this_id) = frame_id_build (cache->base + 16, cache->pc); +} -CORE_ADDR -x86_64_skip_prologue (CORE_ADDR pc) +static void +x86_64_frame_prev_register (struct frame_info *next_frame, void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) { - int i; - struct symtab_and_line v_sal; - struct symbol *v_function; - CORE_ADDR endaddr; + struct x86_64_frame_cache *cache = + x86_64_frame_cache (next_frame, this_cache); - if (! x86_64_function_has_prologue (pc)) - return pc; + gdb_assert (regnum >= 0); - /* OK, we have found the prologue and want PC of the first - non-prologue instruction. */ - pc += PROLOG_BUFSIZE; + if (regnum == SP_REGNUM && cache->saved_sp) + { + *optimizedp = 0; + *lvalp = not_lval; + *addrp = 0; + *realnump = -1; + if (valuep) + { + /* Store the value. */ + store_unsigned_integer (valuep, 8, cache->saved_sp); + } + return; + } - v_function = find_pc_function (pc); - v_sal = find_pc_line (pc, 0); + if (regnum < X86_64_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1) + { + *optimizedp = 0; + *lvalp = lval_memory; + *addrp = cache->saved_regs[regnum]; + *realnump = -1; + if (valuep) + { + /* Read the value in from memory. */ + read_memory (*addrp, valuep, + register_size (current_gdbarch, regnum)); + } + return; + } - /* If pc doesn't point to a function with debuginfo, some of the - following may be NULL. */ - if (!v_function || !v_function->ginfo.value.block || !v_sal.symtab) - return pc; + frame_register_unwind (next_frame, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} - endaddr = BLOCK_END (SYMBOL_BLOCK_VALUE (v_function)); +static const struct frame_unwind x86_64_frame_unwind = +{ + NORMAL_FRAME, + x86_64_frame_this_id, + x86_64_frame_prev_register +}; - for (i = 0; i < v_sal.symtab->linetable->nitems; i++) - if (v_sal.symtab->linetable->item[i].pc >= pc - && v_sal.symtab->linetable->item[i].pc < endaddr) - { - pc = v_sal.symtab->linetable->item[i].pc; - break; - } +static const struct frame_unwind * +x86_64_frame_p (CORE_ADDR pc) +{ + return &x86_64_frame_unwind; +} + - return pc; +/* Signal trampolines. */ + +/* FIXME: kettenis/20030419: Perhaps, we can unify the 32-bit and + 64-bit variants. This would require using identical frame caches + on both platforms. */ + +static struct x86_64_frame_cache * +x86_64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) +{ + struct x86_64_frame_cache *cache; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + CORE_ADDR addr; + char buf[8]; + + if (*this_cache) + return *this_cache; + + cache = x86_64_alloc_frame_cache (); + + frame_unwind_register (next_frame, X86_64_RSP_REGNUM, buf); + cache->base = extract_unsigned_integer (buf, 8) - 8; + + addr = tdep->sigcontext_addr (next_frame); + cache->saved_regs[X86_64_RIP_REGNUM] = addr + tdep->sc_pc_offset; + cache->saved_regs[X86_64_RSP_REGNUM] = addr + tdep->sc_sp_offset; + + *this_cache = cache; + return cache; } static void +x86_64_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, struct frame_id *this_id) +{ + struct x86_64_frame_cache *cache = + x86_64_sigtramp_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->base + 16, frame_pc_unwind (next_frame)); +} + +static void +x86_64_sigtramp_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + /* Make sure we've initialized the cache. */ + x86_64_sigtramp_frame_cache (next_frame, this_cache); + + x86_64_frame_prev_register (next_frame, this_cache, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind x86_64_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + x86_64_sigtramp_frame_this_id, + x86_64_sigtramp_frame_prev_register +}; + +static const struct frame_unwind * +x86_64_sigtramp_frame_p (CORE_ADDR pc) +{ + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + if (PC_IN_SIGTRAMP (pc, name)) + return &x86_64_sigtramp_frame_unwind; + + return NULL; +} + + +static CORE_ADDR +x86_64_frame_base_address (struct frame_info *next_frame, void **this_cache) +{ + struct x86_64_frame_cache *cache = + x86_64_frame_cache (next_frame, this_cache); + + return cache->base; +} + +static const struct frame_base x86_64_frame_base = +{ + &x86_64_frame_unwind, + x86_64_frame_base_address, + x86_64_frame_base_address, + x86_64_frame_base_address +}; + +static void x86_64_save_dummy_frame_tos (CORE_ADDR sp) { - /* We must add the size of the return address that is already - put on the stack. */ - generic_save_dummy_frame_tos (sp + - TYPE_LENGTH (builtin_type_void_func_ptr)); + generic_save_dummy_frame_tos (sp + 16); } static struct frame_id -x86_64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *frame) +x86_64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { - CORE_ADDR base; - frame_unwind_unsigned_register (frame, SP_REGNUM, &base); - return frame_id_build (base, frame_pc_unwind (frame)); + char buf[8]; + CORE_ADDR fp; + + frame_unwind_register (next_frame, X86_64_RBP_REGNUM, buf); + fp = extract_unsigned_integer (buf, 8); + + return frame_id_build (fp + 16, frame_pc_unwind (next_frame)); } void x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int i, sum; /* The x86-64 has 16 SSE registers. */ tdep->num_xmm_regs = 16; @@ -932,115 +1150,94 @@ x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_long_double_bit (gdbarch, 128); set_gdbarch_num_regs (gdbarch, X86_64_NUM_REGS); + set_gdbarch_register_name (gdbarch, x86_64_register_name); + set_gdbarch_register_type (gdbarch, x86_64_register_type); /* Register numbers of various important registers. */ - set_gdbarch_sp_regnum (gdbarch, 7); /* %rsp */ - set_gdbarch_deprecated_fp_regnum (gdbarch, 6); /* %rbp */ - set_gdbarch_pc_regnum (gdbarch, 16); /* %rip */ - set_gdbarch_ps_regnum (gdbarch, 17); /* %eflags */ - set_gdbarch_fp0_regnum (gdbarch, X86_64_NUM_GREGS); /* %st(0) */ + set_gdbarch_sp_regnum (gdbarch, X86_64_RSP_REGNUM); /* %rsp */ + set_gdbarch_pc_regnum (gdbarch, X86_64_RIP_REGNUM); /* %rip */ + set_gdbarch_ps_regnum (gdbarch, X86_64_EFLAGS_REGNUM); /* %eflags */ + set_gdbarch_fp0_regnum (gdbarch, X86_64_ST0_REGNUM); /* %st(0) */ /* The "default" register numbering scheme for the x86-64 is - referred to as the "DWARF register number mapping" in the psABI. - The preferred debugging format for all known x86-64 targets is - actually DWARF2, and GCC doesn't seem to support DWARF (that is - DWARF-1), but we provide the same mapping just in case. This - mapping is also used for stabs, which GCC does support. */ - set_gdbarch_stab_reg_to_regnum (gdbarch, x86_64_dwarf2_reg_to_regnum); - set_gdbarch_dwarf_reg_to_regnum (gdbarch, x86_64_dwarf2_reg_to_regnum); - set_gdbarch_dwarf2_reg_to_regnum (gdbarch, x86_64_dwarf2_reg_to_regnum); - - /* We don't override SDB_REG_RO_REGNUM, sice COFF doesn't seem to be - in use on any of the supported x86-64 targets. */ - - set_gdbarch_register_name (gdbarch, x86_64_register_name); - set_gdbarch_deprecated_register_size (gdbarch, 8); + referred to as the "DWARF Register Number Mapping" in the System + V psABI. The preferred debugging format for all known x86-64 + targets is actually DWARF2, and GCC doesn't seem to support DWARF + (that is DWARF-1), but we provide the same mapping just in case. + This mapping is also used for stabs, which GCC does support. */ + set_gdbarch_stab_reg_to_regnum (gdbarch, x86_64_dwarf_reg_to_regnum); + set_gdbarch_dwarf_reg_to_regnum (gdbarch, x86_64_dwarf_reg_to_regnum); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, x86_64_dwarf_reg_to_regnum); - /* Total amount of space needed to store our copies of the machine's - register (SIZEOF_GREGS + SIZEOF_FPU_REGS + SIZEOF_FPU_CTRL_REGS + - SIZEOF_SSE_REGS) */ - for (i = 0, sum = 0; i < X86_64_NUM_REGS; i++) - sum += x86_64_register_info_table[i].size; - set_gdbarch_deprecated_register_bytes (gdbarch, sum); + /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to + be in use on any of the supported x86-64 targets. */ - set_gdbarch_register_raw_size (gdbarch, x86_64_register_raw_size); - set_gdbarch_register_byte (gdbarch, x86_64_register_byte); - set_gdbarch_register_virtual_type (gdbarch, x86_64_register_virtual_type); - - set_gdbarch_register_convertible (gdbarch, x86_64_register_convertible); - set_gdbarch_register_convert_to_virtual (gdbarch, - x86_64_register_convert_to_virtual); - set_gdbarch_register_convert_to_raw (gdbarch, - x86_64_register_convert_to_raw); - - /* Getting saved registers is handled by unwind information. */ - set_gdbarch_deprecated_get_saved_register (gdbarch, cfi_get_saved_register); - - /* FIXME: kettenis/20021026: Should we set parm_boundary to 64 here? */ - set_gdbarch_deprecated_target_read_fp (gdbarch, cfi_read_fp); + /* Call dummy code. */ + set_gdbarch_push_dummy_call (gdbarch, x86_64_push_dummy_call); set_gdbarch_extract_return_value (gdbarch, x86_64_extract_return_value); - - set_gdbarch_deprecated_push_arguments (gdbarch, x86_64_push_arguments); - set_gdbarch_deprecated_push_return_address (gdbarch, x86_64_push_return_address); - set_gdbarch_deprecated_pop_frame (gdbarch, x86_64_pop_frame); - set_gdbarch_deprecated_store_struct_return (gdbarch, x86_64_store_struct_return); set_gdbarch_store_return_value (gdbarch, x86_64_store_return_value); /* Override, since this is handled by x86_64_extract_return_value. */ set_gdbarch_extract_struct_value_address (gdbarch, NULL); set_gdbarch_use_struct_convention (gdbarch, x86_64_use_struct_convention); - set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, x86_64_frame_init_saved_regs); set_gdbarch_skip_prologue (gdbarch, x86_64_skip_prologue); - set_gdbarch_deprecated_frame_chain (gdbarch, x86_64_linux_frame_chain); - set_gdbarch_frameless_function_invocation (gdbarch, - x86_64_frameless_function_invocation); - /* FIXME: kettenis/20021026: These two are GNU/Linux-specific and - should be moved elsewhere. */ - set_gdbarch_deprecated_frame_saved_pc (gdbarch, x86_64_linux_frame_saved_pc); - set_gdbarch_deprecated_saved_pc_after_call (gdbarch, x86_64_linux_saved_pc_after_call); - set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown); - /* FIXME: kettenis/20021026: This one is GNU/Linux-specific too. */ - set_gdbarch_pc_in_sigtramp (gdbarch, x86_64_linux_in_sigtramp); - + /* Avoid wiring in the MMX registers for now. */ set_gdbarch_num_pseudo_regs (gdbarch, 0); - /* Build call frame information (CFI) from DWARF2 frame debug info. */ - set_gdbarch_dwarf2_build_frame_info (gdbarch, dwarf2_build_frame_info); - - /* Initialization of per-frame CFI. */ - set_gdbarch_deprecated_init_extra_frame_info (gdbarch, cfi_init_extra_frame_info); - - /* Frame PC initialization is handled by using CFI. */ - set_gdbarch_deprecated_init_frame_pc (gdbarch, x86_64_init_frame_pc); - - /* Cons up virtual frame pointer for trace. */ - set_gdbarch_virtual_frame_pointer (gdbarch, cfi_virtual_frame_pointer); + set_gdbarch_unwind_dummy_id (gdbarch, x86_64_unwind_dummy_id); + set_gdbarch_save_dummy_frame_tos (gdbarch, x86_64_save_dummy_frame_tos); /* FIXME: kettenis/20021026: This is ELF-specific. Fine for now, since all supported x86-64 targets are ELF, but that might change in the future. */ set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); - - /* Dummy frame helper functions. */ - set_gdbarch_save_dummy_frame_tos (gdbarch, x86_64_save_dummy_frame_tos); - set_gdbarch_unwind_dummy_id (gdbarch, x86_64_unwind_dummy_id); + + frame_unwind_append_predicate (gdbarch, x86_64_sigtramp_frame_p); + frame_unwind_append_predicate (gdbarch, x86_64_frame_p); + frame_base_set_default (gdbarch, &x86_64_frame_base); +} + + +#define I387_FISEG_REGNUM FISEG_REGNUM +#define I387_FOSEG_REGNUM FOSEG_REGNUM + +/* The 64-bit FXSAVE format differs from the 32-bit format in the + sense that the instruction pointer and data pointer are simply + 64-bit offsets into the code segment and the data segment instead + of a selector offset pair. The functions below store the upper 32 + bits of these pointers (instead of just the 16-bits of the segment + selector). */ + +/* Fill GDB's register array with the floating-point and SSE register + values in *FXSAVE. This function masks off any of the reserved + bits in *FXSAVE. */ + +void +x86_64_supply_fxsave (char *fxsave) +{ + i387_supply_fxsave (fxsave); + + if (fxsave) + { + supply_register (I387_FISEG_REGNUM, fxsave + 12); + supply_register (I387_FOSEG_REGNUM, fxsave + 20); + } } +/* Fill register REGNUM (if it is a floating-point or SSE register) in + *FXSAVE with the value in GDB's register array. If REGNUM is -1, do + this for all registers. This function doesn't touch any of the + reserved bits in *FXSAVE. */ + void -_initialize_x86_64_tdep (void) +x86_64_fill_fxsave (char *fxsave, int regnum) { - /* Initialize the table saying where each register starts in the - register file. */ - { - int i, offset; + i387_fill_fxsave (fxsave, regnum); - offset = 0; - for (i = 0; i < X86_64_NUM_REGS; i++) - { - x86_64_register_byte_table[i] = offset; - offset += x86_64_register_info_table[i].size; - } - } + if (regnum == -1 || regnum == I387_FISEG_REGNUM) + regcache_collect (regnum, fxsave + 12); + if (regnum == -1 || regnum == I387_FOSEG_REGNUM) + regcache_collect (regnum, fxsave + 20); } diff --git a/gdb/x86-64-tdep.h b/gdb/x86-64-tdep.h index 6885a7c..70ceffb 100644 --- a/gdb/x86-64-tdep.h +++ b/gdb/x86-64-tdep.h @@ -1,6 +1,8 @@ -/* Target-dependent code for GDB, the GNU debugger. - Copyright 2001 +/* Target-dependent code for the x86-64. + + Copyright 2001, 2003 Free Software Foundation, Inc. + Contributed by Jiri Smid, SuSE Labs. This file is part of GDB. @@ -28,19 +30,22 @@ struct frame_info; #include "i386-tdep.h" -extern int x86_64_num_regs; -extern int x86_64_num_gregs; +/* Number of general purpose registers. */ +#define X86_64_NUM_GREGS 22 + +void x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch); -int x86_64_register_number (const char *name); -const char *x86_64_register_name (int reg_nr); +/* Fill GDB's register array with the floating-point and SSE register + values in *FXSAVE. This function masks off any of the reserved + bits in *FXSAVE. */ -gdbarch_deprecated_frame_saved_pc_ftype x86_64_linux_frame_saved_pc; -gdbarch_deprecated_saved_pc_after_call_ftype x86_64_linux_saved_pc_after_call; -gdbarch_pc_in_sigtramp_ftype x86_64_linux_in_sigtramp; -CORE_ADDR x86_64_linux_frame_chain (struct frame_info *fi); -CORE_ADDR x86_64_init_frame_pc (int fromleaf, struct frame_info *fi); -int x86_64_function_has_prologue (CORE_ADDR pc); +void x86_64_supply_fxsave (char *fxsave); -void x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch); +/* Fill register REGNUM (if it is a floating-point or SSE register) in + *FXSAVE with the value in GDB's register array. If REGNUM is -1, do + this for all registers. This function doesn't touch any of the + reserved bits in *FXSAVE. */ + +void x86_64_fill_fxsave (char *fxsave, int regnum); -#endif +#endif /* x86-64-tdep.h */ -- 2.7.4