diff options
author | Pedro Alves <palves@redhat.com> | 2013-06-07 10:46:59 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2013-06-07 10:46:59 +0000 |
commit | 3aee891821f538cfb4e0a08a26196c70127f1474 (patch) | |
tree | d95b92cc7d2515eab018d1f19cd8e2f37338442d /gdb | |
parent | 88ab56844a4b8155cd5f2491de5e12a57d24c089 (diff) | |
download | gdb-3aee891821f538cfb4e0a08a26196c70127f1474.zip gdb-3aee891821f538cfb4e0a08a26196c70127f1474.tar.gz gdb-3aee891821f538cfb4e0a08a26196c70127f1474.tar.bz2 |
[GDBserver] Multi-process + multi-arch
This patch makes GDBserver support multi-process + biarch.
Currently, if you're debugging more than one process at once with a
single gdbserver (in extended-remote mode), then all processes must
have the same architecture (e.g., 64-bit vs 32-bit). Otherwise, you
see this:
Added inferior 2
[Switching to inferior 2 [<null>] (<noexec>)]
Reading symbols from /home/pedro/gdb/tests/main32...done.
Temporary breakpoint 2 at 0x4004cf: main. (2 locations)
Starting program: /home/pedro/gdb/tests/main32
warning: Selected architecture i386 is not compatible with reported target architecture i386:x86-64
warning: Architecture rejected target-supplied description
Remote 'g' packet reply is too long: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090cfffff0000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000b042f7460000000000020000230000002b0000002b0000002b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f00003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
... etc, etc ...
Even though the process was running a 32-bit program, GDBserver sent
back to GDB a register set in 64-bit layout.
A patch (http://sourceware.org/ml/gdb-patches/2012-11/msg00228.html) a
while ago made GDB track a target_gdbarch per inferior, and as
consequence, fetch a target description per-inferior. This patch is
the GDBserver counterpart, that makes GDBserver keep track of each
process'es XML target description and register layout. So in the
example above, GDBserver will send the correct register set in 32-bit
layout to GDB.
A new "struct target_desc" object (tdesc for short) is added, that
holds the target description and register layout information about
each process. Each `struct process_info' holds a pointer to a target
description. The regcache also gains a pointer to a target
description, mainly for convenience, and parallel with GDB (and
possible future support for programs that flip processor modes).
The low target's arch_setup routines are responsible for setting the
process'es correct tdesc. This isn't that much different to how
things were done before, except that instead of detecting the inferior
process'es architecture and calling the corresponding
init_registers_FOO routine, which would change the regcache layout
globals and recreate the threads' regcaches, the regcache.c globals
are gone, and the init_registers_$BAR routines now each initialize a
separate global struct target_desc object (one for each arch variant
GDBserver supports), and so all the init_registers_$BAR routines that
are built into GDBserver are called early at GDBserver startup time
(similarly to how GDB handles its built-in target descriptions), and
then the arch_setup routine is responsible for making
process_info->tdesc point to one of these target description globals.
The regcache module is all parameterized to get the regcache's layout
from the tdesc object instead of the old register_bytes, etc. globals.
The threads' regcaches are now created lazily. The old scheme where
we created each of them when we added a new thread doesn't work
anymore, because we add the main thread/lwp before we see it stop for
the first time, and it is only when we see the thread stop for the
first time that we have a chance of determining the inferior's
architecture (through the_low_target.arch_setup). Therefore when we
add the main thread we don't know which architecture/tdesc its
regcache should have.
This patch makes the gdb.multi/multi-arch.exp test now pass against
(extended-remote) GDBserver. It currently fails, without this patch.
The IPA also uses the regcache, so it gains a new global struct
target_desc pointer, which points at the description of the process it
is loaded in.
Re. the linux-low.c & friends changes. Since the register map
etc. may differ between processes (64-bit vs 32-bit) etc., the
linux_target_ops num_regs, regmap and regset_bitmap data fields are no
longer sufficient. A new method is added in their place that returns
a pointer to a new struct that includes all info linux-low.c needs to
access registers of the current inferior.
The patch/discussion that originally introduced
linux-low.c:disabled_regsets mentions that the disabled_regsets set
may be different per mode (in a biarch setup), and indeed that is
cleared whenever we start a new (first) inferior, so that global is
moved as well behind the new `struct regs_info'.
On the x86 side:
I simply replaced the i387-fp.c:num_xmm_registers global with a check
for 64-bit or 32-bit process, which is equivalent to how the global
was set. This avoided coming up with some more general mechanism that
would work for all targets that use this module (GNU/Linux, Windows,
etc.).
Tested:
GNU/Linux IA64
GNU/Linux MIPS64
GNU/Linux PowerPC (Fedora 16)
GNU/Linux s390x (Fedora 16)
GNU/Linux sparc64 (Debian)
GNU/Linux x86_64, -m64 and -m32 (Fedora 17)
Cross built, and smoke tested:
i686-w64-mingw32, under Wine.
GNU/Linux TI C6x, by Yao Qi.
Cross built but otherwise not tested:
aarch64-linux-gnu
arm-linux-gnu
m68k-linux
nios2-linux-gnu
sh-linux-gnu
spu
tilegx-unknown-linux-gnu
Completely untested:
GNU/Linux Blackfin
GNU/Linux CRIS
GNU/Linux CRISv32
GNU/Linux TI Xtensa
GNU/Linux M32R
LynxOS
QNX NTO
gdb/gdbserver/
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'.
gdb/
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.
Diffstat (limited to 'gdb')
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 |