aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2024-07-15 21:01:40 +0100
committerNick Alcock <nick.alcock@oracle.com>2024-11-18 11:50:02 +0000
commit0f4ee0c1f65f3dba547db5b242e7ffadec07d6c0 (patch)
tree1bf94e46b869c7cd11205e660d5d0dabf0306180
parent1d5673e586790c95bfd7032cc2b2871cc56c47cb (diff)
downloadbinutils-0f4ee0c1f65f3dba547db5b242e7ffadec07d6c0.zip
binutils-0f4ee0c1f65f3dba547db5b242e7ffadec07d6c0.tar.gz
binutils-0f4ee0c1f65f3dba547db5b242e7ffadec07d6c0.tar.bz2
include, libctf: add cth_parent_strlen CTFv4 header field
The first format difference between v3 and v4 is a cth_parent_strlen header field. This field (obviously not present in BTF) is populated from the string table length of the parent at serialization time (protection against being serialized before the parent is will be added in a later commit in this series), and will be used at open time to prohibit opening of dicts with a different strlen (which would corrupt the child's string table if it was shared with the parent). For now, just add the field, populate it at serialization time when linking (when not linking, no deduplication is done and the correct value remains unchanged), and dump it. include/ * ctf.h (ctf_header) [cth_parent_strlen]: New. libctf/ * ctf-dump.c (ctf_dump_header_sizefield): New. (ctf_dump_header): Use to dump the cth_parent_strlen. * ctf-open.c (upgrade_header_v2): Populate cth_parent_strlen. (upgrade_header_v3): Likewise. (ctf_flip_header): Flip it. (ctf_bufopen): Drop unnecessary initialization. * ctf-serialize.c (ctf_serialize): Write it out when linking. ld/ * testsuite/ld-ctf/data-func-conflicted-vars.d: Skip the nwe dump output. * testsuite/ld-ctf/data-func-conflicted.d: Likewise.
-rw-r--r--include/ctf.h1
-rw-r--r--ld/testsuite/ld-ctf/data-func-conflicted-vars.d1
-rw-r--r--ld/testsuite/ld-ctf/data-func-conflicted.d1
-rw-r--r--libctf/ctf-dump.c21
-rw-r--r--libctf/ctf-open.c17
-rw-r--r--libctf/ctf-serialize.c10
6 files changed, 49 insertions, 2 deletions
diff --git a/include/ctf.h b/include/ctf.h
index 75d2ed2..d9f8c96 100644
--- a/include/ctf.h
+++ b/include/ctf.h
@@ -190,6 +190,7 @@ typedef struct ctf_header
uint32_t cth_parlabel; /* Ref to name of parent lbl uniq'd against. */
uint32_t cth_parname; /* Ref to basename of parent. */
uint32_t cth_cuname; /* Ref to CU name (may be 0). */
+ uint32_t cth_parent_strlen; /* cth_strlen of parent (may be 0). */
uint32_t cth_lbloff; /* Offset of label section. */
uint32_t cth_objtoff; /* Offset of object section. */
uint32_t cth_funcoff; /* Offset of function section. */
diff --git a/ld/testsuite/ld-ctf/data-func-conflicted-vars.d b/ld/testsuite/ld-ctf/data-func-conflicted-vars.d
index f10fa98..e9e798e 100644
--- a/ld/testsuite/ld-ctf/data-func-conflicted-vars.d
+++ b/ld/testsuite/ld-ctf/data-func-conflicted-vars.d
@@ -45,6 +45,7 @@ CTF archive member: .*/data-func-1\.c:
#...
Parent name: \.ctf
Compilation unit name: .*/data-func-1\.c
+#...
Data object section: .* \(0x[1-9a-f][0-9a-f]* bytes\)
Type section: .* \(0xc bytes\)
String section: .*
diff --git a/ld/testsuite/ld-ctf/data-func-conflicted.d b/ld/testsuite/ld-ctf/data-func-conflicted.d
index 71f6edb..e9543d2 100644
--- a/ld/testsuite/ld-ctf/data-func-conflicted.d
+++ b/ld/testsuite/ld-ctf/data-func-conflicted.d
@@ -40,6 +40,7 @@ CTF archive member: .*/data-func-1\.c:
#...
Parent name: \.ctf
Compilation unit name: .*/data-func-1\.c
+#...
Data object section: .* \(0x[1-9a-f][0-9a-f]* bytes\)
Type section: .* \(0xc bytes\)
String section: .*
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 9f09df7..68bf1c3 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -265,6 +265,24 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
return (ctf_set_errno (fp, errno));
}
+/* Dump one size field from the file header into the cds_items. */
+static int
+ctf_dump_header_sizefield (ctf_dict_t *fp, ctf_dump_state_t *state,
+ const char *name, uint32_t value)
+{
+ char *str;
+ if (value)
+ {
+ if (asprintf (&str, "%s: %x\n", name, value) < 0)
+ goto err;
+ ctf_dump_append (state, str);
+ }
+ return 0;
+
+ err:
+ return (ctf_set_errno (fp, errno));
+}
+
/* Dump one section-offset field from the file header into the cds_items. */
static int
ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
@@ -366,6 +384,9 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
hp->cth_cuname) < 0)
goto err;
+ if (ctf_dump_header_sizefield (fp, state, "Parent strlen", hp->cth_parent_strlen) < 0)
+ goto err;
+
if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
hp->cth_objtoff) < 0)
goto err;
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index a7aa46e..5d1fcb5 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -412,6 +412,7 @@ upgrade_header_v2 (ctf_header_t *hp)
hp->cth_funcoff = oldhp->cth_funcoff;
hp->cth_objtoff = oldhp->cth_objtoff;
hp->cth_lbloff = oldhp->cth_lbloff;
+ hp->cth_parent_strlen = 0; /* Strings start at offset 0. */
hp->cth_cuname = 0; /* No CU name. */
}
@@ -430,6 +431,7 @@ upgrade_header_v3 (ctf_header_t *hp)
hp->cth_funcoff = oldhp->cth_funcoff;
hp->cth_objtoff = oldhp->cth_objtoff;
hp->cth_lbloff = oldhp->cth_lbloff;
+ hp->cth_parent_strlen = 0; /* Strings start at offset 0. */
hp->cth_cuname = oldhp->cth_cuname;
hp->cth_parname = oldhp->cth_parname;
hp->cth_parlabel = oldhp->cth_parlabel;
@@ -1115,6 +1117,7 @@ ctf_flip_header (ctf_header_t *cth)
swap_thing (cth->cth_parlabel);
swap_thing (cth->cth_parname);
swap_thing (cth->cth_cuname);
+ swap_thing (cth->cth_parent_strlen);
swap_thing (cth->cth_objtoff);
swap_thing (cth->cth_funcoff);
swap_thing (cth->cth_objtidxoff);
@@ -1446,7 +1449,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
const ctf_sect_t *strsect, int *errp)
{
const ctf_preamble_t *pp;
- size_t hdrsz = sizeof (ctf_header_t);
+ size_t hdrsz;
ctf_header_t *hp;
ctf_dict_t *fp;
int foreign_endian = 0;
@@ -1623,6 +1626,18 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
return (ctf_set_open_errno (errp, ECTF_CORRUPT));
}
+ if ((hp->cth_parname != 0 && hp->cth_parname < hp->cth_parent_strlen)
+ || (hp->cth_cuname != 0 && hp->cth_cuname < hp->cth_parent_strlen))
+ {
+ ctf_err_warn (NULL, 0, ECTF_CORRUPT,
+ _("Parent dict or CU name string offsets "
+ "(at %x and %x, respectively) are themselves "
+ "within the parent (upper bound: %x), thus "
+ "unreachable.\n"), hp->cth_parname, hp->cth_cuname,
+ hp->cth_parent_strlen);
+ return (ctf_set_open_errno (errp, ECTF_CORRUPT));
+ }
+
/* Once everything is determined to be valid, attempt to decompress the CTF
data buffer if it is compressed, or copy it into new storage if it is not
compressed but needs endian-flipping. Otherwise we just put the data
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index a14514c..ac3266f 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -1104,7 +1104,14 @@ ctf_serialize (ctf_dict_t *fp, size_t *bufsiz)
assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
/* Construct the final string table and fill out all the string refs with the
- final offsets. */
+ final offsets. At link time, before the strtab can be constructed, child
+ dicts also need their cth_parent_strlen header field updated to match the
+ parent's. (These are always newly-created dicts, so we don't need to worry
+ about the upgraded-from-v3 case, which must always retain a
+ cth_parent_strlen value of 0.) */
+
+ if ((fp->ctf_flags & LCTF_LINKING) && fp->ctf_parent)
+ fp->ctf_header->cth_parent_strlen = fp->ctf_parent->ctf_str[CTF_STRTAB_0].cts_len;
strtab = ctf_str_write_strtab (fp);
@@ -1126,6 +1133,7 @@ ctf_serialize (ctf_dict_t *fp, size_t *bufsiz)
hdrp->cth_strlen = strtab->cts_len;
buf_size += hdrp->cth_strlen;
*bufsiz = buf_size;
+ hdrp->cth_parent_strlen = fp->ctf_header->cth_parent_strlen;
return buf;