mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-28 20:43:45 +08:00
481695ed5f
These prototypes were required when compiling GDB as C but are not required for C++. gdb/ChangeLog: * aarch64-linux-nat.c: Remove _initialize_aarch64_linux_nat prototype. * aarch64-linux-tdep.c: Remove _initialize_aarch64_linux_tdep prototype. * aarch64-newlib-tdep.c: Remove _initialize_aarch64_newlib_tdep prototype. * aarch64-tdep.c: Remove _initialize_aarch64_tdep prototype. * ada-exp.y: Remove _initialize_ada_exp prototype. * ada-lang.c: Remove _initialize_ada_language prototype. * ada-tasks.c: Remove _initialize_tasks prototype. * addrmap.c: Remove _initialize_addrmap prototype. * agent.c: Remove _initialize_agent prototype. * aix-thread.c: Remove _initialize_aix_thread prototype. * alpha-bsd-nat.c: Remove _initialize_alphabsd_nat prototype. * alpha-linux-nat.c: Remove _initialize_alpha_linux_nat prototype. * alpha-linux-tdep.c: Remove _initialize_alpha_linux_tdep prototype. * alpha-nbsd-tdep.c: Remove _initialize_alphanbsd_tdep prototype. * alpha-obsd-tdep.c: Remove _initialize_alphaobsd_tdep prototype. * alpha-tdep.c: Remove _initialize_alpha_tdep prototype. * amd64-darwin-tdep.c: Remove _initialize_amd64_darwin_tdep prototype. * amd64-dicos-tdep.c: Remove _initialize_amd64_dicos_tdep prototype. * amd64-fbsd-nat.c: Remove _initialize_amd64fbsd_nat prototype. * amd64-fbsd-tdep.c: Remove _initialize_amd64fbsd_tdep prototype. * amd64-linux-nat.c: Remove _initialize_amd64_linux_nat prototype. * amd64-linux-tdep.c: Remove _initialize_amd64_linux_tdep prototype. * amd64-nbsd-nat.c: Remove _initialize_amd64nbsd_nat prototype. * amd64-nbsd-tdep.c: Remove _initialize_amd64nbsd_tdep prototype. * amd64-obsd-nat.c: Remove _initialize_amd64obsd_nat prototype. * amd64-obsd-tdep.c: Remove _initialize_amd64obsd_tdep prototype. * amd64-sol2-tdep.c: Remove _initialize_amd64_sol2_tdep prototype. * amd64-tdep.c: Remove _initialize_amd64_tdep prototype. * amd64-windows-nat.c: Remove _initialize_amd64_windows_nat prototype. * amd64-windows-tdep.c: Remove _initialize_amd64_windows_tdep prototype. * annotate.c: Remove _initialize_annotate prototype. * arc-newlib-tdep.c: Remove _initialize_arc_newlib_tdep prototype. * arc-tdep.c: Remove _initialize_arc_tdep prototype. * arch-utils.c: Remove _initialize_gdbarch_utils prototype. * arm-linux-nat.c: Remove _initialize_arm_linux_nat prototype. * arm-linux-tdep.c: Remove _initialize_arm_linux_tdep prototype. * arm-nbsd-tdep.c: Remove _initialize_arm_netbsd_tdep prototype. * arm-obsd-tdep.c: Remove _initialize_armobsd_tdep prototype. * arm-symbian-tdep.c: Remove _initialize_arm_symbian_tdep prototype. * arm-tdep.c: Remove _initialize_arm_tdep prototype. * arm-wince-tdep.c: Remove _initialize_arm_wince_tdep prototype. * auto-load.c: Remove _initialize_auto_load prototype. * auxv.c: Remove _initialize_auxv prototype. * avr-tdep.c: Remove _initialize_avr_tdep prototype. * ax-gdb.c: Remove _initialize_ax_gdb prototype. * bfin-linux-tdep.c: Remove _initialize_bfin_linux_tdep prototype. * bfin-tdep.c: Remove _initialize_bfin_tdep prototype. * break-catch-sig.c: Remove _initialize_break_catch_sig prototype. * break-catch-syscall.c: Remove _initialize_break_catch_syscall prototype. * break-catch-throw.c: Remove _initialize_break_catch_throw prototype. * breakpoint.c: Remove _initialize_breakpoint prototype. * bsd-uthread.c: Remove _initialize_bsd_uthread prototype. * btrace.c: Remove _initialize_btrace prototype. * charset.c: Remove _initialize_charset prototype. * cli/cli-cmds.c: Remove _initialize_cli_cmds prototype. * cli/cli-dump.c: Remove _initialize_cli_dump prototype. * cli/cli-interp.c: Remove _initialize_cli_interp prototype. * cli/cli-logging.c: Remove _initialize_cli_logging prototype. * cli/cli-script.c: Remove _initialize_cli_script prototype. * coff-pe-read.c: Remove _initialize_coff_pe_read prototype. * coffread.c: Remove _initialize_coffread prototype. * compile/compile.c: Remove _initialize_compile prototype. * complaints.c: Remove _initialize_complaints prototype. * completer.c: Remove _initialize_completer prototype. * copying.awk: Remove _initialize_copying prototype. * copying.c: Regenerate. * core-regset.c: Remove _initialize_core_regset prototype. * corefile.c: Remove _initialize_core prototype. * corelow.c: Remove _initialize_corelow prototype. * cp-abi.c: Remove _initialize_cp_abi prototype. * cp-namespace.c: Remove _initialize_cp_namespace prototype. * cp-support.c: Remove _initialize_cp_support prototype. * cp-valprint.c: Remove _initialize_cp_valprint prototype. * cris-linux-tdep.c: Remove _initialize_cris_linux_tdep prototype. * cris-tdep.c: Remove _initialize_cris_tdep prototype. * ctf.c: Remove _initialize_ctf prototype. * d-lang.c: Remove _initialize_d_language prototype. * darwin-nat-info.c: Remove _initialize_darwin_info_commands prototype. * darwin-nat.c: Remove _initialize_darwin_inferior prototype. * dbxread.c: Remove _initialize_dbxread prototype. * dcache.c: Remove _initialize_dcache prototype. * demangle.c: Remove _initialize_demangler prototype. * disasm-selftests.c: Remove _initialize_disasm_selftests prototype. * disasm.c: Remove _initialize_disasm prototype. * dtrace-probe.c: Remove _initialize_dtrace_probe prototype. * dummy-frame.c: Remove _initialize_dummy_frame prototype. * dwarf2-frame-tailcall.c: Remove _initialize_tailcall_frame prototype. * dwarf2-frame.c: Remove _initialize_dwarf2_frame prototype. * dwarf2expr.c: Remove _initialize_dwarf2expr prototype. * dwarf2loc.c: Remove _initialize_dwarf2loc prototype. * dwarf2read.c: Remove _initialize_dwarf2_read prototype. * elfread.c: Remove _initialize_elfread prototype. * exec.c: Remove _initialize_exec prototype. * extension.c: Remove _initialize_extension prototype. * f-lang.c: Remove _initialize_f_language prototype. * f-valprint.c: Remove _initialize_f_valprint prototype. * fbsd-nat.c: Remove _initialize_fbsd_nat prototype. * fbsd-tdep.c: Remove _initialize_fbsd_tdep prototype. * filesystem.c: Remove _initialize_filesystem prototype. * findcmd.c: Remove _initialize_mem_search prototype. * fork-child.c: Remove _initialize_fork_child prototype. * frame-base.c: Remove _initialize_frame_base prototype. * frame-unwind.c: Remove _initialize_frame_unwind prototype. * frame.c: Remove _initialize_frame prototype. * frv-linux-tdep.c: Remove _initialize_frv_linux_tdep prototype. * frv-tdep.c: Remove _initialize_frv_tdep prototype. * ft32-tdep.c: Remove _initialize_ft32_tdep prototype. * gcore.c: Remove _initialize_gcore prototype. * gdb_bfd.c: Remove _initialize_gdb_bfd prototype. * gdbarch.c: Regenerate. * gdbarch.sh: Remove _initialize_gdbarch prototype. * gdbtypes.c: Remove _initialize_gdbtypes prototype. * gnu-nat.c: Remove _initialize_gnu_nat prototype. * gnu-v2-abi.c: Remove _initialize_gnu_v2_abi prototype. * gnu-v3-abi.c: Remove _initialize_gnu_v3_abi prototype. * go-lang.c: Remove _initialize_go_language prototype. * go32-nat.c: Remove _initialize_go32_nat prototype. * guile/guile.c: Remove _initialize_guile prototype. * h8300-tdep.c: Remove _initialize_h8300_tdep prototype. * hppa-linux-nat.c: Remove _initialize_hppa_linux_nat prototype. * hppa-linux-tdep.c: Remove _initialize_hppa_linux_tdep prototype. * hppa-nbsd-nat.c: Remove _initialize_hppanbsd_nat prototype. * hppa-nbsd-tdep.c: Remove _initialize_hppanbsd_tdep prototype. * hppa-obsd-nat.c: Remove _initialize_hppaobsd_nat prototype. * hppa-obsd-tdep.c: Remove _initialize_hppaobsd_tdep prototype. * hppa-tdep.c: Remove _initialize_hppa_tdep prototype. * i386-bsd-nat.c: Remove _initialize_i386bsd_nat prototype. * i386-cygwin-tdep.c: Remove _initialize_i386_cygwin_tdep prototype. * i386-darwin-tdep.c: Remove _initialize_i386_darwin_tdep prototype. * i386-dicos-tdep.c: Remove _initialize_i386_dicos_tdep prototype. * i386-fbsd-nat.c: Remove _initialize_i386fbsd_nat prototype. * i386-fbsd-tdep.c: Remove _initialize_i386fbsd_tdep prototype. * i386-gnu-nat.c: Remove _initialize_i386gnu_nat prototype. * i386-gnu-tdep.c: Remove _initialize_i386gnu_tdep prototype. * i386-linux-nat.c: Remove _initialize_i386_linux_nat prototype. * i386-linux-tdep.c: Remove _initialize_i386_linux_tdep prototype. * i386-nbsd-nat.c: Remove _initialize_i386nbsd_nat prototype. * i386-nbsd-tdep.c: Remove _initialize_i386nbsd_tdep prototype. * i386-nto-tdep.c: Remove _initialize_i386nto_tdep prototype. * i386-obsd-nat.c: Remove _initialize_i386obsd_nat prototype. * i386-obsd-tdep.c: Remove _initialize_i386obsd_tdep prototype. * i386-sol2-nat.c: Remove _initialize_amd64_sol2_nat prototype. * i386-sol2-tdep.c: Remove _initialize_amd64_sol2_tdep prototype. * i386-tdep.c: Remove _initialize_i386_tdep prototype. * i386-windows-nat.c: Remove _initialize_i386_windows_nat prototype. * ia64-libunwind-tdep.c: Remove _initialize_libunwind_frame prototype. * ia64-linux-nat.c: Remove _initialize_ia64_linux_nat prototype. * ia64-linux-tdep.c: Remove _initialize_ia64_linux_tdep prototype. * ia64-tdep.c: Remove _initialize_ia64_tdep prototype. * ia64-vms-tdep.c: Remove _initialize_ia64_vms_tdep prototype. * infcall.c: Remove _initialize_infcall prototype. * infcmd.c: Remove _initialize_infcmd prototype. * inferior.c: Remove _initialize_inferiors prototype. * inflow.c: Remove _initialize_inflow prototype. * infrun.c: Remove _initialize_infrun prototype. * interps.c: Remove _initialize_interpreter prototype. * iq2000-tdep.c: Remove _initialize_iq2000_tdep prototype. * jit.c: Remove _initialize_jit prototype. * language.c: Remove _initialize_language prototype. * linux-fork.c: Remove _initialize_linux_fork prototype. * linux-nat.c: Remove _initialize_linux_nat prototype. * linux-tdep.c: Remove _initialize_linux_tdep prototype. * linux-thread-db.c: Remove _initialize_thread_db prototype. * lm32-tdep.c: Remove _initialize_lm32_tdep prototype. * m2-lang.c: Remove _initialize_m2_language prototype. * m32c-tdep.c: Remove _initialize_m32c_tdep prototype. * m32r-linux-nat.c: Remove _initialize_m32r_linux_nat prototype. * m32r-linux-tdep.c: Remove _initialize_m32r_linux_tdep prototype. * m32r-tdep.c: Remove _initialize_m32r_tdep prototype. * m68hc11-tdep.c: Remove _initialize_m68hc11_tdep prototype. * m68k-bsd-nat.c: Remove _initialize_m68kbsd_nat prototype. * m68k-bsd-tdep.c: Remove _initialize_m68kbsd_tdep prototype. * m68k-linux-nat.c: Remove _initialize_m68k_linux_tdep prototype. * m68k-linux-tdep.c: Remove _initialize_m68k_linux_tdep prototype. * m68k-tdep.c: Remove _initialize_m68k_tdep prototype. * m88k-bsd-nat.c: Remove _initialize_m68kbsd_nat prototype. * m88k-tdep.c: Remove _initialize_m68kbsd_tdep prototype. * machoread.c: Remove _initialize_machoread prototype. * macrocmd.c: Remove _initialize_macrocmd prototype. * macroscope.c: Remove _initialize_macroscope prototype. * maint.c: Remove _initialize_maint_cmds prototype. * mdebugread.c: Remove _initialize_mdebugread prototype. * memattr.c: Remove _initialize_mem prototype. * mep-tdep.c: Remove _initialize_mep_tdep prototype. * mi/mi-cmd-env.c: Remove _initialize_mi_cmd_env prototype. * mi/mi-cmds.c: Remove _initialize_mi_cmds prototype. * mi/mi-interp.c: Remove _initialize_mi_interp prototype. * mi/mi-main.c: Remove _initialize_mi_main prototype. * microblaze-linux-tdep.c: Remove _initialize_microblaze_linux_tdep prototype. * microblaze-tdep.c: Remove _initialize_microblaze_tdep prototype. * mips-fbsd-nat.c: Remove _initialize_mips_fbsd_nat prototype. * mips-fbsd-tdep.c: Remove _initialize_mips_fbsd_tdep prototype. * mips-linux-nat.c: Remove _initialize_mips_linux_nat prototype. * mips-linux-tdep.c: Remove _initialize_mips_linux_tdep prototype. * mips-nbsd-nat.c: Remove _initialize_mipsnbsd_nat prototype. * mips-nbsd-tdep.c: Remove _initialize_mipsnbsd_tdep prototype. * mips-sde-tdep.c: Remove _initialize_mips_sde_tdep prototype. * mips-tdep.c: Remove _initialize_mips_tdep prototype. * mips64-obsd-nat.c: Remove _initialize_mips64obsd_nat prototype. * mips64-obsd-tdep.c: Remove _initialize_mips64obsd_tdep prototype. * mipsread.c: Remove _initialize_mipsread prototype. * mn10300-linux-tdep.c: Remove _initialize_mn10300_linux_tdep prototype. * mn10300-tdep.c: Remove _initialize_mn10300_tdep prototype. * moxie-tdep.c: Remove _initialize_moxie_tdep prototype. * msp430-tdep.c: Remove _initialize_msp430_tdep prototype. * mt-tdep.c: Remove _initialize_mt_tdep prototype. * nds32-tdep.c: Remove _initialize_nds32_tdep prototype. * nios2-linux-tdep.c: Remove _initialize_nios2_linux_tdep prototype. * nios2-tdep.c: Remove _initialize_nios2_tdep prototype. * nto-procfs.c: Remove _initialize_procfs prototype. * nto-tdep.c: Remove _initialize_nto_tdep prototype. * objc-lang.c: Remove _initialize_objc_language prototype. * objfiles.c: Remove _initialize_objfiles prototype. * observer.c: Remove observer_test_first_notification_function, observer_test_second_notification_function, observer_test_third_notification_function, and _initialize_observer prototypes. * opencl-lang.c: Remove _initialize_opencl_language prototypes. * osabi.c: Remove _initialize_gdb_osabi prototype. * osdata.c: Remove _initialize_osdata prototype. * p-valprint.c: Remove _initialize_pascal_valprint prototype. * parse.c: Remove _initialize_parse prototype. * ppc-fbsd-nat.c: Remove _initialize_ppcfbsd_nat prototype. * ppc-fbsd-tdep.c: Remove _initialize_ppcfbsd_tdep prototype. * ppc-linux-nat.c: Remove _initialize_ppc_linux_nat prototype. * ppc-linux-tdep.c: Remove _initialize_ppc_linux_tdep prototype. * ppc-nbsd-nat.c: Remove _initialize_ppcnbsd_nat prototype. * ppc-nbsd-tdep.c: Remove _initialize_ppcnbsd_tdep prototype. * ppc-obsd-nat.c: Remove _initialize_ppcobsd_nat prototype. * ppc-obsd-tdep.c: Remove _initialize_ppcobsd_tdep prototype. * printcmd.c: Remove _initialize_printcmd prototype. * probe.c: Remove _initialize_probe prototype. * proc-api.c: Remove _initialize_proc_api prototype. * proc-events.c: Remove _initialize_proc_events prototype. * proc-service.c: Remove _initialize_proc_service prototype. * procfs.c: Remove _initialize_procfs prototype. * psymtab.c: Remove _initialize_psymtab prototype. * python/python.c: Remove _initialize_python prototype. * ravenscar-thread.c: Remove _initialize_ravenscar prototype. * record-btrace.c: Remove _initialize_record_btrace prototype. * record-full.c: Remove _initialize_record_full prototype. * record.c: Remove _initialize_record prototype. * regcache.c: Remove _initialize_regcache prototype. * reggroups.c: Remove _initialize_reggroup prototype. * remote-notif.c: Remove _initialize_notif prototype. * remote-sim.c: Remove _initialize_remote_sim prototype. * remote.c: Remove _initialize_remote prototype. * reverse.c: Remove _initialize_reverse prototype. * rl78-tdep.c: Remove _initialize_rl78_tdep prototype. * rs6000-aix-tdep.c: Remove _initialize_rs6000_aix_tdep prototype. * rs6000-lynx178-tdep.c: Remove _initialize_rs6000_lynx178_tdep prototype. * rs6000-nat.c: Remove _initialize_rs6000_nat prototype. * rs6000-tdep.c: Remove _initialize_rs6000_tdep prototype. * rust-exp.y: Remove _initialize_rust_exp prototype. * rx-tdep.c: Remove _initialize_rx_tdep prototype. * s390-linux-nat.c: Remove _initialize_s390_nat prototype. * s390-linux-tdep.c: Remove _initialize_s390_tdep prototype. * score-tdep.c: Remove _initialize_score_tdep prototype. * selftest-arch.c: Remove _initialize_selftests_foreach_arch prototype. * ser-go32.c: Remove _initialize_ser_dos prototype. * ser-mingw.c: Remove _initialize_ser_windows prototype. * ser-pipe.c: Remove _initialize_ser_pipe prototype. * ser-tcp.c: Remove _initialize_ser_tcp prototype. * ser-unix.c: Remove _initialize_ser_hardwire prototype. * serial.c: Remove _initialize_serial prototype. * sh-linux-tdep.c: Remove _initialize_sh_linux_tdep prototype. * sh-nbsd-nat.c: Remove _initialize_shnbsd_nat prototype. * sh-nbsd-tdep.c: Remove _initialize_shnbsd_tdep prototype. * sh-tdep.c: Remove _initialize_sh_tdep prototype. * skip.c: Remove _initialize_step_skip prototype. * sol-thread.c: Remove _initialize_sol_thread prototype. * solib-aix.c: Remove _initialize_solib_aix prototype. * solib-darwin.c: Remove _initialize_darwin_solib prototype. * solib-dsbt.c: Remove _initialize_dsbt_solib prototype. * solib-frv.c: Remove _initialize_frv_solib prototype. * solib-spu.c: Remove _initialize_spu_solib prototype. * solib-svr4.c: Remove _initialize_svr4_solib prototype. * solib-target.c: Remove _initialize_solib_target prototype. * solib.c: Remove _initialize_solib prototype. * source.c: Remove _initialize_source prototype. * sparc-linux-nat.c: Remove _initialize_sparc_linux_nat prototype. * sparc-linux-tdep.c: Remove _initialize_sparc_linux_tdep prototype. * sparc-nat.c: Remove _initialize_sparc_nat prototype. * sparc-nbsd-nat.c: Remove _initialize_sparcnbsd_nat prototype. * sparc-nbsd-tdep.c: Remove _initialize_sparcnbsd_tdep prototype. * sparc-obsd-tdep.c: Remove _initialize_sparc32obsd_tdep prototype. * sparc-sol2-nat.c: Remove _initialize_sparc_sol2_nat prototype. * sparc-sol2-tdep.c: Remove _initialize_sparc_sol2_tdep prototype. * sparc-tdep.c: Remove _initialize_sparc_tdep prototype. * sparc64-fbsd-nat.c: Remove _initialize_sparc64fbsd_nat prototype. * sparc64-fbsd-tdep.c: Remove _initialize_sparc64fbsd_tdep prototype. * sparc64-linux-nat.c: Remove _initialize_sparc64_linux_nat prototype. * sparc64-linux-tdep.c: Remove _initialize_sparc64_linux_tdep prototype. * sparc64-nat.c: Remove _initialize_sparc64_nat prototype. * sparc64-nbsd-nat.c: Remove _initialize_sparc64nbsd_nat prototype. * sparc64-nbsd-tdep.c: Remove _initialize_sparc64nbsd_tdep prototype. * sparc64-obsd-nat.c: Remove _initialize_sparc64obsd_nat prototype. * sparc64-obsd-tdep.c: Remove _initialize_sparc64obsd_tdep prototype. * sparc64-sol2-tdep.c: Remove _initialize_sparc64_sol2_tdep prototype. * spu-linux-nat.c: Remove _initialize_spu_nat prototype. * spu-multiarch.c: Remove _initialize_spu_multiarch prototype. * spu-tdep.c: Remove _initialize_spu_tdep prototype. * stabsread.c: Remove _initialize_stabsread prototype. * stack.c: Remove _initialize_stack prototype. * stap-probe.c: Remove _initialize_stap_probe prototype. * std-regs.c: Remove _initialize_frame_reg prototype. * symfile-debug.c: Remove _initialize_symfile_debug prototype. * symfile-mem.c: Remove _initialize_symfile_mem prototype. * symfile.c: Remove _initialize_symfile prototype. * symmisc.c: Remove _initialize_symmisc prototype. * symtab.c: Remove _initialize_symtab prototype. * target-dcache.c: Remove _initialize_target_dcache prototype. * target-descriptions.c: Remove _initialize_target_descriptions prototype. * thread.c: Remove _initialize_thread prototype. * tic6x-linux-tdep.c: Remove _initialize_tic6x_linux_tdep prototype. * tic6x-tdep.c: Remove _initialize_tic6x_tdep prototype. * tilegx-linux-nat.c: Remove _initialize_tile_linux_nat prototype. * tilegx-linux-tdep.c: Remove _initialize_tilegx_linux_tdep prototype. * tilegx-tdep.c: Remove _initialize_tilegx_tdep prototype. * tracefile-tfile.c: Remove _initialize_tracefile_tfile prototype. * tracefile.c: Remove _initialize_tracefile prototype. * tracepoint.c: Remove _initialize_tracepoint prototype. * tui/tui-hooks.c: Remove _initialize_tui_hooks prototype. * tui/tui-interp.c: Remove _initialize_tui_interp prototype. * tui/tui-layout.c: Remove _initialize_tui_layout prototype. * tui/tui-regs.c: Remove _initialize_tui_regs prototype. * tui/tui-stack.c: Remove _initialize_tui_stack prototype. * tui/tui-win.c: Remove _initialize_tui_win prototype. * tui/tui.c: Remove _initialize_tui prototype. * typeprint.c: Remove _initialize_typeprint prototype. * user-regs.c: Remove _initialize_user_regs prototype. * utils.c: Remove _initialize_utils prototype. * v850-tdep.c: Remove _initialize_v850_tdep prototype. * valarith.c: Remove _initialize_valarith prototype. * valops.c: Remove _initialize_valops prototype. * valprint.c: Remove _initialize_valprint prototype. * value.c: Remove _initialize_values prototype. * varobj.c: Remove _initialize_varobj prototype. * vax-bsd-nat.c: Remove _initialize_vaxbsd_nat prototype. * vax-nbsd-tdep.c: Remove _initialize_vaxnbsd_tdep prototype. * vax-tdep.c: Remove _initialize_vax_tdep prototype. * windows-nat.c: Remove _initialize_windows_nat, _initialize_check_for_gdb_ini, and _initialize_loadable prototypes. * windows-tdep.c: Remove _initialize_windows_tdep prototype. * xcoffread.c: Remove _initialize_xcoffread prototype. * xml-support.c: Remove _initialize_xml_support prototype. * xstormy16-tdep.c: Remove _initialize_xstormy16_tdep prototype. * xtensa-linux-nat.c: Remove _initialize_xtensa_linux_nat prototype. * xtensa-linux-tdep.c: Remove _initialize_xtensa_linux_tdep prototype. * xtensa-tdep.c: Remove _initialize_xtensa_tdep prototype.
1322 lines
36 KiB
C
1322 lines
36 KiB
C
/* GNU/Linux on ARM native support.
|
|
Copyright (C) 1999-2017 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 "defs.h"
|
|
#include "inferior.h"
|
|
#include "gdbcore.h"
|
|
#include "regcache.h"
|
|
#include "target.h"
|
|
#include "linux-nat.h"
|
|
#include "target-descriptions.h"
|
|
#include "auxv.h"
|
|
#include "observer.h"
|
|
#include "gdbthread.h"
|
|
|
|
#include "arm-tdep.h"
|
|
#include "arm-linux-tdep.h"
|
|
#include "aarch32-linux-nat.h"
|
|
|
|
#include <elf/common.h>
|
|
#include <sys/user.h>
|
|
#include "nat/gdb_ptrace.h"
|
|
#include <sys/utsname.h>
|
|
#include <sys/procfs.h>
|
|
|
|
#include "nat/linux-ptrace.h"
|
|
|
|
/* Prototypes for supply_gregset etc. */
|
|
#include "gregset.h"
|
|
|
|
/* Defines ps_err_e, struct ps_prochandle. */
|
|
#include "gdb_proc_service.h"
|
|
|
|
#ifndef PTRACE_GET_THREAD_AREA
|
|
#define PTRACE_GET_THREAD_AREA 22
|
|
#endif
|
|
|
|
#ifndef PTRACE_GETWMMXREGS
|
|
#define PTRACE_GETWMMXREGS 18
|
|
#define PTRACE_SETWMMXREGS 19
|
|
#endif
|
|
|
|
#ifndef PTRACE_GETVFPREGS
|
|
#define PTRACE_GETVFPREGS 27
|
|
#define PTRACE_SETVFPREGS 28
|
|
#endif
|
|
|
|
#ifndef PTRACE_GETHBPREGS
|
|
#define PTRACE_GETHBPREGS 29
|
|
#define PTRACE_SETHBPREGS 30
|
|
#endif
|
|
|
|
extern int arm_apcs_32;
|
|
|
|
/* Get the whole floating point state of the process and store it
|
|
into regcache. */
|
|
|
|
static void
|
|
fetch_fpregs (struct regcache *regcache)
|
|
{
|
|
int ret, regno, tid;
|
|
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
/* Read the floating point state. */
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = &fp;
|
|
iov.iov_len = ARM_LINUX_SIZEOF_NWFPE;
|
|
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PT_GETFPREGS, tid, 0, fp);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch the floating point registers."));
|
|
|
|
/* Fetch fpsr. */
|
|
regcache_raw_supply (regcache, ARM_FPS_REGNUM,
|
|
fp + NWFPE_FPSR_OFFSET);
|
|
|
|
/* Fetch the floating point registers. */
|
|
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
|
supply_nwfpe_register (regcache, regno, fp);
|
|
}
|
|
|
|
/* Save the whole floating point state of the process using
|
|
the contents from regcache. */
|
|
|
|
static void
|
|
store_fpregs (const struct regcache *regcache)
|
|
{
|
|
int ret, regno, tid;
|
|
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
/* Read the floating point state. */
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
elf_fpregset_t fpregs;
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = &fpregs;
|
|
iov.iov_len = sizeof (fpregs);
|
|
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PT_GETFPREGS, tid, 0, fp);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch the floating point registers."));
|
|
|
|
/* Store fpsr. */
|
|
if (REG_VALID == regcache_register_status (regcache, ARM_FPS_REGNUM))
|
|
regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
|
|
|
|
/* Store the floating point registers. */
|
|
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
|
if (REG_VALID == regcache_register_status (regcache, regno))
|
|
collect_nwfpe_register (regcache, regno, fp);
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = &fp;
|
|
iov.iov_len = ARM_LINUX_SIZEOF_NWFPE;
|
|
|
|
ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to store floating point registers."));
|
|
}
|
|
|
|
/* Fetch all general registers of the process and store into
|
|
regcache. */
|
|
|
|
static void
|
|
fetch_regs (struct regcache *regcache)
|
|
{
|
|
int ret, regno, tid;
|
|
elf_gregset_t regs;
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = ®s;
|
|
iov.iov_len = sizeof (regs);
|
|
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch general registers."));
|
|
|
|
aarch32_gp_regcache_supply (regcache, (uint32_t *) regs, arm_apcs_32);
|
|
}
|
|
|
|
static void
|
|
store_regs (const struct regcache *regcache)
|
|
{
|
|
int ret, regno, tid;
|
|
elf_gregset_t regs;
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
/* Fetch the general registers. */
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = ®s;
|
|
iov.iov_len = sizeof (regs);
|
|
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch general registers."));
|
|
|
|
aarch32_gp_regcache_collect (regcache, (uint32_t *) regs, arm_apcs_32);
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = ®s;
|
|
iov.iov_len = sizeof (regs);
|
|
|
|
ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to store general registers."));
|
|
}
|
|
|
|
/* Fetch all WMMX registers of the process and store into
|
|
regcache. */
|
|
|
|
#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
|
|
|
|
static void
|
|
fetch_wmmx_regs (struct regcache *regcache)
|
|
{
|
|
char regbuf[IWMMXT_REGS_SIZE];
|
|
int ret, regno, tid;
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch WMMX registers."));
|
|
|
|
for (regno = 0; regno < 16; regno++)
|
|
regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
|
|
®buf[regno * 8]);
|
|
|
|
for (regno = 0; regno < 2; regno++)
|
|
regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
|
|
®buf[16 * 8 + regno * 4]);
|
|
|
|
for (regno = 0; regno < 4; regno++)
|
|
regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
|
|
®buf[16 * 8 + 2 * 4 + regno * 4]);
|
|
}
|
|
|
|
static void
|
|
store_wmmx_regs (const struct regcache *regcache)
|
|
{
|
|
char regbuf[IWMMXT_REGS_SIZE];
|
|
int ret, regno, tid;
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch WMMX registers."));
|
|
|
|
for (regno = 0; regno < 16; regno++)
|
|
if (REG_VALID == regcache_register_status (regcache,
|
|
regno + ARM_WR0_REGNUM))
|
|
regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
|
|
®buf[regno * 8]);
|
|
|
|
for (regno = 0; regno < 2; regno++)
|
|
if (REG_VALID == regcache_register_status (regcache,
|
|
regno + ARM_WCSSF_REGNUM))
|
|
regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
|
|
®buf[16 * 8 + regno * 4]);
|
|
|
|
for (regno = 0; regno < 4; regno++)
|
|
if (REG_VALID == regcache_register_status (regcache,
|
|
regno + ARM_WCGR0_REGNUM))
|
|
regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
|
|
®buf[16 * 8 + 2 * 4 + regno * 4]);
|
|
|
|
ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to store WMMX registers."));
|
|
}
|
|
|
|
static void
|
|
fetch_vfp_regs (struct regcache *regcache)
|
|
{
|
|
gdb_byte regbuf[VFP_REGS_SIZE];
|
|
int ret, regno, tid;
|
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = regbuf;
|
|
iov.iov_len = VFP_REGS_SIZE;
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch VFP registers."));
|
|
|
|
aarch32_vfp_regcache_supply (regcache, regbuf,
|
|
tdep->vfp_register_count);
|
|
}
|
|
|
|
static void
|
|
store_vfp_regs (const struct regcache *regcache)
|
|
{
|
|
gdb_byte regbuf[VFP_REGS_SIZE];
|
|
int ret, regno, tid;
|
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
|
|
|
/* Get the thread id for the ptrace call. */
|
|
tid = ptid_get_lwp (regcache_get_ptid (regcache));
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = regbuf;
|
|
iov.iov_len = VFP_REGS_SIZE;
|
|
ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to fetch VFP registers (for update)."));
|
|
|
|
aarch32_vfp_regcache_collect (regcache, regbuf,
|
|
tdep->vfp_register_count);
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_TRUE)
|
|
{
|
|
struct iovec iov;
|
|
|
|
iov.iov_base = regbuf;
|
|
iov.iov_len = VFP_REGS_SIZE;
|
|
ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_VFP, &iov);
|
|
}
|
|
else
|
|
ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
|
|
|
|
if (ret < 0)
|
|
perror_with_name (_("Unable to store VFP registers."));
|
|
}
|
|
|
|
/* Fetch registers from the child process. Fetch all registers if
|
|
regno == -1, otherwise fetch all general registers or all floating
|
|
point registers depending upon the value of regno. */
|
|
|
|
static void
|
|
arm_linux_fetch_inferior_registers (struct target_ops *ops,
|
|
struct regcache *regcache, int regno)
|
|
{
|
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
|
|
|
if (-1 == regno)
|
|
{
|
|
fetch_regs (regcache);
|
|
if (tdep->have_wmmx_registers)
|
|
fetch_wmmx_regs (regcache);
|
|
if (tdep->vfp_register_count > 0)
|
|
fetch_vfp_regs (regcache);
|
|
if (tdep->have_fpa_registers)
|
|
fetch_fpregs (regcache);
|
|
}
|
|
else
|
|
{
|
|
if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
|
|
fetch_regs (regcache);
|
|
else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
|
|
fetch_fpregs (regcache);
|
|
else if (tdep->have_wmmx_registers
|
|
&& regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
|
|
fetch_wmmx_regs (regcache);
|
|
else if (tdep->vfp_register_count > 0
|
|
&& regno >= ARM_D0_REGNUM
|
|
&& (regno < ARM_D0_REGNUM + tdep->vfp_register_count
|
|
|| regno == ARM_FPSCR_REGNUM))
|
|
fetch_vfp_regs (regcache);
|
|
}
|
|
}
|
|
|
|
/* Store registers back into the inferior. Store all registers if
|
|
regno == -1, otherwise store all general registers or all floating
|
|
point registers depending upon the value of regno. */
|
|
|
|
static void
|
|
arm_linux_store_inferior_registers (struct target_ops *ops,
|
|
struct regcache *regcache, int regno)
|
|
{
|
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
|
|
|
if (-1 == regno)
|
|
{
|
|
store_regs (regcache);
|
|
if (tdep->have_wmmx_registers)
|
|
store_wmmx_regs (regcache);
|
|
if (tdep->vfp_register_count > 0)
|
|
store_vfp_regs (regcache);
|
|
if (tdep->have_fpa_registers)
|
|
store_fpregs (regcache);
|
|
}
|
|
else
|
|
{
|
|
if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
|
|
store_regs (regcache);
|
|
else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
|
|
store_fpregs (regcache);
|
|
else if (tdep->have_wmmx_registers
|
|
&& regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
|
|
store_wmmx_regs (regcache);
|
|
else if (tdep->vfp_register_count > 0
|
|
&& regno >= ARM_D0_REGNUM
|
|
&& (regno < ARM_D0_REGNUM + tdep->vfp_register_count
|
|
|| regno == ARM_FPSCR_REGNUM))
|
|
store_vfp_regs (regcache);
|
|
}
|
|
}
|
|
|
|
/* Wrapper functions for the standard regset handling, used by
|
|
thread debugging. */
|
|
|
|
void
|
|
fill_gregset (const struct regcache *regcache,
|
|
gdb_gregset_t *gregsetp, int regno)
|
|
{
|
|
arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
|
|
}
|
|
|
|
void
|
|
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
|
|
{
|
|
arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
|
|
}
|
|
|
|
void
|
|
fill_fpregset (const struct regcache *regcache,
|
|
gdb_fpregset_t *fpregsetp, int regno)
|
|
{
|
|
arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
|
|
}
|
|
|
|
/* Fill GDB's register array with the floating-point register values
|
|
in *fpregsetp. */
|
|
|
|
void
|
|
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
|
|
{
|
|
arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
|
|
}
|
|
|
|
/* Fetch the thread-local storage pointer for libthread_db. */
|
|
|
|
ps_err_e
|
|
ps_get_thread_area (struct ps_prochandle *ph,
|
|
lwpid_t lwpid, int idx, void **base)
|
|
{
|
|
if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
|
|
return PS_ERR;
|
|
|
|
/* IDX is the bias from the thread pointer to the beginning of the
|
|
thread descriptor. It has to be subtracted due to implementation
|
|
quirks in libthread_db. */
|
|
*base = (void *) ((char *)*base - idx);
|
|
|
|
return PS_OK;
|
|
}
|
|
|
|
static const struct target_desc *
|
|
arm_linux_read_description (struct target_ops *ops)
|
|
{
|
|
CORE_ADDR arm_hwcap = 0;
|
|
|
|
if (have_ptrace_getregset == TRIBOOL_UNKNOWN)
|
|
{
|
|
elf_gregset_t gpregs;
|
|
struct iovec iov;
|
|
int tid = ptid_get_lwp (inferior_ptid);
|
|
|
|
iov.iov_base = &gpregs;
|
|
iov.iov_len = sizeof (gpregs);
|
|
|
|
/* Check if PTRACE_GETREGSET works. */
|
|
if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov) < 0)
|
|
have_ptrace_getregset = TRIBOOL_FALSE;
|
|
else
|
|
have_ptrace_getregset = TRIBOOL_TRUE;
|
|
}
|
|
|
|
if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
|
|
{
|
|
return ops->beneath->to_read_description (ops->beneath);
|
|
}
|
|
|
|
if (arm_hwcap & HWCAP_IWMMXT)
|
|
return tdesc_arm_with_iwmmxt;
|
|
|
|
if (arm_hwcap & HWCAP_VFP)
|
|
{
|
|
int pid;
|
|
char *buf;
|
|
const struct target_desc * result = NULL;
|
|
|
|
/* NEON implies VFPv3-D32 or no-VFP unit. Say that we only support
|
|
Neon with VFPv3-D32. */
|
|
if (arm_hwcap & HWCAP_NEON)
|
|
result = tdesc_arm_with_neon;
|
|
else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
|
|
result = tdesc_arm_with_vfpv3;
|
|
else
|
|
result = tdesc_arm_with_vfpv2;
|
|
|
|
/* Now make sure that the kernel supports reading these
|
|
registers. Support was added in 2.6.30. */
|
|
pid = ptid_get_lwp (inferior_ptid);
|
|
errno = 0;
|
|
buf = (char *) alloca (VFP_REGS_SIZE);
|
|
if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
|
|
&& errno == EIO)
|
|
result = NULL;
|
|
|
|
return result;
|
|
}
|
|
|
|
return ops->beneath->to_read_description (ops->beneath);
|
|
}
|
|
|
|
/* Information describing the hardware breakpoint capabilities. */
|
|
struct arm_linux_hwbp_cap
|
|
{
|
|
gdb_byte arch;
|
|
gdb_byte max_wp_length;
|
|
gdb_byte wp_count;
|
|
gdb_byte bp_count;
|
|
};
|
|
|
|
/* Since we cannot dynamically allocate subfields of arm_linux_process_info,
|
|
assume a maximum number of supported break-/watchpoints. */
|
|
#define MAX_BPTS 16
|
|
#define MAX_WPTS 16
|
|
|
|
/* Get hold of the Hardware Breakpoint information for the target we are
|
|
attached to. Returns NULL if the kernel doesn't support Hardware
|
|
breakpoints at all, or a pointer to the information structure. */
|
|
static const struct arm_linux_hwbp_cap *
|
|
arm_linux_get_hwbp_cap (void)
|
|
{
|
|
/* The info structure we return. */
|
|
static struct arm_linux_hwbp_cap info;
|
|
|
|
/* Is INFO in a good state? -1 means that no attempt has been made to
|
|
initialize INFO; 0 means an attempt has been made, but it failed; 1
|
|
means INFO is in an initialized state. */
|
|
static int available = -1;
|
|
|
|
if (available == -1)
|
|
{
|
|
int tid;
|
|
unsigned int val;
|
|
|
|
tid = ptid_get_lwp (inferior_ptid);
|
|
if (ptrace (PTRACE_GETHBPREGS, tid, 0, &val) < 0)
|
|
available = 0;
|
|
else
|
|
{
|
|
info.arch = (gdb_byte)((val >> 24) & 0xff);
|
|
info.max_wp_length = (gdb_byte)((val >> 16) & 0xff);
|
|
info.wp_count = (gdb_byte)((val >> 8) & 0xff);
|
|
info.bp_count = (gdb_byte)(val & 0xff);
|
|
|
|
if (info.wp_count > MAX_WPTS)
|
|
{
|
|
warning (_("arm-linux-gdb supports %d hardware watchpoints but target \
|
|
supports %d"), MAX_WPTS, info.wp_count);
|
|
info.wp_count = MAX_WPTS;
|
|
}
|
|
|
|
if (info.bp_count > MAX_BPTS)
|
|
{
|
|
warning (_("arm-linux-gdb supports %d hardware breakpoints but target \
|
|
supports %d"), MAX_BPTS, info.bp_count);
|
|
info.bp_count = MAX_BPTS;
|
|
}
|
|
available = (info.arch != 0);
|
|
}
|
|
}
|
|
|
|
return available == 1 ? &info : NULL;
|
|
}
|
|
|
|
/* How many hardware breakpoints are available? */
|
|
static int
|
|
arm_linux_get_hw_breakpoint_count (void)
|
|
{
|
|
const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
|
|
return cap != NULL ? cap->bp_count : 0;
|
|
}
|
|
|
|
/* How many hardware watchpoints are available? */
|
|
static int
|
|
arm_linux_get_hw_watchpoint_count (void)
|
|
{
|
|
const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
|
|
return cap != NULL ? cap->wp_count : 0;
|
|
}
|
|
|
|
/* Have we got a free break-/watch-point available for use? Returns -1 if
|
|
there is not an appropriate resource available, otherwise returns 1. */
|
|
static int
|
|
arm_linux_can_use_hw_breakpoint (struct target_ops *self,
|
|
enum bptype type,
|
|
int cnt, int ot)
|
|
{
|
|
if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
|
|
|| type == bp_access_watchpoint || type == bp_watchpoint)
|
|
{
|
|
int count = arm_linux_get_hw_watchpoint_count ();
|
|
|
|
if (count == 0)
|
|
return 0;
|
|
else if (cnt + ot > count)
|
|
return -1;
|
|
}
|
|
else if (type == bp_hardware_breakpoint)
|
|
{
|
|
int count = arm_linux_get_hw_breakpoint_count ();
|
|
|
|
if (count == 0)
|
|
return 0;
|
|
else if (cnt > count)
|
|
return -1;
|
|
}
|
|
else
|
|
gdb_assert (FALSE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Enum describing the different types of ARM hardware break-/watch-points. */
|
|
typedef enum
|
|
{
|
|
arm_hwbp_break = 0,
|
|
arm_hwbp_load = 1,
|
|
arm_hwbp_store = 2,
|
|
arm_hwbp_access = 3
|
|
} arm_hwbp_type;
|
|
|
|
/* Type describing an ARM Hardware Breakpoint Control register value. */
|
|
typedef unsigned int arm_hwbp_control_t;
|
|
|
|
/* Structure used to keep track of hardware break-/watch-points. */
|
|
struct arm_linux_hw_breakpoint
|
|
{
|
|
/* Address to break on, or being watched. */
|
|
unsigned int address;
|
|
/* Control register for break-/watch- point. */
|
|
arm_hwbp_control_t control;
|
|
};
|
|
|
|
/* Structure containing arrays of per process hardware break-/watchpoints
|
|
for caching address and control information.
|
|
|
|
The Linux ptrace interface to hardware break-/watch-points presents the
|
|
values in a vector centred around 0 (which is used fo generic information).
|
|
Positive indicies refer to breakpoint addresses/control registers, negative
|
|
indices to watchpoint addresses/control registers.
|
|
|
|
The Linux vector is indexed as follows:
|
|
-((i << 1) + 2): Control register for watchpoint i.
|
|
-((i << 1) + 1): Address register for watchpoint i.
|
|
0: Information register.
|
|
((i << 1) + 1): Address register for breakpoint i.
|
|
((i << 1) + 2): Control register for breakpoint i.
|
|
|
|
This structure is used as a per-thread cache of the state stored by the
|
|
kernel, so that we don't need to keep calling into the kernel to find a
|
|
free breakpoint.
|
|
|
|
We treat break-/watch-points with their enable bit clear as being deleted.
|
|
*/
|
|
struct arm_linux_debug_reg_state
|
|
{
|
|
/* Hardware breakpoints for this process. */
|
|
struct arm_linux_hw_breakpoint bpts[MAX_BPTS];
|
|
/* Hardware watchpoints for this process. */
|
|
struct arm_linux_hw_breakpoint wpts[MAX_WPTS];
|
|
};
|
|
|
|
/* Per-process arch-specific data we want to keep. */
|
|
struct arm_linux_process_info
|
|
{
|
|
/* Linked list. */
|
|
struct arm_linux_process_info *next;
|
|
/* The process identifier. */
|
|
pid_t pid;
|
|
/* Hardware break-/watchpoints state information. */
|
|
struct arm_linux_debug_reg_state state;
|
|
|
|
};
|
|
|
|
/* Per-thread arch-specific data we want to keep. */
|
|
struct arch_lwp_info
|
|
{
|
|
/* Non-zero if our copy differs from what's recorded in the thread. */
|
|
char bpts_changed[MAX_BPTS];
|
|
char wpts_changed[MAX_WPTS];
|
|
};
|
|
|
|
static struct arm_linux_process_info *arm_linux_process_list = NULL;
|
|
|
|
/* Find process data for process PID. */
|
|
|
|
static struct arm_linux_process_info *
|
|
arm_linux_find_process_pid (pid_t pid)
|
|
{
|
|
struct arm_linux_process_info *proc;
|
|
|
|
for (proc = arm_linux_process_list; proc; proc = proc->next)
|
|
if (proc->pid == pid)
|
|
return proc;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Add process data for process PID. Returns newly allocated info
|
|
object. */
|
|
|
|
static struct arm_linux_process_info *
|
|
arm_linux_add_process (pid_t pid)
|
|
{
|
|
struct arm_linux_process_info *proc;
|
|
|
|
proc = XCNEW (struct arm_linux_process_info);
|
|
proc->pid = pid;
|
|
|
|
proc->next = arm_linux_process_list;
|
|
arm_linux_process_list = proc;
|
|
|
|
return proc;
|
|
}
|
|
|
|
/* Get data specific info for process PID, creating it if necessary.
|
|
Never returns NULL. */
|
|
|
|
static struct arm_linux_process_info *
|
|
arm_linux_process_info_get (pid_t pid)
|
|
{
|
|
struct arm_linux_process_info *proc;
|
|
|
|
proc = arm_linux_find_process_pid (pid);
|
|
if (proc == NULL)
|
|
proc = arm_linux_add_process (pid);
|
|
|
|
return proc;
|
|
}
|
|
|
|
/* Called whenever GDB is no longer debugging process PID. It deletes
|
|
data structures that keep track of debug register state. */
|
|
|
|
static void
|
|
arm_linux_forget_process (pid_t pid)
|
|
{
|
|
struct arm_linux_process_info *proc, **proc_link;
|
|
|
|
proc = arm_linux_process_list;
|
|
proc_link = &arm_linux_process_list;
|
|
|
|
while (proc != NULL)
|
|
{
|
|
if (proc->pid == pid)
|
|
{
|
|
*proc_link = proc->next;
|
|
|
|
xfree (proc);
|
|
return;
|
|
}
|
|
|
|
proc_link = &proc->next;
|
|
proc = *proc_link;
|
|
}
|
|
}
|
|
|
|
/* Get hardware break-/watchpoint state for process PID. */
|
|
|
|
static struct arm_linux_debug_reg_state *
|
|
arm_linux_get_debug_reg_state (pid_t pid)
|
|
{
|
|
return &arm_linux_process_info_get (pid)->state;
|
|
}
|
|
|
|
/* Initialize an ARM hardware break-/watch-point control register value.
|
|
BYTE_ADDRESS_SELECT is the mask of bytes to trigger on; HWBP_TYPE is the
|
|
type of break-/watch-point; ENABLE indicates whether the point is enabled.
|
|
*/
|
|
static arm_hwbp_control_t
|
|
arm_hwbp_control_initialize (unsigned byte_address_select,
|
|
arm_hwbp_type hwbp_type,
|
|
int enable)
|
|
{
|
|
gdb_assert ((byte_address_select & ~0xffU) == 0);
|
|
gdb_assert (hwbp_type != arm_hwbp_break
|
|
|| ((byte_address_select & 0xfU) != 0));
|
|
|
|
return (byte_address_select << 5) | (hwbp_type << 3) | (3 << 1) | enable;
|
|
}
|
|
|
|
/* Does the breakpoint control value CONTROL have the enable bit set? */
|
|
static int
|
|
arm_hwbp_control_is_enabled (arm_hwbp_control_t control)
|
|
{
|
|
return control & 0x1;
|
|
}
|
|
|
|
/* Change a breakpoint control word so that it is in the disabled state. */
|
|
static arm_hwbp_control_t
|
|
arm_hwbp_control_disable (arm_hwbp_control_t control)
|
|
{
|
|
return control & ~0x1;
|
|
}
|
|
|
|
/* Initialise the hardware breakpoint structure P. The breakpoint will be
|
|
enabled, and will point to the placed address of BP_TGT. */
|
|
static void
|
|
arm_linux_hw_breakpoint_initialize (struct gdbarch *gdbarch,
|
|
struct bp_target_info *bp_tgt,
|
|
struct arm_linux_hw_breakpoint *p)
|
|
{
|
|
unsigned mask;
|
|
CORE_ADDR address = bp_tgt->placed_address = bp_tgt->reqstd_address;
|
|
|
|
/* We have to create a mask for the control register which says which bits
|
|
of the word pointed to by address to break on. */
|
|
if (arm_pc_is_thumb (gdbarch, address))
|
|
{
|
|
mask = 0x3;
|
|
address &= ~1;
|
|
}
|
|
else
|
|
{
|
|
mask = 0xf;
|
|
address &= ~3;
|
|
}
|
|
|
|
p->address = (unsigned int) address;
|
|
p->control = arm_hwbp_control_initialize (mask, arm_hwbp_break, 1);
|
|
}
|
|
|
|
/* Get the ARM hardware breakpoint type from the TYPE value we're
|
|
given when asked to set a watchpoint. */
|
|
static arm_hwbp_type
|
|
arm_linux_get_hwbp_type (enum target_hw_bp_type type)
|
|
{
|
|
if (type == hw_read)
|
|
return arm_hwbp_load;
|
|
else if (type == hw_write)
|
|
return arm_hwbp_store;
|
|
else
|
|
return arm_hwbp_access;
|
|
}
|
|
|
|
/* Initialize the hardware breakpoint structure P for a watchpoint at ADDR
|
|
to LEN. The type of watchpoint is given in RW. */
|
|
static void
|
|
arm_linux_hw_watchpoint_initialize (CORE_ADDR addr, int len,
|
|
enum target_hw_bp_type type,
|
|
struct arm_linux_hw_breakpoint *p)
|
|
{
|
|
const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
|
|
unsigned mask;
|
|
|
|
gdb_assert (cap != NULL);
|
|
gdb_assert (cap->max_wp_length != 0);
|
|
|
|
mask = (1 << len) - 1;
|
|
|
|
p->address = (unsigned int) addr;
|
|
p->control = arm_hwbp_control_initialize (mask,
|
|
arm_linux_get_hwbp_type (type), 1);
|
|
}
|
|
|
|
/* Are two break-/watch-points equal? */
|
|
static int
|
|
arm_linux_hw_breakpoint_equal (const struct arm_linux_hw_breakpoint *p1,
|
|
const struct arm_linux_hw_breakpoint *p2)
|
|
{
|
|
return p1->address == p2->address && p1->control == p2->control;
|
|
}
|
|
|
|
/* Callback to mark a watch-/breakpoint to be updated in all threads of
|
|
the current process. */
|
|
|
|
struct update_registers_data
|
|
{
|
|
int watch;
|
|
int index;
|
|
};
|
|
|
|
static int
|
|
update_registers_callback (struct lwp_info *lwp, void *arg)
|
|
{
|
|
struct update_registers_data *data = (struct update_registers_data *) arg;
|
|
|
|
if (lwp->arch_private == NULL)
|
|
lwp->arch_private = XCNEW (struct arch_lwp_info);
|
|
|
|
/* The actual update is done later just before resuming the lwp,
|
|
we just mark that the registers need updating. */
|
|
if (data->watch)
|
|
lwp->arch_private->wpts_changed[data->index] = 1;
|
|
else
|
|
lwp->arch_private->bpts_changed[data->index] = 1;
|
|
|
|
/* If the lwp isn't stopped, force it to momentarily pause, so
|
|
we can update its breakpoint registers. */
|
|
if (!lwp->stopped)
|
|
linux_stop_lwp (lwp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Insert the hardware breakpoint (WATCHPOINT = 0) or watchpoint (WATCHPOINT
|
|
=1) BPT for thread TID. */
|
|
static void
|
|
arm_linux_insert_hw_breakpoint1 (const struct arm_linux_hw_breakpoint* bpt,
|
|
int watchpoint)
|
|
{
|
|
int pid;
|
|
ptid_t pid_ptid;
|
|
gdb_byte count, i;
|
|
struct arm_linux_hw_breakpoint* bpts;
|
|
struct update_registers_data data;
|
|
|
|
pid = ptid_get_pid (inferior_ptid);
|
|
pid_ptid = pid_to_ptid (pid);
|
|
|
|
if (watchpoint)
|
|
{
|
|
count = arm_linux_get_hw_watchpoint_count ();
|
|
bpts = arm_linux_get_debug_reg_state (pid)->wpts;
|
|
}
|
|
else
|
|
{
|
|
count = arm_linux_get_hw_breakpoint_count ();
|
|
bpts = arm_linux_get_debug_reg_state (pid)->bpts;
|
|
}
|
|
|
|
for (i = 0; i < count; ++i)
|
|
if (!arm_hwbp_control_is_enabled (bpts[i].control))
|
|
{
|
|
data.watch = watchpoint;
|
|
data.index = i;
|
|
bpts[i] = *bpt;
|
|
iterate_over_lwps (pid_ptid, update_registers_callback, &data);
|
|
break;
|
|
}
|
|
|
|
gdb_assert (i != count);
|
|
}
|
|
|
|
/* Remove the hardware breakpoint (WATCHPOINT = 0) or watchpoint
|
|
(WATCHPOINT = 1) BPT for thread TID. */
|
|
static void
|
|
arm_linux_remove_hw_breakpoint1 (const struct arm_linux_hw_breakpoint *bpt,
|
|
int watchpoint)
|
|
{
|
|
int pid;
|
|
gdb_byte count, i;
|
|
ptid_t pid_ptid;
|
|
struct arm_linux_hw_breakpoint* bpts;
|
|
struct update_registers_data data;
|
|
|
|
pid = ptid_get_pid (inferior_ptid);
|
|
pid_ptid = pid_to_ptid (pid);
|
|
|
|
if (watchpoint)
|
|
{
|
|
count = arm_linux_get_hw_watchpoint_count ();
|
|
bpts = arm_linux_get_debug_reg_state (pid)->wpts;
|
|
}
|
|
else
|
|
{
|
|
count = arm_linux_get_hw_breakpoint_count ();
|
|
bpts = arm_linux_get_debug_reg_state (pid)->bpts;
|
|
}
|
|
|
|
for (i = 0; i < count; ++i)
|
|
if (arm_linux_hw_breakpoint_equal (bpt, bpts + i))
|
|
{
|
|
data.watch = watchpoint;
|
|
data.index = i;
|
|
bpts[i].control = arm_hwbp_control_disable (bpts[i].control);
|
|
iterate_over_lwps (pid_ptid, update_registers_callback, &data);
|
|
break;
|
|
}
|
|
|
|
gdb_assert (i != count);
|
|
}
|
|
|
|
/* Insert a Hardware breakpoint. */
|
|
static int
|
|
arm_linux_insert_hw_breakpoint (struct target_ops *self,
|
|
struct gdbarch *gdbarch,
|
|
struct bp_target_info *bp_tgt)
|
|
{
|
|
struct lwp_info *lp;
|
|
struct arm_linux_hw_breakpoint p;
|
|
|
|
if (arm_linux_get_hw_breakpoint_count () == 0)
|
|
return -1;
|
|
|
|
arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
|
|
|
|
arm_linux_insert_hw_breakpoint1 (&p, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Remove a hardware breakpoint. */
|
|
static int
|
|
arm_linux_remove_hw_breakpoint (struct target_ops *self,
|
|
struct gdbarch *gdbarch,
|
|
struct bp_target_info *bp_tgt)
|
|
{
|
|
struct lwp_info *lp;
|
|
struct arm_linux_hw_breakpoint p;
|
|
|
|
if (arm_linux_get_hw_breakpoint_count () == 0)
|
|
return -1;
|
|
|
|
arm_linux_hw_breakpoint_initialize (gdbarch, bp_tgt, &p);
|
|
|
|
arm_linux_remove_hw_breakpoint1 (&p, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Are we able to use a hardware watchpoint for the LEN bytes starting at
|
|
ADDR? */
|
|
static int
|
|
arm_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
|
|
CORE_ADDR addr, int len)
|
|
{
|
|
const struct arm_linux_hwbp_cap *cap = arm_linux_get_hwbp_cap ();
|
|
CORE_ADDR max_wp_length, aligned_addr;
|
|
|
|
/* Can not set watchpoints for zero or negative lengths. */
|
|
if (len <= 0)
|
|
return 0;
|
|
|
|
/* Need to be able to use the ptrace interface. */
|
|
if (cap == NULL || cap->wp_count == 0)
|
|
return 0;
|
|
|
|
/* Test that the range [ADDR, ADDR + LEN) fits into the largest address
|
|
range covered by a watchpoint. */
|
|
max_wp_length = (CORE_ADDR)cap->max_wp_length;
|
|
aligned_addr = addr & ~(max_wp_length - 1);
|
|
|
|
if (aligned_addr + max_wp_length < addr + len)
|
|
return 0;
|
|
|
|
/* The current ptrace interface can only handle watchpoints that are a
|
|
power of 2. */
|
|
if ((len & (len - 1)) != 0)
|
|
return 0;
|
|
|
|
/* All tests passed so we must be able to set a watchpoint. */
|
|
return 1;
|
|
}
|
|
|
|
/* Insert a Hardware breakpoint. */
|
|
static int
|
|
arm_linux_insert_watchpoint (struct target_ops *self,
|
|
CORE_ADDR addr, int len,
|
|
enum target_hw_bp_type rw,
|
|
struct expression *cond)
|
|
{
|
|
struct lwp_info *lp;
|
|
struct arm_linux_hw_breakpoint p;
|
|
|
|
if (arm_linux_get_hw_watchpoint_count () == 0)
|
|
return -1;
|
|
|
|
arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
|
|
|
|
arm_linux_insert_hw_breakpoint1 (&p, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Remove a hardware breakpoint. */
|
|
static int
|
|
arm_linux_remove_watchpoint (struct target_ops *self, CORE_ADDR addr,
|
|
int len, enum target_hw_bp_type rw,
|
|
struct expression *cond)
|
|
{
|
|
struct lwp_info *lp;
|
|
struct arm_linux_hw_breakpoint p;
|
|
|
|
if (arm_linux_get_hw_watchpoint_count () == 0)
|
|
return -1;
|
|
|
|
arm_linux_hw_watchpoint_initialize (addr, len, rw, &p);
|
|
|
|
arm_linux_remove_hw_breakpoint1 (&p, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* What was the data address the target was stopped on accessing. */
|
|
static int
|
|
arm_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
|
|
{
|
|
siginfo_t siginfo;
|
|
int slot;
|
|
|
|
if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
|
|
return 0;
|
|
|
|
/* This must be a hardware breakpoint. */
|
|
if (siginfo.si_signo != SIGTRAP
|
|
|| (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
|
|
return 0;
|
|
|
|
/* We must be able to set hardware watchpoints. */
|
|
if (arm_linux_get_hw_watchpoint_count () == 0)
|
|
return 0;
|
|
|
|
slot = siginfo.si_errno;
|
|
|
|
/* If we are in a positive slot then we're looking at a breakpoint and not
|
|
a watchpoint. */
|
|
if (slot >= 0)
|
|
return 0;
|
|
|
|
*addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
|
|
return 1;
|
|
}
|
|
|
|
/* Has the target been stopped by hitting a watchpoint? */
|
|
static int
|
|
arm_linux_stopped_by_watchpoint (struct target_ops *ops)
|
|
{
|
|
CORE_ADDR addr;
|
|
return arm_linux_stopped_data_address (ops, &addr);
|
|
}
|
|
|
|
static int
|
|
arm_linux_watchpoint_addr_within_range (struct target_ops *target,
|
|
CORE_ADDR addr,
|
|
CORE_ADDR start, int length)
|
|
{
|
|
return start <= addr && start + length - 1 >= addr;
|
|
}
|
|
|
|
/* Handle thread creation. We need to copy the breakpoints and watchpoints
|
|
in the parent thread to the child thread. */
|
|
static void
|
|
arm_linux_new_thread (struct lwp_info *lp)
|
|
{
|
|
int i;
|
|
struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
|
|
|
|
/* Mark that all the hardware breakpoint/watchpoint register pairs
|
|
for this thread need to be initialized. */
|
|
|
|
for (i = 0; i < MAX_BPTS; i++)
|
|
{
|
|
info->bpts_changed[i] = 1;
|
|
info->wpts_changed[i] = 1;
|
|
}
|
|
|
|
lp->arch_private = info;
|
|
}
|
|
|
|
/* Called when resuming a thread.
|
|
The hardware debug registers are updated when there is any change. */
|
|
|
|
static void
|
|
arm_linux_prepare_to_resume (struct lwp_info *lwp)
|
|
{
|
|
int pid, i;
|
|
struct arm_linux_hw_breakpoint *bpts, *wpts;
|
|
struct arch_lwp_info *arm_lwp_info = lwp->arch_private;
|
|
|
|
pid = ptid_get_lwp (lwp->ptid);
|
|
bpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->bpts;
|
|
wpts = arm_linux_get_debug_reg_state (ptid_get_pid (lwp->ptid))->wpts;
|
|
|
|
/* NULL means this is the main thread still going through the shell,
|
|
or, no watchpoint has been set yet. In that case, there's
|
|
nothing to do. */
|
|
if (arm_lwp_info == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < arm_linux_get_hw_breakpoint_count (); i++)
|
|
if (arm_lwp_info->bpts_changed[i])
|
|
{
|
|
errno = 0;
|
|
if (arm_hwbp_control_is_enabled (bpts[i].control))
|
|
if (ptrace (PTRACE_SETHBPREGS, pid,
|
|
(PTRACE_TYPE_ARG3) ((i << 1) + 1), &bpts[i].address) < 0)
|
|
perror_with_name (_("Unexpected error setting breakpoint"));
|
|
|
|
if (bpts[i].control != 0)
|
|
if (ptrace (PTRACE_SETHBPREGS, pid,
|
|
(PTRACE_TYPE_ARG3) ((i << 1) + 2), &bpts[i].control) < 0)
|
|
perror_with_name (_("Unexpected error setting breakpoint"));
|
|
|
|
arm_lwp_info->bpts_changed[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < arm_linux_get_hw_watchpoint_count (); i++)
|
|
if (arm_lwp_info->wpts_changed[i])
|
|
{
|
|
errno = 0;
|
|
if (arm_hwbp_control_is_enabled (wpts[i].control))
|
|
if (ptrace (PTRACE_SETHBPREGS, pid,
|
|
(PTRACE_TYPE_ARG3) -((i << 1) + 1), &wpts[i].address) < 0)
|
|
perror_with_name (_("Unexpected error setting watchpoint"));
|
|
|
|
if (wpts[i].control != 0)
|
|
if (ptrace (PTRACE_SETHBPREGS, pid,
|
|
(PTRACE_TYPE_ARG3) -((i << 1) + 2), &wpts[i].control) < 0)
|
|
perror_with_name (_("Unexpected error setting watchpoint"));
|
|
|
|
arm_lwp_info->wpts_changed[i] = 0;
|
|
}
|
|
}
|
|
|
|
/* linux_nat_new_fork hook. */
|
|
|
|
static void
|
|
arm_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
|
|
{
|
|
pid_t parent_pid;
|
|
struct arm_linux_debug_reg_state *parent_state;
|
|
struct arm_linux_debug_reg_state *child_state;
|
|
|
|
/* NULL means no watchpoint has ever been set in the parent. In
|
|
that case, there's nothing to do. */
|
|
if (parent->arch_private == NULL)
|
|
return;
|
|
|
|
/* GDB core assumes the child inherits the watchpoints/hw
|
|
breakpoints of the parent, and will remove them all from the
|
|
forked off process. Copy the debug registers mirrors into the
|
|
new process so that all breakpoints and watchpoints can be
|
|
removed together. */
|
|
|
|
parent_pid = ptid_get_pid (parent->ptid);
|
|
parent_state = arm_linux_get_debug_reg_state (parent_pid);
|
|
child_state = arm_linux_get_debug_reg_state (child_pid);
|
|
*child_state = *parent_state;
|
|
}
|
|
|
|
void
|
|
_initialize_arm_linux_nat (void)
|
|
{
|
|
struct target_ops *t;
|
|
|
|
/* Fill in the generic GNU/Linux methods. */
|
|
t = linux_target ();
|
|
|
|
/* Add our register access methods. */
|
|
t->to_fetch_registers = arm_linux_fetch_inferior_registers;
|
|
t->to_store_registers = arm_linux_store_inferior_registers;
|
|
|
|
/* Add our hardware breakpoint and watchpoint implementation. */
|
|
t->to_can_use_hw_breakpoint = arm_linux_can_use_hw_breakpoint;
|
|
t->to_insert_hw_breakpoint = arm_linux_insert_hw_breakpoint;
|
|
t->to_remove_hw_breakpoint = arm_linux_remove_hw_breakpoint;
|
|
t->to_region_ok_for_hw_watchpoint = arm_linux_region_ok_for_hw_watchpoint;
|
|
t->to_insert_watchpoint = arm_linux_insert_watchpoint;
|
|
t->to_remove_watchpoint = arm_linux_remove_watchpoint;
|
|
t->to_stopped_by_watchpoint = arm_linux_stopped_by_watchpoint;
|
|
t->to_stopped_data_address = arm_linux_stopped_data_address;
|
|
t->to_watchpoint_addr_within_range = arm_linux_watchpoint_addr_within_range;
|
|
|
|
t->to_read_description = arm_linux_read_description;
|
|
|
|
/* Register the target. */
|
|
linux_nat_add_target (t);
|
|
|
|
/* Handle thread creation and exit. */
|
|
linux_nat_set_new_thread (t, arm_linux_new_thread);
|
|
linux_nat_set_prepare_to_resume (t, arm_linux_prepare_to_resume);
|
|
|
|
/* Handle process creation and exit. */
|
|
linux_nat_set_new_fork (t, arm_linux_new_fork);
|
|
linux_nat_set_forget_process (t, arm_linux_forget_process);
|
|
}
|