8sa1-binutils-gdb/gdb/guile/scm-breakpoint.c
Simon Marchi 112e8700a6 Class-ify ui_out
This patch finalizes the C++ conversion of the ui-out subsystem, by
turning the ui_out and ui_out_impl structures into a single class
hierarchy.  ui_out functions are turned into virtual methods of that new
class, so as a result there are a lot of call sites to update.

In the previous version of the patchset, there were separate ui_out and
ui_out_impl classes, but it wasn't really useful and added boilerplate.
In this version there is simply an ui_out base class that is
extended for CLI, TUI and MI.

It's a bit hard to maintain a ChangeLog for such a big patch, I did my
best but I'm sure there are some missing or outdated info in there...

gdb/ChangeLog:

    * ui-out.h (ui_out_begin, ui_out_end, ui_out_table_header,
    ui_out_table_body,  ui_out_field_int, ui_out_field_fmt_int,
    ui_out_field_core_addr, ui_out_field_string, ui_out_field_stream,
    ui_out_field_fmt, ui_out_field_skip, ui_out_spaces, ui_out_text,
    ui_out_message, ui_out_wrap_hint, ui_out_flush, ui_out_test_flags,
    ui_out_query_field, ui_out_is_mi_like_p, ui_out_redirect):
    Remove, replace with a method in class ui_out.
    (table_begin_ftype): Remove, replace with pure virtual method in
    class ui_out.
    (table_body_ftype): Likewise.
    (table_end_ftype): Likewise.
    (table_header_ftype): Likewise.
    (ui_out_begin_ftype): Likewise.
    (ui_out_end_ftype): Likewise.
    (field_int_ftype): Likewise.
    (field_skip_ftype): Likewise.
    (field_string_ftype): Likewise.
    (field_fmt_ftype): Likewise.
    (spaces_ftype): Likewise.
    (text_ftype): Likewise.
    (message_ftype): Likewise.
    (wrap_hint_ftype): Likewise.
    (flush_ftype): Likewise.
    (redirect_ftype): Likewise.
    (data_destroy_ftype): Likewise.
    (struct ui_out_impl): Remove, replace with class ui_out.
    (ui_out_new): Remove.
    (class ui_out): New class.
    * ui-out.c (struct ui_out): Remove, replaced with class ui_out.
    (current_level): Remove, replace with ui_out method.
    (push_level): Likewise.
    (pop_level): Likewise.
    (uo_table_begin, uo_table_body, uo_table_end, uo_table_header,
    uo_begin, uo_end, uo_field_int, uo_field_skip, uo_field_fmt,
    uo_spaces, uo_text, uo_message, uo_wrap_hint, uo_flush,
    uo_redirect, uo_field_string): Remove.
    (ui_out_table_begin): Replace with ...
    (ui_out::table_begin): ... this.
    (ui_out_table_body): Replace with ...
    (ui_out::table_body): ... this.
    (ui_out_table_end): Replace with ...
    (ui_out::table_end): ... this.
    (ui_out_table_header): Replace with ...
    (ui_out::table_header): ... this.
    (ui_out_begin): Replace with ...
    (ui_out::begin): ... this.
    (ui_out_end): Replace with ...
    (ui_out::end): ... this.
    (ui_out_field_int): Replace with ...
    (ui_out::field_int): ... this.
    (ui_out_field_fmt_int): Replace with ...
    (ui_out::field_fmt_int): ... this.
    (ui_out_field_core_addr): Replace with ...
    (ui_out::field_core_addr): ... this.
    (ui_out_field_stream): Replace with ...
    (ui_out::field_stream): ... this.
    (ui_out_field_skip): Replace with ...
    (ui_out::field_skip): ... this.
    (ui_out_field_string): Replace with ...
    (ui_out::field_string): ... this.
    (ui_out_field_fmt): Replace with ...
    (ui_out::field_fmt): ... this.
    (ui_out_spaces): Replace with ...
    (ui_out::spaces): ... this.
    (ui_out_text): Replace with ...
    (ui_out::text): ... this.
    (ui_out_message): Replace with ...
    (ui_out::message): ... this.
    (ui_out_wrap_hint): Replace with ...
    (ui_out::wrap_hint): ... this.
    (ui_out_flush): Replace with ...
    (ui_out::flush): ... this.
    (ui_out_redirect): Replace with ...
    (ui_out::redirect): ... this.
    (ui_out_test_flags): Replace with ...
    (ui_out::test_flags): ... this.
    (ui_out_is_mi_like_p): Replace with ...
    (ui_out::is_mi_like_p): ... this.
    (verify_field): Replace with ...
    (ui_out::verify_field): ... this.
    (ui_out_query_field): Replace with ...
    (ui_out::query_table_field): ... this.
    (ui_out_data): Remove.
    (ui_out_new): Remove, replace with ...
    (ui_out::ui_out): ... this constructor.
    (do_cleanup_table_end, make_cleanup_ui_out_tuple_begin_end,
    do_cleanup_end, make_cleanup_ui_out_tuple_begin_end,
    make_cleanup_ui_out_list_begin_end): Update fallouts of struct
    ui_out -> class ui_out change.
    * cli-out.c (cli_out_data): Remove.
    (cli_uiout_dtor): Remove.
    (cli_table_begin): Replace with ...
    (cli_ui_out::do_table_begin): ... this new method.
    (cli_table_body): Replace with ...
    (cli_ui_out::do_table_body): ... this new method.
    (cli_table_end): Replace with ...
    (cli_ui_out::do_table_end): ... this new method.
    (cli_table_header): Replace with ...
    (cli_ui_out::do_table_header): ... this new method.
    (cli_begin): Replace with ...
    (cli_ui_out::do_begin): ... this new method.
    (cli_end): Replace with ...
    (cli_ui_out::do_end): ... this new method.
    (cli_field_int): Replace with ...
    (cli_ui_out::do_field_int): ... this new method.
    (cli_field_skip): Replace with ...
    (cli_ui_out::do_field_skip): ... this new method.
    (cli_field_string): Replace with ...
    (cli_ui_out::do_field_string): ... this new method.
    (cli_field_fmt): Replace with ...
    (cli_ui_out::do_field_fmt): ... this new method.
    (cli_spaces): Replace with ...
    (cli_ui_out::do_spaces): ... this new method.
    (cli_text): Replace with ...
    (cli_ui_out::do_text): ... this new method.
    (cli_message): Replace with ...
    (cli_ui_out::do_message): ... this new method.
    (cli_wrap_hint): Replace with ...
    (cli_ui_out::do_wrap_hint): ... this new method.
    (cli_flush): Replace with ...
    (cli_ui_out::do_flush): ... this new method.
    (cli_redirect): Replace with ...
    (cli_ui_out::do_redirect): ... this new method.
    (out_field_fmt): Replace with ...
    (cli_ui_out::out_field_fmt): ... this new method.
    (field_separator): Replace with ...
    (cli_ui_out::field_separator): ... this new method.
    (cli_out_set_stream): Replace with ...
    (cli_ui_out::set_stream): ... this new method.
    (cli_ui_out_impl): Remove.
    (cli_out_data_ctor): Remove.
    (cli_ui_out_impl::cli_ui_out_impl): New constructor.
    (cli_ui_out_impl::~cli_ui_out_impl): New destructor.
    (cli_out_new): Change return type to cli_ui_out *, instantiate a
    cli_ui_out.
    * cli-out.h (cli_ui_out_data): Remove, replace with class
    cli_ui_out.
    (class cli_ui_out): New class.
    (cli_ui_out_impl): Remove.
    (cli_out_data_ctor): Remove.
    (cli_out_new): Change return type to cli_ui_out*.
    (cli_out_set_stream): Remove.
    * cli/cli-interp.c (struct cli_interp) <cli_uiout>: Change type
    to cli_ui_out*.
    (cli_interpreter_resume): Adapt.
    (cli_interpreter_exec): Adapt.
    * mi/mi-out.c (mi_ui_out_data, mi_out_data): Remove.
    (mi_ui_out_impl): Remove.
    (mi_table_begin): Replace with ...
    (mi_ui_out::do_table_begin): ... this.
    (mi_table_body): Replace with ...
    (mi_ui_out::do_table_body): ... this.
    (mi_table_end): Replace with ...
    (mi_ui_out::do_table_end): ... this.
    (mi_table_header): Replace with ...
    (mi_ui_out::do_table_header): ... this.
    (mi_begin): Replace with ...
    (mi_ui_out::do_begin): ... this.
    (mi_end): Replace with ...
    (mi_ui_out::do_end): ... this.
    (mi_field_int): Replace with ...
    (mi_ui_out::do_field_int): ... this.
    (mi_field_skip): Replace with ...
    (mi_ui_out::do_field_skip): ... this.
    (mi_field_string): Replace with ...
    (mi_ui_out::do_field_string): ... this.
    (mi_field_fmt): Replace with ...
    (mi_ui_out::do_field_fmt): ... this.
    (mi_spaces): Replace with ...
    (mi_ui_out::do_spaces): ... this.
    (mi_text): Replace with ...
    (mi_ui_out::do_text): ... this.
    (mi_message): Replace with ...
    (mi_ui_out::do_message): ... this.
    (mi_wrap_hint): Replace with ...
    (mi_ui_out::do_wrap_hint): ... this.
    (mi_flush): Replace with ...
    (mi_ui_out::do_flush): ... this.
    (mi_redirect): Replace with ...
    (mi_ui_out::do_redirect):
    (field_separator): Replace with ...
    (mi_ui_out::field_separator):
    (mi_open): Replace with ...
    (mi_ui_out::open): ... this.
    (mi_close): Replace with ...
    (mi_ui_out::close): ... this.
    (mi_out_rewind): Replace with ...
    (mi_ui_out::rewind): ... this.
    (mi_out_put): Replace with ...
    (mi_ui_out::put): ... this.
    (mi_version): Replace with ...
    (mi_ui_out::version): ... this.
    (mi_out_data_ctor): Replace with ...
    (mi_ui_out::mi_ui_out): ... this.
    (mi_out_data_dtor): Replace with ...
    (mi_ui_out::~mi_ui_out): ... this.
    (mi_out_new): Change return type to mi_ui_out*, instantiate
    an mi_ui_out object.
    (as_mi_ui_out): New function.
    (mi_version): Update fallouts of struct ui_out to class ui_out
    transition.
    (mi_out_put): Likewise.
    (mi_out_rewind): Likewise.
    * mi/mi-out.h (mi_out_new): Change return type to mi_ui_out*.
    * tui/tui-out.c (tui_ui_out_data, tui_out_data, tui_ui_out_impl):
    Remove.
    (tui_field_int): Replace with ...
    (tui_ui_out::do_field_int): ... this.
    (tui_field_string): Replace with ...
    (tui_ui_out::do_field_string): ... this.
    (tui_field_fmt): Replace with ...
    (tui_ui_out::do_field_fmt): ... this.
    (tui_text): Replace with ...
    (tui_ui_out::do_text): ... this.
    (tui_out_new): Change return type to tui_ui_out*, instantiate
    tui_ui_out object.
    (tui_ui_out::tui_ui_out): New.
    * tui/tui-out.h: New file.
    * tui/tui.h (tui_out_new): Move declaration to tui/tui-out.h.
    * tui/tui-io.c: Include tui/tui-out.h.
    (tui_old_uiout): Change type to cli_ui_out*.
    (tui_setup_io): Use dynamic_cast.
    * tui/tui-io.h (tui_old_uiout): Change type to cli_ui_out*.
    * tui/tui-interp.c (tui_resume): Adapt.
    * ada-lang.c (print_it_exception): Update fallouts of struct
    ui_out to class ui_out transition.
    (print_one_exception): Likewise.
    (print_mention_exception): Likewise.
    * ada-tasks.c (print_ada_task_info): Likewise.
    (info_task): Likewise.
    (task_command): Likewise.
    * auto-load.c (print_script): Likewise.
    (auto_load_info_scripts): Likewise.
    (info_auto_load_cmd): Likewise.
    * break-catch-sig.c (signal_catchpoint_print_one): Likewise.
    * break-catch-syscall.c (print_it_catch_syscall): Likewise.
    (print_one_catch_syscall): Likewise.
    * break-catch-throw.c (print_it_exception_catchpoint): Likewise.
    (print_one_exception_catchpoint): Likewise.
    (print_one_detail_exception_catchpoint): Likewise.
    (print_mention_exception_catchpoint): Likewise.
    * breakpoint.c (maybe_print_thread_hit_breakpoint): Likewise.
    (print_solib_event): Likewise.
    (watchpoint_check): Likewise.
    (wrap_indent_at_field): Likewise.
    (print_breakpoint_location): Likewise.
    (output_thread_groups): Likewise.
    (print_one_breakpoint_location): Likewise.
    (breakpoint_1): Likewise.
    (default_collect_info): Likewise.
    (watchpoints_info): Likewise.
    (print_it_catch_fork): Likewise.
    (print_one_catch_fork): Likewise.
    (print_it_catch_vfork): Likewise.
    (print_one_catch_vfork): Likewise.
    (print_it_catch_solib): Likewise.
    (print_one_catch_solib): Likewise.
    (print_it_catch_exec): Likewise.
    (print_one_catch_exec): Likewise.
    (mention): Likewise.
    (print_it_ranged_breakpoint): Likewise.
    (print_one_ranged_breakpoint): Likewise.
    (print_one_detail_ranged_breakpoint): Likewise.
    (print_mention_ranged_breakpoint): Likewise.
    (print_it_watchpoint): Likewise.
    (print_mention_watchpoint): Likewise.
    (print_it_masked_watchpoint): Likewise.
    (print_one_detail_masked_watchpoint): Likewise.
    (print_mention_masked_watchpoint): Likewise.
    (bkpt_print_it): Likewise.
    (tracepoint_print_one_detail): Likewise.
    (tracepoint_print_mention): Likewise.
    (update_static_tracepoint): Likewise.
    (tracepoints_info): Likewise.
    (save_breakpoints): Likewise.
    * cli/cli-cmds.c (complete_command): Likewise.
    * cli/cli-logging.c (set_logging_redirect): Likewise.
    (pop_output_files): Likewise.
    (handle_redirections): Likewise.
    * cli/cli-script.c (print_command_lines): Likewise.
    * cli/cli-setshow.c (do_show_command): Likewise.
    (cmd_show_list): Likewise.
    * cp-abi.c (list_cp_abis): Likewise.
    (show_cp_abi_cmd): Likewise.
    * darwin-nat-info.c (darwin_debug_regions_recurse): Likewise.
    * disasm.c (gdb_pretty_print_insn): Likewise.
    (do_mixed_source_and_assembly_deprecated): Likewise.
    (do_mixed_source_and_assembly): Likewise.
    * gdb_bfd.c (print_one_bfd): Likewise.
    (maintenance_info_bfds): Likewise.
    * guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Likewise.
    * guile/scm-ports.c (ioscm_with_output_to_port_worker): Likewise.
    * i386-linux-tdep.c (i386_linux_handle_segmentation_fault): Likewise.
    * i386-tdep.c (i386_mpx_print_bounds): Likewise.
    * infcmd.c (run_command_1): Likewise.
    (print_return_value_1): Likewise.
    * inferior.c (print_selected_inferior): Likewise.
    (print_inferior): Likewise.
    * infrun.c (print_end_stepping_range_reason): Likewise.
    (print_signal_exited_reason): Likewise.
    (print_exited_reason): Likewise.
    (print_signal_received_reason): Likewise.
    (print_no_history_reason): Likewise.
    * interps.c (interp_set): Likewise.
    * linespec.c (decode_line_full): Likewise.
    * linux-thread-db.c (info_auto_load_libthread_db): Likewise.
    * mi/mi-cmd-env.c (mi_cmd_env_pwd): Likewise.
    (mi_cmd_env_path): Likewise.
    (mi_cmd_env_dir): Likewise.
    (mi_cmd_inferior_tty_show): Likewise.
    * mi/mi-cmd-file.c (mi_cmd_file_list_exec_source_file): Likewise.
    (print_partial_file_name): Likewise.
    (mi_cmd_file_list_exec_source_files): Likewise.
    * mi/mi-cmd-info.c (mi_cmd_info_ada_exceptions): Likewise.
    (mi_cmd_info_gdb_mi_command): Likewise.
    * mi/mi-cmd-stack.c (mi_cmd_stack_info_depth): Likewise.
    (mi_cmd_stack_list_args): Likewise.
    (list_arg_or_local): Likewise.
    * mi/mi-cmd-var.c (print_varobj): Likewise.
    (mi_cmd_var_create): Likewise.
    (mi_cmd_var_delete): Likewise.
    (mi_cmd_var_set_format): Likewise.
    (mi_cmd_var_show_format): Likewise.
    (mi_cmd_var_info_num_children): Likewise.
    (mi_cmd_var_list_children): Likewise.
    (mi_cmd_var_info_type): Likewise.
    (mi_cmd_var_info_path_expression): Likewise.
    (mi_cmd_var_info_expression): Likewise.
    (mi_cmd_var_show_attributes): Likewise.
    (mi_cmd_var_evaluate_expression): Likewise.
    (mi_cmd_var_assign): Likewise.
    (varobj_update_one): Likewise.
    * mi/mi-interp.c (as_mi_interp): Likewise.
    (mi_on_normal_stop_1): Likewise.
    (mi_tsv_modified): Likewise.
    (mi_breakpoint_created): Likewise.
    (mi_breakpoint_modified): Likewise.
    (mi_solib_loaded): Likewise.
    (mi_solib_unloaded): Likewise.
    (mi_command_param_changed): Likewise.
    (mi_memory_changed): Likewise.
    (mi_user_selected_context_changed): Likewise.
    * mi/mi-main.c (print_one_inferior): Likewise.
    (output_cores): Likewise.
    (list_available_thread_groups): Likewise.
    (mi_cmd_data_list_register_names): Likewise.
    (mi_cmd_data_list_changed_registers): Likewise.
    (output_register): Likewise.
    (mi_cmd_data_evaluate_expression): Likewise.
    (mi_cmd_data_read_memory): Likewise.
    (mi_cmd_data_read_memory_bytes): Likewise.
    (mi_cmd_list_features): Likewise.
    (mi_cmd_list_target_features): Likewise.
    (mi_cmd_add_inferior): Likewise.
    (mi_execute_command): Likewise.
    (mi_load_progress): Likewise.
    (print_variable_or_computed): Likewise.
    (mi_cmd_trace_frame_collected): Likewise.
    * mi/mi-symbol-cmds.c (mi_cmd_symbol_list_lines): Likewise.
    * osdata.c (info_osdata_command): Likewise.
    * probe.c (gen_ui_out_table_header_info): Likewise.
    (print_ui_out_not_applicables): Likewise.
    (print_ui_out_info): Likewise.
    (info_probes_for_ops): Likewise.
    (enable_probes_command): Likewise.
    (disable_probes_command): Likewise.
    * progspace.c (print_program_space): Likewise.
    * python/py-breakpoint.c (bppy_get_commands): Likewise.
    * python/py-framefilter.c (py_print_type): Likewise.
    (py_print_value): Likewise.
    (py_print_single_arg): Likewise.
    (enumerate_args): Likewise.
    (enumerate_locals): Likewise.
    (py_print_args): Likewise.
    (py_print_frame): Likewise.
    * record-btrace.c (btrace_ui_out_decode_error): Likewise.
    (btrace_call_history_insn_range): Likewise.
    (btrace_call_history_src_line): Likewise.
    (btrace_call_history): Likewise.
    * remote.c (show_remote_cmd): Likewise.
    * skip.c (skip_info): Likewise.
    * solib.c (info_sharedlibrary_command): Likewise.
    * source.c (print_source_lines_base): Likewise.
    * spu-tdep.c (info_spu_event_command): Likewise.
    (info_spu_signal_command): Likewise.
    (info_spu_mailbox_list): Likewise.
    (info_spu_dma_cmdlist): Likewise.
    (info_spu_dma_command): Likewise.
    (info_spu_proxydma_command): Likewise.
    * stack.c (print_stack_frame): Likewise.
    (print_frame_arg): Likewise.
    (read_frame_arg): Likewise.
    (print_frame_args): Likewise.
    (print_frame_info): Likewise.
    (print_frame): Likewise.
    * symfile.c (load_progress): Likewise.
    (generic_load): Likewise.
    (print_transfer_performance): Likewise.
    * thread.c (do_captured_list_thread_ids): Likewise.
    (print_thread_info_1): Likewise.
    (restore_selected_frame): Likewise.
    (do_captured_thread_select): Likewise.
    (print_selected_thread_frame): Likewise.
    * top.c (execute_command_to_string): Likewise.
    * tracepoint.c (tvariables_info_1): Likewise.
    (trace_status_mi): Likewise.
    (tfind_1): Likewise.
    (print_one_static_tracepoint_marker): Likewise.
    (info_static_tracepoint_markers_command): Likewise.
    * utils.c (do_ui_out_redirect_pop): Likewise.
    (fputs_maybe_filtered): Likewise.
2016-12-22 16:19:42 -05:00

1348 lines
35 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Scheme interface to breakpoints.
Copyright (C) 2008-2016 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* See README file in this directory for implementation notes, coding
conventions, et.al. */
#include "defs.h"
#include "value.h"
#include "breakpoint.h"
#include "gdbcmd.h"
#include "gdbthread.h"
#include "observer.h"
#include "cli/cli-script.h"
#include "ada-lang.h"
#include "arch-utils.h"
#include "language.h"
#include "guile-internal.h"
#include "location.h"
/* The <gdb:breakpoint> smob.
N.B.: The name of this struct is known to breakpoint.h.
Note: Breakpoints are added to gdb using a two step process:
1) Call make-breakpoint to create a <gdb:breakpoint> object.
2) Call register-breakpoint! to add the breakpoint to gdb.
It is done this way so that the constructor, make-breakpoint, doesn't have
any side-effects. This means that the smob needs to store everything
that was passed to make-breakpoint. */
typedef struct gdbscm_breakpoint_object
{
/* This always appears first. */
gdb_smob base;
/* Non-zero if this breakpoint was created with make-breakpoint. */
int is_scheme_bkpt;
/* For breakpoints created with make-breakpoint, these are the parameters
that were passed to make-breakpoint. These values are not used except
to register the breakpoint with GDB. */
struct
{
/* The string representation of the breakpoint.
Space for this lives in GC space. */
char *location;
/* The kind of breakpoint.
At the moment this can only be one of bp_breakpoint, bp_watchpoint. */
enum bptype type;
/* If a watchpoint, the kind of watchpoint. */
enum target_hw_bp_type access_type;
/* Non-zero if the breakpoint is an "internal" breakpoint. */
int is_internal;
} spec;
/* The breakpoint number according to gdb.
For breakpoints created from Scheme, this has the value -1 until the
breakpoint is registered with gdb.
This is recorded here because BP will be NULL when deleted. */
int number;
/* The gdb breakpoint object, or NULL if the breakpoint has not been
registered yet, or has been deleted. */
struct breakpoint *bp;
/* Backlink to our containing <gdb:breakpoint> smob.
This is needed when we are deleted, we need to unprotect the object
from GC. */
SCM containing_scm;
/* A stop condition or #f. */
SCM stop;
} breakpoint_smob;
static const char breakpoint_smob_name[] = "gdb:breakpoint";
/* The tag Guile knows the breakpoint smob by. */
static scm_t_bits breakpoint_smob_tag;
/* Variables used to pass information between the breakpoint_smob
constructor and the breakpoint-created hook function. */
static SCM pending_breakpoint_scm = SCM_BOOL_F;
/* Keywords used by create-breakpoint!. */
static SCM type_keyword;
static SCM wp_class_keyword;
static SCM internal_keyword;
/* Administrivia for breakpoint smobs. */
/* The smob "free" function for <gdb:breakpoint>. */
static size_t
bpscm_free_breakpoint_smob (SCM self)
{
breakpoint_smob *bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (self);
if (bp_smob->bp)
bp_smob->bp->scm_bp_object = NULL;
/* Not necessary, done to catch bugs. */
bp_smob->bp = NULL;
bp_smob->containing_scm = SCM_UNDEFINED;
bp_smob->stop = SCM_UNDEFINED;
return 0;
}
/* Return the name of TYPE.
This doesn't handle all types, just the ones we export. */
static const char *
bpscm_type_to_string (enum bptype type)
{
switch (type)
{
case bp_none: return "BP_NONE";
case bp_breakpoint: return "BP_BREAKPOINT";
case bp_watchpoint: return "BP_WATCHPOINT";
case bp_hardware_watchpoint: return "BP_HARDWARE_WATCHPOINT";
case bp_read_watchpoint: return "BP_READ_WATCHPOINT";
case bp_access_watchpoint: return "BP_ACCESS_WATCHPOINT";
default: return "internal/other";
}
}
/* Return the name of ENABLE_STATE. */
static const char *
bpscm_enable_state_to_string (enum enable_state enable_state)
{
switch (enable_state)
{
case bp_disabled: return "disabled";
case bp_enabled: return "enabled";
case bp_call_disabled: return "call_disabled";
default: return "unknown";
}
}
/* The smob "print" function for <gdb:breakpoint>. */
static int
bpscm_print_breakpoint_smob (SCM self, SCM port, scm_print_state *pstate)
{
breakpoint_smob *bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (self);
struct breakpoint *b = bp_smob->bp;
gdbscm_printf (port, "#<%s", breakpoint_smob_name);
/* Only print what we export to the user.
The rest are possibly internal implementation details. */
gdbscm_printf (port, " #%d", bp_smob->number);
/* Careful, the breakpoint may be invalid. */
if (b != NULL)
{
const char *str;
gdbscm_printf (port, " %s %s %s",
bpscm_type_to_string (b->type),
bpscm_enable_state_to_string (b->enable_state),
b->silent ? "silent" : "noisy");
gdbscm_printf (port, " hit:%d", b->hit_count);
gdbscm_printf (port, " ignore:%d", b->ignore_count);
str = event_location_to_string (b->location);
if (str != NULL)
gdbscm_printf (port, " @%s", str);
}
scm_puts (">", port);
scm_remember_upto_here_1 (self);
/* Non-zero means success. */
return 1;
}
/* Low level routine to create a <gdb:breakpoint> object. */
static SCM
bpscm_make_breakpoint_smob (void)
{
breakpoint_smob *bp_smob = (breakpoint_smob *)
scm_gc_malloc (sizeof (breakpoint_smob), breakpoint_smob_name);
SCM bp_scm;
memset (bp_smob, 0, sizeof (*bp_smob));
bp_smob->number = -1;
bp_smob->stop = SCM_BOOL_F;
bp_scm = scm_new_smob (breakpoint_smob_tag, (scm_t_bits) bp_smob);
bp_smob->containing_scm = bp_scm;
gdbscm_init_gsmob (&bp_smob->base);
return bp_scm;
}
/* Return non-zero if we want a Scheme wrapper for breakpoint B.
If FROM_SCHEME is non-zero,this is called for a breakpoint created
by the user from Scheme. Otherwise it is zero. */
static int
bpscm_want_scm_wrapper_p (struct breakpoint *bp, int from_scheme)
{
/* Don't create <gdb:breakpoint> objects for internal GDB breakpoints. */
if (bp->number < 0 && !from_scheme)
return 0;
/* The others are not supported. */
if (bp->type != bp_breakpoint
&& bp->type != bp_watchpoint
&& bp->type != bp_hardware_watchpoint
&& bp->type != bp_read_watchpoint
&& bp->type != bp_access_watchpoint)
return 0;
return 1;
}
/* Install the Scheme side of a breakpoint, CONTAINING_SCM, in
the gdb side BP. */
static void
bpscm_attach_scm_to_breakpoint (struct breakpoint *bp, SCM containing_scm)
{
breakpoint_smob *bp_smob;
bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (containing_scm);
bp_smob->number = bp->number;
bp_smob->bp = bp;
bp_smob->containing_scm = containing_scm;
bp_smob->bp->scm_bp_object = bp_smob;
/* The owner of this breakpoint is not in GC-controlled memory, so we need
to protect it from GC until the breakpoint is deleted. */
scm_gc_protect_object (containing_scm);
}
/* Return non-zero if SCM is a breakpoint smob. */
static int
bpscm_is_breakpoint (SCM scm)
{
return SCM_SMOB_PREDICATE (breakpoint_smob_tag, scm);
}
/* (breakpoint? scm) -> boolean */
static SCM
gdbscm_breakpoint_p (SCM scm)
{
return scm_from_bool (bpscm_is_breakpoint (scm));
}
/* Returns the <gdb:breakpoint> object in SELF.
Throws an exception if SELF is not a <gdb:breakpoint> object. */
static SCM
bpscm_get_breakpoint_arg_unsafe (SCM self, int arg_pos, const char *func_name)
{
SCM_ASSERT_TYPE (bpscm_is_breakpoint (self), self, arg_pos, func_name,
breakpoint_smob_name);
return self;
}
/* Returns a pointer to the breakpoint smob of SELF.
Throws an exception if SELF is not a <gdb:breakpoint> object. */
static breakpoint_smob *
bpscm_get_breakpoint_smob_arg_unsafe (SCM self, int arg_pos,
const char *func_name)
{
SCM bp_scm = bpscm_get_breakpoint_arg_unsafe (self, arg_pos, func_name);
breakpoint_smob *bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (bp_scm);
return bp_smob;
}
/* Return non-zero if breakpoint BP_SMOB is valid. */
static int
bpscm_is_valid (breakpoint_smob *bp_smob)
{
return bp_smob->bp != NULL;
}
/* Returns the breakpoint smob in SELF, verifying it's valid.
Throws an exception if SELF is not a <gdb:breakpoint> object,
or is invalid. */
static breakpoint_smob *
bpscm_get_valid_breakpoint_smob_arg_unsafe (SCM self, int arg_pos,
const char *func_name)
{
breakpoint_smob *bp_smob
= bpscm_get_breakpoint_smob_arg_unsafe (self, arg_pos, func_name);
if (!bpscm_is_valid (bp_smob))
{
gdbscm_invalid_object_error (func_name, arg_pos, self,
_("<gdb:breakpoint>"));
}
return bp_smob;
}
/* Breakpoint methods. */
/* (make-breakpoint string [#:type integer] [#:wp-class integer]
[#:internal boolean) -> <gdb:breakpoint>
The result is the <gdb:breakpoint> Scheme object.
The breakpoint is not available to be used yet, however.
It must still be added to gdb with register-breakpoint!. */
static SCM
gdbscm_make_breakpoint (SCM location_scm, SCM rest)
{
const SCM keywords[] = {
type_keyword, wp_class_keyword, internal_keyword, SCM_BOOL_F
};
char *s;
char *location;
int type_arg_pos = -1, access_type_arg_pos = -1, internal_arg_pos = -1;
enum bptype type = bp_breakpoint;
enum target_hw_bp_type access_type = hw_write;
int internal = 0;
SCM result;
breakpoint_smob *bp_smob;
gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "s#iit",
location_scm, &location, rest,
&type_arg_pos, &type,
&access_type_arg_pos, &access_type,
&internal_arg_pos, &internal);
result = bpscm_make_breakpoint_smob ();
bp_smob = (breakpoint_smob *) SCM_SMOB_DATA (result);
s = location;
location = gdbscm_gc_xstrdup (s);
xfree (s);
switch (type)
{
case bp_breakpoint:
if (access_type_arg_pos > 0)
{
gdbscm_misc_error (FUNC_NAME, access_type_arg_pos,
scm_from_int (access_type),
_("access type with breakpoint is not allowed"));
}
break;
case bp_watchpoint:
switch (access_type)
{
case hw_write:
case hw_access:
case hw_read:
break;
default:
gdbscm_out_of_range_error (FUNC_NAME, access_type_arg_pos,
scm_from_int (access_type),
_("invalid watchpoint class"));
}
break;
default:
gdbscm_out_of_range_error (FUNC_NAME, access_type_arg_pos,
scm_from_int (type),
_("invalid breakpoint type"));
}
bp_smob->is_scheme_bkpt = 1;
bp_smob->spec.location = location;
bp_smob->spec.type = type;
bp_smob->spec.access_type = access_type;
bp_smob->spec.is_internal = internal;
return result;
}
/* (register-breakpoint! <gdb:breakpoint>) -> unspecified
It is an error to register a breakpoint created outside of Guile,
or an already-registered breakpoint. */
static SCM
gdbscm_register_breakpoint_x (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
struct gdb_exception except = exception_none;
char *location, *copy;
struct event_location *eloc;
struct cleanup *cleanup;
/* We only support registering breakpoints created with make-breakpoint. */
if (!bp_smob->is_scheme_bkpt)
scm_misc_error (FUNC_NAME, _("not a Scheme breakpoint"), SCM_EOL);
if (bpscm_is_valid (bp_smob))
scm_misc_error (FUNC_NAME, _("breakpoint is already registered"), SCM_EOL);
pending_breakpoint_scm = self;
location = bp_smob->spec.location;
copy = skip_spaces (location);
eloc = string_to_event_location_basic (&copy, current_language);
cleanup = make_cleanup_delete_event_location (eloc);
TRY
{
int internal = bp_smob->spec.is_internal;
switch (bp_smob->spec.type)
{
case bp_breakpoint:
{
create_breakpoint (get_current_arch (),
eloc, NULL, -1, NULL,
0,
0, bp_breakpoint,
0,
AUTO_BOOLEAN_TRUE,
&bkpt_breakpoint_ops,
0, 1, internal, 0);
break;
}
case bp_watchpoint:
{
enum target_hw_bp_type access_type = bp_smob->spec.access_type;
if (access_type == hw_write)
watch_command_wrapper (location, 0, internal);
else if (access_type == hw_access)
awatch_command_wrapper (location, 0, internal);
else if (access_type == hw_read)
rwatch_command_wrapper (location, 0, internal);
else
gdb_assert_not_reached ("invalid access type");
break;
}
default:
gdb_assert_not_reached ("invalid breakpoint type");
}
}
CATCH (ex, RETURN_MASK_ALL)
{
except = ex;
}
END_CATCH
/* Ensure this gets reset, even if there's an error. */
pending_breakpoint_scm = SCM_BOOL_F;
GDBSCM_HANDLE_GDB_EXCEPTION (except);
do_cleanups (cleanup);
return SCM_UNSPECIFIED;
}
/* (delete-breakpoint! <gdb:breakpoint>) -> unspecified
Scheme function which deletes (removes) the underlying GDB breakpoint
from GDB's list of breakpoints. This triggers the breakpoint_deleted
observer which will call gdbscm_breakpoint_deleted; that function cleans
up the Scheme bits. */
static SCM
gdbscm_delete_breakpoint_x (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
TRY
{
delete_breakpoint (bp_smob->bp);
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
return SCM_UNSPECIFIED;
}
/* iterate_over_breakpoints function for gdbscm_breakpoints. */
static int
bpscm_build_bp_list (struct breakpoint *bp, void *arg)
{
SCM *list = (SCM *) arg;
breakpoint_smob *bp_smob = bp->scm_bp_object;
/* Lazily create wrappers for breakpoints created outside Scheme. */
if (bp_smob == NULL)
{
if (bpscm_want_scm_wrapper_p (bp, 0))
{
SCM bp_scm;
bp_scm = bpscm_make_breakpoint_smob ();
bpscm_attach_scm_to_breakpoint (bp, bp_scm);
/* Refetch it. */
bp_smob = bp->scm_bp_object;
}
}
/* Not all breakpoints will have a companion Scheme object.
Only breakpoints that trigger the created_breakpoint observer call,
and satisfy certain conditions (see bpscm_want_scm_wrapper_p),
get a companion object (this includes Scheme-created breakpoints). */
if (bp_smob != NULL)
*list = scm_cons (bp_smob->containing_scm, *list);
return 0;
}
/* (breakpoints) -> list
Return a list of all breakpoints. */
static SCM
gdbscm_breakpoints (void)
{
SCM list = SCM_EOL;
/* If iterate_over_breakpoints returns non-NULL it means the iteration
terminated early.
In that case abandon building the list and return #f. */
if (iterate_over_breakpoints (bpscm_build_bp_list, &list) != NULL)
return SCM_BOOL_F;
return scm_reverse_x (list, SCM_EOL);
}
/* (breakpoint-valid? <gdb:breakpoint>) -> boolean
Returns #t if SELF is still valid. */
static SCM
gdbscm_breakpoint_valid_p (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_bool (bpscm_is_valid (bp_smob));
}
/* (breakpoint-enabled? <gdb:breakpoint>) -> boolean */
static SCM
gdbscm_breakpoint_enabled_p (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_bool (bp_smob->bp->enable_state == bp_enabled);
}
/* (set-breakpoint-enabled? <gdb:breakpoint> boolean) -> unspecified */
static SCM
gdbscm_set_breakpoint_enabled_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
SCM_ASSERT_TYPE (gdbscm_is_bool (newvalue), newvalue, SCM_ARG2, FUNC_NAME,
_("boolean"));
TRY
{
if (gdbscm_is_true (newvalue))
enable_breakpoint (bp_smob->bp);
else
disable_breakpoint (bp_smob->bp);
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
return SCM_UNSPECIFIED;
}
/* (breakpoint-silent? <gdb:breakpoint>) -> boolean */
static SCM
gdbscm_breakpoint_silent_p (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_bool (bp_smob->bp->silent);
}
/* (set-breakpoint-silent?! <gdb:breakpoint> boolean) -> unspecified */
static SCM
gdbscm_set_breakpoint_silent_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
SCM_ASSERT_TYPE (gdbscm_is_bool (newvalue), newvalue, SCM_ARG2, FUNC_NAME,
_("boolean"));
TRY
{
breakpoint_set_silent (bp_smob->bp, gdbscm_is_true (newvalue));
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
return SCM_UNSPECIFIED;
}
/* (breakpoint-ignore-count <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_ignore_count (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_long (bp_smob->bp->ignore_count);
}
/* (set-breakpoint-ignore-count! <gdb:breakpoint> integer)
-> unspecified */
static SCM
gdbscm_set_breakpoint_ignore_count_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
long value;
SCM_ASSERT_TYPE (scm_is_signed_integer (newvalue, LONG_MIN, LONG_MAX),
newvalue, SCM_ARG2, FUNC_NAME, _("integer"));
value = scm_to_long (newvalue);
if (value < 0)
value = 0;
TRY
{
set_ignore_count (bp_smob->number, (int) value, 0);
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
return SCM_UNSPECIFIED;
}
/* (breakpoint-hit-count <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_hit_count (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_long (bp_smob->bp->hit_count);
}
/* (set-breakpoint-hit-count! <gdb:breakpoint> integer) -> unspecified */
static SCM
gdbscm_set_breakpoint_hit_count_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
long value;
SCM_ASSERT_TYPE (scm_is_signed_integer (newvalue, LONG_MIN, LONG_MAX),
newvalue, SCM_ARG2, FUNC_NAME, _("integer"));
value = scm_to_long (newvalue);
if (value < 0)
value = 0;
if (value != 0)
{
gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
_("hit-count must be zero"));
}
bp_smob->bp->hit_count = 0;
return SCM_UNSPECIFIED;
}
/* (breakpoint-thread <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_thread (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
if (bp_smob->bp->thread == -1)
return SCM_BOOL_F;
return scm_from_long (bp_smob->bp->thread);
}
/* (set-breakpoint-thread! <gdb:breakpoint> integer) -> unspecified */
static SCM
gdbscm_set_breakpoint_thread_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
long id;
if (scm_is_signed_integer (newvalue, LONG_MIN, LONG_MAX))
{
id = scm_to_long (newvalue);
if (!valid_global_thread_id (id))
{
gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
_("invalid thread id"));
}
}
else if (gdbscm_is_false (newvalue))
id = -1;
else
SCM_ASSERT_TYPE (0, newvalue, SCM_ARG2, FUNC_NAME, _("integer or #f"));
breakpoint_set_thread (bp_smob->bp, id);
return SCM_UNSPECIFIED;
}
/* (breakpoint-task <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_task (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
if (bp_smob->bp->task == 0)
return SCM_BOOL_F;
return scm_from_long (bp_smob->bp->task);
}
/* (set-breakpoint-task! <gdb:breakpoint> integer) -> unspecified */
static SCM
gdbscm_set_breakpoint_task_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
long id;
int valid_id = 0;
if (scm_is_signed_integer (newvalue, LONG_MIN, LONG_MAX))
{
id = scm_to_long (newvalue);
TRY
{
valid_id = valid_task_id (id);
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
if (! valid_id)
{
gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG2, newvalue,
_("invalid task id"));
}
}
else if (gdbscm_is_false (newvalue))
id = 0;
else
SCM_ASSERT_TYPE (0, newvalue, SCM_ARG2, FUNC_NAME, _("integer or #f"));
TRY
{
breakpoint_set_task (bp_smob->bp, id);
}
CATCH (except, RETURN_MASK_ALL)
{
GDBSCM_HANDLE_GDB_EXCEPTION (except);
}
END_CATCH
return SCM_UNSPECIFIED;
}
/* (breakpoint-location <gdb:breakpoint>) -> string */
static SCM
gdbscm_breakpoint_location (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
const char *str;
if (bp_smob->bp->type != bp_breakpoint)
return SCM_BOOL_F;
str = event_location_to_string (bp_smob->bp->location);
if (! str)
str = "";
return gdbscm_scm_from_c_string (str);
}
/* (breakpoint-expression <gdb:breakpoint>) -> string
This is only valid for watchpoints.
Returns #f for non-watchpoints. */
static SCM
gdbscm_breakpoint_expression (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
char *str;
struct watchpoint *wp;
if (!is_watchpoint (bp_smob->bp))
return SCM_BOOL_F;
wp = (struct watchpoint *) bp_smob->bp;
str = wp->exp_string;
if (! str)
str = "";
return gdbscm_scm_from_c_string (str);
}
/* (breakpoint-condition <gdb:breakpoint>) -> string */
static SCM
gdbscm_breakpoint_condition (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
char *str;
str = bp_smob->bp->cond_string;
if (! str)
return SCM_BOOL_F;
return gdbscm_scm_from_c_string (str);
}
/* (set-breakpoint-condition! <gdb:breakpoint> string|#f)
-> unspecified */
static SCM
gdbscm_set_breakpoint_condition_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
char *exp;
struct gdb_exception except = exception_none;
SCM_ASSERT_TYPE (scm_is_string (newvalue) || gdbscm_is_false (newvalue),
newvalue, SCM_ARG2, FUNC_NAME,
_("string or #f"));
if (gdbscm_is_false (newvalue))
exp = NULL;
else
exp = gdbscm_scm_to_c_string (newvalue);
TRY
{
set_breakpoint_condition (bp_smob->bp, exp ? exp : "", 0);
}
CATCH (ex, RETURN_MASK_ALL)
{
except = ex;
}
END_CATCH
xfree (exp);
GDBSCM_HANDLE_GDB_EXCEPTION (except);
return SCM_UNSPECIFIED;
}
/* (breakpoint-stop <gdb:breakpoint>) -> procedure or #f */
static SCM
gdbscm_breakpoint_stop (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return bp_smob->stop;
}
/* (set-breakpoint-stop! <gdb:breakpoint> procedure|#f)
-> unspecified */
static SCM
gdbscm_set_breakpoint_stop_x (SCM self, SCM newvalue)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
const struct extension_language_defn *extlang = NULL;
SCM_ASSERT_TYPE (gdbscm_is_procedure (newvalue)
|| gdbscm_is_false (newvalue),
newvalue, SCM_ARG2, FUNC_NAME,
_("procedure or #f"));
if (bp_smob->bp->cond_string != NULL)
extlang = get_ext_lang_defn (EXT_LANG_GDB);
if (extlang == NULL)
extlang = get_breakpoint_cond_ext_lang (bp_smob->bp, EXT_LANG_GUILE);
if (extlang != NULL)
{
char *error_text
= xstrprintf (_("Only one stop condition allowed. There is"
" currently a %s stop condition defined for"
" this breakpoint."),
ext_lang_capitalized_name (extlang));
scm_dynwind_begin ((scm_t_dynwind_flags) 0);
gdbscm_dynwind_xfree (error_text);
gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG1, self, error_text);
/* The following line, while unnecessary, is present for completeness
sake. */
scm_dynwind_end ();
}
bp_smob->stop = newvalue;
return SCM_UNSPECIFIED;
}
/* (breakpoint-commands <gdb:breakpoint>) -> string */
static SCM
gdbscm_breakpoint_commands (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
struct breakpoint *bp;
long length;
struct ui_file *string_file;
struct cleanup *chain;
SCM result;
bp = bp_smob->bp;
if (bp->commands == NULL)
return SCM_BOOL_F;
string_file = mem_fileopen ();
chain = make_cleanup_ui_file_delete (string_file);
current_uiout->redirect (string_file);
TRY
{
print_command_lines (current_uiout, breakpoint_commands (bp), 0);
}
current_uiout->redirect (NULL);
CATCH (except, RETURN_MASK_ALL)
{
do_cleanups (chain);
gdbscm_throw_gdb_exception (except);
}
END_CATCH
std::string cmdstr = ui_file_as_string (string_file);
result = gdbscm_scm_from_c_string (cmdstr.c_str ());
do_cleanups (chain);
return result;
}
/* (breakpoint-type <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_type (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_long (bp_smob->bp->type);
}
/* (breakpoint-visible? <gdb:breakpoint>) -> boolean */
static SCM
gdbscm_breakpoint_visible (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_bool (bp_smob->bp->number >= 0);
}
/* (breakpoint-number <gdb:breakpoint>) -> integer */
static SCM
gdbscm_breakpoint_number (SCM self)
{
breakpoint_smob *bp_smob
= bpscm_get_valid_breakpoint_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
return scm_from_long (bp_smob->number);
}
/* Return TRUE if "stop" has been set for this breakpoint.
This is the extension_language_ops.breakpoint_has_cond "method". */
int
gdbscm_breakpoint_has_cond (const struct extension_language_defn *extlang,
struct breakpoint *b)
{
breakpoint_smob *bp_smob = b->scm_bp_object;
if (bp_smob == NULL)
return 0;
return gdbscm_is_procedure (bp_smob->stop);
}
/* Call the "stop" method in the breakpoint class.
This must only be called if gdbscm_breakpoint_has_cond returns true.
If the stop method returns #t, the inferior will be stopped at the
breakpoint. Otherwise the inferior will be allowed to continue
(assuming other conditions don't indicate "stop").
This is the extension_language_ops.breakpoint_cond_says_stop "method". */
enum ext_lang_bp_stop
gdbscm_breakpoint_cond_says_stop
(const struct extension_language_defn *extlang, struct breakpoint *b)
{
breakpoint_smob *bp_smob = b->scm_bp_object;
SCM predicate_result;
int stop;
if (bp_smob == NULL)
return EXT_LANG_BP_STOP_UNSET;
if (!gdbscm_is_procedure (bp_smob->stop))
return EXT_LANG_BP_STOP_UNSET;
stop = 1;
predicate_result
= gdbscm_safe_call_1 (bp_smob->stop, bp_smob->containing_scm, NULL);
if (gdbscm_is_exception (predicate_result))
; /* Exception already printed. */
/* If the "stop" function returns #f that means
the Scheme breakpoint wants GDB to continue. */
else if (gdbscm_is_false (predicate_result))
stop = 0;
return stop ? EXT_LANG_BP_STOP_YES : EXT_LANG_BP_STOP_NO;
}
/* Event callback functions. */
/* Callback that is used when a breakpoint is created.
For breakpoints created by Scheme, i.e., gdbscm_create_breakpoint_x, finish
object creation by connecting the Scheme wrapper to the gdb object.
We ignore breakpoints created from gdb or python here, we create the
Scheme wrapper for those when there's a need to, e.g.,
gdbscm_breakpoints. */
static void
bpscm_breakpoint_created (struct breakpoint *bp)
{
SCM bp_scm;
if (gdbscm_is_false (pending_breakpoint_scm))
return;
/* Verify our caller error checked the user's request. */
gdb_assert (bpscm_want_scm_wrapper_p (bp, 1));
bp_scm = pending_breakpoint_scm;
pending_breakpoint_scm = SCM_BOOL_F;
bpscm_attach_scm_to_breakpoint (bp, bp_scm);
}
/* Callback that is used when a breakpoint is deleted. This will
invalidate the corresponding Scheme object. */
static void
bpscm_breakpoint_deleted (struct breakpoint *b)
{
int num = b->number;
struct breakpoint *bp;
/* TODO: Why the lookup? We have B. */
bp = get_breakpoint (num);
if (bp)
{
breakpoint_smob *bp_smob = bp->scm_bp_object;
if (bp_smob)
{
bp_smob->bp = NULL;
bp_smob->number = -1;
bp_smob->stop = SCM_BOOL_F;
scm_gc_unprotect_object (bp_smob->containing_scm);
}
}
}
/* Initialize the Scheme breakpoint code. */
static const scheme_integer_constant breakpoint_integer_constants[] =
{
{ "BP_NONE", bp_none },
{ "BP_BREAKPOINT", bp_breakpoint },
{ "BP_WATCHPOINT", bp_watchpoint },
{ "BP_HARDWARE_WATCHPOINT", bp_hardware_watchpoint },
{ "BP_READ_WATCHPOINT", bp_read_watchpoint },
{ "BP_ACCESS_WATCHPOINT", bp_access_watchpoint },
{ "WP_READ", hw_read },
{ "WP_WRITE", hw_write },
{ "WP_ACCESS", hw_access },
END_INTEGER_CONSTANTS
};
static const scheme_function breakpoint_functions[] =
{
{ "make-breakpoint", 1, 0, 1, as_a_scm_t_subr (gdbscm_make_breakpoint),
"\
Create a GDB breakpoint object.\n\
\n\
Arguments:\n\
location [#:type <type>] [#:wp-class <wp-class>] [#:internal <bool>]\n\
Returns:\n\
<gdb:breakpoint object" },
{ "register-breakpoint!", 1, 0, 0,
as_a_scm_t_subr (gdbscm_register_breakpoint_x),
"\
Register a <gdb:breakpoint> object with GDB." },
{ "delete-breakpoint!", 1, 0, 0, as_a_scm_t_subr (gdbscm_delete_breakpoint_x),
"\
Delete the breakpoint from GDB." },
{ "breakpoints", 0, 0, 0, as_a_scm_t_subr (gdbscm_breakpoints),
"\
Return a list of all GDB breakpoints.\n\
\n\
Arguments: none" },
{ "breakpoint?", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_p),
"\
Return #t if the object is a <gdb:breakpoint> object." },
{ "breakpoint-valid?", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_valid_p),
"\
Return #t if the breakpoint has not been deleted from GDB." },
{ "breakpoint-number", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_number),
"\
Return the breakpoint's number." },
{ "breakpoint-type", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_type),
"\
Return the type of the breakpoint." },
{ "breakpoint-visible?", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_visible),
"\
Return #t if the breakpoint is visible to the user." },
{ "breakpoint-location", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_location),
"\
Return the location of the breakpoint as specified by the user." },
{ "breakpoint-expression", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_expression),
"\
Return the expression of the breakpoint as specified by the user.\n\
Valid for watchpoints only, returns #f for non-watchpoints." },
{ "breakpoint-enabled?", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_enabled_p),
"\
Return #t if the breakpoint is enabled." },
{ "set-breakpoint-enabled!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_enabled_x),
"\
Set the breakpoint's enabled state.\n\
\n\
Arguments: <gdb:breakpoint> boolean" },
{ "breakpoint-silent?", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_silent_p),
"\
Return #t if the breakpoint is silent." },
{ "set-breakpoint-silent!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_silent_x),
"\
Set the breakpoint's silent state.\n\
\n\
Arguments: <gdb:breakpoint> boolean" },
{ "breakpoint-ignore-count", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_ignore_count),
"\
Return the breakpoint's \"ignore\" count." },
{ "set-breakpoint-ignore-count!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_ignore_count_x),
"\
Set the breakpoint's \"ignore\" count.\n\
\n\
Arguments: <gdb:breakpoint> count" },
{ "breakpoint-hit-count", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_hit_count),
"\
Return the breakpoint's \"hit\" count." },
{ "set-breakpoint-hit-count!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_hit_count_x),
"\
Set the breakpoint's \"hit\" count. The value must be zero.\n\
\n\
Arguments: <gdb:breakpoint> 0" },
{ "breakpoint-thread", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_thread),
"\
Return the breakpoint's global thread id or #f if there isn't one." },
{ "set-breakpoint-thread!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_thread_x),
"\
Set the global thread id for this breakpoint.\n\
\n\
Arguments: <gdb:breakpoint> global-thread-id" },
{ "breakpoint-task", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_task),
"\
Return the breakpoint's Ada task-id or #f if there isn't one." },
{ "set-breakpoint-task!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_task_x),
"\
Set the breakpoint's Ada task-id.\n\
\n\
Arguments: <gdb:breakpoint> task-id" },
{ "breakpoint-condition", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_condition),
"\
Return the breakpoint's condition as specified by the user.\n\
Return #f if there isn't one." },
{ "set-breakpoint-condition!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_condition_x),
"\
Set the breakpoint's condition.\n\
\n\
Arguments: <gdb:breakpoint> condition\n\
condition: a string" },
{ "breakpoint-stop", 1, 0, 0, as_a_scm_t_subr (gdbscm_breakpoint_stop),
"\
Return the breakpoint's stop predicate.\n\
Return #f if there isn't one." },
{ "set-breakpoint-stop!", 2, 0, 0,
as_a_scm_t_subr (gdbscm_set_breakpoint_stop_x),
"\
Set the breakpoint's stop predicate.\n\
\n\
Arguments: <gdb:breakpoint> procedure\n\
procedure: A procedure of one argument, the breakpoint.\n\
Its result is true if program execution should stop." },
{ "breakpoint-commands", 1, 0, 0,
as_a_scm_t_subr (gdbscm_breakpoint_commands),
"\
Return the breakpoint's commands." },
END_FUNCTIONS
};
void
gdbscm_initialize_breakpoints (void)
{
breakpoint_smob_tag
= gdbscm_make_smob_type (breakpoint_smob_name, sizeof (breakpoint_smob));
scm_set_smob_free (breakpoint_smob_tag, bpscm_free_breakpoint_smob);
scm_set_smob_print (breakpoint_smob_tag, bpscm_print_breakpoint_smob);
observer_attach_breakpoint_created (bpscm_breakpoint_created);
observer_attach_breakpoint_deleted (bpscm_breakpoint_deleted);
gdbscm_define_integer_constants (breakpoint_integer_constants, 1);
gdbscm_define_functions (breakpoint_functions, 1);
type_keyword = scm_from_latin1_keyword ("type");
wp_class_keyword = scm_from_latin1_keyword ("wp-class");
internal_keyword = scm_from_latin1_keyword ("internal");
}