mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 11:04:18 +08:00
d7e747318f
This patch starts from the desire to eliminate make_cleanup_ui_file_delete, but then goes beyond. It makes ui_file & friends a real C++ class hierarchy, and switches temporary ui_file-like objects to stack-based allocation. - mem_fileopen -> string_file mem_fileopen is replaced with a new string_file class that is treated as a value class created on the stack. This alone eliminates most make_cleanup_ui_file_delete calls, and, simplifies code a whole lot (diffstat shows around 1k loc dropped.) string_file's internal buffer is a std::string, thus the "string" in the name. This simplifies the implementation much, compared to mem_fileopen, which managed growing its internal buffer manually. - ui_file_as_string, ui_file_strdup, ui_file_obsavestring all gone The new string_file class has a string() method that provides direct writable access to the internal std::string buffer. This replaced ui_file_as_string, which forced a copy of the same data the stream had inside. With direct access via a writable reference, we can instead move the string out of the string_stream, avoiding deep string copying. Related, ui_file_xstrdup calls are replaced with xstrdup'ping the stream's string, and ui_file_obsavestring is replaced by obstack_copy0. With all those out of the way, getting rid of the weird ui_file_put mechanism was possible. - New ui_file::printf, ui_file::puts, etc. methods These simplify / clarify client code. I considered splitting client-code changes, like these, e.g.: - stb = mem_fileopen (); - fprintf_unfiltered (stb, "%s%s%s", - _("The valid values are:\n"), - regdesc, - _("The default is \"std\".")); + string_file stb; + stb.printf ("%s%s%s", + _("The valid values are:\n"), + regdesc, + _("The default is \"std\".")); In two steps, with the first step leaving fprintf_unfiltered (etc.) calls in place, and only afterwards do a pass to change all those to call stb.printf etc.. I didn't do that split, because (when I tried), it turned out to be pointless make-work: the first pass would have to touch the fprintf_unfiltered line anyway, to replace "stb" with "&stb". - gdb_fopen replaced with stack-based objects This avoids the need for cleanups or unique_ptr's. I.e., this: struct ui_file *file = gdb_fopen (filename, "w"); if (filename == NULL) perror_with_name (filename); cleanups = make_cleanup_ui_file_delete (file); // use file. do_cleanups (cleanups); is replaced with this: stdio_file file; if (!file.open (filename, "w")) perror_with_name (filename); // use file. - odd contorsions in null_file_write / null_file_fputs around when to call to_fputs / to_write eliminated. - Global null_stream object A few places that were allocating a ui_file in order to print to "nowhere" are adjusted to instead refer to a new 'null_stream' global stream. - TUI's tui_sfileopen eliminated. TUI's ui_file much simplified The TUI's ui_file was serving a dual purpose. It supported being used as string buffer, and supported being backed by a stdio FILE. The string buffer part is gone, replaced by using of string_file. The 'FILE *' support is now much simplified, by making the TUI's ui_file inherit from stdio_file. gdb/ChangeLog: 2017-02-02 Pedro Alves <palves@redhat.com> * ada-lang.c (type_as_string): Use string_file. * ada-valprint.c (ada_print_floating): Use string_file. * ada-varobj.c (ada_varobj_scalar_image) (ada_varobj_get_value_image): Use string_file. * aix-thread.c (aix_thread_extra_thread_info): Use string_file. * arm-tdep.c (_initialize_arm_tdep): Use string_printf. * breakpoint.c (update_inserted_breakpoint_locations) (insert_breakpoint_locations, reattach_breakpoints) (print_breakpoint_location, print_one_detail_ranged_breakpoint) (print_it_watchpoint): Use string_file. (save_breakpoints): Use stdio_file. * c-exp.y (oper): Use string_file. * cli/cli-logging.c (set_logging_redirect): Use ui_file_up and tee_file. (pop_output_files): Use delete. (handle_redirections): Use stdio_file and tee_file. * cli/cli-setshow.c (do_show_command): Use string_file. * compile/compile-c-support.c (c_compute_program): Use string_file. * compile/compile-c-symbols.c (generate_vla_size): Take a 'string_file &' instead of a 'ui_file *'. (generate_c_for_for_one_variable): Take a 'string_file &' instead of a 'ui_file *'. Use string_file. (generate_c_for_variable_locations): Take a 'string_file &' instead of a 'ui_file *'. * compile/compile-internal.h (generate_c_for_for_one_variable): Take a 'string_file &' instead of a 'ui_file *'. * compile/compile-loc2c.c (push, pushf, unary, binary) (print_label, pushf_register_address, pushf_register) (do_compile_dwarf_expr_to_c): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * compile/compile.c (compile_to_object): Use string_file. * compile/compile.h (compile_dwarf_expr_to_c) (compile_dwarf_bounds_to_c): Take a 'string_file &' instead of a 'ui_file *'. * cp-support.c (inspect_type): Use string_file and obstack_copy0. (replace_typedefs_qualified_name): Use string_file and obstack_copy0. * disasm.c (gdb_pretty_print_insn): Use string_file. (gdb_disassembly): Adjust reference the null_stream global. (do_ui_file_delete): Delete. (gdb_insn_length): Use null_stream. * dummy-frame.c (maintenance_print_dummy_frames): Use stdio_file. * dwarf2loc.c (dwarf2_compile_property_to_c) (locexpr_generate_c_location, loclist_generate_c_location): Take a 'string_file &' instead of a 'ui_file *'. * dwarf2loc.h (dwarf2_compile_property_to_c): Likewise. * dwarf2read.c (do_ui_file_peek_last): Delete. (dwarf2_compute_name): Use string_file. * event-top.c (gdb_setup_readline): Use stdio_file. * gdbarch.sh (verify_gdbarch): Use string_file. * gdbtypes.c (safe_parse_type): Use null_stream. * guile/scm-breakpoint.c (gdbscm_breakpoint_commands): Use string_file. * guile/scm-disasm.c (gdbscm_print_insn_from_port): Take a 'string_file *' instead of a 'ui_file *'. (gdbscm_arch_disassemble): Use string_file. * guile/scm-frame.c (frscm_print_frame_smob): Use string_file. * guile/scm-ports.c (class ioscm_file_port): Now a class that inherits from ui_file. (ioscm_file_port_delete, ioscm_file_port_rewind) (ioscm_file_port_put): Delete. (ioscm_file_port_write): Rename to ... (ioscm_file_port::write): ... this. Remove file_port_magic checks. (ioscm_file_port_new): Delete. (ioscm_with_output_to_port_worker): Use ioscm_file_port and ui_file_up. * guile/scm-type.c (tyscm_type_name): Use string_file. * guile/scm-value.c (vlscm_print_value_smob, gdbscm_value_print): Use string_file. * infcmd.c (print_return_value_1): Use string_file. * infrun.c (print_target_wait_results): Use string_file. * language.c (add_language): Use string_file. * location.c (explicit_to_string_internal): Use string_file. * main.c (captured_main_1): Use null_file. * maint.c (maintenance_print_architecture): Use stdio_file. * mi/mi-cmd-stack.c (list_arg_or_local): Use string_file. * mi/mi-common.h (struct mi_interp) <out, err, log, targ, event_channel>: Change type to mi_console_file pointer. * mi/mi-console.c (mi_console_file_fputs, mi_console_file_flush) (mi_console_file_delete): Delete. (struct mi_console_file): Delete. (mi_console_file_magic): Delete. (mi_console_file_new): Delete. (mi_console_file::mi_console_file): New. (mi_console_file_delete): Delete. (mi_console_file_fputs): Delete. (mi_console_file::write): New. (mi_console_raw_packet): Delete. (mi_console_file::flush): New. (mi_console_file_flush): Delete. (mi_console_set_raw): Rename to ... (mi_console_file::set_raw): ... this. * mi/mi-console.h (class mi_console_file): New class. (mi_console_file_new, mi_console_set_raw): Delete. * mi/mi-interp.c (mi_interpreter_init): Use mi_console_file. (mi_set_logging): Use delete and tee_file. Adjust. * mi/mi-main.c (output_register): Use string_file. (mi_cmd_data_evaluate_expression): Use string_file. (mi_cmd_data_read_memory): Use string_file. (mi_cmd_execute, print_variable_or_computed): Use string_file. * mi/mi-out.c (mi_ui_out::main_stream): New. (mi_ui_out::rewind): Use main_stream and string_file. (mi_ui_out::put): Use main_stream and string_file. (mi_ui_out::mi_ui_out): Remove 'stream' parameter. Allocate a 'string_file' instead. (mi_out_new): Don't allocate a mem_fileopen stream here. * mi/mi-out.h (mi_ui_out::mi_ui_out): Remove 'stream' parameter. (mi_ui_out::main_stream): Declare method. * printcmd.c (eval_command): Use string_file. * psymtab.c (maintenance_print_psymbols): Use stdio_file. * python/py-arch.c (archpy_disassemble): Use string_file. * python/py-breakpoint.c (bppy_get_commands): Use string_file. * python/py-frame.c (frapy_str): Use string_file. * python/py-framefilter.c (py_print_type, py_print_single_arg): Use string_file. * python/py-type.c (typy_str): Use string_file. * python/py-unwind.c (unwind_infopy_str): Use string_file. * python/py-value.c (valpy_str): Use string_file. * record-btrace.c (btrace_insn_history): Use string_file. * regcache.c (regcache_print): Use stdio_file. * reggroups.c (maintenance_print_reggroups): Use stdio_file. * remote.c (escape_buffer): Use string_file. * rust-lang.c (rust_get_disr_info): Use string_file. * serial.c (serial_open_ops_1): Use stdio_file. (do_serial_close): Use delete. * stack.c (print_frame_arg): Use string_file. (print_frame_args): Remove local mem_fileopen stream, not used. (print_frame): Use string_file. * symmisc.c (maintenance_print_symbols): Use stdio_file. * symtab.h (struct symbol_computed_ops) <generate_c_location>: Take a 'string_file *' instead of a 'ui_file *'. * top.c (new_ui): Use stdio_file and stderr_file. (free_ui): Use delete. (execute_command_to_string): Use string_file. (quit_confirm): Use string_file. * tracepoint.c (collection_list::append_exp): Use string_file. * tui/tui-disasm.c (tui_disassemble): Use string_file. * tui/tui-file.c: Don't include "ui-file.h". (enum streamtype, struct tui_stream): Delete. (tui_file_new, tui_file_delete, tui_fileopen, tui_sfileopen) (tui_file_isatty, tui_file_rewind, tui_file_put): Delete. (tui_file::tui_file): New method. (tui_file_fputs): Delete. (tui_file_get_strbuf): Delete. (tui_file::puts): New method. (tui_file_adjust_strbuf): Delete. (tui_file_flush): Delete. (tui_file::flush): New method. * tui/tui-file.h: Tweak intro comment. Include ui-file.h. (tui_fileopen, tui_sfileopen, tui_file_get_strbuf) (tui_file_adjust_strbuf): Delete declarations. (class tui_file): New class. * tui/tui-io.c (tui_initialize_io): Use tui_file. * tui/tui-regs.c (tui_restore_gdbout): Use delete. (tui_register_format): Use string_stream. * tui/tui-stack.c (tui_make_status_line): Use string_file. (tui_get_function_from_frame): Use string_file. * typeprint.c (type_to_string): Use string_file. * ui-file.c (struct ui_file, ui_file_magic, ui_file_new): Delete. (null_stream): New global. (ui_file_delete): Delete. (ui_file::ui_file): New. (null_file_isatty): Delete. (ui_file::~ui_file): New. (null_file_rewind): Delete. (ui_file::printf): New. (null_file_put): Delete. (null_file_flush): Delete. (ui_file::putstr): New. (null_file_write): Delete. (ui_file::putstrn): New. (null_file_read): Delete. (ui_file::putc): New. (null_file_fputs): Delete. (null_file_write_async_safe): Delete. (ui_file::vprintf): New. (null_file_delete): Delete. (null_file::write): New. (null_file_fseek): Delete. (null_file::puts): New. (ui_file_data): Delete. (null_file::write_async_safe): New. (gdb_flush, ui_file_isatty): Adjust. (ui_file_put, ui_file_rewind): Delete. (ui_file_write): Adjust. (ui_file_write_for_put): Delete. (ui_file_write_async_safe, ui_file_read): Adjust. (ui_file_fseek): Delete. (fputs_unfiltered): Adjust. (set_ui_file_flush, set_ui_file_isatty, set_ui_file_rewind) (set_ui_file_put, set_ui_file_write, set_ui_file_write_async_safe) (set_ui_file_read, set_ui_file_fputs, set_ui_file_fseek) (set_ui_file_data): Delete. (string_file::~string_file, string_file::write) (struct accumulated_ui_file, do_ui_file_xstrdup, ui_file_xstrdup) (do_ui_file_as_string, ui_file_as_string): Delete. (do_ui_file_obsavestring, ui_file_obsavestring): Delete. (struct mem_file): Delete. (mem_file_new): Delete. (stdio_file::stdio_file): New. (mem_file_delete): Delete. (stdio_file::stdio_file): New. (mem_fileopen): Delete. (stdio_file::~stdio_file): New. (mem_file_rewind): Delete. (stdio_file::set_stream): New. (mem_file_put): Delete. (stdio_file::open): New. (mem_file_write): Delete. (stdio_file_magic, struct stdio_file): Delete. (stdio_file_new, stdio_file_delete, stdio_file_flush): Delete. (stdio_file::flush): New. (stdio_file_read): Rename to ... (stdio_file::read): ... this. Adjust. (stdio_file_write): Rename to ... (stdio_file::write): ... this. Adjust. (stdio_file_write_async_safe): Rename to ... (stdio_file::write_async_safe) ... this. Adjust. (stdio_file_fputs): Rename to ... (stdio_file::puts) ... this. Adjust. (stdio_file_isatty): Delete. (stdio_file_fseek): Delete. (stdio_file::isatty): New. (stderr_file_write): Rename to ... (stderr_file::write) ... this. Adjust. (stderr_file_fputs): Rename to ... (stderr_file::puts) ... this. Adjust. (stderr_fileopen, stdio_fileopen, gdb_fopen): Delete. (stderr_file::stderr_file): New. (tee_file_magic): Delete. (struct tee_file): Delete. (tee_file::tee_file): New. (tee_file_new): Delete. (tee_file::~tee_file): New. (tee_file_delete): Delete. (tee_file_flush): Rename to ... (tee_file::flush): ... this. Adjust. (tee_file_write): Rename to ... (tee_file::write): ... this. Adjust. (tee_file::write_async_safe): New. (tee_file_fputs): Rename to ... (tee_file::puts): ... this. Adjust. (tee_file_isatty): Rename to ... (tee_file::isatty): ... this. Adjust. * ui-file.h (struct obstack, struct ui_file): Don't forward-declare. (ui_file_new, ui_file_flush_ftype, set_ui_file_flush) (ui_file_write_ftype) (set_ui_file_write, ui_file_fputs_ftype, set_ui_file_fputs) (ui_file_write_async_safe_ftype, set_ui_file_write_async_safe) (ui_file_read_ftype, set_ui_file_read, ui_file_isatty_ftype) (set_ui_file_isatty, ui_file_rewind_ftype, set_ui_file_rewind) (ui_file_put_method_ftype, ui_file_put_ftype, set_ui_file_put) (ui_file_delete_ftype, set_ui_file_data, ui_file_fseek_ftype) (set_ui_file_fseek): Delete. (ui_file_data, ui_file_delete, ui_file_rewind) (struct ui_file): New. (ui_file_up): New. (class null_file): New. (null_stream): Declare. (ui_file_write_for_put, ui_file_put): Delete. (ui_file_xstrdup, ui_file_as_string, ui_file_obsavestring): Delete. (ui_file_fseek, mem_fileopen, stdio_fileopen, stderr_fileopen) (gdb_fopen, tee_file_new): Delete. (struct string_file): New. (struct stdio_file): New. (stdio_file_up): New. (struct stderr_file): New. (class tee_file): New. * ui-out.c (ui_out::field_stream): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * ui-out.h (class ui_out) <field_stream>: Likewise. * utils.c (do_ui_file_delete, make_cleanup_ui_file_delete) (null_stream): Delete. (error_stream): Take a 'string_file &' instead of a 'ui_file *'. Adjust. * utils.h (struct ui_file): Delete forward declaration.. (make_cleanup_ui_file_delete, null_stream): Delete declarations. (error_stream): Take a 'string_file &' instead of a 'ui_file *'. * varobj.c (varobj_value_get_print_value): Use string_file. * xtensa-tdep.c (xtensa_verify_config): Use string_file. * gdbarch.c: Regenerate.
1010 lines
31 KiB
C
1010 lines
31 KiB
C
/* varobj support for Ada.
|
|
|
|
Copyright (C) 2012-2017 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 "ada-lang.h"
|
|
#include "varobj.h"
|
|
#include "language.h"
|
|
#include "valprint.h"
|
|
|
|
/* Implementation principle used in this unit:
|
|
|
|
For our purposes, the meat of the varobj object is made of two
|
|
elements: The varobj's (struct) value, and the varobj's (struct)
|
|
type. In most situations, the varobj has a non-NULL value, and
|
|
the type becomes redundant, as it can be directly derived from
|
|
the value. In the initial implementation of this unit, most
|
|
routines would only take a value, and return a value.
|
|
|
|
But there are many situations where it is possible for a varobj
|
|
to have a NULL value. For instance, if the varobj becomes out of
|
|
scope. Or better yet, when the varobj is the child of another
|
|
NULL pointer varobj. In that situation, we must rely on the type
|
|
instead of the value to create the child varobj.
|
|
|
|
That's why most functions below work with a (value, type) pair.
|
|
The value may or may not be NULL. But the type is always expected
|
|
to be set. When the value is NULL, then we work with the type
|
|
alone, and keep the value NULL. But when the value is not NULL,
|
|
then we work using the value, because it provides more information.
|
|
But we still always set the type as well, even if that type could
|
|
easily be derived from the value. The reason behind this is that
|
|
it allows the code to use the type without having to worry about
|
|
it being set or not. It makes the code clearer. */
|
|
|
|
static int ada_varobj_get_number_of_children (struct value *parent_value,
|
|
struct type *parent_type);
|
|
|
|
/* A convenience function that decodes the VALUE_PTR/TYPE_PTR couple:
|
|
If there is a value (*VALUE_PTR not NULL), then perform the decoding
|
|
using it, and compute the associated type from the resulting value.
|
|
Otherwise, compute a static approximation of *TYPE_PTR, leaving
|
|
*VALUE_PTR unchanged.
|
|
|
|
The results are written in place. */
|
|
|
|
static void
|
|
ada_varobj_decode_var (struct value **value_ptr, struct type **type_ptr)
|
|
{
|
|
if (*value_ptr)
|
|
{
|
|
*value_ptr = ada_get_decoded_value (*value_ptr);
|
|
*type_ptr = ada_check_typedef (value_type (*value_ptr));
|
|
}
|
|
else
|
|
*type_ptr = ada_get_decoded_type (*type_ptr);
|
|
}
|
|
|
|
/* Return a string containing an image of the given scalar value.
|
|
VAL is the numeric value, while TYPE is the value's type.
|
|
This is useful for plain integers, of course, but even more
|
|
so for enumerated types. */
|
|
|
|
static std::string
|
|
ada_varobj_scalar_image (struct type *type, LONGEST val)
|
|
{
|
|
string_file buf;
|
|
|
|
ada_print_scalar (type, val, &buf);
|
|
return std::move (buf.string ());
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair designates
|
|
a struct or union, compute the (CHILD_VALUE, CHILD_TYPE) couple
|
|
corresponding to the field number FIELDNO. */
|
|
|
|
static void
|
|
ada_varobj_struct_elt (struct value *parent_value,
|
|
struct type *parent_type,
|
|
int fieldno,
|
|
struct value **child_value,
|
|
struct type **child_type)
|
|
{
|
|
struct value *value = NULL;
|
|
struct type *type = NULL;
|
|
|
|
if (parent_value)
|
|
{
|
|
value = value_field (parent_value, fieldno);
|
|
type = value_type (value);
|
|
}
|
|
else
|
|
type = TYPE_FIELD_TYPE (parent_type, fieldno);
|
|
|
|
if (child_value)
|
|
*child_value = value;
|
|
if (child_type)
|
|
*child_type = type;
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a pointer or
|
|
reference, return a (CHILD_VALUE, CHILD_TYPE) couple corresponding
|
|
to the dereferenced value. */
|
|
|
|
static void
|
|
ada_varobj_ind (struct value *parent_value,
|
|
struct type *parent_type,
|
|
struct value **child_value,
|
|
struct type **child_type)
|
|
{
|
|
struct value *value = NULL;
|
|
struct type *type = NULL;
|
|
|
|
if (ada_is_array_descriptor_type (parent_type))
|
|
{
|
|
/* This can only happen when PARENT_VALUE is NULL. Otherwise,
|
|
ada_get_decoded_value would have transformed our parent_type
|
|
into a simple array pointer type. */
|
|
gdb_assert (parent_value == NULL);
|
|
gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF);
|
|
|
|
/* Decode parent_type by the equivalent pointer to (decoded)
|
|
array. */
|
|
while (TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF)
|
|
parent_type = TYPE_TARGET_TYPE (parent_type);
|
|
parent_type = ada_coerce_to_simple_array_type (parent_type);
|
|
parent_type = lookup_pointer_type (parent_type);
|
|
}
|
|
|
|
/* If parent_value is a null pointer, then only perform static
|
|
dereferencing. We cannot dereference null pointers. */
|
|
if (parent_value && value_as_address (parent_value) == 0)
|
|
parent_value = NULL;
|
|
|
|
if (parent_value)
|
|
{
|
|
value = ada_value_ind (parent_value);
|
|
type = value_type (value);
|
|
}
|
|
else
|
|
type = TYPE_TARGET_TYPE (parent_type);
|
|
|
|
if (child_value)
|
|
*child_value = value;
|
|
if (child_type)
|
|
*child_type = type;
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a simple
|
|
array (TYPE_CODE_ARRAY), return the (CHILD_VALUE, CHILD_TYPE)
|
|
pair corresponding to the element at ELT_INDEX. */
|
|
|
|
static void
|
|
ada_varobj_simple_array_elt (struct value *parent_value,
|
|
struct type *parent_type,
|
|
int elt_index,
|
|
struct value **child_value,
|
|
struct type **child_type)
|
|
{
|
|
struct value *value = NULL;
|
|
struct type *type = NULL;
|
|
|
|
if (parent_value)
|
|
{
|
|
struct value *index_value =
|
|
value_from_longest (TYPE_INDEX_TYPE (parent_type), elt_index);
|
|
|
|
value = ada_value_subscript (parent_value, 1, &index_value);
|
|
type = value_type (value);
|
|
}
|
|
else
|
|
type = TYPE_TARGET_TYPE (parent_type);
|
|
|
|
if (child_value)
|
|
*child_value = value;
|
|
if (child_type)
|
|
*child_type = type;
|
|
}
|
|
|
|
/* Given the decoded value and decoded type of a variable object,
|
|
adjust the value and type to those necessary for getting children
|
|
of the variable object.
|
|
|
|
The replacement is performed in place. */
|
|
|
|
static void
|
|
ada_varobj_adjust_for_child_access (struct value **value,
|
|
struct type **type)
|
|
{
|
|
/* Pointers to struct/union types are special: Instead of having
|
|
one child (the struct), their children are the components of
|
|
the struct/union type. We handle this situation by dereferencing
|
|
the (value, type) couple. */
|
|
if (TYPE_CODE (*type) == TYPE_CODE_PTR
|
|
&& (TYPE_CODE (TYPE_TARGET_TYPE (*type)) == TYPE_CODE_STRUCT
|
|
|| TYPE_CODE (TYPE_TARGET_TYPE (*type)) == TYPE_CODE_UNION)
|
|
&& !ada_is_array_descriptor_type (TYPE_TARGET_TYPE (*type))
|
|
&& !ada_is_constrained_packed_array_type (TYPE_TARGET_TYPE (*type)))
|
|
ada_varobj_ind (*value, *type, value, type);
|
|
|
|
/* If this is a tagged type, we need to transform it a bit in order
|
|
to be able to fetch its full view. As always with tagged types,
|
|
we can only do that if we have a value. */
|
|
if (*value != NULL && ada_is_tagged_type (*type, 1))
|
|
{
|
|
*value = ada_tag_value_at_base_address (*value);
|
|
*type = value_type (*value);
|
|
}
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is an array
|
|
(any type of array, "simple" or not), return the number of children
|
|
that this array contains. */
|
|
|
|
static int
|
|
ada_varobj_get_array_number_of_children (struct value *parent_value,
|
|
struct type *parent_type)
|
|
{
|
|
LONGEST lo, hi;
|
|
|
|
if (parent_value == NULL
|
|
&& is_dynamic_type (TYPE_INDEX_TYPE (parent_type)))
|
|
{
|
|
/* This happens when listing the children of an object
|
|
which does not exist in memory (Eg: when requesting
|
|
the children of a null pointer, which is allowed by
|
|
varobj). The array index type being dynamic, we cannot
|
|
determine how many elements this array has. Just assume
|
|
it has none. */
|
|
return 0;
|
|
}
|
|
|
|
if (!get_array_bounds (parent_type, &lo, &hi))
|
|
{
|
|
/* Could not get the array bounds. Pretend this is an empty array. */
|
|
warning (_("unable to get bounds of array, assuming null array"));
|
|
return 0;
|
|
}
|
|
|
|
/* Ada allows the upper bound to be less than the lower bound,
|
|
in order to specify empty arrays... */
|
|
if (hi < lo)
|
|
return 0;
|
|
|
|
return hi - lo + 1;
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair is a struct or
|
|
union, return the number of children this struct contains. */
|
|
|
|
static int
|
|
ada_varobj_get_struct_number_of_children (struct value *parent_value,
|
|
struct type *parent_type)
|
|
{
|
|
int n_children = 0;
|
|
int i;
|
|
|
|
gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT
|
|
|| TYPE_CODE (parent_type) == TYPE_CODE_UNION);
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (parent_type); i++)
|
|
{
|
|
if (ada_is_ignored_field (parent_type, i))
|
|
continue;
|
|
|
|
if (ada_is_wrapper_field (parent_type, i))
|
|
{
|
|
struct value *elt_value;
|
|
struct type *elt_type;
|
|
|
|
ada_varobj_struct_elt (parent_value, parent_type, i,
|
|
&elt_value, &elt_type);
|
|
if (ada_is_tagged_type (elt_type, 0))
|
|
{
|
|
/* We must not use ada_varobj_get_number_of_children
|
|
to determine is element's number of children, because
|
|
this function first calls ada_varobj_decode_var,
|
|
which "fixes" the element. For tagged types, this
|
|
includes reading the object's tag to determine its
|
|
real type, which happens to be the parent_type, and
|
|
leads to an infinite loop (because the element gets
|
|
fixed back into the parent). */
|
|
n_children += ada_varobj_get_struct_number_of_children
|
|
(elt_value, elt_type);
|
|
}
|
|
else
|
|
n_children += ada_varobj_get_number_of_children (elt_value, elt_type);
|
|
}
|
|
else if (ada_is_variant_part (parent_type, i))
|
|
{
|
|
/* In normal situations, the variant part of the record should
|
|
have been "fixed". Or, in other words, it should have been
|
|
replaced by the branch of the variant part that is relevant
|
|
for our value. But there are still situations where this
|
|
can happen, however (Eg. when our parent is a NULL pointer).
|
|
We do not support showing this part of the record for now,
|
|
so just pretend this field does not exist. */
|
|
}
|
|
else
|
|
n_children++;
|
|
}
|
|
|
|
return n_children;
|
|
}
|
|
|
|
/* Assuming that the (PARENT_VALUE, PARENT_TYPE) pair designates
|
|
a pointer, return the number of children this pointer has. */
|
|
|
|
static int
|
|
ada_varobj_get_ptr_number_of_children (struct value *parent_value,
|
|
struct type *parent_type)
|
|
{
|
|
struct type *child_type = TYPE_TARGET_TYPE (parent_type);
|
|
|
|
/* Pointer to functions and to void do not have a child, since
|
|
you cannot print what they point to. */
|
|
if (TYPE_CODE (child_type) == TYPE_CODE_FUNC
|
|
|| TYPE_CODE (child_type) == TYPE_CODE_VOID)
|
|
return 0;
|
|
|
|
/* All other types have 1 child. */
|
|
return 1;
|
|
}
|
|
|
|
/* Return the number of children for the (PARENT_VALUE, PARENT_TYPE)
|
|
pair. */
|
|
|
|
static int
|
|
ada_varobj_get_number_of_children (struct value *parent_value,
|
|
struct type *parent_type)
|
|
{
|
|
ada_varobj_decode_var (&parent_value, &parent_type);
|
|
ada_varobj_adjust_for_child_access (&parent_value, &parent_type);
|
|
|
|
/* A typedef to an array descriptor in fact represents a pointer
|
|
to an unconstrained array. These types always have one child
|
|
(the unconstrained array). */
|
|
if (ada_is_array_descriptor_type (parent_type)
|
|
&& TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF)
|
|
return 1;
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY)
|
|
return ada_varobj_get_array_number_of_children (parent_value,
|
|
parent_type);
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT
|
|
|| TYPE_CODE (parent_type) == TYPE_CODE_UNION)
|
|
return ada_varobj_get_struct_number_of_children (parent_value,
|
|
parent_type);
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_PTR)
|
|
return ada_varobj_get_ptr_number_of_children (parent_value,
|
|
parent_type);
|
|
|
|
/* All other types have no child. */
|
|
return 0;
|
|
}
|
|
|
|
/* Describe the child of the (PARENT_VALUE, PARENT_TYPE) pair
|
|
whose index is CHILD_INDEX:
|
|
|
|
- If CHILD_NAME is not NULL, then a copy of the child's name
|
|
is saved in *CHILD_NAME. This copy must be deallocated
|
|
with xfree after use.
|
|
|
|
- If CHILD_VALUE is not NULL, then save the child's value
|
|
in *CHILD_VALUE. Same thing for the child's type with
|
|
CHILD_TYPE if not NULL.
|
|
|
|
- If CHILD_PATH_EXPR is not NULL, then compute the child's
|
|
path expression. The resulting string must be deallocated
|
|
after use with xfree.
|
|
|
|
Computing the child's path expression requires the PARENT_PATH_EXPR
|
|
to be non-NULL. Otherwise, PARENT_PATH_EXPR may be null if
|
|
CHILD_PATH_EXPR is NULL.
|
|
|
|
PARENT_NAME is the name of the parent, and should never be NULL. */
|
|
|
|
static void ada_varobj_describe_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index,
|
|
std::string *child_name,
|
|
struct value **child_value,
|
|
struct type **child_type,
|
|
std::string *child_path_expr);
|
|
|
|
/* Same as ada_varobj_describe_child, but limited to struct/union
|
|
objects. */
|
|
|
|
static void
|
|
ada_varobj_describe_struct_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index,
|
|
std::string *child_name,
|
|
struct value **child_value,
|
|
struct type **child_type,
|
|
std::string *child_path_expr)
|
|
{
|
|
int fieldno;
|
|
int childno = 0;
|
|
|
|
gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT);
|
|
|
|
for (fieldno = 0; fieldno < TYPE_NFIELDS (parent_type); fieldno++)
|
|
{
|
|
if (ada_is_ignored_field (parent_type, fieldno))
|
|
continue;
|
|
|
|
if (ada_is_wrapper_field (parent_type, fieldno))
|
|
{
|
|
struct value *elt_value;
|
|
struct type *elt_type;
|
|
int elt_n_children;
|
|
|
|
ada_varobj_struct_elt (parent_value, parent_type, fieldno,
|
|
&elt_value, &elt_type);
|
|
if (ada_is_tagged_type (elt_type, 0))
|
|
{
|
|
/* Same as in ada_varobj_get_struct_number_of_children:
|
|
For tagged types, we must be careful to not call
|
|
ada_varobj_get_number_of_children, to prevent our
|
|
element from being fixed back into the parent. */
|
|
elt_n_children = ada_varobj_get_struct_number_of_children
|
|
(elt_value, elt_type);
|
|
}
|
|
else
|
|
elt_n_children =
|
|
ada_varobj_get_number_of_children (elt_value, elt_type);
|
|
|
|
/* Is the child we're looking for one of the children
|
|
of this wrapper field? */
|
|
if (child_index - childno < elt_n_children)
|
|
{
|
|
if (ada_is_tagged_type (elt_type, 0))
|
|
{
|
|
/* Same as in ada_varobj_get_struct_number_of_children:
|
|
For tagged types, we must be careful to not call
|
|
ada_varobj_describe_child, to prevent our element
|
|
from being fixed back into the parent. */
|
|
ada_varobj_describe_struct_child
|
|
(elt_value, elt_type, parent_name, parent_path_expr,
|
|
child_index - childno, child_name, child_value,
|
|
child_type, child_path_expr);
|
|
}
|
|
else
|
|
ada_varobj_describe_child (elt_value, elt_type,
|
|
parent_name, parent_path_expr,
|
|
child_index - childno,
|
|
child_name, child_value,
|
|
child_type, child_path_expr);
|
|
return;
|
|
}
|
|
|
|
/* The child we're looking for is beyond this wrapper
|
|
field, so skip all its children. */
|
|
childno += elt_n_children;
|
|
continue;
|
|
}
|
|
else if (ada_is_variant_part (parent_type, fieldno))
|
|
{
|
|
/* In normal situations, the variant part of the record should
|
|
have been "fixed". Or, in other words, it should have been
|
|
replaced by the branch of the variant part that is relevant
|
|
for our value. But there are still situations where this
|
|
can happen, however (Eg. when our parent is a NULL pointer).
|
|
We do not support showing this part of the record for now,
|
|
so just pretend this field does not exist. */
|
|
continue;
|
|
}
|
|
|
|
if (childno == child_index)
|
|
{
|
|
if (child_name)
|
|
{
|
|
/* The name of the child is none other than the field's
|
|
name, except that we need to strip suffixes from it.
|
|
For instance, fields with alignment constraints will
|
|
have an __XVA suffix added to them. */
|
|
const char *field_name = TYPE_FIELD_NAME (parent_type, fieldno);
|
|
int child_name_len = ada_name_prefix_len (field_name);
|
|
|
|
*child_name = string_printf ("%.*s", child_name_len, field_name);
|
|
}
|
|
|
|
if (child_value && parent_value)
|
|
ada_varobj_struct_elt (parent_value, parent_type, fieldno,
|
|
child_value, NULL);
|
|
|
|
if (child_type)
|
|
ada_varobj_struct_elt (parent_value, parent_type, fieldno,
|
|
NULL, child_type);
|
|
|
|
if (child_path_expr)
|
|
{
|
|
/* The name of the child is none other than the field's
|
|
name, except that we need to strip suffixes from it.
|
|
For instance, fields with alignment constraints will
|
|
have an __XVA suffix added to them. */
|
|
const char *field_name = TYPE_FIELD_NAME (parent_type, fieldno);
|
|
int child_name_len = ada_name_prefix_len (field_name);
|
|
|
|
*child_path_expr =
|
|
string_printf ("(%s).%.*s", parent_path_expr,
|
|
child_name_len, field_name);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
childno++;
|
|
}
|
|
|
|
/* Something went wrong. Either we miscounted the number of
|
|
children, or CHILD_INDEX was too high. But we should never
|
|
reach here. We don't have enough information to recover
|
|
nicely, so just raise an assertion failure. */
|
|
gdb_assert_not_reached ("unexpected code path");
|
|
}
|
|
|
|
/* Same as ada_varobj_describe_child, but limited to pointer objects.
|
|
|
|
Note that CHILD_INDEX is unused in this situation, but still provided
|
|
for consistency of interface with other routines describing an object's
|
|
child. */
|
|
|
|
static void
|
|
ada_varobj_describe_ptr_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index,
|
|
std::string *child_name,
|
|
struct value **child_value,
|
|
struct type **child_type,
|
|
std::string *child_path_expr)
|
|
{
|
|
if (child_name)
|
|
*child_name = string_printf ("%s.all", parent_name);
|
|
|
|
if (child_value && parent_value)
|
|
ada_varobj_ind (parent_value, parent_type, child_value, NULL);
|
|
|
|
if (child_type)
|
|
ada_varobj_ind (parent_value, parent_type, NULL, child_type);
|
|
|
|
if (child_path_expr)
|
|
*child_path_expr = string_printf ("(%s).all", parent_path_expr);
|
|
}
|
|
|
|
/* Same as ada_varobj_describe_child, limited to simple array objects
|
|
(TYPE_CODE_ARRAY only).
|
|
|
|
Assumes that the (PARENT_VALUE, PARENT_TYPE) pair is properly decoded.
|
|
This is done by ada_varobj_describe_child before calling us. */
|
|
|
|
static void
|
|
ada_varobj_describe_simple_array_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index,
|
|
std::string *child_name,
|
|
struct value **child_value,
|
|
struct type **child_type,
|
|
std::string *child_path_expr)
|
|
{
|
|
struct type *index_type;
|
|
int real_index;
|
|
|
|
gdb_assert (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY);
|
|
|
|
index_type = TYPE_INDEX_TYPE (parent_type);
|
|
real_index = child_index + ada_discrete_type_low_bound (index_type);
|
|
|
|
if (child_name)
|
|
*child_name = ada_varobj_scalar_image (index_type, real_index);
|
|
|
|
if (child_value && parent_value)
|
|
ada_varobj_simple_array_elt (parent_value, parent_type, real_index,
|
|
child_value, NULL);
|
|
|
|
if (child_type)
|
|
ada_varobj_simple_array_elt (parent_value, parent_type, real_index,
|
|
NULL, child_type);
|
|
|
|
if (child_path_expr)
|
|
{
|
|
std::string index_img = ada_varobj_scalar_image (index_type, real_index);
|
|
|
|
/* Enumeration litterals by themselves are potentially ambiguous.
|
|
For instance, consider the following package spec:
|
|
|
|
package Pck is
|
|
type Color is (Red, Green, Blue, White);
|
|
type Blood_Cells is (White, Red);
|
|
end Pck;
|
|
|
|
In this case, the litteral "red" for instance, or even
|
|
the fully-qualified litteral "pck.red" cannot be resolved
|
|
by itself. Type qualification is needed to determine which
|
|
enumeration litterals should be used.
|
|
|
|
The following variable will be used to contain the name
|
|
of the array index type when such type qualification is
|
|
needed. */
|
|
const char *index_type_name = NULL;
|
|
|
|
/* If the index type is a range type, find the base type. */
|
|
while (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
|
|
index_type = TYPE_TARGET_TYPE (index_type);
|
|
|
|
if (TYPE_CODE (index_type) == TYPE_CODE_ENUM
|
|
|| TYPE_CODE (index_type) == TYPE_CODE_BOOL)
|
|
{
|
|
index_type_name = ada_type_name (index_type);
|
|
if (index_type_name)
|
|
index_type_name = ada_decode (index_type_name);
|
|
}
|
|
|
|
if (index_type_name != NULL)
|
|
*child_path_expr =
|
|
string_printf ("(%s)(%.*s'(%s))", parent_path_expr,
|
|
ada_name_prefix_len (index_type_name),
|
|
index_type_name, index_img.c_str ());
|
|
else
|
|
*child_path_expr =
|
|
string_printf ("(%s)(%s)", parent_path_expr, index_img.c_str ());
|
|
}
|
|
}
|
|
|
|
/* See description at declaration above. */
|
|
|
|
static void
|
|
ada_varobj_describe_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index,
|
|
std::string *child_name,
|
|
struct value **child_value,
|
|
struct type **child_type,
|
|
std::string *child_path_expr)
|
|
{
|
|
/* We cannot compute the child's path expression without
|
|
the parent's path expression. This is a pre-condition
|
|
for calling this function. */
|
|
if (child_path_expr)
|
|
gdb_assert (parent_path_expr != NULL);
|
|
|
|
ada_varobj_decode_var (&parent_value, &parent_type);
|
|
ada_varobj_adjust_for_child_access (&parent_value, &parent_type);
|
|
|
|
if (child_name)
|
|
*child_name = std::string ();
|
|
if (child_value)
|
|
*child_value = NULL;
|
|
if (child_type)
|
|
*child_type = NULL;
|
|
if (child_path_expr)
|
|
*child_path_expr = std::string ();
|
|
|
|
if (ada_is_array_descriptor_type (parent_type)
|
|
&& TYPE_CODE (parent_type) == TYPE_CODE_TYPEDEF)
|
|
{
|
|
ada_varobj_describe_ptr_child (parent_value, parent_type,
|
|
parent_name, parent_path_expr,
|
|
child_index, child_name,
|
|
child_value, child_type,
|
|
child_path_expr);
|
|
return;
|
|
}
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_ARRAY)
|
|
{
|
|
ada_varobj_describe_simple_array_child
|
|
(parent_value, parent_type, parent_name, parent_path_expr,
|
|
child_index, child_name, child_value, child_type,
|
|
child_path_expr);
|
|
return;
|
|
}
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_STRUCT)
|
|
{
|
|
ada_varobj_describe_struct_child (parent_value, parent_type,
|
|
parent_name, parent_path_expr,
|
|
child_index, child_name,
|
|
child_value, child_type,
|
|
child_path_expr);
|
|
return;
|
|
}
|
|
|
|
if (TYPE_CODE (parent_type) == TYPE_CODE_PTR)
|
|
{
|
|
ada_varobj_describe_ptr_child (parent_value, parent_type,
|
|
parent_name, parent_path_expr,
|
|
child_index, child_name,
|
|
child_value, child_type,
|
|
child_path_expr);
|
|
return;
|
|
}
|
|
|
|
/* It should never happen. But rather than crash, report dummy names
|
|
and return a NULL child_value. */
|
|
if (child_name)
|
|
*child_name = "???";
|
|
}
|
|
|
|
/* Return the name of the child number CHILD_INDEX of the (PARENT_VALUE,
|
|
PARENT_TYPE) pair. PARENT_NAME is the name of the PARENT. */
|
|
|
|
static std::string
|
|
ada_varobj_get_name_of_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name, int child_index)
|
|
{
|
|
std::string child_name;
|
|
|
|
ada_varobj_describe_child (parent_value, parent_type, parent_name,
|
|
NULL, child_index, &child_name, NULL,
|
|
NULL, NULL);
|
|
return child_name;
|
|
}
|
|
|
|
/* Return the path expression of the child number CHILD_INDEX of
|
|
the (PARENT_VALUE, PARENT_TYPE) pair. PARENT_NAME is the name
|
|
of the parent, and PARENT_PATH_EXPR is the parent's path expression.
|
|
Both must be non-NULL. */
|
|
|
|
static std::string
|
|
ada_varobj_get_path_expr_of_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name,
|
|
const char *parent_path_expr,
|
|
int child_index)
|
|
{
|
|
std::string child_path_expr;
|
|
|
|
ada_varobj_describe_child (parent_value, parent_type, parent_name,
|
|
parent_path_expr, child_index, NULL,
|
|
NULL, NULL, &child_path_expr);
|
|
|
|
return child_path_expr;
|
|
}
|
|
|
|
/* Return the value of child number CHILD_INDEX of the (PARENT_VALUE,
|
|
PARENT_TYPE) pair. PARENT_NAME is the name of the parent. */
|
|
|
|
static struct value *
|
|
ada_varobj_get_value_of_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
const char *parent_name, int child_index)
|
|
{
|
|
struct value *child_value;
|
|
|
|
ada_varobj_describe_child (parent_value, parent_type, parent_name,
|
|
NULL, child_index, NULL, &child_value,
|
|
NULL, NULL);
|
|
|
|
return child_value;
|
|
}
|
|
|
|
/* Return the type of child number CHILD_INDEX of the (PARENT_VALUE,
|
|
PARENT_TYPE) pair. */
|
|
|
|
static struct type *
|
|
ada_varobj_get_type_of_child (struct value *parent_value,
|
|
struct type *parent_type,
|
|
int child_index)
|
|
{
|
|
struct type *child_type;
|
|
|
|
ada_varobj_describe_child (parent_value, parent_type, NULL, NULL,
|
|
child_index, NULL, NULL, &child_type, NULL);
|
|
|
|
return child_type;
|
|
}
|
|
|
|
/* Return a string that contains the image of the given VALUE, using
|
|
the print options OPTS as the options for formatting the result.
|
|
|
|
The resulting string must be deallocated after use with xfree. */
|
|
|
|
static std::string
|
|
ada_varobj_get_value_image (struct value *value,
|
|
struct value_print_options *opts)
|
|
{
|
|
string_file buffer;
|
|
|
|
common_val_print (value, &buffer, 0, opts, current_language);
|
|
return std::move (buffer.string ());
|
|
}
|
|
|
|
/* Assuming that the (VALUE, TYPE) pair designates an array varobj,
|
|
return a string that is suitable for use in the "value" field of
|
|
the varobj output. Most of the time, this is the number of elements
|
|
in the array inside square brackets, but there are situations where
|
|
it's useful to add more info.
|
|
|
|
OPTS are the print options used when formatting the result.
|
|
|
|
The result should be deallocated after use using xfree. */
|
|
|
|
static std::string
|
|
ada_varobj_get_value_of_array_variable (struct value *value,
|
|
struct type *type,
|
|
struct value_print_options *opts)
|
|
{
|
|
char *result;
|
|
const int numchild = ada_varobj_get_array_number_of_children (value, type);
|
|
|
|
/* If we have a string, provide its contents in the "value" field.
|
|
Otherwise, the only other way to inspect the contents of the string
|
|
is by looking at the value of each element, as in any other array,
|
|
which is not very convenient... */
|
|
if (value
|
|
&& ada_is_string_type (type)
|
|
&& (opts->format == 0 || opts->format == 's'))
|
|
{
|
|
std::string str = ada_varobj_get_value_image (value, opts);
|
|
return string_printf ("[%d] %s", numchild, str.c_str ());
|
|
}
|
|
else
|
|
return string_printf ("[%d]", numchild);
|
|
}
|
|
|
|
/* Return a string representation of the (VALUE, TYPE) pair, using
|
|
the given print options OPTS as our formatting options. */
|
|
|
|
static std::string
|
|
ada_varobj_get_value_of_variable (struct value *value,
|
|
struct type *type,
|
|
struct value_print_options *opts)
|
|
{
|
|
ada_varobj_decode_var (&value, &type);
|
|
|
|
switch (TYPE_CODE (type))
|
|
{
|
|
case TYPE_CODE_STRUCT:
|
|
case TYPE_CODE_UNION:
|
|
return "{...}";
|
|
case TYPE_CODE_ARRAY:
|
|
return ada_varobj_get_value_of_array_variable (value, type, opts);
|
|
default:
|
|
if (!value)
|
|
return "";
|
|
else
|
|
return ada_varobj_get_value_image (value, opts);
|
|
}
|
|
}
|
|
|
|
/* Ada specific callbacks for VAROBJs. */
|
|
|
|
static int
|
|
ada_number_of_children (const struct varobj *var)
|
|
{
|
|
return ada_varobj_get_number_of_children (var->value, var->type);
|
|
}
|
|
|
|
static std::string
|
|
ada_name_of_variable (const struct varobj *parent)
|
|
{
|
|
return c_varobj_ops.name_of_variable (parent);
|
|
}
|
|
|
|
static std::string
|
|
ada_name_of_child (const struct varobj *parent, int index)
|
|
{
|
|
return ada_varobj_get_name_of_child (parent->value, parent->type,
|
|
parent->name.c_str (), index);
|
|
}
|
|
|
|
static std::string
|
|
ada_path_expr_of_child (const struct varobj *child)
|
|
{
|
|
const struct varobj *parent = child->parent;
|
|
const char *parent_path_expr = varobj_get_path_expr (parent);
|
|
|
|
return ada_varobj_get_path_expr_of_child (parent->value,
|
|
parent->type,
|
|
parent->name.c_str (),
|
|
parent_path_expr,
|
|
child->index);
|
|
}
|
|
|
|
static struct value *
|
|
ada_value_of_child (const struct varobj *parent, int index)
|
|
{
|
|
return ada_varobj_get_value_of_child (parent->value, parent->type,
|
|
parent->name.c_str (), index);
|
|
}
|
|
|
|
static struct type *
|
|
ada_type_of_child (const struct varobj *parent, int index)
|
|
{
|
|
return ada_varobj_get_type_of_child (parent->value, parent->type,
|
|
index);
|
|
}
|
|
|
|
static std::string
|
|
ada_value_of_variable (const struct varobj *var,
|
|
enum varobj_display_formats format)
|
|
{
|
|
struct value_print_options opts;
|
|
|
|
varobj_formatted_print_options (&opts, format);
|
|
|
|
return ada_varobj_get_value_of_variable (var->value, var->type, &opts);
|
|
}
|
|
|
|
/* Implement the "value_is_changeable_p" routine for Ada. */
|
|
|
|
static int
|
|
ada_value_is_changeable_p (const struct varobj *var)
|
|
{
|
|
struct type *type = var->value ? value_type (var->value) : var->type;
|
|
|
|
if (ada_is_array_descriptor_type (type)
|
|
&& TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
|
|
{
|
|
/* This is in reality a pointer to an unconstrained array.
|
|
its value is changeable. */
|
|
return 1;
|
|
}
|
|
|
|
if (ada_is_string_type (type))
|
|
{
|
|
/* We display the contents of the string in the array's
|
|
"value" field. The contents can change, so consider
|
|
that the array is changeable. */
|
|
return 1;
|
|
}
|
|
|
|
return varobj_default_value_is_changeable_p (var);
|
|
}
|
|
|
|
/* Implement the "value_has_mutated" routine for Ada. */
|
|
|
|
static int
|
|
ada_value_has_mutated (const struct varobj *var, struct value *new_val,
|
|
struct type *new_type)
|
|
{
|
|
int i;
|
|
int from = -1;
|
|
int to = -1;
|
|
|
|
/* If the number of fields have changed, then for sure the type
|
|
has mutated. */
|
|
if (ada_varobj_get_number_of_children (new_val, new_type)
|
|
!= var->num_children)
|
|
return 1;
|
|
|
|
/* If the number of fields have remained the same, then we need
|
|
to check the name of each field. If they remain the same,
|
|
then chances are the type hasn't mutated. This is technically
|
|
an incomplete test, as the child's type might have changed
|
|
despite the fact that the name remains the same. But we'll
|
|
handle this situation by saying that the child has mutated,
|
|
not this value.
|
|
|
|
If only part (or none!) of the children have been fetched,
|
|
then only check the ones we fetched. It does not matter
|
|
to the frontend whether a child that it has not fetched yet
|
|
has mutated or not. So just assume it hasn't. */
|
|
|
|
varobj_restrict_range (var->children, &from, &to);
|
|
for (i = from; i < to; i++)
|
|
if (ada_varobj_get_name_of_child (new_val, new_type,
|
|
var->name.c_str (), i)
|
|
!= VEC_index (varobj_p, var->children, i)->name)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* varobj operations for ada. */
|
|
|
|
const struct lang_varobj_ops ada_varobj_ops =
|
|
{
|
|
ada_number_of_children,
|
|
ada_name_of_variable,
|
|
ada_name_of_child,
|
|
ada_path_expr_of_child,
|
|
ada_value_of_child,
|
|
ada_type_of_child,
|
|
ada_value_of_variable,
|
|
ada_value_is_changeable_p,
|
|
ada_value_has_mutated,
|
|
varobj_default_is_path_expr_parent
|
|
};
|