From fbf54e7554e0dcd60e18b1821c5c127fb3eb48ff Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 13 Mar 2020 17:39:52 -0600 Subject: Introduce cp_print_value This adds cp_print_value, a value-based analogue of cp_print_val, and changes cp_print_value_fields to use it. gdb/ChangeLog 2020-03-13 Tom Tromey * cp-valprint.c (cp_print_value_fields): Update. (cp_print_value): New function. --- gdb/ChangeLog | 5 ++ gdb/cp-valprint.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 169 insertions(+), 4 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0a6c2fe..dea6a8d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ 2020-03-13 Tom Tromey + * cp-valprint.c (cp_print_value_fields): Update. + (cp_print_value): New function. + +2020-03-13 Tom Tromey + * m2-valprint.c (m2_value_print_inner): Use cp_print_value_fields. * cp-valprint.c (cp_print_value_fields): New function. diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index e186d48..77725b7 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -54,6 +54,10 @@ static void cp_print_value (struct type *, struct type *, const struct value_print_options *, struct type **); +static void cp_print_value (struct value *, struct ui_file *, + int, const struct value_print_options *, + struct type **); + /* GCC versions after 2.4.5 use this. */ const char vtbl_ptr_name[] = "__vtbl_ptr_type"; @@ -412,7 +416,6 @@ cp_print_value_fields (struct value *val, struct ui_file *stream, static int last_set_recurse = -1; struct type *type = check_typedef (value_type (val)); - CORE_ADDR address = value_address (val); if (recurse == 0) { @@ -441,9 +444,7 @@ cp_print_value_fields (struct value *val, struct ui_file *stream, duplicates of virtual baseclasses. */ if (n_baseclasses > 0) - cp_print_value (type, type, 0, address, stream, - recurse + 1, val, options, - dont_print_vb); + cp_print_value (val, stream, recurse + 1, options, dont_print_vb); /* Second, print out data fields */ @@ -608,6 +609,7 @@ cp_print_value_fields (struct value *val, struct ui_file *stream, { CORE_ADDR addr; + i_offset += value_embedded_offset (val); addr = extract_typed_address (valaddr + i_offset, i_type); print_function_pointer_address (opts, get_type_arch (type), @@ -881,6 +883,164 @@ cp_print_value (struct type *type, struct type *real_type, } } +/* Special val_print routine to avoid printing multiple copies of + virtual baseclasses. */ + +static void +cp_print_value (struct value *val, struct ui_file *stream, + int recurse, const struct value_print_options *options, + struct type **dont_print_vb) +{ + struct type *type = check_typedef (value_type (val)); + CORE_ADDR address = value_address (val); + struct type **last_dont_print + = (struct type **) obstack_next_free (&dont_print_vb_obstack); + struct obstack tmp_obstack = dont_print_vb_obstack; + int i, n_baseclasses = TYPE_N_BASECLASSES (type); + const gdb_byte *valaddr = value_contents_for_printing (val); + + if (dont_print_vb == 0) + { + /* If we're at top level, carve out a completely fresh chunk of + the obstack and use that until this particular invocation + returns. */ + /* Bump up the high-water mark. Now alpha is omega. */ + obstack_finish (&dont_print_vb_obstack); + } + + for (i = 0; i < n_baseclasses; i++) + { + LONGEST boffset = 0; + int skip = 0; + struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); + const char *basename = TYPE_NAME (baseclass); + struct value *base_val = NULL; + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + struct type **first_dont_print + = (struct type **) obstack_base (&dont_print_vb_obstack); + + int j = (struct type **) + obstack_next_free (&dont_print_vb_obstack) - first_dont_print; + + while (--j >= 0) + if (baseclass == first_dont_print[j]) + goto flush_it; + + obstack_ptr_grow (&dont_print_vb_obstack, baseclass); + } + + try + { + boffset = baseclass_offset (type, i, valaddr, + value_embedded_offset (val), + address, val); + } + catch (const gdb_exception_error &ex) + { + if (ex.error == NOT_AVAILABLE_ERROR) + skip = -1; + else + skip = 1; + } + + if (skip == 0) + { + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + /* The virtual base class pointer might have been + clobbered by the user program. Make sure that it + still points to a valid memory location. */ + + if (boffset < 0 || boffset >= TYPE_LENGTH (type)) + { + gdb::byte_vector buf (TYPE_LENGTH (baseclass)); + + if (target_read_memory (address + boffset, buf.data (), + TYPE_LENGTH (baseclass)) != 0) + skip = 1; + base_val = value_from_contents_and_address (baseclass, + buf.data (), + address + boffset); + baseclass = value_type (base_val); + boffset = 0; + } + else + { + base_val = val; + } + } + else + { + base_val = val; + } + } + + /* Now do the printing. */ + if (options->prettyformat) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + fputs_filtered ("<", stream); + /* Not sure what the best notation is in the case where there is + no baseclass name. */ + fputs_filtered (basename ? basename : "", stream); + fputs_filtered ("> = ", stream); + + if (skip < 0) + val_print_unavailable (stream); + else if (skip > 0) + val_print_invalid_address (stream); + else + { + int result = 0; + + if (options->max_depth > -1 + && recurse >= options->max_depth) + { + const struct language_defn *language = current_language; + gdb_assert (language->la_struct_too_deep_ellipsis != NULL); + fputs_filtered (language->la_struct_too_deep_ellipsis, stream); + } + else + { + /* Attempt to run an extension language pretty-printer on the + baseclass if possible. */ + if (!options->raw) + result + = apply_ext_lang_val_pretty_printer (baseclass, boffset, + value_address (base_val), + stream, recurse, + base_val, options, + current_language); + + if (!result) + cp_print_value_fields (value_primitive_field (val, 0, i, type), + stream, recurse, options, + ((struct type **) + obstack_base (&dont_print_vb_obstack)), + 0); + } + } + fputs_filtered (", ", stream); + + flush_it: + ; + } + + if (dont_print_vb == 0) + { + /* Free the space used to deal with the printing + of this type from top level. */ + obstack_free (&dont_print_vb_obstack, last_dont_print); + /* Reset watermark so that we can continue protecting + ourselves from whatever we were protecting ourselves. */ + dont_print_vb_obstack = tmp_obstack; + } +} + /* Print value of a static member. To avoid infinite recursion when printing a class that contains a static instance of the class, we keep the addresses of all printed static member classes in an -- cgit v1.1