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
2214 lines
64 KiB
C
2214 lines
64 KiB
C
/* Helper routines for C++ support in GDB.
|
|
Copyright (C) 2002-2020 Free Software Foundation, Inc.
|
|
|
|
Contributed by MontaVista Software.
|
|
|
|
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 "cp-support.h"
|
|
#include "demangle.h"
|
|
#include "gdbcmd.h"
|
|
#include "dictionary.h"
|
|
#include "objfiles.h"
|
|
#include "frame.h"
|
|
#include "symtab.h"
|
|
#include "block.h"
|
|
#include "complaints.h"
|
|
#include "gdbtypes.h"
|
|
#include "expression.h"
|
|
#include "value.h"
|
|
#include "cp-abi.h"
|
|
#include "namespace.h"
|
|
#include <signal.h>
|
|
#include "gdbsupport/gdb_setjmp.h"
|
|
#include "safe-ctype.h"
|
|
#include "gdbsupport/selftest.h"
|
|
#include "gdbsupport/gdb-sigmask.h"
|
|
#include <atomic>
|
|
#include "event-top.h"
|
|
#include "run-on-main-thread.h"
|
|
|
|
#define d_left(dc) (dc)->u.s_binary.left
|
|
#define d_right(dc) (dc)->u.s_binary.right
|
|
|
|
/* Functions related to demangled name parsing. */
|
|
|
|
static unsigned int cp_find_first_component_aux (const char *name,
|
|
int permissive);
|
|
|
|
static void demangled_name_complaint (const char *name);
|
|
|
|
/* Functions related to overload resolution. */
|
|
|
|
static void overload_list_add_symbol (struct symbol *sym,
|
|
const char *oload_name,
|
|
std::vector<symbol *> *overload_list);
|
|
|
|
static void add_symbol_overload_list_using
|
|
(const char *func_name, const char *the_namespace,
|
|
std::vector<symbol *> *overload_list);
|
|
|
|
static void add_symbol_overload_list_qualified
|
|
(const char *func_name,
|
|
std::vector<symbol *> *overload_list);
|
|
|
|
/* The list of "maint cplus" commands. */
|
|
|
|
struct cmd_list_element *maint_cplus_cmd_list = NULL;
|
|
|
|
/* A list of typedefs which should not be substituted by replace_typedefs. */
|
|
static const char * const ignore_typedefs[] =
|
|
{
|
|
"std::istream", "std::iostream", "std::ostream", "std::string"
|
|
};
|
|
|
|
static void
|
|
replace_typedefs (struct demangle_parse_info *info,
|
|
struct demangle_component *ret_comp,
|
|
canonicalization_ftype *finder,
|
|
void *data);
|
|
|
|
/* A convenience function to copy STRING into OBSTACK, returning a pointer
|
|
to the newly allocated string and saving the number of bytes saved in LEN.
|
|
|
|
It does not copy the terminating '\0' byte! */
|
|
|
|
static char *
|
|
copy_string_to_obstack (struct obstack *obstack, const char *string,
|
|
long *len)
|
|
{
|
|
*len = strlen (string);
|
|
return (char *) obstack_copy (obstack, string, *len);
|
|
}
|
|
|
|
/* Return 1 if STRING is clearly already in canonical form. This
|
|
function is conservative; things which it does not recognize are
|
|
assumed to be non-canonical, and the parser will sort them out
|
|
afterwards. This speeds up the critical path for alphanumeric
|
|
identifiers. */
|
|
|
|
static int
|
|
cp_already_canonical (const char *string)
|
|
{
|
|
/* Identifier start character [a-zA-Z_]. */
|
|
if (!ISIDST (string[0]))
|
|
return 0;
|
|
|
|
/* These are the only two identifiers which canonicalize to other
|
|
than themselves or an error: unsigned -> unsigned int and
|
|
signed -> int. */
|
|
if (string[0] == 'u' && strcmp (&string[1], "nsigned") == 0)
|
|
return 0;
|
|
else if (string[0] == 's' && strcmp (&string[1], "igned") == 0)
|
|
return 0;
|
|
|
|
/* Identifier character [a-zA-Z0-9_]. */
|
|
while (ISIDNUM (string[1]))
|
|
string++;
|
|
|
|
if (string[1] == '\0')
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Inspect the given RET_COMP for its type. If it is a typedef,
|
|
replace the node with the typedef's tree.
|
|
|
|
Returns 1 if any typedef substitutions were made, 0 otherwise. */
|
|
|
|
static int
|
|
inspect_type (struct demangle_parse_info *info,
|
|
struct demangle_component *ret_comp,
|
|
canonicalization_ftype *finder,
|
|
void *data)
|
|
{
|
|
char *name;
|
|
struct symbol *sym;
|
|
|
|
/* Copy the symbol's name from RET_COMP and look it up
|
|
in the symbol table. */
|
|
name = (char *) alloca (ret_comp->u.s_name.len + 1);
|
|
memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
|
|
name[ret_comp->u.s_name.len] = '\0';
|
|
|
|
/* Ignore any typedefs that should not be substituted. */
|
|
for (int i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
|
|
{
|
|
if (strcmp (name, ignore_typedefs[i]) == 0)
|
|
return 0;
|
|
}
|
|
|
|
sym = NULL;
|
|
|
|
try
|
|
{
|
|
sym = lookup_symbol (name, 0, VAR_DOMAIN, 0).symbol;
|
|
}
|
|
catch (const gdb_exception &except)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (sym != NULL)
|
|
{
|
|
struct type *otype = SYMBOL_TYPE (sym);
|
|
|
|
if (finder != NULL)
|
|
{
|
|
const char *new_name = (*finder) (otype, data);
|
|
|
|
if (new_name != NULL)
|
|
{
|
|
ret_comp->u.s_name.s = new_name;
|
|
ret_comp->u.s_name.len = strlen (new_name);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* If the type is a typedef or namespace alias, replace it. */
|
|
if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF
|
|
|| TYPE_CODE (otype) == TYPE_CODE_NAMESPACE)
|
|
{
|
|
long len;
|
|
int is_anon;
|
|
struct type *type;
|
|
std::unique_ptr<demangle_parse_info> i;
|
|
|
|
/* Get the real type of the typedef. */
|
|
type = check_typedef (otype);
|
|
|
|
/* If the symbol name is the same as the original type name,
|
|
don't substitute. That would cause infinite recursion in
|
|
symbol lookups, as the typedef symbol is often the first
|
|
found symbol in the symbol table.
|
|
|
|
However, this can happen in a number of situations, such as:
|
|
|
|
If the symbol is a namespace and its type name is no different
|
|
than the name we looked up, this symbol is not a namespace
|
|
alias and does not need to be substituted.
|
|
|
|
If the symbol is typedef and its type name is the same
|
|
as the symbol's name, e.g., "typedef struct foo foo;". */
|
|
if (TYPE_NAME (type) != nullptr
|
|
&& strcmp (TYPE_NAME (type), name) == 0)
|
|
return 0;
|
|
|
|
is_anon = (TYPE_NAME (type) == NULL
|
|
&& (TYPE_CODE (type) == TYPE_CODE_ENUM
|
|
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|| TYPE_CODE (type) == TYPE_CODE_UNION));
|
|
if (is_anon)
|
|
{
|
|
struct type *last = otype;
|
|
|
|
/* Find the last typedef for the type. */
|
|
while (TYPE_TARGET_TYPE (last) != NULL
|
|
&& (TYPE_CODE (TYPE_TARGET_TYPE (last))
|
|
== TYPE_CODE_TYPEDEF))
|
|
last = TYPE_TARGET_TYPE (last);
|
|
|
|
/* If there is only one typedef for this anonymous type,
|
|
do not substitute it. */
|
|
if (type == otype)
|
|
return 0;
|
|
else
|
|
/* Use the last typedef seen as the type for this
|
|
anonymous type. */
|
|
type = last;
|
|
}
|
|
|
|
string_file buf;
|
|
try
|
|
{
|
|
type_print (type, "", &buf, -1);
|
|
}
|
|
/* If type_print threw an exception, there is little point
|
|
in continuing, so just bow out gracefully. */
|
|
catch (const gdb_exception_error &except)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
len = buf.size ();
|
|
name = obstack_strdup (&info->obstack, buf.string ());
|
|
|
|
/* Turn the result into a new tree. Note that this
|
|
tree will contain pointers into NAME, so NAME cannot
|
|
be free'd until all typedef conversion is done and
|
|
the final result is converted into a string. */
|
|
i = cp_demangled_name_to_comp (name, NULL);
|
|
if (i != NULL)
|
|
{
|
|
/* Merge the two trees. */
|
|
cp_merge_demangle_parse_infos (info, ret_comp, i.get ());
|
|
|
|
/* Replace any newly introduced typedefs -- but not
|
|
if the type is anonymous (that would lead to infinite
|
|
looping). */
|
|
if (!is_anon)
|
|
replace_typedefs (info, ret_comp, finder, data);
|
|
}
|
|
else
|
|
{
|
|
/* This shouldn't happen unless the type printer has
|
|
output something that the name parser cannot grok.
|
|
Nonetheless, an ounce of prevention...
|
|
|
|
Canonicalize the name again, and store it in the
|
|
current node (RET_COMP). */
|
|
std::string canon = cp_canonicalize_string_no_typedefs (name);
|
|
|
|
if (!canon.empty ())
|
|
{
|
|
/* Copy the canonicalization into the obstack. */
|
|
name = copy_string_to_obstack (&info->obstack, canon.c_str (), &len);
|
|
}
|
|
|
|
ret_comp->u.s_name.s = name;
|
|
ret_comp->u.s_name.len = len;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Replace any typedefs appearing in the qualified name
|
|
(DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
|
|
given in INFO. */
|
|
|
|
static void
|
|
replace_typedefs_qualified_name (struct demangle_parse_info *info,
|
|
struct demangle_component *ret_comp,
|
|
canonicalization_ftype *finder,
|
|
void *data)
|
|
{
|
|
string_file buf;
|
|
struct demangle_component *comp = ret_comp;
|
|
|
|
/* Walk each node of the qualified name, reconstructing the name of
|
|
this element. With every node, check for any typedef substitutions.
|
|
If a substitution has occurred, replace the qualified name node
|
|
with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
|
|
substituted name. */
|
|
while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
|
|
{
|
|
if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
|
|
{
|
|
struct demangle_component newobj;
|
|
|
|
buf.write (d_left (comp)->u.s_name.s, d_left (comp)->u.s_name.len);
|
|
newobj.type = DEMANGLE_COMPONENT_NAME;
|
|
newobj.u.s_name.s = obstack_strdup (&info->obstack, buf.string ());
|
|
newobj.u.s_name.len = buf.size ();
|
|
if (inspect_type (info, &newobj, finder, data))
|
|
{
|
|
char *s;
|
|
long slen;
|
|
|
|
/* A typedef was substituted in NEW. Convert it to a
|
|
string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
|
|
node. */
|
|
|
|
buf.clear ();
|
|
gdb::unique_xmalloc_ptr<char> n
|
|
= cp_comp_to_string (&newobj, 100);
|
|
if (n == NULL)
|
|
{
|
|
/* If something went astray, abort typedef substitutions. */
|
|
return;
|
|
}
|
|
|
|
s = copy_string_to_obstack (&info->obstack, n.get (), &slen);
|
|
|
|
d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME;
|
|
d_left (ret_comp)->u.s_name.s = s;
|
|
d_left (ret_comp)->u.s_name.len = slen;
|
|
d_right (ret_comp) = d_right (comp);
|
|
comp = ret_comp;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The current node is not a name, so simply replace any
|
|
typedefs in it. Then print it to the stream to continue
|
|
checking for more typedefs in the tree. */
|
|
replace_typedefs (info, d_left (comp), finder, data);
|
|
gdb::unique_xmalloc_ptr<char> name
|
|
= cp_comp_to_string (d_left (comp), 100);
|
|
if (name == NULL)
|
|
{
|
|
/* If something went astray, abort typedef substitutions. */
|
|
return;
|
|
}
|
|
buf.puts (name.get ());
|
|
}
|
|
|
|
buf.write ("::", 2);
|
|
comp = d_right (comp);
|
|
}
|
|
|
|
/* If the next component is DEMANGLE_COMPONENT_NAME, save the qualified
|
|
name assembled above and append the name given by COMP. Then use this
|
|
reassembled name to check for a typedef. */
|
|
|
|
if (comp->type == DEMANGLE_COMPONENT_NAME)
|
|
{
|
|
buf.write (comp->u.s_name.s, comp->u.s_name.len);
|
|
|
|
/* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
|
|
with a DEMANGLE_COMPONENT_NAME node containing the whole
|
|
name. */
|
|
ret_comp->type = DEMANGLE_COMPONENT_NAME;
|
|
ret_comp->u.s_name.s = obstack_strdup (&info->obstack, buf.string ());
|
|
ret_comp->u.s_name.len = buf.size ();
|
|
inspect_type (info, ret_comp, finder, data);
|
|
}
|
|
else
|
|
replace_typedefs (info, comp, finder, data);
|
|
}
|
|
|
|
|
|
/* A function to check const and volatile qualifiers for argument types.
|
|
|
|
"Parameter declarations that differ only in the presence
|
|
or absence of `const' and/or `volatile' are equivalent."
|
|
C++ Standard N3290, clause 13.1.3 #4. */
|
|
|
|
static void
|
|
check_cv_qualifiers (struct demangle_component *ret_comp)
|
|
{
|
|
while (d_left (ret_comp) != NULL
|
|
&& (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST
|
|
|| d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE))
|
|
{
|
|
d_left (ret_comp) = d_left (d_left (ret_comp));
|
|
}
|
|
}
|
|
|
|
/* Walk the parse tree given by RET_COMP, replacing any typedefs with
|
|
their basic types. */
|
|
|
|
static void
|
|
replace_typedefs (struct demangle_parse_info *info,
|
|
struct demangle_component *ret_comp,
|
|
canonicalization_ftype *finder,
|
|
void *data)
|
|
{
|
|
if (ret_comp)
|
|
{
|
|
if (finder != NULL
|
|
&& (ret_comp->type == DEMANGLE_COMPONENT_NAME
|
|
|| ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME
|
|
|| ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE
|
|
|| ret_comp->type == DEMANGLE_COMPONENT_BUILTIN_TYPE))
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> local_name
|
|
= cp_comp_to_string (ret_comp, 10);
|
|
|
|
if (local_name != NULL)
|
|
{
|
|
struct symbol *sym = NULL;
|
|
|
|
sym = NULL;
|
|
try
|
|
{
|
|
sym = lookup_symbol (local_name.get (), 0,
|
|
VAR_DOMAIN, 0).symbol;
|
|
}
|
|
catch (const gdb_exception &except)
|
|
{
|
|
}
|
|
|
|
if (sym != NULL)
|
|
{
|
|
struct type *otype = SYMBOL_TYPE (sym);
|
|
const char *new_name = (*finder) (otype, data);
|
|
|
|
if (new_name != NULL)
|
|
{
|
|
ret_comp->type = DEMANGLE_COMPONENT_NAME;
|
|
ret_comp->u.s_name.s = new_name;
|
|
ret_comp->u.s_name.len = strlen (new_name);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (ret_comp->type)
|
|
{
|
|
case DEMANGLE_COMPONENT_ARGLIST:
|
|
check_cv_qualifiers (ret_comp);
|
|
/* Fall through */
|
|
|
|
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
|
|
case DEMANGLE_COMPONENT_TEMPLATE:
|
|
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
|
|
case DEMANGLE_COMPONENT_TYPED_NAME:
|
|
replace_typedefs (info, d_left (ret_comp), finder, data);
|
|
replace_typedefs (info, d_right (ret_comp), finder, data);
|
|
break;
|
|
|
|
case DEMANGLE_COMPONENT_NAME:
|
|
inspect_type (info, ret_comp, finder, data);
|
|
break;
|
|
|
|
case DEMANGLE_COMPONENT_QUAL_NAME:
|
|
replace_typedefs_qualified_name (info, ret_comp, finder, data);
|
|
break;
|
|
|
|
case DEMANGLE_COMPONENT_LOCAL_NAME:
|
|
case DEMANGLE_COMPONENT_CTOR:
|
|
case DEMANGLE_COMPONENT_ARRAY_TYPE:
|
|
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
|
|
replace_typedefs (info, d_right (ret_comp), finder, data);
|
|
break;
|
|
|
|
case DEMANGLE_COMPONENT_CONST:
|
|
case DEMANGLE_COMPONENT_RESTRICT:
|
|
case DEMANGLE_COMPONENT_VOLATILE:
|
|
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
|
case DEMANGLE_COMPONENT_CONST_THIS:
|
|
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
|
case DEMANGLE_COMPONENT_POINTER:
|
|
case DEMANGLE_COMPONENT_REFERENCE:
|
|
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
|
|
replace_typedefs (info, d_left (ret_comp), finder, data);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Parse STRING and convert it to canonical form, resolving any
|
|
typedefs. If parsing fails, or if STRING is already canonical,
|
|
return the empty string. Otherwise return the canonical form. If
|
|
FINDER is not NULL, then type components are passed to FINDER to be
|
|
looked up. DATA is passed verbatim to FINDER. */
|
|
|
|
std::string
|
|
cp_canonicalize_string_full (const char *string,
|
|
canonicalization_ftype *finder,
|
|
void *data)
|
|
{
|
|
std::string ret;
|
|
unsigned int estimated_len;
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
|
|
estimated_len = strlen (string) * 2;
|
|
info = cp_demangled_name_to_comp (string, NULL);
|
|
if (info != NULL)
|
|
{
|
|
/* Replace all the typedefs in the tree. */
|
|
replace_typedefs (info.get (), info->tree, finder, data);
|
|
|
|
/* Convert the tree back into a string. */
|
|
gdb::unique_xmalloc_ptr<char> us = cp_comp_to_string (info->tree,
|
|
estimated_len);
|
|
gdb_assert (us);
|
|
|
|
ret = us.get ();
|
|
/* Finally, compare the original string with the computed
|
|
name, returning NULL if they are the same. */
|
|
if (ret == string)
|
|
return std::string ();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Like cp_canonicalize_string_full, but always passes NULL for
|
|
FINDER. */
|
|
|
|
std::string
|
|
cp_canonicalize_string_no_typedefs (const char *string)
|
|
{
|
|
return cp_canonicalize_string_full (string, NULL, NULL);
|
|
}
|
|
|
|
/* Parse STRING and convert it to canonical form. If parsing fails,
|
|
or if STRING is already canonical, return the empty string.
|
|
Otherwise return the canonical form. */
|
|
|
|
std::string
|
|
cp_canonicalize_string (const char *string)
|
|
{
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
unsigned int estimated_len;
|
|
|
|
if (cp_already_canonical (string))
|
|
return std::string ();
|
|
|
|
info = cp_demangled_name_to_comp (string, NULL);
|
|
if (info == NULL)
|
|
return std::string ();
|
|
|
|
estimated_len = strlen (string) * 2;
|
|
gdb::unique_xmalloc_ptr<char> us (cp_comp_to_string (info->tree,
|
|
estimated_len));
|
|
|
|
if (!us)
|
|
{
|
|
warning (_("internal error: string \"%s\" failed to be canonicalized"),
|
|
string);
|
|
return std::string ();
|
|
}
|
|
|
|
std::string ret (us.get ());
|
|
|
|
if (ret == string)
|
|
return std::string ();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Convert a mangled name to a demangle_component tree. *MEMORY is
|
|
set to the block of used memory that should be freed when finished
|
|
with the tree. DEMANGLED_P is set to the char * that should be
|
|
freed when finished with the tree, or NULL if none was needed.
|
|
OPTIONS will be passed to the demangler. */
|
|
|
|
static std::unique_ptr<demangle_parse_info>
|
|
mangled_name_to_comp (const char *mangled_name, int options,
|
|
void **memory, char **demangled_p)
|
|
{
|
|
char *demangled_name;
|
|
|
|
/* If it looks like a v3 mangled name, then try to go directly
|
|
to trees. */
|
|
if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
|
|
{
|
|
struct demangle_component *ret;
|
|
|
|
ret = cplus_demangle_v3_components (mangled_name,
|
|
options, memory);
|
|
if (ret)
|
|
{
|
|
std::unique_ptr<demangle_parse_info> info (new demangle_parse_info);
|
|
info->tree = ret;
|
|
*demangled_p = NULL;
|
|
return info;
|
|
}
|
|
}
|
|
|
|
/* If it doesn't, or if that failed, then try to demangle the
|
|
name. */
|
|
demangled_name = gdb_demangle (mangled_name, options);
|
|
if (demangled_name == NULL)
|
|
return NULL;
|
|
|
|
/* If we could demangle the name, parse it to build the component
|
|
tree. */
|
|
std::unique_ptr<demangle_parse_info> info
|
|
= cp_demangled_name_to_comp (demangled_name, NULL);
|
|
|
|
if (info == NULL)
|
|
{
|
|
xfree (demangled_name);
|
|
return NULL;
|
|
}
|
|
|
|
*demangled_p = demangled_name;
|
|
return info;
|
|
}
|
|
|
|
/* Return the name of the class containing method PHYSNAME. */
|
|
|
|
char *
|
|
cp_class_name_from_physname (const char *physname)
|
|
{
|
|
void *storage = NULL;
|
|
char *demangled_name = NULL;
|
|
gdb::unique_xmalloc_ptr<char> ret;
|
|
struct demangle_component *ret_comp, *prev_comp, *cur_comp;
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
int done;
|
|
|
|
info = mangled_name_to_comp (physname, DMGL_ANSI,
|
|
&storage, &demangled_name);
|
|
if (info == NULL)
|
|
return NULL;
|
|
|
|
done = 0;
|
|
ret_comp = info->tree;
|
|
|
|
/* First strip off any qualifiers, if we have a function or
|
|
method. */
|
|
while (!done)
|
|
switch (ret_comp->type)
|
|
{
|
|
case DEMANGLE_COMPONENT_CONST:
|
|
case DEMANGLE_COMPONENT_RESTRICT:
|
|
case DEMANGLE_COMPONENT_VOLATILE:
|
|
case DEMANGLE_COMPONENT_CONST_THIS:
|
|
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
|
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
|
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
|
ret_comp = d_left (ret_comp);
|
|
break;
|
|
default:
|
|
done = 1;
|
|
break;
|
|
}
|
|
|
|
/* If what we have now is a function, discard the argument list. */
|
|
if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
|
|
ret_comp = d_left (ret_comp);
|
|
|
|
/* If what we have now is a template, strip off the template
|
|
arguments. The left subtree may be a qualified name. */
|
|
if (ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE)
|
|
ret_comp = d_left (ret_comp);
|
|
|
|
/* What we have now should be a name, possibly qualified.
|
|
Additional qualifiers could live in the left subtree or the right
|
|
subtree. Find the last piece. */
|
|
done = 0;
|
|
prev_comp = NULL;
|
|
cur_comp = ret_comp;
|
|
while (!done)
|
|
switch (cur_comp->type)
|
|
{
|
|
case DEMANGLE_COMPONENT_QUAL_NAME:
|
|
case DEMANGLE_COMPONENT_LOCAL_NAME:
|
|
prev_comp = cur_comp;
|
|
cur_comp = d_right (cur_comp);
|
|
break;
|
|
case DEMANGLE_COMPONENT_TEMPLATE:
|
|
case DEMANGLE_COMPONENT_NAME:
|
|
case DEMANGLE_COMPONENT_CTOR:
|
|
case DEMANGLE_COMPONENT_DTOR:
|
|
case DEMANGLE_COMPONENT_OPERATOR:
|
|
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
|
|
done = 1;
|
|
break;
|
|
default:
|
|
done = 1;
|
|
cur_comp = NULL;
|
|
break;
|
|
}
|
|
|
|
if (cur_comp != NULL && prev_comp != NULL)
|
|
{
|
|
/* We want to discard the rightmost child of PREV_COMP. */
|
|
*prev_comp = *d_left (prev_comp);
|
|
/* The ten is completely arbitrary; we don't have a good
|
|
estimate. */
|
|
ret = cp_comp_to_string (ret_comp, 10);
|
|
}
|
|
|
|
xfree (storage);
|
|
xfree (demangled_name);
|
|
return ret.release ();
|
|
}
|
|
|
|
/* Return the child of COMP which is the basename of a method,
|
|
variable, et cetera. All scope qualifiers are discarded, but
|
|
template arguments will be included. The component tree may be
|
|
modified. */
|
|
|
|
static struct demangle_component *
|
|
unqualified_name_from_comp (struct demangle_component *comp)
|
|
{
|
|
struct demangle_component *ret_comp = comp, *last_template;
|
|
int done;
|
|
|
|
done = 0;
|
|
last_template = NULL;
|
|
while (!done)
|
|
switch (ret_comp->type)
|
|
{
|
|
case DEMANGLE_COMPONENT_QUAL_NAME:
|
|
case DEMANGLE_COMPONENT_LOCAL_NAME:
|
|
ret_comp = d_right (ret_comp);
|
|
break;
|
|
case DEMANGLE_COMPONENT_TYPED_NAME:
|
|
ret_comp = d_left (ret_comp);
|
|
break;
|
|
case DEMANGLE_COMPONENT_TEMPLATE:
|
|
gdb_assert (last_template == NULL);
|
|
last_template = ret_comp;
|
|
ret_comp = d_left (ret_comp);
|
|
break;
|
|
case DEMANGLE_COMPONENT_CONST:
|
|
case DEMANGLE_COMPONENT_RESTRICT:
|
|
case DEMANGLE_COMPONENT_VOLATILE:
|
|
case DEMANGLE_COMPONENT_CONST_THIS:
|
|
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
|
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
|
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
|
ret_comp = d_left (ret_comp);
|
|
break;
|
|
case DEMANGLE_COMPONENT_NAME:
|
|
case DEMANGLE_COMPONENT_CTOR:
|
|
case DEMANGLE_COMPONENT_DTOR:
|
|
case DEMANGLE_COMPONENT_OPERATOR:
|
|
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
|
|
done = 1;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
if (last_template)
|
|
{
|
|
d_left (last_template) = ret_comp;
|
|
return last_template;
|
|
}
|
|
|
|
return ret_comp;
|
|
}
|
|
|
|
/* Return the name of the method whose linkage name is PHYSNAME. */
|
|
|
|
char *
|
|
method_name_from_physname (const char *physname)
|
|
{
|
|
void *storage = NULL;
|
|
char *demangled_name = NULL;
|
|
gdb::unique_xmalloc_ptr<char> ret;
|
|
struct demangle_component *ret_comp;
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
|
|
info = mangled_name_to_comp (physname, DMGL_ANSI,
|
|
&storage, &demangled_name);
|
|
if (info == NULL)
|
|
return NULL;
|
|
|
|
ret_comp = unqualified_name_from_comp (info->tree);
|
|
|
|
if (ret_comp != NULL)
|
|
/* The ten is completely arbitrary; we don't have a good
|
|
estimate. */
|
|
ret = cp_comp_to_string (ret_comp, 10);
|
|
|
|
xfree (storage);
|
|
xfree (demangled_name);
|
|
return ret.release ();
|
|
}
|
|
|
|
/* If FULL_NAME is the demangled name of a C++ function (including an
|
|
arg list, possibly including namespace/class qualifications),
|
|
return a new string containing only the function name (without the
|
|
arg list/class qualifications). Otherwise, return NULL. */
|
|
|
|
gdb::unique_xmalloc_ptr<char>
|
|
cp_func_name (const char *full_name)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> ret;
|
|
struct demangle_component *ret_comp;
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
|
|
info = cp_demangled_name_to_comp (full_name, NULL);
|
|
if (!info)
|
|
return nullptr;
|
|
|
|
ret_comp = unqualified_name_from_comp (info->tree);
|
|
|
|
if (ret_comp != NULL)
|
|
ret = cp_comp_to_string (ret_comp, 10);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Helper for cp_remove_params. DEMANGLED_NAME is the name of a
|
|
function, including parameters and (optionally) a return type.
|
|
Return the name of the function without parameters or return type,
|
|
or NULL if we can not parse the name. If REQUIRE_PARAMS is false,
|
|
then tolerate a non-existing or unbalanced parameter list. */
|
|
|
|
static gdb::unique_xmalloc_ptr<char>
|
|
cp_remove_params_1 (const char *demangled_name, bool require_params)
|
|
{
|
|
bool done = false;
|
|
struct demangle_component *ret_comp;
|
|
std::unique_ptr<demangle_parse_info> info;
|
|
gdb::unique_xmalloc_ptr<char> ret;
|
|
|
|
if (demangled_name == NULL)
|
|
return NULL;
|
|
|
|
info = cp_demangled_name_to_comp (demangled_name, NULL);
|
|
if (info == NULL)
|
|
return NULL;
|
|
|
|
/* First strip off any qualifiers, if we have a function or method. */
|
|
ret_comp = info->tree;
|
|
while (!done)
|
|
switch (ret_comp->type)
|
|
{
|
|
case DEMANGLE_COMPONENT_CONST:
|
|
case DEMANGLE_COMPONENT_RESTRICT:
|
|
case DEMANGLE_COMPONENT_VOLATILE:
|
|
case DEMANGLE_COMPONENT_CONST_THIS:
|
|
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
|
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
|
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
|
ret_comp = d_left (ret_comp);
|
|
break;
|
|
default:
|
|
done = true;
|
|
break;
|
|
}
|
|
|
|
/* What we have now should be a function. Return its name. */
|
|
if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
|
|
ret = cp_comp_to_string (d_left (ret_comp), 10);
|
|
else if (!require_params
|
|
&& (ret_comp->type == DEMANGLE_COMPONENT_NAME
|
|
|| ret_comp->type == DEMANGLE_COMPONENT_QUAL_NAME
|
|
|| ret_comp->type == DEMANGLE_COMPONENT_TEMPLATE))
|
|
ret = cp_comp_to_string (ret_comp, 10);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* DEMANGLED_NAME is the name of a function, including parameters and
|
|
(optionally) a return type. Return the name of the function
|
|
without parameters or return type, or NULL if we can not parse the
|
|
name. */
|
|
|
|
gdb::unique_xmalloc_ptr<char>
|
|
cp_remove_params (const char *demangled_name)
|
|
{
|
|
return cp_remove_params_1 (demangled_name, true);
|
|
}
|
|
|
|
/* See cp-support.h. */
|
|
|
|
gdb::unique_xmalloc_ptr<char>
|
|
cp_remove_params_if_any (const char *demangled_name, bool completion_mode)
|
|
{
|
|
/* Trying to remove parameters from the empty string fails. If
|
|
we're completing / matching everything, avoid returning NULL
|
|
which would make callers interpret the result as an error. */
|
|
if (demangled_name[0] == '\0' && completion_mode)
|
|
return make_unique_xstrdup ("");
|
|
|
|
gdb::unique_xmalloc_ptr<char> without_params
|
|
= cp_remove_params_1 (demangled_name, false);
|
|
|
|
if (without_params == NULL && completion_mode)
|
|
{
|
|
std::string copy = demangled_name;
|
|
|
|
while (!copy.empty ())
|
|
{
|
|
copy.pop_back ();
|
|
without_params = cp_remove_params_1 (copy.c_str (), false);
|
|
if (without_params != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return without_params;
|
|
}
|
|
|
|
/* Here are some random pieces of trivia to keep in mind while trying
|
|
to take apart demangled names:
|
|
|
|
- Names can contain function arguments or templates, so the process
|
|
has to be, to some extent recursive: maybe keep track of your
|
|
depth based on encountering <> and ().
|
|
|
|
- Parentheses don't just have to happen at the end of a name: they
|
|
can occur even if the name in question isn't a function, because
|
|
a template argument might be a type that's a function.
|
|
|
|
- Conversely, even if you're trying to deal with a function, its
|
|
demangled name might not end with ')': it could be a const or
|
|
volatile class method, in which case it ends with "const" or
|
|
"volatile".
|
|
|
|
- Parentheses are also used in anonymous namespaces: a variable
|
|
'foo' in an anonymous namespace gets demangled as "(anonymous
|
|
namespace)::foo".
|
|
|
|
- And operator names can contain parentheses or angle brackets. */
|
|
|
|
/* FIXME: carlton/2003-03-13: We have several functions here with
|
|
overlapping functionality; can we combine them? Also, do they
|
|
handle all the above considerations correctly? */
|
|
|
|
|
|
/* This returns the length of first component of NAME, which should be
|
|
the demangled name of a C++ variable/function/method/etc.
|
|
Specifically, it returns the index of the first colon forming the
|
|
boundary of the first component: so, given 'A::foo' or 'A::B::foo'
|
|
it returns the 1, and given 'foo', it returns 0. */
|
|
|
|
/* The character in NAME indexed by the return value is guaranteed to
|
|
always be either ':' or '\0'. */
|
|
|
|
/* NOTE: carlton/2003-03-13: This function is currently only intended
|
|
for internal use: it's probably not entirely safe when called on
|
|
user-generated input, because some of the 'index += 2' lines in
|
|
cp_find_first_component_aux might go past the end of malformed
|
|
input. */
|
|
|
|
unsigned int
|
|
cp_find_first_component (const char *name)
|
|
{
|
|
return cp_find_first_component_aux (name, 0);
|
|
}
|
|
|
|
/* Helper function for cp_find_first_component. Like that function,
|
|
it returns the length of the first component of NAME, but to make
|
|
the recursion easier, it also stops if it reaches an unexpected ')'
|
|
or '>' if the value of PERMISSIVE is nonzero. */
|
|
|
|
static unsigned int
|
|
cp_find_first_component_aux (const char *name, int permissive)
|
|
{
|
|
unsigned int index = 0;
|
|
/* Operator names can show up in unexpected places. Since these can
|
|
contain parentheses or angle brackets, they can screw up the
|
|
recursion. But not every string 'operator' is part of an
|
|
operator name: e.g. you could have a variable 'cooperator'. So
|
|
this variable tells us whether or not we should treat the string
|
|
'operator' as starting an operator. */
|
|
int operator_possible = 1;
|
|
|
|
for (;; ++index)
|
|
{
|
|
switch (name[index])
|
|
{
|
|
case '<':
|
|
/* Template; eat it up. The calls to cp_first_component
|
|
should only return (I hope!) when they reach the '>'
|
|
terminating the component or a '::' between two
|
|
components. (Hence the '+ 2'.) */
|
|
index += 1;
|
|
for (index += cp_find_first_component_aux (name + index, 1);
|
|
name[index] != '>';
|
|
index += cp_find_first_component_aux (name + index, 1))
|
|
{
|
|
if (name[index] != ':')
|
|
{
|
|
demangled_name_complaint (name);
|
|
return strlen (name);
|
|
}
|
|
index += 2;
|
|
}
|
|
operator_possible = 1;
|
|
break;
|
|
case '(':
|
|
/* Similar comment as to '<'. */
|
|
index += 1;
|
|
for (index += cp_find_first_component_aux (name + index, 1);
|
|
name[index] != ')';
|
|
index += cp_find_first_component_aux (name + index, 1))
|
|
{
|
|
if (name[index] != ':')
|
|
{
|
|
demangled_name_complaint (name);
|
|
return strlen (name);
|
|
}
|
|
index += 2;
|
|
}
|
|
operator_possible = 1;
|
|
break;
|
|
case '>':
|
|
case ')':
|
|
if (permissive)
|
|
return index;
|
|
else
|
|
{
|
|
demangled_name_complaint (name);
|
|
return strlen (name);
|
|
}
|
|
case '\0':
|
|
return index;
|
|
case ':':
|
|
/* ':' marks a component iff the next character is also a ':'.
|
|
Otherwise it is probably malformed input. */
|
|
if (name[index + 1] == ':')
|
|
return index;
|
|
break;
|
|
case 'o':
|
|
/* Operator names can screw up the recursion. */
|
|
if (operator_possible
|
|
&& startswith (name + index, CP_OPERATOR_STR))
|
|
{
|
|
index += CP_OPERATOR_LEN;
|
|
while (ISSPACE(name[index]))
|
|
++index;
|
|
switch (name[index])
|
|
{
|
|
case '\0':
|
|
return index;
|
|
/* Skip over one less than the appropriate number of
|
|
characters: the for loop will skip over the last
|
|
one. */
|
|
case '<':
|
|
if (name[index + 1] == '<')
|
|
index += 1;
|
|
else
|
|
index += 0;
|
|
break;
|
|
case '>':
|
|
case '-':
|
|
if (name[index + 1] == '>')
|
|
index += 1;
|
|
else
|
|
index += 0;
|
|
break;
|
|
case '(':
|
|
index += 1;
|
|
break;
|
|
default:
|
|
index += 0;
|
|
break;
|
|
}
|
|
}
|
|
operator_possible = 0;
|
|
break;
|
|
case ' ':
|
|
case ',':
|
|
case '.':
|
|
case '&':
|
|
case '*':
|
|
/* NOTE: carlton/2003-04-18: I'm not sure what the precise
|
|
set of relevant characters are here: it's necessary to
|
|
include any character that can show up before 'operator'
|
|
in a demangled name, and it's safe to include any
|
|
character that can't be part of an identifier's name. */
|
|
operator_possible = 1;
|
|
break;
|
|
default:
|
|
operator_possible = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Complain about a demangled name that we don't know how to parse.
|
|
NAME is the demangled name in question. */
|
|
|
|
static void
|
|
demangled_name_complaint (const char *name)
|
|
{
|
|
complaint ("unexpected demangled name '%s'", name);
|
|
}
|
|
|
|
/* If NAME is the fully-qualified name of a C++
|
|
function/variable/method/etc., this returns the length of its
|
|
entire prefix: all of the namespaces and classes that make up its
|
|
name. Given 'A::foo', it returns 1, given 'A::B::foo', it returns
|
|
4, given 'foo', it returns 0. */
|
|
|
|
unsigned int
|
|
cp_entire_prefix_len (const char *name)
|
|
{
|
|
unsigned int current_len = cp_find_first_component (name);
|
|
unsigned int previous_len = 0;
|
|
|
|
while (name[current_len] != '\0')
|
|
{
|
|
gdb_assert (name[current_len] == ':');
|
|
previous_len = current_len;
|
|
/* Skip the '::'. */
|
|
current_len += 2;
|
|
current_len += cp_find_first_component (name + current_len);
|
|
}
|
|
|
|
return previous_len;
|
|
}
|
|
|
|
/* Overload resolution functions. */
|
|
|
|
/* Test to see if SYM is a symbol that we haven't seen corresponding
|
|
to a function named OLOAD_NAME. If so, add it to
|
|
OVERLOAD_LIST. */
|
|
|
|
static void
|
|
overload_list_add_symbol (struct symbol *sym,
|
|
const char *oload_name,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
/* If there is no type information, we can't do anything, so
|
|
skip. */
|
|
if (SYMBOL_TYPE (sym) == NULL)
|
|
return;
|
|
|
|
/* skip any symbols that we've already considered. */
|
|
for (symbol *listed_sym : *overload_list)
|
|
if (strcmp (sym->linkage_name (), listed_sym->linkage_name ()) == 0)
|
|
return;
|
|
|
|
/* Get the demangled name without parameters */
|
|
gdb::unique_xmalloc_ptr<char> sym_name
|
|
= cp_remove_params (sym->natural_name ());
|
|
if (!sym_name)
|
|
return;
|
|
|
|
/* skip symbols that cannot match */
|
|
if (strcmp (sym_name.get (), oload_name) != 0)
|
|
return;
|
|
|
|
overload_list->push_back (sym);
|
|
}
|
|
|
|
/* Return a null-terminated list of pointers to function symbols that
|
|
are named FUNC_NAME and are visible within NAMESPACE. */
|
|
|
|
struct std::vector<symbol *>
|
|
make_symbol_overload_list (const char *func_name,
|
|
const char *the_namespace)
|
|
{
|
|
const char *name;
|
|
std::vector<symbol *> overload_list;
|
|
|
|
overload_list.reserve (100);
|
|
|
|
add_symbol_overload_list_using (func_name, the_namespace, &overload_list);
|
|
|
|
if (the_namespace[0] == '\0')
|
|
name = func_name;
|
|
else
|
|
{
|
|
char *concatenated_name
|
|
= (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1);
|
|
strcpy (concatenated_name, the_namespace);
|
|
strcat (concatenated_name, "::");
|
|
strcat (concatenated_name, func_name);
|
|
name = concatenated_name;
|
|
}
|
|
|
|
add_symbol_overload_list_qualified (name, &overload_list);
|
|
return overload_list;
|
|
}
|
|
|
|
/* Add all symbols with a name matching NAME in BLOCK to the overload
|
|
list. */
|
|
|
|
static void
|
|
add_symbol_overload_list_block (const char *name,
|
|
const struct block *block,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
struct block_iterator iter;
|
|
struct symbol *sym;
|
|
|
|
lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
|
|
|
|
ALL_BLOCK_SYMBOLS_WITH_NAME (block, lookup_name, iter, sym)
|
|
overload_list_add_symbol (sym, name, overload_list);
|
|
}
|
|
|
|
/* Adds the function FUNC_NAME from NAMESPACE to the overload set. */
|
|
|
|
static void
|
|
add_symbol_overload_list_namespace (const char *func_name,
|
|
const char *the_namespace,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
const char *name;
|
|
const struct block *block = NULL;
|
|
|
|
if (the_namespace[0] == '\0')
|
|
name = func_name;
|
|
else
|
|
{
|
|
char *concatenated_name
|
|
= (char *) alloca (strlen (the_namespace) + 2 + strlen (func_name) + 1);
|
|
|
|
strcpy (concatenated_name, the_namespace);
|
|
strcat (concatenated_name, "::");
|
|
strcat (concatenated_name, func_name);
|
|
name = concatenated_name;
|
|
}
|
|
|
|
/* Look in the static block. */
|
|
block = block_static_block (get_selected_block (0));
|
|
if (block)
|
|
add_symbol_overload_list_block (name, block, overload_list);
|
|
|
|
/* Look in the global block. */
|
|
block = block_global_block (block);
|
|
if (block)
|
|
add_symbol_overload_list_block (name, block, overload_list);
|
|
|
|
}
|
|
|
|
/* Search the namespace of the given type and namespace of and public
|
|
base types. */
|
|
|
|
static void
|
|
add_symbol_overload_list_adl_namespace (struct type *type,
|
|
const char *func_name,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
char *the_namespace;
|
|
const char *type_name;
|
|
int i, prefix_len;
|
|
|
|
while (TYPE_CODE (type) == TYPE_CODE_PTR
|
|
|| TYPE_IS_REFERENCE (type)
|
|
|| TYPE_CODE (type) == TYPE_CODE_ARRAY
|
|
|| TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
|
|
{
|
|
if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
|
|
type = check_typedef(type);
|
|
else
|
|
type = TYPE_TARGET_TYPE (type);
|
|
}
|
|
|
|
type_name = TYPE_NAME (type);
|
|
|
|
if (type_name == NULL)
|
|
return;
|
|
|
|
prefix_len = cp_entire_prefix_len (type_name);
|
|
|
|
if (prefix_len != 0)
|
|
{
|
|
the_namespace = (char *) alloca (prefix_len + 1);
|
|
strncpy (the_namespace, type_name, prefix_len);
|
|
the_namespace[prefix_len] = '\0';
|
|
|
|
add_symbol_overload_list_namespace (func_name, the_namespace,
|
|
overload_list);
|
|
}
|
|
|
|
/* Check public base type */
|
|
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
|
|
for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
|
|
{
|
|
if (BASETYPE_VIA_PUBLIC (type, i))
|
|
add_symbol_overload_list_adl_namespace (TYPE_BASECLASS (type, i),
|
|
func_name,
|
|
overload_list);
|
|
}
|
|
}
|
|
|
|
/* Adds to OVERLOAD_LIST the overload list overload candidates for
|
|
FUNC_NAME found through argument dependent lookup. */
|
|
|
|
void
|
|
add_symbol_overload_list_adl (gdb::array_view<type *> arg_types,
|
|
const char *func_name,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
for (type *arg_type : arg_types)
|
|
add_symbol_overload_list_adl_namespace (arg_type, func_name,
|
|
overload_list);
|
|
}
|
|
|
|
/* This applies the using directives to add namespaces to search in,
|
|
and then searches for overloads in all of those namespaces. It
|
|
adds the symbols found to sym_return_val. Arguments are as in
|
|
make_symbol_overload_list. */
|
|
|
|
static void
|
|
add_symbol_overload_list_using (const char *func_name,
|
|
const char *the_namespace,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
struct using_direct *current;
|
|
const struct block *block;
|
|
|
|
/* First, go through the using directives. If any of them apply,
|
|
look in the appropriate namespaces for new functions to match
|
|
on. */
|
|
|
|
for (block = get_selected_block (0);
|
|
block != NULL;
|
|
block = BLOCK_SUPERBLOCK (block))
|
|
for (current = block_using (block);
|
|
current != NULL;
|
|
current = current->next)
|
|
{
|
|
/* Prevent recursive calls. */
|
|
if (current->searched)
|
|
continue;
|
|
|
|
/* If this is a namespace alias or imported declaration ignore
|
|
it. */
|
|
if (current->alias != NULL || current->declaration != NULL)
|
|
continue;
|
|
|
|
if (strcmp (the_namespace, current->import_dest) == 0)
|
|
{
|
|
/* Mark this import as searched so that the recursive call
|
|
does not search it again. */
|
|
scoped_restore reset_directive_searched
|
|
= make_scoped_restore (¤t->searched, 1);
|
|
|
|
add_symbol_overload_list_using (func_name,
|
|
current->import_src,
|
|
overload_list);
|
|
}
|
|
}
|
|
|
|
/* Now, add names for this namespace. */
|
|
add_symbol_overload_list_namespace (func_name, the_namespace,
|
|
overload_list);
|
|
}
|
|
|
|
/* This does the bulk of the work of finding overloaded symbols.
|
|
FUNC_NAME is the name of the overloaded function we're looking for
|
|
(possibly including namespace info). */
|
|
|
|
static void
|
|
add_symbol_overload_list_qualified (const char *func_name,
|
|
std::vector<symbol *> *overload_list)
|
|
{
|
|
const struct block *b, *surrounding_static_block = 0;
|
|
|
|
/* Look through the partial symtabs for all symbols which begin by
|
|
matching FUNC_NAME. Make sure we read that symbol table in. */
|
|
|
|
for (objfile *objf : current_program_space->objfiles ())
|
|
{
|
|
if (objf->sf)
|
|
objf->sf->qf->expand_symtabs_for_function (objf, func_name);
|
|
}
|
|
|
|
/* Search upwards from currently selected frame (so that we can
|
|
complete on local vars. */
|
|
|
|
for (b = get_selected_block (0); b != NULL; b = BLOCK_SUPERBLOCK (b))
|
|
add_symbol_overload_list_block (func_name, b, overload_list);
|
|
|
|
surrounding_static_block = block_static_block (get_selected_block (0));
|
|
|
|
/* Go through the symtabs and check the externs and statics for
|
|
symbols which match. */
|
|
|
|
for (objfile *objfile : current_program_space->objfiles ())
|
|
{
|
|
for (compunit_symtab *cust : objfile->compunits ())
|
|
{
|
|
QUIT;
|
|
b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
|
|
add_symbol_overload_list_block (func_name, b, overload_list);
|
|
}
|
|
}
|
|
|
|
for (objfile *objfile : current_program_space->objfiles ())
|
|
{
|
|
for (compunit_symtab *cust : objfile->compunits ())
|
|
{
|
|
QUIT;
|
|
b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
|
|
/* Don't do this block twice. */
|
|
if (b == surrounding_static_block)
|
|
continue;
|
|
add_symbol_overload_list_block (func_name, b, overload_list);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Lookup the rtti type for a class name. */
|
|
|
|
struct type *
|
|
cp_lookup_rtti_type (const char *name, const struct block *block)
|
|
{
|
|
struct symbol * rtti_sym;
|
|
struct type * rtti_type;
|
|
|
|
/* Use VAR_DOMAIN here as NAME may be a typedef. PR 18141, 18417.
|
|
Classes "live" in both STRUCT_DOMAIN and VAR_DOMAIN. */
|
|
rtti_sym = lookup_symbol (name, block, VAR_DOMAIN, NULL).symbol;
|
|
|
|
if (rtti_sym == NULL)
|
|
{
|
|
warning (_("RTTI symbol not found for class '%s'"), name);
|
|
return NULL;
|
|
}
|
|
|
|
if (SYMBOL_CLASS (rtti_sym) != LOC_TYPEDEF)
|
|
{
|
|
warning (_("RTTI symbol for class '%s' is not a type"), name);
|
|
return NULL;
|
|
}
|
|
|
|
rtti_type = check_typedef (SYMBOL_TYPE (rtti_sym));
|
|
|
|
switch (TYPE_CODE (rtti_type))
|
|
{
|
|
case TYPE_CODE_STRUCT:
|
|
break;
|
|
case TYPE_CODE_NAMESPACE:
|
|
/* chastain/2003-11-26: the symbol tables often contain fake
|
|
symbols for namespaces with the same name as the struct.
|
|
This warning is an indication of a bug in the lookup order
|
|
or a bug in the way that the symbol tables are populated. */
|
|
warning (_("RTTI symbol for class '%s' is a namespace"), name);
|
|
return NULL;
|
|
default:
|
|
warning (_("RTTI symbol for class '%s' has bad type"), name);
|
|
return NULL;
|
|
}
|
|
|
|
return rtti_type;
|
|
}
|
|
|
|
#ifdef HAVE_WORKING_FORK
|
|
|
|
/* If true, attempt to catch crashes in the demangler and print
|
|
useful debugging information. */
|
|
|
|
static bool catch_demangler_crashes = true;
|
|
|
|
/* Stack context and environment for demangler crash recovery. */
|
|
|
|
static thread_local SIGJMP_BUF *gdb_demangle_jmp_buf;
|
|
|
|
/* If true, attempt to dump core from the signal handler. */
|
|
|
|
static std::atomic<bool> gdb_demangle_attempt_core_dump;
|
|
|
|
/* Signal handler for gdb_demangle. */
|
|
|
|
static void
|
|
gdb_demangle_signal_handler (int signo)
|
|
{
|
|
if (gdb_demangle_attempt_core_dump)
|
|
{
|
|
if (fork () == 0)
|
|
dump_core ();
|
|
|
|
gdb_demangle_attempt_core_dump = false;
|
|
}
|
|
|
|
SIGLONGJMP (*gdb_demangle_jmp_buf, signo);
|
|
}
|
|
|
|
/* A helper for gdb_demangle that reports a demangling failure. */
|
|
|
|
static void
|
|
report_failed_demangle (const char *name, bool core_dump_allowed,
|
|
int crash_signal)
|
|
{
|
|
static bool error_reported = false;
|
|
|
|
if (!error_reported)
|
|
{
|
|
std::string short_msg
|
|
= string_printf (_("unable to demangle '%s' "
|
|
"(demangler failed with signal %d)"),
|
|
name, crash_signal);
|
|
|
|
std::string long_msg
|
|
= string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
|
|
"demangler-warning", short_msg.c_str ());
|
|
|
|
target_terminal::scoped_restore_terminal_state term_state;
|
|
target_terminal::ours_for_output ();
|
|
|
|
begin_line ();
|
|
if (core_dump_allowed)
|
|
fprintf_unfiltered (gdb_stderr,
|
|
_("%s\nAttempting to dump core.\n"),
|
|
long_msg.c_str ());
|
|
else
|
|
warn_cant_dump_core (long_msg.c_str ());
|
|
|
|
demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
|
|
|
|
error_reported = true;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/* A wrapper for bfd_demangle. */
|
|
|
|
char *
|
|
gdb_demangle (const char *name, int options)
|
|
{
|
|
char *result = NULL;
|
|
int crash_signal = 0;
|
|
|
|
#ifdef HAVE_WORKING_FORK
|
|
scoped_restore restore_segv
|
|
= make_scoped_restore (&thread_local_segv_handler,
|
|
catch_demangler_crashes
|
|
? gdb_demangle_signal_handler
|
|
: nullptr);
|
|
|
|
bool core_dump_allowed = gdb_demangle_attempt_core_dump;
|
|
SIGJMP_BUF jmp_buf;
|
|
scoped_restore restore_jmp_buf
|
|
= make_scoped_restore (&gdb_demangle_jmp_buf, &jmp_buf);
|
|
if (catch_demangler_crashes)
|
|
{
|
|
/* The signal handler may keep the signal blocked when we longjmp out
|
|
of it. If we have sigprocmask, we can use it to unblock the signal
|
|
afterwards and we can avoid the performance overhead of saving the
|
|
signal mask just in case the signal gets triggered. Otherwise, just
|
|
tell sigsetjmp to save the mask. */
|
|
#ifdef HAVE_SIGPROCMASK
|
|
crash_signal = SIGSETJMP (*gdb_demangle_jmp_buf, 0);
|
|
#else
|
|
crash_signal = SIGSETJMP (*gdb_demangle_jmp_buf, 1);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (crash_signal == 0)
|
|
result = bfd_demangle (NULL, name, options);
|
|
|
|
#ifdef HAVE_WORKING_FORK
|
|
if (catch_demangler_crashes)
|
|
{
|
|
if (crash_signal != 0)
|
|
{
|
|
#ifdef HAVE_SIGPROCMASK
|
|
/* If we got the signal, SIGSEGV may still be blocked; restore it. */
|
|
sigset_t segv_sig_set;
|
|
sigemptyset (&segv_sig_set);
|
|
sigaddset (&segv_sig_set, SIGSEGV);
|
|
gdb_sigmask (SIG_UNBLOCK, &segv_sig_set, NULL);
|
|
#endif
|
|
|
|
/* If there was a failure, we can't report it here, because
|
|
we might be in a background thread. Instead, arrange for
|
|
the reporting to happen on the main thread. */
|
|
std::string copy = name;
|
|
run_on_main_thread ([=] ()
|
|
{
|
|
report_failed_demangle (copy.c_str (), core_dump_allowed,
|
|
crash_signal);
|
|
});
|
|
|
|
result = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
/* See cp-support.h. */
|
|
|
|
int
|
|
gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
|
|
{
|
|
*demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
|
|
return *demangled != NULL;
|
|
}
|
|
|
|
/* See cp-support.h. */
|
|
|
|
unsigned int
|
|
cp_search_name_hash (const char *search_name)
|
|
{
|
|
/* cp_entire_prefix_len assumes a fully-qualified name with no
|
|
leading "::". */
|
|
if (startswith (search_name, "::"))
|
|
search_name += 2;
|
|
|
|
unsigned int prefix_len = cp_entire_prefix_len (search_name);
|
|
if (prefix_len != 0)
|
|
search_name += prefix_len + 2;
|
|
|
|
unsigned int hash = 0;
|
|
for (const char *string = search_name; *string != '\0'; ++string)
|
|
{
|
|
string = skip_spaces (string);
|
|
|
|
if (*string == '(')
|
|
break;
|
|
|
|
/* Ignore ABI tags such as "[abi:cxx11]. */
|
|
if (*string == '['
|
|
&& startswith (string + 1, "abi:")
|
|
&& string[5] != ':')
|
|
break;
|
|
|
|
hash = SYMBOL_HASH_NEXT (hash, *string);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
/* Helper for cp_symbol_name_matches (i.e., symbol_name_matcher_ftype
|
|
implementation for symbol_name_match_type::WILD matching). Split
|
|
to a separate function for unit-testing convenience.
|
|
|
|
If SYMBOL_SEARCH_NAME has more scopes than LOOKUP_NAME, we try to
|
|
match ignoring the extra leading scopes of SYMBOL_SEARCH_NAME.
|
|
This allows conveniently setting breakpoints on functions/methods
|
|
inside any namespace/class without specifying the fully-qualified
|
|
name.
|
|
|
|
E.g., these match:
|
|
|
|
[symbol search name] [lookup name]
|
|
foo::bar::func foo::bar::func
|
|
foo::bar::func bar::func
|
|
foo::bar::func func
|
|
|
|
While these don't:
|
|
|
|
[symbol search name] [lookup name]
|
|
foo::zbar::func bar::func
|
|
foo::bar::func foo::func
|
|
|
|
See more examples in the test_cp_symbol_name_matches selftest
|
|
function below.
|
|
|
|
See symbol_name_matcher_ftype for description of SYMBOL_SEARCH_NAME
|
|
and COMP_MATCH_RES.
|
|
|
|
LOOKUP_NAME/LOOKUP_NAME_LEN is the name we're looking up.
|
|
|
|
See strncmp_iw_with_mode for description of MODE.
|
|
*/
|
|
|
|
static bool
|
|
cp_symbol_name_matches_1 (const char *symbol_search_name,
|
|
const char *lookup_name,
|
|
size_t lookup_name_len,
|
|
strncmp_iw_mode mode,
|
|
completion_match_result *comp_match_res)
|
|
{
|
|
const char *sname = symbol_search_name;
|
|
completion_match_for_lcd *match_for_lcd
|
|
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
|
|
|
|
while (true)
|
|
{
|
|
if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
|
|
mode, language_cplus, match_for_lcd) == 0)
|
|
{
|
|
if (comp_match_res != NULL)
|
|
{
|
|
/* Note here we set different MATCH and MATCH_FOR_LCD
|
|
strings. This is because with
|
|
|
|
(gdb) b push_bac[TAB]
|
|
|
|
we want the completion matches to list
|
|
|
|
std::vector<int>::push_back(...)
|
|
std::vector<char>::push_back(...)
|
|
|
|
etc., which are SYMBOL_SEARCH_NAMEs, while we want
|
|
the input line to auto-complete to
|
|
|
|
(gdb) push_back(...)
|
|
|
|
which is SNAME, not to
|
|
|
|
(gdb) std::vector<
|
|
|
|
which would be the regular common prefix between all
|
|
the matches otherwise. */
|
|
comp_match_res->set_match (symbol_search_name, sname);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
unsigned int len = cp_find_first_component (sname);
|
|
|
|
if (sname[len] == '\0')
|
|
return false;
|
|
|
|
gdb_assert (sname[len] == ':');
|
|
/* Skip the '::'. */
|
|
sname += len + 2;
|
|
}
|
|
}
|
|
|
|
/* C++ symbol_name_matcher_ftype implementation. */
|
|
|
|
static bool
|
|
cp_fq_symbol_name_matches (const char *symbol_search_name,
|
|
const lookup_name_info &lookup_name,
|
|
completion_match_result *comp_match_res)
|
|
{
|
|
/* Get the demangled name. */
|
|
const std::string &name = lookup_name.cplus ().lookup_name ();
|
|
completion_match_for_lcd *match_for_lcd
|
|
= (comp_match_res != NULL ? &comp_match_res->match_for_lcd : NULL);
|
|
strncmp_iw_mode mode = (lookup_name.completion_mode ()
|
|
? strncmp_iw_mode::NORMAL
|
|
: strncmp_iw_mode::MATCH_PARAMS);
|
|
|
|
if (strncmp_iw_with_mode (symbol_search_name,
|
|
name.c_str (), name.size (),
|
|
mode, language_cplus, match_for_lcd) == 0)
|
|
{
|
|
if (comp_match_res != NULL)
|
|
comp_match_res->set_match (symbol_search_name);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* C++ symbol_name_matcher_ftype implementation for wild matches.
|
|
Defers work to cp_symbol_name_matches_1. */
|
|
|
|
static bool
|
|
cp_symbol_name_matches (const char *symbol_search_name,
|
|
const lookup_name_info &lookup_name,
|
|
completion_match_result *comp_match_res)
|
|
{
|
|
/* Get the demangled name. */
|
|
const std::string &name = lookup_name.cplus ().lookup_name ();
|
|
|
|
strncmp_iw_mode mode = (lookup_name.completion_mode ()
|
|
? strncmp_iw_mode::NORMAL
|
|
: strncmp_iw_mode::MATCH_PARAMS);
|
|
|
|
return cp_symbol_name_matches_1 (symbol_search_name,
|
|
name.c_str (), name.size (),
|
|
mode, comp_match_res);
|
|
}
|
|
|
|
/* See cp-support.h. */
|
|
|
|
symbol_name_matcher_ftype *
|
|
cp_get_symbol_name_matcher (const lookup_name_info &lookup_name)
|
|
{
|
|
switch (lookup_name.match_type ())
|
|
{
|
|
case symbol_name_match_type::FULL:
|
|
case symbol_name_match_type::EXPRESSION:
|
|
case symbol_name_match_type::SEARCH_NAME:
|
|
return cp_fq_symbol_name_matches;
|
|
case symbol_name_match_type::WILD:
|
|
return cp_symbol_name_matches;
|
|
}
|
|
|
|
gdb_assert_not_reached ("");
|
|
}
|
|
|
|
#if GDB_SELF_TEST
|
|
|
|
namespace selftests {
|
|
|
|
static void
|
|
test_cp_symbol_name_matches ()
|
|
{
|
|
#define CHECK_MATCH(SYMBOL, INPUT) \
|
|
SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL, \
|
|
INPUT, sizeof (INPUT) - 1, \
|
|
strncmp_iw_mode::MATCH_PARAMS, \
|
|
NULL))
|
|
|
|
#define CHECK_NOT_MATCH(SYMBOL, INPUT) \
|
|
SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL, \
|
|
INPUT, sizeof (INPUT) - 1, \
|
|
strncmp_iw_mode::MATCH_PARAMS, \
|
|
NULL))
|
|
|
|
/* Like CHECK_MATCH, and also check that INPUT (and all substrings
|
|
that start at index 0) completes to SYMBOL. */
|
|
#define CHECK_MATCH_C(SYMBOL, INPUT) \
|
|
do \
|
|
{ \
|
|
CHECK_MATCH (SYMBOL, INPUT); \
|
|
for (size_t i = 0; i < sizeof (INPUT) - 1; i++) \
|
|
SELF_CHECK (cp_symbol_name_matches_1 (SYMBOL, INPUT, i, \
|
|
strncmp_iw_mode::NORMAL, \
|
|
NULL)); \
|
|
} while (0)
|
|
|
|
/* Like CHECK_NOT_MATCH, and also check that INPUT does NOT complete
|
|
to SYMBOL. */
|
|
#define CHECK_NOT_MATCH_C(SYMBOL, INPUT) \
|
|
do \
|
|
{ \
|
|
CHECK_NOT_MATCH (SYMBOL, INPUT); \
|
|
SELF_CHECK (!cp_symbol_name_matches_1 (SYMBOL, INPUT, \
|
|
sizeof (INPUT) - 1, \
|
|
strncmp_iw_mode::NORMAL, \
|
|
NULL)); \
|
|
} while (0)
|
|
|
|
/* Lookup name without parens matches all overloads. */
|
|
CHECK_MATCH_C ("function()", "function");
|
|
CHECK_MATCH_C ("function(int)", "function");
|
|
|
|
/* Check whitespace around parameters is ignored. */
|
|
CHECK_MATCH_C ("function()", "function ()");
|
|
CHECK_MATCH_C ("function ( )", "function()");
|
|
CHECK_MATCH_C ("function ()", "function( )");
|
|
CHECK_MATCH_C ("func(int)", "func( int )");
|
|
CHECK_MATCH_C ("func(int)", "func ( int ) ");
|
|
CHECK_MATCH_C ("func ( int )", "func( int )");
|
|
CHECK_MATCH_C ("func ( int )", "func ( int ) ");
|
|
|
|
/* Check symbol name prefixes aren't incorrectly matched. */
|
|
CHECK_NOT_MATCH ("func", "function");
|
|
CHECK_NOT_MATCH ("function", "func");
|
|
CHECK_NOT_MATCH ("function()", "func");
|
|
|
|
/* Check that if the lookup name includes parameters, only the right
|
|
overload matches. */
|
|
CHECK_MATCH_C ("function(int)", "function(int)");
|
|
CHECK_NOT_MATCH_C ("function(int)", "function()");
|
|
|
|
/* Check that whitespace within symbol names is not ignored. */
|
|
CHECK_NOT_MATCH_C ("function", "func tion");
|
|
CHECK_NOT_MATCH_C ("func__tion", "func_ _tion");
|
|
CHECK_NOT_MATCH_C ("func11tion", "func1 1tion");
|
|
|
|
/* Check the converse, which can happen with template function,
|
|
where the return type is part of the demangled name. */
|
|
CHECK_NOT_MATCH_C ("func tion", "function");
|
|
CHECK_NOT_MATCH_C ("func1 1tion", "func11tion");
|
|
CHECK_NOT_MATCH_C ("func_ _tion", "func__tion");
|
|
|
|
/* Within parameters too. */
|
|
CHECK_NOT_MATCH_C ("func(param)", "func(par am)");
|
|
|
|
/* Check handling of whitespace around C++ operators. */
|
|
CHECK_NOT_MATCH_C ("operator<<", "opera tor<<");
|
|
CHECK_NOT_MATCH_C ("operator<<", "operator< <");
|
|
CHECK_NOT_MATCH_C ("operator<<", "operator < <");
|
|
CHECK_NOT_MATCH_C ("operator==", "operator= =");
|
|
CHECK_NOT_MATCH_C ("operator==", "operator = =");
|
|
CHECK_MATCH_C ("operator<<", "operator <<");
|
|
CHECK_MATCH_C ("operator<<()", "operator <<");
|
|
CHECK_NOT_MATCH_C ("operator<<()", "operator<<(int)");
|
|
CHECK_NOT_MATCH_C ("operator<<(int)", "operator<<()");
|
|
CHECK_MATCH_C ("operator==", "operator ==");
|
|
CHECK_MATCH_C ("operator==()", "operator ==");
|
|
CHECK_MATCH_C ("operator <<", "operator<<");
|
|
CHECK_MATCH_C ("operator ==", "operator==");
|
|
CHECK_MATCH_C ("operator bool", "operator bool");
|
|
CHECK_MATCH_C ("operator bool ()", "operator bool");
|
|
CHECK_MATCH_C ("operatorX<<", "operatorX < <");
|
|
CHECK_MATCH_C ("Xoperator<<", "Xoperator < <");
|
|
|
|
CHECK_MATCH_C ("operator()(int)", "operator()(int)");
|
|
CHECK_MATCH_C ("operator()(int)", "operator ( ) ( int )");
|
|
CHECK_MATCH_C ("operator()<long>(int)", "operator ( ) < long > ( int )");
|
|
/* The first "()" is not the parameter list. */
|
|
CHECK_NOT_MATCH ("operator()(int)", "operator");
|
|
|
|
/* Misc user-defined operator tests. */
|
|
|
|
CHECK_NOT_MATCH_C ("operator/=()", "operator ^=");
|
|
/* Same length at end of input. */
|
|
CHECK_NOT_MATCH_C ("operator>>", "operator[]");
|
|
/* Same length but not at end of input. */
|
|
CHECK_NOT_MATCH_C ("operator>>()", "operator[]()");
|
|
|
|
CHECK_MATCH_C ("base::operator char*()", "base::operator char*()");
|
|
CHECK_MATCH_C ("base::operator char*()", "base::operator char * ()");
|
|
CHECK_MATCH_C ("base::operator char**()", "base::operator char * * ()");
|
|
CHECK_MATCH ("base::operator char**()", "base::operator char * *");
|
|
CHECK_MATCH_C ("base::operator*()", "base::operator*()");
|
|
CHECK_NOT_MATCH_C ("base::operator char*()", "base::operatorc");
|
|
CHECK_NOT_MATCH ("base::operator char*()", "base::operator char");
|
|
CHECK_NOT_MATCH ("base::operator char*()", "base::operat");
|
|
|
|
/* Check handling of whitespace around C++ scope operators. */
|
|
CHECK_NOT_MATCH_C ("foo::bar", "foo: :bar");
|
|
CHECK_MATCH_C ("foo::bar", "foo :: bar");
|
|
CHECK_MATCH_C ("foo :: bar", "foo::bar");
|
|
|
|
CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi()");
|
|
CHECK_MATCH_C ("abc::def::ghi ( )", "abc::def::ghi()");
|
|
CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi ( )");
|
|
CHECK_MATCH_C ("function()", "function()");
|
|
CHECK_MATCH_C ("bar::function()", "bar::function()");
|
|
|
|
/* Wild matching tests follow. */
|
|
|
|
/* Tests matching symbols in some scope. */
|
|
CHECK_MATCH_C ("foo::function()", "function");
|
|
CHECK_MATCH_C ("foo::function(int)", "function");
|
|
CHECK_MATCH_C ("foo::bar::function()", "function");
|
|
CHECK_MATCH_C ("bar::function()", "bar::function");
|
|
CHECK_MATCH_C ("foo::bar::function()", "bar::function");
|
|
CHECK_MATCH_C ("foo::bar::function(int)", "bar::function");
|
|
|
|
/* Same, with parameters in the lookup name. */
|
|
CHECK_MATCH_C ("foo::function()", "function()");
|
|
CHECK_MATCH_C ("foo::bar::function()", "function()");
|
|
CHECK_MATCH_C ("foo::function(int)", "function(int)");
|
|
CHECK_MATCH_C ("foo::function()", "foo::function()");
|
|
CHECK_MATCH_C ("foo::bar::function()", "bar::function()");
|
|
CHECK_MATCH_C ("foo::bar::function(int)", "bar::function(int)");
|
|
CHECK_MATCH_C ("bar::function()", "bar::function()");
|
|
|
|
CHECK_NOT_MATCH_C ("foo::bar::function(int)", "bar::function()");
|
|
|
|
CHECK_MATCH_C ("(anonymous namespace)::bar::function(int)",
|
|
"bar::function(int)");
|
|
CHECK_MATCH_C ("foo::(anonymous namespace)::bar::function(int)",
|
|
"function(int)");
|
|
|
|
/* Lookup scope wider than symbol scope, should not match. */
|
|
CHECK_NOT_MATCH_C ("function()", "bar::function");
|
|
CHECK_NOT_MATCH_C ("function()", "bar::function()");
|
|
|
|
/* Explicit global scope doesn't match. */
|
|
CHECK_NOT_MATCH_C ("foo::function()", "::function");
|
|
CHECK_NOT_MATCH_C ("foo::function()", "::function()");
|
|
CHECK_NOT_MATCH_C ("foo::function(int)", "::function()");
|
|
CHECK_NOT_MATCH_C ("foo::function(int)", "::function(int)");
|
|
|
|
/* Test ABI tag matching/ignoring. */
|
|
|
|
/* If the symbol name has an ABI tag, but the lookup name doesn't,
|
|
then the ABI tag in the symbol name is ignored. */
|
|
CHECK_MATCH_C ("function[abi:foo]()", "function");
|
|
CHECK_MATCH_C ("function[abi:foo](int)", "function");
|
|
CHECK_MATCH_C ("function[abi:foo]()", "function ()");
|
|
CHECK_NOT_MATCH_C ("function[abi:foo]()", "function (int)");
|
|
|
|
CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo]");
|
|
CHECK_MATCH_C ("function[abi:foo](int)", "function[abi:foo]");
|
|
CHECK_MATCH_C ("function[abi:foo]()", "function[abi:foo] ()");
|
|
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function");
|
|
CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function");
|
|
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo]");
|
|
CHECK_MATCH_C ("function[abi:foo][abi:bar](int)", "function[abi:foo]");
|
|
CHECK_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] ()");
|
|
CHECK_NOT_MATCH_C ("function[abi:foo][abi:bar]()", "function[abi:foo] (int)");
|
|
|
|
CHECK_MATCH_C ("function [abi:foo][abi:bar] ( )", "function [abi:foo]");
|
|
|
|
/* If the symbol name does not have an ABI tag, while the lookup
|
|
name has one, then there's no match. */
|
|
CHECK_NOT_MATCH_C ("function()", "function[abi:foo]()");
|
|
CHECK_NOT_MATCH_C ("function()", "function[abi:foo]");
|
|
}
|
|
|
|
/* If non-NULL, return STR wrapped in quotes. Otherwise, return a
|
|
"<null>" string (with no quotes). */
|
|
|
|
static std::string
|
|
quote (const char *str)
|
|
{
|
|
if (str != NULL)
|
|
return std::string (1, '"') + str + '"';
|
|
else
|
|
return "<null>";
|
|
}
|
|
|
|
/* Check that removing parameter info out of NAME produces EXPECTED.
|
|
COMPLETION_MODE indicates whether we're testing normal and
|
|
completion mode. FILE and LINE are used to provide better test
|
|
location information in case ithe check fails. */
|
|
|
|
static void
|
|
check_remove_params (const char *file, int line,
|
|
const char *name, const char *expected,
|
|
bool completion_mode)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char> result
|
|
= cp_remove_params_if_any (name, completion_mode);
|
|
|
|
if ((expected == NULL) != (result == NULL)
|
|
|| (expected != NULL
|
|
&& strcmp (result.get (), expected) != 0))
|
|
{
|
|
error (_("%s:%d: make-paramless self-test failed: (completion=%d) "
|
|
"\"%s\" -> %s, expected %s"),
|
|
file, line, completion_mode, name,
|
|
quote (result.get ()).c_str (), quote (expected).c_str ());
|
|
}
|
|
}
|
|
|
|
/* Entry point for cp_remove_params unit tests. */
|
|
|
|
static void
|
|
test_cp_remove_params ()
|
|
{
|
|
/* Check that removing parameter info out of NAME produces EXPECTED.
|
|
Checks both normal and completion modes. */
|
|
#define CHECK(NAME, EXPECTED) \
|
|
do \
|
|
{ \
|
|
check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, false); \
|
|
check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true); \
|
|
} \
|
|
while (0)
|
|
|
|
/* Similar, but used when NAME is incomplete -- i.e., is has
|
|
unbalanced parentheses. In this case, looking for the exact name
|
|
should fail / return empty. */
|
|
#define CHECK_INCOMPL(NAME, EXPECTED) \
|
|
do \
|
|
{ \
|
|
check_remove_params (__FILE__, __LINE__, NAME, NULL, false); \
|
|
check_remove_params (__FILE__, __LINE__, NAME, EXPECTED, true); \
|
|
} \
|
|
while (0)
|
|
|
|
CHECK ("function()", "function");
|
|
CHECK_INCOMPL ("function(", "function");
|
|
CHECK ("function() const", "function");
|
|
|
|
CHECK ("(anonymous namespace)::A::B::C",
|
|
"(anonymous namespace)::A::B::C");
|
|
|
|
CHECK ("A::(anonymous namespace)",
|
|
"A::(anonymous namespace)");
|
|
|
|
CHECK_INCOMPL ("A::(anonymou", "A");
|
|
|
|
CHECK ("A::foo<int>()",
|
|
"A::foo<int>");
|
|
|
|
CHECK_INCOMPL ("A::foo<int>(",
|
|
"A::foo<int>");
|
|
|
|
CHECK ("A::foo<(anonymous namespace)::B>::func(int)",
|
|
"A::foo<(anonymous namespace)::B>::func");
|
|
|
|
CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::func(in",
|
|
"A::foo<(anonymous namespace)::B>::func");
|
|
|
|
CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>::",
|
|
"A::foo<(anonymous namespace)::B>");
|
|
|
|
CHECK_INCOMPL ("A::foo<(anonymous namespace)::B>:",
|
|
"A::foo<(anonymous namespace)::B>");
|
|
|
|
CHECK ("A::foo<(anonymous namespace)::B>",
|
|
"A::foo<(anonymous namespace)::B>");
|
|
|
|
CHECK_INCOMPL ("A::foo<(anonymous namespace)::B",
|
|
"A::foo");
|
|
|
|
/* Shouldn't this parse? Looks like a bug in
|
|
cp_demangled_name_to_comp. See PR c++/22411. */
|
|
#if 0
|
|
CHECK ("A::foo<void(int)>::func(int)",
|
|
"A::foo<void(int)>::func");
|
|
#else
|
|
CHECK_INCOMPL ("A::foo<void(int)>::func(int)",
|
|
"A::foo");
|
|
#endif
|
|
|
|
CHECK_INCOMPL ("A::foo<void(int",
|
|
"A::foo");
|
|
|
|
#undef CHECK
|
|
#undef CHECK_INCOMPL
|
|
}
|
|
|
|
} // namespace selftests
|
|
|
|
#endif /* GDB_SELF_CHECK */
|
|
|
|
/* Don't allow just "maintenance cplus". */
|
|
|
|
static void
|
|
maint_cplus_command (const char *arg, int from_tty)
|
|
{
|
|
printf_unfiltered (_("\"maintenance cplus\" must be followed "
|
|
"by the name of a command.\n"));
|
|
help_list (maint_cplus_cmd_list,
|
|
"maintenance cplus ",
|
|
all_commands, gdb_stdout);
|
|
}
|
|
|
|
/* This is a front end for cp_find_first_component, for unit testing.
|
|
Be careful when using it: see the NOTE above
|
|
cp_find_first_component. */
|
|
|
|
static void
|
|
first_component_command (const char *arg, int from_tty)
|
|
{
|
|
int len;
|
|
char *prefix;
|
|
|
|
if (!arg)
|
|
return;
|
|
|
|
len = cp_find_first_component (arg);
|
|
prefix = (char *) alloca (len + 1);
|
|
|
|
memcpy (prefix, arg, len);
|
|
prefix[len] = '\0';
|
|
|
|
printf_unfiltered ("%s\n", prefix);
|
|
}
|
|
|
|
/* Implement "info vtbl". */
|
|
|
|
static void
|
|
info_vtbl_command (const char *arg, int from_tty)
|
|
{
|
|
struct value *value;
|
|
|
|
value = parse_and_eval (arg);
|
|
cplus_print_vtable (value);
|
|
}
|
|
|
|
void _initialize_cp_support ();
|
|
void
|
|
_initialize_cp_support ()
|
|
{
|
|
add_prefix_cmd ("cplus", class_maintenance,
|
|
maint_cplus_command,
|
|
_("C++ maintenance commands."),
|
|
&maint_cplus_cmd_list,
|
|
"maintenance cplus ",
|
|
0, &maintenancelist);
|
|
add_alias_cmd ("cp", "cplus",
|
|
class_maintenance, 1,
|
|
&maintenancelist);
|
|
|
|
add_cmd ("first_component",
|
|
class_maintenance,
|
|
first_component_command,
|
|
_("Print the first class/namespace component of NAME."),
|
|
&maint_cplus_cmd_list);
|
|
|
|
add_info ("vtbl", info_vtbl_command,
|
|
_("Show the virtual function table for a C++ object.\n\
|
|
Usage: info vtbl EXPRESSION\n\
|
|
Evaluate EXPRESSION and display the virtual function table for the\n\
|
|
resulting object."));
|
|
|
|
#ifdef HAVE_WORKING_FORK
|
|
add_setshow_boolean_cmd ("catch-demangler-crashes", class_maintenance,
|
|
&catch_demangler_crashes, _("\
|
|
Set whether to attempt to catch demangler crashes."), _("\
|
|
Show whether to attempt to catch demangler crashes."), _("\
|
|
If enabled GDB will attempt to catch demangler crashes and\n\
|
|
display the offending symbol."),
|
|
NULL,
|
|
NULL,
|
|
&maintenance_set_cmdlist,
|
|
&maintenance_show_cmdlist);
|
|
|
|
gdb_demangle_attempt_core_dump = can_dump_core (LIMIT_CUR);
|
|
#endif
|
|
|
|
#if GDB_SELF_TEST
|
|
selftests::register_test ("cp_symbol_name_matches",
|
|
selftests::test_cp_symbol_name_matches);
|
|
selftests::register_test ("cp_remove_params",
|
|
selftests::test_cp_remove_params);
|
|
#endif
|
|
}
|