aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce McCulloch <bruce.mcculloch@oracle.com>2024-11-01 12:31:46 -0400
committerNick Alcock <nick.alcock@oracle.com>2025-09-24 14:36:39 +0100
commit47111cfd4f971a7c56a7400f0709b3b51eeb8ef4 (patch)
treeafb96e257e351069a7375318cca35f6c83053647
parent572b0825c73613a562e6a2738105f8d9b2577996 (diff)
downloadbinutils-users/nalcock/try-mdarray-big-corrupt-structs.zip
binutils-users/nalcock/try-mdarray-big-corrupt-structs.tar.gz
binutils-users/nalcock/try-mdarray-big-corrupt-structs.tar.bz2
libctf: dump CTF array dimensions in the right orderusers/nalcock/try-mdarray-big-corrupt-structs
Before GCC PR114186, all looked good in the land of multidimensional arrays: you wrote int a[5][10]; and ctf_type_aname() et al would print it as int [5][10] Unfortunately this was two bugs in one. GCC was emitting the array as if it were int a[10][5], i.e. as this: a -> [10] -> [5] -> int rather than a -> [5] -> [10] -> int as it should be. libctf was hiding this by printing them in the wrong order, concealing the bug from anyone using objdump --ctf or anything but actual type graph traversal. Once this was fixed for GCC, the bug was visible in libctf: multidimensional arrays were printed backwards! (But this is just a print-time bug: the underlying bug, that something traversing the type graph would see the array in backwards order, was fixed by the fix to GCC.) Fix this libctf bug, printing the arrays the right way round. In a possibly futile attempt to retain some vestige of backwards compatibility, introduce a new bug-compat flag CTF_F_ARRNELEMS, which, if on, indicates that PR114186 is fixed and GCC is emitting array elements the right way round. (Unfortunately, the fix went in without this flag, so some GCCs will still emit CTF that will cause libctf to print them wrong, even with this fix -- but it's no wronger than it was before, and new GCC and new binutils, as well as GCC older than any fix for PR114186 and new binutils, will print things properly. Someone traversing the type graph will see things right after the GCC fix, wrong before it, and there isn't really any reliable way to tell which you have, though if CTF_F_ARRNELEMS is set, you definitely have a fixed GCC. The test checks for this, but it's not something we expect actual users to ever do -- CTF dict flags are an internal implementation detail with no user-visible API for a reason.) [nca: log message, test compat with older compilers] include/ * ctf.h (CTF_F_ARRNELEMS): New bug-compat flag. (CTF_F_MAX): Adjust. libctf/ PR libctf/32161 * ctf-decl.c (ctf_decl_push): Prepend if this is an array and the bug-compat flag is set. * ctf-dump.c (ctf_dump_header): Dump the new bug-compat flag. * testsuite/libctf-lookup/multidim-array*: New test.
-rw-r--r--include/ctf.h3
-rw-r--r--libctf/ctf-decl.c7
-rw-r--r--libctf/ctf-dump.c8
-rw-r--r--libctf/testsuite/libctf-lookup/multidim-array-ctf.c3
-rw-r--r--libctf/testsuite/libctf-lookup/multidim-array.c71
-rw-r--r--libctf/testsuite/libctf-lookup/multidim-array.lk9
6 files changed, 97 insertions, 4 deletions
diff --git a/include/ctf.h b/include/ctf.h
index 72a639a..819003e 100644
--- a/include/ctf.h
+++ b/include/ctf.h
@@ -213,8 +213,9 @@ typedef struct ctf_header
#define CTF_F_NEWFUNCINFO 0x2 /* New v3 func info section format. */
#define CTF_F_IDXSORTED 0x4 /* Index sections already sorted. */
#define CTF_F_DYNSTR 0x8 /* Strings come from .dynstr. */
+#define CTF_F_ARRNELEMS 0x10 /* Array elems no longer reversed. */
#define CTF_F_MAX (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO | CTF_F_IDXSORTED \
- | CTF_F_DYNSTR)
+ | CTF_F_DYNSTR | CTF_F_ARRNELEMS)
typedef struct ctf_lblent
{
diff --git a/libctf/ctf-decl.c b/libctf/ctf-decl.c
index 9e11913..e5331b4 100644
--- a/libctf/ctf-decl.c
+++ b/libctf/ctf-decl.c
@@ -154,9 +154,12 @@ ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type)
cd->cd_qualp = prec;
/* By convention qualifiers of base types precede the type specifier (e.g.
- const int vs. int const) even though the two forms are equivalent. */
+ const int vs. int const) even though the two forms are equivalent.
+ As of gcc-14.2.0, arrays must also be prepended in order to dump with the
+ dimensions properly ordered. */
- if (is_qual && prec == CTF_PREC_BASE)
+ if ((is_qual && prec == CTF_PREC_BASE) || ((kind == CTF_K_ARRAY) &&
+ (fp->ctf_openflags & (CTF_F_ARRNELEMS))))
ctf_list_prepend (&cd->cd_nodes[prec], cdp);
else
ctf_list_append (&cd->cd_nodes[prec], cdp);
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 54febd6..57fbd64 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -326,7 +326,7 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
if (fp->ctf_openflags > 0)
{
- if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
+ if (asprintf (&flagstr, "%s%s%s%s%s%s%s%s%s",
fp->ctf_openflags & CTF_F_COMPRESS
? "CTF_F_COMPRESS": "",
(fp->ctf_openflags & CTF_F_COMPRESS)
@@ -343,6 +343,12 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
&& (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
| CTF_F_IDXSORTED))
? ", " : "",
+ fp->ctf_openflags & CTF_F_ARRNELEMS
+ ? "CTF_F_ARRNELEMS" : "",
+ fp->ctf_openflags & (CTF_F_ARRNELEMS)
+ && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
+ | CTF_F_IDXSORTED | CTF_F_ARRNELEMS))
+ ? ", " : "",
fp->ctf_openflags & CTF_F_DYNSTR
? "CTF_F_DYNSTR" : "") < 0)
goto err;
diff --git a/libctf/testsuite/libctf-lookup/multidim-array-ctf.c b/libctf/testsuite/libctf-lookup/multidim-array-ctf.c
new file mode 100644
index 0000000..05b6ebe
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/multidim-array-ctf.c
@@ -0,0 +1,3 @@
+int a[3][5][9];
+int b[1][2];
+
diff --git a/libctf/testsuite/libctf-lookup/multidim-array.c b/libctf/testsuite/libctf-lookup/multidim-array.c
new file mode 100644
index 0000000..2a86f26
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/multidim-array.c
@@ -0,0 +1,71 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ ctf_archive_t *ctf;
+ ctf_dict_t *fp;
+ int err;
+ ctf_dump_state_t *dump_state = NULL;
+ char *dumpstr;
+ ctf_next_t *it = NULL;
+ ctf_id_t type;
+ int flagged = 0;
+
+ if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+ goto open_err;
+ if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+ goto open_err;
+
+ /* First, check for signs that the compiler is fixed but not emitting the
+ relevant flag yet. This combination is not expected to work right. */
+
+ while ((dumpstr = ctf_dump (fp, &dump_state, CTF_SECT_HEADER,
+ NULL, NULL)) != NULL)
+ {
+ if (strstr (dumpstr, "CTF_F_ARRNELEMS") != NULL)
+ flagged = 1;
+ free (dumpstr);
+ }
+
+ if (!flagged)
+ {
+ ctf_arinfo_t ar;
+
+ if ((type = ctf_lookup_by_symbol_name (fp, "a")) == CTF_ERR)
+ goto unexpected;
+
+ if (ctf_array_info (fp, type, &ar) < 0)
+ goto unexpected;
+
+ if (ar.ctr_nelems == 3)
+ {
+ fprintf (stderr, "UNSUPPORTED: compiler has GCC PR114186 fixed but "
+ "no indicative flag\n");
+ return 0;
+ }
+ }
+
+ /* Now check for the actual bug. */
+
+ while ((type = ctf_type_next (fp, &it, NULL, 1)) != -1)
+ printf ("%s\n", ctf_type_aname (fp, type));
+
+ ctf_dict_close (fp);
+ ctf_close (ctf);
+
+ return 0;
+
+ open_err:
+ fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err));
+ return 1;
+
+ unexpected:
+ fprintf (stderr, "Cannot look up symbol to determine compiler bugginess: %s\n",
+ ctf_errmsg (ctf_errno (fp)));
+ return 1;
+}
+
diff --git a/libctf/testsuite/libctf-lookup/multidim-array.lk b/libctf/testsuite/libctf-lookup/multidim-array.lk
new file mode 100644
index 0000000..20056f1
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/multidim-array.lk
@@ -0,0 +1,9 @@
+# source: multidim-array-ctf.c
+int
+long unsigned int
+int \[9\]
+int \[5\]\[9\]
+int \[3\]\[5\]\[9\]
+int \[2\]
+int \[1\]\[2\]
+