224c3ddb89
Most allocation functions (if not all) return a void* pointing to the allocated memory. In C++, we need to add an explicit cast when assigning the result to a pointer to another type (which is the case more often than not). The content of this patch is taken from Pedro's branch, from commit "(mostly) auto-generated patch to insert casts needed for C++". I validated that the changes make sense and manually reflowed the code to make it respect the coding style. I also found multiple places where I could use XNEW/XNEWVEC/XRESIZEVEC/etc. Thanks a lot to whoever did that automated script to insert casts, doing it completely by hand would have taken a ridiculous amount of time. Only files built on x86 with --enable-targets=all are modified. This means that all other -nat.c files are untouched and will have to be dealt with later by using appropiate compilers. Or maybe we can try to build them with a regular g++ just to know where to add casts, I don't know. I built-tested this with --enable-targets=all and reg-tested. Here's the changelog entry, which was not too bad to make despite the size, thanks to David Malcom's script. I fixed some bits by hand, but there might be some wrong parts left (hopefully not). gdb/ChangeLog: * aarch64-linux-tdep.c (aarch64_stap_parse_special_token): Add cast to allocation result assignment. * ada-exp.y (write_object_renaming): Likewise. (write_ambiguous_var): Likewise. (ada_nget_field_index): Likewise. (write_var_or_type): Likewise. * ada-lang.c (ada_decode_symbol): Likewise. (ada_value_assign): Likewise. (value_pointer): Likewise. (cache_symbol): Likewise. (add_nonlocal_symbols): Likewise. (ada_name_for_lookup): Likewise. (symbol_completion_add): Likewise. (ada_to_fixed_type_1): Likewise. (ada_get_next_arg): Likewise. (defns_collected): Likewise. * ada-lex.l (processId): Likewise. (processString): Likewise. * ada-tasks.c (read_known_tasks_array): Likewise. (read_known_tasks_list): Likewise. * ada-typeprint.c (decoded_type_name): Likewise. * addrmap.c (addrmap_mutable_create_fixed): Likewise. * amd64-tdep.c (amd64_push_arguments): Likewise. (amd64_displaced_step_copy_insn): Likewise. (amd64_classify_insn_at): Likewise. (amd64_relocate_instruction): Likewise. * amd64obsd-tdep.c (amd64obsd_sigtramp_p): Likewise. * arch-utils.c (simple_displaced_step_copy_insn): Likewise. (initialize_current_architecture): Likewise. * arm-linux-tdep.c (arm_stap_parse_special_token): Likewise. * arm-symbian-tdep.c (arm_symbian_osabi_sniffer): Likewise. * arm-tdep.c (arm_exidx_new_objfile): Likewise. (arm_push_dummy_call): Likewise. (extend_buffer_earlier): Likewise. (arm_adjust_breakpoint_address): Likewise. (arm_skip_stub): Likewise. * auto-load.c (filename_is_in_pattern): Likewise. (maybe_add_script_file): Likewise. (maybe_add_script_text): Likewise. (auto_load_objfile_script_1): Likewise. * auxv.c (ld_so_xfer_auxv): Likewise. * ax-general.c (new_agent_expr): Likewise. (grow_expr): Likewise. (ax_reg_mask): Likewise. * bcache.c (bcache_full): Likewise. * breakpoint.c (program_breakpoint_here_p): Likewise. * btrace.c (parse_xml_raw): Likewise. * build-id.c (build_id_to_debug_bfd): Likewise. * buildsym.c (end_symtab_with_blockvector): Likewise. * c-exp.y (string_exp): Likewise. (qualified_name): Likewise. (write_destructor_name): Likewise. (operator_stoken): Likewise. (parse_number): Likewise. (scan_macro_expansion): Likewise. (yylex): Likewise. (c_print_token): Likewise. * c-lang.c (c_get_string): Likewise. (emit_numeric_character): Likewise. * charset.c (wchar_iterate): Likewise. * cli/cli-cmds.c (complete_command): Likewise. (make_command): Likewise. * cli/cli-dump.c (restore_section_callback): Likewise. (restore_binary_file): Likewise. * cli/cli-interp.c (cli_interpreter_exec): Likewise. * cli/cli-script.c (execute_control_command): Likewise. * cli/cli-setshow.c (do_set_command): Likewise. * coff-pe-read.c (add_pe_forwarded_sym): Likewise. (read_pe_exported_syms): Likewise. * coffread.c (coff_read_struct_type): Likewise. (coff_read_enum_type): Likewise. * common/btrace-common.c (btrace_data_append): Likewise. * common/buffer.c (buffer_grow): Likewise. * common/filestuff.c (gdb_fopen_cloexec): Likewise. * common/format.c (parse_format_string): Likewise. * common/gdb_vecs.c (delim_string_to_char_ptr_vec_append): Likewise. * common/xml-utils.c (xml_escape_text): Likewise. * compile/compile-object-load.c (copy_sections): Likewise. (compile_object_load): Likewise. * compile/compile-object-run.c (compile_object_run): Likewise. * completer.c (filename_completer): Likewise. * corefile.c (read_memory_typed_address): Likewise. (write_memory_unsigned_integer): Likewise. (write_memory_signed_integer): Likewise. (complete_set_gnutarget): Likewise. * corelow.c (get_core_register_section): Likewise. * cp-name-parser.y (d_grab): Likewise. (allocate_info): Likewise. (cp_new_demangle_parse_info): Likewise. * cp-namespace.c (cp_scan_for_anonymous_namespaces): Likewise. (cp_lookup_symbol_in_namespace): Likewise. (lookup_namespace_scope): Likewise. (find_symbol_in_baseclass): Likewise. (cp_lookup_nested_symbol): Likewise. (cp_lookup_transparent_type_loop): Likewise. * cp-support.c (copy_string_to_obstack): Likewise. (make_symbol_overload_list): Likewise. (make_symbol_overload_list_namespace): Likewise. (make_symbol_overload_list_adl_namespace): Likewise. (first_component_command): Likewise. * cp-valprint.c (cp_print_value): Likewise. * ctf.c (ctf_xfer_partial): Likewise. * d-exp.y (StringExp): Likewise. * d-namespace.c (d_lookup_symbol_in_module): Likewise. (lookup_module_scope): Likewise. (find_symbol_in_baseclass): Likewise. (d_lookup_nested_symbol): Likewise. * dbxread.c (find_stab_function_addr): Likewise. (read_dbx_symtab): Likewise. (dbx_end_psymtab): Likewise. (cp_set_block_scope): Likewise. * dcache.c (dcache_alloc): Likewise. * demangle.c (_initialize_demangler): Likewise. * dicos-tdep.c (dicos_load_module_p): Likewise. * dictionary.c (dict_create_hashed_expandable): Likewise. (dict_create_linear_expandable): Likewise. (expand_hashtable): Likewise. (add_symbol_linear_expandable): Likewise. * dwarf2-frame.c (add_cie): Likewise. (add_fde): Likewise. (dwarf2_build_frame_info): Likewise. * dwarf2expr.c (dwarf_expr_grow_stack): Likewise. (dwarf_expr_fetch_address): Likewise. (add_piece): Likewise. (execute_stack_op): Likewise. * dwarf2loc.c (chain_candidate): Likewise. (dwarf_entry_parameter_to_value): Likewise. (read_pieced_value): Likewise. (write_pieced_value): Likewise. * dwarf2read.c (dwarf2_read_section): Likewise. (add_type_unit): Likewise. (read_comp_units_from_section): Likewise. (fixup_go_packaging): Likewise. (dwarf2_compute_name): Likewise. (dwarf2_physname): Likewise. (create_dwo_unit_in_dwp_v1): Likewise. (create_dwo_unit_in_dwp_v2): Likewise. (read_func_scope): Likewise. (read_call_site_scope): Likewise. (dwarf2_attach_fields_to_type): Likewise. (process_structure_scope): Likewise. (mark_common_block_symbol_computed): Likewise. (read_common_block): Likewise. (abbrev_table_read_table): Likewise. (guess_partial_die_structure_name): Likewise. (fixup_partial_die): Likewise. (add_file_name): Likewise. (dwarf2_const_value_data): Likewise. (dwarf2_const_value_attr): Likewise. (build_error_marker_type): Likewise. (guess_full_die_structure_name): Likewise. (anonymous_struct_prefix): Likewise. (typename_concat): Likewise. (dwarf2_canonicalize_name): Likewise. (dwarf2_name): Likewise. (write_constant_as_bytes): Likewise. (dwarf2_fetch_constant_bytes): Likewise. (copy_string): Likewise. (parse_macro_definition): Likewise. * elfread.c (elf_symfile_segments): Likewise. (elf_rel_plt_read): Likewise. (elf_gnu_ifunc_resolve_by_cache): Likewise. (elf_gnu_ifunc_resolve_by_got): Likewise. (elf_read_minimal_symbols): Likewise. (elf_gnu_ifunc_record_cache): Likewise. * event-top.c (top_level_prompt): Likewise. (command_line_handler): Likewise. * exec.c (resize_section_table): Likewise. * expprint.c (print_subexp_standard): Likewise. * fbsd-tdep.c (fbsd_collect_regset_section_cb): Likewise. * findcmd.c (parse_find_args): Likewise. * findvar.c (address_from_register): Likewise. * frame.c (get_prev_frame_always): Likewise. * gdb_bfd.c (gdb_bfd_ref): Likewise. (get_section_descriptor): Likewise. * gdb_obstack.c (obconcat): Likewise. (obstack_strdup): Likewise. * gdbtypes.c (lookup_function_type_with_arguments): Likewise. (create_set_type): Likewise. (lookup_unsigned_typename): Likewise. (lookup_signed_typename): Likewise. (resolve_dynamic_union): Likewise. (resolve_dynamic_struct): Likewise. (add_dyn_prop): Likewise. (copy_dynamic_prop_list): Likewise. (arch_flags_type): Likewise. (append_composite_type_field_raw): Likewise. * gdbtypes.h (INIT_FUNC_SPECIFIC): Likewise. * gnu-v3-abi.c (gnuv3_rtti_type): Likewise. * go-exp.y (string_exp): Likewise. * go-lang.c (go_demangle): Likewise. * guile/guile.c (compute_scheme_string): Likewise. * guile/scm-cmd.c (gdbscm_parse_command_name): Likewise. (gdbscm_canonicalize_command_name): Likewise. * guile/scm-ports.c (ioscm_init_stdio_buffers): Likewise. (ioscm_init_memory_port): Likewise. (ioscm_reinit_memory_port): Likewise. * guile/scm-utils.c (gdbscm_gc_xstrdup): Likewise. (gdbscm_gc_dup_argv): Likewise. * h8300-tdep.c (h8300_push_dummy_call): Likewise. * hppa-tdep.c (internalize_unwinds): Likewise. (read_unwind_info): Likewise. * i386-cygwin-tdep.c (core_process_module_section): Likewise. (windows_core_xfer_shared_libraries): Likewise. * i386-tdep.c (i386_displaced_step_copy_insn): Likewise. (i386_stap_parse_special_token_triplet): Likewise. (i386_stap_parse_special_token_three_arg_disp): Likewise. * i386obsd-tdep.c (i386obsd_sigtramp_p): Likewise. * inf-child.c (inf_child_fileio_readlink): Likewise. * inf-ptrace.c (inf_ptrace_fetch_register): Likewise. (inf_ptrace_store_register): Likewise. * infrun.c (follow_exec): Likewise. (displaced_step_prepare_throw): Likewise. (save_stop_context): Likewise. (save_infcall_suspend_state): Likewise. * jit.c (jit_read_descriptor): Likewise. (jit_read_code_entry): Likewise. (jit_symtab_line_mapping_add_impl): Likewise. (finalize_symtab): Likewise. (jit_unwind_reg_get_impl): Likewise. * jv-exp.y (QualifiedName): Likewise. * jv-lang.c (get_java_utf8_name): Likewise. (type_from_class): Likewise. (java_demangle_type_signature): Likewise. (java_class_name_from_physname): Likewise. * jv-typeprint.c (java_type_print_base): Likewise. * jv-valprint.c (java_value_print): Likewise. * language.c (add_language): Likewise. * linespec.c (add_sal_to_sals_basic): Likewise. (add_sal_to_sals): Likewise. (decode_objc): Likewise. (find_linespec_symbols): Likewise. * linux-fork.c (fork_save_infrun_state): Likewise. * linux-nat.c (linux_nat_detach): Likewise. (linux_nat_fileio_readlink): Likewise. * linux-record.c (record_linux_sockaddr): Likewise. (record_linux_msghdr): Likewise. (Do): Likewise. * linux-tdep.c (linux_core_info_proc_mappings): Likewise. (linux_collect_regset_section_cb): Likewise. (linux_get_siginfo_data): Likewise. * linux-thread-db.c (try_thread_db_load_from_pdir_1): Likewise. (try_thread_db_load_from_dir): Likewise. (thread_db_load_search): Likewise. (info_auto_load_libthread_db): Likewise. * m32c-tdep.c (m32c_m16c_address_to_pointer): Likewise. (m32c_m16c_pointer_to_address): Likewise. * m68hc11-tdep.c (m68hc11_pseudo_register_write): Likewise. * m68k-tdep.c (m68k_get_longjmp_target): Likewise. * machoread.c (macho_check_dsym): Likewise. * macroexp.c (resize_buffer): Likewise. (gather_arguments): Likewise. (maybe_expand): Likewise. * macrotab.c (new_macro_key): Likewise. (new_source_file): Likewise. (new_macro_definition): Likewise. * mdebugread.c (parse_symbol): Likewise. (parse_type): Likewise. (parse_partial_symbols): Likewise. (psymtab_to_symtab_1): Likewise. * mem-break.c (default_memory_insert_breakpoint): Likewise. * mi/mi-cmd-break.c (mi_argv_to_format): Likewise. * mi/mi-main.c (mi_cmd_data_read_memory): Likewise. (mi_cmd_data_read_memory_bytes): Likewise. (mi_cmd_data_write_memory_bytes): Likewise. (mi_cmd_trace_frame_collected): Likewise. * mi/mi-parse.c (mi_parse_argv): Likewise. (mi_parse): Likewise. * minidebug.c (lzma_open): Likewise. (lzma_pread): Likewise. * mips-tdep.c (mips_read_fp_register_single): Likewise. (mips_print_fp_register): Likewise. * mipsnbsd-tdep.c (mipsnbsd_get_longjmp_target): Likewise. * mipsread.c (read_alphacoff_dynamic_symtab): Likewise. * mt-tdep.c (mt_register_name): Likewise. (mt_registers_info): Likewise. (mt_push_dummy_call): Likewise. * namespace.c (add_using_directive): Likewise. * nat/linux-btrace.c (perf_event_read): Likewise. (linux_enable_bts): Likewise. * nat/linux-osdata.c (linux_common_core_of_thread): Likewise. * nat/linux-ptrace.c (linux_ptrace_test_ret_to_nx): Likewise. * nto-tdep.c (nto_find_and_open_solib): Likewise. (nto_parse_redirection): Likewise. * objc-lang.c (objc_demangle): Likewise. (find_methods): Likewise. * objfiles.c (get_objfile_bfd_data): Likewise. (set_objfile_main_name): Likewise. (allocate_objfile): Likewise. (objfile_relocate): Likewise. (update_section_map): Likewise. * osabi.c (generic_elf_osabi_sniff_abi_tag_sections): Likewise. * p-exp.y (exp): Likewise. (yylex): Likewise. * p-valprint.c (pascal_object_print_value): Likewise. * parse.c (initialize_expout): Likewise. (mark_completion_tag): Likewise. (copy_name): Likewise. (parse_float): Likewise. (type_stack_reserve): Likewise. * ppc-linux-tdep.c (ppc_stap_parse_special_token): Likewise. (ppu2spu_prev_register): Likewise. * ppc-ravenscar-thread.c (supply_register_at_address): Likewise. * printcmd.c (printf_wide_c_string): Likewise. (printf_pointer): Likewise. * probe.c (parse_probes): Likewise. * python/py-cmd.c (gdbpy_parse_command_name): Likewise. (cmdpy_init): Likewise. * python/py-gdb-readline.c (gdbpy_readline_wrapper): Likewise. * python/py-symtab.c (set_sal): Likewise. * python/py-unwind.c (pyuw_sniffer): Likewise. * python/python.c (python_interactive_command): Likewise. (compute_python_string): Likewise. * ravenscar-thread.c (get_running_thread_id): Likewise. * record-full.c (record_full_exec_insn): Likewise. (record_full_core_open_1): Likewise. * regcache.c (regcache_raw_read_signed): Likewise. (regcache_raw_read_unsigned): Likewise. (regcache_cooked_read_signed): Likewise. (regcache_cooked_read_unsigned): Likewise. * remote-fileio.c (remote_fileio_func_open): Likewise. (remote_fileio_func_rename): Likewise. (remote_fileio_func_unlink): Likewise. (remote_fileio_func_stat): Likewise. (remote_fileio_func_system): Likewise. * remote-mips.c (mips_xfer_memory): Likewise. (mips_load_srec): Likewise. (pmon_end_download): Likewise. * remote.c (new_remote_state): Likewise. (map_regcache_remote_table): Likewise. (remote_register_number_and_offset): Likewise. (init_remote_state): Likewise. (get_memory_packet_size): Likewise. (remote_pass_signals): Likewise. (remote_program_signals): Likewise. (remote_start_remote): Likewise. (remote_check_symbols): Likewise. (remote_query_supported): Likewise. (extended_remote_attach): Likewise. (process_g_packet): Likewise. (store_registers_using_G): Likewise. (putpkt_binary): Likewise. (read_frame): Likewise. (compare_sections_command): Likewise. (remote_hostio_pread): Likewise. (remote_hostio_readlink): Likewise. (remote_file_put): Likewise. (remote_file_get): Likewise. (remote_pid_to_exec_file): Likewise. (_initialize_remote): Likewise. * rs6000-aix-tdep.c (rs6000_aix_ld_info_to_xml): Likewise. (rs6000_aix_core_xfer_shared_libraries_aix): Likewise. * rs6000-tdep.c (ppc_displaced_step_copy_insn): Likewise. (bfd_uses_spe_extensions): Likewise. * s390-linux-tdep.c (s390_displaced_step_copy_insn): Likewise. * score-tdep.c (score7_malloc_and_get_memblock): Likewise. * solib-dsbt.c (decode_loadmap): Likewise. (fetch_loadmap): Likewise. (scan_dyntag): Likewise. (enable_break): Likewise. (dsbt_relocate_main_executable): Likewise. * solib-frv.c (fetch_loadmap): Likewise. (enable_break2): Likewise. (frv_relocate_main_executable): Likewise. * solib-spu.c (spu_relocate_main_executable): Likewise. (spu_bfd_open): Likewise. * solib-svr4.c (lm_info_read): Likewise. (read_program_header): Likewise. (find_program_interpreter): Likewise. (scan_dyntag): Likewise. (elf_locate_base): Likewise. (open_symbol_file_object): Likewise. (read_program_headers_from_bfd): Likewise. (svr4_relocate_main_executable): Likewise. * solib-target.c (solib_target_relocate_section_addresses): Likewise. * solib.c (solib_find_1): Likewise. (exec_file_find): Likewise. (solib_find): Likewise. * source.c (openp): Likewise. (print_source_lines_base): Likewise. (forward_search_command): Likewise. * sparc-ravenscar-thread.c (supply_register_at_address): Likewise. * spu-tdep.c (spu2ppu_prev_register): Likewise. (spu_get_overlay_table): Likewise. * stabsread.c (patch_block_stabs): Likewise. (define_symbol): Likewise. (again:): Likewise. (read_member_functions): Likewise. (read_one_struct_field): Likewise. (read_enum_type): Likewise. (common_block_start): Likewise. * stack.c (read_frame_arg): Likewise. (backtrace_command): Likewise. * stap-probe.c (stap_parse_register_operand): Likewise. * symfile.c (syms_from_objfile_1): Likewise. (find_separate_debug_file): Likewise. (load_command): Likewise. (load_progress): Likewise. (load_section_callback): Likewise. (reread_symbols): Likewise. (add_filename_language): Likewise. (allocate_compunit_symtab): Likewise. (read_target_long_array): Likewise. (simple_read_overlay_table): Likewise. * symtab.c (symbol_set_names): Likewise. (resize_symbol_cache): Likewise. (rbreak_command): Likewise. (completion_list_add_name): Likewise. (completion_list_objc_symbol): Likewise. (add_filename_to_list): Likewise. * target-descriptions.c (maint_print_c_tdesc_cmd): Likewise. * target-memory.c (target_write_memory_blocks): Likewise. * target.c (target_read_string): Likewise. (read_whatever_is_readable): Likewise. (target_read_alloc_1): Likewise. (simple_search_memory): Likewise. (target_fileio_read_alloc_1): Likewise. * tilegx-tdep.c (tilegx_push_dummy_call): Likewise. * top.c (command_line_input): Likewise. * tracefile-tfile.c (tfile_fetch_registers): Likewise. * tracefile.c (tracefile_fetch_registers): Likewise. * tracepoint.c (add_memrange): Likewise. (init_collection_list): Likewise. (add_aexpr): Likewise. (trace_dump_actions): Likewise. (parse_trace_status): Likewise. (parse_tracepoint_definition): Likewise. (parse_tsv_definition): Likewise. (parse_static_tracepoint_marker_definition): Likewise. * tui/tui-file.c (tui_sfileopen): Likewise. (tui_file_adjust_strbuf): Likewise. * tui/tui-io.c (tui_expand_tabs): Likewise. * tui/tui-source.c (tui_set_source_content): Likewise. * typeprint.c (find_global_typedef): Likewise. * ui-file.c (do_ui_file_xstrdup): Likewise. (ui_file_obsavestring): Likewise. (mem_file_write): Likewise. * utils.c (make_hex_string): Likewise. (get_regcomp_error): Likewise. (puts_filtered_tabular): Likewise. (gdb_realpath_keepfile): Likewise. (ldirname): Likewise. (gdb_bfd_errmsg): Likewise. (substitute_path_component): Likewise. * valops.c (search_struct_method): Likewise. (find_oload_champ_namespace_loop): Likewise. * valprint.c (print_decimal_chars): Likewise. (read_string): Likewise. (generic_emit_char): Likewise. * varobj.c (varobj_delete): Likewise. (varobj_value_get_print_value): Likewise. * vaxobsd-tdep.c (vaxobsd_sigtramp_sniffer): Likewise. * windows-tdep.c (display_one_tib): Likewise. * xcoffread.c (read_xcoff_symtab): Likewise. (process_xcoff_symbol): Likewise. (swap_sym): Likewise. (scan_xcoff_symtab): Likewise. (xcoff_initial_scan): Likewise. * xml-support.c (gdb_xml_end_element): Likewise. (xml_process_xincludes): Likewise. (xml_fetch_content_from_file): Likewise. * xml-syscall.c (xml_list_of_syscalls): Likewise. * xstormy16-tdep.c (xstormy16_push_dummy_call): Likewise. gdb/gdbserver/ChangeLog: * ax.c (gdb_parse_agent_expr): Add cast to allocation result assignment. (gdb_unparse_agent_expr): Likewise. * hostio.c (require_data): Likewise. (handle_pread): Likewise. * linux-low.c (disable_regset): Likewise. (fetch_register): Likewise. (store_register): Likewise. (get_dynamic): Likewise. (linux_qxfer_libraries_svr4): Likewise. * mem-break.c (delete_fast_tracepoint_jump): Likewise. (set_fast_tracepoint_jump): Likewise. (uninsert_fast_tracepoint_jumps_at): Likewise. (reinsert_fast_tracepoint_jumps_at): Likewise. (validate_inserted_breakpoint): Likewise. (clone_agent_expr): Likewise. * regcache.c (init_register_cache): Likewise. * remote-utils.c (putpkt_binary_1): Likewise. (decode_M_packet): Likewise. (decode_X_packet): Likewise. (look_up_one_symbol): Likewise. (relocate_instruction): Likewise. (monitor_output): Likewise. * server.c (handle_search_memory): Likewise. (handle_qxfer_exec_file): Likewise. (handle_qxfer_libraries): Likewise. (handle_qxfer): Likewise. (handle_query): Likewise. (handle_v_cont): Likewise. (handle_v_run): Likewise. (captured_main): Likewise. * target.c (write_inferior_memory): Likewise. * thread-db.c (try_thread_db_load_from_dir): Likewise. * tracepoint.c (init_trace_buffer): Likewise. (add_tracepoint_action): Likewise. (add_traceframe): Likewise. (add_traceframe_block): Likewise. (cmd_qtdpsrc): Likewise. (cmd_qtdv): Likewise. (cmd_qtstatus): Likewise. (response_source): Likewise. (response_tsv): Likewise. (cmd_qtnotes): Likewise. (gdb_collect): Likewise. (initialize_tracepoint): Likewise.
2018 lines
52 KiB
C
2018 lines
52 KiB
C
/* Memory breakpoint operations for the remote server for GDB.
|
|
Copyright (C) 2002-2015 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 "server.h"
|
|
#include "regcache.h"
|
|
#include "ax.h"
|
|
const unsigned char *breakpoint_data;
|
|
int breakpoint_len;
|
|
|
|
#define MAX_BREAKPOINT_LEN 8
|
|
|
|
/* Helper macro used in loops that append multiple items to a singly-linked
|
|
list instead of inserting items at the head of the list, as, say, in the
|
|
breakpoint lists. LISTPP is a pointer to the pointer that is the head of
|
|
the new list. ITEMP is a pointer to the item to be added to the list.
|
|
TAILP must be defined to be the same type as ITEMP, and initialized to
|
|
NULL. */
|
|
|
|
#define APPEND_TO_LIST(listpp, itemp, tailp) \
|
|
do \
|
|
{ \
|
|
if ((tailp) == NULL) \
|
|
*(listpp) = (itemp); \
|
|
else \
|
|
(tailp)->next = (itemp); \
|
|
(tailp) = (itemp); \
|
|
} \
|
|
while (0)
|
|
|
|
/* GDB will never try to install multiple breakpoints at the same
|
|
address. However, we can see GDB requesting to insert a breakpoint
|
|
at an address is had already inserted one previously in a few
|
|
situations.
|
|
|
|
- The RSP documentation on Z packets says that to avoid potential
|
|
problems with duplicate packets, the operations should be
|
|
implemented in an idempotent way.
|
|
|
|
- A breakpoint is set at ADDR, an address in a shared library.
|
|
Then the shared library is unloaded. And then another, unrelated,
|
|
breakpoint at ADDR is set. There is not breakpoint removal request
|
|
between the first and the second breakpoint.
|
|
|
|
- When GDB wants to update the target-side breakpoint conditions or
|
|
commands, it re-inserts the breakpoint, with updated
|
|
conditions/commands associated.
|
|
|
|
Also, we need to keep track of internal breakpoints too, so we do
|
|
need to be able to install multiple breakpoints at the same address
|
|
transparently.
|
|
|
|
We keep track of two different, and closely related structures. A
|
|
raw breakpoint, which manages the low level, close to the metal
|
|
aspect of a breakpoint. It holds the breakpoint address, and for
|
|
software breakpoints, a buffer holding a copy of the instructions
|
|
that would be in memory had not been a breakpoint there (we call
|
|
that the shadow memory of the breakpoint). We occasionally need to
|
|
temporarilly uninsert a breakpoint without the client knowing about
|
|
it (e.g., to step over an internal breakpoint), so we keep an
|
|
`inserted' state associated with this low level breakpoint
|
|
structure. There can only be one such object for a given address.
|
|
Then, we have (a bit higher level) breakpoints. This structure
|
|
holds a callback to be called whenever a breakpoint is hit, a
|
|
high-level type, and a link to a low level raw breakpoint. There
|
|
can be many high-level breakpoints at the same address, and all of
|
|
them will point to the same raw breakpoint, which is reference
|
|
counted. */
|
|
|
|
/* The low level, physical, raw breakpoint. */
|
|
struct raw_breakpoint
|
|
{
|
|
struct raw_breakpoint *next;
|
|
|
|
/* The low level type of the breakpoint (software breakpoint,
|
|
watchpoint, etc.) */
|
|
enum raw_bkpt_type raw_type;
|
|
|
|
/* A reference count. Each high level breakpoint referencing this
|
|
raw breakpoint accounts for one reference. */
|
|
int refcount;
|
|
|
|
/* The breakpoint's insertion address. There can only be one raw
|
|
breakpoint for a given PC. */
|
|
CORE_ADDR pc;
|
|
|
|
/* The breakpoint's size. */
|
|
int size;
|
|
|
|
/* The breakpoint's shadow memory. */
|
|
unsigned char old_data[MAX_BREAKPOINT_LEN];
|
|
|
|
/* Positive if this breakpoint is currently inserted in the
|
|
inferior. Negative if it was, but we've detected that it's now
|
|
gone. Zero if not inserted. */
|
|
int inserted;
|
|
};
|
|
|
|
/* The type of a breakpoint. */
|
|
enum bkpt_type
|
|
{
|
|
/* A GDB breakpoint, requested with a Z0 packet. */
|
|
gdb_breakpoint_Z0,
|
|
|
|
/* A GDB hardware breakpoint, requested with a Z1 packet. */
|
|
gdb_breakpoint_Z1,
|
|
|
|
/* A GDB write watchpoint, requested with a Z2 packet. */
|
|
gdb_breakpoint_Z2,
|
|
|
|
/* A GDB read watchpoint, requested with a Z3 packet. */
|
|
gdb_breakpoint_Z3,
|
|
|
|
/* A GDB access watchpoint, requested with a Z4 packet. */
|
|
gdb_breakpoint_Z4,
|
|
|
|
/* A basic-software-single-step breakpoint. */
|
|
reinsert_breakpoint,
|
|
|
|
/* Any other breakpoint type that doesn't require specific
|
|
treatment goes here. E.g., an event breakpoint. */
|
|
other_breakpoint,
|
|
};
|
|
|
|
struct point_cond_list
|
|
{
|
|
/* Pointer to the agent expression that is the breakpoint's
|
|
conditional. */
|
|
struct agent_expr *cond;
|
|
|
|
/* Pointer to the next condition. */
|
|
struct point_cond_list *next;
|
|
};
|
|
|
|
struct point_command_list
|
|
{
|
|
/* Pointer to the agent expression that is the breakpoint's
|
|
commands. */
|
|
struct agent_expr *cmd;
|
|
|
|
/* Flag that is true if this command should run even while GDB is
|
|
disconnected. */
|
|
int persistence;
|
|
|
|
/* Pointer to the next command. */
|
|
struct point_command_list *next;
|
|
};
|
|
|
|
/* A high level (in gdbserver's perspective) breakpoint. */
|
|
struct breakpoint
|
|
{
|
|
struct breakpoint *next;
|
|
|
|
/* The breakpoint's type. */
|
|
enum bkpt_type type;
|
|
|
|
/* Pointer to the condition list that should be evaluated on
|
|
the target or NULL if the breakpoint is unconditional or
|
|
if GDB doesn't want us to evaluate the conditionals on the
|
|
target's side. */
|
|
struct point_cond_list *cond_list;
|
|
|
|
/* Point to the list of commands to run when this is hit. */
|
|
struct point_command_list *command_list;
|
|
|
|
/* Link to this breakpoint's raw breakpoint. This is always
|
|
non-NULL. */
|
|
struct raw_breakpoint *raw;
|
|
|
|
/* Function to call when we hit this breakpoint. If it returns 1,
|
|
the breakpoint shall be deleted; 0 or if this callback is NULL,
|
|
it will be left inserted. */
|
|
int (*handler) (CORE_ADDR);
|
|
};
|
|
|
|
/* See mem-break.h. */
|
|
|
|
enum target_hw_bp_type
|
|
raw_bkpt_type_to_target_hw_bp_type (enum raw_bkpt_type raw_type)
|
|
{
|
|
switch (raw_type)
|
|
{
|
|
case raw_bkpt_type_hw:
|
|
return hw_execute;
|
|
case raw_bkpt_type_write_wp:
|
|
return hw_write;
|
|
case raw_bkpt_type_read_wp:
|
|
return hw_read;
|
|
case raw_bkpt_type_access_wp:
|
|
return hw_access;
|
|
default:
|
|
internal_error (__FILE__, __LINE__,
|
|
"bad raw breakpoint type %d", (int) raw_type);
|
|
}
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
static enum bkpt_type
|
|
Z_packet_to_bkpt_type (char z_type)
|
|
{
|
|
gdb_assert ('0' <= z_type && z_type <= '4');
|
|
|
|
return gdb_breakpoint_Z0 + (z_type - '0');
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
enum raw_bkpt_type
|
|
Z_packet_to_raw_bkpt_type (char z_type)
|
|
{
|
|
switch (z_type)
|
|
{
|
|
case Z_PACKET_SW_BP:
|
|
return raw_bkpt_type_sw;
|
|
case Z_PACKET_HW_BP:
|
|
return raw_bkpt_type_hw;
|
|
case Z_PACKET_WRITE_WP:
|
|
return raw_bkpt_type_write_wp;
|
|
case Z_PACKET_READ_WP:
|
|
return raw_bkpt_type_read_wp;
|
|
case Z_PACKET_ACCESS_WP:
|
|
return raw_bkpt_type_access_wp;
|
|
default:
|
|
gdb_assert_not_reached ("unhandled Z packet type.");
|
|
}
|
|
}
|
|
|
|
int
|
|
any_persistent_commands ()
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp;
|
|
struct point_command_list *cl;
|
|
|
|
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
|
|
{
|
|
for (cl = bp->command_list; cl != NULL; cl = cl->next)
|
|
if (cl->persistence)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Find low-level breakpoint of type TYPE at address ADDR that is not
|
|
insert-disabled. Returns NULL if not found. */
|
|
|
|
static struct raw_breakpoint *
|
|
find_enabled_raw_code_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if (bp->pc == addr
|
|
&& bp->raw_type == type
|
|
&& bp->inserted >= 0)
|
|
return bp;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Find low-level breakpoint of type TYPE at address ADDR. Returns
|
|
NULL if not found. */
|
|
|
|
static struct raw_breakpoint *
|
|
find_raw_breakpoint_at (CORE_ADDR addr, enum raw_bkpt_type type, int size)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if (bp->pc == addr && bp->raw_type == type && bp->size == size)
|
|
return bp;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
int
|
|
insert_memory_breakpoint (struct raw_breakpoint *bp)
|
|
{
|
|
unsigned char buf[MAX_BREAKPOINT_LEN];
|
|
int err;
|
|
|
|
if (breakpoint_data == NULL)
|
|
return 1;
|
|
|
|
/* If the architecture treats the size field of Z packets as a
|
|
'kind' field, then we'll need to be able to know which is the
|
|
breakpoint instruction too. */
|
|
if (bp->size != breakpoint_len)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Don't know how to insert breakpoints of size %d.\n",
|
|
bp->size);
|
|
return -1;
|
|
}
|
|
|
|
/* Note that there can be fast tracepoint jumps installed in the
|
|
same memory range, so to get at the original memory, we need to
|
|
use read_inferior_memory, which masks those out. */
|
|
err = read_inferior_memory (bp->pc, buf, breakpoint_len);
|
|
if (err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to read shadow memory of"
|
|
" breakpoint at 0x%s (%s).\n",
|
|
paddress (bp->pc), strerror (err));
|
|
}
|
|
else
|
|
{
|
|
memcpy (bp->old_data, buf, breakpoint_len);
|
|
|
|
err = (*the_target->write_memory) (bp->pc, breakpoint_data,
|
|
breakpoint_len);
|
|
if (err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to insert breakpoint at 0x%s (%s).\n",
|
|
paddress (bp->pc), strerror (err));
|
|
}
|
|
}
|
|
return err != 0 ? -1 : 0;
|
|
}
|
|
|
|
/* See mem-break.h */
|
|
|
|
int
|
|
remove_memory_breakpoint (struct raw_breakpoint *bp)
|
|
{
|
|
unsigned char buf[MAX_BREAKPOINT_LEN];
|
|
int err;
|
|
|
|
/* Since there can be trap breakpoints inserted in the same address
|
|
range, we use `write_inferior_memory', which takes care of
|
|
layering breakpoints on top of fast tracepoints, and on top of
|
|
the buffer we pass it. This works because the caller has already
|
|
either unlinked the breakpoint or marked it uninserted. Also
|
|
note that we need to pass the current shadow contents, because
|
|
write_inferior_memory updates any shadow memory with what we pass
|
|
here, and we want that to be a nop. */
|
|
memcpy (buf, bp->old_data, breakpoint_len);
|
|
err = write_inferior_memory (bp->pc, buf, breakpoint_len);
|
|
if (err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to uninsert raw breakpoint "
|
|
"at 0x%s (%s) while deleting it.\n",
|
|
paddress (bp->pc), strerror (err));
|
|
}
|
|
return err != 0 ? -1 : 0;
|
|
}
|
|
|
|
/* Set a RAW breakpoint of type TYPE and size SIZE at WHERE. On
|
|
success, a pointer to the new breakpoint is returned. On failure,
|
|
returns NULL and writes the error code to *ERR. */
|
|
|
|
static struct raw_breakpoint *
|
|
set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int size,
|
|
int *err)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
if (type == raw_bkpt_type_sw || type == raw_bkpt_type_hw)
|
|
{
|
|
bp = find_enabled_raw_code_breakpoint_at (where, type);
|
|
if (bp != NULL && bp->size != size)
|
|
{
|
|
/* A different size than previously seen. The previous
|
|
breakpoint must be gone then. */
|
|
if (debug_threads)
|
|
debug_printf ("Inconsistent breakpoint size? Was %d, now %d.\n",
|
|
bp->size, size);
|
|
bp->inserted = -1;
|
|
bp = NULL;
|
|
}
|
|
}
|
|
else
|
|
bp = find_raw_breakpoint_at (where, type, size);
|
|
|
|
if (bp != NULL)
|
|
{
|
|
bp->refcount++;
|
|
return bp;
|
|
}
|
|
|
|
bp = XCNEW (struct raw_breakpoint);
|
|
bp->pc = where;
|
|
bp->size = size;
|
|
bp->refcount = 1;
|
|
bp->raw_type = type;
|
|
|
|
*err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp);
|
|
if (*err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n",
|
|
paddress (where), *err);
|
|
free (bp);
|
|
return NULL;
|
|
}
|
|
|
|
bp->inserted = 1;
|
|
/* Link the breakpoint in. */
|
|
bp->next = proc->raw_breakpoints;
|
|
proc->raw_breakpoints = bp;
|
|
return bp;
|
|
}
|
|
|
|
/* Notice that breakpoint traps are always installed on top of fast
|
|
tracepoint jumps. This is even if the fast tracepoint is installed
|
|
at a later time compared to when the breakpoint was installed.
|
|
This means that a stopping breakpoint or tracepoint has higher
|
|
"priority". In turn, this allows having fast and slow tracepoints
|
|
(and breakpoints) at the same address behave correctly. */
|
|
|
|
|
|
/* A fast tracepoint jump. */
|
|
|
|
struct fast_tracepoint_jump
|
|
{
|
|
struct fast_tracepoint_jump *next;
|
|
|
|
/* A reference count. GDB can install more than one fast tracepoint
|
|
at the same address (each with its own action list, for
|
|
example). */
|
|
int refcount;
|
|
|
|
/* The fast tracepoint's insertion address. There can only be one
|
|
of these for a given PC. */
|
|
CORE_ADDR pc;
|
|
|
|
/* Non-zero if this fast tracepoint jump is currently inserted in
|
|
the inferior. */
|
|
int inserted;
|
|
|
|
/* The length of the jump instruction. */
|
|
int length;
|
|
|
|
/* A poor-man's flexible array member, holding both the jump
|
|
instruction to insert, and a copy of the instruction that would
|
|
be in memory had not been a jump there (the shadow memory of the
|
|
tracepoint jump). */
|
|
unsigned char insn_and_shadow[0];
|
|
};
|
|
|
|
/* Fast tracepoint FP's jump instruction to insert. */
|
|
#define fast_tracepoint_jump_insn(fp) \
|
|
((fp)->insn_and_shadow + 0)
|
|
|
|
/* The shadow memory of fast tracepoint jump FP. */
|
|
#define fast_tracepoint_jump_shadow(fp) \
|
|
((fp)->insn_and_shadow + (fp)->length)
|
|
|
|
|
|
/* Return the fast tracepoint jump set at WHERE. */
|
|
|
|
static struct fast_tracepoint_jump *
|
|
find_fast_tracepoint_jump_at (CORE_ADDR where)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct fast_tracepoint_jump *jp;
|
|
|
|
for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next)
|
|
if (jp->pc == where)
|
|
return jp;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
fast_tracepoint_jump_here (CORE_ADDR where)
|
|
{
|
|
struct fast_tracepoint_jump *jp = find_fast_tracepoint_jump_at (where);
|
|
|
|
return (jp != NULL);
|
|
}
|
|
|
|
int
|
|
delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel)
|
|
{
|
|
struct fast_tracepoint_jump *bp, **bp_link;
|
|
int ret;
|
|
struct process_info *proc = current_process ();
|
|
|
|
bp = proc->fast_tracepoint_jumps;
|
|
bp_link = &proc->fast_tracepoint_jumps;
|
|
|
|
while (bp)
|
|
{
|
|
if (bp == todel)
|
|
{
|
|
if (--bp->refcount == 0)
|
|
{
|
|
struct fast_tracepoint_jump *prev_bp_link = *bp_link;
|
|
unsigned char *buf;
|
|
|
|
/* Unlink it. */
|
|
*bp_link = bp->next;
|
|
|
|
/* Since there can be breakpoints inserted in the same
|
|
address range, we use `write_inferior_memory', which
|
|
takes care of layering breakpoints on top of fast
|
|
tracepoints, and on top of the buffer we pass it.
|
|
This works because we've already unlinked the fast
|
|
tracepoint jump above. Also note that we need to
|
|
pass the current shadow contents, because
|
|
write_inferior_memory updates any shadow memory with
|
|
what we pass here, and we want that to be a nop. */
|
|
buf = (unsigned char *) alloca (bp->length);
|
|
memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length);
|
|
ret = write_inferior_memory (bp->pc, buf, bp->length);
|
|
if (ret != 0)
|
|
{
|
|
/* Something went wrong, relink the jump. */
|
|
*bp_link = prev_bp_link;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("Failed to uninsert fast tracepoint jump "
|
|
"at 0x%s (%s) while deleting it.\n",
|
|
paddress (bp->pc), strerror (ret));
|
|
return ret;
|
|
}
|
|
|
|
free (bp);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
bp_link = &bp->next;
|
|
bp = *bp_link;
|
|
}
|
|
}
|
|
|
|
warning ("Could not find fast tracepoint jump in list.");
|
|
return ENOENT;
|
|
}
|
|
|
|
void
|
|
inc_ref_fast_tracepoint_jump (struct fast_tracepoint_jump *jp)
|
|
{
|
|
jp->refcount++;
|
|
}
|
|
|
|
struct fast_tracepoint_jump *
|
|
set_fast_tracepoint_jump (CORE_ADDR where,
|
|
unsigned char *insn, ULONGEST length)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct fast_tracepoint_jump *jp;
|
|
int err;
|
|
unsigned char *buf;
|
|
|
|
/* We refcount fast tracepoint jumps. Check if we already know
|
|
about a jump at this address. */
|
|
jp = find_fast_tracepoint_jump_at (where);
|
|
if (jp != NULL)
|
|
{
|
|
jp->refcount++;
|
|
return jp;
|
|
}
|
|
|
|
/* We don't, so create a new object. Double the length, because the
|
|
flexible array member holds both the jump insn, and the
|
|
shadow. */
|
|
jp = (struct fast_tracepoint_jump *) xcalloc (1, sizeof (*jp) + (length * 2));
|
|
jp->pc = where;
|
|
jp->length = length;
|
|
memcpy (fast_tracepoint_jump_insn (jp), insn, length);
|
|
jp->refcount = 1;
|
|
buf = (unsigned char *) alloca (length);
|
|
|
|
/* Note that there can be trap breakpoints inserted in the same
|
|
address range. To access the original memory contents, we use
|
|
`read_inferior_memory', which masks out breakpoints. */
|
|
err = read_inferior_memory (where, buf, length);
|
|
if (err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to read shadow memory of"
|
|
" fast tracepoint at 0x%s (%s).\n",
|
|
paddress (where), strerror (err));
|
|
free (jp);
|
|
return NULL;
|
|
}
|
|
memcpy (fast_tracepoint_jump_shadow (jp), buf, length);
|
|
|
|
/* Link the jump in. */
|
|
jp->inserted = 1;
|
|
jp->next = proc->fast_tracepoint_jumps;
|
|
proc->fast_tracepoint_jumps = jp;
|
|
|
|
/* Since there can be trap breakpoints inserted in the same address
|
|
range, we use use `write_inferior_memory', which takes care of
|
|
layering breakpoints on top of fast tracepoints, on top of the
|
|
buffer we pass it. This works because we've already linked in
|
|
the fast tracepoint jump above. Also note that we need to pass
|
|
the current shadow contents, because write_inferior_memory
|
|
updates any shadow memory with what we pass here, and we want
|
|
that to be a nop. */
|
|
err = write_inferior_memory (where, buf, length);
|
|
if (err != 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Failed to insert fast tracepoint jump at 0x%s (%s).\n",
|
|
paddress (where), strerror (err));
|
|
|
|
/* Unlink it. */
|
|
proc->fast_tracepoint_jumps = jp->next;
|
|
free (jp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return jp;
|
|
}
|
|
|
|
void
|
|
uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc)
|
|
{
|
|
struct fast_tracepoint_jump *jp;
|
|
int err;
|
|
|
|
jp = find_fast_tracepoint_jump_at (pc);
|
|
if (jp == NULL)
|
|
{
|
|
/* This can happen when we remove all breakpoints while handling
|
|
a step-over. */
|
|
if (debug_threads)
|
|
debug_printf ("Could not find fast tracepoint jump at 0x%s "
|
|
"in list (uninserting).\n",
|
|
paddress (pc));
|
|
return;
|
|
}
|
|
|
|
if (jp->inserted)
|
|
{
|
|
unsigned char *buf;
|
|
|
|
jp->inserted = 0;
|
|
|
|
/* Since there can be trap breakpoints inserted in the same
|
|
address range, we use use `write_inferior_memory', which
|
|
takes care of layering breakpoints on top of fast
|
|
tracepoints, and on top of the buffer we pass it. This works
|
|
because we've already marked the fast tracepoint fast
|
|
tracepoint jump uninserted above. Also note that we need to
|
|
pass the current shadow contents, because
|
|
write_inferior_memory updates any shadow memory with what we
|
|
pass here, and we want that to be a nop. */
|
|
buf = (unsigned char *) alloca (jp->length);
|
|
memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
|
|
err = write_inferior_memory (jp->pc, buf, jp->length);
|
|
if (err != 0)
|
|
{
|
|
jp->inserted = 1;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("Failed to uninsert fast tracepoint jump at"
|
|
" 0x%s (%s).\n",
|
|
paddress (pc), strerror (err));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
reinsert_fast_tracepoint_jumps_at (CORE_ADDR where)
|
|
{
|
|
struct fast_tracepoint_jump *jp;
|
|
int err;
|
|
unsigned char *buf;
|
|
|
|
jp = find_fast_tracepoint_jump_at (where);
|
|
if (jp == NULL)
|
|
{
|
|
/* This can happen when we remove breakpoints when a tracepoint
|
|
hit causes a tracing stop, while handling a step-over. */
|
|
if (debug_threads)
|
|
debug_printf ("Could not find fast tracepoint jump at 0x%s "
|
|
"in list (reinserting).\n",
|
|
paddress (where));
|
|
return;
|
|
}
|
|
|
|
if (jp->inserted)
|
|
error ("Jump already inserted at reinsert time.");
|
|
|
|
jp->inserted = 1;
|
|
|
|
/* Since there can be trap breakpoints inserted in the same address
|
|
range, we use `write_inferior_memory', which takes care of
|
|
layering breakpoints on top of fast tracepoints, and on top of
|
|
the buffer we pass it. This works because we've already marked
|
|
the fast tracepoint jump inserted above. Also note that we need
|
|
to pass the current shadow contents, because
|
|
write_inferior_memory updates any shadow memory with what we pass
|
|
here, and we want that to be a nop. */
|
|
buf = (unsigned char *) alloca (jp->length);
|
|
memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
|
|
err = write_inferior_memory (where, buf, jp->length);
|
|
if (err != 0)
|
|
{
|
|
jp->inserted = 0;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("Failed to reinsert fast tracepoint jump at"
|
|
" 0x%s (%s).\n",
|
|
paddress (where), strerror (err));
|
|
}
|
|
}
|
|
|
|
/* Set a high-level breakpoint of type TYPE, with low level type
|
|
RAW_TYPE and size SIZE, at WHERE. On success, a pointer to the new
|
|
breakpoint is returned. On failure, returns NULL and writes the
|
|
error code to *ERR. HANDLER is called when the breakpoint is hit.
|
|
HANDLER should return 1 if the breakpoint should be deleted, 0
|
|
otherwise. */
|
|
|
|
static struct breakpoint *
|
|
set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type,
|
|
CORE_ADDR where, int size,
|
|
int (*handler) (CORE_ADDR), int *err)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp;
|
|
struct raw_breakpoint *raw;
|
|
|
|
raw = set_raw_breakpoint_at (raw_type, where, size, err);
|
|
|
|
if (raw == NULL)
|
|
{
|
|
/* warn? */
|
|
return NULL;
|
|
}
|
|
|
|
bp = XCNEW (struct breakpoint);
|
|
bp->type = type;
|
|
|
|
bp->raw = raw;
|
|
bp->handler = handler;
|
|
|
|
bp->next = proc->breakpoints;
|
|
proc->breakpoints = bp;
|
|
|
|
return bp;
|
|
}
|
|
|
|
/* See mem-break.h */
|
|
|
|
struct breakpoint *
|
|
set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
|
|
{
|
|
int err_ignored;
|
|
|
|
return set_breakpoint (other_breakpoint, raw_bkpt_type_sw,
|
|
where, breakpoint_len, handler,
|
|
&err_ignored);
|
|
}
|
|
|
|
|
|
static int
|
|
delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel)
|
|
{
|
|
struct raw_breakpoint *bp, **bp_link;
|
|
int ret;
|
|
|
|
bp = proc->raw_breakpoints;
|
|
bp_link = &proc->raw_breakpoints;
|
|
|
|
while (bp)
|
|
{
|
|
if (bp == todel)
|
|
{
|
|
if (bp->inserted > 0)
|
|
{
|
|
struct raw_breakpoint *prev_bp_link = *bp_link;
|
|
|
|
*bp_link = bp->next;
|
|
|
|
ret = the_target->remove_point (bp->raw_type, bp->pc, bp->size,
|
|
bp);
|
|
if (ret != 0)
|
|
{
|
|
/* Something went wrong, relink the breakpoint. */
|
|
*bp_link = prev_bp_link;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("Failed to uninsert raw breakpoint "
|
|
"at 0x%s while deleting it.\n",
|
|
paddress (bp->pc));
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
*bp_link = bp->next;
|
|
|
|
free (bp);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
bp_link = &bp->next;
|
|
bp = *bp_link;
|
|
}
|
|
}
|
|
|
|
warning ("Could not find raw breakpoint in list.");
|
|
return ENOENT;
|
|
}
|
|
|
|
static int
|
|
release_breakpoint (struct process_info *proc, struct breakpoint *bp)
|
|
{
|
|
int newrefcount;
|
|
int ret;
|
|
|
|
newrefcount = bp->raw->refcount - 1;
|
|
if (newrefcount == 0)
|
|
{
|
|
ret = delete_raw_breakpoint (proc, bp->raw);
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
else
|
|
bp->raw->refcount = newrefcount;
|
|
|
|
free (bp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel)
|
|
{
|
|
struct breakpoint *bp, **bp_link;
|
|
int err;
|
|
|
|
bp = proc->breakpoints;
|
|
bp_link = &proc->breakpoints;
|
|
|
|
while (bp)
|
|
{
|
|
if (bp == todel)
|
|
{
|
|
*bp_link = bp->next;
|
|
|
|
err = release_breakpoint (proc, bp);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
bp = *bp_link;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
bp_link = &bp->next;
|
|
bp = *bp_link;
|
|
}
|
|
}
|
|
|
|
warning ("Could not find breakpoint in list.");
|
|
return ENOENT;
|
|
}
|
|
|
|
int
|
|
delete_breakpoint (struct breakpoint *todel)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
return delete_breakpoint_1 (proc, todel);
|
|
}
|
|
|
|
/* Locate a GDB breakpoint of type Z_TYPE and size SIZE placed at
|
|
address ADDR and return a pointer to its structure. If SIZE is -1,
|
|
the breakpoints' sizes are ignored. */
|
|
|
|
static struct breakpoint *
|
|
find_gdb_breakpoint (char z_type, CORE_ADDR addr, int size)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp;
|
|
enum bkpt_type type = Z_packet_to_bkpt_type (z_type);
|
|
|
|
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
|
|
if (bp->type == type && bp->raw->pc == addr
|
|
&& (size == -1 || bp->raw->size == size))
|
|
return bp;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
z_type_supported (char z_type)
|
|
{
|
|
return (z_type >= '0' && z_type <= '4'
|
|
&& the_target->supports_z_point_type != NULL
|
|
&& the_target->supports_z_point_type (z_type));
|
|
}
|
|
|
|
/* Create a new GDB breakpoint of type Z_TYPE at ADDR with size SIZE.
|
|
Returns a pointer to the newly created breakpoint on success. On
|
|
failure returns NULL and sets *ERR to either -1 for error, or 1 if
|
|
Z_TYPE breakpoints are not supported on this target. */
|
|
|
|
static struct breakpoint *
|
|
set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err)
|
|
{
|
|
struct breakpoint *bp;
|
|
enum bkpt_type type;
|
|
enum raw_bkpt_type raw_type;
|
|
|
|
/* If we see GDB inserting a second code breakpoint at the same
|
|
address, then either: GDB is updating the breakpoint's conditions
|
|
or commands; or, the first breakpoint must have disappeared due
|
|
to a shared library unload. On targets where the shared
|
|
libraries are handled by userspace, like SVR4, for example,
|
|
GDBserver can't tell if a library was loaded or unloaded. Since
|
|
we refcount raw breakpoints, we must be careful to make sure GDB
|
|
breakpoints never contribute more than one reference. if we
|
|
didn't do this, in case the previous breakpoint is gone due to a
|
|
shared library unload, we'd just increase the refcount of the
|
|
previous breakpoint at this address, but the trap was not planted
|
|
in the inferior anymore, thus the breakpoint would never be hit.
|
|
Note this must be careful to not create a window where
|
|
breakpoints are removed from the target, for non-stop, in case
|
|
the target can poke at memory while the program is running. */
|
|
if (z_type == Z_PACKET_SW_BP
|
|
|| z_type == Z_PACKET_HW_BP)
|
|
{
|
|
bp = find_gdb_breakpoint (z_type, addr, -1);
|
|
|
|
if (bp != NULL)
|
|
{
|
|
if (bp->raw->size != size)
|
|
{
|
|
/* A different size than previously seen. The previous
|
|
breakpoint must be gone then. */
|
|
bp->raw->inserted = -1;
|
|
delete_breakpoint (bp);
|
|
bp = NULL;
|
|
}
|
|
else if (z_type == Z_PACKET_SW_BP)
|
|
{
|
|
/* Check if the breakpoint is actually gone from the
|
|
target, due to an solib unload, for example. Might
|
|
as well validate _all_ breakpoints. */
|
|
validate_breakpoints ();
|
|
|
|
/* Breakpoints that don't pass validation are
|
|
deleted. */
|
|
bp = find_gdb_breakpoint (z_type, addr, -1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Data breakpoints for the same address but different size are
|
|
expected. GDB doesn't merge these. The backend gets to do
|
|
that if it wants/can. */
|
|
bp = find_gdb_breakpoint (z_type, addr, size);
|
|
}
|
|
|
|
if (bp != NULL)
|
|
{
|
|
/* We already know about this breakpoint, there's nothing else
|
|
to do - GDB's reference is already accounted for. Note that
|
|
whether the breakpoint inserted is left as is - we may be
|
|
stepping over it, for example, in which case we don't want to
|
|
force-reinsert it. */
|
|
return bp;
|
|
}
|
|
|
|
raw_type = Z_packet_to_raw_bkpt_type (z_type);
|
|
type = Z_packet_to_bkpt_type (z_type);
|
|
return set_breakpoint (type, raw_type, addr, size, NULL, err);
|
|
}
|
|
|
|
static int
|
|
check_gdb_bp_preconditions (char z_type, int *err)
|
|
{
|
|
/* As software/memory breakpoints work by poking at memory, we need
|
|
to prepare to access memory. If that operation fails, we need to
|
|
return error. Seeing an error, if this is the first breakpoint
|
|
of that type that GDB tries to insert, GDB would then assume the
|
|
breakpoint type is supported, but it may actually not be. So we
|
|
need to check whether the type is supported at all before
|
|
preparing to access memory. */
|
|
if (!z_type_supported (z_type))
|
|
{
|
|
*err = 1;
|
|
return 0;
|
|
}
|
|
else if (current_thread == NULL)
|
|
{
|
|
*err = -1;
|
|
return 0;
|
|
}
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
/* See mem-break.h. This is a wrapper for set_gdb_breakpoint_1 that
|
|
knows to prepare to access memory for Z0 breakpoints. */
|
|
|
|
struct breakpoint *
|
|
set_gdb_breakpoint (char z_type, CORE_ADDR addr, int size, int *err)
|
|
{
|
|
struct breakpoint *bp;
|
|
|
|
if (!check_gdb_bp_preconditions (z_type, err))
|
|
return NULL;
|
|
|
|
/* If inserting a software/memory breakpoint, need to prepare to
|
|
access memory. */
|
|
if (z_type == Z_PACKET_SW_BP)
|
|
{
|
|
*err = prepare_to_access_memory ();
|
|
if (*err != 0)
|
|
return NULL;
|
|
}
|
|
|
|
bp = set_gdb_breakpoint_1 (z_type, addr, size, err);
|
|
|
|
if (z_type == Z_PACKET_SW_BP)
|
|
done_accessing_memory ();
|
|
|
|
return bp;
|
|
}
|
|
|
|
/* Delete a GDB breakpoint of type Z_TYPE and size SIZE previously
|
|
inserted at ADDR with set_gdb_breakpoint_at. Returns 0 on success,
|
|
-1 on error, and 1 if Z_TYPE breakpoints are not supported on this
|
|
target. */
|
|
|
|
static int
|
|
delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size)
|
|
{
|
|
struct breakpoint *bp;
|
|
int err;
|
|
|
|
bp = find_gdb_breakpoint (z_type, addr, size);
|
|
if (bp == NULL)
|
|
return -1;
|
|
|
|
/* Before deleting the breakpoint, make sure to free its condition
|
|
and command lists. */
|
|
clear_breakpoint_conditions_and_commands (bp);
|
|
err = delete_breakpoint (bp);
|
|
if (err != 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* See mem-break.h. This is a wrapper for delete_gdb_breakpoint that
|
|
knows to prepare to access memory for Z0 breakpoints. */
|
|
|
|
int
|
|
delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int size)
|
|
{
|
|
int ret;
|
|
|
|
if (!check_gdb_bp_preconditions (z_type, &ret))
|
|
return ret;
|
|
|
|
/* If inserting a software/memory breakpoint, need to prepare to
|
|
access memory. */
|
|
if (z_type == Z_PACKET_SW_BP)
|
|
{
|
|
int err;
|
|
|
|
err = prepare_to_access_memory ();
|
|
if (err != 0)
|
|
return -1;
|
|
}
|
|
|
|
ret = delete_gdb_breakpoint_1 (z_type, addr, size);
|
|
|
|
if (z_type == Z_PACKET_SW_BP)
|
|
done_accessing_memory ();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Clear all conditions associated with a breakpoint. */
|
|
|
|
static void
|
|
clear_breakpoint_conditions (struct breakpoint *bp)
|
|
{
|
|
struct point_cond_list *cond;
|
|
|
|
if (bp->cond_list == NULL)
|
|
return;
|
|
|
|
cond = bp->cond_list;
|
|
|
|
while (cond != NULL)
|
|
{
|
|
struct point_cond_list *cond_next;
|
|
|
|
cond_next = cond->next;
|
|
gdb_free_agent_expr (cond->cond);
|
|
free (cond);
|
|
cond = cond_next;
|
|
}
|
|
|
|
bp->cond_list = NULL;
|
|
}
|
|
|
|
/* Clear all commands associated with a breakpoint. */
|
|
|
|
static void
|
|
clear_breakpoint_commands (struct breakpoint *bp)
|
|
{
|
|
struct point_command_list *cmd;
|
|
|
|
if (bp->command_list == NULL)
|
|
return;
|
|
|
|
cmd = bp->command_list;
|
|
|
|
while (cmd != NULL)
|
|
{
|
|
struct point_command_list *cmd_next;
|
|
|
|
cmd_next = cmd->next;
|
|
gdb_free_agent_expr (cmd->cmd);
|
|
free (cmd);
|
|
cmd = cmd_next;
|
|
}
|
|
|
|
bp->command_list = NULL;
|
|
}
|
|
|
|
void
|
|
clear_breakpoint_conditions_and_commands (struct breakpoint *bp)
|
|
{
|
|
clear_breakpoint_conditions (bp);
|
|
clear_breakpoint_commands (bp);
|
|
}
|
|
|
|
/* Add condition CONDITION to GDBserver's breakpoint BP. */
|
|
|
|
static void
|
|
add_condition_to_breakpoint (struct breakpoint *bp,
|
|
struct agent_expr *condition)
|
|
{
|
|
struct point_cond_list *new_cond;
|
|
|
|
/* Create new condition. */
|
|
new_cond = XCNEW (struct point_cond_list);
|
|
new_cond->cond = condition;
|
|
|
|
/* Add condition to the list. */
|
|
new_cond->next = bp->cond_list;
|
|
bp->cond_list = new_cond;
|
|
}
|
|
|
|
/* Add a target-side condition CONDITION to a breakpoint. */
|
|
|
|
int
|
|
add_breakpoint_condition (struct breakpoint *bp, char **condition)
|
|
{
|
|
char *actparm = *condition;
|
|
struct agent_expr *cond;
|
|
|
|
if (condition == NULL)
|
|
return 1;
|
|
|
|
if (bp == NULL)
|
|
return 0;
|
|
|
|
cond = gdb_parse_agent_expr (&actparm);
|
|
|
|
if (cond == NULL)
|
|
{
|
|
fprintf (stderr, "Condition evaluation failed. "
|
|
"Assuming unconditional.\n");
|
|
return 0;
|
|
}
|
|
|
|
add_condition_to_breakpoint (bp, cond);
|
|
|
|
*condition = actparm;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Evaluate condition (if any) at breakpoint BP. Return 1 if
|
|
true and 0 otherwise. */
|
|
|
|
static int
|
|
gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
|
|
{
|
|
/* Fetch registers for the current inferior. */
|
|
struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
|
|
ULONGEST value = 0;
|
|
struct point_cond_list *cl;
|
|
int err = 0;
|
|
struct eval_agent_expr_context ctx;
|
|
|
|
if (bp == NULL)
|
|
return 0;
|
|
|
|
/* Check if the breakpoint is unconditional. If it is,
|
|
the condition always evaluates to TRUE. */
|
|
if (bp->cond_list == NULL)
|
|
return 1;
|
|
|
|
ctx.regcache = get_thread_regcache (current_thread, 1);
|
|
ctx.tframe = NULL;
|
|
ctx.tpoint = NULL;
|
|
|
|
/* Evaluate each condition in the breakpoint's list of conditions.
|
|
Return true if any of the conditions evaluates to TRUE.
|
|
|
|
If we failed to evaluate the expression, TRUE is returned. This
|
|
forces GDB to reevaluate the conditions. */
|
|
for (cl = bp->cond_list;
|
|
cl && !value && !err; cl = cl->next)
|
|
{
|
|
/* Evaluate the condition. */
|
|
err = gdb_eval_agent_expr (&ctx, cl->cond, &value);
|
|
}
|
|
|
|
if (err)
|
|
return 1;
|
|
|
|
return (value != 0);
|
|
}
|
|
|
|
int
|
|
gdb_condition_true_at_breakpoint (CORE_ADDR where)
|
|
{
|
|
/* Only check code (software or hardware) breakpoints. */
|
|
return (gdb_condition_true_at_breakpoint_z_type (Z_PACKET_SW_BP, where)
|
|
|| gdb_condition_true_at_breakpoint_z_type (Z_PACKET_HW_BP, where));
|
|
}
|
|
|
|
/* Add commands COMMANDS to GDBserver's breakpoint BP. */
|
|
|
|
void
|
|
add_commands_to_breakpoint (struct breakpoint *bp,
|
|
struct agent_expr *commands, int persist)
|
|
{
|
|
struct point_command_list *new_cmd;
|
|
|
|
/* Create new command. */
|
|
new_cmd = XCNEW (struct point_command_list);
|
|
new_cmd->cmd = commands;
|
|
new_cmd->persistence = persist;
|
|
|
|
/* Add commands to the list. */
|
|
new_cmd->next = bp->command_list;
|
|
bp->command_list = new_cmd;
|
|
}
|
|
|
|
/* Add a target-side command COMMAND to the breakpoint at ADDR. */
|
|
|
|
int
|
|
add_breakpoint_commands (struct breakpoint *bp, char **command,
|
|
int persist)
|
|
{
|
|
char *actparm = *command;
|
|
struct agent_expr *cmd;
|
|
|
|
if (command == NULL)
|
|
return 1;
|
|
|
|
if (bp == NULL)
|
|
return 0;
|
|
|
|
cmd = gdb_parse_agent_expr (&actparm);
|
|
|
|
if (cmd == NULL)
|
|
{
|
|
fprintf (stderr, "Command evaluation failed. "
|
|
"Disabling.\n");
|
|
return 0;
|
|
}
|
|
|
|
add_commands_to_breakpoint (bp, cmd, persist);
|
|
|
|
*command = actparm;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Return true if there are no commands to run at this location,
|
|
which likely means we want to report back to GDB. */
|
|
|
|
static int
|
|
gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
|
|
{
|
|
struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
|
|
|
|
if (bp == NULL)
|
|
return 1;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("at 0x%s, type Z%c, bp command_list is 0x%s\n",
|
|
paddress (addr), z_type,
|
|
phex_nz ((uintptr_t) bp->command_list, 0));
|
|
return (bp->command_list == NULL);
|
|
}
|
|
|
|
/* Return true if there are no commands to run at this location,
|
|
which likely means we want to report back to GDB. */
|
|
|
|
int
|
|
gdb_no_commands_at_breakpoint (CORE_ADDR where)
|
|
{
|
|
/* Only check code (software or hardware) breakpoints. */
|
|
return (gdb_no_commands_at_breakpoint_z_type (Z_PACKET_SW_BP, where)
|
|
&& gdb_no_commands_at_breakpoint_z_type (Z_PACKET_HW_BP, where));
|
|
}
|
|
|
|
/* Run a breakpoint's commands. Returns 0 if there was a problem
|
|
running any command, 1 otherwise. */
|
|
|
|
static int
|
|
run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr)
|
|
{
|
|
/* Fetch registers for the current inferior. */
|
|
struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
|
|
ULONGEST value = 0;
|
|
struct point_command_list *cl;
|
|
int err = 0;
|
|
struct eval_agent_expr_context ctx;
|
|
|
|
if (bp == NULL)
|
|
return 1;
|
|
|
|
ctx.regcache = get_thread_regcache (current_thread, 1);
|
|
ctx.tframe = NULL;
|
|
ctx.tpoint = NULL;
|
|
|
|
for (cl = bp->command_list;
|
|
cl && !value && !err; cl = cl->next)
|
|
{
|
|
/* Run the command. */
|
|
err = gdb_eval_agent_expr (&ctx, cl->cmd, &value);
|
|
|
|
/* If one command has a problem, stop digging the hole deeper. */
|
|
if (err)
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
run_breakpoint_commands (CORE_ADDR where)
|
|
{
|
|
/* Only check code (software or hardware) breakpoints. If one
|
|
command has a problem, stop digging the hole deeper. */
|
|
if (run_breakpoint_commands_z_type (Z_PACKET_SW_BP, where))
|
|
run_breakpoint_commands_z_type (Z_PACKET_HW_BP, where);
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
int
|
|
gdb_breakpoint_here (CORE_ADDR where)
|
|
{
|
|
/* Only check code (software or hardware) breakpoints. */
|
|
return (find_gdb_breakpoint (Z_PACKET_SW_BP, where, -1) != NULL
|
|
|| find_gdb_breakpoint (Z_PACKET_HW_BP, where, -1) != NULL);
|
|
}
|
|
|
|
void
|
|
set_reinsert_breakpoint (CORE_ADDR stop_at)
|
|
{
|
|
struct breakpoint *bp;
|
|
|
|
bp = set_breakpoint_at (stop_at, NULL);
|
|
bp->type = reinsert_breakpoint;
|
|
}
|
|
|
|
void
|
|
delete_reinsert_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp, **bp_link;
|
|
|
|
bp = proc->breakpoints;
|
|
bp_link = &proc->breakpoints;
|
|
|
|
while (bp)
|
|
{
|
|
if (bp->type == reinsert_breakpoint)
|
|
{
|
|
*bp_link = bp->next;
|
|
release_breakpoint (proc, bp);
|
|
bp = *bp_link;
|
|
}
|
|
else
|
|
{
|
|
bp_link = &bp->next;
|
|
bp = *bp_link;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
uninsert_raw_breakpoint (struct raw_breakpoint *bp)
|
|
{
|
|
if (bp->inserted < 0)
|
|
{
|
|
if (debug_threads)
|
|
debug_printf ("Breakpoint at %s is marked insert-disabled.\n",
|
|
paddress (bp->pc));
|
|
}
|
|
else if (bp->inserted > 0)
|
|
{
|
|
int err;
|
|
|
|
bp->inserted = 0;
|
|
|
|
err = the_target->remove_point (bp->raw_type, bp->pc, bp->size, bp);
|
|
if (err != 0)
|
|
{
|
|
bp->inserted = 1;
|
|
|
|
if (debug_threads)
|
|
debug_printf ("Failed to uninsert raw breakpoint at 0x%s.\n",
|
|
paddress (bp->pc));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
uninsert_breakpoints_at (CORE_ADDR pc)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
int found = 0;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& bp->pc == pc)
|
|
{
|
|
found = 1;
|
|
|
|
if (bp->inserted)
|
|
uninsert_raw_breakpoint (bp);
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
/* This can happen when we remove all breakpoints while handling
|
|
a step-over. */
|
|
if (debug_threads)
|
|
debug_printf ("Could not find breakpoint at 0x%s "
|
|
"in list (uninserting).\n",
|
|
paddress (pc));
|
|
}
|
|
}
|
|
|
|
void
|
|
uninsert_all_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& bp->inserted)
|
|
uninsert_raw_breakpoint (bp);
|
|
}
|
|
|
|
static void
|
|
reinsert_raw_breakpoint (struct raw_breakpoint *bp)
|
|
{
|
|
int err;
|
|
|
|
if (bp->inserted)
|
|
error ("Breakpoint already inserted at reinsert time.");
|
|
|
|
err = the_target->insert_point (bp->raw_type, bp->pc, bp->size, bp);
|
|
if (err == 0)
|
|
bp->inserted = 1;
|
|
else if (debug_threads)
|
|
debug_printf ("Failed to reinsert breakpoint at 0x%s (%d).\n",
|
|
paddress (bp->pc), err);
|
|
}
|
|
|
|
void
|
|
reinsert_breakpoints_at (CORE_ADDR pc)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
int found = 0;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& bp->pc == pc)
|
|
{
|
|
found = 1;
|
|
|
|
reinsert_raw_breakpoint (bp);
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
/* This can happen when we remove all breakpoints while handling
|
|
a step-over. */
|
|
if (debug_threads)
|
|
debug_printf ("Could not find raw breakpoint at 0x%s "
|
|
"in list (reinserting).\n",
|
|
paddress (pc));
|
|
}
|
|
}
|
|
|
|
void
|
|
reinsert_all_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& !bp->inserted)
|
|
reinsert_raw_breakpoint (bp);
|
|
}
|
|
|
|
void
|
|
check_breakpoints (CORE_ADDR stop_pc)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp, **bp_link;
|
|
|
|
bp = proc->breakpoints;
|
|
bp_link = &proc->breakpoints;
|
|
|
|
while (bp)
|
|
{
|
|
struct raw_breakpoint *raw = bp->raw;
|
|
|
|
if ((raw->raw_type == raw_bkpt_type_sw
|
|
|| raw->raw_type == raw_bkpt_type_hw)
|
|
&& raw->pc == stop_pc)
|
|
{
|
|
if (!raw->inserted)
|
|
{
|
|
warning ("Hit a removed breakpoint?");
|
|
return;
|
|
}
|
|
|
|
if (bp->handler != NULL && (*bp->handler) (stop_pc))
|
|
{
|
|
*bp_link = bp->next;
|
|
|
|
release_breakpoint (proc, bp);
|
|
|
|
bp = *bp_link;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
bp_link = &bp->next;
|
|
bp = *bp_link;
|
|
}
|
|
}
|
|
|
|
void
|
|
set_breakpoint_data (const unsigned char *bp_data, int bp_len)
|
|
{
|
|
breakpoint_data = bp_data;
|
|
breakpoint_len = bp_len;
|
|
}
|
|
|
|
int
|
|
breakpoint_here (CORE_ADDR addr)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& bp->pc == addr)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
breakpoint_inserted_here (CORE_ADDR addr)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if ((bp->raw_type == raw_bkpt_type_sw
|
|
|| bp->raw_type == raw_bkpt_type_hw)
|
|
&& bp->pc == addr
|
|
&& bp->inserted)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
int
|
|
software_breakpoint_inserted_here (CORE_ADDR addr)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if (bp->raw_type == raw_bkpt_type_sw
|
|
&& bp->pc == addr
|
|
&& bp->inserted)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* See mem-break.h. */
|
|
|
|
int
|
|
hardware_breakpoint_inserted_here (CORE_ADDR addr)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp;
|
|
|
|
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
|
|
if (bp->raw_type == raw_bkpt_type_hw
|
|
&& bp->pc == addr
|
|
&& bp->inserted)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
validate_inserted_breakpoint (struct raw_breakpoint *bp)
|
|
{
|
|
unsigned char *buf;
|
|
int err;
|
|
|
|
gdb_assert (bp->inserted);
|
|
gdb_assert (bp->raw_type == raw_bkpt_type_sw);
|
|
|
|
buf = (unsigned char *) alloca (breakpoint_len);
|
|
err = (*the_target->read_memory) (bp->pc, buf, breakpoint_len);
|
|
if (err || memcmp (buf, breakpoint_data, breakpoint_len) != 0)
|
|
{
|
|
/* Tag it as gone. */
|
|
bp->inserted = -1;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
delete_disabled_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp, *next;
|
|
|
|
for (bp = proc->breakpoints; bp != NULL; bp = next)
|
|
{
|
|
next = bp->next;
|
|
if (bp->raw->inserted < 0)
|
|
delete_breakpoint_1 (proc, bp);
|
|
}
|
|
}
|
|
|
|
/* Check if breakpoints we inserted still appear to be inserted. They
|
|
may disappear due to a shared library unload, and worse, a new
|
|
shared library may be reloaded at the same address as the
|
|
previously unloaded one. If that happens, we should make sure that
|
|
the shadow memory of the old breakpoints isn't used when reading or
|
|
writing memory. */
|
|
|
|
void
|
|
validate_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct breakpoint *bp;
|
|
|
|
for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
|
|
{
|
|
struct raw_breakpoint *raw = bp->raw;
|
|
|
|
if (raw->raw_type == raw_bkpt_type_sw && raw->inserted > 0)
|
|
validate_inserted_breakpoint (raw);
|
|
}
|
|
|
|
delete_disabled_breakpoints ();
|
|
}
|
|
|
|
void
|
|
check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp = proc->raw_breakpoints;
|
|
struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps;
|
|
CORE_ADDR mem_end = mem_addr + mem_len;
|
|
int disabled_one = 0;
|
|
|
|
for (; jp != NULL; jp = jp->next)
|
|
{
|
|
CORE_ADDR bp_end = jp->pc + jp->length;
|
|
CORE_ADDR start, end;
|
|
int copy_offset, copy_len, buf_offset;
|
|
|
|
gdb_assert (fast_tracepoint_jump_shadow (jp) >= buf + mem_len
|
|
|| buf >= fast_tracepoint_jump_shadow (jp) + (jp)->length);
|
|
|
|
if (mem_addr >= bp_end)
|
|
continue;
|
|
if (jp->pc >= mem_end)
|
|
continue;
|
|
|
|
start = jp->pc;
|
|
if (mem_addr > start)
|
|
start = mem_addr;
|
|
|
|
end = bp_end;
|
|
if (end > mem_end)
|
|
end = mem_end;
|
|
|
|
copy_len = end - start;
|
|
copy_offset = start - jp->pc;
|
|
buf_offset = start - mem_addr;
|
|
|
|
if (jp->inserted)
|
|
memcpy (buf + buf_offset,
|
|
fast_tracepoint_jump_shadow (jp) + copy_offset,
|
|
copy_len);
|
|
}
|
|
|
|
for (; bp != NULL; bp = bp->next)
|
|
{
|
|
CORE_ADDR bp_end = bp->pc + breakpoint_len;
|
|
CORE_ADDR start, end;
|
|
int copy_offset, copy_len, buf_offset;
|
|
|
|
if (bp->raw_type != raw_bkpt_type_sw)
|
|
continue;
|
|
|
|
gdb_assert (bp->old_data >= buf + mem_len
|
|
|| buf >= &bp->old_data[sizeof (bp->old_data)]);
|
|
|
|
if (mem_addr >= bp_end)
|
|
continue;
|
|
if (bp->pc >= mem_end)
|
|
continue;
|
|
|
|
start = bp->pc;
|
|
if (mem_addr > start)
|
|
start = mem_addr;
|
|
|
|
end = bp_end;
|
|
if (end > mem_end)
|
|
end = mem_end;
|
|
|
|
copy_len = end - start;
|
|
copy_offset = start - bp->pc;
|
|
buf_offset = start - mem_addr;
|
|
|
|
if (bp->inserted > 0)
|
|
{
|
|
if (validate_inserted_breakpoint (bp))
|
|
memcpy (buf + buf_offset, bp->old_data + copy_offset, copy_len);
|
|
else
|
|
disabled_one = 1;
|
|
}
|
|
}
|
|
|
|
if (disabled_one)
|
|
delete_disabled_breakpoints ();
|
|
}
|
|
|
|
void
|
|
check_mem_write (CORE_ADDR mem_addr, unsigned char *buf,
|
|
const unsigned char *myaddr, int mem_len)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
struct raw_breakpoint *bp = proc->raw_breakpoints;
|
|
struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps;
|
|
CORE_ADDR mem_end = mem_addr + mem_len;
|
|
int disabled_one = 0;
|
|
|
|
/* First fast tracepoint jumps, then breakpoint traps on top. */
|
|
|
|
for (; jp != NULL; jp = jp->next)
|
|
{
|
|
CORE_ADDR jp_end = jp->pc + jp->length;
|
|
CORE_ADDR start, end;
|
|
int copy_offset, copy_len, buf_offset;
|
|
|
|
gdb_assert (fast_tracepoint_jump_shadow (jp) >= myaddr + mem_len
|
|
|| myaddr >= fast_tracepoint_jump_shadow (jp) + (jp)->length);
|
|
gdb_assert (fast_tracepoint_jump_insn (jp) >= buf + mem_len
|
|
|| buf >= fast_tracepoint_jump_insn (jp) + (jp)->length);
|
|
|
|
if (mem_addr >= jp_end)
|
|
continue;
|
|
if (jp->pc >= mem_end)
|
|
continue;
|
|
|
|
start = jp->pc;
|
|
if (mem_addr > start)
|
|
start = mem_addr;
|
|
|
|
end = jp_end;
|
|
if (end > mem_end)
|
|
end = mem_end;
|
|
|
|
copy_len = end - start;
|
|
copy_offset = start - jp->pc;
|
|
buf_offset = start - mem_addr;
|
|
|
|
memcpy (fast_tracepoint_jump_shadow (jp) + copy_offset,
|
|
myaddr + buf_offset, copy_len);
|
|
if (jp->inserted)
|
|
memcpy (buf + buf_offset,
|
|
fast_tracepoint_jump_insn (jp) + copy_offset, copy_len);
|
|
}
|
|
|
|
for (; bp != NULL; bp = bp->next)
|
|
{
|
|
CORE_ADDR bp_end = bp->pc + breakpoint_len;
|
|
CORE_ADDR start, end;
|
|
int copy_offset, copy_len, buf_offset;
|
|
|
|
if (bp->raw_type != raw_bkpt_type_sw)
|
|
continue;
|
|
|
|
gdb_assert (bp->old_data >= myaddr + mem_len
|
|
|| myaddr >= &bp->old_data[sizeof (bp->old_data)]);
|
|
|
|
if (mem_addr >= bp_end)
|
|
continue;
|
|
if (bp->pc >= mem_end)
|
|
continue;
|
|
|
|
start = bp->pc;
|
|
if (mem_addr > start)
|
|
start = mem_addr;
|
|
|
|
end = bp_end;
|
|
if (end > mem_end)
|
|
end = mem_end;
|
|
|
|
copy_len = end - start;
|
|
copy_offset = start - bp->pc;
|
|
buf_offset = start - mem_addr;
|
|
|
|
memcpy (bp->old_data + copy_offset, myaddr + buf_offset, copy_len);
|
|
if (bp->inserted > 0)
|
|
{
|
|
if (validate_inserted_breakpoint (bp))
|
|
memcpy (buf + buf_offset, breakpoint_data + copy_offset, copy_len);
|
|
else
|
|
disabled_one = 1;
|
|
}
|
|
}
|
|
|
|
if (disabled_one)
|
|
delete_disabled_breakpoints ();
|
|
}
|
|
|
|
/* Delete all breakpoints, and un-insert them from the inferior. */
|
|
|
|
void
|
|
delete_all_breakpoints (void)
|
|
{
|
|
struct process_info *proc = current_process ();
|
|
|
|
while (proc->breakpoints)
|
|
delete_breakpoint_1 (proc, proc->breakpoints);
|
|
}
|
|
|
|
/* Clear the "inserted" flag in all breakpoints. */
|
|
|
|
void
|
|
mark_breakpoints_out (struct process_info *proc)
|
|
{
|
|
struct raw_breakpoint *raw_bp;
|
|
|
|
for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
|
|
raw_bp->inserted = 0;
|
|
}
|
|
|
|
/* Release all breakpoints, but do not try to un-insert them from the
|
|
inferior. */
|
|
|
|
void
|
|
free_all_breakpoints (struct process_info *proc)
|
|
{
|
|
mark_breakpoints_out (proc);
|
|
|
|
/* Note: use PROC explicitly instead of deferring to
|
|
delete_all_breakpoints --- CURRENT_INFERIOR may already have been
|
|
released when we get here. There should be no call to
|
|
current_process from here on. */
|
|
while (proc->breakpoints)
|
|
delete_breakpoint_1 (proc, proc->breakpoints);
|
|
}
|
|
|
|
/* Clone an agent expression. */
|
|
|
|
static struct agent_expr *
|
|
clone_agent_expr (const struct agent_expr *src_ax)
|
|
{
|
|
struct agent_expr *ax;
|
|
|
|
ax = XCNEW (struct agent_expr);
|
|
ax->length = src_ax->length;
|
|
ax->bytes = (unsigned char *) xcalloc (ax->length, 1);
|
|
memcpy (ax->bytes, src_ax->bytes, ax->length);
|
|
return ax;
|
|
}
|
|
|
|
/* Deep-copy the contents of one breakpoint to another. */
|
|
|
|
static struct breakpoint *
|
|
clone_one_breakpoint (const struct breakpoint *src)
|
|
{
|
|
struct breakpoint *dest;
|
|
struct raw_breakpoint *dest_raw;
|
|
struct point_cond_list *current_cond;
|
|
struct point_cond_list *new_cond;
|
|
struct point_cond_list *cond_tail = NULL;
|
|
struct point_command_list *current_cmd;
|
|
struct point_command_list *new_cmd;
|
|
struct point_command_list *cmd_tail = NULL;
|
|
|
|
/* Clone the raw breakpoint. */
|
|
dest_raw = XCNEW (struct raw_breakpoint);
|
|
dest_raw->raw_type = src->raw->raw_type;
|
|
dest_raw->refcount = src->raw->refcount;
|
|
dest_raw->pc = src->raw->pc;
|
|
dest_raw->size = src->raw->size;
|
|
memcpy (dest_raw->old_data, src->raw->old_data, MAX_BREAKPOINT_LEN);
|
|
dest_raw->inserted = src->raw->inserted;
|
|
|
|
/* Clone the high-level breakpoint. */
|
|
dest = XCNEW (struct breakpoint);
|
|
dest->type = src->type;
|
|
dest->raw = dest_raw;
|
|
dest->handler = src->handler;
|
|
|
|
/* Clone the condition list. */
|
|
for (current_cond = src->cond_list; current_cond != NULL;
|
|
current_cond = current_cond->next)
|
|
{
|
|
new_cond = XCNEW (struct point_cond_list);
|
|
new_cond->cond = clone_agent_expr (current_cond->cond);
|
|
APPEND_TO_LIST (&dest->cond_list, new_cond, cond_tail);
|
|
}
|
|
|
|
/* Clone the command list. */
|
|
for (current_cmd = src->command_list; current_cmd != NULL;
|
|
current_cmd = current_cmd->next)
|
|
{
|
|
new_cmd = XCNEW (struct point_command_list);
|
|
new_cmd->cmd = clone_agent_expr (current_cmd->cmd);
|
|
new_cmd->persistence = current_cmd->persistence;
|
|
APPEND_TO_LIST (&dest->command_list, new_cmd, cmd_tail);
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/* Create a new breakpoint list NEW_LIST that is a copy of the
|
|
list starting at SRC_LIST. Create the corresponding new
|
|
raw_breakpoint list NEW_RAW_LIST as well. */
|
|
|
|
void
|
|
clone_all_breakpoints (struct breakpoint **new_list,
|
|
struct raw_breakpoint **new_raw_list,
|
|
const struct breakpoint *src_list)
|
|
{
|
|
const struct breakpoint *bp;
|
|
struct breakpoint *new_bkpt;
|
|
struct breakpoint *bkpt_tail = NULL;
|
|
struct raw_breakpoint *raw_bkpt_tail = NULL;
|
|
|
|
for (bp = src_list; bp != NULL; bp = bp->next)
|
|
{
|
|
new_bkpt = clone_one_breakpoint (bp);
|
|
APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail);
|
|
APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail);
|
|
}
|
|
}
|