mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-05-25 03:06:11 +08:00

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.
1611 lines
43 KiB
C
1611 lines
43 KiB
C
/* Python frame filters
|
|
|
|
Copyright (C) 2013-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/>. */
|
|
|
|
#include "defs.h"
|
|
#include "objfiles.h"
|
|
#include "symtab.h"
|
|
#include "language.h"
|
|
#include "arch-utils.h"
|
|
#include "python.h"
|
|
#include "ui-out.h"
|
|
#include "valprint.h"
|
|
#include "annotate.h"
|
|
#include "hashtab.h"
|
|
#include "demangle.h"
|
|
#include "mi/mi-cmds.h"
|
|
#include "python-internal.h"
|
|
|
|
enum mi_print_types
|
|
{
|
|
MI_PRINT_ARGS,
|
|
MI_PRINT_LOCALS
|
|
};
|
|
|
|
/* Helper function to extract a symbol, a name and a language
|
|
definition from a Python object that conforms to the "Symbol Value"
|
|
interface. OBJ is the Python object to extract the values from.
|
|
NAME is a pass-through argument where the name of the symbol will
|
|
be written. NAME is allocated in this function, but the caller is
|
|
responsible for clean up. SYM is a pass-through argument where the
|
|
symbol will be written and SYM_BLOCK is a pass-through argument to
|
|
write the block where the symbol lies in. In the case of the API
|
|
returning a string, this will be set to NULL. LANGUAGE is also a
|
|
pass-through argument denoting the language attributed to the
|
|
Symbol. In the case of SYM being NULL, this will be set to the
|
|
current language. Returns EXT_LANG_BT_ERROR on error with the
|
|
appropriate Python exception set, and EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
extract_sym (PyObject *obj, gdb::unique_xmalloc_ptr<char> *name,
|
|
struct symbol **sym, struct block **sym_block,
|
|
const struct language_defn **language)
|
|
{
|
|
PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
|
|
|
|
if (result == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
|
|
/* For 'symbol' callback, the function can return a symbol or a
|
|
string. */
|
|
if (gdbpy_is_string (result))
|
|
{
|
|
*name = python_string_to_host_string (result);
|
|
Py_DECREF (result);
|
|
|
|
if (*name == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
/* If the API returns a string (and not a symbol), then there is
|
|
no symbol derived language available and the frame filter has
|
|
either overridden the symbol with a string, or supplied a
|
|
entirely synthetic symbol/value pairing. In that case, use
|
|
python_language. */
|
|
*language = python_language;
|
|
*sym = NULL;
|
|
*sym_block = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* This type checks 'result' during the conversion so we
|
|
just call it unconditionally and check the return. */
|
|
*sym = symbol_object_to_symbol (result);
|
|
/* TODO: currently, we have no way to recover the block in which SYMBOL
|
|
was found, so we have no block to return. Trying to evaluate SYMBOL
|
|
will yield an incorrect value when it's located in a FRAME and
|
|
evaluated from another frame (as permitted in nested functions). */
|
|
*sym_block = NULL;
|
|
|
|
Py_DECREF (result);
|
|
|
|
if (*sym == NULL)
|
|
{
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
_("Unexpected value. Expecting a "
|
|
"gdb.Symbol or a Python string."));
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
/* Duplicate the symbol name, so the caller has consistency
|
|
in garbage collection. */
|
|
name->reset (xstrdup (SYMBOL_PRINT_NAME (*sym)));
|
|
|
|
/* If a symbol is specified attempt to determine the language
|
|
from the symbol. If mode is not "auto", then the language
|
|
has been explicitly set, use that. */
|
|
if (language_mode == language_mode_auto)
|
|
*language = language_def (SYMBOL_LANGUAGE (*sym));
|
|
else
|
|
*language = current_language;
|
|
}
|
|
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
|
|
/* Helper function to extract a value from an object that conforms to
|
|
the "Symbol Value" interface. OBJ is the Python object to extract
|
|
the value from. VALUE is a pass-through argument where the value
|
|
will be written. If the object does not have the value attribute,
|
|
or provides the Python None for a value, VALUE will be set to NULL
|
|
and this function will return as successful. Returns EXT_LANG_BT_ERROR
|
|
on error with the appropriate Python exception set, and EXT_LANG_BT_OK on
|
|
success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
extract_value (PyObject *obj, struct value **value)
|
|
{
|
|
if (PyObject_HasAttrString (obj, "value"))
|
|
{
|
|
PyObject *vresult = PyObject_CallMethod (obj, "value", NULL);
|
|
|
|
if (vresult == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
|
|
/* The Python code has returned 'None' for a value, so we set
|
|
value to NULL. This flags that GDB should read the
|
|
value. */
|
|
if (vresult == Py_None)
|
|
{
|
|
Py_DECREF (vresult);
|
|
*value = NULL;
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
else
|
|
{
|
|
*value = convert_value_from_python (vresult);
|
|
Py_DECREF (vresult);
|
|
|
|
if (*value == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
}
|
|
else
|
|
*value = NULL;
|
|
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
|
|
/* MI prints only certain values according to the type of symbol and
|
|
also what the user has specified. SYM is the symbol to check, and
|
|
MI_PRINT_TYPES is an enum specifying what the user wants emitted
|
|
for the MI command in question. */
|
|
static int
|
|
mi_should_print (struct symbol *sym, enum mi_print_types type)
|
|
{
|
|
int print_me = 0;
|
|
|
|
switch (SYMBOL_CLASS (sym))
|
|
{
|
|
default:
|
|
case LOC_UNDEF: /* catches errors */
|
|
case LOC_CONST: /* constant */
|
|
case LOC_TYPEDEF: /* local typedef */
|
|
case LOC_LABEL: /* local label */
|
|
case LOC_BLOCK: /* local function */
|
|
case LOC_CONST_BYTES: /* loc. byte seq. */
|
|
case LOC_UNRESOLVED: /* unresolved static */
|
|
case LOC_OPTIMIZED_OUT: /* optimized out */
|
|
print_me = 0;
|
|
break;
|
|
|
|
case LOC_ARG: /* argument */
|
|
case LOC_REF_ARG: /* reference arg */
|
|
case LOC_REGPARM_ADDR: /* indirect register arg */
|
|
case LOC_LOCAL: /* stack local */
|
|
case LOC_STATIC: /* static */
|
|
case LOC_REGISTER: /* register */
|
|
case LOC_COMPUTED: /* computed location */
|
|
if (type == MI_PRINT_LOCALS)
|
|
print_me = ! SYMBOL_IS_ARGUMENT (sym);
|
|
else
|
|
print_me = SYMBOL_IS_ARGUMENT (sym);
|
|
}
|
|
return print_me;
|
|
}
|
|
|
|
/* Helper function which outputs a type name extracted from VAL to a
|
|
"type" field in the output stream OUT. OUT is the ui-out structure
|
|
the type name will be output too, and VAL is the value that the
|
|
type will be extracted from. Returns EXT_LANG_BT_ERROR on error, with
|
|
any GDB exceptions converted to a Python exception, or EXT_LANG_BT_OK on
|
|
success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_type (struct ui_out *out, struct value *val)
|
|
{
|
|
|
|
TRY
|
|
{
|
|
struct ui_file *stb;
|
|
struct cleanup *cleanup;
|
|
|
|
stb = mem_fileopen ();
|
|
cleanup = make_cleanup_ui_file_delete (stb);
|
|
check_typedef (value_type (val));
|
|
type_print (value_type (val), "", stb, -1);
|
|
out->field_stream ("type", stb);
|
|
do_cleanups (cleanup);
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
|
|
/* Helper function which outputs a value to an output field in a
|
|
stream. OUT is the ui-out structure the value will be output to,
|
|
VAL is the value that will be printed, OPTS contains the value
|
|
printing options, ARGS_TYPE is an enumerator describing the
|
|
argument format, and LANGUAGE is the language_defn that the value
|
|
will be printed with. Returns EXT_LANG_BT_ERROR on error, with any GDB
|
|
exceptions converted to a Python exception, or EXT_LANG_BT_OK on
|
|
success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_value (struct ui_out *out, struct value *val,
|
|
const struct value_print_options *opts,
|
|
int indent,
|
|
enum ext_lang_frame_args args_type,
|
|
const struct language_defn *language)
|
|
{
|
|
int should_print = 0;
|
|
|
|
/* MI does not print certain values, differentiated by type,
|
|
depending on what ARGS_TYPE indicates. Test type against option.
|
|
For CLI print all values. */
|
|
if (args_type == MI_PRINT_SIMPLE_VALUES
|
|
|| args_type == MI_PRINT_ALL_VALUES)
|
|
{
|
|
struct type *type = NULL;
|
|
|
|
TRY
|
|
{
|
|
type = check_typedef (value_type (val));
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
if (args_type == MI_PRINT_ALL_VALUES)
|
|
should_print = 1;
|
|
else if (args_type == MI_PRINT_SIMPLE_VALUES
|
|
&& TYPE_CODE (type) != TYPE_CODE_ARRAY
|
|
&& TYPE_CODE (type) != TYPE_CODE_STRUCT
|
|
&& TYPE_CODE (type) != TYPE_CODE_UNION)
|
|
should_print = 1;
|
|
}
|
|
else if (args_type != NO_VALUES)
|
|
should_print = 1;
|
|
|
|
if (should_print)
|
|
{
|
|
TRY
|
|
{
|
|
struct ui_file *stb;
|
|
struct cleanup *cleanup;
|
|
|
|
stb = mem_fileopen ();
|
|
cleanup = make_cleanup_ui_file_delete (stb);
|
|
common_val_print (val, stb, indent, opts, language);
|
|
out->field_stream ("value", stb);
|
|
do_cleanups (cleanup);
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
return EXT_LANG_BT_OK;
|
|
}
|
|
|
|
/* Helper function to call a Python method and extract an iterator
|
|
from the result. If the function returns anything but an iterator
|
|
the exception is preserved and NULL is returned. FILTER is the
|
|
Python object to call, and FUNC is the name of the method. Returns
|
|
a PyObject, or NULL on error with the appropriate exception set.
|
|
This function can return an iterator, or NULL. */
|
|
|
|
static PyObject *
|
|
get_py_iter_from_func (PyObject *filter, char *func)
|
|
{
|
|
if (PyObject_HasAttrString (filter, func))
|
|
{
|
|
PyObject *result = PyObject_CallMethod (filter, func, NULL);
|
|
|
|
if (result != NULL)
|
|
{
|
|
if (result == Py_None)
|
|
{
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
PyObject *iterator = PyObject_GetIter (result);
|
|
|
|
Py_DECREF (result);
|
|
return iterator;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
Py_RETURN_NONE;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Helper function to output a single frame argument and value to an
|
|
output stream. This function will account for entry values if the
|
|
FV parameter is populated, the frame argument has entry values
|
|
associated with them, and the appropriate "set entry-value"
|
|
options are set. Will output in CLI or MI like format depending
|
|
on the type of output stream detected. OUT is the output stream,
|
|
SYM_NAME is the name of the symbol. If SYM_NAME is populated then
|
|
it must have an accompanying value in the parameter FV. FA is a
|
|
frame argument structure. If FA is populated, both SYM_NAME and
|
|
FV are ignored. OPTS contains the value printing options,
|
|
ARGS_TYPE is an enumerator describing the argument format,
|
|
PRINT_ARGS_FIELD is a flag which indicates if we output "ARGS=1"
|
|
in MI output in commands where both arguments and locals are
|
|
printed. Returns EXT_LANG_BT_ERROR on error, with any GDB exceptions
|
|
converted to a Python exception, or EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_single_arg (struct ui_out *out,
|
|
const char *sym_name,
|
|
struct frame_arg *fa,
|
|
struct value *fv,
|
|
const struct value_print_options *opts,
|
|
enum ext_lang_frame_args args_type,
|
|
int print_args_field,
|
|
const struct language_defn *language)
|
|
{
|
|
struct value *val;
|
|
enum ext_lang_bt_status retval = EXT_LANG_BT_OK;
|
|
|
|
if (fa != NULL)
|
|
{
|
|
if (fa->val == NULL && fa->error == NULL)
|
|
return EXT_LANG_BT_OK;
|
|
language = language_def (SYMBOL_LANGUAGE (fa->sym));
|
|
val = fa->val;
|
|
}
|
|
else
|
|
val = fv;
|
|
|
|
TRY
|
|
{
|
|
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
|
|
|
|
/* MI has varying rules for tuples, but generally if there is only
|
|
one element in each item in the list, do not start a tuple. The
|
|
exception is -stack-list-variables which emits an ARGS="1" field
|
|
if the value is a frame argument. This is denoted in this
|
|
function with PRINT_ARGS_FIELD which is flag from the caller to
|
|
emit the ARGS field. */
|
|
if (out->is_mi_like_p ())
|
|
{
|
|
if (print_args_field || args_type != NO_VALUES)
|
|
make_cleanup_ui_out_tuple_begin_end (out, NULL);
|
|
}
|
|
|
|
annotate_arg_begin ();
|
|
|
|
/* If frame argument is populated, check for entry-values and the
|
|
entry value options. */
|
|
if (fa != NULL)
|
|
{
|
|
struct ui_file *stb;
|
|
|
|
stb = mem_fileopen ();
|
|
make_cleanup_ui_file_delete (stb);
|
|
fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
|
|
SYMBOL_LANGUAGE (fa->sym),
|
|
DMGL_PARAMS | DMGL_ANSI);
|
|
if (fa->entry_kind == print_entry_values_compact)
|
|
{
|
|
fputs_filtered ("=", stb);
|
|
|
|
fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
|
|
SYMBOL_LANGUAGE (fa->sym),
|
|
DMGL_PARAMS | DMGL_ANSI);
|
|
}
|
|
if (fa->entry_kind == print_entry_values_only
|
|
|| fa->entry_kind == print_entry_values_compact)
|
|
{
|
|
fputs_filtered ("@entry", stb);
|
|
}
|
|
out->field_stream ("name", stb);
|
|
}
|
|
else
|
|
/* Otherwise, just output the name. */
|
|
out->field_string ("name", sym_name);
|
|
|
|
annotate_arg_name_end ();
|
|
|
|
if (! out->is_mi_like_p ())
|
|
out->text ("=");
|
|
|
|
if (print_args_field)
|
|
out->field_int ("arg", 1);
|
|
|
|
/* For MI print the type, but only for simple values. This seems
|
|
weird, but this is how MI choose to format the various output
|
|
types. */
|
|
if (args_type == MI_PRINT_SIMPLE_VALUES && val != NULL)
|
|
{
|
|
if (py_print_type (out, val) == EXT_LANG_BT_ERROR)
|
|
{
|
|
retval = EXT_LANG_BT_ERROR;
|
|
do_cleanups (cleanups);
|
|
}
|
|
}
|
|
|
|
if (retval != EXT_LANG_BT_ERROR)
|
|
{
|
|
if (val != NULL)
|
|
annotate_arg_value (value_type (val));
|
|
|
|
/* If the output is to the CLI, and the user option "set print
|
|
frame-arguments" is set to none, just output "...". */
|
|
if (! out->is_mi_like_p () && args_type == NO_VALUES)
|
|
out->field_string ("value", "...");
|
|
else
|
|
{
|
|
/* Otherwise, print the value for both MI and the CLI, except
|
|
for the case of MI_PRINT_NO_VALUES. */
|
|
if (args_type != NO_VALUES)
|
|
{
|
|
if (val == NULL)
|
|
{
|
|
gdb_assert (fa != NULL && fa->error != NULL);
|
|
out->field_fmt ("value",
|
|
_("<error reading variable: %s>"),
|
|
fa->error);
|
|
}
|
|
else if (py_print_value (out, val, opts, 0, args_type, language)
|
|
== EXT_LANG_BT_ERROR)
|
|
retval = EXT_LANG_BT_ERROR;
|
|
}
|
|
}
|
|
|
|
do_cleanups (cleanups);
|
|
}
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
}
|
|
END_CATCH
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Helper function to loop over frame arguments provided by the
|
|
"frame_arguments" Python API. Elements in the iterator must
|
|
conform to the "Symbol Value" interface. ITER is the Python
|
|
iterable object, OUT is the output stream, ARGS_TYPE is an
|
|
enumerator describing the argument format, PRINT_ARGS_FIELD is a
|
|
flag which indicates if we output "ARGS=1" in MI output in commands
|
|
where both arguments and locals are printed, and FRAME is the
|
|
backing frame. Returns EXT_LANG_BT_ERROR on error, with any GDB
|
|
exceptions converted to a Python exception, or EXT_LANG_BT_OK on
|
|
success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
enumerate_args (PyObject *iter,
|
|
struct ui_out *out,
|
|
enum ext_lang_frame_args args_type,
|
|
int print_args_field,
|
|
struct frame_info *frame)
|
|
{
|
|
PyObject *item;
|
|
struct value_print_options opts;
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
if (args_type == CLI_SCALAR_VALUES)
|
|
{
|
|
/* True in "summary" mode, false otherwise. */
|
|
opts.summary = 1;
|
|
}
|
|
|
|
opts.deref_ref = 1;
|
|
|
|
TRY
|
|
{
|
|
annotate_frame_args ();
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
|
|
/* Collect the first argument outside of the loop, so output of
|
|
commas in the argument output is correct. At the end of the
|
|
loop block collect another item from the iterator, and, if it is
|
|
not null emit a comma. */
|
|
item = PyIter_Next (iter);
|
|
if (item == NULL && PyErr_Occurred ())
|
|
goto error;
|
|
|
|
while (item)
|
|
{
|
|
const struct language_defn *language;
|
|
gdb::unique_xmalloc_ptr<char> sym_name;
|
|
struct symbol *sym;
|
|
struct block *sym_block;
|
|
struct value *val;
|
|
enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
|
|
|
|
success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
{
|
|
Py_DECREF (item);
|
|
goto error;
|
|
}
|
|
|
|
success = extract_value (item, &val);
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
{
|
|
Py_DECREF (item);
|
|
goto error;
|
|
}
|
|
|
|
Py_DECREF (item);
|
|
item = NULL;
|
|
|
|
if (sym && out->is_mi_like_p ()
|
|
&& ! mi_should_print (sym, MI_PRINT_ARGS))
|
|
continue;
|
|
|
|
/* If the object did not provide a value, read it using
|
|
read_frame_args and account for entry values, if any. */
|
|
if (val == NULL)
|
|
{
|
|
struct frame_arg arg, entryarg;
|
|
|
|
/* If there is no value, and also no symbol, set error and
|
|
exit. */
|
|
if (sym == NULL)
|
|
{
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
_("No symbol or value provided."));
|
|
goto error;
|
|
}
|
|
|
|
TRY
|
|
{
|
|
read_frame_arg (sym, frame, &arg, &entryarg);
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
|
|
/* The object has not provided a value, so this is a frame
|
|
argument to be read by GDB. In this case we have to
|
|
account for entry-values. */
|
|
|
|
if (arg.entry_kind != print_entry_values_only)
|
|
{
|
|
if (py_print_single_arg (out, NULL, &arg,
|
|
NULL, &opts,
|
|
args_type,
|
|
print_args_field,
|
|
NULL) == EXT_LANG_BT_ERROR)
|
|
{
|
|
xfree (arg.error);
|
|
xfree (entryarg.error);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
if (entryarg.entry_kind != print_entry_values_no)
|
|
{
|
|
if (arg.entry_kind != print_entry_values_only)
|
|
{
|
|
TRY
|
|
{
|
|
out->text (", ");
|
|
out->wrap_hint (" ");
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
xfree (arg.error);
|
|
xfree (entryarg.error);
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
if (py_print_single_arg (out, NULL, &entryarg, NULL, &opts,
|
|
args_type, print_args_field, NULL)
|
|
== EXT_LANG_BT_ERROR)
|
|
{
|
|
xfree (arg.error);
|
|
xfree (entryarg.error);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
xfree (arg.error);
|
|
xfree (entryarg.error);
|
|
}
|
|
else
|
|
{
|
|
/* If the object has provided a value, we just print that. */
|
|
if (val != NULL)
|
|
{
|
|
if (py_print_single_arg (out, sym_name.get (), NULL, val, &opts,
|
|
args_type, print_args_field,
|
|
language) == EXT_LANG_BT_ERROR)
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* Collect the next item from the iterator. If
|
|
this is the last item, do not print the
|
|
comma. */
|
|
item = PyIter_Next (iter);
|
|
if (item != NULL)
|
|
{
|
|
TRY
|
|
{
|
|
out->text (", ");
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
Py_DECREF (item);
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
}
|
|
else if (PyErr_Occurred ())
|
|
goto error;
|
|
|
|
TRY
|
|
{
|
|
annotate_arg_end ();
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
Py_DECREF (item);
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
return EXT_LANG_BT_OK;
|
|
|
|
error:
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
|
|
/* Helper function to loop over variables provided by the
|
|
"frame_locals" Python API. Elements in the iterable must conform
|
|
to the "Symbol Value" interface. ITER is the Python iterable
|
|
object, OUT is the output stream, INDENT is whether we should
|
|
indent the output (for CLI), ARGS_TYPE is an enumerator describing
|
|
the argument format, PRINT_ARGS_FIELD is flag which indicates
|
|
whether to output the ARGS field in the case of
|
|
-stack-list-variables and FRAME is the backing frame. Returns
|
|
EXT_LANG_BT_ERROR on error, with any GDB exceptions converted to a Python
|
|
exception, or EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
enumerate_locals (PyObject *iter,
|
|
struct ui_out *out,
|
|
int indent,
|
|
enum ext_lang_frame_args args_type,
|
|
int print_args_field,
|
|
struct frame_info *frame)
|
|
{
|
|
PyObject *item;
|
|
struct value_print_options opts;
|
|
|
|
get_user_print_options (&opts);
|
|
opts.deref_ref = 1;
|
|
|
|
while ((item = PyIter_Next (iter)))
|
|
{
|
|
const struct language_defn *language;
|
|
gdb::unique_xmalloc_ptr<char> sym_name;
|
|
struct value *val;
|
|
enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
|
|
struct symbol *sym;
|
|
struct block *sym_block;
|
|
int local_indent = 8 + (8 * indent);
|
|
struct cleanup *locals_cleanups;
|
|
|
|
locals_cleanups = make_cleanup_py_decref (item);
|
|
|
|
success = extract_sym (item, &sym_name, &sym, &sym_block, &language);
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
|
|
success = extract_value (item, &val);
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
|
|
if (sym != NULL && out->is_mi_like_p ()
|
|
&& ! mi_should_print (sym, MI_PRINT_LOCALS))
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
continue;
|
|
}
|
|
|
|
/* If the object did not provide a value, read it. */
|
|
if (val == NULL)
|
|
{
|
|
TRY
|
|
{
|
|
val = read_var_value (sym, sym_block, frame);
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
/* With PRINT_NO_VALUES, MI does not emit a tuple normally as
|
|
each output contains only one field. The exception is
|
|
-stack-list-variables, which always provides a tuple. */
|
|
if (out->is_mi_like_p ())
|
|
{
|
|
if (print_args_field || args_type != NO_VALUES)
|
|
make_cleanup_ui_out_tuple_begin_end (out, NULL);
|
|
}
|
|
TRY
|
|
{
|
|
if (! out->is_mi_like_p ())
|
|
{
|
|
/* If the output is not MI we indent locals. */
|
|
out->spaces (local_indent);
|
|
}
|
|
|
|
out->field_string ("name", sym_name.get ());
|
|
|
|
if (! out->is_mi_like_p ())
|
|
out->text (" = ");
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
|
|
if (args_type == MI_PRINT_SIMPLE_VALUES)
|
|
{
|
|
if (py_print_type (out, val) == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/* CLI always prints values for locals. MI uses the
|
|
simple/no/all system. */
|
|
if (! out->is_mi_like_p ())
|
|
{
|
|
int val_indent = (indent + 1) * 4;
|
|
|
|
if (py_print_value (out, val, &opts, val_indent, args_type,
|
|
language) == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (args_type != NO_VALUES)
|
|
{
|
|
if (py_print_value (out, val, &opts, 0, args_type,
|
|
language) == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (locals_cleanups);
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
do_cleanups (locals_cleanups);
|
|
|
|
TRY
|
|
{
|
|
out->text ("\n");
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
goto error;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
if (item == NULL && PyErr_Occurred ())
|
|
goto error;
|
|
|
|
return EXT_LANG_BT_OK;
|
|
|
|
error:
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
/* Helper function for -stack-list-variables. Returns EXT_LANG_BT_ERROR on
|
|
error, or EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_mi_print_variables (PyObject *filter, struct ui_out *out,
|
|
struct value_print_options *opts,
|
|
enum ext_lang_frame_args args_type,
|
|
struct frame_info *frame)
|
|
{
|
|
struct cleanup *old_chain;
|
|
PyObject *args_iter;
|
|
PyObject *locals_iter;
|
|
|
|
args_iter = get_py_iter_from_func (filter, "frame_args");
|
|
old_chain = make_cleanup_py_xdecref (args_iter);
|
|
if (args_iter == NULL)
|
|
goto error;
|
|
|
|
locals_iter = get_py_iter_from_func (filter, "frame_locals");
|
|
if (locals_iter == NULL)
|
|
goto error;
|
|
|
|
make_cleanup_py_decref (locals_iter);
|
|
make_cleanup_ui_out_list_begin_end (out, "variables");
|
|
|
|
if (args_iter != Py_None)
|
|
if (enumerate_args (args_iter, out, args_type, 1, frame)
|
|
== EXT_LANG_BT_ERROR)
|
|
goto error;
|
|
|
|
if (locals_iter != Py_None)
|
|
if (enumerate_locals (locals_iter, out, 1, args_type, 1, frame)
|
|
== EXT_LANG_BT_ERROR)
|
|
goto error;
|
|
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_OK;
|
|
|
|
error:
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
/* Helper function for printing locals. This function largely just
|
|
creates the wrapping tuple, and calls enumerate_locals. Returns
|
|
EXT_LANG_BT_ERROR on error, or EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_locals (PyObject *filter,
|
|
struct ui_out *out,
|
|
enum ext_lang_frame_args args_type,
|
|
int indent,
|
|
struct frame_info *frame)
|
|
{
|
|
PyObject *locals_iter = get_py_iter_from_func (filter,
|
|
"frame_locals");
|
|
struct cleanup *old_chain = make_cleanup_py_xdecref (locals_iter);
|
|
|
|
if (locals_iter == NULL)
|
|
goto locals_error;
|
|
|
|
make_cleanup_ui_out_list_begin_end (out, "locals");
|
|
|
|
if (locals_iter != Py_None)
|
|
if (enumerate_locals (locals_iter, out, indent, args_type,
|
|
0, frame) == EXT_LANG_BT_ERROR)
|
|
goto locals_error;
|
|
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_OK;
|
|
|
|
locals_error:
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
/* Helper function for printing frame arguments. This function
|
|
largely just creates the wrapping tuple, and calls enumerate_args.
|
|
Returns EXT_LANG_BT_ERROR on error, with any GDB exceptions converted to
|
|
a Python exception, or EXT_LANG_BT_OK on success. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_args (PyObject *filter,
|
|
struct ui_out *out,
|
|
enum ext_lang_frame_args args_type,
|
|
struct frame_info *frame)
|
|
{
|
|
PyObject *args_iter = get_py_iter_from_func (filter, "frame_args");
|
|
struct cleanup *old_chain = make_cleanup_py_xdecref (args_iter);
|
|
|
|
if (args_iter == NULL)
|
|
goto args_error;
|
|
|
|
make_cleanup_ui_out_list_begin_end (out, "args");
|
|
|
|
TRY
|
|
{
|
|
annotate_frame_args ();
|
|
if (! out->is_mi_like_p ())
|
|
out->text (" (");
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
goto args_error;
|
|
}
|
|
END_CATCH
|
|
|
|
if (args_iter != Py_None)
|
|
if (enumerate_args (args_iter, out, args_type, 0, frame)
|
|
== EXT_LANG_BT_ERROR)
|
|
goto args_error;
|
|
|
|
TRY
|
|
{
|
|
if (! out->is_mi_like_p ())
|
|
out->text (")");
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
goto args_error;
|
|
}
|
|
END_CATCH
|
|
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_OK;
|
|
|
|
args_error:
|
|
do_cleanups (old_chain);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
/* Print a single frame to the designated output stream, detecting
|
|
whether the output is MI or console, and formatting the output
|
|
according to the conventions of that protocol. FILTER is the
|
|
frame-filter associated with this frame. FLAGS is an integer
|
|
describing the various print options. The FLAGS variables is
|
|
described in "apply_frame_filter" function. ARGS_TYPE is an
|
|
enumerator describing the argument format. OUT is the output
|
|
stream to print, INDENT is the level of indention for this frame
|
|
(in the case of elided frames), and LEVELS_PRINTED is a hash-table
|
|
containing all the frames level that have already been printed.
|
|
If a frame level has been printed, do not print it again (in the
|
|
case of elided frames). Returns EXT_LANG_BT_ERROR on error, with any
|
|
GDB exceptions converted to a Python exception, or EXT_LANG_BT_COMPLETED
|
|
on success. It can also throw an exception RETURN_QUIT. */
|
|
|
|
static enum ext_lang_bt_status
|
|
py_print_frame (PyObject *filter, int flags,
|
|
enum ext_lang_frame_args args_type,
|
|
struct ui_out *out, int indent, htab_t levels_printed)
|
|
{
|
|
int has_addr = 0;
|
|
CORE_ADDR address = 0;
|
|
struct gdbarch *gdbarch = NULL;
|
|
struct frame_info *frame = NULL;
|
|
struct cleanup *cleanup_stack;
|
|
struct value_print_options opts;
|
|
PyObject *py_inf_frame;
|
|
int print_level, print_frame_info, print_args, print_locals;
|
|
gdb::unique_xmalloc_ptr<char> function_to_free;
|
|
|
|
/* Extract print settings from FLAGS. */
|
|
print_level = (flags & PRINT_LEVEL) ? 1 : 0;
|
|
print_frame_info = (flags & PRINT_FRAME_INFO) ? 1 : 0;
|
|
print_args = (flags & PRINT_ARGS) ? 1 : 0;
|
|
print_locals = (flags & PRINT_LOCALS) ? 1 : 0;
|
|
|
|
get_user_print_options (&opts);
|
|
|
|
/* Get the underlying frame. This is needed to determine GDB
|
|
architecture, and also, in the cases of frame variables/arguments to
|
|
read them if they returned filter object requires us to do so. */
|
|
py_inf_frame = PyObject_CallMethod (filter, "inferior_frame", NULL);
|
|
if (py_inf_frame == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
|
|
frame = frame_object_to_frame_info (py_inf_frame);;
|
|
|
|
Py_DECREF (py_inf_frame);
|
|
|
|
if (frame == NULL)
|
|
return EXT_LANG_BT_ERROR;
|
|
|
|
TRY
|
|
{
|
|
gdbarch = get_frame_arch (frame);
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
/* stack-list-variables. */
|
|
if (print_locals && print_args && ! print_frame_info)
|
|
{
|
|
if (py_mi_print_variables (filter, out, &opts,
|
|
args_type, frame) == EXT_LANG_BT_ERROR)
|
|
return EXT_LANG_BT_ERROR;
|
|
return EXT_LANG_BT_COMPLETED;
|
|
}
|
|
|
|
cleanup_stack = make_cleanup (null_cleanup, NULL);
|
|
|
|
/* -stack-list-locals does not require a
|
|
wrapping frame attribute. */
|
|
if (print_frame_info || (print_args && ! print_locals))
|
|
make_cleanup_ui_out_tuple_begin_end (out, "frame");
|
|
|
|
if (print_frame_info)
|
|
{
|
|
/* Elided frames are also printed with this function (recursively)
|
|
and are printed with indention. */
|
|
if (indent > 0)
|
|
{
|
|
TRY
|
|
{
|
|
out->spaces (indent * 4);
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
/* The address is required for frame annotations, and also for
|
|
address printing. */
|
|
if (PyObject_HasAttrString (filter, "address"))
|
|
{
|
|
PyObject *paddr = PyObject_CallMethod (filter, "address", NULL);
|
|
|
|
if (paddr == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
if (paddr != Py_None)
|
|
{
|
|
if (get_addr_from_python (paddr, &address) < 0)
|
|
{
|
|
Py_DECREF (paddr);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
has_addr = 1;
|
|
}
|
|
Py_DECREF (paddr);
|
|
}
|
|
}
|
|
|
|
/* Print frame level. MI does not require the level if
|
|
locals/variables only are being printed. */
|
|
if ((print_frame_info || print_args) && print_level)
|
|
{
|
|
struct frame_info **slot;
|
|
int level;
|
|
|
|
slot = (struct frame_info **) htab_find_slot (levels_printed,
|
|
frame, INSERT);
|
|
TRY
|
|
{
|
|
level = frame_relative_level (frame);
|
|
|
|
/* Check if this frame has already been printed (there are cases
|
|
where elided synthetic dummy-frames have to 'borrow' the frame
|
|
architecture from the eliding frame. If that is the case, do
|
|
not print 'level', but print spaces. */
|
|
if (*slot == frame)
|
|
out->field_skip ("level");
|
|
else
|
|
{
|
|
*slot = frame;
|
|
annotate_frame_begin (print_level ? level : 0,
|
|
gdbarch, address);
|
|
out->text ("#");
|
|
out->field_fmt_int (2, ui_left, "level",
|
|
level);
|
|
}
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
if (print_frame_info)
|
|
{
|
|
/* Print address to the address field. If an address is not provided,
|
|
print nothing. */
|
|
if (opts.addressprint && has_addr)
|
|
{
|
|
TRY
|
|
{
|
|
annotate_frame_address ();
|
|
out->field_core_addr ("addr", gdbarch, address);
|
|
annotate_frame_address_end ();
|
|
out->text (" in ");
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
/* Print frame function name. */
|
|
if (PyObject_HasAttrString (filter, "function"))
|
|
{
|
|
PyObject *py_func = PyObject_CallMethod (filter, "function", NULL);
|
|
struct cleanup *py_func_cleanup;
|
|
const char *function = NULL;
|
|
|
|
if (py_func == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
py_func_cleanup = make_cleanup_py_decref (py_func);
|
|
|
|
if (gdbpy_is_string (py_func))
|
|
{
|
|
function_to_free = python_string_to_host_string (py_func);
|
|
|
|
if (function_to_free == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
function = function_to_free.get ();
|
|
}
|
|
else if (PyLong_Check (py_func))
|
|
{
|
|
CORE_ADDR addr;
|
|
struct bound_minimal_symbol msymbol;
|
|
|
|
if (get_addr_from_python (py_func, &addr) < 0)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
msymbol = lookup_minimal_symbol_by_pc (addr);
|
|
if (msymbol.minsym != NULL)
|
|
function = MSYMBOL_PRINT_NAME (msymbol.minsym);
|
|
}
|
|
else if (py_func != Py_None)
|
|
{
|
|
PyErr_SetString (PyExc_RuntimeError,
|
|
_("FrameDecorator.function: expecting a " \
|
|
"String, integer or None."));
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
TRY
|
|
{
|
|
annotate_frame_function_name ();
|
|
if (function == NULL)
|
|
out->field_skip ("func");
|
|
else
|
|
out->field_string ("func", function);
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
do_cleanups (py_func_cleanup);
|
|
}
|
|
}
|
|
|
|
|
|
/* Frame arguments. Check the result, and error if something went
|
|
wrong. */
|
|
if (print_args)
|
|
{
|
|
if (py_print_args (filter, out, args_type, frame) == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
}
|
|
|
|
/* File name/source/line number information. */
|
|
if (print_frame_info)
|
|
{
|
|
TRY
|
|
{
|
|
annotate_frame_source_begin ();
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
|
|
if (PyObject_HasAttrString (filter, "filename"))
|
|
{
|
|
PyObject *py_fn = PyObject_CallMethod (filter, "filename", NULL);
|
|
struct cleanup *py_fn_cleanup;
|
|
|
|
if (py_fn == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
py_fn_cleanup = make_cleanup_py_decref (py_fn);
|
|
|
|
if (py_fn != Py_None)
|
|
{
|
|
gdb::unique_xmalloc_ptr<char>
|
|
filename (python_string_to_host_string (py_fn));
|
|
|
|
if (filename == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
TRY
|
|
{
|
|
out->wrap_hint (" ");
|
|
out->text (" at ");
|
|
annotate_frame_source_file ();
|
|
out->field_string ("file", filename.get ());
|
|
annotate_frame_source_file_end ();
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
do_cleanups (py_fn_cleanup);
|
|
}
|
|
|
|
if (PyObject_HasAttrString (filter, "line"))
|
|
{
|
|
PyObject *py_line = PyObject_CallMethod (filter, "line", NULL);
|
|
struct cleanup *py_line_cleanup;
|
|
int line;
|
|
|
|
if (py_line == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
py_line_cleanup = make_cleanup_py_decref (py_line);
|
|
|
|
if (py_line != Py_None)
|
|
{
|
|
line = PyLong_AsLong (py_line);
|
|
if (PyErr_Occurred ())
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
|
|
TRY
|
|
{
|
|
out->text (":");
|
|
annotate_frame_source_line ();
|
|
out->field_int ("line", line);
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
do_cleanups (py_line_cleanup);
|
|
}
|
|
}
|
|
|
|
/* For MI we need to deal with the "children" list population of
|
|
elided frames, so if MI output detected do not send newline. */
|
|
if (! out->is_mi_like_p ())
|
|
{
|
|
TRY
|
|
{
|
|
annotate_frame_end ();
|
|
out->text ("\n");
|
|
}
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
{
|
|
gdbpy_convert_exception (except);
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
if (print_locals)
|
|
{
|
|
if (py_print_locals (filter, out, args_type, indent,
|
|
frame) == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
}
|
|
|
|
{
|
|
PyObject *elided;
|
|
struct cleanup *elided_cleanup;
|
|
|
|
/* Finally recursively print elided frames, if any. */
|
|
elided = get_py_iter_from_func (filter, "elided");
|
|
if (elided == NULL)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
elided_cleanup = make_cleanup_py_decref (elided);
|
|
|
|
if (elided != Py_None)
|
|
{
|
|
PyObject *item;
|
|
|
|
make_cleanup_ui_out_list_begin_end (out, "children");
|
|
|
|
if (! out->is_mi_like_p ())
|
|
indent++;
|
|
|
|
while ((item = PyIter_Next (elided)))
|
|
{
|
|
struct cleanup *item_cleanup = make_cleanup_py_decref (item);
|
|
|
|
enum ext_lang_bt_status success = py_print_frame (item, flags,
|
|
args_type, out,
|
|
indent,
|
|
levels_printed);
|
|
|
|
do_cleanups (item_cleanup);
|
|
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
}
|
|
if (item == NULL && PyErr_Occurred ())
|
|
{
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|
|
}
|
|
do_cleanups (elided_cleanup);
|
|
}
|
|
|
|
do_cleanups (cleanup_stack);
|
|
return EXT_LANG_BT_COMPLETED;
|
|
}
|
|
|
|
/* Helper function to initiate frame filter invocation at starting
|
|
frame FRAME. */
|
|
|
|
static PyObject *
|
|
bootstrap_python_frame_filters (struct frame_info *frame,
|
|
int frame_low, int frame_high)
|
|
{
|
|
struct cleanup *cleanups =
|
|
make_cleanup (null_cleanup, NULL);
|
|
PyObject *module, *sort_func, *iterable, *frame_obj, *iterator;
|
|
PyObject *py_frame_low, *py_frame_high;
|
|
|
|
frame_obj = frame_info_to_frame_object (frame);
|
|
if (frame_obj == NULL)
|
|
goto error;
|
|
make_cleanup_py_decref (frame_obj);
|
|
|
|
module = PyImport_ImportModule ("gdb.frames");
|
|
if (module == NULL)
|
|
goto error;
|
|
make_cleanup_py_decref (module);
|
|
|
|
sort_func = PyObject_GetAttrString (module, "execute_frame_filters");
|
|
if (sort_func == NULL)
|
|
goto error;
|
|
make_cleanup_py_decref (sort_func);
|
|
|
|
py_frame_low = PyInt_FromLong (frame_low);
|
|
if (py_frame_low == NULL)
|
|
goto error;
|
|
make_cleanup_py_decref (py_frame_low);
|
|
|
|
py_frame_high = PyInt_FromLong (frame_high);
|
|
if (py_frame_high == NULL)
|
|
goto error;
|
|
make_cleanup_py_decref (py_frame_high);
|
|
|
|
iterable = PyObject_CallFunctionObjArgs (sort_func, frame_obj,
|
|
py_frame_low,
|
|
py_frame_high,
|
|
NULL);
|
|
if (iterable == NULL)
|
|
goto error;
|
|
|
|
do_cleanups (cleanups);
|
|
|
|
if (iterable != Py_None)
|
|
{
|
|
iterator = PyObject_GetIter (iterable);
|
|
Py_DECREF (iterable);
|
|
}
|
|
else
|
|
{
|
|
return iterable;
|
|
}
|
|
|
|
return iterator;
|
|
|
|
error:
|
|
do_cleanups (cleanups);
|
|
return NULL;
|
|
}
|
|
|
|
/* This is the only publicly exported function in this file. FRAME
|
|
is the source frame to start frame-filter invocation. FLAGS is an
|
|
integer holding the flags for printing. The following elements of
|
|
the FRAME_FILTER_FLAGS enum denotes the make-up of FLAGS:
|
|
PRINT_LEVEL is a flag indicating whether to print the frame's
|
|
relative level in the output. PRINT_FRAME_INFO is a flag that
|
|
indicates whether this function should print the frame
|
|
information, PRINT_ARGS is a flag that indicates whether to print
|
|
frame arguments, and PRINT_LOCALS, likewise, with frame local
|
|
variables. ARGS_TYPE is an enumerator describing the argument
|
|
format, OUT is the output stream to print. FRAME_LOW is the
|
|
beginning of the slice of frames to print, and FRAME_HIGH is the
|
|
upper limit of the frames to count. Returns EXT_LANG_BT_ERROR on error,
|
|
or EXT_LANG_BT_COMPLETED on success. */
|
|
|
|
enum ext_lang_bt_status
|
|
gdbpy_apply_frame_filter (const struct extension_language_defn *extlang,
|
|
struct frame_info *frame, int flags,
|
|
enum ext_lang_frame_args args_type,
|
|
struct ui_out *out, int frame_low, int frame_high)
|
|
{
|
|
struct gdbarch *gdbarch = NULL;
|
|
struct cleanup *cleanups;
|
|
enum ext_lang_bt_status success = EXT_LANG_BT_ERROR;
|
|
PyObject *iterable;
|
|
PyObject *item;
|
|
htab_t levels_printed;
|
|
|
|
if (!gdb_python_initialized)
|
|
return EXT_LANG_BT_NO_FILTERS;
|
|
|
|
TRY
|
|
{
|
|
gdbarch = get_frame_arch (frame);
|
|
}
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
{
|
|
/* Let gdb try to print the stack trace. */
|
|
return EXT_LANG_BT_NO_FILTERS;
|
|
}
|
|
END_CATCH
|
|
|
|
cleanups = ensure_python_env (gdbarch, current_language);
|
|
|
|
iterable = bootstrap_python_frame_filters (frame, frame_low, frame_high);
|
|
|
|
if (iterable == NULL)
|
|
{
|
|
/* Normally if there is an error GDB prints the exception,
|
|
abandons the backtrace and exits. The user can then call "bt
|
|
no-filters", and get a default backtrace (it would be
|
|
confusing to automatically start a standard backtrace halfway
|
|
through a Python filtered backtrace). However in the case
|
|
where GDB cannot initialize the frame filters (most likely
|
|
due to incorrect auto-load paths), GDB has printed nothing.
|
|
In this case it is OK to print the default backtrace after
|
|
printing the error message. GDB returns EXT_LANG_BT_NO_FILTERS
|
|
here to signify there are no filters after printing the
|
|
initialization error. This return code will trigger a
|
|
default backtrace. */
|
|
|
|
gdbpy_print_stack ();
|
|
do_cleanups (cleanups);
|
|
return EXT_LANG_BT_NO_FILTERS;
|
|
}
|
|
|
|
/* If iterable is None, then there are no frame filters registered.
|
|
If this is the case, defer to default GDB printing routines in MI
|
|
and CLI. */
|
|
make_cleanup_py_decref (iterable);
|
|
if (iterable == Py_None)
|
|
{
|
|
success = EXT_LANG_BT_NO_FILTERS;
|
|
goto done;
|
|
}
|
|
|
|
levels_printed = htab_create (20,
|
|
htab_hash_pointer,
|
|
htab_eq_pointer,
|
|
NULL);
|
|
make_cleanup_htab_delete (levels_printed);
|
|
|
|
while ((item = PyIter_Next (iterable)))
|
|
{
|
|
struct cleanup *item_cleanup = make_cleanup_py_decref (item);
|
|
|
|
success = py_print_frame (item, flags, args_type, out, 0,
|
|
levels_printed);
|
|
|
|
do_cleanups (item_cleanup);
|
|
|
|
/* Do not exit on error printing a single frame. Print the
|
|
error and continue with other frames. */
|
|
if (success == EXT_LANG_BT_ERROR)
|
|
gdbpy_print_stack ();
|
|
}
|
|
|
|
if (item == NULL && PyErr_Occurred ())
|
|
goto error;
|
|
|
|
done:
|
|
do_cleanups (cleanups);
|
|
return success;
|
|
|
|
/* Exit and abandon backtrace on error, printing the exception that
|
|
is set. */
|
|
error:
|
|
gdbpy_print_stack ();
|
|
do_cleanups (cleanups);
|
|
return EXT_LANG_BT_ERROR;
|
|
}
|