From: Nick Alcock Date: Thu, 24 Apr 2025 14:48:16 +0000 (+0100) Subject: libctf: create: vlen growth and prefix addition (NEEDS REVIEW) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a93ad066f717d47a97700a09c1c744edaefb327d;p=thirdparty%2Fbinutils-gdb.git 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. --- diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index f58df00fb01..5cd5898b669 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -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. */ +/* 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. */ + static int -ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen) +ctf_add_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vbytes, int additive) { - unsigned char *old = dtd->dtd_vlen; + unsigned char *old = (unsigned char *) dtd->dtd_buf; - if (dtd->dtd_vlen_alloc > vlen) - return 0; + 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) + { + size *= 2; + vlen_size = size - prefix_size; + } + } + else { - dtd->dtd_vlen = old; + 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