forked from Imagelibrary/binutils-gdb
libctf: create: vlen growth and prefix addition (NEEDS REVIEW)
This commit modifies ctf_grow_vlen to account for the recent changes to ctf_dtdef_t, and adds a new ctf_add_prefix function to add a prefix to an existing type, moving the dtd_data and dtd_vlen up accordinly. It deserves close review, since this is probably the single greatest bug cluster in libctf: the number of times I added to a variable of type ctf_type_t and assumed it would move it in bytes rather than ctf_type_t units is hard to believe.
This commit is contained in:
@@ -74,30 +74,96 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure a vlen has enough space: expand it otherwise. Unlike the ptrtab,
|
||||
which grows quite slowly, the vlen grows in big jumps because it is quite
|
||||
expensive to expand: the caller has to scan the old vlen for string refs
|
||||
first and remove them, then re-add them afterwards. The initial size is
|
||||
more or less arbitrary. */
|
||||
static int
|
||||
ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
|
||||
{
|
||||
unsigned char *old = dtd->dtd_vlen;
|
||||
/* Make sure a vlen has enough space: expand it otherwise. Either grow it to
|
||||
roughly enough space for VBYTES, or add precisely VBYTES on to the space
|
||||
reserved for the vlen. (In one mode, VBYTES is a minimum: in the other,
|
||||
it's an addend. */
|
||||
|
||||
if (dtd->dtd_vlen_alloc > vlen)
|
||||
static int
|
||||
ctf_add_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes, int additive)
|
||||
{
|
||||
unsigned char *old = (unsigned char *) dtd->dtd_buf;
|
||||
|
||||
size_t size = dtd->dtd_buf_size;
|
||||
size_t old_size = size;
|
||||
size_t vlen_size = dtd->dtd_vlen_size;
|
||||
size_t prefix_size = size - vlen_size;
|
||||
size_t old_data_index = dtd->dtd_data - dtd->dtd_buf;
|
||||
size_t old_vlen_offset = dtd->dtd_vlen - old;
|
||||
|
||||
if (!additive)
|
||||
{
|
||||
if ((size - vlen_size) > vbytes)
|
||||
return 0;
|
||||
|
||||
if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen,
|
||||
dtd->dtd_vlen_alloc * 2)) == NULL)
|
||||
while (vlen_size < vbytes)
|
||||
{
|
||||
dtd->dtd_vlen = old;
|
||||
size *= 2;
|
||||
vlen_size = size - prefix_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vlen_size += vbytes;
|
||||
size += vbytes;
|
||||
}
|
||||
|
||||
if ((dtd->dtd_buf = realloc (dtd->dtd_buf, size)) == NULL)
|
||||
{
|
||||
dtd->dtd_buf = (ctf_type_t *) old;
|
||||
return (ctf_set_errno (fp, ENOMEM));
|
||||
}
|
||||
memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
|
||||
dtd->dtd_vlen_alloc *= 2;
|
||||
|
||||
memset (((unsigned char *) dtd->dtd_buf) + old_size, 0, size - old_size);
|
||||
dtd->dtd_data = dtd->dtd_buf + old_data_index;
|
||||
dtd->dtd_vlen = ((unsigned char *) dtd->dtd_buf) + old_vlen_offset;
|
||||
dtd->dtd_buf_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure a vlen has enough space: expand it otherwise. Grow it in fairly
|
||||
big jumps, for amortized-constant-time growth. */
|
||||
|
||||
static int
|
||||
ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes)
|
||||
{
|
||||
return ctf_add_vlen (fp, dtd, vbytes, 0);
|
||||
}
|
||||
|
||||
/* Add a prefix to a given DTD, at the end of the prefix chain, and return it.
|
||||
Make sure the vlen has enough room for at least VBYTES bytes, too. */
|
||||
static ctf_type_t *
|
||||
ctf_add_prefix (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes)
|
||||
{
|
||||
ctf_type_t *new_prefix;
|
||||
size_t old_buf_size = dtd->dtd_buf_size;
|
||||
|
||||
/* Grow the type, then tweak the vlen forwards and move things around to leave
|
||||
a gap. If we run off the end of the headers without finding a non-prefix,
|
||||
something is wrong. */
|
||||
|
||||
if (vbytes == 0)
|
||||
{
|
||||
if (ctf_add_vlen (fp, dtd, sizeof (ctf_type_t), 1) < 0)
|
||||
return NULL; /* errno is set for us. */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctf_grow_vlen (fp, dtd, vbytes + sizeof (ctf_type_t)) < 0)
|
||||
return NULL; /* errno is set for us. */
|
||||
}
|
||||
|
||||
new_prefix = dtd->dtd_data;
|
||||
memmove (dtd->dtd_data + 1, dtd->dtd_data, old_buf_size
|
||||
- ((unsigned char *) dtd->dtd_data - (unsigned char *) dtd->dtd_buf));
|
||||
dtd->dtd_vlen += sizeof (ctf_type_t);
|
||||
dtd->dtd_data++;
|
||||
memset (new_prefix, 0, sizeof (ctf_type_t));
|
||||
|
||||
return new_prefix;
|
||||
}
|
||||
|
||||
/* To create an empty CTF dict, we just declare a zeroed header and call
|
||||
ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new dict r/w and
|
||||
initialize the dynamic members. We start assigning type IDs at 1 because
|
||||
|
||||
Reference in New Issue
Block a user