mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 15:15:42 +00:00
The intent of the name lookup code was for lookups to yield non-bitfield basic types except if none existed with a given name, and only then return bitfield types with that name. Unfortunately, the code as written only does this if the base type has a type ID higher than all bitfield types, which is most unlikely (the opposite is almost always the case). Adjust it so that what ends up in the name table is the highest-width zero-offset type with a given name, if any such exist, and failing that the first type with that name we see, no matter its offset. (We don't define *which* bitfield type you get, after all, so we might as well just stuff in the first we find.) Reported by Stephen Brennan <stephen.brennan@oracle.com>. libctf/ * ctf-open.c (init_types): Modify to allow some lookups during open; detect bitfield name reuse and prefer less bitfieldy types. * testsuite/libctf-writable/libctf-bitfield-name-lookup.*: New test.
138 lines
3.4 KiB
C
138 lines
3.4 KiB
C
/* Verify that name lookup of basic types including old-style bitfield types
|
|
yields the non-bitfield. */
|
|
|
|
#include <ctf-api.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
int bitfieldery (int count, int up, int pos)
|
|
{
|
|
unsigned char *ctf_written;
|
|
size_t size;
|
|
ctf_dict_t *dict;
|
|
const char *err = "opening";
|
|
int open_err;
|
|
ctf_encoding_t en;
|
|
ctf_encoding_t basic;
|
|
ctf_id_t type;
|
|
size_t i;
|
|
|
|
/* This is rendered annoying by two factors: old-style bitfields are not
|
|
generated by current compilers, so we need to build a suitable dict by
|
|
hand; and this is an open-time bug, so we need to serialize it and then
|
|
load it back in again. */
|
|
|
|
if ((dict = ctf_create (&open_err)) == NULL)
|
|
goto open_err;
|
|
|
|
/* Populate with a pile of bitfields of increasing/decreasing size, with a
|
|
single basic type dropped in at position POS. Oscillate the offset
|
|
between 0 and 1. */
|
|
|
|
basic.cte_bits = count;
|
|
basic.cte_offset = 0;
|
|
basic.cte_format = CTF_INT_SIGNED;
|
|
|
|
en.cte_bits = up ? 0 : count - 1;
|
|
en.cte_offset = 0;
|
|
en.cte_format = CTF_INT_SIGNED;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (i == pos)
|
|
{
|
|
err = "populating with basic type";
|
|
if (ctf_add_integer (dict, CTF_ADD_ROOT, "int", &basic) < 0)
|
|
goto err;
|
|
}
|
|
|
|
err = "populating";
|
|
if (ctf_add_integer (dict, CTF_ADD_ROOT, "int", &en) < 0)
|
|
goto err;
|
|
|
|
en.cte_bits += up ? 1 : -1;
|
|
if (en.cte_offset == 0)
|
|
en.cte_offset = 1;
|
|
else
|
|
en.cte_offset = 0;
|
|
}
|
|
|
|
/* Possibly populate with at-end basic type. */
|
|
if (i == pos)
|
|
{
|
|
err = "populating with basic type";
|
|
if (ctf_add_integer (dict, CTF_ADD_ROOT, "int", &basic) < 0)
|
|
goto err;
|
|
}
|
|
|
|
err = "writing";
|
|
if ((ctf_written = ctf_write_mem (dict, &size, 4096)) == NULL)
|
|
goto err;
|
|
ctf_dict_close (dict);
|
|
|
|
err = "opening";
|
|
if ((dict = ctf_simple_open ((char *) ctf_written, size, NULL, 0,
|
|
0, NULL, 0, &open_err)) == NULL)
|
|
goto open_err;
|
|
|
|
err = "looking up";
|
|
if ((type = ctf_lookup_by_name (dict, "int")) == CTF_ERR)
|
|
goto err;
|
|
|
|
err = "encoding check";
|
|
if (ctf_type_encoding (dict, type, &en) < 0)
|
|
goto err;
|
|
|
|
if (en.cte_bits < count || en.cte_offset != 0)
|
|
{
|
|
fprintf (stderr, "Name lookup with count %i, pos %i, counting %s "
|
|
"gave bitfield ID %lx with bits %i, offset %i\n", count, pos,
|
|
up ? "up" : "down", type, en.cte_bits, en.cte_offset);
|
|
return 1;
|
|
}
|
|
ctf_dict_close (dict);
|
|
free (ctf_written);
|
|
|
|
return 0;
|
|
|
|
open_err:
|
|
fprintf (stdout, "Error %s: %s\n", err, ctf_errmsg (open_err));
|
|
return 1;
|
|
|
|
err:
|
|
fprintf (stdout, "Error %s: %s\n", err, ctf_errmsg (ctf_errno (dict)));
|
|
return 1;
|
|
}
|
|
|
|
/* Do a bunch of tests with a type of a given size: up and down, basic type
|
|
at and near the start and end, and in the middle. */
|
|
|
|
void mass_bitfieldery (long size)
|
|
{
|
|
size *= 8;
|
|
bitfieldery (size, 1, 0);
|
|
bitfieldery (size, 0, 0);
|
|
bitfieldery (size, 1, 1);
|
|
bitfieldery (size, 0, 1);
|
|
bitfieldery (size, 1, size / 2);
|
|
bitfieldery (size, 0, size / 2);
|
|
bitfieldery (size, 1, size - 1);
|
|
bitfieldery (size, 0, size - 1);
|
|
bitfieldery (size, 1, size);
|
|
bitfieldery (size, 0, size);
|
|
}
|
|
|
|
int main (void)
|
|
{
|
|
mass_bitfieldery (sizeof (char));
|
|
mass_bitfieldery (sizeof (short));
|
|
mass_bitfieldery (sizeof (int));
|
|
mass_bitfieldery (sizeof (long));
|
|
mass_bitfieldery (sizeof (uint64_t));
|
|
|
|
printf ("All done.\n");
|
|
|
|
return 0;
|
|
}
|