diff options
51 files changed, 2343 insertions, 711 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6661193..1e0839f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2013-06-07 Pedro Alves <palves@redhat.com> + + * regformats/regdat.sh: Output #include tdesc.h. Make globals + static. Output a global target description pointer. + (init_registers_${name}): Adjust to initialize a + target description structure. + 2013-06-07 Will Newton <will.newton@linaro.org> * printcmd.c (build_address_symbolic): Call diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 563b48e..5bb05cd 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,355 @@ +2013-06-07 Pedro Alves <palves@redhat.com> + + * Makefile.in (OBS): Add tdesc.o. + (IPA_OBJS): Add tdesc-ipa.o. + (tdesc-ipa.o): New rule. + * ax.c (gdb_eval_agent_expr): Adjust register_size call to new + interface. + * linux-low.c (new_inferior): Delete. + (disabled_regsets, num_regsets): Delete. + (linux_add_process): Adjust to set the new per-process + new_inferior flag. + (linux_detach_one_lwp): Adjust to call regcache_invalidate_thread. + (linux_wait_for_lwp): Adjust. Only call arch_setup if the event + was a stop. When calling arch_setup, switch the current inferior + to the thread that got an event. + (linux_resume_one_lwp): Adjust to call regcache_invalidate_thread. + (regsets_fetch_inferior_registers) + (regsets_store_inferior_registers): New regsets_info parameter. + Adjust to use it. + (linux_register_in_regsets): New regs_info parameter. Adjust to + use it. + (register_addr, fetch_register, store_register): New usrregs_info + parameter. Adjust to use it. + (usr_fetch_inferior_registers, usr_store_inferior_registers): New + parameter regs_info. Adjust to use it. + (linux_fetch_registers): Get the current inferior's regs_info, and + adjust to use it. + (linux_store_registers): Ditto. + [HAVE_LINUX_REGSETS] (initialize_regsets_info): New. + (initialize_low): Don't initialize the target_regsets here. Call + initialize_low_arch. + * linux-low.h (target_regsets): Delete declaration. + (struct regsets_info): New. + (struct usrregs_info): New. + (struct regs_info): New. + (struct process_info_private) <new_inferior>: New field. + (struct linux_target_ops): Delete the num_regs, regmap, and + regset_bitmap fields. New field regs_info. + [HAVE_LINUX_REGSETS] (initialize_regsets_info): Declare. + * i387-fp.c (num_xmm_registers): Delete. + (i387_cache_to_fsave, i387_fsave_to_cache): Adjust find_regno + calls to new interface. + (i387_cache_to_fxsave, i387_cache_to_xsave, i387_fxsave_to_cache) + (i387_xsave_to_cache): Adjust find_regno calls to new interface. + Infer the number of xmm registers from the regcache's target + description. + * i387-fp.h (num_xmm_registers): Delete. + * inferiors.c (add_thread): Don't install the thread's regcache + here. + * proc-service.c (gregset_info): Fetch the current inferior's + regs_info. Adjust to use it. + * regcache.c: Include tdesc.h. + (register_bytes, reg_defs, num_registers) + (gdbserver_expedite_regs): Delete. + (get_thread_regcache): If the thread doesn't have a regcache yet, + create one, instead of aborting gdbserver. + (regcache_invalidate_one): Rename to ... + (regcache_invalidate_thread): ... this. + (regcache_invalidate_one): New. + (regcache_invalidate): Only invalidate registers of the current + process. + (init_register_cache): Add target_desc parameter, and use it. + (new_register_cache): Ditto. Assert the target description has a + non zero registers_size. + (regcache_cpy): Add assertions. Adjust. + (realloc_register_cache, set_register_cache): Delete. + (registers_to_string, registers_from_string): Adjust. + (find_register_by_name, find_regno, find_register_by_number) + (register_cache_size): Add target_desc parameter, and use it. + (free_register_cache_thread, free_register_cache_thread_one) + (regcache_release, register_cache_size): New. + (register_size): Add target_desc parameter, and use it. + (register_data, supply_register, supply_register_zeroed) + (supply_regblock, supply_register_by_name, collect_register) + (collect_register_as_string, collect_register_by_name): Adjust. + * regcache.h (struct target_desc): Forward declare. + (struct regcache) <tdesc>: New field. + (init_register_cache, new_register_cache): Add target_desc + parameter. + (regcache_invalidate_thread): Declare. + (regcache_invalidate_one): Delete declaration. + (regcache_release): Declare. + (find_register_by_number, register_cache_size, register_size) + (find_regno): Add target_desc parameter. + (gdbserver_expedite_regs, gdbserver_xmltarget): Delete + declarations. + * remote-utils.c: Include tdesc.h. + (outreg, prepare_resume_reply): Adjust. + * server.c: Include tdesc.h. + (gdbserver_xmltarget): Delete declaration. + (get_features_xml, process_serial_event): Adjust. + * server.h [IN_PROCESS_AGENT] (struct target_desc): Forward + declare. + (struct process_info) <tdesc>: New field. + (ipa_tdesc): Declare. + * tdesc.c: New file. + * tdesc.h: New file. + * tracepoint.c: Include tdesc.h. + [IN_PROCESS_AGENT] (ipa_tdesc): Define. + (get_context_regcache): Adjust to pass ipa_tdesc down. + (do_action_at_tracepoint): Adjust to get the register cache size + from the context regcache's description. + (traceframe_walk_blocks): Adjust to get the register cache size + from the current trace frame's description. + (traceframe_get_pc): Adjust to get current trace frame's + description and pass it down. + (gdb_collect): Adjust to get the register cache size from the + IPA's description. + * linux-amd64-ipa.c (tdesc_amd64_linux): Declare. + (gdbserver_xmltarget): Delete. + (initialize_low_tracepoint): Set the ipa's target description. + * linux-i386-ipa.c (tdesc_i386_linux): Declare. + (initialize_low_tracepoint): Set the ipa's target description. + * linux-x86-low.c: Include tdesc.h. + [__x86_64__] (is_64bit_tdesc): New. + (ps_get_thread_area, x86_get_thread_area): Use it. + (i386_cannot_store_register): Rename to ... + (x86_cannot_store_register): ... this. Use is_64bit_tdesc. + (i386_cannot_fetch_register): Rename to ... + (x86_cannot_fetch_register): ... this. Use is_64bit_tdesc. + (x86_fill_gregset, x86_store_gregset): Adjust register_size calls + to new interface. + (target_regsets): Rename to ... + (x86_regsets): ... this. + (x86_get_pc, x86_set_pc): Adjust register_size calls to new + interface. + (x86_siginfo_fixup): Use is_64bit_tdesc. + [__x86_64__] (tdesc_amd64_linux, tdesc_amd64_avx_linux) + (tdesc_x32_avx_linux, tdesc_x32_linux) + (tdesc_i386_linux, tdesc_i386_mmx_linux, tdesc_i386_avx_linux): + Declare. + (x86_linux_update_xmltarget): Delete. + (I386_LINUX_XSAVE_XCR0_OFFSET): Define. + (have_ptrace_getfpxregs, have_ptrace_getregset): New. + (AMD64_LINUX_USER64_CS): New. + (x86_linux_read_description): New, based on + x86_linux_update_xmltarget. + (same_process_callback): New. + (x86_arch_setup_process_callback): New. + (x86_linux_update_xmltarget): New. + (x86_regsets_info): New. + (amd64_linux_regs_info): New. + (i386_linux_usrregs_info): New. + (i386_linux_regs_info): New. + (x86_linux_regs_info): New. + (x86_arch_setup): Reimplement. + (x86_install_fast_tracepoint_jump_pad): Use is_64bit_tdesc. + (x86_emit_ops): Ditto. + (the_low_target): Adjust. Install x86_linux_regs_info, + x86_cannot_fetch_register, and x86_cannot_store_register. + (initialize_low_arch): New. + * linux-ia64-low.c (tdesc_ia64): Declare. + (ia64_fetch_register): Adjust. + (ia64_usrregs_info, regs_info): New globals. + (ia64_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-sparc-low.c (tdesc_sparc64): Declare. + (sparc_fill_gregset_to_stack, sparc_store_gregset_from_stack): + Adjust. + (sparc_arch_setup): New function. + (sparc_regsets_info, sparc_usrregs_info, regs_info): New globals. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-ppc-low.c (tdesc_powerpc_32l, tdesc_powerpc_altivec32l) + (tdesc_powerpc_cell32l, tdesc_powerpc_vsx32l) + (tdesc_powerpc_isa205_32l, tdesc_powerpc_isa205_altivec32l) + (tdesc_powerpc_isa205_vsx32l, tdesc_powerpc_e500l) + (tdesc_powerpc_64l, tdesc_powerpc_altivec64l) + (tdesc_powerpc_cell64l, tdesc_powerpc_vsx64l) + (tdesc_powerpc_isa205_64l, tdesc_powerpc_isa205_altivec64l) + (tdesc_powerpc_isa205_vsx64l): Declare. + (ppc_cannot_store_register, ppc_collect_ptrace_register) + (ppc_supply_ptrace_register, parse_spufs_run, ppc_get_pc) + (ppc_set_pc, ppc_get_hwcap): Adjust. + (ppc_usrregs_info): Forward declare. + (!__powerpc64__) ppc_regmap_adjusted: New global. + (ppc_arch_setup): Adjust to the current process'es target + description. + (ppc_fill_vsxregset, ppc_store_vsxregset, ppc_fill_vrregset) + (ppc_store_vrregset, ppc_fill_evrregset, ppc_store_evrregse) + (ppc_store_evrregset): Adjust. + (target_regsets): Rename to ... + (ppc_regsets): ... this, and make static. + (ppc_usrregs_info, ppc_regsets_info, regs_info): New globals. + (ppc_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-s390-low.c (tdesc_s390_linux32, tdesc_s390_linux32v1) + (tdesc_s390_linux32v2, tdesc_s390_linux64, tdesc_s390_linux64v1) + (tdesc_s390_linux64v2, tdesc_s390x_linux64, tdesc_s390x_linux64v1) + (tdesc_s390x_linux64v2): Declare. + (s390_collect_ptrace_register, s390_supply_ptrace_register) + (s390_fill_gregset, s390_store_last_break): Adjust. + (target_regsets): Rename to ... + (s390_regsets): ... this, and make static. + (s390_get_pc, s390_set_pc): Adjust. + (s390_get_hwcap): New target_desc parameter, and use it. + [__s390x__] (have_hwcap_s390_high_gprs): New global. + (s390_arch_setup): Adjust to set the current process'es target + description. Don't adjust the regmap. + (s390_usrregs_info, s390_regsets_info, regs_info): New globals. + [__s390x__] (s390_usrregs_info_3264, s390_regsets_info_3264) + (regs_info_3264): New globals. + (s390_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-mips-low.c (tdesc_mips_linux, tdesc_mips_dsp_linux) + (tdesc_mips64_linux, tdesc_mips64_dsp_linux): Declare. + [__mips64] (init_registers_mips_linux) + (init_registers_mips_dsp_linux): Delete defines. + [__mips64] (tdesc_mips_linux, tdesc_mips_dsp_linux): New defines. + (have_dsp): New global. + (mips_read_description): New, based on mips_arch_setup. + (mips_arch_setup): Reimplement. + (get_usrregs_info): New function. + (mips_cannot_fetch_register, mips_cannot_store_register) + (mips_get_pc, mips_set_pc, mips_fill_gregset, mips_store_gregset) + (mips_fill_fpregset, mips_store_fpregset): Adjust. + (target_regsets): Rename to ... + (mips_regsets): ... this, and make static. + (mips_regsets_info, mips_dsp_usrregs_info, mips_usrregs_info) + (dsp_regs_info, regs_info): New globals. + (mips_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-arm-low.c (tdesc_arm, tdesc_arm_with_iwmmxt) + (tdesc_arm_with_vfpv2, tdesc_arm_with_vfpv3, tdesc_arm_with_neon): + Declare. + (arm_fill_vfpregset, arm_store_vfpregset): Adjust. + (arm_read_description): New, with bits factored from + arm_arch_setup. + (arm_arch_setup): Reimplement. + (target_regsets): Rename to ... + (arm_regsets): ... this, and make static. + (arm_regsets_info, arm_usrregs_info, regs_info): New globals. + (arm_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-m68k-low.c (tdesc_m68k): Declare. + (target_regsets): Rename to ... + (m68k_regsets): ... this, and make static. + (m68k_regsets_info, m68k_usrregs_info, regs_info): New globals. + (m68k_regs_info): New function. + (m68k_arch_setup): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-sh-low.c (tdesc_sharch): Declare. + (target_regsets): Rename to ... + (sh_regsets): ... this, and make static. + (sh_regsets_info, sh_usrregs_info, regs_info): New globals. + (sh_regs_info, sh_arch_setup): New functions. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-bfin-low.c (tdesc_bfin): Declare. + (bfin_arch_setup): New function. + (bfin_usrregs_info, regs_info): New globals. + (bfin_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-cris-low.c (tdesc_cris): Declare. + (cris_arch_setup): New function. + (cris_usrregs_info, regs_info): New globals. + (cris_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-cris-low.c (tdesc_crisv32): Declare. + (cris_arch_setup): New function. + (cris_regsets_info, cris_usrregs_info, regs_info): New globals. + (cris_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-m32r-low.c (tdesc_m32r): Declare. + (m32r_arch_setup): New function. + (m32r_usrregs_info, regs_info): New globals. + (m32r_regs_info): Adjust. + (initialize_low_arch): New function. + * linux-tic6x-low.c (tdesc_tic6x_c64xp_linux) + (tdesc_tic6x_c64x_linux, tdesc_tic6x_c62x_linux): Declare. + (tic6x_usrregs_info): Forward declare. + (tic6x_read_description): New function, based on ... + (tic6x_arch_setup): ... this. Reimplement. + (target_regsets): Rename to ... + (tic6x_regsets): ... this, and make static. + (tic6x_regsets_info, tic6x_usrregs_info, regs_info): New globals. + (tic6x_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-xtensa-low.c (tdesc_xtensa): Declare. + (xtensa_fill_gregset, xtensa_store_gregset): Adjust. + (target_regsets): Rename to ... + (xtensa_regsets): ... this, and make static. + (xtensa_regsets_info, xtensa_usrregs_info, regs_info): New + globals. + (xtensa_arch_setup, xtensa_regs_info): New functions. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-nios2-low.c (tdesc_nios2_linux): Declare. + (nios2_arch_setup): Set the current process'es tdesc. + (target_regsets): Rename to ... + (nios2_regsets): ... this. + (nios2_regsets_info, nios2_usrregs_info, regs_info): New globals. + (nios2_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-aarch64-low.c (tdesc_aarch64): Declare. + (aarch64_arch_setup): Set the current process'es tdesc. + (target_regsets): Rename to ... + (aarch64_regsets): ... this. + (aarch64_regsets_info, aarch64_usrregs_info, regs_info): New globals. + (aarch64_regs_info): New function. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * linux-tile-low.c (tdesc_tilegx, tdesc_tilegx32): Declare + globals. + (target_regsets): Rename to ... + (tile_regsets): ... this. + (tile_regsets_info, tile_usrregs_info, regs_info): New globals. + (tile_regs_info): New function. + (tile_arch_setup): Set the current process'es tdesc. + (the_low_target): Adjust. + (initialize_low_arch): New function. + * spu-low.c (tdesc_spu): Declare. + (spu_create_inferior, spu_attach): Set the new process'es tdesc. + * win32-arm-low.c (tdesc_arm): Declare. + (arm_arch_setup): New function. + (the_low_target): Install arm_arch_setup instead of + init_registers_arm. + * win32-i386-low.c (tdesc_i386, tdesc_amd64): Declare. + (init_windows_x86): Rename to ... + (i386_arch_setup): ... this. Set `win32_tdesc'. + (the_low_target): Adjust. + * win32-low.c (win32_tdesc): New global. + (child_add_thread): Don't create the thread cache here. + (do_initial_child_stuff): Set the new process'es tdesc. + * win32-low.h (struct target_desc): Forward declare. + (win32_tdesc): Declare. + * lynx-i386-low.c (tdesc_i386): Declare global. + (lynx_i386_arch_setup): Set `lynx_tdesc'. + * lynx-low.c (lynx_tdesc): New global. + (lynx_add_process): Set the new process'es tdesc. + * lynx-low.h (struct target_desc): Forward declare. + (lynx_tdesc): Declare global. + * lynx-ppc-low.c (tdesc_powerpc_32): Declare global. + (lynx_ppc_arch_setup): Set `lynx_tdesc'. + * nto-low.c (nto_tdesc): New global. + (do_attach): Set the new process'es tdesc. + * nto-low.h (struct target_desc): Forward declare. + (nto_tdesc): Declare. + * nto-x86-low.c (tdesc_i386): Declare. + (nto_x86_arch_setup): Set `nto_tdesc'. + 2013-06-04 Gary Benson <gbenson@redhat.com> * server.c (handle_query): Add "augmented-libraries-svr4-read+" diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index c7ff4c6..e8470a8 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -170,7 +170,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o targ utils.o version.o vec.o gdb_vecs.o \ mem-break.o hostio.o event-loop.o tracepoint.o \ xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \ - dll.o notif.o \ + dll.o notif.o tdesc.o \ $(XML_BUILTIN) \ $(DEPFILES) $(LIBOBJS) GDBREPLAY_OBS = gdbreplay.o version.o @@ -287,7 +287,7 @@ gdbreplay$(EXEEXT): $(GDBREPLAY_OBS) ${CC-LD} $(INTERNAL_CFLAGS) $(INTERNAL_LDFLAGS) -o gdbreplay$(EXEEXT) $(GDBREPLAY_OBS) \ $(XM_CLIBS) -IPA_OBJS=ax-ipa.o tracepoint-ipa.o format-ipa.o utils-ipa.o regcache-ipa.o remote-utils-ipa.o common-utils-ipa.o ${IPA_DEPFILES} +IPA_OBJS=ax-ipa.o tracepoint-ipa.o format-ipa.o utils-ipa.o regcache-ipa.o remote-utils-ipa.o common-utils-ipa.o tdesc-ipa.o ${IPA_DEPFILES} IPA_LIB=libinproctrace.so @@ -505,6 +505,9 @@ linux-amd64-ipa.o: linux-amd64-ipa.c amd64-linux-ipa.o: amd64-linux.c $(IPAGENT_COMPILE) $< $(POSTCOMPILE) +tdesc-ipa.o: tdesc.c + $(IPAGENT_COMPILE) $< + $(POSTCOMPILE) ax.o: ax.c $(COMPILE) $(WARN_CFLAGS_NO_FORMAT) $< diff --git a/gdb/gdbserver/ax.c b/gdb/gdbserver/ax.c index cd5cf2b..b6824a2 100644 --- a/gdb/gdbserver/ax.c +++ b/gdb/gdbserver/ax.c @@ -1162,7 +1162,7 @@ gdb_eval_agent_expr (struct eval_agent_expr_context *ctx, int regnum = arg; struct regcache *regcache = ctx->regcache; - switch (register_size (regnum)) + switch (register_size (regcache->tdesc, regnum)) { case 8: collect_register (regcache, regnum, cnv.u64.bytes); diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c index d2543b2..2886519 100644 --- a/gdb/gdbserver/i387-fp.c +++ b/gdb/gdbserver/i387-fp.c @@ -20,8 +20,6 @@ #include "i387-fp.h" #include "i386-xstate.h" -int num_xmm_registers = 8; - /* Note: These functions preserve the reserved bits in control registers. However, gdbserver promptly throws away that information. */ @@ -117,7 +115,7 @@ i387_cache_to_fsave (struct regcache *regcache, void *buf) { struct i387_fsave *fp = (struct i387_fsave *) buf; int i; - int st0_regnum = find_regno ("st0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); unsigned long val, val2; for (i = 0; i < 8; i++) @@ -157,7 +155,7 @@ i387_fsave_to_cache (struct regcache *regcache, const void *buf) { struct i387_fsave *fp = (struct i387_fsave *) buf; int i; - int st0_regnum = find_regno ("st0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); unsigned long val; for (i = 0; i < 8; i++) @@ -193,9 +191,11 @@ i387_cache_to_fxsave (struct regcache *regcache, void *buf) { struct i387_fxsave *fp = (struct i387_fxsave *) buf; int i; - int st0_regnum = find_regno ("st0"); - int xmm0_regnum = find_regno ("xmm0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); unsigned long val, val2; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; for (i = 0; i < 8; i++) collect_register (regcache, i + st0_regnum, @@ -249,6 +249,8 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) unsigned long long xstate_bv = 0; char raw[16]; char *p; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; /* The supported bits in `xstat_bv' are 1 byte. Clear part in vector registers if its bit in xstat_bv is zero. */ @@ -274,7 +276,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) /* Check if any x87 registers are changed. */ if ((x86_xcr0 & I386_XSTATE_X87)) { - int st0_regnum = find_regno ("st0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); for (i = 0; i < 8; i++) { @@ -291,7 +293,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) /* Check if any SSE registers are changed. */ if ((x86_xcr0 & I386_XSTATE_SSE)) { - int xmm0_regnum = find_regno ("xmm0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); for (i = 0; i < num_xmm_registers; i++) { @@ -308,7 +310,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf) /* Check if any AVX registers are changed. */ if ((x86_xcr0 & I386_XSTATE_AVX)) { - int ymm0h_regnum = find_regno ("ymm0h"); + int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); for (i = 0; i < num_xmm_registers; i++) { @@ -413,9 +415,11 @@ i387_fxsave_to_cache (struct regcache *regcache, const void *buf) { struct i387_fxsave *fp = (struct i387_fxsave *) buf; int i, top; - int st0_regnum = find_regno ("st0"); - int xmm0_regnum = find_regno ("xmm0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); unsigned long val; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; for (i = 0; i < 8; i++) supply_register (regcache, i + st0_regnum, @@ -468,6 +472,8 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) unsigned long val; unsigned int clear_bv; gdb_byte *p; + /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */ + int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8; /* The supported bits in `xstat_bv' are 1 byte. Clear part in vector registers if its bit in xstat_bv is zero. */ @@ -476,7 +482,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) /* Check if any x87 registers are changed. */ if ((x86_xcr0 & I386_XSTATE_X87) != 0) { - int st0_regnum = find_regno ("st0"); + int st0_regnum = find_regno (regcache->tdesc, "st0"); if ((clear_bv & I386_XSTATE_X87) != 0) { @@ -493,7 +499,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) if ((x86_xcr0 & I386_XSTATE_SSE) != 0) { - int xmm0_regnum = find_regno ("xmm0"); + int xmm0_regnum = find_regno (regcache->tdesc, "xmm0"); if ((clear_bv & I386_XSTATE_SSE)) { @@ -510,7 +516,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf) if ((x86_xcr0 & I386_XSTATE_AVX) != 0) { - int ymm0h_regnum = find_regno ("ymm0h"); + int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h"); if ((clear_bv & I386_XSTATE_AVX) != 0) { diff --git a/gdb/gdbserver/i387-fp.h b/gdb/gdbserver/i387-fp.h index efc70ed..9473cda 100644 --- a/gdb/gdbserver/i387-fp.h +++ b/gdb/gdbserver/i387-fp.h @@ -30,6 +30,4 @@ void i387_xsave_to_cache (struct regcache *regcache, const void *buf); extern unsigned long long x86_xcr0; -extern int num_xmm_registers; - #endif /* I387_FP_H */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 6953d0e..39eb52e 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -102,7 +102,6 @@ add_thread (ptid_t thread_id, void *target_data) current_inferior = new_thread; new_thread->target_data = target_data; - set_inferior_regcache_data (new_thread, new_register_cache ()); } ptid_t diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c index cdf9cfd..e37f602 100644 --- a/gdb/gdbserver/linux-aarch64-low.c +++ b/gdb/gdbserver/linux-aarch64-low.c @@ -32,6 +32,7 @@ /* Defined in auto-generated files. */ void init_registers_aarch64 (void); +extern const struct target_desc *tdesc_aarch64; #ifdef HAVE_SYS_REG_H #include <sys/reg.h> @@ -1188,7 +1189,7 @@ aarch64_arch_setup (void) struct iovec iov; struct user_hwdebug_state dreg_state; - init_registers_aarch64 (); + current_process ()->tdesc = tdesc_aarch64; pid = lwpid_of (get_thread_lwp (current_inferior)); iov.iov_base = &dreg_state; @@ -1235,7 +1236,7 @@ aarch64_arch_setup (void) } } -struct regset_info target_regsets[] = +static struct regset_info aarch64_regsets[] = { { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (struct user_pt_regs), GENERAL_REGS, @@ -1247,12 +1248,36 @@ struct regset_info target_regsets[] = { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info aarch64_regsets_info = + { + aarch64_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info aarch64_usrregs_info = + { + AARCH64_NUM_REGS, + aarch64_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &aarch64_usrregs_info, + &aarch64_regsets_info, + }; + +static const struct regs_info * +aarch64_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { aarch64_arch_setup, - AARCH64_NUM_REGS, - aarch64_regmap, - NULL, + aarch64_regs_info, aarch64_cannot_fetch_register, aarch64_cannot_store_register, NULL, @@ -1274,3 +1299,11 @@ struct linux_target_ops the_low_target = aarch64_linux_new_thread, aarch64_linux_prepare_to_resume, }; + +void +initialize_low_arch (void) +{ + init_registers_aarch64 (); + + initialize_regsets_info (&aarch64_regsets_info); +} diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c index dc20a15..34daedf 100644 --- a/gdb/gdbserver/linux-amd64-ipa.c +++ b/gdb/gdbserver/linux-amd64-ipa.c @@ -22,6 +22,7 @@ /* Defined in auto-generated file amd64-linux.c. */ void init_registers_amd64_linux (void); +extern const struct target_desc *tdesc_amd64_linux; /* fast tracepoints collect registers. */ @@ -164,12 +165,9 @@ supply_static_tracepoint_registers (struct regcache *regcache, #endif /* HAVE_UST */ -/* This is only needed because reg-i386-linux-lib.o references it. We - may use it proper at some point. */ -const char *gdbserver_xmltarget; - void initialize_low_tracepoint (void) { init_registers_amd64_linux (); + ipa_tdesc = tdesc_amd64_linux; } diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index 8ddd90a..a6b745d 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -29,10 +29,19 @@ /* Defined in auto-generated files. */ void init_registers_arm (void); +extern const struct target_desc *tdesc_arm; + void init_registers_arm_with_iwmmxt (void); +extern const struct target_desc *tdesc_arm_with_iwmmxt; + void init_registers_arm_with_vfpv2 (void); +extern const struct target_desc *tdesc_arm_with_vfpv2; + void init_registers_arm_with_vfpv3 (void); +extern const struct target_desc *tdesc_arm_with_vfpv3; + void init_registers_arm_with_neon (void); +extern const struct target_desc *tdesc_arm_with_neon; #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 22 @@ -212,7 +221,7 @@ arm_fill_vfpregset (struct regcache *regcache, void *buf) else num = 16; - base = find_regno ("d0"); + base = find_regno (regcache->tdesc, "d0"); for (i = 0; i < num; i++) collect_register (regcache, base + i, (char *) buf + i * 8); @@ -232,7 +241,7 @@ arm_store_vfpregset (struct regcache *regcache, const void *buf) else num = 16; - base = find_regno ("d0"); + base = find_regno (regcache->tdesc, "d0"); for (i = 0; i < num; i++) supply_register (regcache, base + i, (char *) buf + i * 8); @@ -768,8 +777,8 @@ arm_get_hwcap (unsigned long *valp) return 0; } -static void -arm_arch_setup (void) +static const struct target_desc * +arm_read_description (void) { int pid = lwpid_of (get_thread_lwp (current_inferior)); @@ -778,29 +787,24 @@ arm_arch_setup (void) arm_hwcap = 0; if (arm_get_hwcap (&arm_hwcap) == 0) - { - init_registers_arm (); - return; - } + return tdesc_arm; if (arm_hwcap & HWCAP_IWMMXT) - { - init_registers_arm_with_iwmmxt (); - return; - } + return tdesc_arm_with_iwmmxt; if (arm_hwcap & HWCAP_VFP) { + const struct target_desc *result; char *buf; /* NEON implies either no VFP, or VFPv3-D32. We only support it with VFP. */ if (arm_hwcap & HWCAP_NEON) - init_registers_arm_with_neon (); + result = tdesc_arm_with_neon; else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) - init_registers_arm_with_vfpv3 (); + result = tdesc_arm_with_vfpv3; else - init_registers_arm_with_vfpv2 (); + result = tdesc_arm_with_vfpv2; /* Now make sure that the kernel supports reading these registers. Support was added in 2.6.30. */ @@ -810,19 +814,25 @@ arm_arch_setup (void) && errno == EIO) { arm_hwcap = 0; - init_registers_arm (); + result = tdesc_arm; } free (buf); - return; + return result; } /* The default configuration uses legacy FPA registers, probably simulated. */ - init_registers_arm (); + return tdesc_arm; } -struct regset_info target_regsets[] = { +static void +arm_arch_setup (void) +{ + current_process ()->tdesc = arm_read_description (); +} + +static struct regset_info arm_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, 18 * 4, GENERAL_REGS, arm_fill_gregset, arm_store_gregset }, @@ -835,11 +845,35 @@ struct regset_info target_regsets[] = { { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info arm_regsets_info = + { + arm_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info arm_usrregs_info = + { + arm_num_regs, + arm_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &arm_usrregs_info, + &arm_regsets_info + }; + +static const struct regs_info * +arm_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { arm_arch_setup, - arm_num_regs, - arm_regmap, - NULL, + arm_regs_info, arm_cannot_fetch_register, arm_cannot_store_register, NULL, /* fetch_register */ @@ -871,3 +905,16 @@ struct linux_target_ops the_low_target = { arm_new_thread, arm_prepare_to_resume, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_arm (); + init_registers_arm_with_iwmmxt (); + init_registers_arm_with_vfpv2 (); + init_registers_arm_with_vfpv3 (); + init_registers_arm_with_neon (); + + initialize_regsets_info (&arm_regsets_info); +} diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c index 3295ffd..cced3e1 100644 --- a/gdb/gdbserver/linux-bfin-low.c +++ b/gdb/gdbserver/linux-bfin-low.c @@ -26,6 +26,7 @@ /* Defined in auto-generated file reg-bfin.c. */ void init_registers_bfin (void); +extern const struct target_desc *tdesc_bfin; static int bfin_regmap[] = { @@ -90,11 +91,33 @@ bfin_breakpoint_at (CORE_ADDR where) return 0; } +static void +bfin_arch_setup (void) +{ + current_process ()->tdesc = tdesc_bfin; +} + +static struct usrregs_info bfin_usrregs_info = + { + bfin_num_regs, + bfin_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &bfin_usrregs_info, + }; + +static const struct regs_info * +bfin_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_bfin, - bfin_num_regs, - bfin_regmap, - NULL, + bfin_arch_setup, + bfin_regs_info, bfin_cannot_fetch_register, bfin_cannot_store_register, NULL, /* fetch_register */ @@ -106,3 +129,10 @@ struct linux_target_ops the_low_target = { 2, bfin_breakpoint_at, }; + + +void +initialize_low_arch (void) +{ + init_registers_bfin (); +} diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c index b9217de..b548117 100644 --- a/gdb/gdbserver/linux-cris-low.c +++ b/gdb/gdbserver/linux-cris-low.c @@ -22,6 +22,7 @@ /* Defined in auto-generated file reg-cris.c. */ void init_registers_cris (void); +extern const struct target_desc *tdesc_cris; /* CRISv10 */ #define cris_num_regs 32 @@ -107,11 +108,33 @@ cris_reinsert_addr (void) return pc; } +static void +cris_arch_setup (void) +{ + current_process ()->tdesc = tdesc_cris; +} + +static struct usrregs_info cris_usrregs_info = + { + cris_num_regs, + cris_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &cris_usrregs_info, + }; + +static const struct regs_info * +cris_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_cris, - cris_num_regs, - cris_regmap, - NULL, + cris_arch_setup, + cris_regs_info, cris_cannot_fetch_register, cris_cannot_store_register, NULL, /* fetch_register */ @@ -127,3 +150,9 @@ struct linux_target_ops the_low_target = { 0, 0, }; + +void +initialize_low_arch (void) +{ + init_registers_cris (); +} diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c index ca0e276..efe50a7 100644 --- a/gdb/gdbserver/linux-crisv32-low.c +++ b/gdb/gdbserver/linux-crisv32-low.c @@ -22,6 +22,7 @@ /* Defined in auto-generated file reg-crisv32.c. */ void init_registers_crisv32 (void); +extern const struct target_desc *tdesc_crisv32; /* CRISv32 */ #define cris_num_regs 49 @@ -362,17 +363,50 @@ cris_store_gregset (struct regcache *regcache, const void *buf) } } -struct regset_info target_regsets[] = { +static void +cris_arch_setup (void) +{ + current_process ()->tdesc = tdesc_crisv32; +} + +typedef unsigned long elf_gregset_t[cris_num_regs]; + +static struct regset_info cris_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, cris_num_regs * 4, GENERAL_REGS, cris_fill_gregset, cris_store_gregset }, { 0, 0, 0, -1, -1, NULL, NULL } }; + +static struct regsets_info cris_regsets_info = + { + cris_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info cris_usrregs_info = + { + cris_num_regs, + cris_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &cris_usrregs_info, + &cris_regsets_info + }; + +static const struct regs_info * +cris_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_crisv32, - -1, - NULL, - NULL, + cris_arch_setup, + cris_regs_info, NULL, NULL, NULL, /* fetch_register */ @@ -388,3 +422,11 @@ struct linux_target_ops the_low_target = { cris_stopped_by_watchpoint, cris_stopped_data_address, }; + +void +initialize_low_arch (void) +{ + init_register_crisv32 (); + + initialize_regsets_info (&cris_regsets_info); +} diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c index 1c52284..e0245c5 100644 --- a/gdb/gdbserver/linux-i386-ipa.c +++ b/gdb/gdbserver/linux-i386-ipa.c @@ -49,6 +49,7 @@ enum i386_gdb_regnum /* Defined in auto-generated file i386-linux.c. */ void init_registers_i386_linux (void); +extern const struct target_desc *tdesc_i386_linux; #define FT_CR_EAX 15 #define FT_CR_ECX 14 @@ -250,5 +251,6 @@ void initialize_low_tracepoint (void) { init_registers_i386_linux (); + ipa_tdesc = tdesc_i386_linux; initialize_fast_tracepoint_trampoline_buffer (); } diff --git a/gdb/gdbserver/linux-ia64-low.c b/gdb/gdbserver/linux-ia64-low.c index deedb21..8cd2da4 100644 --- a/gdb/gdbserver/linux-ia64-low.c +++ b/gdb/gdbserver/linux-ia64-low.c @@ -25,6 +25,7 @@ /* Defined in auto-generated file reg-ia64.c. */ void init_registers_ia64 (void); +extern const struct target_desc *tdesc_ia64; #define ia64_num_regs 462 @@ -290,7 +291,7 @@ ia64_fetch_register (struct regcache *regcache, int regnum) { const gdb_byte zero[8] = { 0 }; - gdb_assert (sizeof (zero) == register_size (regnum)); + gdb_assert (sizeof (zero) == register_size (regcache->tdesc, regnum)); supply_register (regcache, regnum, zero); return 1; } @@ -300,7 +301,7 @@ ia64_fetch_register (struct regcache *regcache, int regnum) { const gdb_byte f_zero[16] = { 0 }; - gdb_assert (sizeof (f_zero) == register_size (regnum)); + gdb_assert (sizeof (f_zero) == register_size (regcache->tdesc, regnum)); supply_register (regcache, regnum, f_zero); return 1; } @@ -311,7 +312,7 @@ ia64_fetch_register (struct regcache *regcache, int regnum) const gdb_byte f_one[16] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0 }; - gdb_assert (sizeof (f_one) == register_size (regnum)); + gdb_assert (sizeof (f_one) == register_size (regcache->tdesc, regnum)); supply_register (regcache, regnum, f_one); return 1; } @@ -319,12 +320,41 @@ ia64_fetch_register (struct regcache *regcache, int regnum) return 0; } +static struct usrregs_info ia64_usrregs_info = + { + ia64_num_regs, + ia64_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &ia64_usrregs_info + }; + +static const struct regs_info * +ia64_regs_info (void) +{ + return ®s_info; +} + +static void +ia64_arch_setup (void) +{ + current_process ()->tdesc = tdesc_ia64; +} + + struct linux_target_ops the_low_target = { - init_registers_ia64, - ia64_num_regs, - ia64_regmap, - NULL, + ia64_arch_setup, + ia64_regs_info, ia64_cannot_fetch_register, ia64_cannot_store_register, ia64_fetch_register, }; + +void +initialize_low_arch (void) +{ + init_registers_ia64 (); +} diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 03ac469..4247b11 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -224,15 +224,6 @@ int using_threads = 1; jump pads). */ static int stabilizing_threads; -/* This flag is true iff we've just created or attached to our first - inferior but it has not stopped yet. As soon as it does, we need - to call the low target's arch_setup callback. Doing this only on - the first inferior avoids reinializing the architecture on every - inferior, and avoids messing with the register caches of the - already running inferiors. NOTE: this assumes all inferiors under - control of gdbserver have the same architecture. */ -static int new_inferior; - static void linux_resume_one_lwp (struct lwp_info *lwp, int step, int signal, siginfo_t *info); static void linux_resume (struct thread_resume *resume_info, size_t n); @@ -293,11 +284,6 @@ struct pending_signals struct pending_signals *prev; }; -#ifdef HAVE_LINUX_REGSETS -static char *disabled_regsets; -static int num_regsets; -#endif - /* The read/write ends of the pipe registered as waitable file in the event loop. */ static int linux_event_pipe[2] = { -1, -1 }; @@ -379,13 +365,12 @@ linux_add_process (int pid, int attached) { struct process_info *proc; - /* Is this the first process? If so, then set the arch. */ - if (all_processes.head == NULL) - new_inferior = 1; - proc = add_process (pid, attached); proc->private = xcalloc (1, sizeof (*proc->private)); + /* Set the arch when the first LWP stops. */ + proc->private->new_inferior = 1; + if (the_low_target.new_process != NULL) proc->private->arch_private = the_low_target.new_process (); @@ -1203,8 +1188,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) } /* Flush any pending changes to the process's registers. */ - regcache_invalidate_one ((struct inferior_list_entry *) - get_lwp_thread (lwp)); + regcache_invalidate_thread (get_lwp_thread (lwp)); /* Pass on any pending signal for this thread. */ sig = get_detach_signal (thread); @@ -1412,17 +1396,28 @@ retry: child->last_status = *wstatp; - /* Architecture-specific setup after inferior is running. - This needs to happen after we have attached to the inferior - and it is stopped for the first time, but before we access - any inferior registers. */ - if (new_inferior) + if (WIFSTOPPED (*wstatp)) { - the_low_target.arch_setup (); -#ifdef HAVE_LINUX_REGSETS - memset (disabled_regsets, 0, num_regsets); -#endif - new_inferior = 0; + struct process_info *proc; + + /* Architecture-specific setup after inferior is running. This + needs to happen after we have attached to the inferior and it + is stopped for the first time, but before we access any + inferior registers. */ + proc = find_process_pid (pid_of (child)); + if (proc->private->new_inferior) + { + struct thread_info *saved_inferior; + + saved_inferior = current_inferior; + current_inferior = get_lwp_thread (child); + + the_low_target.arch_setup (); + + current_inferior = saved_inferior; + + proc->private->new_inferior = 0; + } } /* Fetch the possibly triggered data watchpoint info and store it in @@ -3348,8 +3343,7 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n", if (the_low_target.prepare_to_resume != NULL) the_low_target.prepare_to_resume (lwp); - regcache_invalidate_one ((struct inferior_list_entry *) - get_lwp_thread (lwp)); + regcache_invalidate_thread (get_lwp_thread (lwp)); errno = 0; lwp->stopped = 0; lwp->stopped_by_watchpoint = 0; @@ -4058,14 +4052,15 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except) #define use_linux_regsets 1 static int -regsets_fetch_inferior_registers (struct regcache *regcache) +regsets_fetch_inferior_registers (struct regsets_info *regsets_info, + struct regcache *regcache) { struct regset_info *regset; int saw_general_regs = 0; int pid; struct iovec iov; - regset = target_regsets; + regset = regsets_info->regsets; pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) @@ -4073,7 +4068,8 @@ regsets_fetch_inferior_registers (struct regcache *regcache) void *buf, *data; int nt_type, res; - if (regset->size == 0 || disabled_regsets[regset - target_regsets]) + if (regset->size == 0 + || regsets_info->disabled_regsets[regset - regsets_info->regsets]) { regset ++; continue; @@ -4101,9 +4097,12 @@ regsets_fetch_inferior_registers (struct regcache *regcache) { if (errno == EIO) { + int dr_offset; + /* If we get EIO on a regset, do not try it again for - this process. */ - disabled_regsets[regset - target_regsets] = 1; + this process mode. */ + dr_offset = regset - regsets_info->regsets; + regsets_info->disabled_regsets[dr_offset] = 1; free (buf); continue; } @@ -4128,14 +4127,15 @@ regsets_fetch_inferior_registers (struct regcache *regcache) } static int -regsets_store_inferior_registers (struct regcache *regcache) +regsets_store_inferior_registers (struct regsets_info *regsets_info, + struct regcache *regcache) { struct regset_info *regset; int saw_general_regs = 0; int pid; struct iovec iov; - regset = target_regsets; + regset = regsets_info->regsets; pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) @@ -4143,7 +4143,8 @@ regsets_store_inferior_registers (struct regcache *regcache) void *buf, *data; int nt_type, res; - if (regset->size == 0 || disabled_regsets[regset - target_regsets]) + if (regset->size == 0 + || regsets_info->disabled_regsets[regset - regsets_info->regsets]) { regset ++; continue; @@ -4190,9 +4191,12 @@ regsets_store_inferior_registers (struct regcache *regcache) { if (errno == EIO) { + int dr_offset; + /* If we get EIO on a regset, do not try it again for - this process. */ - disabled_regsets[regset - target_regsets] = 1; + this process mode. */ + dr_offset = regset - regsets_info->regsets; + regsets_info->disabled_regsets[dr_offset] = 1; free (buf); continue; } @@ -4224,8 +4228,8 @@ regsets_store_inferior_registers (struct regcache *regcache) #else /* !HAVE_LINUX_REGSETS */ #define use_linux_regsets 0 -#define regsets_fetch_inferior_registers(regcache) 1 -#define regsets_store_inferior_registers(regcache) 1 +#define regsets_fetch_inferior_registers(regsets_info, regcache) 1 +#define regsets_store_inferior_registers(regsets_info, regcache) 1 #endif @@ -4233,50 +4237,52 @@ regsets_store_inferior_registers (struct regcache *regcache) calls or 0 if it has to be transferred individually. */ static int -linux_register_in_regsets (int regno) +linux_register_in_regsets (const struct regs_info *regs_info, int regno) { unsigned char mask = 1 << (regno % 8); size_t index = regno / 8; return (use_linux_regsets - && (the_low_target.regset_bitmap == NULL - || (the_low_target.regset_bitmap[index] & mask) != 0)); + && (regs_info->regset_bitmap == NULL + || (regs_info->regset_bitmap[index] & mask) != 0)); } #ifdef HAVE_LINUX_USRREGS int -register_addr (int regnum) +register_addr (const struct usrregs_info *usrregs, int regnum) { int addr; - if (regnum < 0 || regnum >= the_low_target.num_regs) + if (regnum < 0 || regnum >= usrregs->num_regs) error ("Invalid register number %d.", regnum); - addr = the_low_target.regmap[regnum]; + addr = usrregs->regmap[regnum]; return addr; } /* Fetch one register. */ static void -fetch_register (struct regcache *regcache, int regno) +fetch_register (const struct usrregs_info *usrregs, + struct regcache *regcache, int regno) { CORE_ADDR regaddr; int i, size; char *buf; int pid; - if (regno >= the_low_target.num_regs) + if (regno >= usrregs->num_regs) return; if ((*the_low_target.cannot_fetch_register) (regno)) return; - regaddr = register_addr (regno); + regaddr = register_addr (usrregs, regno); if (regaddr == -1) return; - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + size = ((register_size (regcache->tdesc, regno) + + sizeof (PTRACE_XFER_TYPE) - 1) & -sizeof (PTRACE_XFER_TYPE)); buf = alloca (size); @@ -4302,23 +4308,25 @@ fetch_register (struct regcache *regcache, int regno) /* Store one register. */ static void -store_register (struct regcache *regcache, int regno) +store_register (const struct usrregs_info *usrregs, + struct regcache *regcache, int regno) { CORE_ADDR regaddr; int i, size; char *buf; int pid; - if (regno >= the_low_target.num_regs) + if (regno >= usrregs->num_regs) return; if ((*the_low_target.cannot_store_register) (regno)) return; - regaddr = register_addr (regno); + regaddr = register_addr (usrregs, regno); if (regaddr == -1) return; - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + size = ((register_size (regcache->tdesc, regno) + + sizeof (PTRACE_XFER_TYPE) - 1) & -sizeof (PTRACE_XFER_TYPE)); buf = alloca (size); memset (buf, 0, size); @@ -4359,16 +4367,19 @@ store_register (struct regcache *regcache, int regno) unless ALL is non-zero. Otherwise, REGNO specifies which register (so we can save time). */ static void -usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all) +usr_fetch_inferior_registers (const struct regs_info *regs_info, + struct regcache *regcache, int regno, int all) { + struct usrregs_info *usr = regs_info->usrregs; + if (regno == -1) { - for (regno = 0; regno < the_low_target.num_regs; regno++) - if (all || !linux_register_in_regsets (regno)) - fetch_register (regcache, regno); + for (regno = 0; regno < usr->num_regs; regno++) + if (all || !linux_register_in_regsets (regs_info, regno)) + fetch_register (usr, regcache, regno); } else - fetch_register (regcache, regno); + fetch_register (usr, regcache, regno); } /* Store our register values back into the inferior. @@ -4377,22 +4388,25 @@ usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all) unless ALL is non-zero. Otherwise, REGNO specifies which register (so we can save time). */ static void -usr_store_inferior_registers (struct regcache *regcache, int regno, int all) +usr_store_inferior_registers (const struct regs_info *regs_info, + struct regcache *regcache, int regno, int all) { + struct usrregs_info *usr = regs_info->usrregs; + if (regno == -1) { - for (regno = 0; regno < the_low_target.num_regs; regno++) - if (all || !linux_register_in_regsets (regno)) - store_register (regcache, regno); + for (regno = 0; regno < usr->num_regs; regno++) + if (all || !linux_register_in_regsets (regs_info, regno)) + store_register (usr, regcache, regno); } else - store_register (regcache, regno); + store_register (usr, regcache, regno); } #else /* !HAVE_LINUX_USRREGS */ -#define usr_fetch_inferior_registers(regcache, regno, all) do {} while (0) -#define usr_store_inferior_registers(regcache, regno, all) do {} while (0) +#define usr_fetch_inferior_registers(regs_info, regcache, regno, all) do {} while (0) +#define usr_store_inferior_registers(regs_info, regcache, regno, all) do {} while (0) #endif @@ -4402,15 +4416,18 @@ linux_fetch_registers (struct regcache *regcache, int regno) { int use_regsets; int all = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); if (regno == -1) { - if (the_low_target.fetch_register != NULL) - for (regno = 0; regno < the_low_target.num_regs; regno++) + if (the_low_target.fetch_register != NULL + && regs_info->usrregs != NULL) + for (regno = 0; regno < regs_info->usrregs->num_regs; regno++) (*the_low_target.fetch_register) (regcache, regno); - all = regsets_fetch_inferior_registers (regcache); - usr_fetch_inferior_registers (regcache, -1, all); + all = regsets_fetch_inferior_registers (regs_info->regsets_info, regcache); + if (regs_info->usrregs != NULL) + usr_fetch_inferior_registers (regs_info, regcache, -1, all); } else { @@ -4418,11 +4435,12 @@ linux_fetch_registers (struct regcache *regcache, int regno) && (*the_low_target.fetch_register) (regcache, regno)) return; - use_regsets = linux_register_in_regsets (regno); + use_regsets = linux_register_in_regsets (regs_info, regno); if (use_regsets) - all = regsets_fetch_inferior_registers (regcache); - if (!use_regsets || all) - usr_fetch_inferior_registers (regcache, regno, 1); + all = regsets_fetch_inferior_registers (regs_info->regsets_info, + regcache); + if ((!use_regsets || all) && regs_info->usrregs != NULL) + usr_fetch_inferior_registers (regs_info, regcache, regno, 1); } } @@ -4431,19 +4449,23 @@ linux_store_registers (struct regcache *regcache, int regno) { int use_regsets; int all = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); if (regno == -1) { - all = regsets_store_inferior_registers (regcache); - usr_store_inferior_registers (regcache, regno, all); + all = regsets_store_inferior_registers (regs_info->regsets_info, + regcache); + if (regs_info->usrregs != NULL) + usr_store_inferior_registers (regs_info, regcache, regno, all); } else { - use_regsets = linux_register_in_regsets (regno); + use_regsets = linux_register_in_regsets (regs_info, regno); if (use_regsets) - all = regsets_store_inferior_registers (regcache); - if (!use_regsets || all) - usr_store_inferior_registers (regcache, regno, 1); + all = regsets_store_inferior_registers (regs_info->regsets_info, + regcache); + if ((!use_regsets || all) && regs_info->usrregs != NULL) + usr_store_inferior_registers (regs_info, regcache, regno, 1); } } @@ -5906,8 +5928,14 @@ linux_low_enable_btrace (ptid_t ptid) struct btrace_target_info *tinfo; tinfo = linux_enable_btrace (ptid); + if (tinfo != NULL) - tinfo->ptr_bits = register_size (0) * 8; + { + struct thread_info *thread = find_thread_ptid (ptid); + struct regcache *regcache = get_thread_regcache (thread, 0); + + tinfo->ptr_bits = register_size (regcache->tdesc, 0) * 8; + } return tinfo; } @@ -6027,6 +6055,18 @@ linux_init_signals () #endif } +#ifdef HAVE_LINUX_REGSETS +void +initialize_regsets_info (struct regsets_info *info) +{ + for (info->num_regsets = 0; + info->regsets[info->num_regsets].size >= 0; + info->num_regsets++) + ; + info->disabled_regsets = xmalloc (info->num_regsets); +} +#endif + void initialize_low (void) { @@ -6038,14 +6078,11 @@ initialize_low (void) linux_init_signals (); linux_test_for_tracefork (); linux_ptrace_init_warnings (); -#ifdef HAVE_LINUX_REGSETS - for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++) - ; - disabled_regsets = xmalloc (num_regsets); -#endif sigchld_action.sa_handler = sigchld_handler; sigemptyset (&sigchld_action.sa_mask); sigchld_action.sa_flags = SA_RESTART; sigaction (SIGCHLD, &sigchld_action, NULL); + + initialize_low_arch (); } diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 4dd3c9c..bce0288 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -46,8 +46,58 @@ struct regset_info regset_fill_func fill_function; regset_store_func store_function; }; -extern struct regset_info target_regsets[]; + +/* Aggregation of all the supported regsets of a given + architecture/mode. */ + +struct regsets_info +{ + /* The regsets array. */ + struct regset_info *regsets; + + /* The number of regsets in the REGSETS array. */ + int num_regsets; + + /* If we get EIO on a regset, do not try it again. Note the set of + supported regsets may depend on processor mode on biarch + machines. */ + char *disabled_regsets; +}; + +#endif + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. */ + +struct usrregs_info +{ + /* The number of registers accessible. */ + int num_regs; + + /* The registers map. */ + int *regmap; +}; + +/* All info needed to access an architecture/mode's registers. */ + +struct regs_info +{ + /* Regset support bitmap: 1 for registers that are transferred as a part + of a regset, 0 for ones that need to be handled individually. This + can be NULL if all registers are transferred with regsets or regsets + are not supported. */ + unsigned char *regset_bitmap; + + /* Info used when accessing registers with PTRACE_PEEKUSER / + PTRACE_POKEUSER. This can be NULL if all registers are + transferred with regsets .*/ + struct usrregs_info *usrregs; + +#ifdef HAVE_LINUX_REGSETS + /* Info used when accessing registers with regsets. */ + struct regsets_info *regsets_info; #endif +}; struct process_info_private { @@ -60,6 +110,11 @@ struct process_info_private /* &_r_debug. 0 if not yet determined. -1 if no PT_DYNAMIC in Phdrs. */ CORE_ADDR r_debug; + + /* This flag is true iff we've just created or attached to the first + LWP of this process but it has not stopped yet. As soon as it + does, we need to call the low target's arch_setup callback. */ + int new_inferior; }; struct lwp_info; @@ -69,14 +124,7 @@ struct linux_target_ops /* Architecture-specific setup. */ void (*arch_setup) (void); - int num_regs; - int *regmap; - - /* Regset support bitmap: 1 for registers that are transferred as a part - of a regset, 0 for ones that need to be handled individually. This - can be NULL if all registers are transferred with regsets or regsets - are not supported. */ - unsigned char *regset_bitmap; + const struct regs_info *(*regs_info) (void); int (*cannot_fetch_register) (int); /* Returns 0 if we can store the register, 1 if we can not @@ -294,6 +342,12 @@ void linux_attach_lwp (unsigned long pid); struct lwp_info *find_lwp_pid (ptid_t ptid); void linux_stop_lwp (struct lwp_info *lwp); +#ifdef HAVE_LINUX_REGSETS +void initialize_regsets_info (struct regsets_info *regsets_info); +#endif + +void initialize_low_arch (void); + /* From thread-db.c */ int thread_db_init (int use_events); void thread_db_detach (struct process_info *); diff --git a/gdb/gdbserver/linux-m32r-low.c b/gdb/gdbserver/linux-m32r-low.c index 58ee646..f8ddd3c 100644 --- a/gdb/gdbserver/linux-m32r-low.c +++ b/gdb/gdbserver/linux-m32r-low.c @@ -25,6 +25,7 @@ /* Defined in auto-generated file reg-m32r.c. */ void init_registers_m32r (void); +extern const struct target_desc *tdesc_m32r; #define m32r_num_regs 25 @@ -87,11 +88,33 @@ m32r_breakpoint_at (CORE_ADDR where) return 0; } +static void +m32r_arch_setup (void) +{ + current_process ()->tdesc = tdesc_m32r; +} + +static struct usrregs_info m32r_usrregs_info = + { + m32r_num_regs, + m32r_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &m32r_usrregs_info, + }; + +static const struct regs_info * +m32r_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_m32r, - m32r_num_regs, - m32r_regmap, - NULL, + m32r_arch_setup, + m32r_regs_info, m32r_cannot_fetch_register, m32r_cannot_store_register, NULL, /* fetch_register */ @@ -103,3 +126,9 @@ struct linux_target_ops the_low_target = { 0, m32r_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + init_registers_m32r (); +} diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c index bc59e3e..9a73a62 100644 --- a/gdb/gdbserver/linux-m68k-low.c +++ b/gdb/gdbserver/linux-m68k-low.c @@ -21,6 +21,7 @@ /* Defined in auto-generated file reg-m68k.c. */ void init_registers_m68k (void); +extern const struct target_desc *tdesc_m68k; #ifdef HAVE_SYS_REG_H #include <sys/reg.h> @@ -109,7 +110,7 @@ m68k_store_fpregset (struct regcache *regcache, const void *buf) #endif /* HAVE_PTRACE_GETREGS */ -struct regset_info target_regsets[] = { +static struct regset_info m68k_regsets[] = { #ifdef HAVE_PTRACE_GETREGS { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), GENERAL_REGS, @@ -174,11 +175,41 @@ ps_get_thread_area (const struct ps_prochandle *ph, } #endif /* PTRACE_GET_THREAD_AREA */ +static struct regsets_info m68k_regsets_info = + { + m68k_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info m68k_usrregs_info = + { + m68k_num_regs, + m68k_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &m68k_usrregs_info, + &m68k_regsets_info + }; + +static const struct regs_info * +m68k_regs_info (void) +{ + return ®s_info; +} + +static void +m68k_arch_setup (void) +{ + current_process ()->tdesc = tdesc_m68k; +} + struct linux_target_ops the_low_target = { - init_registers_m68k, - m68k_num_regs, - m68k_regmap, - NULL, + m68k_arch_setup, + m68k_regs_info, m68k_cannot_fetch_register, m68k_cannot_store_register, NULL, /* fetch_register */ @@ -190,3 +221,12 @@ struct linux_target_ops the_low_target = { 2, m68k_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_m68k (); + + initialize_regsets_info (&m68k_regsets_info); +} diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c index 0cf83be..1010528 100644 --- a/gdb/gdbserver/linux-mips-low.c +++ b/gdb/gdbserver/linux-mips-low.c @@ -26,16 +26,23 @@ /* Defined in auto-generated file mips-linux.c. */ void init_registers_mips_linux (void); +extern const struct target_desc *tdesc_mips_linux; + /* Defined in auto-generated file mips-dsp-linux.c. */ void init_registers_mips_dsp_linux (void); +extern const struct target_desc *tdesc_mips_dsp_linux; + /* Defined in auto-generated file mips64-linux.c. */ void init_registers_mips64_linux (void); +extern const struct target_desc *tdesc_mips64_linux; + /* Defined in auto-generated file mips64-dsp-linux.c. */ void init_registers_mips64_dsp_linux (void); +extern const struct target_desc *tdesc_mips64_dsp_linux; #ifdef __mips64 -#define init_registers_mips_linux init_registers_mips64_linux -#define init_registers_mips_dsp_linux init_registers_mips64_dsp_linux +#define tdesc_mips_linux tdesc_mips64_linux +#define tdesc_mips_dsp_linux tdesc_mips64_dsp_linux #endif #ifndef PTRACE_GET_THREAD_AREA @@ -108,17 +115,15 @@ static unsigned char mips_dsp_regset_bitmap[(mips_dsp_num_regs + 7) / 8] = { 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x80 }; +static int have_dsp = -1; + /* Try peeking at an arbitrarily chosen DSP register and pick the available user register set accordingly. */ -static void -mips_arch_setup (void) +static const struct target_desc * +mips_read_description (void) { - static void (*init_registers) (void); - - gdb_assert (current_inferior); - - if (init_registers == NULL) + if (have_dsp < 0) { int pid = lwpid_of (get_thread_lwp (current_inferior)); @@ -126,23 +131,32 @@ mips_arch_setup (void) switch (errno) { case 0: - the_low_target.num_regs = mips_dsp_num_regs; - the_low_target.regmap = mips_dsp_regmap; - the_low_target.regset_bitmap = mips_dsp_regset_bitmap; - init_registers = init_registers_mips_dsp_linux; + have_dsp = 1; break; case EIO: - the_low_target.num_regs = mips_num_regs; - the_low_target.regmap = mips_regmap; - the_low_target.regset_bitmap = NULL; - init_registers = init_registers_mips_linux; + have_dsp = 0; break; default: perror_with_name ("ptrace"); break; } } - init_registers (); + + return have_dsp ? tdesc_mips_dsp_linux : tdesc_mips_linux; +} + +static void +mips_arch_setup (void) +{ + current_process ()->tdesc = mips_read_description (); +} + +static struct usrregs_info * +get_usrregs_info (void) +{ + const struct regs_info *regs_info = the_low_target.regs_info (); + + return regs_info->usrregs; } /* From mips-linux-nat.c. */ @@ -155,10 +169,14 @@ mips_arch_setup (void) static int mips_cannot_fetch_register (int regno) { - if (the_low_target.regmap[regno] == -1) + const struct target_desc *tdesc; + + if (get_usrregs_info ()->regmap[regno] == -1) return 1; - if (find_regno ("r0") == regno) + tdesc = current_process ()->tdesc; + + if (find_regno (tdesc, "r0") == regno) return 1; return 0; @@ -167,19 +185,23 @@ mips_cannot_fetch_register (int regno) static int mips_cannot_store_register (int regno) { - if (the_low_target.regmap[regno] == -1) + const struct target_desc *tdesc; + + if (get_usrregs_info ()->regmap[regno] == -1) return 1; - if (find_regno ("r0") == regno) + tdesc = current_process ()->tdesc; + + if (find_regno (tdesc, "r0") == regno) return 1; - if (find_regno ("cause") == regno) + if (find_regno (tdesc, "cause") == regno) return 1; - if (find_regno ("badvaddr") == regno) + if (find_regno (tdesc, "badvaddr") == regno) return 1; - if (find_regno ("fir") == regno) + if (find_regno (tdesc, "fir") == regno) return 1; return 0; @@ -190,14 +212,14 @@ mips_get_pc (struct regcache *regcache) { union mips_register pc; collect_register_by_name (regcache, "pc", pc.buf); - return register_size (0) == 4 ? pc.reg32 : pc.reg64; + return register_size (regcache->tdesc, 0) == 4 ? pc.reg32 : pc.reg64; } static void mips_set_pc (struct regcache *regcache, CORE_ADDR pc) { union mips_register newpc; - if (register_size (0) == 4) + if (register_size (regcache->tdesc, 0) == 4) newpc.reg32 = pc; else newpc.reg64 = pc; @@ -218,7 +240,7 @@ mips_reinsert_addr (void) struct regcache *regcache = get_thread_regcache (current_inferior, 1); union mips_register ra; collect_register_by_name (regcache, "r31", ra.buf); - return register_size (0) == 4 ? ra.reg32 : ra.reg64; + return register_size (regcache->tdesc, 0) == 4 ? ra.reg32 : ra.reg64; } static int @@ -315,27 +337,28 @@ mips_fill_gregset (struct regcache *regcache, void *buf) { union mips_register *regset = buf; int i, use_64bit; + const struct target_desc *tdesc = regcache->tdesc; - use_64bit = (register_size (0) == 8); + use_64bit = (register_size (tdesc, 0) == 8); for (i = 1; i < 32; i++) mips_collect_register (regcache, use_64bit, i, regset + i); mips_collect_register (regcache, use_64bit, - find_regno ("lo"), regset + 32); + find_regno (tdesc, "lo"), regset + 32); mips_collect_register (regcache, use_64bit, - find_regno ("hi"), regset + 33); + find_regno (tdesc, "hi"), regset + 33); mips_collect_register (regcache, use_64bit, - find_regno ("pc"), regset + 34); + find_regno (tdesc, "pc"), regset + 34); mips_collect_register (regcache, use_64bit, - find_regno ("badvaddr"), regset + 35); + find_regno (tdesc, "badvaddr"), regset + 35); mips_collect_register (regcache, use_64bit, - find_regno ("status"), regset + 36); + find_regno (tdesc, "status"), regset + 36); mips_collect_register (regcache, use_64bit, - find_regno ("cause"), regset + 37); + find_regno (tdesc, "cause"), regset + 37); mips_collect_register (regcache, use_64bit, - find_regno ("restart"), regset + 0); + find_regno (tdesc, "restart"), regset + 0); } static void @@ -344,23 +367,26 @@ mips_store_gregset (struct regcache *regcache, const void *buf) const union mips_register *regset = buf; int i, use_64bit; - use_64bit = (register_size (0) == 8); + use_64bit = (register_size (regcache->tdesc, 0) == 8); for (i = 0; i < 32; i++) mips_supply_register (regcache, use_64bit, i, regset + i); - mips_supply_register (regcache, use_64bit, find_regno ("lo"), regset + 32); - mips_supply_register (regcache, use_64bit, find_regno ("hi"), regset + 33); - mips_supply_register (regcache, use_64bit, find_regno ("pc"), regset + 34); mips_supply_register (regcache, use_64bit, - find_regno ("badvaddr"), regset + 35); + find_regno (regcache->tdesc, "lo"), regset + 32); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "hi"), regset + 33); mips_supply_register (regcache, use_64bit, - find_regno ("status"), regset + 36); + find_regno (regcache->tdesc, "pc"), regset + 34); mips_supply_register (regcache, use_64bit, - find_regno ("cause"), regset + 37); + find_regno (regcache->tdesc, "badvaddr"), regset + 35); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "status"), regset + 36); + mips_supply_register (regcache, use_64bit, + find_regno (regcache->tdesc, "cause"), regset + 37); mips_supply_register (regcache, use_64bit, - find_regno ("restart"), regset + 0); + find_regno (regcache->tdesc, "restart"), regset + 0); } static void @@ -369,8 +395,8 @@ mips_fill_fpregset (struct regcache *regcache, void *buf) union mips_register *regset = buf; int i, use_64bit, first_fp, big_endian; - use_64bit = (register_size (0) == 8); - first_fp = find_regno ("f0"); + use_64bit = (register_size (regcache->tdesc, 0) == 8); + first_fp = find_regno (regcache->tdesc, "f0"); big_endian = (__BYTE_ORDER == __BIG_ENDIAN); /* See GDB for a discussion of this peculiar layout. */ @@ -382,8 +408,9 @@ mips_fill_fpregset (struct regcache *regcache, void *buf) regset[i & ~1].buf + 4 * (big_endian != (i & 1))); mips_collect_register_32bit (regcache, use_64bit, - find_regno ("fcsr"), regset[32].buf); - mips_collect_register_32bit (regcache, use_64bit, find_regno ("fir"), + find_regno (regcache->tdesc, "fcsr"), regset[32].buf); + mips_collect_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fir"), regset[32].buf + 4); } @@ -393,8 +420,8 @@ mips_store_fpregset (struct regcache *regcache, const void *buf) const union mips_register *regset = buf; int i, use_64bit, first_fp, big_endian; - use_64bit = (register_size (0) == 8); - first_fp = find_regno ("f0"); + use_64bit = (register_size (regcache->tdesc, 0) == 8); + first_fp = find_regno (regcache->tdesc, "f0"); big_endian = (__BYTE_ORDER == __BIG_ENDIAN); /* See GDB for a discussion of this peculiar layout. */ @@ -406,13 +433,15 @@ mips_store_fpregset (struct regcache *regcache, const void *buf) regset[i & ~1].buf + 4 * (big_endian != (i & 1))); mips_supply_register_32bit (regcache, use_64bit, - find_regno ("fcsr"), regset[32].buf); - mips_supply_register_32bit (regcache, use_64bit, find_regno ("fir"), + find_regno (regcache->tdesc, "fcsr"), + regset[32].buf); + mips_supply_register_32bit (regcache, use_64bit, + find_regno (regcache->tdesc, "fir"), regset[32].buf + 4); } #endif /* HAVE_PTRACE_GETREGS */ -struct regset_info target_regsets[] = { +static struct regset_info mips_regsets[] = { #ifdef HAVE_PTRACE_GETREGS { PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS, mips_fill_gregset, mips_store_gregset }, @@ -422,11 +451,51 @@ struct regset_info target_regsets[] = { { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info mips_regsets_info = + { + mips_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info mips_dsp_usrregs_info = + { + mips_dsp_num_regs, + mips_dsp_regmap, + }; + +static struct usrregs_info mips_usrregs_info = + { + mips_num_regs, + mips_regmap, + }; + +static struct regs_info dsp_regs_info = + { + mips_dsp_regset_bitmap, + &mips_dsp_usrregs_info, + &mips_regsets_info + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &mips_usrregs_info, + &mips_regsets_info + }; + +static const struct regs_info * +mips_regs_info (void) +{ + if (have_dsp) + return &dsp_regs_info; + else + return ®s_info; +} + struct linux_target_ops the_low_target = { mips_arch_setup, - -1, - NULL, - NULL, + mips_regs_info, mips_cannot_fetch_register, mips_cannot_store_register, NULL, /* fetch_register */ @@ -438,3 +507,15 @@ struct linux_target_ops the_low_target = { 0, mips_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_mips_linux (); + init_registers_mips_dsp_linux (); + init_registers_mips64_linux (); + init_registers_mips64_dsp_linux (); + + initialize_regsets_info (&mips_regsets_info); +} diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c index c41579f..8d97864 100644 --- a/gdb/gdbserver/linux-nios2-low.c +++ b/gdb/gdbserver/linux-nios2-low.c @@ -40,6 +40,7 @@ /* Defined in auto-generated file nios2-linux.c. */ void init_registers_nios2_linux (void); +extern const struct target_desc *tdesc_nios2_linux; /* This union is used to convert between int and byte buffer representations of register contents. */ @@ -68,7 +69,7 @@ static int nios2_regmap[] = { static void nios2_arch_setup (void) { - init_registers_nios2_linux (); + current_process ()->tdesc = tdesc_nios2_linux; } /* Implement the cannot_fetch_register linux_target_ops method. */ @@ -206,7 +207,7 @@ nios2_store_gregset (struct regcache *regcache, const void *buf) } #endif /* HAVE_PTRACE_GETREGS */ -struct regset_info target_regsets[] = +static struct regset_info nios2_regsets[] = { #ifdef HAVE_PTRACE_GETREGS { PTRACE_GETREGS, PTRACE_SETREGS, 0, nios2_num_regs * 4, GENERAL_REGS, @@ -215,12 +216,36 @@ struct regset_info target_regsets[] = { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info nios2_regsets_info = + { + nios2_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info nios2_usrregs_info = + { + nios2_num_regs, + nios2_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &nios2_usrregs_info, + &nios2_regsets_info + }; + +static const struct regs_info * +nios2_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { nios2_arch_setup, - nios2_num_regs, - nios2_regmap, - NULL, + nios2_regs_info, nios2_cannot_fetch_register, nios2_cannot_store_register, NULL, @@ -232,3 +257,11 @@ struct linux_target_ops the_low_target = 0, nios2_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + init_registers_nios2_linux (); + + initialize_regsets_info (&nios2_regsets_info); +} diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c index 1c81c79..aed1749 100644 --- a/gdb/gdbserver/linux-ppc-low.c +++ b/gdb/gdbserver/linux-ppc-low.c @@ -35,34 +35,63 @@ static unsigned long ppc_hwcap; /* Defined in auto-generated file powerpc-32l.c. */ void init_registers_powerpc_32l (void); +extern const struct target_desc *tdesc_powerpc_32l; + /* Defined in auto-generated file powerpc-altivec32l.c. */ void init_registers_powerpc_altivec32l (void); +extern const struct target_desc *tdesc_powerpc_altivec32l; + /* Defined in auto-generated file powerpc-cell32l.c. */ void init_registers_powerpc_cell32l (void); +extern const struct target_desc *tdesc_powerpc_cell32l; + /* Defined in auto-generated file powerpc-vsx32l.c. */ void init_registers_powerpc_vsx32l (void); +extern const struct target_desc *tdesc_powerpc_vsx32l; + /* Defined in auto-generated file powerpc-isa205-32l.c. */ void init_registers_powerpc_isa205_32l (void); +extern const struct target_desc *tdesc_powerpc_isa205_32l; + /* Defined in auto-generated file powerpc-isa205-altivec32l.c. */ void init_registers_powerpc_isa205_altivec32l (void); +extern const struct target_desc *tdesc_powerpc_isa205_altivec32l; + /* Defined in auto-generated file powerpc-isa205-vsx32l.c. */ void init_registers_powerpc_isa205_vsx32l (void); +extern const struct target_desc *tdesc_powerpc_isa205_vsx32l; + /* Defined in auto-generated file powerpc-e500l.c. */ void init_registers_powerpc_e500l (void); +extern const struct target_desc *tdesc_powerpc_e500l; + /* Defined in auto-generated file powerpc-64l.c. */ void init_registers_powerpc_64l (void); +extern const struct target_desc *tdesc_powerpc_64l; + /* Defined in auto-generated file powerpc-altivec64l.c. */ void init_registers_powerpc_altivec64l (void); +extern const struct target_desc *tdesc_powerpc_altivec64l; + /* Defined in auto-generated file powerpc-cell64l.c. */ void init_registers_powerpc_cell64l (void); +extern const struct target_desc *tdesc_powerpc_cell64l; + /* Defined in auto-generated file powerpc-vsx64l.c. */ void init_registers_powerpc_vsx64l (void); +extern const struct target_desc *tdesc_powerpc_vsx64l; + /* Defined in auto-generated file powerpc-isa205-64l.c. */ void init_registers_powerpc_isa205_64l (void); +extern const struct target_desc *tdesc_powerpc_isa205_64l; + /* Defined in auto-generated file powerpc-isa205-altivec64l.c. */ void init_registers_powerpc_isa205_altivec64l (void); +extern const struct target_desc *tdesc_powerpc_isa205_altivec64l; + /* Defined in auto-generated file powerpc-isa205-vsx64l.c. */ void init_registers_powerpc_isa205_vsx64l (void); +extern const struct target_desc *tdesc_powerpc_isa205_vsx64l; #define ppc_num_regs 73 @@ -147,15 +176,18 @@ static int ppc_regmap_e500[] = static int ppc_cannot_store_register (int regno) { + const struct target_desc *tdesc = current_process ()->tdesc; + #ifndef __powerpc64__ /* Some kernels do not allow us to store fpscr. */ - if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE) && regno == find_regno ("fpscr")) + if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE) + && regno == find_regno (tdesc, "fpscr")) return 2; #endif /* Some kernels do not allow us to store orig_r3 or trap. */ - if (regno == find_regno ("orig_r3") - || regno == find_regno ("trap")) + if (regno == find_regno (tdesc, "orig_r3") + || regno == find_regno (tdesc, "trap")) return 2; return 0; @@ -170,7 +202,7 @@ ppc_cannot_fetch_register (int regno) static void ppc_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) { - int size = register_size (regno); + int size = register_size (regcache->tdesc, regno); memset (buf, 0, sizeof (long)); @@ -184,7 +216,7 @@ static void ppc_supply_ptrace_register (struct regcache *regcache, int regno, const char *buf) { - int size = register_size (regno); + int size = register_size (regcache->tdesc, regno); if (size < sizeof (long)) supply_register (regcache, regno, buf + sizeof (long) - size); else @@ -205,7 +237,7 @@ parse_spufs_run (struct regcache *regcache, int *fd, CORE_ADDR *addr) int curr_insn; int curr_r0; - if (register_size (0) == 4) + if (register_size (regcache->tdesc, 0) == 4) { unsigned int pc, r0, r3, r4; collect_register_by_name (regcache, "pc", &pc); @@ -257,7 +289,7 @@ ppc_get_pc (struct regcache *regcache) return ((CORE_ADDR)1 << 63) | ((CORE_ADDR)fd << 32) | (CORE_ADDR) (pc - 4); } - else if (register_size (0) == 4) + else if (register_size (regcache->tdesc, 0) == 4) { unsigned int pc; collect_register_by_name (regcache, "pc", &pc); @@ -282,7 +314,7 @@ ppc_set_pc (struct regcache *regcache, CORE_ADDR pc) unsigned int newpc = pc; (*the_target->write_memory) (addr, (unsigned char *) &newpc, 4); } - else if (register_size (0) == 4) + else if (register_size (regcache->tdesc, 0) == 4) { unsigned int newpc = pc; supply_register_by_name (regcache, "pc", &newpc); @@ -298,7 +330,8 @@ ppc_set_pc (struct regcache *regcache, CORE_ADDR pc) static int ppc_get_hwcap (unsigned long *valp) { - int wordsize = register_size (0); + const struct target_desc *tdesc = current_process ()->tdesc; + int wordsize = register_size (tdesc, 0); unsigned char *data = alloca (2 * wordsize); int offset = 0; @@ -330,9 +363,16 @@ ppc_get_hwcap (unsigned long *valp) return 0; } +/* Forward declaration. */ +static struct usrregs_info ppc_usrregs_info; +#ifndef __powerpc64__ +static int ppc_regmap_adjusted; +#endif + static void ppc_arch_setup (void) { + const struct target_desc *tdesc; #ifdef __powerpc64__ long msr; struct regcache *regcache; @@ -340,20 +380,21 @@ ppc_arch_setup (void) /* On a 64-bit host, assume 64-bit inferior process with no AltiVec registers. Reset ppc_hwcap to ensure that the collect_register call below does not fail. */ - init_registers_powerpc_64l (); + tdesc = tdesc_powerpc_64l; + current_process ()->tdesc = tdesc; ppc_hwcap = 0; /* Only if the high bit of the MSR is set, we actually have a 64-bit inferior. */ - regcache = new_register_cache (); - fetch_inferior_registers (regcache, find_regno ("msr")); + regcache = new_register_cache (tdesc); + fetch_inferior_registers (regcache, find_regno (tdesc, "msr")); collect_register_by_name (regcache, "msr", &msr); free_register_cache (regcache); if (msr < 0) { ppc_get_hwcap (&ppc_hwcap); if (ppc_hwcap & PPC_FEATURE_CELL) - init_registers_powerpc_cell64l (); + tdesc = tdesc_powerpc_cell64l; else if (ppc_hwcap & PPC_FEATURE_HAS_VSX) { /* Power ISA 2.05 (implemented by Power 6 and newer processors) @@ -364,59 +405,67 @@ ppc_arch_setup (void) Point, we check if that feature is available to decide the size of the FPSCR. */ if (ppc_hwcap & PPC_FEATURE_HAS_DFP) - init_registers_powerpc_isa205_vsx64l (); + tdesc = tdesc_powerpc_isa205_vsx64l; else - init_registers_powerpc_vsx64l (); + tdesc = tdesc_powerpc_vsx64l; } else if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) { if (ppc_hwcap & PPC_FEATURE_HAS_DFP) - init_registers_powerpc_isa205_altivec64l (); + tdesc = tdesc_powerpc_isa205_altivec64l; else - init_registers_powerpc_altivec64l (); + tdesc = tdesc_powerpc_altivec64l; } + current_process ()->tdesc = tdesc; return; } #endif /* OK, we have a 32-bit inferior. */ - init_registers_powerpc_32l (); + tdesc = tdesc_powerpc_32l; + current_process ()->tdesc = tdesc; ppc_get_hwcap (&ppc_hwcap); if (ppc_hwcap & PPC_FEATURE_CELL) - init_registers_powerpc_cell32l (); + tdesc = tdesc_powerpc_cell32l; else if (ppc_hwcap & PPC_FEATURE_HAS_VSX) { if (ppc_hwcap & PPC_FEATURE_HAS_DFP) - init_registers_powerpc_isa205_vsx32l (); + tdesc = tdesc_powerpc_isa205_vsx32l; else - init_registers_powerpc_vsx32l (); + tdesc = tdesc_powerpc_vsx32l; } else if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) { if (ppc_hwcap & PPC_FEATURE_HAS_DFP) - init_registers_powerpc_isa205_altivec32l (); + tdesc = tdesc_powerpc_isa205_altivec32l; else - init_registers_powerpc_altivec32l (); + tdesc = tdesc_powerpc_altivec32l; } /* On 32-bit machines, check for SPE registers. Set the low target's regmap field as appropriately. */ #ifndef __powerpc64__ - the_low_target.regmap = ppc_regmap; if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + tdesc = tdesc_powerpc_e500l; + + if (!ppc_regmap_adjusted) { - init_registers_powerpc_e500l (); - the_low_target.regmap = ppc_regmap_e500; - } + if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + ppc_usrregs_info.regmap = ppc_regmap_e500; - /* If the FPSCR is 64-bit wide, we need to fetch the whole 64-bit - slot and not just its second word. The PT_FPSCR supplied in a - 32-bit GDB compilation doesn't reflect this. */ - if (register_size (70) == 8) - ppc_regmap[70] = (48 + 2*32) * sizeof (long); + /* If the FPSCR is 64-bit wide, we need to fetch the whole + 64-bit slot and not just its second word. The PT_FPSCR + supplied in a 32-bit GDB compilation doesn't reflect + this. */ + if (register_size (tdesc, 70) == 8) + ppc_regmap[70] = (48 + 2*32) * sizeof (long); + + ppc_regmap_adjusted = 1; + } #endif + current_process ()->tdesc = tdesc; } /* Correct in either endianness. @@ -484,7 +533,7 @@ ppc_fill_vsxregset (struct regcache *regcache, void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_VSX)) return; - base = find_regno ("vs0h"); + base = find_regno (regcache->tdesc, "vs0h"); for (i = 0; i < 32; i++) collect_register (regcache, base + i, ®set[i * 8]); } @@ -498,7 +547,7 @@ ppc_store_vsxregset (struct regcache *regcache, const void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_VSX)) return; - base = find_regno ("vs0h"); + base = find_regno (regcache->tdesc, "vs0h"); for (i = 0; i < 32; i++) supply_register (regcache, base + i, ®set[i * 8]); } @@ -519,7 +568,7 @@ ppc_fill_vrregset (struct regcache *regcache, void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)) return; - base = find_regno ("vr0"); + base = find_regno (regcache->tdesc, "vr0"); for (i = 0; i < 32; i++) collect_register (regcache, base + i, ®set[i * 16]); @@ -536,7 +585,7 @@ ppc_store_vrregset (struct regcache *regcache, const void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)) return; - base = find_regno ("vr0"); + base = find_regno (regcache->tdesc, "vr0"); for (i = 0; i < 32; i++) supply_register (regcache, base + i, ®set[i * 16]); @@ -565,7 +614,7 @@ ppc_fill_evrregset (struct regcache *regcache, void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE)) return; - ev0 = find_regno ("ev0h"); + ev0 = find_regno (regcache->tdesc, "ev0h"); for (i = 0; i < 32; i++) collect_register (regcache, ev0 + i, ®set->evr[i]); @@ -582,7 +631,7 @@ ppc_store_evrregset (struct regcache *regcache, const void *buf) if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE)) return; - ev0 = find_regno ("ev0h"); + ev0 = find_regno (regcache->tdesc, "ev0h"); for (i = 0; i < 32; i++) supply_register (regcache, ev0 + i, ®set->evr[i]); @@ -590,7 +639,7 @@ ppc_store_evrregset (struct regcache *regcache, const void *buf) supply_register_by_name (regcache, "spefscr", ®set->spefscr); } -struct regset_info target_regsets[] = { +static struct regset_info ppc_regsets[] = { /* List the extra register sets before GENERAL_REGS. That way we will fetch them every time, but still fall back to PTRACE_PEEKUSER for the general registers. Some kernels support these, but not the newer @@ -605,11 +654,35 @@ struct regset_info target_regsets[] = { { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct usrregs_info ppc_usrregs_info = + { + ppc_num_regs, + ppc_regmap, + }; + +static struct regsets_info ppc_regsets_info = + { + ppc_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &ppc_usrregs_info, + &ppc_regsets_info + }; + +static const struct regs_info * +ppc_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { ppc_arch_setup, - ppc_num_regs, - ppc_regmap, - NULL, + ppc_regs_info, ppc_cannot_fetch_register, ppc_cannot_store_register, NULL, /* fetch_register */ @@ -627,3 +700,27 @@ struct linux_target_ops the_low_target = { ppc_collect_ptrace_register, ppc_supply_ptrace_register, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + + init_registers_powerpc_32l (); + init_registers_powerpc_altivec32l (); + init_registers_powerpc_cell32l (); + init_registers_powerpc_vsx32l (); + init_registers_powerpc_isa205_32l (); + init_registers_powerpc_isa205_altivec32l (); + init_registers_powerpc_isa205_vsx32l (); + init_registers_powerpc_e500l (); + init_registers_powerpc_64l (); + init_registers_powerpc_altivec64l (); + init_registers_powerpc_cell64l (); + init_registers_powerpc_vsx64l (); + init_registers_powerpc_isa205_64l (); + init_registers_powerpc_isa205_altivec64l (); + init_registers_powerpc_isa205_vsx64l (); + + initialize_regsets_info (&ppc_regsets_info); +} diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c index 5d9fb80..18d6370 100644 --- a/gdb/gdbserver/linux-s390-low.c +++ b/gdb/gdbserver/linux-s390-low.c @@ -42,22 +42,39 @@ /* Defined in auto-generated file s390-linux32.c. */ void init_registers_s390_linux32 (void); +extern const struct target_desc *tdesc_s390_linux32; + /* Defined in auto-generated file s390-linux32v1.c. */ void init_registers_s390_linux32v1 (void); +extern const struct target_desc *tdesc_s390_linux32v1; + /* Defined in auto-generated file s390-linux32v2.c. */ void init_registers_s390_linux32v2 (void); +extern const struct target_desc *tdesc_s390_linux32v2; + /* Defined in auto-generated file s390-linux64.c. */ void init_registers_s390_linux64 (void); +extern const struct target_desc *tdesc_s390_linux64; + /* Defined in auto-generated file s390-linux64v1.c. */ void init_registers_s390_linux64v1 (void); +extern const struct target_desc *tdesc_s390_linux64v1; + /* Defined in auto-generated file s390-linux64v2.c. */ void init_registers_s390_linux64v2 (void); +extern const struct target_desc *tdesc_s390_linux64v2; + /* Defined in auto-generated file s390x-linux64.c. */ void init_registers_s390x_linux64 (void); +extern const struct target_desc *tdesc_s390x_linux64; + /* Defined in auto-generated file s390x-linux64v1.c. */ void init_registers_s390x_linux64v1 (void); +extern const struct target_desc *tdesc_s390x_linux64v1; + /* Defined in auto-generated file s390x-linux64v2.c. */ void init_registers_s390x_linux64v2 (void); +extern const struct target_desc *tdesc_s390x_linux64v2; #define s390_num_regs 52 @@ -138,15 +155,17 @@ s390_cannot_store_register (int regno) static void s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) { - int size = register_size (regno); + int size = register_size (regcache->tdesc, regno); if (size < sizeof (long)) { - int regaddr = the_low_target.regmap[regno]; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; + int regaddr = usr->regmap[regno]; memset (buf, 0, sizeof (long)); - if ((regno ^ 1) < the_low_target.num_regs - && the_low_target.regmap[regno ^ 1] == regaddr) + if ((regno ^ 1) < usr->num_regs + && usr->regmap[regno ^ 1] == regaddr) { collect_register (regcache, regno & ~1, buf); collect_register (regcache, (regno & ~1) + 1, @@ -156,7 +175,7 @@ s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) { /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying the basic addressing mode bit from the PSW address. */ - char *addr = alloca (register_size (regno ^ 1)); + char *addr = alloca (register_size (regcache->tdesc, regno ^ 1)); collect_register (regcache, regno, buf); collect_register (regcache, regno ^ 1, addr); buf[1] &= ~0x8; @@ -183,13 +202,15 @@ static void s390_supply_ptrace_register (struct regcache *regcache, int regno, const char *buf) { - int size = register_size (regno); + int size = register_size (regcache->tdesc, regno); if (size < sizeof (long)) { - int regaddr = the_low_target.regmap[regno]; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; + int regaddr = usr->regmap[regno]; - if ((regno ^ 1) < the_low_target.num_regs - && the_low_target.regmap[regno ^ 1] == regaddr) + if ((regno ^ 1) < usr->num_regs + && usr->regmap[regno ^ 1] == regaddr) { supply_register (regcache, regno & ~1, buf); supply_register (regcache, (regno & ~1) + 1, @@ -200,7 +221,7 @@ s390_supply_ptrace_register (struct regcache *regcache, /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying the basic addressing mode into the PSW address. */ char *mask = alloca (size); - char *addr = alloca (register_size (regno ^ 1)); + char *addr = alloca (register_size (regcache->tdesc, regno ^ 1)); memcpy (mask, buf, size); mask[1] |= 0x8; supply_register (regcache, regno, mask); @@ -236,18 +257,21 @@ s390_supply_ptrace_register (struct regcache *regcache, /* Provide only a fill function for the general register set. ps_lgetregs will use this for NPTL support. */ -static void s390_fill_gregset (struct regcache *regcache, void *buf) +static void +s390_fill_gregset (struct regcache *regcache, void *buf) { int i; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct usrregs_info *usr = regs_info->usrregs; - for (i = 0; i < the_low_target.num_regs; i++) + for (i = 0; i < usr->num_regs; i++) { - if (the_low_target.regmap[i] < PT_PSWMASK - || the_low_target.regmap[i] > PT_ACR15) + if (usr->regmap[i] < PT_PSWMASK + || usr->regmap[i] > PT_ACR15) continue; - s390_collect_ptrace_register (regcache, i, (char *) buf - + the_low_target.regmap[i]); + s390_collect_ptrace_register (regcache, i, + (char *) buf + usr->regmap[i]); } } @@ -262,8 +286,10 @@ s390_fill_last_break (struct regcache *regcache, void *buf) static void s390_store_last_break (struct regcache *regcache, const void *buf) { - supply_register_by_name (regcache, "last_break", - (const char *)buf + 8 - register_size (0)); + const char *p; + + p = (const char *) buf + 8 - register_size (regcache->tdesc, 0); + supply_register_by_name (regcache, "last_break", p); } static void @@ -278,7 +304,7 @@ s390_store_system_call (struct regcache *regcache, const void *buf) supply_register_by_name (regcache, "system_call", buf); } -struct regset_info target_regsets[] = { +static struct regset_info s390_regsets[] = { { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL }, /* Last break address is read-only; do not attempt PTRACE_SETREGSET. */ { PTRACE_GETREGSET, PTRACE_GETREGSET, NT_S390_LAST_BREAK, 0, @@ -295,7 +321,7 @@ static const unsigned char s390_breakpoint[] = { 0, 1 }; static CORE_ADDR s390_get_pc (struct regcache *regcache) { - if (register_size (0) == 4) + if (register_size (regcache->tdesc, 0) == 4) { unsigned int pswa; collect_register_by_name (regcache, "pswa", &pswa); @@ -312,7 +338,7 @@ s390_get_pc (struct regcache *regcache) static void s390_set_pc (struct regcache *regcache, CORE_ADDR newpc) { - if (register_size (0) == 4) + if (register_size (regcache->tdesc, 0) == 4) { unsigned int pswa; collect_register_by_name (regcache, "pswa", &pswa); @@ -328,9 +354,9 @@ s390_set_pc (struct regcache *regcache, CORE_ADDR newpc) #ifdef __s390x__ static unsigned long -s390_get_hwcap (void) +s390_get_hwcap (const struct target_desc *tdesc) { - int wordsize = register_size (0); + int wordsize = register_size (tdesc, 0); unsigned char *data = alloca (2 * wordsize); int offset = 0; @@ -371,9 +397,16 @@ s390_check_regset (int pid, int regset, int regsize) return 1; } +#ifdef __s390x__ +/* For a 31-bit inferior, whether the kernel supports using the full + 64-bit GPRs. */ +static int have_hwcap_s390_high_gprs = 0; +#endif + static void s390_arch_setup (void) { + const struct target_desc *tdesc; struct regset_info *regset; /* Check whether the kernel supports extra register sets. */ @@ -384,7 +417,7 @@ s390_arch_setup (void) = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4); /* Update target_regsets according to available register sets. */ - for (regset = target_regsets; regset->fill_function != NULL; regset++) + for (regset = s390_regsets; regset->fill_function != NULL; regset++) if (regset->get_request == PTRACE_GETREGSET) switch (regset->nt_type) { @@ -400,51 +433,48 @@ s390_arch_setup (void) /* Assume 31-bit inferior process. */ if (have_regset_system_call) - init_registers_s390_linux32v2 (); + tdesc = tdesc_s390_linux32v2; else if (have_regset_last_break) - init_registers_s390_linux32v1 (); + tdesc = tdesc_s390_linux32v1; else - init_registers_s390_linux32 (); - - the_low_target.num_regs = s390_num_regs; - the_low_target.regmap = s390_regmap; + tdesc = tdesc_s390_linux32; /* On a 64-bit host, check the low bit of the (31-bit) PSWM -- if this is one, we actually have a 64-bit inferior. */ #ifdef __s390x__ { unsigned int pswm; - struct regcache *regcache = new_register_cache (); - fetch_inferior_registers (regcache, find_regno ("pswm")); + struct regcache *regcache = new_register_cache (tdesc); + fetch_inferior_registers (regcache, find_regno (tdesc, "pswm")); collect_register_by_name (regcache, "pswm", &pswm); free_register_cache (regcache); if (pswm & 1) { if (have_regset_system_call) - init_registers_s390x_linux64v2 (); + tdesc = tdesc_s390x_linux64v2; else if (have_regset_last_break) - init_registers_s390x_linux64v1 (); + tdesc = tdesc_s390x_linux64v1; else - init_registers_s390x_linux64 (); + tdesc = tdesc_s390x_linux64; } /* For a 31-bit inferior, check whether the kernel supports using the full 64-bit GPRs. */ - else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) + else if (s390_get_hwcap (tdesc) & HWCAP_S390_HIGH_GPRS) { + have_hwcap_s390_high_gprs = 1; + if (have_regset_system_call) - init_registers_s390_linux64v2 (); + tdesc = tdesc_s390_linux64v2; else if (have_regset_last_break) - init_registers_s390_linux64v1 (); + tdesc = tdesc_s390_linux64v1; else - init_registers_s390_linux64 (); - - the_low_target.num_regs = s390_num_regs_3264; - the_low_target.regmap = s390_regmap_3264; + tdesc = tdesc_s390_linux64; } } #endif + current_process ()->tdesc = tdesc; } @@ -456,12 +486,66 @@ s390_breakpoint_at (CORE_ADDR pc) return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0; } +static struct usrregs_info s390_usrregs_info = + { + s390_num_regs, + s390_regmap, + }; + +static struct regsets_info s390_regsets_info = + { + s390_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &s390_usrregs_info, + &s390_regsets_info + }; + +#ifdef __s390x__ +static struct usrregs_info s390_usrregs_info_3264 = + { + s390_num_regs_3264, + s390_regmap_3264 + }; + +static struct regsets_info s390_regsets_info_3264 = + { + s390_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info_3264 = + { + NULL, /* regset_bitmap */ + &s390_usrregs_info_3264, + &s390_regsets_info_3264 + }; +#endif + +static const struct regs_info * +s390_regs_info (void) +{ +#ifdef __s390x__ + if (have_hwcap_s390_high_gprs) + { + const struct target_desc *tdesc = current_process ()->tdesc; + + if (register_size (tdesc, 0) == 4) + return ®s_info_3264; + } +#endif + return ®s_info; +} struct linux_target_ops the_low_target = { s390_arch_setup, - s390_num_regs, - s390_regmap, - NULL, + s390_regs_info, s390_cannot_fetch_register, s390_cannot_store_register, NULL, /* fetch_register */ @@ -479,3 +563,24 @@ struct linux_target_ops the_low_target = { s390_collect_ptrace_register, s390_supply_ptrace_register, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + + init_registers_s390_linux32 (); + init_registers_s390_linux32v1 (); + init_registers_s390_linux32v2 (); + init_registers_s390_linux64 (); + init_registers_s390_linux64v1 (); + init_registers_s390_linux64v2 (); + init_registers_s390x_linux64 (); + init_registers_s390x_linux64v1 (); + init_registers_s390x_linux64v2 (); + + initialize_regsets_info (&s390_regsets_info); +#ifdef __s390x__ + initialize_regsets_info (&s390_regsets_info_3264); +#endif +} diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c index f268b55..e582a2b 100644 --- a/gdb/gdbserver/linux-sh-low.c +++ b/gdb/gdbserver/linux-sh-low.c @@ -21,6 +21,7 @@ /* Defined in auto-generated file reg-sh.c. */ void init_registers_sh (void); +extern const struct target_desc *tdesc_sh; #ifdef HAVE_SYS_REG_H #include <sys/reg.h> @@ -102,16 +103,46 @@ static void sh_fill_gregset (struct regcache *regcache, void *buf) collect_register (regcache, i, (char *) buf + sh_regmap[i]); } -struct regset_info target_regsets[] = { +static struct regset_info sh_regsets[] = { { 0, 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL }, { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info sh_regsets_info = + { + sh_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info sh_usrregs_info = + { + sh_num_regs, + sh_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &sh_usrregs_info, + &sh_regsets_info + }; + +static const struct regs_info * +sh_regs_info (void) +{ + return ®s_info; +} + +static void +sh_arch_setup (void) +{ + current_process ()->tdesc = tdesc_sh; +} + struct linux_target_ops the_low_target = { - init_registers_sh, - sh_num_regs, - sh_regmap, - NULL, + sh_arch_setup, + sh_regs_info, sh_cannot_fetch_register, sh_cannot_store_register, NULL, /* fetch_register */ @@ -123,3 +154,11 @@ struct linux_target_ops the_low_target = { 0, sh_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + init_registers_sh (); + + initialize_regsets_info (&sh_regsets_info); +} diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c index 32590b2..444d446 100644 --- a/gdb/gdbserver/linux-sparc-low.c +++ b/gdb/gdbserver/linux-sparc-low.c @@ -100,6 +100,7 @@ static const struct regs_range_t fpregs_ranges[] = { /* Defined in auto-generated file reg-sparc64.c. */ void init_registers_sparc64 (void); +extern const struct target_desc *tdesc_sparc64; static int sparc_cannot_store_register (int regno) @@ -119,12 +120,12 @@ sparc_fill_gregset_to_stack (struct regcache *regcache, const void *buf) int i; CORE_ADDR addr = 0; unsigned char tmp_reg_buf[8]; - const int l0_regno = find_regno ("l0"); + const int l0_regno = find_regno (regcache->tdesc, "l0"); const int i7_regno = l0_regno + 15; /* These registers have to be stored in the stack. */ memcpy (&addr, - ((char *) buf) + sparc_regmap[find_regno ("sp")], + ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], sizeof (addr)); addr += BIAS; @@ -171,12 +172,12 @@ sparc_store_gregset_from_stack (struct regcache *regcache, const void *buf) int i; CORE_ADDR addr = 0; unsigned char tmp_reg_buf[8]; - const int l0_regno = find_regno ("l0"); + const int l0_regno = find_regno (regcache->tdesc, "l0"); const int i7_regno = l0_regno + 15; /* These registers have to be obtained from the stack. */ memcpy (&addr, - ((char *) buf) + sparc_regmap[find_regno ("sp")], + ((char *) buf) + sparc_regmap[find_regno (regcache->tdesc, "sp")], sizeof (addr)); addr += BIAS; @@ -269,8 +270,13 @@ sparc_reinsert_addr (void) return lr; } +static void +sparc_arch_setup (void) +{ + current_process ()->tdesc = tdesc_sparc64; +} -struct regset_info target_regsets[] = { +static struct regset_info sparc_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), GENERAL_REGS, sparc_fill_gregset, sparc_store_gregset }, @@ -280,12 +286,37 @@ struct regset_info target_regsets[] = { { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info sparc_regsets_info = + { + sparc_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info sparc_usrregs_info = + { + sparc_num_regs, + /* No regmap needs to be provided since this impl. doesn't use + USRREGS. */ + NULL + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &sparc_usrregs_info, + &sparc_regsets_info + }; + +static const struct regs_info * +sparc_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_sparc64, - sparc_num_regs, - /* No regmap needs to be provided since this impl. doesn't use USRREGS. */ - NULL, - NULL, + sparc_arch_setup, + sparc_regs_info, sparc_cannot_fetch_register, sparc_cannot_store_register, NULL, /* fetch_register */ @@ -300,3 +331,12 @@ struct linux_target_ops the_low_target = { NULL, NULL, NULL, NULL, NULL, NULL }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_sparc64 (); + + initialize_regsets_info (&sparc_regsets_info); +} diff --git a/gdb/gdbserver/linux-tic6x-low.c b/gdb/gdbserver/linux-tic6x-low.c index 93a1e65..2367dea 100644 --- a/gdb/gdbserver/linux-tic6x-low.c +++ b/gdb/gdbserver/linux-tic6x-low.c @@ -38,10 +38,15 @@ /* Defined in auto-generated file tic6x-c64xp-linux.c. */ void init_registers_tic6x_c64xp_linux (void); +extern const struct target_desc *tdesc_tic6x_c64xp_linux; + /* Defined in auto-generated file tic6x-c64x-linux.c. */ void init_registers_tic6x_c64x_linux (void); +extern const struct target_desc *tdesc_tic6x_c64x_linux; + /* Defined in auto-generated file tic62x-c6xp-linux.c. */ void init_registers_tic6x_c62x_linux (void); +extern const struct target_desc *tdesc_tic6x_c62x_linux; union tic6x_register { @@ -167,11 +172,15 @@ extern struct linux_target_ops the_low_target; static int *tic6x_regmap; static unsigned int tic6x_breakpoint; -static void -tic6x_arch_setup (void) +/* Forward definition. */ +static struct usrregs_info tic6x_usrregs_info; + +static const struct target_desc * +tic6x_read_description (void) { register unsigned int csr asm ("B2"); unsigned int cpuid; + const struct target_desc *tdesc; /* Determine the CPU we're running on to find the register order. */ __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :); @@ -182,29 +191,30 @@ tic6x_arch_setup (void) case 0x02: /* C67x */ tic6x_regmap = tic6x_regmap_c62x; tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - init_registers_tic6x_c62x_linux (); + tdesc = tdesc_tic6x_c62x_linux; break; case 0x03: /* C67x+ */ tic6x_regmap = tic6x_regmap_c64x; tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - init_registers_tic6x_c64x_linux (); + tdesc = tdesc_tic6x_c64x_linux; break; case 0x0c: /* C64x */ tic6x_regmap = tic6x_regmap_c64x; tic6x_breakpoint = 0x0000a122; /* BNOP .S2 0,5 */ - init_registers_tic6x_c64x_linux (); + tdesc = tdesc_tic6x_c64x_linux; break; case 0x10: /* C64x+ */ case 0x14: /* C674x */ case 0x15: /* C66x */ tic6x_regmap = tic6x_regmap_c64xp; tic6x_breakpoint = 0x56454314; /* illegal opcode */ - init_registers_tic6x_c64xp_linux (); + tdesc = tdesc_tic6x_c64xp_linux; break; default: error ("Unknown CPU ID 0x%02x", cpuid); } - the_low_target.regmap = tic6x_regmap; + tic6x_usrregs_info.regmap = tic6x_regmap; + return tdesc; } static int @@ -311,17 +321,47 @@ tic6x_store_gregset (struct regcache *regcache, const void *buf) tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]); } -struct regset_info target_regsets[] = { +static struct regset_info tic6x_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS, tic6x_fill_gregset, tic6x_store_gregset }, { 0, 0, 0, -1, -1, NULL, NULL } }; +static void +tic6x_arch_setup (void) +{ + current_process ()->tdesc = tic6x_read_description (); +} + +static struct regsets_info tic6x_regsets_info = + { + tic6x_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info tic6x_usrregs_info = + { + TIC6X_NUM_REGS, + NULL, /* Set in tic6x_read_description. */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &tic6x_usrregs_info, + &tic6x_regsets_info + }; + +static const struct regs_info * +tic6x_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { tic6x_arch_setup, - TIC6X_NUM_REGS, - 0, - NULL, + tic6x_regs_info, tic6x_cannot_fetch_register, tic6x_cannot_store_register, NULL, /* fetch_register */ @@ -333,3 +373,14 @@ struct linux_target_ops the_low_target = { 0, tic6x_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_tic6x_c64xp_linux (); + init_registers_tic6x_c64x_linux (); + init_registers_tic6x_c62x_linux (); + + initialize_regsets_info (&tic6x_regsets_info); +} diff --git a/gdb/gdbserver/linux-tile-low.c b/gdb/gdbserver/linux-tile-low.c index f242675..8963b9a 100644 --- a/gdb/gdbserver/linux-tile-low.c +++ b/gdb/gdbserver/linux-tile-low.c @@ -25,8 +25,11 @@ /* Defined in auto-generated file reg-tilegx.c. */ void init_registers_tilegx (void); +extern const struct target_desc *tdesc_tilegx; + /* Defined in auto-generated file reg-tilegx32.c. */ void init_registers_tilegx32 (void); +extern const struct target_desc *tdesc_tilegx32; #define tile_num_regs 65 @@ -119,13 +122,39 @@ tile_store_gregset (struct regcache *regcache, const void *buf) supply_register (regcache, i, ((uint_reg_t *) buf) + tile_regmap[i]); } -struct regset_info target_regsets[] = +static struct regset_info tile_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, tile_num_regs * 4, GENERAL_REGS, tile_fill_gregset, tile_store_gregset }, { 0, 0, 0, -1, -1, NULL, NULL } }; +static struct regsets_info tile_regsets_info = + { + tile_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info tile_usrregs_info = + { + tile_num_regs, + tile_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &tile_usrregs_info, + &tile_regsets_info, + }; + +static const struct regs_info * +tile_regs_info (void) +{ + return ®s_info; +} + static void tile_arch_setup (void) { @@ -138,18 +167,16 @@ tile_arch_setup (void) error (_("Can't debug 64-bit process with 32-bit GDBserver")); if (!is_elf64) - init_registers_tilegx32(); + current_process ()->tdesc = tdesc_tilegx32; else - init_registers_tilegx(); + current_process ()->tdesc = tdesc_tilegx; } struct linux_target_ops the_low_target = { tile_arch_setup, - tile_num_regs, - tile_regmap, - NULL, + tile_regs_info, tile_cannot_fetch_register, tile_cannot_store_register, NULL, @@ -161,3 +188,12 @@ struct linux_target_ops the_low_target = 0, tile_breakpoint_at, }; + +void +initialize_low_arch (void) +{ + init_registers_tilegx32(); + init_registers_tilegx(); + + initialize_regsets_info (&tile_regsets_info); +} diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index dfe78b1..a03f512 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -30,21 +30,43 @@ #include "gdb_proc_service.h" #include "agent.h" +#include "tdesc.h" -/* Defined in auto-generated file i386-linux.c. */ -void init_registers_i386_linux (void); +#ifdef __x86_64__ /* Defined in auto-generated file amd64-linux.c. */ void init_registers_amd64_linux (void); -/* Defined in auto-generated file i386-avx-linux.c. */ -void init_registers_i386_avx_linux (void); +extern const struct target_desc *tdesc_amd64_linux; + /* Defined in auto-generated file amd64-avx-linux.c. */ void init_registers_amd64_avx_linux (void); -/* Defined in auto-generated file i386-mmx-linux.c. */ -void init_registers_i386_mmx_linux (void); +extern const struct target_desc *tdesc_amd64_avx_linux; + /* Defined in auto-generated file x32-linux.c. */ void init_registers_x32_linux (void); +extern const struct target_desc *tdesc_x32_linux; + /* Defined in auto-generated file x32-avx-linux.c. */ void init_registers_x32_avx_linux (void); +extern const struct target_desc *tdesc_x32_avx_linux; +#endif + +/* Defined in auto-generated file i386-linux.c. */ +void init_registers_i386_linux (void); +extern const struct target_desc *tdesc_i386_linux; + +/* Defined in auto-generated file i386-mmx-linux.c. */ +void init_registers_i386_mmx_linux (void); +extern const struct target_desc *tdesc_i386_mmx_linux; + +/* Defined in auto-generated file i386-avx-linux.c. */ +void init_registers_i386_avx_linux (void); +extern const struct target_desc *tdesc_i386_avx_linux; + +#ifdef __x86_64__ +static struct target_desc *tdesc_amd64_linux_no_xml; +#endif +static struct target_desc *tdesc_i386_linux_no_xml; + static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 }; static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 }; @@ -160,6 +182,22 @@ static /*const*/ int i386_regmap[] = #define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) #endif + +#ifdef __x86_64__ + +/* Returns true if the current inferior belongs to a x86-64 process, + per the tdesc. */ + +static int +is_64bit_tdesc (void) +{ + struct regcache *regcache = get_thread_regcache (current_inferior, 0); + + return register_size (regcache->tdesc, 0) == 8; +} + +#endif + /* Called by libthread_db. */ @@ -168,7 +206,7 @@ ps_get_thread_area (const struct ps_prochandle *ph, lwpid_t lwpid, int idx, void **base) { #ifdef __x86_64__ - int use_64bit = register_size (0) == 8; + int use_64bit = is_64bit_tdesc (); if (use_64bit) { @@ -211,7 +249,7 @@ static int x86_get_thread_area (int lwpid, CORE_ADDR *addr) { #ifdef __x86_64__ - int use_64bit = register_size (0) == 8; + int use_64bit = is_64bit_tdesc (); if (use_64bit) { @@ -251,14 +289,24 @@ x86_get_thread_area (int lwpid, CORE_ADDR *addr) static int -i386_cannot_store_register (int regno) +x86_cannot_store_register (int regno) { +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return 0; +#endif + return regno >= I386_NUM_REGS; } static int -i386_cannot_fetch_register (int regno) +x86_cannot_fetch_register (int regno) { +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return 0; +#endif + return regno >= I386_NUM_REGS; } @@ -268,7 +316,7 @@ x86_fill_gregset (struct regcache *regcache, void *buf) int i; #ifdef __x86_64__ - if (register_size (0) == 8) + if (register_size (regcache->tdesc, 0) == 8) { for (i = 0; i < X86_64_NUM_REGS; i++) if (x86_64_regmap[i] != -1) @@ -290,7 +338,7 @@ x86_store_gregset (struct regcache *regcache, const void *buf) int i; #ifdef __x86_64__ - if (register_size (0) == 8) + if (register_size (regcache->tdesc, 0) == 8) { for (i = 0; i < X86_64_NUM_REGS; i++) if (x86_64_regmap[i] != -1) @@ -359,11 +407,9 @@ x86_store_xstateregset (struct regcache *regcache, const void *buf) This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS doesn't work. IWBN to avoid the duplication in the case where it does work. Maybe the arch_setup routine could check whether it works - and update target_regsets accordingly, maybe by moving target_regsets - to linux_target_ops and set the right one there, rather than having to - modify the target_regsets global. */ + and update the supported regsets accordingly. */ -struct regset_info target_regsets[] = +static struct regset_info x86_regsets[] = { #ifdef HAVE_PTRACE_GETREGS { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), @@ -388,7 +434,7 @@ struct regset_info target_regsets[] = static CORE_ADDR x86_get_pc (struct regcache *regcache) { - int use_64bit = register_size (0) == 8; + int use_64bit = register_size (regcache->tdesc, 0) == 8; if (use_64bit) { @@ -407,7 +453,7 @@ x86_get_pc (struct regcache *regcache) static void x86_set_pc (struct regcache *regcache, CORE_ADDR pc) { - int use_64bit = register_size (0) == 8; + int use_64bit = register_size (regcache->tdesc, 0) == 8; if (use_64bit) { @@ -1107,7 +1153,7 @@ x86_siginfo_fixup (siginfo_t *native, void *inf, int direction) { #ifdef __x86_64__ /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ - if (register_size (0) == 4) + if (!is_64bit_tdesc ()) { if (sizeof (siginfo_t) != sizeof (compat_siginfo_t)) fatal ("unexpected difference in siginfo"); @@ -1141,138 +1187,207 @@ x86_siginfo_fixup (siginfo_t *native, void *inf, int direction) static int use_xml; -/* Update gdbserver_xmltarget. */ +/* Format of XSAVE extended state is: + struct + { + fxsave_bytes[0..463] + sw_usable_bytes[464..511] + xstate_hdr_bytes[512..575] + avx_bytes[576..831] + future_state etc + }; + + Same memory layout will be used for the coredump NT_X86_XSTATE + representing the XSAVE extended state registers. + + The first 8 bytes of the sw_usable_bytes[464..467] is the OS enabled + extended state mask, which is the same as the extended control register + 0 (the XFEATURE_ENABLED_MASK register), XCR0. We can use this mask + together with the mask saved in the xstate_hdr_bytes to determine what + states the processor/OS supports and what state, used or initialized, + the process/thread is in. */ +#define I386_LINUX_XSAVE_XCR0_OFFSET 464 + +/* Does the current host support the GETFPXREGS request? The header + file may or may not define it, and even if it is defined, the + kernel will return EIO if it's running on a pre-SSE processor. */ +int have_ptrace_getfpxregs = +#ifdef HAVE_PTRACE_GETFPXREGS + -1 +#else + 0 +#endif +; -static void -x86_linux_update_xmltarget (void) +/* Does the current host support PTRACE_GETREGSET? */ +static int have_ptrace_getregset = -1; + +/* Get Linux/x86 target description from running target. */ + +static const struct target_desc * +x86_linux_read_description (void) { - int pid; + unsigned int machine; + int is_elf64; + int avx; + int tid; + static uint64_t xcr0; struct regset_info *regset; - static unsigned long long xcr0; - static int have_ptrace_getregset = -1; -#if !defined(__x86_64__) && defined(HAVE_PTRACE_GETFPXREGS) - static int have_ptrace_getfpxregs = -1; -#endif - if (!current_inferior) - return; + tid = lwpid_of (get_thread_lwp (current_inferior)); - /* Before changing the register cache internal layout or the target - regsets, flush the contents of the current valid caches back to - the threads. */ - regcache_invalidate (); + is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine); - pid = pid_of (get_thread_lwp (current_inferior)); -#ifdef __x86_64__ - if (num_xmm_registers == 8) - init_registers_i386_linux (); - else if (linux_is_elf64) - init_registers_amd64_linux (); - else - init_registers_x32_linux (); -#else + if (sizeof (void *) == 4) { -# ifdef HAVE_PTRACE_GETFPXREGS - if (have_ptrace_getfpxregs == -1) - { - elf_fpxregset_t fpxregs; + if (is_elf64 > 0) + error (_("Can't debug 64-bit process with 32-bit GDBserver")); +#ifndef __x86_64__ + else if (machine == EM_X86_64) + error (_("Can't debug x86-64 process with 32-bit GDBserver")); +#endif + } - if (ptrace (PTRACE_GETFPXREGS, pid, 0, (int) &fpxregs) < 0) - { - have_ptrace_getfpxregs = 0; - x86_xcr0 = I386_XSTATE_X87_MASK; - - /* Disable PTRACE_GETFPXREGS. */ - for (regset = target_regsets; - regset->fill_function != NULL; regset++) - if (regset->get_request == PTRACE_GETFPXREGS) - { - regset->size = 0; - break; - } - } - else - have_ptrace_getfpxregs = 1; - } +#if !defined __x86_64__ && defined HAVE_PTRACE_GETFPXREGS + if (machine == EM_386 && have_ptrace_getfpxregs == -1) + { + elf_fpxregset_t fpxregs; - if (!have_ptrace_getfpxregs) + if (ptrace (PTRACE_GETFPXREGS, tid, 0, (long) &fpxregs) < 0) { - init_registers_i386_mmx_linux (); - return; + have_ptrace_getfpxregs = 0; + have_ptrace_getregset = 0; + return tdesc_i386_mmx_linux; } -# endif - init_registers_i386_linux (); + else + have_ptrace_getfpxregs = 1; } #endif if (!use_xml) { + x86_xcr0 = I386_XSTATE_SSE_MASK; + /* Don't use XML. */ #ifdef __x86_64__ - if (num_xmm_registers == 8) - gdbserver_xmltarget = xmltarget_i386_linux_no_xml; + if (machine == EM_X86_64) + return tdesc_amd64_linux_no_xml; else - gdbserver_xmltarget = xmltarget_amd64_linux_no_xml; -#else - gdbserver_xmltarget = xmltarget_i386_linux_no_xml; #endif - - x86_xcr0 = I386_XSTATE_SSE_MASK; - - return; + return tdesc_i386_linux_no_xml; } - /* Check if XSAVE extended state is supported. */ if (have_ptrace_getregset == -1) { - unsigned long long xstateregs[I386_XSTATE_SSE_SIZE / sizeof (long long)]; + uint64_t xstateregs[(I386_XSTATE_SSE_SIZE / sizeof (uint64_t))]; struct iovec iov; iov.iov_base = xstateregs; iov.iov_len = sizeof (xstateregs); /* Check if PTRACE_GETREGSET works. */ - if (ptrace (PTRACE_GETREGSET, pid, (unsigned int) NT_X86_XSTATE, - &iov) < 0) + if (ptrace (PTRACE_GETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + have_ptrace_getregset = 0; + else { - have_ptrace_getregset = 0; - return; + have_ptrace_getregset = 1; + + /* Get XCR0 from XSAVE extended state. */ + xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET + / sizeof (uint64_t))]; + + /* Use PTRACE_GETREGSET if it is available. */ + for (regset = x86_regsets; + regset->fill_function != NULL; regset++) + if (regset->get_request == PTRACE_GETREGSET) + regset->size = I386_XSTATE_SIZE (xcr0); + else if (regset->type != GENERAL_REGS) + regset->size = 0; } - else - have_ptrace_getregset = 1; - - /* Get XCR0 from XSAVE extended state at byte 464. */ - xcr0 = xstateregs[464 / sizeof (long long)]; - - /* Use PTRACE_GETREGSET if it is available. */ - for (regset = target_regsets; - regset->fill_function != NULL; regset++) - if (regset->get_request == PTRACE_GETREGSET) - regset->size = I386_XSTATE_SIZE (xcr0); - else if (regset->type != GENERAL_REGS) - regset->size = 0; } - if (have_ptrace_getregset) - { - /* AVX is the highest feature we support. */ - if ((xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK) - { - x86_xcr0 = xcr0; + /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ + avx = (have_ptrace_getregset + && (xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK); + + /* AVX is the highest feature we support. */ + if (avx) + x86_xcr0 = xcr0; + if (machine == EM_X86_64) + { #ifdef __x86_64__ - /* I386 has 8 xmm regs. */ - if (num_xmm_registers == 8) - init_registers_i386_avx_linux (); - else if (linux_is_elf64) - init_registers_amd64_avx_linux (); + if (avx) + { + if (!is_elf64) + return tdesc_x32_avx_linux; else - init_registers_x32_avx_linux (); -#else - init_registers_i386_avx_linux (); -#endif + return tdesc_amd64_avx_linux; + } + else + { + if (!is_elf64) + return tdesc_x32_linux; + else + return tdesc_amd64_linux; } +#endif } + else + { + if (avx) + return tdesc_i386_avx_linux; + else + return tdesc_i386_linux; + } + + gdb_assert_not_reached ("failed to return tdesc"); +} + +/* Callback for find_inferior. Stops iteration when a thread with a + given PID is found. */ + +static int +same_process_callback (struct inferior_list_entry *entry, void *data) +{ + int pid = *(int *) data; + + return (ptid_get_pid (entry->id) == pid); +} + +/* Callback for for_each_inferior. Calls the arch_setup routine for + each process. */ + +static void +x86_arch_setup_process_callback (struct inferior_list_entry *entry) +{ + int pid = ptid_get_pid (entry->id); + + /* Look up any thread of this processes. */ + current_inferior + = (struct thread_info *) find_inferior (&all_threads, + same_process_callback, &pid); + + the_low_target.arch_setup (); +} + +/* Update all the target description of all processes; a new GDB + connected, and it may or not support xml target descriptions. */ + +static void +x86_linux_update_xmltarget (void) +{ + struct thread_info *save_inferior = current_inferior; + + /* Before changing the register cache's internal layout, flush the + contents of the current valid caches back to the threads, and + release the current regcache objects. */ + regcache_release (); + + for_each_inferior (&all_processes, x86_arch_setup_process_callback); + + current_inferior = save_inferior; } /* Process qSupported query, "xmlRegisters=". Update the buffer size for @@ -1305,62 +1420,54 @@ x86_linux_process_qsupported (const char *query) x86_linux_update_xmltarget (); } -/* Initialize gdbserver for the architecture of the inferior. */ +/* Common for x86/x86-64. */ -static void -x86_arch_setup (void) -{ - int pid = pid_of (get_thread_lwp (current_inferior)); - unsigned int machine; - int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine); - - if (sizeof (void *) == 4) - { - if (is_elf64 > 0) - error (_("Can't debug 64-bit process with 32-bit GDBserver")); -#ifndef __x86_64__ - else if (machine == EM_X86_64) - error (_("Can't debug x86-64 process with 32-bit GDBserver")); -#endif - } +static struct regsets_info x86_regsets_info = + { + x86_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; #ifdef __x86_64__ - if (is_elf64 < 0) - { - /* This can only happen if /proc/<pid>/exe is unreadable, - but "that can't happen" if we've gotten this far. - Fall through and assume this is a 32-bit program. */ - } - else if (machine == EM_X86_64) - { - /* Amd64 doesn't have HAVE_LINUX_USRREGS. */ - the_low_target.num_regs = -1; - the_low_target.regmap = NULL; - the_low_target.cannot_fetch_register = NULL; - the_low_target.cannot_store_register = NULL; - - /* Amd64 has 16 xmm regs. */ - num_xmm_registers = 16; - - linux_is_elf64 = is_elf64; - x86_linux_update_xmltarget (); - return; - } - - linux_is_elf64 = 0; +static struct regs_info amd64_linux_regs_info = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs_info */ + &x86_regsets_info + }; #endif +static struct usrregs_info i386_linux_usrregs_info = + { + I386_NUM_REGS, + i386_regmap, + }; - /* Ok we have a 32-bit inferior. */ +static struct regs_info i386_linux_regs_info = + { + NULL, /* regset_bitmap */ + &i386_linux_usrregs_info, + &x86_regsets_info + }; - the_low_target.num_regs = I386_NUM_REGS; - the_low_target.regmap = i386_regmap; - the_low_target.cannot_fetch_register = i386_cannot_fetch_register; - the_low_target.cannot_store_register = i386_cannot_store_register; +const struct regs_info * +x86_linux_regs_info (void) +{ +#ifdef __x86_64__ + if (is_64bit_tdesc ()) + return &amd64_linux_regs_info; + else +#endif + return &i386_linux_regs_info; +} - /* I386 has 8 xmm regs. */ - num_xmm_registers = 8; +/* Initialize the target description for the architecture of the + inferior. */ - x86_linux_update_xmltarget (); +static void +x86_arch_setup (void) +{ + current_process ()->tdesc = x86_linux_read_description (); } static int @@ -1790,7 +1897,7 @@ x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr, char *err) { #ifdef __x86_64__ - if (register_size (0) == 8) + if (is_64bit_tdesc ()) return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr, collector, lockaddr, orig_size, jump_entry, @@ -1824,7 +1931,7 @@ x86_get_min_fast_tracepoint_insn_len (void) #ifdef __x86_64__ /* On x86-64, 5-byte jump instructions with a 4-byte offset are always used for fast tracepoints. */ - if (register_size (0) == 8) + if (is_64bit_tdesc ()) return 5; #endif @@ -3167,9 +3274,7 @@ static struct emit_ops * x86_emit_ops (void) { #ifdef __x86_64__ - int use_64bit = register_size (0) == 8; - - if (use_64bit) + if (is_64bit_tdesc ()) return &amd64_emit_ops; else #endif @@ -3188,11 +3293,9 @@ x86_supports_range_stepping (void) struct linux_target_ops the_low_target = { x86_arch_setup, - -1, - NULL, - NULL, - NULL, - NULL, + x86_linux_regs_info, + x86_cannot_fetch_register, + x86_cannot_store_register, NULL, /* fetch_register */ x86_get_pc, x86_set_pc, @@ -3223,3 +3326,27 @@ struct linux_target_ops the_low_target = x86_get_min_fast_tracepoint_insn_len, x86_supports_range_stepping, }; + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ +#ifdef __x86_64__ + init_registers_amd64_linux (); + init_registers_amd64_avx_linux (); + init_registers_x32_linux (); + + tdesc_amd64_linux_no_xml = xmalloc (sizeof (struct target_desc)); + copy_target_description (tdesc_amd64_linux_no_xml, tdesc_amd64_linux); + tdesc_amd64_linux_no_xml->xmltarget = xmltarget_amd64_linux_no_xml; +#endif + init_registers_i386_linux (); + init_registers_i386_mmx_linux (); + init_registers_i386_avx_linux (); + + tdesc_i386_linux_no_xml = xmalloc (sizeof (struct target_desc)); + copy_target_description (tdesc_i386_linux_no_xml, tdesc_i386_linux); + tdesc_i386_linux_no_xml->xmltarget = xmltarget_i386_linux_no_xml; + + initialize_regsets_info (&x86_regsets_info); +} diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c index d988a46..6083f33 100644 --- a/gdb/gdbserver/linux-xtensa-low.c +++ b/gdb/gdbserver/linux-xtensa-low.c @@ -22,6 +22,7 @@ /* Defined in auto-generated file reg-xtensa.c. */ void init_registers_xtensa (void); +extern const struct target_desc *tdesc_xtensa; #include <sys/ptrace.h> #include <xtensa-config.h> @@ -40,19 +41,20 @@ static void xtensa_fill_gregset (struct regcache *regcache, void *buf) { elf_greg_t* rset = (elf_greg_t*)buf; + const struct target_desc *tdesc = regcache->tdesc; int ar0_regnum; char *ptr; int i; /* Take care of AR registers. */ - ar0_regnum = find_regno ("ar0"); + ar0_regnum = find_regno (tdesc, "ar0"); ptr = (char*)&rset[R_A0]; for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) { collect_register (regcache, i, ptr); - ptr += register_size(i); + ptr += register_size (tdesc, i); } /* Loop registers, if hardware has it. */ @@ -74,19 +76,20 @@ static void xtensa_store_gregset (struct regcache *regcache, const void *buf) { const elf_greg_t* rset = (const elf_greg_t*)buf; + const struct target_desc *tdesc = regcache->tdesc; int ar0_regnum; char *ptr; int i; /* Take care of AR registers. */ - ar0_regnum = find_regno ("ar0"); + ar0_regnum = find_regno (tdesc, "ar0"); ptr = (char *)&rset[R_A0]; for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) { supply_register (regcache, i, ptr); - ptr += register_size(i); + ptr += register_size (tdesc, i); } /* Loop registers, if hardware has it. */ @@ -130,7 +133,7 @@ xtensa_store_xtregset (struct regcache *regcache, const void *buf) } } -struct regset_info target_regsets[] = { +static struct regset_info xtensa_regsets[] = { { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), GENERAL_REGS, xtensa_fill_gregset, xtensa_store_gregset }, @@ -176,11 +179,41 @@ xtensa_breakpoint_at (CORE_ADDR where) xtensa_breakpoint, xtensa_breakpoint_len) == 0; } +static struct regsets_info xtensa_regsets_info = + { + xtensa_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct usrregs_info xtensa_usrregs_info = + { + xtensa_num_regs, + xtensa_regmap, + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + &xtensa_usrregs_info, + &xtensa_regsets_info + }; + +static void +xtensa_arch_setup (void) +{ + current_process ()->tdesc = tdesc_xtensa; +} + +static const struct regs_info * +xtensa_regs_info (void) +{ + return ®s_info; +} + struct linux_target_ops the_low_target = { - init_registers_xtensa, - 0, - 0, - NULL, + xtensa_arch_setup, + xtensa_regs_info, 0, 0, NULL, /* fetch_register */ @@ -192,3 +225,13 @@ struct linux_target_ops the_low_target = { 0, xtensa_breakpoint_at, }; + + +void +initialize_low_arch (void) +{ + /* Initialize the Linux target descriptions. */ + init_registers_xtensa (); + + initialize_regsets_info (&xtensa_regsets_info); +} diff --git a/gdb/gdbserver/lynx-i386-low.c b/gdb/gdbserver/lynx-i386-low.c index e461bb2..11b5f4c 100644 --- a/gdb/gdbserver/lynx-i386-low.c +++ b/gdb/gdbserver/lynx-i386-low.c @@ -122,6 +122,7 @@ enum lynx_i386_gdb_regnum /* Defined in auto-generated file i386.c. */ extern void init_registers_i386 (void); +extern const struct target_desc *tdesc_i386; /* The fill_function for the general-purpose register set. */ @@ -297,6 +298,7 @@ static void lynx_i386_arch_setup (void) { init_registers_i386 (); + lynx_tdesc = tdesc_i386; } /* Description of all the x86-lynx register sets. */ diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index 3dbffa5..4cf8683 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -30,6 +30,8 @@ int using_threads = 1; +const struct target_desc *lynx_tdesc; + /* Per-process private data. */ struct process_info_private @@ -214,6 +216,7 @@ lynx_add_process (int pid, int attached) struct process_info *proc; proc = add_process (pid, attached); + proc->tdesc = lynx_tdesc; proc->private = xcalloc (1, sizeof (*proc->private)); proc->private->last_wait_event_ptid = null_ptid; diff --git a/gdb/gdbserver/lynx-low.h b/gdb/gdbserver/lynx-low.h index 552c50f..47deaab 100644 --- a/gdb/gdbserver/lynx-low.h +++ b/gdb/gdbserver/lynx-low.h @@ -18,6 +18,7 @@ #include "server.h" struct regcache; +struct target_desc; /* Some information relative to a given register set. */ @@ -50,3 +51,6 @@ struct lynx_target_ops extern struct lynx_target_ops the_low_target; +/* The inferior's target description. This is a global because the + LynxOS ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *lynx_tdesc; diff --git a/gdb/gdbserver/lynx-ppc-low.c b/gdb/gdbserver/lynx-ppc-low.c index 5e5ac5d..dc5dd3c 100644 --- a/gdb/gdbserver/lynx-ppc-low.c +++ b/gdb/gdbserver/lynx-ppc-low.c @@ -69,6 +69,7 @@ typedef struct usr_fcontext_s /* Defined in auto-generated file powerpc-32.c. */ extern void init_registers_powerpc_32 (void); +extern const struct target_desc *tdesc_powerpc_32; /* The fill_function for the general-purpose register set. */ @@ -164,6 +165,7 @@ static void lynx_ppc_arch_setup (void) { init_registers_powerpc_32 (); + lynx_tdesc = tdesc_powerpc_32; } /* Description of all the powerpc-lynx register sets. */ diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index 5e4c60d..3670133 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -35,6 +35,8 @@ extern int using_threads; int using_threads = 1; +const struct target_desc *nto_tdesc; + static void nto_trace (const char *fmt, ...) { @@ -203,11 +205,13 @@ do_attach (pid_t pid) && (status.flags & _DEBUG_FLAG_STOPPED)) { ptid_t ptid; + struct process_info *proc; kill (pid, SIGCONT); ptid = ptid_build (status.pid, status.tid, 0); the_low_target.arch_setup (); - add_process (status.pid, 1); + proc = add_process (status.pid, 1); + proc->tdesc = nto_tdesc; TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid, ptid_get_lwp (ptid)); nto_find_new_threads (&nto_inferior); diff --git a/gdb/gdbserver/nto-low.h b/gdb/gdbserver/nto-low.h index 2c450b7..1cc8f22 100644 --- a/gdb/gdbserver/nto-low.h +++ b/gdb/gdbserver/nto-low.h @@ -19,6 +19,8 @@ #ifndef NTO_LOW_H #define NTO_LOW_H +struct target_desc; + enum regset_type { NTO_REG_GENERAL, @@ -40,5 +42,9 @@ struct nto_target_ops extern struct nto_target_ops the_low_target; +/* The inferior's target description. This is a global because the + LynxOS ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *nto_tdesc; + #endif diff --git a/gdb/gdbserver/nto-x86-low.c b/gdb/gdbserver/nto-x86-low.c index 9163880..c9cb004 100644 --- a/gdb/gdbserver/nto-x86-low.c +++ b/gdb/gdbserver/nto-x86-low.c @@ -28,6 +28,7 @@ /* Definition auto generated from reg-i386.dep. */ extern void init_registers_i386 (); extern struct reg *regs_i386; +extern const struct target_desc *tdesc_i386; const unsigned char x86_breakpoint[] = { 0xCC }; #define x86_breakpoint_len 1 @@ -91,6 +92,7 @@ nto_x86_arch_setup (void) { init_registers_i386 (); the_low_target.num_regs = 16; + nto_tdesc = tdesc_i386; } struct nto_target_ops the_low_target = diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c index 235bab7..69b86f8 100644 --- a/gdb/gdbserver/proc-service.c +++ b/gdb/gdbserver/proc-service.c @@ -39,18 +39,20 @@ typedef size_t gdb_ps_size_t; #ifdef HAVE_REGSETS static struct regset_info * -gregset_info(void) +gregset_info (void) { int i = 0; + const struct regs_info *regs_info = (*the_low_target.regs_info) (); + struct regsets_info *regsets_info = regs_info->regsets_info; - while (target_regsets[i].size != -1) + while (regsets_info->regsets[i].size != -1) { - if (target_regsets[i].type == GENERAL_REGS) + if (regsets_info->regsets[i].type == GENERAL_REGS) break; i++; } - return &target_regsets[i]; + return ®sets_info->regsets[i]; } #endif diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 778bd05..be47ed3 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -19,17 +19,11 @@ #include "server.h" #include "regdef.h" #include "gdbthread.h" +#include "tdesc.h" #include <stdlib.h> #include <string.h> -static int register_bytes; - -static struct reg *reg_defs; -static int num_registers; - -const char **gdbserver_expedite_regs; - #ifndef IN_PROCESS_AGENT struct regcache * @@ -39,8 +33,23 @@ get_thread_regcache (struct thread_info *thread, int fetch) regcache = (struct regcache *) inferior_regcache_data (thread); + /* Threads' regcaches are created lazily, because biarch targets add + the main thread/lwp before seeing it stop for the first time, and + it is only after the target sees the thread stop for the first + time that the target has a chance of determining the process's + architecture. IOW, when we first add the process's main thread + we don't know which architecture/tdesc its regcache should + have. */ if (regcache == NULL) - fatal ("no register cache"); + { + struct process_info *proc = get_thread_process (thread); + + if (proc->tdesc == NULL) + fatal ("no target description"); + + regcache = new_register_cache (proc->tdesc); + set_inferior_regcache_data (thread, regcache); + } if (fetch && regcache->registers_valid == 0) { @@ -56,9 +65,8 @@ get_thread_regcache (struct thread_info *thread, int fetch) } void -regcache_invalidate_one (struct inferior_list_entry *entry) +regcache_invalidate_thread (struct thread_info *thread) { - struct thread_info *thread = (struct thread_info *) entry; struct regcache *regcache; regcache = (struct regcache *) inferior_regcache_data (thread); @@ -78,16 +86,35 @@ regcache_invalidate_one (struct inferior_list_entry *entry) regcache->registers_valid = 0; } +static int +regcache_invalidate_one (struct inferior_list_entry *entry, + void *pid_p) +{ + struct thread_info *thread = (struct thread_info *) entry; + int pid = *(int *) pid_p; + + /* Only invalidate the regcaches of threads of this process. */ + if (ptid_get_pid (entry->id) == pid) + regcache_invalidate_thread (thread); + + return 0; +} + void regcache_invalidate (void) { - for_each_inferior (&all_threads, regcache_invalidate_one); + /* Only update the threads of the current process. */ + int pid = ptid_get_pid (current_inferior->entry.id); + + find_inferior (&all_threads, regcache_invalidate_one, &pid); } #endif struct regcache * -init_register_cache (struct regcache *regcache, unsigned char *regbuf) +init_register_cache (struct regcache *regcache, + const struct target_desc *tdesc, + unsigned char *regbuf) { #ifndef IN_PROCESS_AGENT if (regbuf == NULL) @@ -96,9 +123,10 @@ init_register_cache (struct regcache *regcache, unsigned char *regbuf) created, in case there are registers the target never fetches. This way they'll read as zero instead of garbage. */ - regcache->registers = xcalloc (1, register_bytes); + regcache->tdesc = tdesc; + regcache->registers = xcalloc (1, tdesc->registers_size); regcache->registers_owned = 1; - regcache->register_status = xcalloc (1, num_registers); + regcache->register_status = xcalloc (1, tdesc->num_registers); gdb_assert (REG_UNAVAILABLE == 0); } else @@ -108,6 +136,7 @@ init_register_cache (struct regcache *regcache, unsigned char *regbuf) else #endif { + regcache->tdesc = tdesc; regcache->registers = regbuf; regcache->registers_owned = 0; #ifndef IN_PROCESS_AGENT @@ -123,15 +152,14 @@ init_register_cache (struct regcache *regcache, unsigned char *regbuf) #ifndef IN_PROCESS_AGENT struct regcache * -new_register_cache (void) +new_register_cache (const struct target_desc *tdesc) { struct regcache *regcache; - if (register_bytes == 0) - return NULL; /* The architecture hasn't been initialized yet. */ + gdb_assert (tdesc->registers_size != 0); regcache = xmalloc (sizeof (*regcache)); - return init_register_cache (regcache, NULL); + return init_register_cache (regcache, tdesc, NULL); } void @@ -151,67 +179,19 @@ free_register_cache (struct regcache *regcache) void regcache_cpy (struct regcache *dst, struct regcache *src) { - memcpy (dst->registers, src->registers, register_bytes); + gdb_assert (src != NULL && dst != NULL); + gdb_assert (src->tdesc == dst->tdesc); + gdb_assert (src != dst); + + memcpy (dst->registers, src->registers, src->tdesc->registers_size); #ifndef IN_PROCESS_AGENT if (dst->register_status != NULL && src->register_status != NULL) - memcpy (dst->register_status, src->register_status, num_registers); + memcpy (dst->register_status, src->register_status, + src->tdesc->num_registers); #endif dst->registers_valid = src->registers_valid; } -#ifndef IN_PROCESS_AGENT -static void -realloc_register_cache (struct inferior_list_entry *thread_p) -{ - struct thread_info *thread = (struct thread_info *) thread_p; - struct regcache *regcache - = (struct regcache *) inferior_regcache_data (thread); - - if (regcache != NULL) - regcache_invalidate_one (thread_p); - free_register_cache (regcache); - set_inferior_regcache_data (thread, new_register_cache ()); -} -#endif - -void -set_register_cache (struct reg *regs, int n) -{ - int offset, i; - -#ifndef IN_PROCESS_AGENT - /* Before changing the register cache internal layout, flush the - contents of valid caches back to the threads. */ - regcache_invalidate (); -#endif - - reg_defs = regs; - num_registers = n; - - offset = 0; - for (i = 0; i < n; i++) - { - regs[i].offset = offset; - offset += regs[i].size; - } - - register_bytes = offset / 8; - - /* Make sure PBUFSIZ is large enough to hold a full register packet. */ - if (2 * register_bytes + 32 > PBUFSIZ) - fatal ("Register packet size exceeds PBUFSIZ."); - -#ifndef IN_PROCESS_AGENT - /* Re-allocate all pre-existing register caches. */ - for_each_inferior (&all_threads, realloc_register_cache); -#endif -} - -int -register_cache_size (void) -{ - return register_bytes; -} #ifndef IN_PROCESS_AGENT @@ -219,21 +199,23 @@ void registers_to_string (struct regcache *regcache, char *buf) { unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; int i; - for (i = 0; i < num_registers; i++) + for (i = 0; i < tdesc->num_registers; i++) { if (regcache->register_status[i] == REG_VALID) { - convert_int_to_ascii (registers, buf, register_size (i)); - buf += register_size (i) * 2; + convert_int_to_ascii (registers, buf, + register_size (tdesc, i)); + buf += register_size (tdesc, i) * 2; } else { - memset (buf, 'x', register_size (i) * 2); - buf += register_size (i) * 2; + memset (buf, 'x', register_size (tdesc, i) * 2); + buf += register_size (tdesc, i) * 2; } - registers += register_size (i); + registers += register_size (tdesc, i); } *buf = '\0'; } @@ -243,59 +225,97 @@ registers_from_string (struct regcache *regcache, char *buf) { int len = strlen (buf); unsigned char *registers = regcache->registers; + const struct target_desc *tdesc = regcache->tdesc; - if (len != register_bytes * 2) + if (len != tdesc->registers_size * 2) { warning ("Wrong sized register packet (expected %d bytes, got %d)", - 2*register_bytes, len); - if (len > register_bytes * 2) - len = register_bytes * 2; + 2 * tdesc->registers_size, len); + if (len > tdesc->registers_size * 2) + len = tdesc->registers_size * 2; } convert_ascii_to_int (buf, registers, len / 2); } struct reg * -find_register_by_name (const char *name) +find_register_by_name (const struct target_desc *tdesc, const char *name) { int i; - for (i = 0; i < num_registers; i++) - if (!strcmp (name, reg_defs[i].name)) - return ®_defs[i]; + for (i = 0; i < tdesc->num_registers; i++) + if (strcmp (name, tdesc->reg_defs[i].name) == 0) + return &tdesc->reg_defs[i]; fatal ("Unknown register %s requested", name); return 0; } int -find_regno (const char *name) +find_regno (const struct target_desc *tdesc, const char *name) { int i; - for (i = 0; i < num_registers; i++) - if (!strcmp (name, reg_defs[i].name)) + for (i = 0; i < tdesc->num_registers; i++) + if (strcmp (name, tdesc->reg_defs[i].name) == 0) return i; fatal ("Unknown register %s requested", name); return -1; } struct reg * -find_register_by_number (int n) +find_register_by_number (const struct target_desc *tdesc, int n) { - return ®_defs[n]; + return &tdesc->reg_defs[n]; } #endif +#ifndef IN_PROCESS_AGENT +static void +free_register_cache_thread (struct thread_info *thread) +{ + struct regcache *regcache + = (struct regcache *) inferior_regcache_data (thread); + + if (regcache != NULL) + { + regcache_invalidate_thread (thread); + free_register_cache (regcache); + set_inferior_regcache_data (thread, NULL); + } +} + +static void +free_register_cache_thread_one (struct inferior_list_entry *entry) +{ + struct thread_info *thread = (struct thread_info *) entry; + + free_register_cache_thread (thread); +} + +void +regcache_release (void) +{ + /* Flush and release all pre-existing register caches. */ + for_each_inferior (&all_threads, free_register_cache_thread_one); +} +#endif + int -register_size (int n) +register_cache_size (const struct target_desc *tdesc) { - return reg_defs[n].size / 8; + return tdesc->registers_size; +} + +int +register_size (const struct target_desc *tdesc, int n) +{ + return tdesc->reg_defs[n].size / 8; } static unsigned char * register_data (struct regcache *regcache, int n, int fetch) { - return regcache->registers + (reg_defs[n].offset / 8); + return regcache->registers + regcache->tdesc->reg_defs[n].offset / 8; } /* Supply register N, whose contents are stored in BUF, to REGCACHE. @@ -307,7 +327,8 @@ supply_register (struct regcache *regcache, int n, const void *buf) { if (buf) { - memcpy (register_data (regcache, n, 0), buf, register_size (n)); + memcpy (register_data (regcache, n, 0), buf, + register_size (regcache->tdesc, n)); #ifndef IN_PROCESS_AGENT if (regcache->register_status != NULL) regcache->register_status[n] = REG_VALID; @@ -315,7 +336,8 @@ supply_register (struct regcache *regcache, int n, const void *buf) } else { - memset (register_data (regcache, n, 0), 0, register_size (n)); + memset (register_data (regcache, n, 0), 0, + register_size (regcache->tdesc, n)); #ifndef IN_PROCESS_AGENT if (regcache->register_status != NULL) regcache->register_status[n] = REG_UNAVAILABLE; @@ -328,7 +350,8 @@ supply_register (struct regcache *regcache, int n, const void *buf) void supply_register_zeroed (struct regcache *regcache, int n) { - memset (register_data (regcache, n, 0), 0, register_size (n)); + memset (register_data (regcache, n, 0), 0, + register_size (regcache->tdesc, n)); #ifndef IN_PROCESS_AGENT if (regcache->register_status != NULL) regcache->register_status[n] = REG_VALID; @@ -344,24 +367,28 @@ supply_regblock (struct regcache *regcache, const void *buf) { if (buf) { - memcpy (regcache->registers, buf, register_bytes); + const struct target_desc *tdesc = regcache->tdesc; + + memcpy (regcache->registers, buf, tdesc->registers_size); #ifndef IN_PROCESS_AGENT { int i; - for (i = 0; i < num_registers; i++) + for (i = 0; i < tdesc->num_registers; i++) regcache->register_status[i] = REG_VALID; } #endif } else { - memset (regcache->registers, 0, register_bytes); + const struct target_desc *tdesc = regcache->tdesc; + + memset (regcache->registers, 0, tdesc->registers_size); #ifndef IN_PROCESS_AGENT { int i; - for (i = 0; i < num_registers; i++) + for (i = 0; i < tdesc->num_registers; i++) regcache->register_status[i] = REG_UNAVAILABLE; } #endif @@ -374,7 +401,7 @@ void supply_register_by_name (struct regcache *regcache, const char *name, const void *buf) { - supply_register (regcache, find_regno (name), buf); + supply_register (regcache, find_regno (regcache->tdesc, name), buf); } #endif @@ -382,7 +409,8 @@ supply_register_by_name (struct regcache *regcache, void collect_register (struct regcache *regcache, int n, void *buf) { - memcpy (buf, register_data (regcache, n, 1), register_size (n)); + memcpy (buf, register_data (regcache, n, 1), + register_size (regcache->tdesc, n)); } #ifndef IN_PROCESS_AGENT @@ -390,15 +418,15 @@ collect_register (struct regcache *regcache, int n, void *buf) void collect_register_as_string (struct regcache *regcache, int n, char *buf) { - convert_int_to_ascii (register_data (regcache, n, 1), - buf, register_size (n)); + convert_int_to_ascii (register_data (regcache, n, 1), buf, + register_size (regcache->tdesc, n)); } void collect_register_by_name (struct regcache *regcache, const char *name, void *buf) { - collect_register (regcache, find_regno (name), buf); + collect_register (regcache, find_regno (regcache->tdesc, name), buf); } /* Special handling for register PC. */ diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h index ce86322..48c57a2 100644 --- a/gdb/gdbserver/regcache.h +++ b/gdb/gdbserver/regcache.h @@ -21,6 +21,7 @@ struct inferior_list_entry; struct thread_info; +struct target_desc; /* The register exists, it has a value, but we don't know what it is. Used when inspecting traceframes. */ @@ -35,6 +36,9 @@ struct thread_info; struct regcache { + /* The regcache's target description. */ + const struct target_desc *tdesc; + /* Whether the REGISTERS buffer's contents are valid. If false, we haven't fetched the registers from the target yet. Not that this register cache is _not_ pass-through, unlike GDB's. Note that @@ -50,13 +54,14 @@ struct regcache }; struct regcache *init_register_cache (struct regcache *regcache, + const struct target_desc *tdesc, unsigned char *regbuf); void regcache_cpy (struct regcache *dst, struct regcache *src); /* Create a new register cache for INFERIOR. */ -struct regcache *new_register_cache (void); +struct regcache *new_register_cache (const struct target_desc *tdesc); struct regcache *get_thread_regcache (struct thread_info *thread, int fetch); @@ -64,11 +69,20 @@ struct regcache *get_thread_regcache (struct thread_info *thread, int fetch); void free_register_cache (struct regcache *regcache); -/* Invalidate cached registers for one or all threads. */ +/* Invalidate cached registers for one thread. */ + +void regcache_invalidate_thread (struct thread_info *); + +/* Invalidate cached registers for all threads of the current + process. */ -void regcache_invalidate_one (struct inferior_list_entry *); void regcache_invalidate (void); +/* Invalidate and release the register cache of all threads of the + current process. */ + +void regcache_release (void); + /* Convert all registers to a string in the currently specified remote format. */ @@ -84,18 +98,13 @@ void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc); /* Return a pointer to the description of register ``n''. */ -struct reg *find_register_by_number (int n); - -int register_size (int n); +struct reg *find_register_by_number (const struct target_desc *tdesc, int n); -int register_cache_size (void); +int register_cache_size (const struct target_desc *tdesc); -int find_regno (const char *name); +int register_size (const struct target_desc *tdesc, int n); -/* The following two variables are set by auto-generated - code in the init_registers_... routines. */ -extern const char **gdbserver_expedite_regs; -extern const char *gdbserver_xmltarget; +int find_regno (const struct target_desc *tdesc, const char *name); void supply_register (struct regcache *regcache, int n, const void *buf); diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 42c6a54..3f055cf 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -20,6 +20,7 @@ #include "terminal.h" #include "target.h" #include "gdbthread.h" +#include "tdesc.h" #include <stdio.h> #include <string.h> #if HAVE_SYS_IOCTL_H @@ -1270,7 +1271,7 @@ outreg (struct regcache *regcache, int regno, char *buf) *buf++ = tohex (regno & 0xf); *buf++ = ':'; collect_register_as_string (regcache, regno, buf); - buf += 2 * register_size (regno); + buf += 2 * register_size (regcache->tdesc, regno); *buf++ = ';'; return buf; @@ -1328,12 +1329,12 @@ prepare_resume_reply (char *buf, ptid_t ptid, sprintf (buf, "T%02x", status->value.sig); buf += strlen (buf); - regp = gdbserver_expedite_regs; - saved_inferior = current_inferior; current_inferior = find_thread_ptid (ptid); + regp = current_target_desc ()->expedite_regs; + regcache = get_thread_regcache (current_inferior, 1); if (the_target->stopped_by_watchpoint != NULL @@ -1358,7 +1359,7 @@ prepare_resume_reply (char *buf, ptid_t ptid, while (*regp) { - buf = outreg (regcache, find_regno (*regp), buf); + buf = outreg (regcache, find_regno (regcache->tdesc, *regp), buf); regp ++; } *buf = '\0'; diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 1d1e7b4..4a1d1dc 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -20,6 +20,7 @@ #include "gdbthread.h" #include "agent.h" #include "notif.h" +#include "tdesc.h" #if HAVE_UNISTD_H #include <unistd.h> @@ -76,8 +77,6 @@ int program_signals_p; jmp_buf toplevel; -const char *gdbserver_xmltarget; - /* The PID of the originally created or attached inferior. Used to send signals to the process when GDB sends us an asynchronous interrupt (user hitting Control-C in the client), and to wait for the child to exit @@ -646,21 +645,22 @@ handle_general_set (char *own_buf) static const char * get_features_xml (const char *annex) { - /* gdbserver_xmltarget defines what to return when looking - for the "target.xml" file. Its contents can either be - verbatim XML code (prefixed with a '@') or else the name - of the actual XML file to be used in place of "target.xml". + const struct target_desc *desc = current_target_desc (); + + /* `desc->xmltarget' defines what to return when looking for the + "target.xml" file. Its contents can either be verbatim XML code + (prefixed with a '@') or else the name of the actual XML file to + be used in place of "target.xml". This variable is set up from the auto-generated init_registers_... routine for the current target. */ - if (gdbserver_xmltarget - && strcmp (annex, "target.xml") == 0) + if (desc->xmltarget != NULL && strcmp (annex, "target.xml") == 0) { - if (*gdbserver_xmltarget == '@') - return gdbserver_xmltarget + 1; + if (*desc->xmltarget == '@') + return desc->xmltarget + 1; else - annex = gdbserver_xmltarget; + annex = desc->xmltarget; } #ifdef USE_XML @@ -3294,7 +3294,8 @@ process_serial_event (void) require_running (own_buf); if (current_traceframe >= 0) { - struct regcache *regcache = new_register_cache (); + struct regcache *regcache + = new_register_cache (current_target_desc ()); if (fetch_traceframe_registers (current_traceframe, regcache, -1) == 0) diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 139cd49..18d060c 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -112,6 +112,7 @@ struct inferior_list_entry struct thread_info; struct process_info; struct regcache; +struct target_desc; #include "regcache.h" #include "gdb/signals.h" @@ -157,6 +158,8 @@ struct process_info /* The list of installed fast tracepoints. */ struct fast_tracepoint_jump *fast_tracepoint_jumps; + const struct target_desc *tdesc; + /* Private target data. */ struct process_info_private *private; }; @@ -431,6 +434,9 @@ void supply_static_tracepoint_registers (struct regcache *regcache, CORE_ADDR pc); void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg); + +extern const struct target_desc *ipa_tdesc; + #else void stop_tracing (void); diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index deaa115..6e3974a 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -56,7 +56,7 @@ int using_threads = 0; /* Defined in auto-generated file reg-spu.c. */ void init_registers_spu (void); - +extern const struct target_desc *tdesc_spu; /* Fetch PPU register REGNO. */ static CORE_ADDR @@ -266,6 +266,7 @@ spu_create_inferior (char *program, char **allargs) { int pid; ptid_t ptid; + struct process_info *proc; pid = fork (); if (pid < 0) @@ -287,7 +288,8 @@ spu_create_inferior (char *program, char **allargs) _exit (0177); } - add_process (pid, 0); + proc = add_process (pid, 0); + proc->tdesc = tdesc_spu; ptid = ptid_build (pid, pid, 0); add_thread (ptid, NULL); @@ -299,6 +301,7 @@ int spu_attach (unsigned long pid) { ptid_t ptid; + struct process_info *proc; if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0) { @@ -308,7 +311,8 @@ spu_attach (unsigned long pid) _exit (0177); } - add_process (pid, 1); + proc = add_process (pid, 1); + proc->tdesc = tdesc_spu; ptid = ptid_build (pid, pid, 0); add_thread (ptid, NULL); return 0; diff --git a/gdb/gdbserver/tdesc.c b/gdb/gdbserver/tdesc.c new file mode 100644 index 0000000..ac3c14a --- /dev/null +++ b/gdb/gdbserver/tdesc.c @@ -0,0 +1,66 @@ +/* Copyright (C) 2012-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#include "server.h" +#include "tdesc.h" +#include "regdef.h" + +void +init_target_desc (struct target_desc *tdesc) +{ + int offset, i; + + offset = 0; + for (i = 0; i < tdesc->num_registers; i++) + { + tdesc->reg_defs[i].offset = offset; + offset += tdesc->reg_defs[i].size; + } + + tdesc->registers_size = offset / 8; + + /* Make sure PBUFSIZ is large enough to hold a full register + packet. */ + if (2 * tdesc->registers_size + 32 > PBUFSIZ) + fatal ("Register packet size exceeds PBUFSIZ."); +} + +#ifndef IN_PROCESS_AGENT + +static const struct target_desc default_description; + +void +copy_target_description (struct target_desc *dest, + const struct target_desc *src) +{ + dest->reg_defs = src->reg_defs; + dest->num_registers = src->num_registers; + dest->expedite_regs = src->expedite_regs; + dest->registers_size = src->registers_size; + dest->xmltarget = src->xmltarget; +} + +const struct target_desc * +current_target_desc (void) +{ + if (current_inferior == NULL) + return &default_description; + + return current_process ()->tdesc; +} + +#endif diff --git a/gdb/gdbserver/tdesc.h b/gdb/gdbserver/tdesc.h new file mode 100644 index 0000000..f3d018d --- /dev/null +++ b/gdb/gdbserver/tdesc.h @@ -0,0 +1,64 @@ +/* Target description definitions for remote server for GDB. + Copyright (C) 2012-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef TDESC_H +#define TDESC_H + +struct reg; + +/* A target description. */ + +struct target_desc +{ + /* An array of NUM_REGISTERS elements of register definitions that + describe the inferior's register set. */ + struct reg *reg_defs; + + /* The number of registers in inferior's register set (and thus in + the regcache). */ + int num_registers; + + /* The register cache size, in bytes. */ + int registers_size; + + /* An array of register names. These are the "expedite" registers: + registers whose values are sent along with stop replies. */ + const char **expedite_regs; + + /* Defines what to return when looking for the "target.xml" file in + response to qXfer:features:read. Its contents can either be + verbatim XML code (prefixed with a '@') or else the name of the + actual XML file to be used in place of "target.xml". */ + const char *xmltarget; +}; + +/* Copy target description SRC to DEST. */ + +void copy_target_description (struct target_desc *dest, + const struct target_desc *src); + +/* Initialize TDESC. */ + +void init_target_desc (struct target_desc *tdesc); + +/* Return the current inferior's target description. Never returns + NULL. */ + +const struct target_desc *current_target_desc (void); + +#endif /* TDESC_H */ diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 1ff6114..d237e7f 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -29,6 +29,7 @@ #include <stdint.h> #include "ax.h" +#include "tdesc.h" #define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */ @@ -4675,6 +4676,14 @@ collect_data_at_step (struct tracepoint_hit_ctx *ctx, #endif +#ifdef IN_PROCESS_AGENT +/* The target description used by the IPA. Given that the IPA library + is built for a specific architecture that is loaded into the + inferior, there only needs to be one such description per + build. */ +const struct target_desc *ipa_tdesc; +#endif + static struct regcache * get_context_regcache (struct tracepoint_hit_ctx *ctx) { @@ -4687,7 +4696,7 @@ get_context_regcache (struct tracepoint_hit_ctx *ctx) if (!fctx->regcache_initted) { fctx->regcache_initted = 1; - init_register_cache (&fctx->regcache, fctx->regspace); + init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace); supply_regblock (&fctx->regcache, NULL); supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs); } @@ -4702,7 +4711,7 @@ get_context_regcache (struct tracepoint_hit_ctx *ctx) if (!sctx->regcache_initted) { sctx->regcache_initted = 1; - init_register_cache (&sctx->regcache, sctx->regspace); + init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace); supply_regblock (&sctx->regcache, NULL); /* Pass down the tracepoint address, because REGS doesn't include the PC, but we know what it must have been. */ @@ -4761,13 +4770,15 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, unsigned char *regspace; struct regcache tregcache; struct regcache *context_regcache; - + int regcache_size; trace_debug ("Want to collect registers"); + context_regcache = get_context_regcache (ctx); + regcache_size = register_cache_size (context_regcache->tdesc); + /* Collect all registers for now. */ - regspace = add_traceframe_block (tframe, tpoint, - 1 + register_cache_size ()); + regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size); if (regspace == NULL) { trace_debug ("Trace buffer block allocation failed, skipping"); @@ -4776,11 +4787,10 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, /* Identify a register block. */ *regspace = 'R'; - context_regcache = get_context_regcache (ctx); - /* Wrap the regblock in a register cache (in the stack, we don't want to malloc here). */ - init_register_cache (&tregcache, regspace + 1); + init_register_cache (&tregcache, context_regcache->tdesc, + regspace + 1); /* Copy the register data to the regblock. */ regcache_cpy (&tregcache, context_regcache); @@ -5083,7 +5093,7 @@ traceframe_walk_blocks (unsigned char *database, unsigned int datasize, { case 'R': /* Skip over the registers block. */ - dataptr += register_cache_size (); + dataptr += current_target_desc ()->registers_size; break; case 'M': /* Skip over the memory block. */ @@ -5178,12 +5188,13 @@ traceframe_get_pc (struct traceframe *tframe) { struct regcache regcache; unsigned char *dataptr; + const struct target_desc *tdesc = current_target_desc (); dataptr = traceframe_find_regblock (tframe, -1); if (dataptr == NULL) return 0; - init_register_cache (®cache, dataptr); + init_register_cache (®cache, tdesc, dataptr); return regcache_read_pc (®cache); } @@ -5737,7 +5748,7 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs) ctx.regcache_initted = 0; /* Wrap the regblock in a register cache (in the stack, we don't want to malloc here). */ - ctx.regspace = alloca (register_cache_size ()); + ctx.regspace = alloca (ipa_tdesc->registers_size); if (ctx.regspace == NULL) { trace_debug ("Trace buffer block allocation failed, skipping"); @@ -6597,7 +6608,7 @@ gdb_probe (const struct marker *mdata, void *probe_private, /* Wrap the regblock in a register cache (in the stack, we don't want to malloc here). */ - ctx.regspace = alloca (register_cache_size ()); + ctx.regspace = alloca (ipa_tdesc->registers_size); if (ctx.regspace == NULL) { trace_debug ("Trace buffer block allocation failed, skipping"); diff --git a/gdb/gdbserver/win32-arm-low.c b/gdb/gdbserver/win32-arm-low.c index 09ac1da..0f93ef0 100644 --- a/gdb/gdbserver/win32-arm-low.c +++ b/gdb/gdbserver/win32-arm-low.c @@ -24,7 +24,7 @@ /* Defined in auto-generated file reg-arm.c. */ void init_registers_arm (void); - +extern const struct target_desc *tdesc_arm; static void arm_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) @@ -108,12 +108,19 @@ arm_store_inferior_register (struct regcache *regcache, collect_register (regcache, r, regptr (&th->context, r)); } +static void +arm_arch_setup (void) +{ + init_registers_arm (); + win32_tdesc = tdesc_arm; +} + /* Correct in either endianness. We do not support Thumb yet. */ static const unsigned long arm_wince_breakpoint = 0xe6000010; #define arm_wince_breakpoint_len 4 struct win32_target_ops the_low_target = { - init_registers_arm, + arm_arch_setup, sizeof (mappings) / sizeof (mappings[0]), NULL, /* initial_stuff */ arm_get_thread_context, diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c index 1db9393..049e8a2 100644 --- a/gdb/gdbserver/win32-i386-low.c +++ b/gdb/gdbserver/win32-i386-low.c @@ -31,9 +31,11 @@ #ifdef __x86_64__ /* Defined in auto-generated file reg-amd64.c. */ void init_registers_amd64 (void); +extern const struct target_desc *tdesc_amd64; #else /* Defined in auto-generated file reg-i386.c. */ void init_registers_i386 (void); +extern const struct target_desc *tdesc_i386; #endif static struct i386_debug_reg_state debug_reg_state; @@ -399,17 +401,19 @@ static const unsigned char i386_win32_breakpoint = 0xcc; #define i386_win32_breakpoint_len 1 static void -init_windows_x86 (void) +i386_arch_setup (void) { #ifdef __x86_64__ init_registers_amd64 (); + win32_tdesc = tdesc_amd64; #else init_registers_i386 (); + win32_tdesc = tdesc_i386; #endif } struct win32_target_ops the_low_target = { - init_windows_x86, + i386_arch_setup, sizeof (mappings) / sizeof (mappings[0]), i386_initial_stuff, i386_get_thread_context, diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 2cb5465..d1caa73 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -87,6 +87,8 @@ static int soft_interrupt_requested = 0; by suspending all the threads. */ static int faked_breakpoint = 0; +const struct target_desc *win32_tdesc; + #define NUM_REGS (the_low_target.num_regs) typedef BOOL WINAPI (*winapi_DebugActiveProcessStop) (DWORD dwProcessId); @@ -193,9 +195,6 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; add_thread (ptid, th); - set_inferior_regcache_data ((struct thread_info *) - find_inferior_id (&all_threads, ptid), - new_register_cache ()); if (the_low_target.thread_added != NULL) (*the_low_target.thread_added) (th); @@ -308,6 +307,8 @@ child_init_thread_list (void) static void do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) { + struct process_info *proc; + last_sig = GDB_SIGNAL_0; current_process_handle = proch; @@ -319,7 +320,8 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) memset (¤t_event, 0, sizeof (current_event)); - add_process (pid, attached); + proc = add_process (pid, attached); + proc->tdesc = win32_tdesc; child_init_thread_list (); if (the_low_target.initial_stuff != NULL) diff --git a/gdb/gdbserver/win32-low.h b/gdb/gdbserver/win32-low.h index 4f262c2..718362e 100644 --- a/gdb/gdbserver/win32-low.h +++ b/gdb/gdbserver/win32-low.h @@ -18,6 +18,12 @@ #include <windows.h> +struct target_desc; + +/* The inferior's target description. This is a global because the + Windows ports support neither bi-arch nor multi-process. */ +extern const struct target_desc *win32_tdesc; + /* Thread information structure used to track extra information about each thread. */ typedef struct win32_thread_info diff --git a/gdb/regformats/regdat.sh b/gdb/regformats/regdat.sh index be4e01e..6256125 100755 --- a/gdb/regformats/regdat.sh +++ b/gdb/regformats/regdat.sh @@ -121,6 +121,7 @@ exec > new-$2 copyright $1 echo '#include "server.h"' echo '#include "regdef.h"' +echo '#include "tdesc.h"' echo offset=0 i=0 @@ -134,7 +135,7 @@ while do_read do if test "${type}" = "name"; then name="${entry}" - echo "struct reg regs_${name}[] = {" + echo "static struct reg regs_${name}[] = {" continue elif test "${type}" = "xmltarget"; then xmltarget="${entry}" @@ -160,12 +161,12 @@ done echo "};" echo -echo "const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };" +echo "static const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };" if test "${xmltarget}" = x; then if test "${xmlarch}" = x && test "${xmlosabi}" = x; then - echo "const char *xmltarget_${name} = 0;" + echo "static const char *xmltarget_${name} = 0;" else - echo "const char *xmltarget_${name} = \"@<target>\\" + echo "static const char *xmltarget_${name} = \"@<target>\\" if test "${xmlarch}" != x; then echo "<architecture>${xmlarch}</architecture>\\" fi @@ -175,18 +176,27 @@ if test "${xmltarget}" = x; then echo "</target>\";" fi else - echo "const char *xmltarget_${name} = \"${xmltarget}\";" + echo "static const char *xmltarget_${name} = \"${xmltarget}\";" fi echo cat <<EOF +const struct target_desc *tdesc_${name}; + void -init_registers_${name} () +init_registers_${name} (void) { - set_register_cache (regs_${name}, - sizeof (regs_${name}) / sizeof (regs_${name}[0])); - gdbserver_expedite_regs = expedite_regs_${name}; - gdbserver_xmltarget = xmltarget_${name}; + static struct target_desc tdesc_${name}_s; + struct target_desc *result = &tdesc_${name}_s; + + result->reg_defs = regs_${name}; + result->num_registers = sizeof (regs_${name}) / sizeof (regs_${name}[0]); + result->expedite_regs = expedite_regs_${name}; + result->xmltarget = xmltarget_${name}; + + init_target_desc (result); + + tdesc_${name} = result; } EOF |