6c2659886f
I'd like to enable the -Wmissing-declarations warning. However, it
warns for every _initialize function, for example:
CXX dcache.o
/home/smarchi/src/binutils-gdb/gdb/dcache.c: In function ‘void _initialize_dcache()’:
/home/smarchi/src/binutils-gdb/gdb/dcache.c:688:1: error: no previous declaration for ‘void _initialize_dcache()’ [-Werror=missing-declarations]
_initialize_dcache (void)
^~~~~~~~~~~~~~~~~~
The only practical way forward I found is to add back the declarations,
which were removed by this commit:
commit 481695ed5f
Author: John Baldwin <jhb@FreeBSD.org>
Date: Sat Sep 9 11:02:37 2017 -0700
Remove unnecessary function prototypes.
I don't think it's a big problem to have the declarations for these
functions, but if anybody has a better solution for this, I'll be happy
to use it.
gdb/ChangeLog:
* aarch64-fbsd-nat.c (_initialize_aarch64_fbsd_nat): Add declaration.
* aarch64-fbsd-tdep.c (_initialize_aarch64_fbsd_tdep): Add declaration.
* aarch64-linux-nat.c (_initialize_aarch64_linux_nat): Add declaration.
* aarch64-linux-tdep.c (_initialize_aarch64_linux_tdep): Add declaration.
* aarch64-newlib-tdep.c (_initialize_aarch64_newlib_tdep): Add declaration.
* aarch64-tdep.c (_initialize_aarch64_tdep): Add declaration.
* ada-exp.y (_initialize_ada_exp): Add declaration.
* ada-lang.c (_initialize_ada_language): Add declaration.
* ada-tasks.c (_initialize_tasks): Add declaration.
* agent.c (_initialize_agent): Add declaration.
* aix-thread.c (_initialize_aix_thread): Add declaration.
* alpha-bsd-nat.c (_initialize_alphabsd_nat): Add declaration.
* alpha-linux-nat.c (_initialize_alpha_linux_nat): Add declaration.
* alpha-linux-tdep.c (_initialize_alpha_linux_tdep): Add declaration.
* alpha-nbsd-tdep.c (_initialize_alphanbsd_tdep): Add declaration.
* alpha-obsd-tdep.c (_initialize_alphaobsd_tdep): Add declaration.
* alpha-tdep.c (_initialize_alpha_tdep): Add declaration.
* amd64-darwin-tdep.c (_initialize_amd64_darwin_tdep): Add declaration.
* amd64-dicos-tdep.c (_initialize_amd64_dicos_tdep): Add declaration.
* amd64-fbsd-nat.c (_initialize_amd64fbsd_nat): Add declaration.
* amd64-fbsd-tdep.c (_initialize_amd64fbsd_tdep): Add declaration.
* amd64-linux-nat.c (_initialize_amd64_linux_nat): Add declaration.
* amd64-linux-tdep.c (_initialize_amd64_linux_tdep): Add declaration.
* amd64-nbsd-nat.c (_initialize_amd64nbsd_nat): Add declaration.
* amd64-nbsd-tdep.c (_initialize_amd64nbsd_tdep): Add declaration.
* amd64-obsd-nat.c (_initialize_amd64obsd_nat): Add declaration.
* amd64-obsd-tdep.c (_initialize_amd64obsd_tdep): Add declaration.
* amd64-sol2-tdep.c (_initialize_amd64_sol2_tdep): Add declaration.
* amd64-tdep.c (_initialize_amd64_tdep): Add declaration.
* amd64-windows-nat.c (_initialize_amd64_windows_nat): Add declaration.
* amd64-windows-tdep.c (_initialize_amd64_windows_tdep): Add declaration.
* annotate.c (_initialize_annotate): Add declaration.
* arc-newlib-tdep.c (_initialize_arc_newlib_tdep): Add declaration.
* arc-tdep.c (_initialize_arc_tdep): Add declaration.
* arch-utils.c (_initialize_gdbarch_utils): Add declaration.
* arm-fbsd-nat.c (_initialize_arm_fbsd_nat): Add declaration.
* arm-fbsd-tdep.c (_initialize_arm_fbsd_tdep): Add declaration.
* arm-linux-nat.c (_initialize_arm_linux_nat): Add declaration.
* arm-linux-tdep.c (_initialize_arm_linux_tdep): Add declaration.
* arm-nbsd-nat.c (_initialize_arm_netbsd_nat): Add declaration.
* arm-nbsd-tdep.c (_initialize_arm_netbsd_tdep): Add declaration.
* arm-obsd-tdep.c (_initialize_armobsd_tdep): Add declaration.
* arm-pikeos-tdep.c (_initialize_arm_pikeos_tdep): Add declaration.
* arm-symbian-tdep.c (_initialize_arm_symbian_tdep): Add declaration.
* arm-tdep.c (_initialize_arm_tdep): Add declaration.
* arm-wince-tdep.c (_initialize_arm_wince_tdep): Add declaration.
* auto-load.c (_initialize_auto_load): Add declaration.
* auxv.c (_initialize_auxv): Add declaration.
* avr-tdep.c (_initialize_avr_tdep): Add declaration.
* ax-gdb.c (_initialize_ax_gdb): Add declaration.
* bfin-linux-tdep.c (_initialize_bfin_linux_tdep): Add declaration.
* bfin-tdep.c (_initialize_bfin_tdep): Add declaration.
* break-catch-sig.c (_initialize_break_catch_sig): Add declaration.
* break-catch-syscall.c (_initialize_break_catch_syscall): Add declaration.
* break-catch-throw.c (_initialize_break_catch_throw): Add declaration.
* breakpoint.c (_initialize_breakpoint): Add declaration.
* bsd-uthread.c (_initialize_bsd_uthread): Add declaration.
* btrace.c (_initialize_btrace): Add declaration.
* charset.c (_initialize_charset): Add declaration.
* cli/cli-cmds.c (_initialize_cli_cmds): Add declaration.
* cli/cli-dump.c (_initialize_cli_dump): Add declaration.
* cli/cli-interp.c (_initialize_cli_interp): Add declaration.
* cli/cli-logging.c (_initialize_cli_logging): Add declaration.
* cli/cli-script.c (_initialize_cli_script): Add declaration.
* cli/cli-style.c (_initialize_cli_style): Add declaration.
* coff-pe-read.c (_initialize_coff_pe_read): Add declaration.
* coffread.c (_initialize_coffread): Add declaration.
* compile/compile-cplus-types.c (_initialize_compile_cplus_types): Add declaration.
* compile/compile.c (_initialize_compile): Add declaration.
* complaints.c (_initialize_complaints): Add declaration.
* completer.c (_initialize_completer): Add declaration.
* copying.c (_initialize_copying): Add declaration.
* corefile.c (_initialize_core): Add declaration.
* corelow.c (_initialize_corelow): Add declaration.
* cp-abi.c (_initialize_cp_abi): Add declaration.
* cp-namespace.c (_initialize_cp_namespace): Add declaration.
* cp-support.c (_initialize_cp_support): Add declaration.
* cp-valprint.c (_initialize_cp_valprint): Add declaration.
* cris-linux-tdep.c (_initialize_cris_linux_tdep): Add declaration.
* cris-tdep.c (_initialize_cris_tdep): Add declaration.
* csky-linux-tdep.c (_initialize_csky_linux_tdep): Add declaration.
* csky-tdep.c (_initialize_csky_tdep): Add declaration.
* ctfread.c (_initialize_ctfread): Add declaration.
* d-lang.c (_initialize_d_language): Add declaration.
* darwin-nat-info.c (_initialize_darwin_info_commands): Add declaration.
* darwin-nat.c (_initialize_darwin_nat): Add declaration.
* dbxread.c (_initialize_dbxread): Add declaration.
* dcache.c (_initialize_dcache): Add declaration.
* disasm-selftests.c (_initialize_disasm_selftests): Add declaration.
* disasm.c (_initialize_disasm): Add declaration.
* dtrace-probe.c (_initialize_dtrace_probe): Add declaration.
* dummy-frame.c (_initialize_dummy_frame): Add declaration.
* dwarf-index-cache.c (_initialize_index_cache): Add declaration.
* dwarf-index-write.c (_initialize_dwarf_index_write): Add declaration.
* dwarf2-frame-tailcall.c (_initialize_tailcall_frame): Add declaration.
* dwarf2-frame.c (_initialize_dwarf2_frame): Add declaration.
* dwarf2expr.c (_initialize_dwarf2expr): Add declaration.
* dwarf2loc.c (_initialize_dwarf2loc): Add declaration.
* dwarf2read.c (_initialize_dwarf2_read): Add declaration.
* elfread.c (_initialize_elfread): Add declaration.
* exec.c (_initialize_exec): Add declaration.
* extension.c (_initialize_extension): Add declaration.
* f-lang.c (_initialize_f_language): Add declaration.
* f-valprint.c (_initialize_f_valprint): Add declaration.
* fbsd-nat.c (_initialize_fbsd_nat): Add declaration.
* fbsd-tdep.c (_initialize_fbsd_tdep): Add declaration.
* filesystem.c (_initialize_filesystem): Add declaration.
* findcmd.c (_initialize_mem_search): Add declaration.
* findvar.c (_initialize_findvar): Add declaration.
* fork-child.c (_initialize_fork_child): Add declaration.
* frame-base.c (_initialize_frame_base): Add declaration.
* frame-unwind.c (_initialize_frame_unwind): Add declaration.
* frame.c (_initialize_frame): Add declaration.
* frv-linux-tdep.c (_initialize_frv_linux_tdep): Add declaration.
* frv-tdep.c (_initialize_frv_tdep): Add declaration.
* ft32-tdep.c (_initialize_ft32_tdep): Add declaration.
* gcore.c (_initialize_gcore): Add declaration.
* gdb-demangle.c (_initialize_gdb_demangle): Add declaration.
* gdb_bfd.c (_initialize_gdb_bfd): Add declaration.
* gdbarch-selftests.c (_initialize_gdbarch_selftests): Add declaration.
* gdbarch.c (_initialize_gdbarch): Add declaration.
* gdbtypes.c (_initialize_gdbtypes): Add declaration.
* gnu-nat.c (_initialize_gnu_nat): Add declaration.
* gnu-v2-abi.c (_initialize_gnu_v2_abi): Add declaration.
* gnu-v3-abi.c (_initialize_gnu_v3_abi): Add declaration.
* go-lang.c (_initialize_go_language): Add declaration.
* go32-nat.c (_initialize_go32_nat): Add declaration.
* guile/guile.c (_initialize_guile): Add declaration.
* h8300-tdep.c (_initialize_h8300_tdep): Add declaration.
* hppa-linux-nat.c (_initialize_hppa_linux_nat): Add declaration.
* hppa-linux-tdep.c (_initialize_hppa_linux_tdep): Add declaration.
* hppa-nbsd-nat.c (_initialize_hppanbsd_nat): Add declaration.
* hppa-nbsd-tdep.c (_initialize_hppanbsd_tdep): Add declaration.
* hppa-obsd-nat.c (_initialize_hppaobsd_nat): Add declaration.
* hppa-obsd-tdep.c (_initialize_hppabsd_tdep): Add declaration.
* hppa-tdep.c (_initialize_hppa_tdep): Add declaration.
* i386-bsd-nat.c (_initialize_i386bsd_nat): Add declaration.
* i386-cygwin-tdep.c (_initialize_i386_cygwin_tdep): Add declaration.
* i386-darwin-nat.c (_initialize_i386_darwin_nat): Add declaration.
* i386-darwin-tdep.c (_initialize_i386_darwin_tdep): Add declaration.
* i386-dicos-tdep.c (_initialize_i386_dicos_tdep): Add declaration.
* i386-fbsd-nat.c (_initialize_i386fbsd_nat): Add declaration.
* i386-fbsd-tdep.c (_initialize_i386fbsd_tdep): Add declaration.
* i386-gnu-nat.c (_initialize_i386gnu_nat): Add declaration.
* i386-gnu-tdep.c (_initialize_i386gnu_tdep): Add declaration.
* i386-go32-tdep.c (_initialize_i386_go32_tdep): Add declaration.
* i386-linux-nat.c (_initialize_i386_linux_nat): Add declaration.
* i386-linux-tdep.c (_initialize_i386_linux_tdep): Add declaration.
* i386-nbsd-nat.c (_initialize_i386nbsd_nat): Add declaration.
* i386-nbsd-tdep.c (_initialize_i386nbsd_tdep): Add declaration.
* i386-nto-tdep.c (_initialize_i386nto_tdep): Add declaration.
* i386-obsd-nat.c (_initialize_i386obsd_nat): Add declaration.
* i386-obsd-tdep.c (_initialize_i386obsd_tdep): Add declaration.
* i386-sol2-nat.c (_initialize_amd64_sol2_nat): Add declaration.
* i386-sol2-tdep.c (_initialize_i386_sol2_tdep): Add declaration.
* i386-tdep.c (_initialize_i386_tdep): Add declaration.
* i386-windows-nat.c (_initialize_i386_windows_nat): Add declaration.
* ia64-libunwind-tdep.c (_initialize_libunwind_frame): Add declaration.
* ia64-linux-nat.c (_initialize_ia64_linux_nat): Add declaration.
* ia64-linux-tdep.c (_initialize_ia64_linux_tdep): Add declaration.
* ia64-tdep.c (_initialize_ia64_tdep): Add declaration.
* ia64-vms-tdep.c (_initialize_ia64_vms_tdep): Add declaration.
* infcall.c (_initialize_infcall): Add declaration.
* infcmd.c (_initialize_infcmd): Add declaration.
* inflow.c (_initialize_inflow): Add declaration.
* infrun.c (_initialize_infrun): Add declaration.
* interps.c (_initialize_interpreter): Add declaration.
* iq2000-tdep.c (_initialize_iq2000_tdep): Add declaration.
* jit.c (_initialize_jit): Add declaration.
* language.c (_initialize_language): Add declaration.
* linux-fork.c (_initialize_linux_fork): Add declaration.
* linux-nat.c (_initialize_linux_nat): Add declaration.
* linux-tdep.c (_initialize_linux_tdep): Add declaration.
* linux-thread-db.c (_initialize_thread_db): Add declaration.
* lm32-tdep.c (_initialize_lm32_tdep): Add declaration.
* m2-lang.c (_initialize_m2_language): Add declaration.
* m32c-tdep.c (_initialize_m32c_tdep): Add declaration.
* m32r-linux-nat.c (_initialize_m32r_linux_nat): Add declaration.
* m32r-linux-tdep.c (_initialize_m32r_linux_tdep): Add declaration.
* m32r-tdep.c (_initialize_m32r_tdep): Add declaration.
* m68hc11-tdep.c (_initialize_m68hc11_tdep): Add declaration.
* m68k-bsd-nat.c (_initialize_m68kbsd_nat): Add declaration.
* m68k-bsd-tdep.c (_initialize_m68kbsd_tdep): Add declaration.
* m68k-linux-nat.c (_initialize_m68k_linux_nat): Add declaration.
* m68k-linux-tdep.c (_initialize_m68k_linux_tdep): Add declaration.
* m68k-tdep.c (_initialize_m68k_tdep): Add declaration.
* machoread.c (_initialize_machoread): Add declaration.
* macrocmd.c (_initialize_macrocmd): Add declaration.
* macroscope.c (_initialize_macroscope): Add declaration.
* maint-test-options.c (_initialize_maint_test_options): Add declaration.
* maint-test-settings.c (_initialize_maint_test_settings): Add declaration.
* maint.c (_initialize_maint_cmds): Add declaration.
* mdebugread.c (_initialize_mdebugread): Add declaration.
* memattr.c (_initialize_mem): Add declaration.
* mep-tdep.c (_initialize_mep_tdep): Add declaration.
* mi/mi-cmd-env.c (_initialize_mi_cmd_env): Add declaration.
* mi/mi-cmds.c (_initialize_mi_cmds): Add declaration.
* mi/mi-interp.c (_initialize_mi_interp): Add declaration.
* mi/mi-main.c (_initialize_mi_main): Add declaration.
* microblaze-linux-tdep.c (_initialize_microblaze_linux_tdep): Add declaration.
* microblaze-tdep.c (_initialize_microblaze_tdep): Add declaration.
* mips-fbsd-nat.c (_initialize_mips_fbsd_nat): Add declaration.
* mips-fbsd-tdep.c (_initialize_mips_fbsd_tdep): Add declaration.
* mips-linux-nat.c (_initialize_mips_linux_nat): Add declaration.
* mips-linux-tdep.c (_initialize_mips_linux_tdep): Add declaration.
* mips-nbsd-nat.c (_initialize_mipsnbsd_nat): Add declaration.
* mips-nbsd-tdep.c (_initialize_mipsnbsd_tdep): Add declaration.
* mips-sde-tdep.c (_initialize_mips_sde_tdep): Add declaration.
* mips-tdep.c (_initialize_mips_tdep): Add declaration.
* mips64-obsd-nat.c (_initialize_mips64obsd_nat): Add declaration.
* mips64-obsd-tdep.c (_initialize_mips64obsd_tdep): Add declaration.
* mipsread.c (_initialize_mipsread): Add declaration.
* mn10300-linux-tdep.c (_initialize_mn10300_linux_tdep): Add declaration.
* mn10300-tdep.c (_initialize_mn10300_tdep): Add declaration.
* moxie-tdep.c (_initialize_moxie_tdep): Add declaration.
* msp430-tdep.c (_initialize_msp430_tdep): Add declaration.
* nds32-tdep.c (_initialize_nds32_tdep): Add declaration.
* nios2-linux-tdep.c (_initialize_nios2_linux_tdep): Add declaration.
* nios2-tdep.c (_initialize_nios2_tdep): Add declaration.
* nto-procfs.c (_initialize_procfs): Add declaration.
* objc-lang.c (_initialize_objc_language): Add declaration.
* observable.c (_initialize_observer): Add declaration.
* opencl-lang.c (_initialize_opencl_language): Add declaration.
* or1k-linux-tdep.c (_initialize_or1k_linux_tdep): Add declaration.
* or1k-tdep.c (_initialize_or1k_tdep): Add declaration.
* osabi.c (_initialize_gdb_osabi): Add declaration.
* osdata.c (_initialize_osdata): Add declaration.
* p-valprint.c (_initialize_pascal_valprint): Add declaration.
* parse.c (_initialize_parse): Add declaration.
* ppc-fbsd-nat.c (_initialize_ppcfbsd_nat): Add declaration.
* ppc-fbsd-tdep.c (_initialize_ppcfbsd_tdep): Add declaration.
* ppc-linux-nat.c (_initialize_ppc_linux_nat): Add declaration.
* ppc-linux-tdep.c (_initialize_ppc_linux_tdep): Add declaration.
* ppc-nbsd-nat.c (_initialize_ppcnbsd_nat): Add declaration.
* ppc-nbsd-tdep.c (_initialize_ppcnbsd_tdep): Add declaration.
* ppc-obsd-nat.c (_initialize_ppcobsd_nat): Add declaration.
* ppc-obsd-tdep.c (_initialize_ppcobsd_tdep): Add declaration.
* printcmd.c (_initialize_printcmd): Add declaration.
* probe.c (_initialize_probe): Add declaration.
* proc-api.c (_initialize_proc_api): Add declaration.
* proc-events.c (_initialize_proc_events): Add declaration.
* proc-service.c (_initialize_proc_service): Add declaration.
* procfs.c (_initialize_procfs): Add declaration.
* producer.c (_initialize_producer): Add declaration.
* psymtab.c (_initialize_psymtab): Add declaration.
* python/python.c (_initialize_python): Add declaration.
* ravenscar-thread.c (_initialize_ravenscar): Add declaration.
* record-btrace.c (_initialize_record_btrace): Add declaration.
* record-full.c (_initialize_record_full): Add declaration.
* record.c (_initialize_record): Add declaration.
* regcache-dump.c (_initialize_regcache_dump): Add declaration.
* regcache.c (_initialize_regcache): Add declaration.
* reggroups.c (_initialize_reggroup): Add declaration.
* remote-notif.c (_initialize_notif): Add declaration.
* remote-sim.c (_initialize_remote_sim): Add declaration.
* remote.c (_initialize_remote): Add declaration.
* reverse.c (_initialize_reverse): Add declaration.
* riscv-fbsd-nat.c (_initialize_riscv_fbsd_nat): Add declaration.
* riscv-fbsd-tdep.c (_initialize_riscv_fbsd_tdep): Add declaration.
* riscv-linux-nat.c (_initialize_riscv_linux_nat): Add declaration.
* riscv-linux-tdep.c (_initialize_riscv_linux_tdep): Add declaration.
* riscv-tdep.c (_initialize_riscv_tdep): Add declaration.
* rl78-tdep.c (_initialize_rl78_tdep): Add declaration.
* rs6000-aix-tdep.c (_initialize_rs6000_aix_tdep): Add declaration.
* rs6000-lynx178-tdep.c (_initialize_rs6000_lynx178_tdep):
Add declaration.
* rs6000-nat.c (_initialize_rs6000_nat): Add declaration.
* rs6000-tdep.c (_initialize_rs6000_tdep): Add declaration.
* run-on-main-thread.c (_initialize_run_on_main_thread): Add declaration.
* rust-exp.y (_initialize_rust_exp): Add declaration.
* rx-tdep.c (_initialize_rx_tdep): Add declaration.
* s12z-tdep.c (_initialize_s12z_tdep): Add declaration.
* s390-linux-nat.c (_initialize_s390_nat): Add declaration.
* s390-linux-tdep.c (_initialize_s390_linux_tdep): Add declaration.
* s390-tdep.c (_initialize_s390_tdep): Add declaration.
* score-tdep.c (_initialize_score_tdep): Add declaration.
* ser-go32.c (_initialize_ser_dos): Add declaration.
* ser-mingw.c (_initialize_ser_windows): Add declaration.
* ser-pipe.c (_initialize_ser_pipe): Add declaration.
* ser-tcp.c (_initialize_ser_tcp): Add declaration.
* ser-uds.c (_initialize_ser_socket): Add declaration.
* ser-unix.c (_initialize_ser_hardwire): Add declaration.
* serial.c (_initialize_serial): Add declaration.
* sh-linux-tdep.c (_initialize_sh_linux_tdep): Add declaration.
* sh-nbsd-nat.c (_initialize_shnbsd_nat): Add declaration.
* sh-nbsd-tdep.c (_initialize_shnbsd_tdep): Add declaration.
* sh-tdep.c (_initialize_sh_tdep): Add declaration.
* skip.c (_initialize_step_skip): Add declaration.
* sol-thread.c (_initialize_sol_thread): Add declaration.
* solib-aix.c (_initialize_solib_aix): Add declaration.
* solib-darwin.c (_initialize_darwin_solib): Add declaration.
* solib-dsbt.c (_initialize_dsbt_solib): Add declaration.
* solib-frv.c (_initialize_frv_solib): Add declaration.
* solib-svr4.c (_initialize_svr4_solib): Add declaration.
* solib-target.c (_initialize_solib_target): Add declaration.
* solib.c (_initialize_solib): Add declaration.
* source-cache.c (_initialize_source_cache): Add declaration.
* source.c (_initialize_source): Add declaration.
* sparc-linux-nat.c (_initialize_sparc_linux_nat): Add declaration.
* sparc-linux-tdep.c (_initialize_sparc_linux_tdep): Add declaration.
* sparc-nat.c (_initialize_sparc_nat): Add declaration.
* sparc-nbsd-nat.c (_initialize_sparcnbsd_nat): Add declaration.
* sparc-nbsd-tdep.c (_initialize_sparcnbsd_tdep): Add declaration.
* sparc-obsd-tdep.c (_initialize_sparc32obsd_tdep): Add declaration.
* sparc-sol2-tdep.c (_initialize_sparc_sol2_tdep): Add declaration.
* sparc-tdep.c (_initialize_sparc_tdep): Add declaration.
* sparc64-fbsd-nat.c (_initialize_sparc64fbsd_nat): Add declaration.
* sparc64-fbsd-tdep.c (_initialize_sparc64fbsd_tdep): Add declaration.
* sparc64-linux-nat.c (_initialize_sparc64_linux_nat): Add declaration.
* sparc64-linux-tdep.c (_initialize_sparc64_linux_tdep): Add declaration.
* sparc64-nat.c (_initialize_sparc64_nat): Add declaration.
* sparc64-nbsd-nat.c (_initialize_sparc64nbsd_nat): Add declaration.
* sparc64-nbsd-tdep.c (_initialize_sparc64nbsd_tdep): Add declaration.
* sparc64-obsd-nat.c (_initialize_sparc64obsd_nat): Add declaration.
* sparc64-obsd-tdep.c (_initialize_sparc64obsd_tdep): Add declaration.
* sparc64-sol2-tdep.c (_initialize_sparc64_sol2_tdep): Add declaration.
* sparc64-tdep.c (_initialize_sparc64_adi_tdep): Add declaration.
* stabsread.c (_initialize_stabsread): Add declaration.
* stack.c (_initialize_stack): Add declaration.
* stap-probe.c (_initialize_stap_probe): Add declaration.
* std-regs.c (_initialize_frame_reg): Add declaration.
* symfile-debug.c (_initialize_symfile_debug): Add declaration.
* symfile-mem.c (_initialize_symfile_mem): Add declaration.
* symfile.c (_initialize_symfile): Add declaration.
* symmisc.c (_initialize_symmisc): Add declaration.
* symtab.c (_initialize_symtab): Add declaration.
* target.c (_initialize_target): Add declaration.
* target-connection.c (_initialize_target_connection): Add
declaration.
* target-dcache.c (_initialize_target_dcache): Add declaration.
* target-descriptions.c (_initialize_target_descriptions): Add declaration.
* thread.c (_initialize_thread): Add declaration.
* tic6x-linux-tdep.c (_initialize_tic6x_linux_tdep): Add declaration.
* tic6x-tdep.c (_initialize_tic6x_tdep): Add declaration.
* tilegx-linux-nat.c (_initialize_tile_linux_nat): Add declaration.
* tilegx-linux-tdep.c (_initialize_tilegx_linux_tdep): Add declaration.
* tilegx-tdep.c (_initialize_tilegx_tdep): Add declaration.
* tracectf.c (_initialize_ctf): Add declaration.
* tracefile-tfile.c (_initialize_tracefile_tfile): Add declaration.
* tracefile.c (_initialize_tracefile): Add declaration.
* tracepoint.c (_initialize_tracepoint): Add declaration.
* tui/tui-hooks.c (_initialize_tui_hooks): Add declaration.
* tui/tui-interp.c (_initialize_tui_interp): Add declaration.
* tui/tui-layout.c (_initialize_tui_layout): Add declaration.
* tui/tui-regs.c (_initialize_tui_regs): Add declaration.
* tui/tui-stack.c (_initialize_tui_stack): Add declaration.
* tui/tui-win.c (_initialize_tui_win): Add declaration.
* tui/tui.c (_initialize_tui): Add declaration.
* typeprint.c (_initialize_typeprint): Add declaration.
* ui-style.c (_initialize_ui_style): Add declaration.
* unittests/array-view-selftests.c (_initialize_array_view_selftests): Add declaration.
* unittests/child-path-selftests.c (_initialize_child_path_selftests): Add declaration.
* unittests/cli-utils-selftests.c (_initialize_cli_utils_selftests): Add declaration.
* unittests/common-utils-selftests.c (_initialize_common_utils_selftests): Add declaration.
* unittests/copy_bitwise-selftests.c (_initialize_copy_bitwise_utils_selftests): Add declaration.
* unittests/environ-selftests.c (_initialize_environ_selftests): Add declaration.
* unittests/filtered_iterator-selftests.c
(_initialize_filtered_iterator_selftests): Add declaration.
* unittests/format_pieces-selftests.c (_initialize_format_pieces_selftests): Add declaration.
* unittests/function-view-selftests.c (_initialize_function_view_selftests): Add declaration.
* unittests/help-doc-selftests.c (_initialize_help_doc_selftests): Add declaration.
* unittests/lookup_name_info-selftests.c (_initialize_lookup_name_info_selftests): Add declaration.
* unittests/main-thread-selftests.c
(_initialize_main_thread_selftests): Add declaration.
* unittests/memory-map-selftests.c (_initialize_memory_map_selftests): Add declaration.
* unittests/memrange-selftests.c (_initialize_memrange_selftests): Add declaration.
* unittests/mkdir-recursive-selftests.c (_initialize_mkdir_recursive_selftests): Add declaration.
* unittests/observable-selftests.c (_initialize_observer_selftest): Add declaration.
* unittests/offset-type-selftests.c (_initialize_offset_type_selftests): Add declaration.
* unittests/optional-selftests.c (_initialize_optional_selftests): Add declaration.
* unittests/parse-connection-spec-selftests.c (_initialize_parse_connection_spec_selftests): Add declaration.
* unittests/rsp-low-selftests.c (_initialize_rsp_low_selftests): Add declaration.
* unittests/scoped_fd-selftests.c (_initialize_scoped_fd_selftests): Add declaration.
* unittests/scoped_mmap-selftests.c (_initialize_scoped_mmap_selftests): Add declaration.
* unittests/scoped_restore-selftests.c (_initialize_scoped_restore_selftests): Add declaration.
* unittests/string_view-selftests.c (_initialize_string_view_selftests): Add declaration.
* unittests/style-selftests.c (_initialize_style_selftest): Add declaration.
* unittests/tracepoint-selftests.c (_initialize_tracepoint_selftests): Add declaration.
* unittests/tui-selftests.c (_initialize_tui_selftest): Add
declaration.
* unittests/unpack-selftests.c (_initialize_unpack_selftests): Add declaration.
* unittests/utils-selftests.c (_initialize_utils_selftests): Add declaration.
* unittests/vec-utils-selftests.c (_initialize_vec_utils_selftests): Add declaration.
* unittests/xml-utils-selftests.c (_initialize_xml_utils): Add declaration.
* user-regs.c (_initialize_user_regs): Add declaration.
* utils.c (_initialize_utils): Add declaration.
* v850-tdep.c (_initialize_v850_tdep): Add declaration.
* valops.c (_initialize_valops): Add declaration.
* valprint.c (_initialize_valprint): Add declaration.
* value.c (_initialize_values): Add declaration.
* varobj.c (_initialize_varobj): Add declaration.
* vax-bsd-nat.c (_initialize_vaxbsd_nat): Add declaration.
* vax-nbsd-tdep.c (_initialize_vaxnbsd_tdep): Add declaration.
* vax-tdep.c (_initialize_vax_tdep): Add declaration.
* windows-nat.c (_initialize_windows_nat): Add declaration.
(_initialize_check_for_gdb_ini): Add declaration.
(_initialize_loadable): Add declaration.
* windows-tdep.c (_initialize_windows_tdep): Add declaration.
* x86-bsd-nat.c (_initialize_x86_bsd_nat): Add declaration.
* x86-linux-nat.c (_initialize_x86_linux_nat): Add declaration.
* xcoffread.c (_initialize_xcoffread): Add declaration.
* xml-support.c (_initialize_xml_support): Add declaration.
* xstormy16-tdep.c (_initialize_xstormy16_tdep): Add declaration.
* xtensa-linux-nat.c (_initialize_xtensa_linux_nat): Add declaration.
* xtensa-linux-tdep.c (_initialize_xtensa_linux_tdep): Add declaration.
* xtensa-tdep.c (_initialize_xtensa_tdep): Add declaration.
Change-Id: I13eec7e0ed2b3c427377a7bdb055cf46da64def9
1739 lines
48 KiB
C
1739 lines
48 KiB
C
/* SystemTap probe support for GDB.
|
||
|
||
Copyright (C) 2012-2020 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 "stap-probe.h"
|
||
#include "probe.h"
|
||
#include "ui-out.h"
|
||
#include "objfiles.h"
|
||
#include "arch-utils.h"
|
||
#include "command.h"
|
||
#include "gdbcmd.h"
|
||
#include "filenames.h"
|
||
#include "value.h"
|
||
#include "ax.h"
|
||
#include "ax-gdb.h"
|
||
#include "complaints.h"
|
||
#include "cli/cli-utils.h"
|
||
#include "linespec.h"
|
||
#include "user-regs.h"
|
||
#include "parser-defs.h"
|
||
#include "language.h"
|
||
#include "elf-bfd.h"
|
||
|
||
#include <ctype.h>
|
||
|
||
/* The name of the SystemTap section where we will find information about
|
||
the probes. */
|
||
|
||
#define STAP_BASE_SECTION_NAME ".stapsdt.base"
|
||
|
||
/* Should we display debug information for the probe's argument expression
|
||
parsing? */
|
||
|
||
static unsigned int stap_expression_debug = 0;
|
||
|
||
/* The various possibilities of bitness defined for a probe's argument.
|
||
|
||
The relationship is:
|
||
|
||
- STAP_ARG_BITNESS_UNDEFINED: The user hasn't specified the bitness.
|
||
- STAP_ARG_BITNESS_8BIT_UNSIGNED: argument string starts with `1@'.
|
||
- STAP_ARG_BITNESS_8BIT_SIGNED: argument string starts with `-1@'.
|
||
- STAP_ARG_BITNESS_16BIT_UNSIGNED: argument string starts with `2@'.
|
||
- STAP_ARG_BITNESS_16BIT_SIGNED: argument string starts with `-2@'.
|
||
- STAP_ARG_BITNESS_32BIT_UNSIGNED: argument string starts with `4@'.
|
||
- STAP_ARG_BITNESS_32BIT_SIGNED: argument string starts with `-4@'.
|
||
- STAP_ARG_BITNESS_64BIT_UNSIGNED: argument string starts with `8@'.
|
||
- STAP_ARG_BITNESS_64BIT_SIGNED: argument string starts with `-8@'. */
|
||
|
||
enum stap_arg_bitness
|
||
{
|
||
STAP_ARG_BITNESS_UNDEFINED,
|
||
STAP_ARG_BITNESS_8BIT_UNSIGNED,
|
||
STAP_ARG_BITNESS_8BIT_SIGNED,
|
||
STAP_ARG_BITNESS_16BIT_UNSIGNED,
|
||
STAP_ARG_BITNESS_16BIT_SIGNED,
|
||
STAP_ARG_BITNESS_32BIT_UNSIGNED,
|
||
STAP_ARG_BITNESS_32BIT_SIGNED,
|
||
STAP_ARG_BITNESS_64BIT_UNSIGNED,
|
||
STAP_ARG_BITNESS_64BIT_SIGNED,
|
||
};
|
||
|
||
/* The following structure represents a single argument for the probe. */
|
||
|
||
struct stap_probe_arg
|
||
{
|
||
/* Constructor for stap_probe_arg. */
|
||
stap_probe_arg (enum stap_arg_bitness bitness_, struct type *atype_,
|
||
expression_up &&aexpr_)
|
||
: bitness (bitness_), atype (atype_), aexpr (std::move (aexpr_))
|
||
{}
|
||
|
||
/* The bitness of this argument. */
|
||
enum stap_arg_bitness bitness;
|
||
|
||
/* The corresponding `struct type *' to the bitness. */
|
||
struct type *atype;
|
||
|
||
/* The argument converted to an internal GDB expression. */
|
||
expression_up aexpr;
|
||
};
|
||
|
||
/* Class that implements the static probe methods for "stap" probes. */
|
||
|
||
class stap_static_probe_ops : public static_probe_ops
|
||
{
|
||
public:
|
||
/* We need a user-provided constructor to placate some compilers.
|
||
See PR build/24937. */
|
||
stap_static_probe_ops ()
|
||
{
|
||
}
|
||
|
||
/* See probe.h. */
|
||
bool is_linespec (const char **linespecp) const override;
|
||
|
||
/* See probe.h. */
|
||
void get_probes (std::vector<std::unique_ptr<probe>> *probesp,
|
||
struct objfile *objfile) const override;
|
||
|
||
/* See probe.h. */
|
||
const char *type_name () const override;
|
||
|
||
/* See probe.h. */
|
||
std::vector<struct info_probe_column> gen_info_probes_table_header
|
||
() const override;
|
||
};
|
||
|
||
/* SystemTap static_probe_ops. */
|
||
|
||
const stap_static_probe_ops stap_static_probe_ops {};
|
||
|
||
class stap_probe : public probe
|
||
{
|
||
public:
|
||
/* Constructor for stap_probe. */
|
||
stap_probe (std::string &&name_, std::string &&provider_, CORE_ADDR address_,
|
||
struct gdbarch *arch_, CORE_ADDR sem_addr, const char *args_text)
|
||
: probe (std::move (name_), std::move (provider_), address_, arch_),
|
||
m_sem_addr (sem_addr),
|
||
m_have_parsed_args (false), m_unparsed_args_text (args_text)
|
||
{}
|
||
|
||
/* See probe.h. */
|
||
CORE_ADDR get_relocated_address (struct objfile *objfile) override;
|
||
|
||
/* See probe.h. */
|
||
unsigned get_argument_count (struct gdbarch *gdbarch) override;
|
||
|
||
/* See probe.h. */
|
||
bool can_evaluate_arguments () const override;
|
||
|
||
/* See probe.h. */
|
||
struct value *evaluate_argument (unsigned n,
|
||
struct frame_info *frame) override;
|
||
|
||
/* See probe.h. */
|
||
void compile_to_ax (struct agent_expr *aexpr,
|
||
struct axs_value *axs_value,
|
||
unsigned n) override;
|
||
|
||
/* See probe.h. */
|
||
void set_semaphore (struct objfile *objfile,
|
||
struct gdbarch *gdbarch) override;
|
||
|
||
/* See probe.h. */
|
||
void clear_semaphore (struct objfile *objfile,
|
||
struct gdbarch *gdbarch) override;
|
||
|
||
/* See probe.h. */
|
||
const static_probe_ops *get_static_ops () const override;
|
||
|
||
/* See probe.h. */
|
||
std::vector<const char *> gen_info_probes_table_values () const override;
|
||
|
||
/* Return argument N of probe.
|
||
|
||
If the probe's arguments have not been parsed yet, parse them. If
|
||
there are no arguments, throw an exception (error). Otherwise,
|
||
return the requested argument. */
|
||
struct stap_probe_arg *get_arg_by_number (unsigned n,
|
||
struct gdbarch *gdbarch)
|
||
{
|
||
if (!m_have_parsed_args)
|
||
this->parse_arguments (gdbarch);
|
||
|
||
gdb_assert (m_have_parsed_args);
|
||
if (m_parsed_args.empty ())
|
||
internal_error (__FILE__, __LINE__,
|
||
_("Probe '%s' apparently does not have arguments, but \n"
|
||
"GDB is requesting its argument number %u anyway. "
|
||
"This should not happen. Please report this bug."),
|
||
this->get_name ().c_str (), n);
|
||
|
||
if (n > m_parsed_args.size ())
|
||
internal_error (__FILE__, __LINE__,
|
||
_("Probe '%s' has %d arguments, but GDB is requesting\n"
|
||
"argument %u. This should not happen. Please\n"
|
||
"report this bug."),
|
||
this->get_name ().c_str (),
|
||
(int) m_parsed_args.size (), n);
|
||
|
||
return &m_parsed_args[n];
|
||
}
|
||
|
||
/* Function which parses an argument string from the probe,
|
||
correctly splitting the arguments and storing their information
|
||
in properly ways.
|
||
|
||
Consider the following argument string (x86 syntax):
|
||
|
||
`4@%eax 4@$10'
|
||
|
||
We have two arguments, `%eax' and `$10', both with 32-bit
|
||
unsigned bitness. This function basically handles them, properly
|
||
filling some structures with this information. */
|
||
void parse_arguments (struct gdbarch *gdbarch);
|
||
|
||
private:
|
||
/* If the probe has a semaphore associated, then this is the value of
|
||
it, relative to SECT_OFF_DATA. */
|
||
CORE_ADDR m_sem_addr;
|
||
|
||
/* True if the arguments have been parsed. */
|
||
bool m_have_parsed_args;
|
||
|
||
/* The text version of the probe's arguments, unparsed. */
|
||
const char *m_unparsed_args_text;
|
||
|
||
/* Information about each argument. This is an array of `stap_probe_arg',
|
||
with each entry representing one argument. This is only valid if
|
||
M_ARGS_PARSED is true. */
|
||
std::vector<struct stap_probe_arg> m_parsed_args;
|
||
};
|
||
|
||
/* When parsing the arguments, we have to establish different precedences
|
||
for the various kinds of asm operators. This enumeration represents those
|
||
precedences.
|
||
|
||
This logic behind this is available at
|
||
<http://sourceware.org/binutils/docs/as/Infix-Ops.html#Infix-Ops>, or using
|
||
the command "info '(as)Infix Ops'". */
|
||
|
||
enum stap_operand_prec
|
||
{
|
||
/* Lowest precedence, used for non-recognized operands or for the beginning
|
||
of the parsing process. */
|
||
STAP_OPERAND_PREC_NONE = 0,
|
||
|
||
/* Precedence of logical OR. */
|
||
STAP_OPERAND_PREC_LOGICAL_OR,
|
||
|
||
/* Precedence of logical AND. */
|
||
STAP_OPERAND_PREC_LOGICAL_AND,
|
||
|
||
/* Precedence of additive (plus, minus) and comparative (equal, less,
|
||
greater-than, etc) operands. */
|
||
STAP_OPERAND_PREC_ADD_CMP,
|
||
|
||
/* Precedence of bitwise operands (bitwise OR, XOR, bitwise AND,
|
||
logical NOT). */
|
||
STAP_OPERAND_PREC_BITWISE,
|
||
|
||
/* Precedence of multiplicative operands (multiplication, division,
|
||
remainder, left shift and right shift). */
|
||
STAP_OPERAND_PREC_MUL
|
||
};
|
||
|
||
static void stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
|
||
enum stap_operand_prec prec);
|
||
|
||
static void stap_parse_argument_conditionally (struct stap_parse_info *p);
|
||
|
||
/* Returns true if *S is an operator, false otherwise. */
|
||
|
||
static bool stap_is_operator (const char *op);
|
||
|
||
static void
|
||
show_stapexpressiondebug (struct ui_file *file, int from_tty,
|
||
struct cmd_list_element *c, const char *value)
|
||
{
|
||
fprintf_filtered (file, _("SystemTap Probe expression debugging is %s.\n"),
|
||
value);
|
||
}
|
||
|
||
/* Returns the operator precedence level of OP, or STAP_OPERAND_PREC_NONE
|
||
if the operator code was not recognized. */
|
||
|
||
static enum stap_operand_prec
|
||
stap_get_operator_prec (enum exp_opcode op)
|
||
{
|
||
switch (op)
|
||
{
|
||
case BINOP_LOGICAL_OR:
|
||
return STAP_OPERAND_PREC_LOGICAL_OR;
|
||
|
||
case BINOP_LOGICAL_AND:
|
||
return STAP_OPERAND_PREC_LOGICAL_AND;
|
||
|
||
case BINOP_ADD:
|
||
case BINOP_SUB:
|
||
case BINOP_EQUAL:
|
||
case BINOP_NOTEQUAL:
|
||
case BINOP_LESS:
|
||
case BINOP_LEQ:
|
||
case BINOP_GTR:
|
||
case BINOP_GEQ:
|
||
return STAP_OPERAND_PREC_ADD_CMP;
|
||
|
||
case BINOP_BITWISE_IOR:
|
||
case BINOP_BITWISE_AND:
|
||
case BINOP_BITWISE_XOR:
|
||
case UNOP_LOGICAL_NOT:
|
||
return STAP_OPERAND_PREC_BITWISE;
|
||
|
||
case BINOP_MUL:
|
||
case BINOP_DIV:
|
||
case BINOP_REM:
|
||
case BINOP_LSH:
|
||
case BINOP_RSH:
|
||
return STAP_OPERAND_PREC_MUL;
|
||
|
||
default:
|
||
return STAP_OPERAND_PREC_NONE;
|
||
}
|
||
}
|
||
|
||
/* Given S, read the operator in it. Return the EXP_OPCODE which
|
||
represents the operator detected, or throw an error if no operator
|
||
was found. */
|
||
|
||
static enum exp_opcode
|
||
stap_get_opcode (const char **s)
|
||
{
|
||
const char c = **s;
|
||
enum exp_opcode op;
|
||
|
||
*s += 1;
|
||
|
||
switch (c)
|
||
{
|
||
case '*':
|
||
op = BINOP_MUL;
|
||
break;
|
||
|
||
case '/':
|
||
op = BINOP_DIV;
|
||
break;
|
||
|
||
case '%':
|
||
op = BINOP_REM;
|
||
break;
|
||
|
||
case '<':
|
||
op = BINOP_LESS;
|
||
if (**s == '<')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_LSH;
|
||
}
|
||
else if (**s == '=')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_LEQ;
|
||
}
|
||
else if (**s == '>')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_NOTEQUAL;
|
||
}
|
||
break;
|
||
|
||
case '>':
|
||
op = BINOP_GTR;
|
||
if (**s == '>')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_RSH;
|
||
}
|
||
else if (**s == '=')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_GEQ;
|
||
}
|
||
break;
|
||
|
||
case '|':
|
||
op = BINOP_BITWISE_IOR;
|
||
if (**s == '|')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_LOGICAL_OR;
|
||
}
|
||
break;
|
||
|
||
case '&':
|
||
op = BINOP_BITWISE_AND;
|
||
if (**s == '&')
|
||
{
|
||
*s += 1;
|
||
op = BINOP_LOGICAL_AND;
|
||
}
|
||
break;
|
||
|
||
case '^':
|
||
op = BINOP_BITWISE_XOR;
|
||
break;
|
||
|
||
case '!':
|
||
op = UNOP_LOGICAL_NOT;
|
||
break;
|
||
|
||
case '+':
|
||
op = BINOP_ADD;
|
||
break;
|
||
|
||
case '-':
|
||
op = BINOP_SUB;
|
||
break;
|
||
|
||
case '=':
|
||
gdb_assert (**s == '=');
|
||
op = BINOP_EQUAL;
|
||
break;
|
||
|
||
default:
|
||
error (_("Invalid opcode in expression `%s' for SystemTap"
|
||
"probe"), *s);
|
||
}
|
||
|
||
return op;
|
||
}
|
||
|
||
/* Given the bitness of the argument, represented by B, return the
|
||
corresponding `struct type *', or throw an error if B is
|
||
unknown. */
|
||
|
||
static struct type *
|
||
stap_get_expected_argument_type (struct gdbarch *gdbarch,
|
||
enum stap_arg_bitness b,
|
||
const char *probe_name)
|
||
{
|
||
switch (b)
|
||
{
|
||
case STAP_ARG_BITNESS_UNDEFINED:
|
||
if (gdbarch_addr_bit (gdbarch) == 32)
|
||
return builtin_type (gdbarch)->builtin_uint32;
|
||
else
|
||
return builtin_type (gdbarch)->builtin_uint64;
|
||
|
||
case STAP_ARG_BITNESS_8BIT_UNSIGNED:
|
||
return builtin_type (gdbarch)->builtin_uint8;
|
||
|
||
case STAP_ARG_BITNESS_8BIT_SIGNED:
|
||
return builtin_type (gdbarch)->builtin_int8;
|
||
|
||
case STAP_ARG_BITNESS_16BIT_UNSIGNED:
|
||
return builtin_type (gdbarch)->builtin_uint16;
|
||
|
||
case STAP_ARG_BITNESS_16BIT_SIGNED:
|
||
return builtin_type (gdbarch)->builtin_int16;
|
||
|
||
case STAP_ARG_BITNESS_32BIT_SIGNED:
|
||
return builtin_type (gdbarch)->builtin_int32;
|
||
|
||
case STAP_ARG_BITNESS_32BIT_UNSIGNED:
|
||
return builtin_type (gdbarch)->builtin_uint32;
|
||
|
||
case STAP_ARG_BITNESS_64BIT_SIGNED:
|
||
return builtin_type (gdbarch)->builtin_int64;
|
||
|
||
case STAP_ARG_BITNESS_64BIT_UNSIGNED:
|
||
return builtin_type (gdbarch)->builtin_uint64;
|
||
|
||
default:
|
||
error (_("Undefined bitness for probe '%s'."), probe_name);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Helper function to check for a generic list of prefixes. GDBARCH
|
||
is the current gdbarch being used. S is the expression being
|
||
analyzed. If R is not NULL, it will be used to return the found
|
||
prefix. PREFIXES is the list of expected prefixes.
|
||
|
||
This function does a case-insensitive match.
|
||
|
||
Return true if any prefix has been found, false otherwise. */
|
||
|
||
static bool
|
||
stap_is_generic_prefix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r, const char *const *prefixes)
|
||
{
|
||
const char *const *p;
|
||
|
||
if (prefixes == NULL)
|
||
{
|
||
if (r != NULL)
|
||
*r = "";
|
||
|
||
return true;
|
||
}
|
||
|
||
for (p = prefixes; *p != NULL; ++p)
|
||
if (strncasecmp (s, *p, strlen (*p)) == 0)
|
||
{
|
||
if (r != NULL)
|
||
*r = *p;
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/* Return true if S points to a register prefix, false otherwise. For
|
||
a description of the arguments, look at stap_is_generic_prefix. */
|
||
|
||
static bool
|
||
stap_is_register_prefix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *t = gdbarch_stap_register_prefixes (gdbarch);
|
||
|
||
return stap_is_generic_prefix (gdbarch, s, r, t);
|
||
}
|
||
|
||
/* Return true if S points to a register indirection prefix, false
|
||
otherwise. For a description of the arguments, look at
|
||
stap_is_generic_prefix. */
|
||
|
||
static bool
|
||
stap_is_register_indirection_prefix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *t = gdbarch_stap_register_indirection_prefixes (gdbarch);
|
||
|
||
return stap_is_generic_prefix (gdbarch, s, r, t);
|
||
}
|
||
|
||
/* Return true if S points to an integer prefix, false otherwise. For
|
||
a description of the arguments, look at stap_is_generic_prefix.
|
||
|
||
This function takes care of analyzing whether we are dealing with
|
||
an expected integer prefix, or, if there is no integer prefix to be
|
||
expected, whether we are dealing with a digit. It does a
|
||
case-insensitive match. */
|
||
|
||
static bool
|
||
stap_is_integer_prefix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *t = gdbarch_stap_integer_prefixes (gdbarch);
|
||
const char *const *p;
|
||
|
||
if (t == NULL)
|
||
{
|
||
/* A NULL value here means that integers do not have a prefix.
|
||
We just check for a digit then. */
|
||
if (r != NULL)
|
||
*r = "";
|
||
|
||
return isdigit (*s) > 0;
|
||
}
|
||
|
||
for (p = t; *p != NULL; ++p)
|
||
{
|
||
size_t len = strlen (*p);
|
||
|
||
if ((len == 0 && isdigit (*s))
|
||
|| (len > 0 && strncasecmp (s, *p, len) == 0))
|
||
{
|
||
/* Integers may or may not have a prefix. The "len == 0"
|
||
check covers the case when integers do not have a prefix
|
||
(therefore, we just check if we have a digit). The call
|
||
to "strncasecmp" covers the case when they have a
|
||
prefix. */
|
||
if (r != NULL)
|
||
*r = *p;
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/* Helper function to check for a generic list of suffixes. If we are
|
||
not expecting any suffixes, then it just returns 1. If we are
|
||
expecting at least one suffix, then it returns true if a suffix has
|
||
been found, false otherwise. GDBARCH is the current gdbarch being
|
||
used. S is the expression being analyzed. If R is not NULL, it
|
||
will be used to return the found suffix. SUFFIXES is the list of
|
||
expected suffixes. This function does a case-insensitive
|
||
match. */
|
||
|
||
static bool
|
||
stap_generic_check_suffix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r, const char *const *suffixes)
|
||
{
|
||
const char *const *p;
|
||
bool found = false;
|
||
|
||
if (suffixes == NULL)
|
||
{
|
||
if (r != NULL)
|
||
*r = "";
|
||
|
||
return true;
|
||
}
|
||
|
||
for (p = suffixes; *p != NULL; ++p)
|
||
if (strncasecmp (s, *p, strlen (*p)) == 0)
|
||
{
|
||
if (r != NULL)
|
||
*r = *p;
|
||
|
||
found = true;
|
||
break;
|
||
}
|
||
|
||
return found;
|
||
}
|
||
|
||
/* Return true if S points to an integer suffix, false otherwise. For
|
||
a description of the arguments, look at
|
||
stap_generic_check_suffix. */
|
||
|
||
static bool
|
||
stap_check_integer_suffix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *p = gdbarch_stap_integer_suffixes (gdbarch);
|
||
|
||
return stap_generic_check_suffix (gdbarch, s, r, p);
|
||
}
|
||
|
||
/* Return true if S points to a register suffix, false otherwise. For
|
||
a description of the arguments, look at
|
||
stap_generic_check_suffix. */
|
||
|
||
static bool
|
||
stap_check_register_suffix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *p = gdbarch_stap_register_suffixes (gdbarch);
|
||
|
||
return stap_generic_check_suffix (gdbarch, s, r, p);
|
||
}
|
||
|
||
/* Return true if S points to a register indirection suffix, false
|
||
otherwise. For a description of the arguments, look at
|
||
stap_generic_check_suffix. */
|
||
|
||
static bool
|
||
stap_check_register_indirection_suffix (struct gdbarch *gdbarch, const char *s,
|
||
const char **r)
|
||
{
|
||
const char *const *p = gdbarch_stap_register_indirection_suffixes (gdbarch);
|
||
|
||
return stap_generic_check_suffix (gdbarch, s, r, p);
|
||
}
|
||
|
||
/* Function responsible for parsing a register operand according to
|
||
SystemTap parlance. Assuming:
|
||
|
||
RP = register prefix
|
||
RS = register suffix
|
||
RIP = register indirection prefix
|
||
RIS = register indirection suffix
|
||
|
||
Then a register operand can be:
|
||
|
||
[RIP] [RP] REGISTER [RS] [RIS]
|
||
|
||
This function takes care of a register's indirection, displacement and
|
||
direct access. It also takes into consideration the fact that some
|
||
registers are named differently inside and outside GDB, e.g., PPC's
|
||
general-purpose registers are represented by integers in the assembly
|
||
language (e.g., `15' is the 15th general-purpose register), but inside
|
||
GDB they have a prefix (the letter `r') appended. */
|
||
|
||
static void
|
||
stap_parse_register_operand (struct stap_parse_info *p)
|
||
{
|
||
/* Simple flag to indicate whether we have seen a minus signal before
|
||
certain number. */
|
||
bool got_minus = false;
|
||
/* Flags to indicate whether this register access is being displaced and/or
|
||
indirected. */
|
||
bool disp_p = false;
|
||
bool indirect_p = false;
|
||
struct gdbarch *gdbarch = p->gdbarch;
|
||
/* Needed to generate the register name as a part of an expression. */
|
||
struct stoken str;
|
||
/* Variables used to extract the register name from the probe's
|
||
argument. */
|
||
const char *start;
|
||
const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
|
||
const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
|
||
const char *reg_prefix;
|
||
const char *reg_ind_prefix;
|
||
const char *reg_suffix;
|
||
const char *reg_ind_suffix;
|
||
|
||
/* Checking for a displacement argument. */
|
||
if (*p->arg == '+')
|
||
{
|
||
/* If it's a plus sign, we don't need to do anything, just advance the
|
||
pointer. */
|
||
++p->arg;
|
||
}
|
||
else if (*p->arg == '-')
|
||
{
|
||
got_minus = true;
|
||
++p->arg;
|
||
}
|
||
|
||
if (isdigit (*p->arg))
|
||
{
|
||
/* The value of the displacement. */
|
||
long displacement;
|
||
char *endp;
|
||
|
||
disp_p = true;
|
||
displacement = strtol (p->arg, &endp, 10);
|
||
p->arg = endp;
|
||
|
||
/* Generating the expression for the displacement. */
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
|
||
write_exp_elt_longcst (&p->pstate, displacement);
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
if (got_minus)
|
||
write_exp_elt_opcode (&p->pstate, UNOP_NEG);
|
||
}
|
||
|
||
/* Getting rid of register indirection prefix. */
|
||
if (stap_is_register_indirection_prefix (gdbarch, p->arg, ®_ind_prefix))
|
||
{
|
||
indirect_p = true;
|
||
p->arg += strlen (reg_ind_prefix);
|
||
}
|
||
|
||
if (disp_p && !indirect_p)
|
||
error (_("Invalid register displacement syntax on expression `%s'."),
|
||
p->saved_arg);
|
||
|
||
/* Getting rid of register prefix. */
|
||
if (stap_is_register_prefix (gdbarch, p->arg, ®_prefix))
|
||
p->arg += strlen (reg_prefix);
|
||
|
||
/* Now we should have only the register name. Let's extract it and get
|
||
the associated number. */
|
||
start = p->arg;
|
||
|
||
/* We assume the register name is composed by letters and numbers. */
|
||
while (isalnum (*p->arg))
|
||
++p->arg;
|
||
|
||
std::string regname (start, p->arg - start);
|
||
|
||
/* We only add the GDB's register prefix/suffix if we are dealing with
|
||
a numeric register. */
|
||
if (isdigit (*start))
|
||
{
|
||
if (gdb_reg_prefix != NULL)
|
||
regname = gdb_reg_prefix + regname;
|
||
|
||
if (gdb_reg_suffix != NULL)
|
||
regname += gdb_reg_suffix;
|
||
}
|
||
|
||
int regnum = user_reg_map_name_to_regnum (gdbarch, regname.c_str (),
|
||
regname.size ());
|
||
|
||
/* Is this a valid register name? */
|
||
if (regnum == -1)
|
||
error (_("Invalid register name `%s' on expression `%s'."),
|
||
regname.c_str (), p->saved_arg);
|
||
|
||
/* Check if there's any special treatment that the arch-specific
|
||
code would like to perform on the register name. */
|
||
if (gdbarch_stap_adjust_register_p (gdbarch))
|
||
{
|
||
std::string newregname
|
||
= gdbarch_stap_adjust_register (gdbarch, p, regname, regnum);
|
||
|
||
if (regname != newregname)
|
||
{
|
||
/* This is just a check we perform to make sure that the
|
||
arch-dependent code has provided us with a valid
|
||
register name. */
|
||
regnum = user_reg_map_name_to_regnum (gdbarch, newregname.c_str (),
|
||
newregname.size ());
|
||
|
||
if (regnum == -1)
|
||
internal_error (__FILE__, __LINE__,
|
||
_("Invalid register name '%s' after replacing it"
|
||
" (previous name was '%s')"),
|
||
newregname.c_str (), regname.c_str ());
|
||
|
||
regname = newregname;
|
||
}
|
||
}
|
||
|
||
write_exp_elt_opcode (&p->pstate, OP_REGISTER);
|
||
str.ptr = regname.c_str ();
|
||
str.length = regname.size ();
|
||
write_exp_string (&p->pstate, str);
|
||
write_exp_elt_opcode (&p->pstate, OP_REGISTER);
|
||
|
||
if (indirect_p)
|
||
{
|
||
if (disp_p)
|
||
write_exp_elt_opcode (&p->pstate, BINOP_ADD);
|
||
|
||
/* Casting to the expected type. */
|
||
write_exp_elt_opcode (&p->pstate, UNOP_CAST);
|
||
write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
|
||
write_exp_elt_opcode (&p->pstate, UNOP_CAST);
|
||
|
||
write_exp_elt_opcode (&p->pstate, UNOP_IND);
|
||
}
|
||
|
||
/* Getting rid of the register name suffix. */
|
||
if (stap_check_register_suffix (gdbarch, p->arg, ®_suffix))
|
||
p->arg += strlen (reg_suffix);
|
||
else
|
||
error (_("Missing register name suffix on expression `%s'."),
|
||
p->saved_arg);
|
||
|
||
/* Getting rid of the register indirection suffix. */
|
||
if (indirect_p)
|
||
{
|
||
if (stap_check_register_indirection_suffix (gdbarch, p->arg,
|
||
®_ind_suffix))
|
||
p->arg += strlen (reg_ind_suffix);
|
||
else
|
||
error (_("Missing indirection suffix on expression `%s'."),
|
||
p->saved_arg);
|
||
}
|
||
}
|
||
|
||
/* This function is responsible for parsing a single operand.
|
||
|
||
A single operand can be:
|
||
|
||
- an unary operation (e.g., `-5', `~2', or even with subexpressions
|
||
like `-(2 + 1)')
|
||
- a register displacement, which will be treated as a register
|
||
operand (e.g., `-4(%eax)' on x86)
|
||
- a numeric constant, or
|
||
- a register operand (see function `stap_parse_register_operand')
|
||
|
||
The function also calls special-handling functions to deal with
|
||
unrecognized operands, allowing arch-specific parsers to be
|
||
created. */
|
||
|
||
static void
|
||
stap_parse_single_operand (struct stap_parse_info *p)
|
||
{
|
||
struct gdbarch *gdbarch = p->gdbarch;
|
||
const char *int_prefix = NULL;
|
||
|
||
/* We first try to parse this token as a "special token". */
|
||
if (gdbarch_stap_parse_special_token_p (gdbarch)
|
||
&& (gdbarch_stap_parse_special_token (gdbarch, p) != 0))
|
||
{
|
||
/* If the return value of the above function is not zero,
|
||
it means it successfully parsed the special token.
|
||
|
||
If it is NULL, we try to parse it using our method. */
|
||
return;
|
||
}
|
||
|
||
if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+')
|
||
{
|
||
char c = *p->arg;
|
||
/* We use this variable to do a lookahead. */
|
||
const char *tmp = p->arg;
|
||
bool has_digit = false;
|
||
|
||
/* Skipping signal. */
|
||
++tmp;
|
||
|
||
/* This is an unary operation. Here is a list of allowed tokens
|
||
here:
|
||
|
||
- numeric literal;
|
||
- number (from register displacement)
|
||
- subexpression (beginning with `(')
|
||
|
||
We handle the register displacement here, and the other cases
|
||
recursively. */
|
||
if (p->inside_paren_p)
|
||
tmp = skip_spaces (tmp);
|
||
|
||
while (isdigit (*tmp))
|
||
{
|
||
/* We skip the digit here because we are only interested in
|
||
knowing what kind of unary operation this is. The digit
|
||
will be handled by one of the functions that will be
|
||
called below ('stap_parse_argument_conditionally' or
|
||
'stap_parse_register_operand'). */
|
||
++tmp;
|
||
has_digit = true;
|
||
}
|
||
|
||
if (has_digit && stap_is_register_indirection_prefix (gdbarch, tmp,
|
||
NULL))
|
||
{
|
||
/* If we are here, it means it is a displacement. The only
|
||
operations allowed here are `-' and `+'. */
|
||
if (c != '-' && c != '+')
|
||
error (_("Invalid operator `%c' for register displacement "
|
||
"on expression `%s'."), c, p->saved_arg);
|
||
|
||
stap_parse_register_operand (p);
|
||
}
|
||
else
|
||
{
|
||
/* This is not a displacement. We skip the operator, and
|
||
deal with it when the recursion returns. */
|
||
++p->arg;
|
||
stap_parse_argument_conditionally (p);
|
||
if (c == '-')
|
||
write_exp_elt_opcode (&p->pstate, UNOP_NEG);
|
||
else if (c == '~')
|
||
write_exp_elt_opcode (&p->pstate, UNOP_COMPLEMENT);
|
||
}
|
||
}
|
||
else if (isdigit (*p->arg))
|
||
{
|
||
/* A temporary variable, needed for lookahead. */
|
||
const char *tmp = p->arg;
|
||
char *endp;
|
||
long number;
|
||
|
||
/* We can be dealing with a numeric constant, or with a register
|
||
displacement. */
|
||
number = strtol (tmp, &endp, 10);
|
||
tmp = endp;
|
||
|
||
if (p->inside_paren_p)
|
||
tmp = skip_spaces (tmp);
|
||
|
||
/* If "stap_is_integer_prefix" returns true, it means we can
|
||
accept integers without a prefix here. But we also need to
|
||
check whether the next token (i.e., "tmp") is not a register
|
||
indirection prefix. */
|
||
if (stap_is_integer_prefix (gdbarch, p->arg, NULL)
|
||
&& !stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
|
||
{
|
||
const char *int_suffix;
|
||
|
||
/* We are dealing with a numeric constant. */
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
write_exp_elt_type (&p->pstate,
|
||
builtin_type (gdbarch)->builtin_long);
|
||
write_exp_elt_longcst (&p->pstate, number);
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
|
||
p->arg = tmp;
|
||
|
||
if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
|
||
p->arg += strlen (int_suffix);
|
||
else
|
||
error (_("Invalid constant suffix on expression `%s'."),
|
||
p->saved_arg);
|
||
}
|
||
else if (stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
|
||
stap_parse_register_operand (p);
|
||
else
|
||
error (_("Unknown numeric token on expression `%s'."),
|
||
p->saved_arg);
|
||
}
|
||
else if (stap_is_integer_prefix (gdbarch, p->arg, &int_prefix))
|
||
{
|
||
/* We are dealing with a numeric constant. */
|
||
long number;
|
||
char *endp;
|
||
const char *int_suffix;
|
||
|
||
p->arg += strlen (int_prefix);
|
||
number = strtol (p->arg, &endp, 10);
|
||
p->arg = endp;
|
||
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
|
||
write_exp_elt_longcst (&p->pstate, number);
|
||
write_exp_elt_opcode (&p->pstate, OP_LONG);
|
||
|
||
if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
|
||
p->arg += strlen (int_suffix);
|
||
else
|
||
error (_("Invalid constant suffix on expression `%s'."),
|
||
p->saved_arg);
|
||
}
|
||
else if (stap_is_register_prefix (gdbarch, p->arg, NULL)
|
||
|| stap_is_register_indirection_prefix (gdbarch, p->arg, NULL))
|
||
stap_parse_register_operand (p);
|
||
else
|
||
error (_("Operator `%c' not recognized on expression `%s'."),
|
||
*p->arg, p->saved_arg);
|
||
}
|
||
|
||
/* This function parses an argument conditionally, based on single or
|
||
non-single operands. A non-single operand would be a parenthesized
|
||
expression (e.g., `(2 + 1)'), and a single operand is anything that
|
||
starts with `-', `~', `+' (i.e., unary operators), a digit, or
|
||
something recognized by `gdbarch_stap_is_single_operand'. */
|
||
|
||
static void
|
||
stap_parse_argument_conditionally (struct stap_parse_info *p)
|
||
{
|
||
gdb_assert (gdbarch_stap_is_single_operand_p (p->gdbarch));
|
||
|
||
if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */
|
||
|| isdigit (*p->arg)
|
||
|| gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
|
||
stap_parse_single_operand (p);
|
||
else if (*p->arg == '(')
|
||
{
|
||
/* We are dealing with a parenthesized operand. It means we
|
||
have to parse it as it was a separate expression, without
|
||
left-side or precedence. */
|
||
++p->arg;
|
||
p->arg = skip_spaces (p->arg);
|
||
++p->inside_paren_p;
|
||
|
||
stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
|
||
|
||
--p->inside_paren_p;
|
||
if (*p->arg != ')')
|
||
error (_("Missign close-paren on expression `%s'."),
|
||
p->saved_arg);
|
||
|
||
++p->arg;
|
||
if (p->inside_paren_p)
|
||
p->arg = skip_spaces (p->arg);
|
||
}
|
||
else
|
||
error (_("Cannot parse expression `%s'."), p->saved_arg);
|
||
}
|
||
|
||
/* Helper function for `stap_parse_argument'. Please, see its comments to
|
||
better understand what this function does. */
|
||
|
||
static void
|
||
stap_parse_argument_1 (struct stap_parse_info *p, bool has_lhs,
|
||
enum stap_operand_prec prec)
|
||
{
|
||
/* This is an operator-precedence parser.
|
||
|
||
We work with left- and right-sides of expressions, and
|
||
parse them depending on the precedence of the operators
|
||
we find. */
|
||
|
||
gdb_assert (p->arg != NULL);
|
||
|
||
if (p->inside_paren_p)
|
||
p->arg = skip_spaces (p->arg);
|
||
|
||
if (!has_lhs)
|
||
{
|
||
/* We were called without a left-side, either because this is the
|
||
first call, or because we were called to parse a parenthesized
|
||
expression. It doesn't really matter; we have to parse the
|
||
left-side in order to continue the process. */
|
||
stap_parse_argument_conditionally (p);
|
||
}
|
||
|
||
/* Start to parse the right-side, and to "join" left and right sides
|
||
depending on the operation specified.
|
||
|
||
This loop shall continue until we run out of characters in the input,
|
||
or until we find a close-parenthesis, which means that we've reached
|
||
the end of a sub-expression. */
|
||
while (*p->arg != '\0' && *p->arg != ')' && !isspace (*p->arg))
|
||
{
|
||
const char *tmp_exp_buf;
|
||
enum exp_opcode opcode;
|
||
enum stap_operand_prec cur_prec;
|
||
|
||
if (!stap_is_operator (p->arg))
|
||
error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
|
||
p->saved_arg);
|
||
|
||
/* We have to save the current value of the expression buffer because
|
||
the `stap_get_opcode' modifies it in order to get the current
|
||
operator. If this operator's precedence is lower than PREC, we
|
||
should return and not advance the expression buffer pointer. */
|
||
tmp_exp_buf = p->arg;
|
||
opcode = stap_get_opcode (&tmp_exp_buf);
|
||
|
||
cur_prec = stap_get_operator_prec (opcode);
|
||
if (cur_prec < prec)
|
||
{
|
||
/* If the precedence of the operator that we are seeing now is
|
||
lower than the precedence of the first operator seen before
|
||
this parsing process began, it means we should stop parsing
|
||
and return. */
|
||
break;
|
||
}
|
||
|
||
p->arg = tmp_exp_buf;
|
||
if (p->inside_paren_p)
|
||
p->arg = skip_spaces (p->arg);
|
||
|
||
/* Parse the right-side of the expression. */
|
||
stap_parse_argument_conditionally (p);
|
||
|
||
/* While we still have operators, try to parse another
|
||
right-side, but using the current right-side as a left-side. */
|
||
while (*p->arg != '\0' && stap_is_operator (p->arg))
|
||
{
|
||
enum exp_opcode lookahead_opcode;
|
||
enum stap_operand_prec lookahead_prec;
|
||
|
||
/* Saving the current expression buffer position. The explanation
|
||
is the same as above. */
|
||
tmp_exp_buf = p->arg;
|
||
lookahead_opcode = stap_get_opcode (&tmp_exp_buf);
|
||
lookahead_prec = stap_get_operator_prec (lookahead_opcode);
|
||
|
||
if (lookahead_prec <= prec)
|
||
{
|
||
/* If we are dealing with an operator whose precedence is lower
|
||
than the first one, just abandon the attempt. */
|
||
break;
|
||
}
|
||
|
||
/* Parse the right-side of the expression, but since we already
|
||
have a left-side at this point, set `has_lhs' to 1. */
|
||
stap_parse_argument_1 (p, 1, lookahead_prec);
|
||
}
|
||
|
||
write_exp_elt_opcode (&p->pstate, opcode);
|
||
}
|
||
}
|
||
|
||
/* Parse a probe's argument.
|
||
|
||
Assuming that:
|
||
|
||
LP = literal integer prefix
|
||
LS = literal integer suffix
|
||
|
||
RP = register prefix
|
||
RS = register suffix
|
||
|
||
RIP = register indirection prefix
|
||
RIS = register indirection suffix
|
||
|
||
This routine assumes that arguments' tokens are of the form:
|
||
|
||
- [LP] NUMBER [LS]
|
||
- [RP] REGISTER [RS]
|
||
- [RIP] [RP] REGISTER [RS] [RIS]
|
||
- If we find a number without LP, we try to parse it as a literal integer
|
||
constant (if LP == NULL), or as a register displacement.
|
||
- We count parenthesis, and only skip whitespaces if we are inside them.
|
||
- If we find an operator, we skip it.
|
||
|
||
This function can also call a special function that will try to match
|
||
unknown tokens. It will return the expression_up generated from
|
||
parsing the argument. */
|
||
|
||
static expression_up
|
||
stap_parse_argument (const char **arg, struct type *atype,
|
||
struct gdbarch *gdbarch)
|
||
{
|
||
/* We need to initialize the expression buffer, in order to begin
|
||
our parsing efforts. We use language_c here because we may need
|
||
to do pointer arithmetics. */
|
||
struct stap_parse_info p (*arg, atype, language_def (language_c),
|
||
gdbarch);
|
||
|
||
stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
|
||
|
||
gdb_assert (p.inside_paren_p == 0);
|
||
|
||
/* Casting the final expression to the appropriate type. */
|
||
write_exp_elt_opcode (&p.pstate, UNOP_CAST);
|
||
write_exp_elt_type (&p.pstate, atype);
|
||
write_exp_elt_opcode (&p.pstate, UNOP_CAST);
|
||
|
||
p.arg = skip_spaces (p.arg);
|
||
*arg = p.arg;
|
||
|
||
return p.pstate.release ();
|
||
}
|
||
|
||
/* Implementation of 'parse_arguments' method. */
|
||
|
||
void
|
||
stap_probe::parse_arguments (struct gdbarch *gdbarch)
|
||
{
|
||
const char *cur;
|
||
|
||
gdb_assert (!m_have_parsed_args);
|
||
cur = m_unparsed_args_text;
|
||
m_have_parsed_args = true;
|
||
|
||
if (cur == NULL || *cur == '\0' || *cur == ':')
|
||
return;
|
||
|
||
while (*cur != '\0')
|
||
{
|
||
enum stap_arg_bitness bitness;
|
||
bool got_minus = false;
|
||
|
||
/* We expect to find something like:
|
||
|
||
N@OP
|
||
|
||
Where `N' can be [+,-][1,2,4,8]. This is not mandatory, so
|
||
we check it here. If we don't find it, go to the next
|
||
state. */
|
||
if ((cur[0] == '-' && isdigit (cur[1]) && cur[2] == '@')
|
||
|| (isdigit (cur[0]) && cur[1] == '@'))
|
||
{
|
||
if (*cur == '-')
|
||
{
|
||
/* Discard the `-'. */
|
||
++cur;
|
||
got_minus = true;
|
||
}
|
||
|
||
/* Defining the bitness. */
|
||
switch (*cur)
|
||
{
|
||
case '1':
|
||
bitness = (got_minus ? STAP_ARG_BITNESS_8BIT_SIGNED
|
||
: STAP_ARG_BITNESS_8BIT_UNSIGNED);
|
||
break;
|
||
|
||
case '2':
|
||
bitness = (got_minus ? STAP_ARG_BITNESS_16BIT_SIGNED
|
||
: STAP_ARG_BITNESS_16BIT_UNSIGNED);
|
||
break;
|
||
|
||
case '4':
|
||
bitness = (got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
|
||
: STAP_ARG_BITNESS_32BIT_UNSIGNED);
|
||
break;
|
||
|
||
case '8':
|
||
bitness = (got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
|
||
: STAP_ARG_BITNESS_64BIT_UNSIGNED);
|
||
break;
|
||
|
||
default:
|
||
{
|
||
/* We have an error, because we don't expect anything
|
||
except 1, 2, 4 and 8. */
|
||
warning (_("unrecognized bitness %s%c' for probe `%s'"),
|
||
got_minus ? "`-" : "`", *cur,
|
||
this->get_name ().c_str ());
|
||
return;
|
||
}
|
||
}
|
||
/* Discard the number and the `@' sign. */
|
||
cur += 2;
|
||
}
|
||
else
|
||
bitness = STAP_ARG_BITNESS_UNDEFINED;
|
||
|
||
struct type *atype
|
||
= stap_get_expected_argument_type (gdbarch, bitness,
|
||
this->get_name ().c_str ());
|
||
|
||
expression_up expr = stap_parse_argument (&cur, atype, gdbarch);
|
||
|
||
if (stap_expression_debug)
|
||
dump_raw_expression (expr.get (), gdb_stdlog,
|
||
"before conversion to prefix form");
|
||
|
||
prefixify_expression (expr.get ());
|
||
|
||
if (stap_expression_debug)
|
||
dump_prefix_expression (expr.get (), gdb_stdlog);
|
||
|
||
m_parsed_args.emplace_back (bitness, atype, std::move (expr));
|
||
|
||
/* Start it over again. */
|
||
cur = skip_spaces (cur);
|
||
}
|
||
}
|
||
|
||
/* Helper function to relocate an address. */
|
||
|
||
static CORE_ADDR
|
||
relocate_address (CORE_ADDR address, struct objfile *objfile)
|
||
{
|
||
return address + objfile->section_offsets[SECT_OFF_DATA (objfile)];
|
||
}
|
||
|
||
/* Implementation of the get_relocated_address method. */
|
||
|
||
CORE_ADDR
|
||
stap_probe::get_relocated_address (struct objfile *objfile)
|
||
{
|
||
return relocate_address (this->get_address (), objfile);
|
||
}
|
||
|
||
/* Given PROBE, returns the number of arguments present in that probe's
|
||
argument string. */
|
||
|
||
unsigned
|
||
stap_probe::get_argument_count (struct gdbarch *gdbarch)
|
||
{
|
||
if (!m_have_parsed_args)
|
||
{
|
||
if (this->can_evaluate_arguments ())
|
||
this->parse_arguments (gdbarch);
|
||
else
|
||
{
|
||
static bool have_warned_stap_incomplete = false;
|
||
|
||
if (!have_warned_stap_incomplete)
|
||
{
|
||
warning (_(
|
||
"The SystemTap SDT probe support is not fully implemented on this target;\n"
|
||
"you will not be able to inspect the arguments of the probes.\n"
|
||
"Please report a bug against GDB requesting a port to this target."));
|
||
have_warned_stap_incomplete = true;
|
||
}
|
||
|
||
/* Marking the arguments as "already parsed". */
|
||
m_have_parsed_args = true;
|
||
}
|
||
}
|
||
|
||
gdb_assert (m_have_parsed_args);
|
||
return m_parsed_args.size ();
|
||
}
|
||
|
||
/* Return true if OP is a valid operator inside a probe argument, or
|
||
false otherwise. */
|
||
|
||
static bool
|
||
stap_is_operator (const char *op)
|
||
{
|
||
bool ret = true;
|
||
|
||
switch (*op)
|
||
{
|
||
case '*':
|
||
case '/':
|
||
case '%':
|
||
case '^':
|
||
case '!':
|
||
case '+':
|
||
case '-':
|
||
case '<':
|
||
case '>':
|
||
case '|':
|
||
case '&':
|
||
break;
|
||
|
||
case '=':
|
||
if (op[1] != '=')
|
||
ret = false;
|
||
break;
|
||
|
||
default:
|
||
/* We didn't find any operator. */
|
||
ret = false;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/* Implement the `can_evaluate_arguments' method. */
|
||
|
||
bool
|
||
stap_probe::can_evaluate_arguments () const
|
||
{
|
||
struct gdbarch *gdbarch = this->get_gdbarch ();
|
||
|
||
/* For SystemTap probes, we have to guarantee that the method
|
||
stap_is_single_operand is defined on gdbarch. If it is not, then it
|
||
means that argument evaluation is not implemented on this target. */
|
||
return gdbarch_stap_is_single_operand_p (gdbarch);
|
||
}
|
||
|
||
/* Evaluate the probe's argument N (indexed from 0), returning a value
|
||
corresponding to it. Assertion is thrown if N does not exist. */
|
||
|
||
struct value *
|
||
stap_probe::evaluate_argument (unsigned n, struct frame_info *frame)
|
||
{
|
||
struct stap_probe_arg *arg;
|
||
int pos = 0;
|
||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||
|
||
arg = this->get_arg_by_number (n, gdbarch);
|
||
return evaluate_subexp_standard (arg->atype, arg->aexpr.get (), &pos,
|
||
EVAL_NORMAL);
|
||
}
|
||
|
||
/* Compile the probe's argument N (indexed from 0) to agent expression.
|
||
Assertion is thrown if N does not exist. */
|
||
|
||
void
|
||
stap_probe::compile_to_ax (struct agent_expr *expr, struct axs_value *value,
|
||
unsigned n)
|
||
{
|
||
struct stap_probe_arg *arg;
|
||
union exp_element *pc;
|
||
|
||
arg = this->get_arg_by_number (n, expr->gdbarch);
|
||
|
||
pc = arg->aexpr->elts;
|
||
gen_expr (arg->aexpr.get (), &pc, expr, value);
|
||
|
||
require_rvalue (expr, value);
|
||
value->type = arg->atype;
|
||
}
|
||
|
||
|
||
/* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's
|
||
address. SET is zero if the semaphore should be cleared, or one if
|
||
it should be set. This is a helper function for
|
||
'stap_probe::set_semaphore' and 'stap_probe::clear_semaphore'. */
|
||
|
||
static void
|
||
stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
|
||
{
|
||
gdb_byte bytes[sizeof (LONGEST)];
|
||
/* The ABI specifies "unsigned short". */
|
||
struct type *type = builtin_type (gdbarch)->builtin_unsigned_short;
|
||
ULONGEST value;
|
||
|
||
/* Swallow errors. */
|
||
if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
|
||
{
|
||
warning (_("Could not read the value of a SystemTap semaphore."));
|
||
return;
|
||
}
|
||
|
||
enum bfd_endian byte_order = type_byte_order (type);
|
||
value = extract_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order);
|
||
/* Note that we explicitly don't worry about overflow or
|
||
underflow. */
|
||
if (set)
|
||
++value;
|
||
else
|
||
--value;
|
||
|
||
store_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order, value);
|
||
|
||
if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0)
|
||
warning (_("Could not write the value of a SystemTap semaphore."));
|
||
}
|
||
|
||
/* Implementation of the 'set_semaphore' method.
|
||
|
||
SystemTap semaphores act as reference counters, so calls to this
|
||
function must be paired with calls to 'clear_semaphore'.
|
||
|
||
This function and 'clear_semaphore' race with another tool
|
||
changing the probes, but that is too rare to care. */
|
||
|
||
void
|
||
stap_probe::set_semaphore (struct objfile *objfile, struct gdbarch *gdbarch)
|
||
{
|
||
if (m_sem_addr == 0)
|
||
return;
|
||
stap_modify_semaphore (relocate_address (m_sem_addr, objfile), 1, gdbarch);
|
||
}
|
||
|
||
/* Implementation of the 'clear_semaphore' method. */
|
||
|
||
void
|
||
stap_probe::clear_semaphore (struct objfile *objfile, struct gdbarch *gdbarch)
|
||
{
|
||
if (m_sem_addr == 0)
|
||
return;
|
||
stap_modify_semaphore (relocate_address (m_sem_addr, objfile), 0, gdbarch);
|
||
}
|
||
|
||
/* Implementation of the 'get_static_ops' method. */
|
||
|
||
const static_probe_ops *
|
||
stap_probe::get_static_ops () const
|
||
{
|
||
return &stap_static_probe_ops;
|
||
}
|
||
|
||
/* Implementation of the 'gen_info_probes_table_values' method. */
|
||
|
||
std::vector<const char *>
|
||
stap_probe::gen_info_probes_table_values () const
|
||
{
|
||
const char *val = NULL;
|
||
|
||
if (m_sem_addr != 0)
|
||
val = print_core_address (this->get_gdbarch (), m_sem_addr);
|
||
|
||
return std::vector<const char *> { val };
|
||
}
|
||
|
||
/* Helper function that parses the information contained in a
|
||
SystemTap's probe. Basically, the information consists in:
|
||
|
||
- Probe's PC address;
|
||
- Link-time section address of `.stapsdt.base' section;
|
||
- Link-time address of the semaphore variable, or ZERO if the
|
||
probe doesn't have an associated semaphore;
|
||
- Probe's provider name;
|
||
- Probe's name;
|
||
- Probe's argument format. */
|
||
|
||
static void
|
||
handle_stap_probe (struct objfile *objfile, struct sdt_note *el,
|
||
std::vector<std::unique_ptr<probe>> *probesp,
|
||
CORE_ADDR base)
|
||
{
|
||
bfd *abfd = objfile->obfd;
|
||
int size = bfd_get_arch_size (abfd) / 8;
|
||
struct gdbarch *gdbarch = get_objfile_arch (objfile);
|
||
struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
|
||
|
||
/* Provider and the name of the probe. */
|
||
const char *provider = (const char *) &el->data[3 * size];
|
||
const char *name = ((const char *)
|
||
memchr (provider, '\0',
|
||
(char *) el->data + el->size - provider));
|
||
/* Making sure there is a name. */
|
||
if (name == NULL)
|
||
{
|
||
complaint (_("corrupt probe name when reading `%s'"),
|
||
objfile_name (objfile));
|
||
|
||
/* There is no way to use a probe without a name or a provider, so
|
||
returning here makes sense. */
|
||
return;
|
||
}
|
||
else
|
||
++name;
|
||
|
||
/* Retrieving the probe's address. */
|
||
CORE_ADDR address = extract_typed_address (&el->data[0], ptr_type);
|
||
|
||
/* Link-time sh_addr of `.stapsdt.base' section. */
|
||
CORE_ADDR base_ref = extract_typed_address (&el->data[size], ptr_type);
|
||
|
||
/* Semaphore address. */
|
||
CORE_ADDR sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
|
||
|
||
address += base - base_ref;
|
||
if (sem_addr != 0)
|
||
sem_addr += base - base_ref;
|
||
|
||
/* Arguments. We can only extract the argument format if there is a valid
|
||
name for this probe. */
|
||
const char *probe_args = ((const char*)
|
||
memchr (name, '\0',
|
||
(char *) el->data + el->size - name));
|
||
|
||
if (probe_args != NULL)
|
||
++probe_args;
|
||
|
||
if (probe_args == NULL
|
||
|| (memchr (probe_args, '\0', (char *) el->data + el->size - name)
|
||
!= el->data + el->size - 1))
|
||
{
|
||
complaint (_("corrupt probe argument when reading `%s'"),
|
||
objfile_name (objfile));
|
||
/* If the argument string is NULL, it means some problem happened with
|
||
it. So we return. */
|
||
return;
|
||
}
|
||
|
||
stap_probe *ret = new stap_probe (std::string (name), std::string (provider),
|
||
address, gdbarch, sem_addr, probe_args);
|
||
|
||
/* Successfully created probe. */
|
||
probesp->emplace_back (ret);
|
||
}
|
||
|
||
/* Helper function which tries to find the base address of the SystemTap
|
||
base section named STAP_BASE_SECTION_NAME. */
|
||
|
||
static void
|
||
get_stap_base_address_1 (bfd *abfd, asection *sect, void *obj)
|
||
{
|
||
asection **ret = (asection **) obj;
|
||
|
||
if ((sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
|
||
&& sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
|
||
*ret = sect;
|
||
}
|
||
|
||
/* Helper function which iterates over every section in the BFD file,
|
||
trying to find the base address of the SystemTap base section.
|
||
Returns 1 if found (setting BASE to the proper value), zero otherwise. */
|
||
|
||
static int
|
||
get_stap_base_address (bfd *obfd, bfd_vma *base)
|
||
{
|
||
asection *ret = NULL;
|
||
|
||
bfd_map_over_sections (obfd, get_stap_base_address_1, (void *) &ret);
|
||
|
||
if (ret == NULL)
|
||
{
|
||
complaint (_("could not obtain base address for "
|
||
"SystemTap section on objfile `%s'."),
|
||
obfd->filename);
|
||
return 0;
|
||
}
|
||
|
||
if (base != NULL)
|
||
*base = ret->vma;
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* Implementation of the 'is_linespec' method. */
|
||
|
||
bool
|
||
stap_static_probe_ops::is_linespec (const char **linespecp) const
|
||
{
|
||
static const char *const keywords[] = { "-pstap", "-probe-stap", NULL };
|
||
|
||
return probe_is_linespec_by_keyword (linespecp, keywords);
|
||
}
|
||
|
||
/* Implementation of the 'get_probes' method. */
|
||
|
||
void
|
||
stap_static_probe_ops::get_probes
|
||
(std::vector<std::unique_ptr<probe>> *probesp,
|
||
struct objfile *objfile) const
|
||
{
|
||
/* If we are here, then this is the first time we are parsing the
|
||
SystemTap probe's information. We basically have to count how many
|
||
probes the objfile has, and then fill in the necessary information
|
||
for each one. */
|
||
bfd *obfd = objfile->obfd;
|
||
bfd_vma base;
|
||
struct sdt_note *iter;
|
||
unsigned save_probesp_len = probesp->size ();
|
||
|
||
if (objfile->separate_debug_objfile_backlink != NULL)
|
||
{
|
||
/* This is a .debug file, not the objfile itself. */
|
||
return;
|
||
}
|
||
|
||
if (elf_tdata (obfd)->sdt_note_head == NULL)
|
||
{
|
||
/* There isn't any probe here. */
|
||
return;
|
||
}
|
||
|
||
if (!get_stap_base_address (obfd, &base))
|
||
{
|
||
/* There was an error finding the base address for the section.
|
||
Just return NULL. */
|
||
return;
|
||
}
|
||
|
||
/* Parsing each probe's information. */
|
||
for (iter = elf_tdata (obfd)->sdt_note_head;
|
||
iter != NULL;
|
||
iter = iter->next)
|
||
{
|
||
/* We first have to handle all the information about the
|
||
probe which is present in the section. */
|
||
handle_stap_probe (objfile, iter, probesp, base);
|
||
}
|
||
|
||
if (save_probesp_len == probesp->size ())
|
||
{
|
||
/* If we are here, it means we have failed to parse every known
|
||
probe. */
|
||
complaint (_("could not parse SystemTap probe(s) from inferior"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* Implementation of the type_name method. */
|
||
|
||
const char *
|
||
stap_static_probe_ops::type_name () const
|
||
{
|
||
return "stap";
|
||
}
|
||
|
||
/* Implementation of the 'gen_info_probes_table_header' method. */
|
||
|
||
std::vector<struct info_probe_column>
|
||
stap_static_probe_ops::gen_info_probes_table_header () const
|
||
{
|
||
struct info_probe_column stap_probe_column;
|
||
|
||
stap_probe_column.field_name = "semaphore";
|
||
stap_probe_column.print_name = _("Semaphore");
|
||
|
||
return std::vector<struct info_probe_column> { stap_probe_column };
|
||
}
|
||
|
||
/* Implementation of the `info probes stap' command. */
|
||
|
||
static void
|
||
info_probes_stap_command (const char *arg, int from_tty)
|
||
{
|
||
info_probes_for_spops (arg, from_tty, &stap_static_probe_ops);
|
||
}
|
||
|
||
void _initialize_stap_probe ();
|
||
void
|
||
_initialize_stap_probe ()
|
||
{
|
||
all_static_probe_ops.push_back (&stap_static_probe_ops);
|
||
|
||
add_setshow_zuinteger_cmd ("stap-expression", class_maintenance,
|
||
&stap_expression_debug,
|
||
_("Set SystemTap expression debugging."),
|
||
_("Show SystemTap expression debugging."),
|
||
_("When non-zero, the internal representation "
|
||
"of SystemTap expressions will be printed."),
|
||
NULL,
|
||
show_stapexpressiondebug,
|
||
&setdebuglist, &showdebuglist);
|
||
|
||
add_cmd ("stap", class_info, info_probes_stap_command,
|
||
_("\
|
||
Show information about SystemTap static probes.\n\
|
||
Usage: info probes stap [PROVIDER [NAME [OBJECT]]]\n\
|
||
Each argument is a regular expression, used to select probes.\n\
|
||
PROVIDER matches probe provider names.\n\
|
||
NAME matches the probe names.\n\
|
||
OBJECT matches the executable or shared library name."),
|
||
info_probes_cmdlist_get ());
|
||
|
||
}
|