Move ptype/o printing code to typeprint.c
This moves the hole-printing support code for ptype/o from c-typeprint.c to be methods on print_offset_data. This allows the code to be used from non-C languages. gdb/ChangeLog 2018-06-26 Tom Tromey <tom@tromey.com> * typeprint.h (struct print_offset_data) <update, finish, maybe_print_hole>: New methods. <indentation>: New constant. * typeprint.c (print_offset_data::indentation): Define. (print_offset_data::maybe_print_hole, print_offset_data::update) (print_offset_data::finish): Move from c-typeprint.c and rename. * c-typeprint.c (OFFSET_SPC_LEN): Remove. (print_spaces_filtered_with_print_options): Update. (c_print_type_union_field_offset, maybe_print_hole) (c_print_type_struct_field_offset): Move to typeprint.c and rename. (c_type_print_base_struct_union): Update.
This commit is contained in:
parent
30aa13067f
commit
e0c547d14a
@ -1,3 +1,18 @@
|
||||
2018-06-26 Tom Tromey <tom@tromey.com>
|
||||
|
||||
* typeprint.h (struct print_offset_data) <update, finish,
|
||||
maybe_print_hole>: New methods.
|
||||
<indentation>: New constant.
|
||||
* typeprint.c (print_offset_data::indentation): Define.
|
||||
(print_offset_data::maybe_print_hole, print_offset_data::update)
|
||||
(print_offset_data::finish): Move from c-typeprint.c and rename.
|
||||
* c-typeprint.c (OFFSET_SPC_LEN): Remove.
|
||||
(print_spaces_filtered_with_print_options): Update.
|
||||
(c_print_type_union_field_offset, maybe_print_hole)
|
||||
(c_print_type_struct_field_offset): Move to typeprint.c and
|
||||
rename.
|
||||
(c_type_print_base_struct_union): Update.
|
||||
|
||||
2018-06-25 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdbthread.h (thread_info_ref, delete_thread)
|
||||
|
@ -32,14 +32,6 @@
|
||||
#include "cp-abi.h"
|
||||
#include "cp-support.h"
|
||||
|
||||
/* When printing the offsets of a struct and its fields (i.e., 'ptype
|
||||
/o'; type_print_options::print_offsets), we use this many
|
||||
characters when printing the offset information at the beginning of
|
||||
the line. This is needed in order to generate the correct amount
|
||||
of whitespaces when no offset info should be printed for a certain
|
||||
field. */
|
||||
#define OFFSET_SPC_LEN 23
|
||||
|
||||
/* A list of access specifiers used for printing. */
|
||||
|
||||
enum access_specifier
|
||||
@ -913,7 +905,7 @@ print_spaces_filtered_with_print_options
|
||||
if (!flags->print_offsets)
|
||||
print_spaces_filtered (level, stream);
|
||||
else
|
||||
print_spaces_filtered (level + OFFSET_SPC_LEN, stream);
|
||||
print_spaces_filtered (level + print_offset_data::indentation, stream);
|
||||
}
|
||||
|
||||
/* Output an access specifier to STREAM, if needed. LAST_ACCESS is the
|
||||
@ -956,127 +948,6 @@ output_access_specifier (struct ui_file *stream,
|
||||
return last_access;
|
||||
}
|
||||
|
||||
/* Print information about field at index FIELD_IDX of the union type
|
||||
TYPE. Since union fields don't have the concept of offsets, we
|
||||
just print their sizes.
|
||||
|
||||
The output is strongly based on pahole(1). */
|
||||
|
||||
static void
|
||||
c_print_type_union_field_offset (struct type *type, unsigned int field_idx,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
struct type *ftype = check_typedef (TYPE_FIELD_TYPE (type, field_idx));
|
||||
|
||||
fprintf_filtered (stream, "/* %4u */", TYPE_LENGTH (ftype));
|
||||
}
|
||||
|
||||
/* Helper function for ptype/o implementation that prints information
|
||||
about a hole, if necessary. STREAM is where to print. BITPOS is
|
||||
the bitpos of the current field. PODATA is the offset-printing
|
||||
state. FOR_WHAT is a string describing the purpose of the
|
||||
hole. */
|
||||
|
||||
static void
|
||||
maybe_print_hole (struct ui_file *stream, unsigned int bitpos,
|
||||
struct print_offset_data *podata, const char *for_what)
|
||||
{
|
||||
/* We check for PODATA->END_BITPOS > 0 because there is a specific
|
||||
scenario when PODATA->END_BITPOS can be zero and BITPOS can be >
|
||||
0: when we are dealing with a struct/class with a virtual method.
|
||||
Because of the vtable, the first field of the struct/class will
|
||||
have an offset of sizeof (void *) (the size of the vtable). If
|
||||
we do not check for PODATA->END_BITPOS > 0 here, GDB will report
|
||||
a hole before the first field, which is not accurate. */
|
||||
if (podata->end_bitpos > 0 && podata->end_bitpos < bitpos)
|
||||
{
|
||||
/* If PODATA->END_BITPOS is smaller than the current type's
|
||||
bitpos, it means there's a hole in the struct, so we report
|
||||
it here. */
|
||||
unsigned int hole = bitpos - podata->end_bitpos;
|
||||
unsigned int hole_byte = hole / TARGET_CHAR_BIT;
|
||||
unsigned int hole_bit = hole % TARGET_CHAR_BIT;
|
||||
|
||||
if (hole_bit > 0)
|
||||
fprintf_filtered (stream, "/* XXX %2u-bit %s */\n", hole_bit,
|
||||
for_what);
|
||||
|
||||
if (hole_byte > 0)
|
||||
fprintf_filtered (stream, "/* XXX %2u-byte %s */\n", hole_byte,
|
||||
for_what);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print information about field at index FIELD_IDX of the struct type
|
||||
TYPE.
|
||||
|
||||
PODATA->END_BITPOS is the one-past-the-end bit position of the
|
||||
previous field (where we expect this field to be if there is no
|
||||
hole). At the end, ENDPOS is updated to the one-past-the-end bit
|
||||
position of the current field.
|
||||
|
||||
PODATA->OFFSET_BITPOS is the offset value we carry over when we are
|
||||
printing a struct that is inside another struct; this is useful so
|
||||
that the offset is constantly incremented (if we didn't carry it
|
||||
over, the offset would be reset to zero when printing the inner
|
||||
struct).
|
||||
|
||||
The output is strongly based on pahole(1). */
|
||||
|
||||
static void
|
||||
c_print_type_struct_field_offset (struct type *type, unsigned int field_idx,
|
||||
struct ui_file *stream,
|
||||
struct print_offset_data *podata)
|
||||
{
|
||||
struct type *ftype = check_typedef (TYPE_FIELD_TYPE (type, field_idx));
|
||||
unsigned int bitpos = TYPE_FIELD_BITPOS (type, field_idx);
|
||||
unsigned int fieldsize_byte = TYPE_LENGTH (ftype);
|
||||
unsigned int fieldsize_bit = fieldsize_byte * TARGET_CHAR_BIT;
|
||||
|
||||
maybe_print_hole (stream, bitpos, podata, "hole");
|
||||
|
||||
if (TYPE_FIELD_PACKED (type, field_idx))
|
||||
{
|
||||
/* We're dealing with a bitfield. Print how many bits are left
|
||||
to be used. */
|
||||
unsigned int bitsize = TYPE_FIELD_BITSIZE (type, field_idx);
|
||||
/* The bitpos relative to the beginning of our container
|
||||
field. */
|
||||
unsigned int relative_bitpos;
|
||||
|
||||
/* The following was copied from
|
||||
value.c:value_primitive_field. */
|
||||
if ((bitpos % fieldsize_bit) + bitsize <= fieldsize_bit)
|
||||
relative_bitpos = bitpos % fieldsize_bit;
|
||||
else
|
||||
relative_bitpos = bitpos % TARGET_CHAR_BIT;
|
||||
|
||||
/* This is the exact offset (in bits) of this bitfield. */
|
||||
unsigned int bit_offset
|
||||
= (bitpos - relative_bitpos) + podata->offset_bitpos;
|
||||
|
||||
/* The position of the field, relative to the beginning of the
|
||||
struct, and how many bits are left to be used in this
|
||||
container. */
|
||||
fprintf_filtered (stream, "/* %4u:%2u", bit_offset / TARGET_CHAR_BIT,
|
||||
fieldsize_bit - (relative_bitpos + bitsize));
|
||||
fieldsize_bit = bitsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The position of the field, relative to the beginning of the
|
||||
struct. */
|
||||
fprintf_filtered (stream, "/* %4u",
|
||||
(bitpos + podata->offset_bitpos) / TARGET_CHAR_BIT);
|
||||
|
||||
fprintf_filtered (stream, " ");
|
||||
}
|
||||
|
||||
fprintf_filtered (stream, " | %4u */", fieldsize_byte);
|
||||
|
||||
podata->end_bitpos = bitpos + fieldsize_bit;
|
||||
}
|
||||
|
||||
/* Return true if an access label (i.e., "public:", "private:",
|
||||
"protected:") needs to be printed for TYPE. */
|
||||
|
||||
@ -1289,20 +1160,7 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
|
||||
bool is_static = field_is_static (&TYPE_FIELD (type, i));
|
||||
|
||||
if (flags->print_offsets)
|
||||
{
|
||||
if (!is_static)
|
||||
{
|
||||
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
|
||||
{
|
||||
c_print_type_struct_field_offset
|
||||
(type, i, stream, podata);
|
||||
}
|
||||
else if (TYPE_CODE (type) == TYPE_CODE_UNION)
|
||||
c_print_type_union_field_offset (type, i, stream);
|
||||
}
|
||||
else
|
||||
print_spaces_filtered (OFFSET_SPC_LEN, stream);
|
||||
}
|
||||
podata->update (type, i, stream);
|
||||
|
||||
print_spaces_filtered (level + 4, stream);
|
||||
if (is_static)
|
||||
@ -1560,19 +1418,9 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
|
||||
if (flags->print_offsets)
|
||||
{
|
||||
if (show > 0)
|
||||
{
|
||||
unsigned int bitpos = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
|
||||
maybe_print_hole (stream, bitpos, podata, "padding");
|
||||
podata->finish (type, level, stream);
|
||||
|
||||
fputs_filtered ("\n", stream);
|
||||
print_spaces_filtered_with_print_options (level + 4,
|
||||
stream,
|
||||
flags);
|
||||
fprintf_filtered (stream, "/* total size (bytes): %4u */\n",
|
||||
TYPE_LENGTH (type));
|
||||
}
|
||||
|
||||
print_spaces_filtered (OFFSET_SPC_LEN, stream);
|
||||
print_spaces_filtered (print_offset_data::indentation, stream);
|
||||
if (level == 0)
|
||||
print_spaces_filtered (2, stream);
|
||||
}
|
||||
|
124
gdb/typeprint.c
124
gdb/typeprint.c
@ -65,6 +65,130 @@ static struct type_print_options default_ptype_flags =
|
||||
|
||||
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
const int print_offset_data::indentation = 23;
|
||||
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
void
|
||||
print_offset_data::maybe_print_hole (struct ui_file *stream,
|
||||
unsigned int bitpos,
|
||||
const char *for_what)
|
||||
{
|
||||
/* We check for END_BITPOS > 0 because there is a specific
|
||||
scenario when END_BITPOS can be zero and BITPOS can be >
|
||||
0: when we are dealing with a struct/class with a virtual method.
|
||||
Because of the vtable, the first field of the struct/class will
|
||||
have an offset of sizeof (void *) (the size of the vtable). If
|
||||
we do not check for END_BITPOS > 0 here, GDB will report
|
||||
a hole before the first field, which is not accurate. */
|
||||
if (end_bitpos > 0 && end_bitpos < bitpos)
|
||||
{
|
||||
/* If END_BITPOS is smaller than the current type's
|
||||
bitpos, it means there's a hole in the struct, so we report
|
||||
it here. */
|
||||
unsigned int hole = bitpos - end_bitpos;
|
||||
unsigned int hole_byte = hole / TARGET_CHAR_BIT;
|
||||
unsigned int hole_bit = hole % TARGET_CHAR_BIT;
|
||||
|
||||
if (hole_bit > 0)
|
||||
fprintf_filtered (stream, "/* XXX %2u-bit %s */\n", hole_bit,
|
||||
for_what);
|
||||
|
||||
if (hole_byte > 0)
|
||||
fprintf_filtered (stream, "/* XXX %2u-byte %s */\n", hole_byte,
|
||||
for_what);
|
||||
}
|
||||
}
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
void
|
||||
print_offset_data::update (struct type *type, unsigned int field_idx,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
if (field_is_static (&TYPE_FIELD (type, field_idx)))
|
||||
{
|
||||
print_spaces_filtered (indentation, stream);
|
||||
return;
|
||||
}
|
||||
|
||||
struct type *ftype = check_typedef (TYPE_FIELD_TYPE (type, field_idx));
|
||||
if (TYPE_CODE (type) == TYPE_CODE_UNION)
|
||||
{
|
||||
/* Since union fields don't have the concept of offsets, we just
|
||||
print their sizes. */
|
||||
fprintf_filtered (stream, "/* %4u */", TYPE_LENGTH (ftype));
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int bitpos = TYPE_FIELD_BITPOS (type, field_idx);
|
||||
unsigned int fieldsize_byte = TYPE_LENGTH (ftype);
|
||||
unsigned int fieldsize_bit = fieldsize_byte * TARGET_CHAR_BIT;
|
||||
|
||||
maybe_print_hole (stream, bitpos, "hole");
|
||||
|
||||
if (TYPE_FIELD_PACKED (type, field_idx))
|
||||
{
|
||||
/* We're dealing with a bitfield. Print how many bits are left
|
||||
to be used. */
|
||||
unsigned int bitsize = TYPE_FIELD_BITSIZE (type, field_idx);
|
||||
/* The bitpos relative to the beginning of our container
|
||||
field. */
|
||||
unsigned int relative_bitpos;
|
||||
|
||||
/* The following was copied from
|
||||
value.c:value_primitive_field. */
|
||||
if ((bitpos % fieldsize_bit) + bitsize <= fieldsize_bit)
|
||||
relative_bitpos = bitpos % fieldsize_bit;
|
||||
else
|
||||
relative_bitpos = bitpos % TARGET_CHAR_BIT;
|
||||
|
||||
/* This is the exact offset (in bits) of this bitfield. */
|
||||
unsigned int bit_offset
|
||||
= (bitpos - relative_bitpos) + offset_bitpos;
|
||||
|
||||
/* The position of the field, relative to the beginning of the
|
||||
struct, and how many bits are left to be used in this
|
||||
container. */
|
||||
fprintf_filtered (stream, "/* %4u:%2u", bit_offset / TARGET_CHAR_BIT,
|
||||
fieldsize_bit - (relative_bitpos + bitsize));
|
||||
fieldsize_bit = bitsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The position of the field, relative to the beginning of the
|
||||
struct. */
|
||||
fprintf_filtered (stream, "/* %4u",
|
||||
(bitpos + offset_bitpos) / TARGET_CHAR_BIT);
|
||||
|
||||
fprintf_filtered (stream, " ");
|
||||
}
|
||||
|
||||
fprintf_filtered (stream, " | %4u */", fieldsize_byte);
|
||||
|
||||
end_bitpos = bitpos + fieldsize_bit;
|
||||
}
|
||||
|
||||
/* See typeprint.h. */
|
||||
|
||||
void
|
||||
print_offset_data::finish (struct type *type, int level,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
unsigned int bitpos = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
|
||||
maybe_print_hole (stream, bitpos, "padding");
|
||||
|
||||
fputs_filtered ("\n", stream);
|
||||
print_spaces_filtered (level + 4 + print_offset_data::indentation, stream);
|
||||
fprintf_filtered (stream, "/* total size (bytes): %4u */\n",
|
||||
TYPE_LENGTH (type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* A hash function for a typedef_field. */
|
||||
|
||||
static hashval_t
|
||||
|
@ -38,6 +38,39 @@ struct print_offset_data
|
||||
field (where we expect the current field to be if there is no
|
||||
hole). */
|
||||
unsigned int end_bitpos = 0;
|
||||
|
||||
/* Print information about field at index FIELD_IDX of the struct type
|
||||
TYPE and update this object.
|
||||
|
||||
If the field is static, it simply prints the correct number of
|
||||
spaces.
|
||||
|
||||
The output is strongly based on pahole(1). */
|
||||
void update (struct type *type, unsigned int field_idx,
|
||||
struct ui_file *stream);
|
||||
|
||||
/* Call when all fields have been printed. This will print
|
||||
information about any padding that may exist. LEVEL is the
|
||||
desired indentation level. */
|
||||
void finish (struct type *type, int level, struct ui_file *stream);
|
||||
|
||||
/* When printing the offsets of a struct and its fields (i.e.,
|
||||
'ptype /o'; type_print_options::print_offsets), we use this many
|
||||
characters when printing the offset information at the beginning
|
||||
of the line. This is needed in order to generate the correct
|
||||
amount of whitespaces when no offset info should be printed for a
|
||||
certain field. */
|
||||
static const int indentation;
|
||||
|
||||
private:
|
||||
|
||||
/* Helper function for ptype/o implementation that prints
|
||||
information about a hole, if necessary. STREAM is where to
|
||||
print. BITPOS is the bitpos of the current field. FOR_WHAT is a
|
||||
string describing the purpose of the hole. */
|
||||
|
||||
void maybe_print_hole (struct ui_file *stream, unsigned int bitpos,
|
||||
const char *for_what);
|
||||
};
|
||||
|
||||
struct type_print_options
|
||||
|
Loading…
x
Reference in New Issue
Block a user