forked from Imagelibrary/binutils-gdb
libctf: create: structure and union member addition
There is one API addition here:
int ctf_add_member_bitfield (ctf_dict_t *, ctf_id_t souid,
const char *, ctf_id_t type,
unsigned long bit_offset,
int bit_width);
SoU addition handles the representational changes for bitfields and for
CTF_K_BIG structs (i.e. all structs you can add members to), errors out if
you add bitfields to structs that aren't created with the
CTF_ADD_STRUCT_BITFIELDS flag, and arranges to add padding as needed if
there is too much of a gap for the offsets to encode in one hop (that
part is still untested).
This commit is contained in:
@@ -871,7 +871,9 @@ extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int);
|
|||||||
/* Add a member to a struct or union, either at the next available offset (with
|
/* Add a member to a struct or union, either at the next available offset (with
|
||||||
suitable padding for the alignment) or at a specific offset, and possibly
|
suitable padding for the alignment) or at a specific offset, and possibly
|
||||||
with a specific encoding (creating a slice for you). Offsets need not be
|
with a specific encoding (creating a slice for you). Offsets need not be
|
||||||
unique, and need not be added in ascending order. */
|
unique, and need not be added in ascending order. ctf_add_member_bitfield
|
||||||
|
with a nonzero bit_width will fail unless the struct was created with
|
||||||
|
CTF_ADD_STRUCT_BITFIELDS. */
|
||||||
|
|
||||||
extern int ctf_add_member (ctf_dict_t *, ctf_id_t, const char *, ctf_id_t);
|
extern int ctf_add_member (ctf_dict_t *, ctf_id_t, const char *, ctf_id_t);
|
||||||
extern int ctf_add_member_offset (ctf_dict_t *, ctf_id_t, const char *,
|
extern int ctf_add_member_offset (ctf_dict_t *, ctf_id_t, const char *,
|
||||||
@@ -879,6 +881,10 @@ extern int ctf_add_member_offset (ctf_dict_t *, ctf_id_t, const char *,
|
|||||||
extern int ctf_add_member_encoded (ctf_dict_t *, ctf_id_t, const char *,
|
extern int ctf_add_member_encoded (ctf_dict_t *, ctf_id_t, const char *,
|
||||||
ctf_id_t, unsigned long,
|
ctf_id_t, unsigned long,
|
||||||
const ctf_encoding_t);
|
const ctf_encoding_t);
|
||||||
|
extern int ctf_add_member_bitfield (ctf_dict_t *, ctf_id_t souid,
|
||||||
|
const char *, ctf_id_t type,
|
||||||
|
unsigned long bit_offset,
|
||||||
|
int bit_width);
|
||||||
|
|
||||||
extern int ctf_add_variable (ctf_dict_t *, const char *, ctf_id_t);
|
extern int ctf_add_variable (ctf_dict_t *, const char *, ctf_id_t);
|
||||||
|
|
||||||
|
|||||||
@@ -1276,18 +1276,21 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
ctf_add_member_bitfield (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
||||||
ctf_id_t type, unsigned long bit_offset)
|
ctf_id_t type, unsigned long bit_offset,
|
||||||
|
int bit_width)
|
||||||
{
|
{
|
||||||
ctf_dict_t *ofp = fp;
|
ctf_dict_t *ofp = fp;
|
||||||
ctf_dict_t *tmp = fp;
|
ctf_dict_t *tmp = fp;
|
||||||
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid);
|
ctf_dtdef_t *dtd;
|
||||||
|
ctf_type_t *prefix;
|
||||||
|
|
||||||
ssize_t msize, malign, ssize;
|
ssize_t msize, ssize;
|
||||||
uint32_t kind, vlen, root;
|
uint32_t kind, kflag;
|
||||||
|
size_t vlen;
|
||||||
size_t i;
|
size_t i;
|
||||||
int is_incomplete = 0;
|
int is_incomplete = 0;
|
||||||
ctf_lmember_t *memb;
|
ctf_member_t *memb;
|
||||||
|
|
||||||
if (fp->ctf_flags & LCTF_NO_STR)
|
if (fp->ctf_flags & LCTF_NO_STR)
|
||||||
return (ctf_set_errno (fp, ECTF_NOPARENT));
|
return (ctf_set_errno (fp, ECTF_NOPARENT));
|
||||||
@@ -1306,53 +1309,71 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
|||||||
fp = fp->ctf_parent;
|
fp = fp->ctf_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtd = ctf_dtd_lookup (fp, souid);
|
||||||
|
|
||||||
if (souid < fp->ctf_stypes)
|
if (souid < fp->ctf_stypes)
|
||||||
return (ctf_set_errno (ofp, ECTF_RDONLY));
|
return (ctf_set_errno (ofp, ECTF_RDONLY));
|
||||||
|
|
||||||
if (dtd == NULL)
|
if (dtd == NULL)
|
||||||
return (ctf_set_errno (ofp, ECTF_BADID));
|
return (ctf_set_errno (ofp, ECTF_BADID));
|
||||||
|
|
||||||
if ((ctf_lookup_by_id (&tmp, type)) == NULL)
|
if ((ctf_lookup_by_id (&tmp, type, NULL)) == NULL)
|
||||||
return -1; /* errno is set for us. */
|
return -1; /* errno is set for us. */
|
||||||
|
|
||||||
if (name != NULL && name[0] == '\0')
|
if (name != NULL && name[0] == '\0')
|
||||||
name = NULL;
|
name = NULL;
|
||||||
|
|
||||||
kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
|
if ((prefix = (ctf_type_t *) ctf_find_prefix (fp, dtd->dtd_buf, CTF_K_BIG)) == NULL)
|
||||||
root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
|
return (ctf_set_errno (ofp, ECTF_CORRUPT));
|
||||||
vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
|
|
||||||
|
kind = LCTF_KIND (fp, prefix);
|
||||||
|
kflag = CTF_INFO_KFLAG (dtd->dtd_data->ctt_info);
|
||||||
|
vlen = LCTF_VLEN (fp, prefix);
|
||||||
|
|
||||||
if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
|
if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
|
||||||
return (ctf_set_errno (ofp, ECTF_NOTSOU));
|
return (ctf_set_errno (ofp, ECTF_NOTSOU));
|
||||||
|
|
||||||
|
if (!kflag && bit_width != 0)
|
||||||
|
return (ctf_set_errno (ofp, ECTF_NOTBITSOU));
|
||||||
|
|
||||||
if (vlen == CTF_MAX_VLEN)
|
if (vlen == CTF_MAX_VLEN)
|
||||||
return (ctf_set_errno (ofp, ECTF_DTFULL));
|
return (ctf_set_errno (ofp, ECTF_DTFULL));
|
||||||
|
|
||||||
if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
|
/* Figure out the offset of this field: all structures in DTDs
|
||||||
return (ctf_set_errno (ofp, ctf_errno (fp)));
|
are CTF_K_BIG, which means their offsets are all encoded as
|
||||||
memb = (ctf_lmember_t *) dtd->dtd_vlen;
|
distances from the last field's. */
|
||||||
|
|
||||||
|
if (bit_offset != (unsigned long) -1)
|
||||||
|
{
|
||||||
|
if (bit_offset < dtd->dtd_last_offset)
|
||||||
|
return (ctf_set_errno (ofp, ECTF_DESCENDING));
|
||||||
|
|
||||||
|
bit_offset -= dtd->dtd_last_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
memb = (ctf_member_t *) dtd->dtd_vlen;
|
||||||
|
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
{
|
{
|
||||||
for (i = 0; i < vlen; i++)
|
for (i = 0; i < vlen; i++)
|
||||||
if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
|
if (strcmp (ctf_strptr (fp, memb[i].ctm_name), name) == 0)
|
||||||
return (ctf_set_errno (ofp, ECTF_DUPLICATE));
|
return (ctf_set_errno (ofp, ECTF_DUPLICATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((msize = ctf_type_size (fp, type)) < 0 ||
|
if ((msize = ctf_type_size (fp, type)) < 0 ||
|
||||||
(malign = ctf_type_align (fp, type)) < 0)
|
(ctf_type_align (fp, type)) < 0)
|
||||||
{
|
{
|
||||||
/* The unimplemented type, and any type that resolves to it, has no size
|
/* The unimplemented type, and any type that resolves to it, has no size
|
||||||
and no alignment: it can correspond to any number of compiler-inserted
|
and no alignment: it can correspond to any number of compiler-inserted
|
||||||
types. We allow incomplete types through since they are routinely
|
types. We allow incomplete types through since they are routinely
|
||||||
added to the ends of structures, and can even be added elsewhere in
|
added to the ends of structures, and can even be added elsewhere in
|
||||||
structures by the deduplicator. They are assumed to be zero-size with
|
structures by the deduplicator and by the padding inserter below. They
|
||||||
no alignment: this is often wrong, but problems can be avoided in this
|
are assumed to be zero-size with no alignment: this is often wrong, but
|
||||||
case by explicitly specifying the size of the structure via the _sized
|
problems can be avoided in this case by explicitly specifying the size
|
||||||
functions. The deduplicator always does this. */
|
of the structure via the _sized functions. The deduplicator always
|
||||||
|
does this. */
|
||||||
|
|
||||||
msize = 0;
|
msize = 0;
|
||||||
malign = 0;
|
|
||||||
if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
|
if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
|
||||||
ctf_set_errno (fp, 0);
|
ctf_set_errno (fp, 0);
|
||||||
else if (ctf_errno (fp) == ECTF_INCOMPLETE)
|
else if (ctf_errno (fp) == ECTF_INCOMPLETE)
|
||||||
@@ -1361,95 +1382,130 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
|||||||
return -1; /* errno is set for us. */
|
return -1; /* errno is set for us. */
|
||||||
}
|
}
|
||||||
|
|
||||||
memb[vlen].ctlm_name = ctf_str_add (fp, name);
|
/* Figure out the right offset for naturally-aligned types, if need be,
|
||||||
memb[vlen].ctlm_type = type;
|
and insert additional unnamed members as needed. */
|
||||||
if (memb[vlen].ctlm_name == 0 && name != NULL && name[0] != '\0')
|
|
||||||
return -1; /* errno is set for us. */
|
|
||||||
|
|
||||||
if (kind == CTF_K_STRUCT && vlen != 0)
|
if (kind == CTF_K_UNION || vlen == 0)
|
||||||
{
|
{
|
||||||
|
bit_offset = 0;
|
||||||
|
ssize = ctf_get_ctt_size (fp, prefix, NULL, NULL);
|
||||||
|
ssize = MAX (ssize, msize);
|
||||||
|
}
|
||||||
|
else /* Subsequent struct member. */
|
||||||
|
{
|
||||||
|
size_t bound;
|
||||||
|
ssize_t off;
|
||||||
|
int added_padding = 0;
|
||||||
|
|
||||||
if (bit_offset == (unsigned long) - 1)
|
if (bit_offset == (unsigned long) - 1)
|
||||||
{
|
{
|
||||||
/* Natural alignment. */
|
/* Natural alignment. */
|
||||||
|
|
||||||
ctf_id_t ltype = ctf_type_resolve (fp, memb[vlen - 1].ctlm_type);
|
|
||||||
size_t off = CTF_LMEM_OFFSET(&memb[vlen - 1]);
|
|
||||||
|
|
||||||
ctf_encoding_t linfo;
|
|
||||||
ssize_t lsize;
|
|
||||||
|
|
||||||
/* Propagate any error from ctf_type_resolve. If the last member was
|
|
||||||
of unimplemented type, this may be -ECTF_NONREPRESENTABLE: we
|
|
||||||
cannot insert right after such a member without explicit offset
|
|
||||||
specification, because its alignment and size is not known. */
|
|
||||||
if (ltype == CTF_ERR)
|
|
||||||
return -1; /* errno is set for us. */
|
|
||||||
|
|
||||||
if (is_incomplete)
|
if (is_incomplete)
|
||||||
{
|
{
|
||||||
ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
|
ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
|
||||||
_("ctf_add_member_offset: cannot add member %s of "
|
_("ctf_add_member: cannot add member %s of "
|
||||||
"incomplete type %lx to struct %lx without "
|
"incomplete type %lx to struct %lx without "
|
||||||
"specifying explicit offset\n"),
|
"specifying explicit offset\n"),
|
||||||
name ? name : _("(unnamed member)"), type, souid);
|
name ? name : _("(unnamed member)"), type, souid);
|
||||||
return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
|
return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctf_type_encoding (fp, ltype, &linfo) == 0)
|
if ((off = ctf_type_align_natural (fp, memb[vlen - 1].ctm_type,
|
||||||
off += linfo.cte_bits;
|
type, dtd->dtd_last_offset)) < 0)
|
||||||
else if ((lsize = ctf_type_size (fp, ltype)) > 0)
|
|
||||||
off += lsize * CHAR_BIT;
|
|
||||||
else if (lsize == -1 && ctf_errno (fp) == ECTF_INCOMPLETE)
|
|
||||||
{
|
{
|
||||||
const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name);
|
if (ctf_errno (fp) == ECTF_INCOMPLETE)
|
||||||
|
{
|
||||||
|
const char *lname = ctf_strraw (fp, memb[vlen - 1].ctm_name);
|
||||||
|
|
||||||
ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
|
ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
|
||||||
_("ctf_add_member_offset: cannot add member %s of "
|
_("ctf_add_member_offset: cannot add member %s "
|
||||||
"type %lx to struct %lx without specifying "
|
"of type %lx to struct %lx without "
|
||||||
"explicit offset after member %s of type %lx, "
|
"specifying explicit offset after member %s"
|
||||||
"which is an incomplete type\n"),
|
"of type %x, which is an incomplete type\n"),
|
||||||
name ? name : _("(unnamed member)"), type, souid,
|
name ? name : _("(unnamed member)"), type, souid,
|
||||||
lname ? lname : _("(unnamed member)"), ltype);
|
lname ? lname : _("(unnamed member)"),
|
||||||
return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
|
memb[vlen -1].ctm_type);
|
||||||
|
}
|
||||||
|
return (ctf_set_errno (ofp, ctf_errno (fp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Round up the offset of the end of the last member to
|
/* Convert the offset to a gap-since-the-last. */
|
||||||
the next byte boundary, convert 'off' to bytes, and
|
off -= dtd->dtd_last_offset;
|
||||||
then round it up again to the next multiple of the
|
bit_offset = off;
|
||||||
alignment required by the new member. Finally,
|
|
||||||
convert back to bits and store the result in
|
|
||||||
dmd_offset. Technically we could do more efficient
|
|
||||||
packing if the new member is a bit-field, but we're
|
|
||||||
the "compiler" and ANSI says we can do as we choose. */
|
|
||||||
|
|
||||||
off = roundup (off, CHAR_BIT) / CHAR_BIT;
|
|
||||||
off = roundup (off, MAX (malign, 1));
|
|
||||||
memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (off * CHAR_BIT);
|
|
||||||
memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (off * CHAR_BIT);
|
|
||||||
ssize = off + msize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Insert as many nameless members as needed. */
|
||||||
|
|
||||||
|
if (kflag)
|
||||||
|
bound = CTF_MAX_BIT_OFFSET;
|
||||||
else
|
else
|
||||||
|
bound = CTF_MAX_SIZE;
|
||||||
|
|
||||||
|
while (bit_offset > bound)
|
||||||
{
|
{
|
||||||
/* Specified offset in bits. */
|
added_padding = 1;
|
||||||
|
|
||||||
memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (bit_offset);
|
off = bound;
|
||||||
memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (bit_offset);
|
if (kflag)
|
||||||
ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
|
off = CTF_MEMBER_BIT_OFFSET (bound);
|
||||||
ssize = MAX (ssize, ((signed) bit_offset / CHAR_BIT) + msize);
|
|
||||||
|
if (ctf_add_member_bitfield (fp, souid, "", 0, off, 0) < 0)
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
|
||||||
|
bit_offset =- off;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
off = bit_offset;
|
||||||
{
|
if (kflag)
|
||||||
memb[vlen].ctlm_offsethi = 0;
|
off = CTF_MEMBER_BIT_OFFSET (off);
|
||||||
memb[vlen].ctlm_offsetlo = 0;
|
|
||||||
ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
|
/* Possibly hunt down the prefix and member list again: they may have been
|
||||||
ssize = MAX (ssize, msize);
|
moved by the realloc()s involved in field additions. */
|
||||||
|
|
||||||
|
if (added_padding
|
||||||
|
&& (prefix = (ctf_type_t *) ctf_find_prefix (fp, dtd->dtd_buf, CTF_K_BIG)) == NULL)
|
||||||
|
return (ctf_set_errno (ofp, ECTF_CORRUPT));
|
||||||
|
|
||||||
|
vlen = LCTF_VLEN (fp, prefix);
|
||||||
|
memb = (ctf_member_t *) dtd->dtd_vlen;
|
||||||
|
bit_offset = off;
|
||||||
|
|
||||||
|
ssize = ctf_get_ctt_size (fp, prefix, NULL, NULL);
|
||||||
|
ssize = MAX (ssize, ((signed) ((bit_offset + dtd->dtd_last_offset)) / CHAR_BIT) + msize);
|
||||||
}
|
}
|
||||||
|
|
||||||
dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
|
if (kflag)
|
||||||
dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
|
memb[vlen].ctm_offset = CTF_MEMBER_MAKE_BIT_OFFSET (bit_width, bit_offset);
|
||||||
dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize);
|
else
|
||||||
dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
|
memb[vlen].ctm_offset = bit_offset;
|
||||||
|
|
||||||
|
vlen = LCTF_VLEN (fp, prefix);
|
||||||
|
|
||||||
|
if (ctf_grow_vlen (fp, dtd, sizeof (ctf_member_t) * (vlen + 1)) < 0)
|
||||||
|
return (ctf_set_errno (ofp, ctf_errno (fp)));
|
||||||
|
|
||||||
|
dtd->dtd_vlen_size += sizeof (ctf_member_t);
|
||||||
|
|
||||||
|
/* Hunt down the prefix and member list yet again, since they may have been
|
||||||
|
reallocated by ctf_grow_vlen. */
|
||||||
|
|
||||||
|
if ((prefix = (ctf_type_t *) ctf_find_prefix (fp, dtd->dtd_buf, CTF_K_BIG)) == NULL)
|
||||||
|
return (ctf_set_errno (ofp, ECTF_CORRUPT));
|
||||||
|
memb = (ctf_member_t *) dtd->dtd_vlen;
|
||||||
|
|
||||||
|
memb[vlen].ctm_name = ctf_str_add (fp, name);
|
||||||
|
memb[vlen].ctm_type = type;
|
||||||
|
if (memb[vlen].ctm_name == 0 && name != NULL && name[0] != '\0')
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
|
||||||
|
dtd->dtd_data->ctt_size = CTF_SIZE_TO_LSIZE_LO (ssize);
|
||||||
|
prefix->ctt_size = CTF_SIZE_TO_LSIZE_HI (ssize);
|
||||||
|
|
||||||
|
dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, kflag, CTF_VLEN_TO_VLEN_LO(vlen + 1));
|
||||||
|
prefix->ctt_info = CTF_TYPE_INFO (CTF_K_BIG, 0, CTF_VLEN_TO_VLEN_HI(vlen + 1));
|
||||||
|
|
||||||
|
dtd->dtd_last_offset += bit_offset;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1466,15 +1522,31 @@ ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
|||||||
if (dtd == NULL)
|
if (dtd == NULL)
|
||||||
return (ctf_set_errno (fp, ECTF_BADID));
|
return (ctf_set_errno (fp, ECTF_BADID));
|
||||||
|
|
||||||
kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
|
kind = LCTF_KIND (fp, dtd->dtd_buf);
|
||||||
|
|
||||||
if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
|
if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
|
||||||
return (ctf_set_errno (fp, ECTF_NOTINTFP));
|
return (ctf_set_errno (fp, ECTF_NOTINTFP));
|
||||||
|
|
||||||
if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
|
/* Create a slice if need be. */
|
||||||
return -1; /* errno is set for us. */
|
|
||||||
|
|
||||||
return ctf_add_member_offset (fp, souid, name, type, bit_offset);
|
if (encoding.cte_offset != 0 ||
|
||||||
|
encoding.cte_format != 0 ||
|
||||||
|
(encoding.cte_bits != 0 && CTF_INFO_KFLAG (dtd->dtd_data->ctt_info) == 0))
|
||||||
|
{
|
||||||
|
if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
type = otype;
|
||||||
|
|
||||||
|
return ctf_add_member_bitfield (fp, souid, name, type, bit_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
|
||||||
|
ctf_id_t type, unsigned long bit_offset)
|
||||||
|
{
|
||||||
|
return ctf_add_member_bitfield (fp, souid, name, type, bit_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -812,6 +812,8 @@ extern char *ctf_str_append_noerr (char *, const char *);
|
|||||||
|
|
||||||
extern ctf_id_t ctf_type_resolve_unsliced (ctf_dict_t *, ctf_id_t);
|
extern ctf_id_t ctf_type_resolve_unsliced (ctf_dict_t *, ctf_id_t);
|
||||||
extern int ctf_type_kind_unsliced (ctf_dict_t *, ctf_id_t);
|
extern int ctf_type_kind_unsliced (ctf_dict_t *, ctf_id_t);
|
||||||
|
extern ssize_t ctf_type_align_natural (ctf_dict_t *fp, ctf_id_t prev_type,
|
||||||
|
ctf_id_t type, ssize_t bit_offset);
|
||||||
|
|
||||||
_libctf_printflike_ (1, 2)
|
_libctf_printflike_ (1, 2)
|
||||||
extern void ctf_dprintf (const char *, ...);
|
extern void ctf_dprintf (const char *, ...);
|
||||||
|
|||||||
@@ -1094,6 +1094,60 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine the natural alignment (in bits) for some type, given the previous
|
||||||
|
TYPE at BIT_OFFSET.
|
||||||
|
|
||||||
|
Not public because doing this entirely right requires arch-dependent
|
||||||
|
attention: this is just to reduce code repetition in ctf-create.c.
|
||||||
|
|
||||||
|
Errors if the TYPE or PREV_TYPE are unsuitable for automatic alignment
|
||||||
|
determination: in particular, you can insert incomplete or nonrepresentable
|
||||||
|
TYPEs, but PREV_TYPE cannot be incomplete or nonrepresentable. */
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
ctf_type_align_natural (ctf_dict_t *fp, ctf_id_t prev_type,
|
||||||
|
ctf_id_t type, ssize_t bit_offset)
|
||||||
|
{
|
||||||
|
ctf_encoding_t info;
|
||||||
|
ssize_t size;
|
||||||
|
ssize_t align;
|
||||||
|
|
||||||
|
if ((prev_type = ctf_type_resolve (fp, prev_type)) == CTF_ERR)
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
|
||||||
|
if ((align = ctf_type_align (fp, type)) < 0)
|
||||||
|
{
|
||||||
|
/* Ignore incompleteness and nonrepresentability of the type we're
|
||||||
|
inserting: just assume such a type has no alignment constraints of its
|
||||||
|
own. */
|
||||||
|
if (ctf_errno (fp) == ECTF_NONREPRESENTABLE
|
||||||
|
|| ctf_errno (fp) == ECTF_INCOMPLETE)
|
||||||
|
align = 0;
|
||||||
|
else
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctf_type_encoding (fp, prev_type, &info) == 0)
|
||||||
|
bit_offset += info.cte_bits;
|
||||||
|
else if ((size = ctf_type_size (fp, prev_type)) > 0)
|
||||||
|
bit_offset += size * CHAR_BIT;
|
||||||
|
else if (size < 0)
|
||||||
|
return -1; /* errno is set for us. */
|
||||||
|
|
||||||
|
/* Round up the offset of the end of the last member to the next byte
|
||||||
|
boundary, convert 'off' to bytes, and then round it up again to the next
|
||||||
|
multiple of the alignment required by the new member. Finally, convert
|
||||||
|
back to bits and store the result. Technically we could do more efficient
|
||||||
|
packing within structs if the new member is a bit-field, but we're the
|
||||||
|
"compiler" and the Standard says we can do as we choose. */
|
||||||
|
|
||||||
|
bit_offset = roundup (bit_offset, CHAR_BIT) / CHAR_BIT;
|
||||||
|
bit_offset = roundup (bit_offset, MAX (align, 1));
|
||||||
|
bit_offset *= CHAR_BIT;
|
||||||
|
|
||||||
|
return bit_offset;
|
||||||
|
}
|
||||||
|
|
||||||
/* Resolve the type down to a base type node, and then return the alignment
|
/* Resolve the type down to a base type node, and then return the alignment
|
||||||
needed for the type storage in bytes.
|
needed for the type storage in bytes.
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ LIBCTF_2.0 {
|
|||||||
ctf_add_member_offset;
|
ctf_add_member_offset;
|
||||||
ctf_add_member_encoded;
|
ctf_add_member_encoded;
|
||||||
ctf_add_variable;
|
ctf_add_variable;
|
||||||
|
ctf_add_member_bitfield;
|
||||||
|
|
||||||
ctf_set_array;
|
ctf_set_array;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user