Add initial type alignment support

This adds some basic type alignment support to gdb.  It changes struct
type to store the alignment, and updates dwarf2read.c to handle
DW_AT_alignment.  It also adds a new gdbarch method and updates
i386-tdep.c.

None of this new functionality is used anywhere yet, so tests will
wait until the next patch.

2018-04-30  Tom Tromey  <tom@tromey.com>

	* i386-tdep.c (i386_type_align): New function.
	(i386_gdbarch_init): Update.
	* gdbarch.sh (type_align): New method.
	* gdbarch.c, gdbarch.h: Rebuild.
	* arch-utils.h (default_type_align): Declare.
	* arch-utils.c (default_type_align): New function.
	* gdbtypes.h (TYPE_ALIGN_BITS): New define.
	(struct type) <align_log2>: New field.
	<instance_flags>: Now a bitfield.
	(TYPE_RAW_ALIGN): New macro.
	(type_align, type_raw_align, set_type_align): Declare.
	* gdbtypes.c (type_align, type_raw_align, set_type_align): New
	functions.
	* dwarf2read.c (quirk_rust_enum): Set type alignment.
	(get_alignment, maybe_set_alignment): New functions.
	(read_structure_type, read_enumeration_type, read_array_type)
	(read_set_type, read_tag_pointer_type, read_tag_reference_type)
	(read_subrange_type, read_base_type): Set type alignment.
This commit is contained in:
Tom Tromey 2018-04-20 11:50:09 -06:00
parent fe944acf8f
commit 2b4424c35b
10 changed files with 359 additions and 5 deletions

View File

@ -1,3 +1,24 @@
2018-04-30 Tom Tromey <tom@tromey.com>
* i386-tdep.c (i386_type_align): New function.
(i386_gdbarch_init): Update.
* gdbarch.sh (type_align): New method.
* gdbarch.c, gdbarch.h: Rebuild.
* arch-utils.h (default_type_align): Declare.
* arch-utils.c (default_type_align): New function.
* gdbtypes.h (TYPE_ALIGN_BITS): New define.
(struct type) <align_log2>: New field.
<instance_flags>: Now a bitfield.
(TYPE_RAW_ALIGN): New macro.
(type_align, type_raw_align, set_type_align): Declare.
* gdbtypes.c (type_align, type_raw_align, set_type_align): New
functions.
* dwarf2read.c (quirk_rust_enum): Set type alignment.
(get_alignment, maybe_set_alignment): New functions.
(read_structure_type, read_enumeration_type, read_array_type)
(read_set_type, read_tag_pointer_type, read_tag_reference_type)
(read_subrange_type, read_base_type): Set type alignment.
2018-04-30 Simon Marchi <simon.marchi@ericsson.com>
* dwarf2read.c (read_index_from_section): Use bool.

View File

@ -987,6 +987,14 @@ default_in_indirect_branch_thunk (gdbarch *gdbarch, CORE_ADDR pc)
return false;
}
/* See arch-utils.h. */
ULONGEST
default_type_align (struct gdbarch *gdbarch, struct type *type)
{
return TYPE_LENGTH (check_typedef (type));
}
void
_initialize_gdbarch_utils (void)
{

View File

@ -267,4 +267,8 @@ extern CORE_ADDR gdbarch_skip_prologue_noexcept (gdbarch *gdbarch,
extern bool default_in_indirect_branch_thunk (gdbarch *gdbarch,
CORE_ADDR pc);
/* Default implementation of gdbarch type_align method. */
extern ULONGEST default_type_align (struct gdbarch *gdbarch,
struct type *type);
#endif

View File

@ -9907,6 +9907,7 @@ quirk_rust_enum (struct type *type, struct objfile *objfile)
TYPE_FIELDS (union_type)
= (struct field *) TYPE_ZALLOC (type, 3 * sizeof (struct field));
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
set_type_align (union_type, TYPE_RAW_ALIGN (type));
/* Put the discriminant must at index 0. */
TYPE_FIELD_TYPE (union_type, 0) = field_type;
@ -9962,6 +9963,7 @@ quirk_rust_enum (struct type *type, struct objfile *objfile)
TYPE_CODE (union_type) = TYPE_CODE_UNION;
TYPE_NFIELDS (union_type) = TYPE_NFIELDS (type);
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
set_type_align (union_type, TYPE_RAW_ALIGN (type));
TYPE_FIELDS (union_type) = TYPE_FIELDS (type);
struct type *field_type = TYPE_FIELD_TYPE (union_type, 0);
@ -10027,6 +10029,7 @@ quirk_rust_enum (struct type *type, struct objfile *objfile)
TYPE_CODE (union_type) = TYPE_CODE_UNION;
TYPE_NFIELDS (union_type) = 1 + TYPE_NFIELDS (type);
TYPE_LENGTH (union_type) = TYPE_LENGTH (type);
set_type_align (union_type, TYPE_RAW_ALIGN (type));
TYPE_FIELDS (union_type)
= (struct field *) TYPE_ZALLOC (union_type,
(TYPE_NFIELDS (union_type)
@ -15578,6 +15581,82 @@ quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile)
smash_to_methodptr_type (type, new_type);
}
/* If the DIE has a DW_AT_alignment attribute, return its value, doing
appropriate error checking and issuing complaints if there is a
problem. */
static ULONGEST
get_alignment (struct dwarf2_cu *cu, struct die_info *die)
{
struct attribute *attr = dwarf2_attr (die, DW_AT_alignment, cu);
if (attr == nullptr)
return 0;
if (!attr_form_is_constant (attr))
{
complaint (&symfile_complaints,
_("DW_AT_alignment must have constant form"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
return 0;
}
ULONGEST align;
if (attr->form == DW_FORM_sdata)
{
LONGEST val = DW_SND (attr);
if (val < 0)
{
complaint (&symfile_complaints,
_("DW_AT_alignment value must not be negative"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
return 0;
}
align = val;
}
else
align = DW_UNSND (attr);
if (align == 0)
{
complaint (&symfile_complaints,
_("DW_AT_alignment value must not be zero"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
return 0;
}
if ((align & (align - 1)) != 0)
{
complaint (&symfile_complaints,
_("DW_AT_alignment value must be a power of 2"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
return 0;
}
return align;
}
/* If the DIE has a DW_AT_alignment attribute, use its value to set
the alignment for TYPE. */
static void
maybe_set_alignment (struct dwarf2_cu *cu, struct die_info *die,
struct type *type)
{
if (!set_type_align (type, get_alignment (cu, die)))
complaint (&symfile_complaints,
_("DW_AT_alignment value too large"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
}
/* Called when we find the DIE that starts a structure or union scope
(definition) to create a type for the structure or union. Fill in
@ -15688,6 +15767,8 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
TYPE_LENGTH (type) = 0;
}
maybe_set_alignment (cu, die, type);
if (producer_is_icc_lt_14 (cu) && (TYPE_LENGTH (type) == 0))
{
/* ICC<14 does not output the required DW_AT_declaration on
@ -16132,6 +16213,8 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
TYPE_LENGTH (type) = 0;
}
maybe_set_alignment (cu, die, type);
/* The enumeration DIE can be incomplete. In Ada, any type can be
declared as private in the package spec, and then defined only
inside the package body. Such types are known as Taft Amendment
@ -16157,6 +16240,9 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TYPE_TARGET_TYPE (type));
if (TYPE_LENGTH (type) == 0)
TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type));
if (TYPE_RAW_ALIGN (type) == 0
&& TYPE_RAW_ALIGN (TYPE_TARGET_TYPE (type)) != 0)
set_type_align (type, TYPE_RAW_ALIGN (TYPE_TARGET_TYPE (type)));
}
TYPE_DECLARED_CLASS (type) = dwarf2_flag_true_p (die, DW_AT_enum_class, cu);
@ -16381,6 +16467,8 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
if (name)
TYPE_NAME (type) = name;
maybe_set_alignment (cu, die, type);
/* Install the type in the die. */
set_die_type (die, type, cu);
@ -16445,6 +16533,8 @@ read_set_type (struct die_info *die, struct dwarf2_cu *cu)
if (attr)
TYPE_LENGTH (set_type) = DW_UNSND (attr);
maybe_set_alignment (cu, die, set_type);
return set_die_type (die, set_type, cu);
}
@ -16816,10 +16906,15 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
else
addr_class = DW_ADDR_none;
/* If the pointer size or address class is different than the
default, create a type variant marked as such and set the
length accordingly. */
if (TYPE_LENGTH (type) != byte_size || addr_class != DW_ADDR_none)
ULONGEST alignment = get_alignment (cu, die);
/* If the pointer size, alignment, or address class is different
than the default, create a type variant marked as such and set
the length accordingly. */
if (TYPE_LENGTH (type) != byte_size
|| (alignment != 0 && TYPE_RAW_ALIGN (type) != 0
&& alignment != TYPE_RAW_ALIGN (type))
|| addr_class != DW_ADDR_none)
{
if (gdbarch_address_class_type_flags_p (gdbarch))
{
@ -16836,6 +16931,14 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
complaint (&symfile_complaints,
_("invalid pointer size %d"), byte_size);
}
else if (TYPE_RAW_ALIGN (type) != alignment)
{
complaint (&symfile_complaints,
_("Invalid DW_AT_alignment"
" - DIE at %s [in module %s]"),
sect_offset_str (die->sect_off),
objfile_name (cu->per_cu->dwarf2_per_objfile->objfile));
}
else
{
/* Should we also complain about unhandled address classes? */
@ -16843,6 +16946,7 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
}
TYPE_LENGTH (type) = byte_size;
set_type_align (type, alignment);
return set_die_type (die, type, cu);
}
@ -16912,6 +17016,7 @@ read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu,
{
TYPE_LENGTH (type) = cu_header->addr_size;
}
maybe_set_alignment (cu, die, type);
return set_die_type (die, type, cu);
}
@ -17398,6 +17503,8 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
if (name && strcmp (name, "char") == 0)
TYPE_NOSIGN (type) = 1;
maybe_set_alignment (cu, die, type);
return set_die_type (die, type, cu);
}
@ -17660,6 +17767,8 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
if (attr)
TYPE_LENGTH (range_type) = DW_UNSND (attr);
maybe_set_alignment (cu, die, range_type);
set_die_type (die, range_type, cu);
/* set_die_type should be already done. */

View File

@ -353,6 +353,7 @@ struct gdbarch
gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size;
char ** disassembler_options;
const disasm_options_t * valid_disassembler_options;
gdbarch_type_align_ftype *type_align;
};
/* Create a new ``struct gdbarch'' based on information provided by
@ -465,6 +466,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->gcc_target_options = default_gcc_target_options;
gdbarch->gnu_triplet_regexp = default_gnu_triplet_regexp;
gdbarch->addressable_memory_unit_size = default_addressable_memory_unit_size;
gdbarch->type_align = default_type_align;
/* gdbarch_alloc() */
return gdbarch;
@ -716,6 +718,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of addressable_memory_unit_size, invalid_p == 0 */
/* Skip verify of disassembler_options, invalid_p == 0 */
/* Skip verify of valid_disassembler_options, invalid_p == 0 */
/* Skip verify of type_align, invalid_p == 0 */
if (!log.empty ())
internal_error (__FILE__, __LINE__,
_("verify_gdbarch: the following are invalid ...%s"),
@ -1441,6 +1444,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: target_desc = %s\n",
host_address_to_string (gdbarch->target_desc));
fprintf_unfiltered (file,
"gdbarch_dump: type_align = <%s>\n",
host_address_to_string (gdbarch->type_align));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
gdbarch_unwind_pc_p (gdbarch));
@ -5100,6 +5106,23 @@ set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch,
gdbarch->valid_disassembler_options = valid_disassembler_options;
}
ULONGEST
gdbarch_type_align (struct gdbarch *gdbarch, struct type *type)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->type_align != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_type_align called\n");
return gdbarch->type_align (gdbarch, type);
}
void
set_gdbarch_type_align (struct gdbarch *gdbarch,
gdbarch_type_align_ftype type_align)
{
gdbarch->type_align = type_align;
}
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */

View File

@ -1560,6 +1560,12 @@ extern void set_gdbarch_disassembler_options (struct gdbarch *gdbarch, char ** d
extern const disasm_options_t * gdbarch_valid_disassembler_options (struct gdbarch *gdbarch);
extern void set_gdbarch_valid_disassembler_options (struct gdbarch *gdbarch, const disasm_options_t * valid_disassembler_options);
/* Type alignment. */
typedef ULONGEST (gdbarch_type_align_ftype) (struct gdbarch *gdbarch, struct type *type);
extern ULONGEST gdbarch_type_align (struct gdbarch *gdbarch, struct type *type);
extern void set_gdbarch_type_align (struct gdbarch *gdbarch, gdbarch_type_align_ftype *type_align);
/* Definition for an unknown syscall, used basically in error-cases. */
#define UNKNOWN_SYSCALL (-1)

View File

@ -1163,6 +1163,9 @@ m;int;addressable_memory_unit_size;void;;;default_addressable_memory_unit_size;;
v;char **;disassembler_options;;;0;0;;0;pstring_ptr (gdbarch->disassembler_options)
v;const disasm_options_t *;valid_disassembler_options;;;0;0;;0;host_address_to_string (gdbarch->valid_disassembler_options)
# Type alignment.
m;ULONGEST;type_align;struct type *type;type;;default_type_align;;0
EOF
}

View File

@ -3013,6 +3013,128 @@ init_pointer_type (struct objfile *objfile,
return t;
}
/* See gdbtypes.h. */
unsigned
type_raw_align (struct type *type)
{
if (type->align_log2 != 0)
return 1 << (type->align_log2 - 1);
return 0;
}
/* See gdbtypes.h. */
unsigned
type_align (struct type *type)
{
unsigned raw_align = type_raw_align (type);
if (raw_align != 0)
return raw_align;
ULONGEST align = 0;
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
case TYPE_CODE_FUNC:
case TYPE_CODE_FLAGS:
case TYPE_CODE_INT:
case TYPE_CODE_FLT:
case TYPE_CODE_ENUM:
case TYPE_CODE_REF:
case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_CHAR:
case TYPE_CODE_BOOL:
case TYPE_CODE_DECFLOAT:
{
struct gdbarch *arch = get_type_arch (type);
align = gdbarch_type_align (arch, type);
}
break;
case TYPE_CODE_ARRAY:
case TYPE_CODE_COMPLEX:
case TYPE_CODE_TYPEDEF:
align = type_align (TYPE_TARGET_TYPE (type));
break;
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
{
if (TYPE_NFIELDS (type) == 0)
{
/* An empty struct has alignment 1. */
align = 1;
break;
}
for (unsigned i = 0; i < TYPE_NFIELDS (type); ++i)
{
ULONGEST f_align = type_align (TYPE_FIELD_TYPE (type, i));
if (f_align == 0)
{
/* Don't pretend we know something we don't. */
align = 0;
break;
}
if (f_align > align)
align = f_align;
}
}
break;
case TYPE_CODE_SET:
case TYPE_CODE_RANGE:
case TYPE_CODE_STRING:
/* Not sure what to do here, and these can't appear in C or C++
anyway. */
break;
case TYPE_CODE_METHODPTR:
case TYPE_CODE_MEMBERPTR:
align = TYPE_LENGTH (type);
break;
case TYPE_CODE_VOID:
align = 1;
break;
case TYPE_CODE_ERROR:
case TYPE_CODE_METHOD:
default:
break;
}
if ((align & (align - 1)) != 0)
{
/* Not a power of 2, so pass. */
align = 0;
}
return align;
}
/* See gdbtypes.h. */
bool
set_type_align (struct type *type, ULONGEST align)
{
/* Must be a power of 2. Zero is ok. */
gdb_assert ((align & (align - 1)) == 0);
unsigned result = 0;
while (align != 0)
{
++result;
align >>= 1;
}
if (result >= (1 << TYPE_ALIGN_BITS))
return false;
type->align_log2 = result;
return true;
}
/* Queries on types. */

View File

@ -802,6 +802,10 @@ struct main_type
struct dynamic_prop_list *dyn_prop_list;
};
/* * Number of bits allocated for alignment. */
#define TYPE_ALIGN_BITS 8
/* * A ``struct type'' describes a particular instance of a type, with
some particular qualification. */
@ -831,6 +835,14 @@ struct type
struct type *chain;
/* * The alignment for this type. Zero means that the alignment was
not specified in the debug info. Note that this is stored in a
funny way: as the log base 2 (plus 1) of the alignment; so a
value of 1 means the alignment is 1, and a value of 9 means the
alignment is 256. */
unsigned align_log2 : TYPE_ALIGN_BITS;
/* * Flags specific to this instance of the type, indicating where
on the ring we are.
@ -841,7 +853,7 @@ struct type
instance flags are completely inherited from the target type. No
qualifiers can be cleared by the typedef. See also
check_typedef. */
int instance_flags;
unsigned instance_flags : 9;
/* * Length of storage for a value of this type. The value is the
expression in host bytes of what sizeof(type) would return. This
@ -1292,6 +1304,26 @@ extern void allocate_gnat_aux_type (struct type *);
so you only have to call check_typedef once. Since allocate_value
calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */
#define TYPE_LENGTH(thistype) (thistype)->length
/* * Return the alignment of the type in target addressable memory
units, or 0 if no alignment was specified. */
#define TYPE_RAW_ALIGN(thistype) type_raw_align (thistype)
/* * Return the alignment of the type in target addressable memory
units, or 0 if no alignment was specified. */
extern unsigned type_raw_align (struct type *);
/* * Return the alignment of the type in target addressable memory
units. Return 0 if the alignment cannot be determined; but note
that this makes an effort to compute the alignment even it it was
not specified in the debug info. */
extern unsigned type_align (struct type *);
/* * Set the alignment of the type. The alignment must be a power of
2. Returns false if the given value does not fit in the available
space in struct type. */
extern bool set_type_align (struct type *, ULONGEST);
/* * Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real
type, you need to do TYPE_CODE (check_type (this_type)). */
#define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code

View File

@ -8346,6 +8346,31 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
return valid_p;
}
/* Implement the type_align gdbarch function. */
static ULONGEST
i386_type_align (struct gdbarch *gdbarch, struct type *type)
{
type = check_typedef (type);
if (gdbarch_ptr_bit (gdbarch) == 32)
{
if ((TYPE_CODE (type) == TYPE_CODE_INT
|| TYPE_CODE (type) == TYPE_CODE_FLT)
&& TYPE_LENGTH (type) > 4)
return 4;
/* Handle x86's funny long double. */
if (TYPE_CODE (type) == TYPE_CODE_FLT
&& gdbarch_long_double_bit (gdbarch) == TYPE_LENGTH (type) * 8)
return 4;
}
return TYPE_LENGTH (type);
}
/* Note: This is called for both i386 and amd64. */
@ -8405,6 +8430,7 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->record_regmap = i386_record_regmap;
set_gdbarch_long_long_align_bit (gdbarch, 32);
set_gdbarch_type_align (gdbarch, i386_type_align);
/* The format used for `long double' on almost all i386 targets is
the i387 extended floating-point format. In fact, of all targets