@@ -3,6 +3,12 @@
*** Changes since GDB 7.10
+* GDB's printf command now has a format specifier (%q) to display the
+ textual label (enumerator) of an enumeration value. For example:
+
+ (gdb) printf "Visiting node of type %q\n", node
+ Visiting node of type NODE_INTEGER
+
* GDB now supports debugging kernel-based threads on FreeBSD.
* Per-inferior thread numbers
@@ -294,6 +294,10 @@ parse_format_string (const char **arg)
case '\0':
error (_("Incomplete format specifier at end of format string"));
+ case 'q':
+ this_argclass = enum_arg;
+ break;
+
default:
error (_("Unrecognized format specifier '%c' in printf"), *f);
}
@@ -35,7 +35,7 @@ enum argclass
literal_piece,
int_arg, long_arg, long_long_arg, ptr_arg,
string_arg, wide_string_arg, wide_char_arg,
- double_arg, long_double_arg, decfloat_arg
+ double_arg, long_double_arg, decfloat_arg, enum_arg
};
/* A format piece is a section of the format string that may include a
@@ -24343,6 +24343,9 @@ sequences, such as @code{\n}, @samp{\t}, @samp{\\}, @samp{\"},
single character. Octal and hexadecimal escape sequences are not
supported.
+@code{printf} supports the @samp{q} conversion letter to print the textual
+label (enumerator) of a C enumeration value.
+
Additionally, @code{printf} supports conversion specifications for DFP
(@dfn{Decimal Floating Point}) types using the following length modifiers
together with a floating point specifier.
@@ -2258,6 +2258,23 @@ printf_pointer (struct ui_file *stream, const char *format,
}
}
+static void
+printf_enum (struct ui_file *stream, struct value *value)
+{
+ struct type *type = check_typedef (value_type (value));
+
+ if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ val_print_enum_label (type, value_contents_for_printing (value),
+ value_embedded_offset (value), stream);
+ }
+ else
+ {
+ error (_("\
+Value given for enum format specifier (%%q) is not of an enum type."));
+ }
+}
+
/* printf "printf format string" ARG to STREAM. */
static void
@@ -2446,6 +2463,9 @@ ui_printf (const char *arg, struct ui_file *stream)
case ptr_arg:
printf_pointer (stream, current_substring, val_args[i]);
break;
+ case enum_arg:
+ printf_enum (stream, val_args[i]);
+ break;
case literal_piece:
/* Print a portion of the format string that has no
directives. Note that this will not include any
@@ -90,7 +90,7 @@ struct some_arrays {
struct some_arrays *parrays = &arrays;
-enum some_volatile_enum { enumvolval1, enumvolval2 };
+enum some_volatile_enum { enumvolval1, enumvolval2, enumvolval3, enumvolval4 };
/* A volatile enum variable whose name is the same as the enumeration
name. See PR11827. */
@@ -763,6 +763,16 @@ proc test_printf {} {
"" \
"create hibob command"
gdb_test "hibob" "hi bob zzz.*y" "run hibob command"
+
+ # Test for enum printing (%q) in printf
+ gdb_test "printf \"%q\\n\", some_volatile_enum" "enumvolval1"
+ gdb_test "printf \"%q\\n\", enumvolval2" "enumvolval2"
+ gdb_test "printf \"%q\\n\", (enum some_volatile_enum) 1" "enumvolval2"
+ gdb_test "printf \"%q\\n\", (enum some_volatile_enum) 111" "111"
+ gdb_test "printf \"%q\\n\", three" "\\(ONE | TWO\\)"
+ gdb_test "printf \"%q\\n\", (enum flag_enum) 8" "\\(unknown: 8\\)"
+
+ gdb_test "printf \"%q\\n\", 2" "Value given for enum format specifier \\(%q\\) is not of an enum type."
}
#Test printing DFP values with printf
@@ -526,35 +526,23 @@ generic_val_print_ref (struct type *type, const gdb_byte *valaddr,
}
}
-/* generic_val_print helper for TYPE_CODE_ENUM. */
-
-static void
-generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
- int embedded_offset, struct ui_file *stream,
- const struct value *original_value,
- const struct value_print_options *options)
+void
+val_print_enum_label (struct type *type, const gdb_byte *valaddr,
+ int embedded_offset, struct ui_file *stream)
{
- unsigned int i;
- unsigned int len;
- LONGEST val;
+ int len = TYPE_NFIELDS (type);
+ int i;
struct gdbarch *gdbarch = get_type_arch (type);
int unit_size = gdbarch_addressable_memory_unit_size (gdbarch);
+ LONGEST val = unpack_long (type, valaddr + embedded_offset * unit_size);
- if (options->format)
- {
- val_print_scalar_formatted (type, valaddr, embedded_offset,
- original_value, options, 0, stream);
- return;
- }
- len = TYPE_NFIELDS (type);
- val = unpack_long (type, valaddr + embedded_offset * unit_size);
for (i = 0; i < len; i++)
{
QUIT;
if (val == TYPE_FIELD_ENUMVAL (type, i))
- {
- break;
- }
+ {
+ break;
+ }
}
if (i < len)
{
@@ -565,31 +553,31 @@ generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
int first = 1;
/* We have a "flag" enum, so we try to decompose it into
- pieces as appropriate. A flag enum has disjoint
- constants by definition. */
+ pieces as appropriate. A flag enum has disjoint
+ constants by definition. */
fputs_filtered ("(", stream);
for (i = 0; i < len; ++i)
- {
- QUIT;
+ {
+ QUIT;
- if ((val & TYPE_FIELD_ENUMVAL (type, i)) != 0)
- {
- if (!first)
- fputs_filtered (" | ", stream);
- first = 0;
+ if ((val & TYPE_FIELD_ENUMVAL (type, i)) != 0)
+ {
+ if (!first)
+ fputs_filtered (" | ", stream);
+ first = 0;
- val &= ~TYPE_FIELD_ENUMVAL (type, i);
- fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
- }
- }
+ val &= ~TYPE_FIELD_ENUMVAL (type, i);
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ }
if (first || val != 0)
- {
- if (!first)
- fputs_filtered (" | ", stream);
- fputs_filtered ("unknown: ", stream);
- print_longest (stream, 'd', 0, val);
- }
+ {
+ if (!first)
+ fputs_filtered (" | ", stream);
+ fputs_filtered ("unknown: ", stream);
+ print_longest (stream, 'd', 0, val);
+ }
fputs_filtered (")", stream);
}
@@ -597,6 +585,25 @@ generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
print_longest (stream, 'd', 0, val);
}
+/* generic_val_print helper for TYPE_CODE_ENUM. */
+
+static void
+generic_val_print_enum (struct type *type, const gdb_byte *valaddr,
+ int embedded_offset, struct ui_file *stream,
+ const struct value *original_value,
+ const struct value_print_options *options)
+{
+ if (options->format)
+ {
+ val_print_scalar_formatted (type, valaddr, embedded_offset,
+ original_value, options, 0, stream);
+ }
+ else
+ {
+ val_print_enum_label (type, valaddr, embedded_offset, stream);
+ }
+}
+
/* generic_val_print helper for TYPE_CODE_FLAGS. */
static void
@@ -170,6 +170,9 @@ extern void val_print_unavailable (struct ui_file *stream);
extern void val_print_invalid_address (struct ui_file *stream);
+extern void val_print_enum_label (struct type *type, const gdb_byte *valaddr,
+ int embedded_offset, struct ui_file *stream);
+
/* An instance of this is passed to generic_val_print and describes
some language-specific ways to print things. */