public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
@ 2020-12-18 19:51 Nick Alcock
  2020-12-18 19:51 ` [PATCH 01/13] libctf: do not print array declarators backwards Nick Alcock
                   ` (13 more replies)
  0 siblings, 14 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

This patch series accumulates a bunch of related work, mostly bugfixes tied
together by the fact that I couldn't do them without a testsuite to test the
lookup side of libctf used by CTF consumers (the ctf_type_*, ctf_arc_* and
ctf_open API).  The dedup machinery used by the linker uses a lot of the
lookup code, but that's not enough to probe specific fixes.

There are also some improvements to the look-and-feel of the output from the
CTF dumper used by objdump and readelf, and additions to the information
dumped (notably, enumerands and their values are dumped now).

The only potentially contentious changes are an API change adding a flags
arg to ctf_member_next (whose API is still changeable since it hasn't been
in a release yet), and the banning with a new ECTF_INCOMPLETE error of
attempts to get the size or alignment of a forward and of attempts to make
arrays with forwards as elements.

The 'new testsuite' commit needs a little review, since it touches the top
level Makefile.def.  The testsuite also introduces new burdens on libctf's
build system, since, even on non-ELF platforms, it links test programs
against the built libctf and then runs them (on the host), so as a result
libctf now needs to be self-contained enough for linking with -lctf with
libtool to work.  (I've spotted and fixed several problems in this area, but
more may lurk.  They only affect make libctf-check, not building.)

I'll also be putting in one commit omitted here because it entirely consists
of changes to a past ChangeLog entry:

-       * libctf/ctf_open_bfd (ctf_bfdopen_ctfsect): Use it.
+       * ctf-open-bfd.c (ctf_bfdopen_ctfsect): Use it.


Because this involved build system changes, I tested it more than usual:
with builds and make check-libctf check-ld on x86_64-pc-linux-gnu,
sparc64-unknown-linux-gnu, x86_64-unknown-freebsd-12.2, and 64-bit Cygwin
native builds and crosses to mingw32 and mingw64 hosts and
x86_64-pc-linux-gnu targets; with --enable-targets=all, all combinations of
-enable/--disable-static and -shared, and --disable-nls. GDB currently
doesn't build with --disable-static but everything else seems happy.

The biggest hole in my test matrix right now is Mach-O, but that doesn't
seem to be easily visible remotely and I don't have any Apple hardware
myself.

Nick Alcock (13):
  libctf: do not print array declarators backwards
  libctf, ld: CTF dumper changes for consistency
  libctf, ld: more dumper improvements
  libctf, ld: prohibit doing things with forwards prohibited in C
  libctf, ld: dump enums: generally improve dump formatting
  libctf: rip out BFD_DEPENDENCIES / BFD_LIBADD
  libctf: new testsuite
  libctf: new test of enum lookups with the _next iterator
  libctf: warn about information loss because of unreleased format
    changes
  libctf, include: support unnamed structure members better
  libctf: remove outdated comment about parent dict importing
  libctf: fix lookups of pointers by name in parent dicts
  libctf, ld: fix formatting of forwards to unions and enums

-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 01/13] libctf: do not print array declarators backwards
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 02/13] libctf, ld: CTF dumper changes for consistency Nick Alcock
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

The CTF declarator stack code (used by ctf_type_aname() and thus
ultimately by ctf-dump.c and objdump --ctf etc) contains careful
code to prepend array declarators to the stack it's building up
on the grounds that array declarators are ordered inside out: only
they're not, they're ordered outside in.

This has led to our (non-upstreamed) compiler emitting array declarators
backwards for years, because it looks backwards in the dumper unless
it's actually emitted backwards into the CTF so the dumper can wrongly
reverse it again: but

  int[5][6]

should be an array of 6 int[5]s, not an array of 5 int[6]'s, so even if
the dumper gets it right, actual users calling ctf_array_info are going
to see a completely wrong type graph with the wrong bounds in it.

Fix trivial.

libctf/ChangeLog
2020-12-07  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-decl.c (ctf_decl_push): Don't print array decls backwards.
---
 libctf/ctf-decl.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libctf/ctf-decl.c b/libctf/ctf-decl.c
index fbb4e6c2c1a..f3939ea143d 100644
--- a/libctf/ctf-decl.c
+++ b/libctf/ctf-decl.c
@@ -152,11 +152,10 @@ ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type)
   if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
     cd->cd_qualp = prec;
 
-  /* C array declarators are ordered inside out so prepend them.  Also by
-     convention qualifiers of base types precede the type specifier (e.g.
+  /* By convention qualifiers of base types precede the type specifier (e.g.
      const int vs. int const) even though the two forms are equivalent.  */
 
-  if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
+  if (is_qual && prec == CTF_PREC_BASE)
     ctf_list_prepend (&cd->cd_nodes[prec], cdp);
   else
     ctf_list_append (&cd->cd_nodes[prec], cdp);
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 02/13] libctf, ld: CTF dumper changes for consistency
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
  2020-12-18 19:51 ` [PATCH 01/13] libctf: do not print array declarators backwards Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 03/13] libctf, ld: more dumper improvements Nick Alcock
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

In most places in CTF dumper output, we emit 0x... for hex strings, but
in three places (top-level type IDs, string table offsets, and the file
magic number) we don't emit the 0x.

This is very confusing if by chance there are no hex digits in the
output.  Add 0x consistently to everything, and adjust tests
accordingly.  While we're at it, improve the indentation of the output
so that subsequent lines in aggregate output are indented by at least as
many columns as the colon in the type output.  (Subsequent indentation
is still 4 spaces at a time.)

ld/ChangeLog
2020-12-07  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/array.d: Adjust for dumper changes.
	* testsuite/ld-ctf/conflicting-cycle-1.B-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-1.B-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-1.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.A-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.A-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.C-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.C-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-enums.d: Likewise.
	* testsuite/ld-ctf/conflicting-typedefs.d: Likewise.
	* testsuite/ld-ctf/cross-tu-cyclic-conflicting.d: Likewise.
	* testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d: Likewise.
	* testsuite/ld-ctf/cross-tu-into-cycle.d: Likewise.
	* testsuite/ld-ctf/cross-tu-noncyclic.d: Likewise.
	* testsuite/ld-ctf/cycle-1.d: Likewise.
	* testsuite/ld-ctf/cycle-2.A.d: Likewise.
	* testsuite/ld-ctf/cycle-2.B.d: Likewise.
	* testsuite/ld-ctf/cycle-2.C.d: Likewise.
	* testsuite/ld-ctf/data-func-conflicted.d: Likewise.
	* testsuite/ld-ctf/diag-cttname-null.d: Likewise.
	* testsuite/ld-ctf/diag-cuname.d: Likewise.
	* testsuite/ld-ctf/diag-parlabel.d: Likewise.
	* testsuite/ld-ctf/diag-wrong-magic-number-mixed.d: Likewise.
	* testsuite/ld-ctf/function.d: Likewise.
	* testsuite/ld-ctf/slice.d: Likewise.
	* testsuite/ld-ctf/super-sub-cycles.d: Likewise.

libctf/ChangeLog
2020-12-07  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-dump.c (ctf_dump_format_type): Add 0x to hex type IDs.
	(ctf_dump_header): Add 0x to the hex magic number.
	(ctf_dump_str): Add 0x to the hex string offsets.
	(ctf_dump_membstate_t) <cdm_toplevel_indent>: New.
	(ctf_dump_type): Adjust.  Free it when we're done.
	(type_hex_digits): New.
	(ctf_dump_member): Align output depending on the width of the type
	ID being generated.  Use printf padding, not a loop, to generate
	indentation.
---
 ld/testsuite/ld-ctf/array.d                   |  6 +--
 ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d | 10 ++--
 ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d | 12 ++---
 .../ld-ctf/conflicting-cycle-1.parent.d       |  6 +--
 ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d | 12 ++---
 ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d | 14 +++---
 .../ld-ctf/conflicting-cycle-2.parent.d       | 14 +++---
 ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d | 12 ++---
 ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d | 14 +++---
 .../ld-ctf/conflicting-cycle-3.parent.d       |  8 +--
 ld/testsuite/ld-ctf/conflicting-enums.d       | 10 ++--
 ld/testsuite/ld-ctf/conflicting-typedefs.d    | 18 +++----
 .../ld-ctf/cross-tu-cyclic-conflicting.d      | 38 +++++++-------
 .../ld-ctf/cross-tu-cyclic-nonconflicting.d   | 34 ++++++-------
 ld/testsuite/ld-ctf/cross-tu-into-cycle.d     | 22 ++++----
 ld/testsuite/ld-ctf/cross-tu-noncyclic.d      | 24 ++++-----
 ld/testsuite/ld-ctf/cycle-1.d                 | 12 ++---
 ld/testsuite/ld-ctf/cycle-2.A.d               | 14 +++---
 ld/testsuite/ld-ctf/cycle-2.B.d               | 14 +++---
 ld/testsuite/ld-ctf/cycle-2.C.d               | 14 +++---
 ld/testsuite/ld-ctf/data-func-conflicted.d    |  6 +--
 ld/testsuite/ld-ctf/diag-cttname-null.d       |  8 +--
 ld/testsuite/ld-ctf/diag-cuname.d             | 12 ++---
 ld/testsuite/ld-ctf/diag-parlabel.d           | 12 ++---
 .../ld-ctf/diag-wrong-magic-number-mixed.d    | 14 +++---
 ld/testsuite/ld-ctf/function.d                |  6 +--
 ld/testsuite/ld-ctf/slice.d                   | 14 +++---
 ld/testsuite/ld-ctf/super-sub-cycles.d        | 30 +++++------
 libctf/ctf-dump.c                             | 50 +++++++++++++++----
 29 files changed, 244 insertions(+), 216 deletions(-)

diff --git a/ld/testsuite/ld-ctf/array.d b/ld/testsuite/ld-ctf/array.d
index 82e9939783f..e07d63e2243 100644
--- a/ld/testsuite/ld-ctf/array.d
+++ b/ld/testsuite/ld-ctf/array.d
@@ -10,7 +10,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Data object section:	.* \(0x8 bytes\)
@@ -29,7 +29,7 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: .*\[10\] .*
+     0x[0-9a-f]*: .*\[10\] .*
 #...
-     [0-9a-f]*: .*\[10\] .*
+     0x[0-9a-f]*: .*\[10\] .*
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
index 40636f062f5..99b0564bad7 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
@@ -14,7 +14,7 @@
 CTF archive member: .*/B.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .ctf
@@ -30,12 +30,12 @@ CTF archive member: .*/B.c:
   Function objects:
 
   Variables:
-    b ->  80000001: struct B \(size 0x[0-9]*\)
+    b ->  0x80000001: struct B \(size 0x[0-9]*\)
 
   Types:
-     8[0-9a-f]*: struct B .*
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+     0x8[0-9a-f]*: struct B .*
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
index c6fdceb8cf8..32bc5c24f05 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
@@ -14,7 +14,7 @@
 CTF archive member: .*/B-2.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .ctf
@@ -30,13 +30,13 @@ CTF archive member: .*/B-2.c:
   Function objects:
 
   Variables:
-    b ->  80000001: struct B \(.*
+    b ->  0x80000001: struct B \(.*
 
   Types:
-     8[0-9a-f]*: struct B \(.*
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x8[0-9a-f]*: struct B \(.*
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
index 558eb36f2fe..4cbe9b61f3c 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
@@ -13,7 +13,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0xac bytes\)
@@ -29,8 +29,8 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: struct B \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B \(.*
+     0x[0-9a-f]*: struct B \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B \(.*
 #...
 CTF archive member: .*:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
index 79282a248e6..5e5fade0af8 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
@@ -16,7 +16,7 @@
 CTF archive member: .*/A.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .*
@@ -29,13 +29,13 @@ CTF archive member: .*/A.c:
   Function objects:
 
   Variables:
-    a ->  80000001: struct A \(size 0x[0-9a-f]*\)
+    a ->  0x80000001: struct A \(size 0x[0-9a-f]*\)
 
   Types:
-     8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
+     0x8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
 
   Strings:
-    0: 
+    0x0: 
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
index 4f6d44e3577..ff6785cfde2 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
@@ -16,7 +16,7 @@
 CTF archive member: .*/A-2.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .*
@@ -29,14 +29,14 @@ CTF archive member: .*/A-2.c:
   Function objects:
 
   Variables:
-    a ->  80000001: struct A \(size 0x[0-9a-f]*\)
+    a ->  0x80000001: struct A \(size 0x[0-9a-f]*\)
 
   Types:
-     8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 
   Strings:
-    0: 
+    0x0: 
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
index 95aa17d4dd2..d111ef7b994 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
@@ -15,7 +15,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0x94 bytes\)
@@ -28,13 +28,13 @@ Contents of CTF section .ctf:
   Function objects:
 
   Variables:
-    cycle_1 ->  [0-9a-f]*: struct cycle_1 \* \(size 0x[0-9a-f]*\) -> [0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
+    cycle_1 ->  0x[0-9a-f]*: struct cycle_1 \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
 
   Types:
 #...
-     [0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(aligned at 0x[0-9a-f]*\)
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
index 48078b93c97..df61153db2a 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
@@ -15,7 +15,7 @@
 CTF archive member: .*/C.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .*
@@ -28,13 +28,13 @@ CTF archive member: .*/C.c:
   Function objects:
 
   Variables:
-    c ->  80000001: struct C \(size 0x[0-9a-f]*\)
+    c ->  0x80000001: struct C \(size 0x[0-9a-f]*\)
 
   Types:
-     8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
+     0x8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
 
   Strings:
-    0: 
+    0x0: 
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
index 854a71938e4..e1cfd0cf771 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
@@ -15,7 +15,7 @@
 CTF archive member: .*/C-2.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: .*
@@ -28,14 +28,14 @@ CTF archive member: .*/C-2.c:
   Function objects:
 
   Variables:
-    c ->  80000001: struct C \(size 0x[0-9a-f]*\)
+    c ->  0x80000001: struct C \(size 0x[0-9a-f]*\)
 
   Types:
-     8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 
   Strings:
-    0: 
+    0x0: 
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
index 28525b6c4fa..11d2a048618 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
@@ -14,7 +14,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	0x0 -- 0x57 \(0x58 bytes\)
@@ -30,9 +30,9 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 #...
   Strings:
-    0: 
+    0x0: 
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-enums.d b/ld/testsuite/ld-ctf/conflicting-enums.d
index 8b16b4cb9e1..b93d8124f36 100644
--- a/ld/testsuite/ld-ctf/conflicting-enums.d
+++ b/ld/testsuite/ld-ctf/conflicting-enums.d
@@ -10,7 +10,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
   Types:
@@ -20,16 +20,16 @@ Contents of CTF section .ctf:
 CTF archive member: .*enum.*\.c:
 #...
   Types:
-     8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
+     0x8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
 
   Strings:
 #...
 CTF archive member: .*enum.*\.c:
 #...
   Types:
-     8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
+     0x8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-typedefs.d b/ld/testsuite/ld-ctf/conflicting-typedefs.d
index 09d6c3cf54e..309e4535d7f 100644
--- a/ld/testsuite/ld-ctf/conflicting-typedefs.d
+++ b/ld/testsuite/ld-ctf/conflicting-typedefs.d
@@ -10,24 +10,24 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
   Types:
-     1: .*int .*
-        .*
-     [0-9]:.*int .*
-        .*
-     [0-9]: word .*
-        \[0x0\] \(ID 0x[0-9]\) \(kind 10\) word \(aligned at 0x[48]\)
+     0x1: .*int .*
+          .*
+     0x[0-9]:.*int .*
+          .*
+     0x[0-9]: word .*
+           *\[0x0\] \(ID 0x[0-9]\) \(kind 10\) word \(aligned at 0x[48]\)
 
   Strings:
 #...
 CTF archive member: .*typedef.*\.c:
 #...
   Types:
-     80000001: word .*
-        \[0x0\] \(ID 0x80000001\) \(kind 10\) word \(aligned at 0x[48]\)
+     0x80000001: word .*
+           *\[0x0\] \(ID 0x80000001\) \(kind 10\) word \(aligned at 0x[48]\)
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
index aa36533ea37..3c975ebaa51 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
@@ -14,20 +14,20 @@ Contents of CTF section \.ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: long int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x[0-9a-f]*: long int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 #...
-     [0-9a-f]*: struct B .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
+     0x[0-9a-f]*: struct B .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
 #...
-     [0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+     0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 #...
-     [0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A .*
+     0x[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A .*
 #...
-     [0-9a-f]*: struct C .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C .*
+     0x[0-9a-f]*: struct C .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C .*
 #...
 
   Strings:
@@ -36,10 +36,10 @@ Contents of CTF section \.ctf:
 CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-1\.c:
 #...
   Types:
-     80.*[0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+     0x80.*[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
 
   Strings:
 #...
@@ -47,11 +47,11 @@ CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-1\.c:
 CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-2\.c:
 #...
   Types:
-     80.*[0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* bar .*
+     0x80.*[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* bar .*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
index 39f5c187e54..9b0d738434a 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
@@ -14,7 +14,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
 
@@ -29,22 +29,22 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo \(aligned at 0x[0-9a-f]*\)
-     [0-9a-f]*: long int .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9].*
-     [0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(aligned at 0x[0-9a-f]*\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* bar \(aligned at 0x[0-9a-f]*\)
-     [0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -> [0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* \(aligned at 0x[0-9a-f]*\)
-     [0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> [0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* \(aligned at 0x[0-9a-f]*\)
-     [0-9a-f]*: int .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:.*
+     0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: long int .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9].*
+     0x[0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(aligned at 0x[0-9a-f]*\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* bar \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: int .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:.*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-into-cycle.d b/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
index 6bfdc40a800..a21fedc8126 100644
--- a/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
+++ b/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
@@ -16,7 +16,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
 
@@ -31,16 +31,16 @@ Contents of CTF section .ctf:
     conflicty ->  .*
 
   Types:
-     [0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
-     [0-9a-f]*: struct B .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* next .*
-     [0-9a-f]*: struct B \* .*
-        \[0x0\] .*
-     [0-9a-f]*: struct A \* .*
-        \[0x0\] .*
+     0x[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+     0x[0-9a-f]*: struct B .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* next .*
+     0x[0-9a-f]*: struct B \* .*
+           *\[0x0\] .*
+     0x[0-9a-f]*: struct A \* .*
+           *\[0x0\] .*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-noncyclic.d b/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
index 418119a7367..d96e5d20ee8 100644
--- a/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
+++ b/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
@@ -12,7 +12,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0x74 bytes\)
@@ -29,18 +29,18 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* .*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+     0x[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* .*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
 #...
-     [0-9a-f]*: struct B .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* .*
+     0x[0-9a-f]*: struct B .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* .*
 #...
-     [0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -\> [0-9a-f]*: struct B .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* .*
+     0x[0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct B .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* .*
 #...
-     [0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> [0-9a-f]*: struct A .*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* .*
+     0x[0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct A .*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* .*
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-1.d b/ld/testsuite/ld-ctf/cycle-1.d
index 8e9530b3146..578709349fa 100644
--- a/ld/testsuite/ld-ctf/cycle-1.d
+++ b/ld/testsuite/ld-ctf/cycle-1.d
@@ -12,7 +12,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0xa8 bytes\)
@@ -28,9 +28,9 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: struct cycle_1 \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(.*
+     0x[0-9a-f]*: struct cycle_1 \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(.*
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-2.A.d b/ld/testsuite/ld-ctf/cycle-2.A.d
index a909b90e738..ddb5381e93c 100644
--- a/ld/testsuite/ld-ctf/cycle-2.A.d
+++ b/ld/testsuite/ld-ctf/cycle-2.A.d
@@ -11,7 +11,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0x6c bytes\)
@@ -25,16 +25,16 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    a ->  [0-9a-f]*: struct A \(.*
+    a ->  0x[0-9a-f]*: struct A \(.*
 #...
   Types:
 #...
-     [0-9a-f]*: struct A \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+     0x[0-9a-f]*: struct A \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: A
+    0x[0-9a-f]*: A
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-2.B.d b/ld/testsuite/ld-ctf/cycle-2.B.d
index 320e17cc767..1d1cdc5377d 100644
--- a/ld/testsuite/ld-ctf/cycle-2.B.d
+++ b/ld/testsuite/ld-ctf/cycle-2.B.d
@@ -11,7 +11,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0x6c bytes\)
@@ -25,16 +25,16 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    b ->  [0-9a-f]*: struct B \(.*
+    b ->  0x[0-9a-f]*: struct B \(.*
 #...
   Types:
 #...
-     [0-9a-f]*: struct B \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+     0x[0-9a-f]*: struct B \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: B
+    0x[0-9a-f]*: B
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-2.C.d b/ld/testsuite/ld-ctf/cycle-2.C.d
index df436062bd3..4d8f14513dd 100644
--- a/ld/testsuite/ld-ctf/cycle-2.C.d
+++ b/ld/testsuite/ld-ctf/cycle-2.C.d
@@ -11,7 +11,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Type section:	.* \(0x6c bytes\)
@@ -25,16 +25,16 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    c ->  [0-9a-f]*: struct C \(.*
+    c ->  0x[0-9a-f]*: struct C \(.*
 #...
   Types:
 #...
-     [0-9a-f]*: struct C \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
+     0x[0-9a-f]*: struct C \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: C
+    0x[0-9a-f]*: C
 #...
diff --git a/ld/testsuite/ld-ctf/data-func-conflicted.d b/ld/testsuite/ld-ctf/data-func-conflicted.d
index 1fa8bb2fe5f..62855f8189e 100644
--- a/ld/testsuite/ld-ctf/data-func-conflicted.d
+++ b/ld/testsuite/ld-ctf/data-func-conflicted.d
@@ -10,7 +10,7 @@
 Contents of CTF section \.ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Data object section:	.* \(0xc bytes\)
@@ -34,7 +34,7 @@ Contents of CTF section \.ctf:
 CTF archive member: .*/data-func-1\.c:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Parent name: \.ctf
@@ -59,5 +59,5 @@ CTF archive member: .*/data-func-1\.c:
   Variables:
 
   Types:
-     80000001: foo_t .* -> .* int .*
+     0x80000001: foo_t .* -> .* int .*
 #...
diff --git a/ld/testsuite/ld-ctf/diag-cttname-null.d b/ld/testsuite/ld-ctf/diag-cttname-null.d
index 4523dbc5e2f..00db4251a4d 100644
--- a/ld/testsuite/ld-ctf/diag-cttname-null.d
+++ b/ld/testsuite/ld-ctf/diag-cttname-null.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
   Data objects:
@@ -17,7 +17,7 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: struct  \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct  \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+     0x[0-9a-f]*: struct  \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct  \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
 #...
diff --git a/ld/testsuite/ld-ctf/diag-cuname.d b/ld/testsuite/ld-ctf/diag-cuname.d
index 45e9a7e6771..19a4bfd80fa 100644
--- a/ld/testsuite/ld-ctf/diag-cuname.d
+++ b/ld/testsuite/ld-ctf/diag-cuname.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Compilation unit name: \(\?\)
@@ -29,12 +29,12 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: struct A \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+     0x[0-9a-f]*: struct A \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: \(\?\)
+    0x[0-9a-f]*: \(\?\)
 #...
diff --git a/ld/testsuite/ld-ctf/diag-parlabel.d b/ld/testsuite/ld-ctf/diag-parlabel.d
index f0f40243310..b2b047cb10f 100644
--- a/ld/testsuite/ld-ctf/diag-parlabel.d
+++ b/ld/testsuite/ld-ctf/diag-parlabel.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Compilation unit name: .*A.c
@@ -28,12 +28,12 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     [0-9a-f]*: struct A \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+     0x[0-9a-f]*: struct A \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: A
+    0x[0-9a-f]*: A
 #...
diff --git a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
index cb394985d93..8fc1cc883da 100644
--- a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
+++ b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
@@ -10,7 +10,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Variable section:	0x0 -- 0x17 \(0x18 bytes\)
@@ -25,16 +25,16 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    b ->  [0-9a-f]*: struct B \(.*
+    b ->  0x[0-9a-f]*: struct B \(.*
 #...
   Types:
 #...
-     [0-9a-f]*: struct B \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+     0x[0-9a-f]*: struct B \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
 #...
   Strings:
-    0: 
+    0x0: 
 #...
-    [0-9a-f]*: B
+    0x[0-9a-f]*: B
 #...
diff --git a/ld/testsuite/ld-ctf/function.d b/ld/testsuite/ld-ctf/function.d
index f5303d7c3ba..241adc2fb3a 100644
--- a/ld/testsuite/ld-ctf/function.d
+++ b/ld/testsuite/ld-ctf/function.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Compilation unit name: .*function.c
@@ -22,6 +22,6 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\) \(size 0x0\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 5\) int \(\*\) \(char, int[0-9]*, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
+     0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\) \(size 0x0\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 5\) int \(\*\) \(char, int[0-9]*, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
 #...
diff --git a/ld/testsuite/ld-ctf/slice.d b/ld/testsuite/ld-ctf/slice.d
index b493ce05c75..e42ffdf4b65 100644
--- a/ld/testsuite/ld-ctf/slice.d
+++ b/ld/testsuite/ld-ctf/slice.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Compilation unit name: .*slice.c
@@ -23,10 +23,10 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: struct slices \(size 0x[0-9a-f]*\)
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct slices \(aligned at 0x1\)
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  one:1 \(aligned at 0x1, format 0x1, offset:bits 0x0:0x1\)
-            \[0x1\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  two:2 \(aligned at 0x1, format 0x1, offset:bits 0x1:0x2\)
-            \[0x3\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  six:6 \(aligned at 0x1, format 0x1, offset:bits 0x3:0x6\)
-            \[0x9\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  ten:10 \(aligned at 0x2, format 0x1, offset:bits 0x9:0xa\)
+     0x[0-9a-f]*: struct slices \(size 0x[0-9a-f]*\)
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct slices \(aligned at 0x1\)
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  one:1 \(aligned at 0x1, format 0x1, offset:bits 0x0:0x1\)
+               *\[0x1\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  two:2 \(aligned at 0x1, format 0x1, offset:bits 0x1:0x2\)
+               *\[0x3\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  six:6 \(aligned at 0x1, format 0x1, offset:bits 0x3:0x6\)
+               *\[0x9\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  ten:10 \(aligned at 0x2, format 0x1, offset:bits 0x9:0xa\)
 #...
diff --git a/ld/testsuite/ld-ctf/super-sub-cycles.d b/ld/testsuite/ld-ctf/super-sub-cycles.d
index e4707d331e6..65a43a4de9c 100644
--- a/ld/testsuite/ld-ctf/super-sub-cycles.d
+++ b/ld/testsuite/ld-ctf/super-sub-cycles.d
@@ -9,7 +9,7 @@
 Contents of CTF section .ctf:
 
   Header:
-    Magic number: dff2
+    Magic number: 0xdff2
     Version: 4 \(CTF_VERSION_3\)
 #...
     Compilation unit name: .*super-sub-cycles.c
@@ -18,18 +18,18 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     [0-9a-f]*: struct A \(.*
-        \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-            \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B b \(.*
-                \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C c \(.*
-                    \[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
-                    \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
-                        \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-                \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
-                    \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-            \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct X x \(.*
-                \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Y y \(.*
-                    \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Z z \(.*
-                        \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct Y \* y \(.*
-                        \[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct D \* d \(.*
+     0x[0-9a-f]*: struct A \(.*
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
+               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B b \(.*
+                   *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C c \(.*
+                       *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
+                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
+                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+                   *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
+                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct X x \(.*
+                   *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Y y \(.*
+                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Z z \(.*
+                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct Y \* y \(.*
+                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct D \* d \(.*
 #...
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index b0de345da32..83b27b213b2 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -47,6 +47,7 @@ typedef struct ctf_dump_membstate
 {
   char **cdm_str;
   ctf_dict_t *cdm_fp;
+  char *cdm_toplevel_indent;
 } ctf_dump_membstate_t;
 
 static int
@@ -115,7 +116,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 	  goto err;
 	}
 
-      if (asprintf (&bit, " %s%lx: ", nonroot_leader, id) < 0)
+      if (asprintf (&bit, " %s0x%lx: ", nonroot_leader, id) < 0)
 	goto oom;
       str = str_append (str, bit);
       free (bit);
@@ -236,7 +237,7 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
     };
   const char *verstr = NULL;
 
-  if (asprintf (&str, "Magic number: %x\n", hp->cth_magic) < 0)
+  if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_magic) < 0)
       goto err;
   ctf_dump_append (state, str);
 
@@ -454,26 +455,51 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   return 0;
 }
 
+/* Report the number of digits in the hexadecimal representation of a type
+   ID.  */
+
+static int
+type_hex_digits (ctf_id_t id)
+{
+  int i = 0;
+
+  if (id == 0)
+    return 1;
+
+  for (; id > 0; id >>= 4, i++);
+  return i;
+}
+
 /* Dump a single member into the string in the membstate.  */
 static int
 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
-		  int depth, void *arg)
+		 int depth, void *arg)
 {
   ctf_dump_membstate_t *state = arg;
   char *typestr = NULL;
   char *bit = NULL;
   ctf_encoding_t ep;
   int has_encoding = 0;
-  ssize_t i;
 
-  for (i = 0; i < depth; i++)
-    *state->cdm_str = str_append (*state->cdm_str, "    ");
+  /* Align neatly.  */
+
+  if (depth == 0)
+    {
+      if (asprintf (&state->cdm_toplevel_indent, "     %*s",
+		    type_hex_digits (id), "") < 0)
+	goto oom;
+    }
+
+  if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, depth * 4, "") < 0)
+    goto oom;
+  *state->cdm_str = str_append (*state->cdm_str, bit);
+  free (bit);
 
   if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
     {
       if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE)
 	{
-	  if (asprintf (&bit, "    [0x%lx] (type not represented in CTF)",
+	  if (asprintf (&bit, "[0x%lx] (type not represented in CTF)",
 			offset) < 0)
 	    goto oom;
 
@@ -491,7 +517,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
       has_encoding = 1;
       ctf_type_encoding (state->cdm_fp, id, &ep);
 
-      if (asprintf (&bit, "    [0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
+      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
 		    "(aligned at 0x%lx", offset, id,
 		    ctf_type_kind (state->cdm_fp, id), typestr,
 		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
@@ -501,7 +527,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
     }
   else
     {
-      if (asprintf (&bit, "    [0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
+      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
 		    "(aligned at 0x%lx", offset, id,
 		    ctf_type_kind (state->cdm_fp, id), typestr,
 		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
@@ -540,7 +566,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 {
   char *str;
   ctf_dump_state_t *state = arg;
-  ctf_dump_membstate_t membstate = { &str, state->cds_fp };
+  ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
   size_t len;
 
   if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
@@ -558,6 +584,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 		    _("cannot visit members dumping type 0x%lx"), id);
       goto err;
     }
+  free (membstate.cdm_toplevel_indent);
 
   /* Trim off the last linefeed added by ctf_dump_member().  */
   len = strlen (str);
@@ -568,6 +595,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
   return 0;
 
  err:
+  free (membstate.cdm_toplevel_indent);
   free (str);
   return 0;				/* Swallow the error.  */
 }
@@ -583,7 +611,7 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
 	 fp->ctf_str[CTF_STRTAB_0].cts_len;)
     {
       char *str;
-      if (asprintf (&str, "%lx: %s",
+      if (asprintf (&str, "0x%lx: %s",
 		    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
 		    s) < 0)
 	return (ctf_set_errno (fp, errno));
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 03/13] libctf, ld: more dumper improvements
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
  2020-12-18 19:51 ` [PATCH 01/13] libctf: do not print array declarators backwards Nick Alcock
  2020-12-18 19:51 ` [PATCH 02/13] libctf, ld: CTF dumper changes for consistency Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C Nick Alcock
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

Dump more details about the types found in data object and function info
sections (the type ID and recursive info on the type itself, but not on
its members).  Before now, this was being dumped for entries in the
variable section, but not for the closely-related function info and data
object sections, which is inconsistent and makes finding the
corresponding types in the type section unnecessarily hard.  (This also
gets rid of code in which bugs have already been found in favour of the
same code everything else in the dumper uses to dump types.)

While we're doing that, change the recursive type dumper in question to
recursively dump info on arrays' element type, just as we do for all
types that reference other types. (Arrays are not a kind of reference
type in libctf, but perhaps we should change that in future and make
ctf_type_reference return the element type.)

ld/ChangeLog
2020-12-07  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/array.d: Adjust for dumper changes.
	* testsuite/ld-ctf/data-func-conflicted.d: Likewise.
	* testsuite/ld-ctf/diag-cttname-null.d: Likewise.
	* testsuite/ld-ctf/diag-cuname.d: Likewise.
	* testsuite/ld-ctf/diag-parlabel.d: Likewise.
	* testsuite/ld-ctf/function.d: Likewise.
	* testsuite/ld-ctf/slice.d: Likewise.

libctf/ChangeLog
2020-12-07  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-dump.c (ctf_dump_objts): Dump by calling ctf_dump_format_type.
	(ctf_dump_format_type): Don't emit the size for function objects.
	Dump the element type of arrays like we dump the pointed-to type of
	pointers, etc.
---
 ld/testsuite/ld-ctf/array.d                |  4 +-
 ld/testsuite/ld-ctf/data-func-conflicted.d | 22 +++----
 ld/testsuite/ld-ctf/diag-cttname-null.d    |  2 +-
 ld/testsuite/ld-ctf/diag-cuname.d          |  2 +-
 ld/testsuite/ld-ctf/diag-parlabel.d        |  2 +-
 ld/testsuite/ld-ctf/function.d             |  4 +-
 ld/testsuite/ld-ctf/slice.d                |  2 +-
 libctf/ctf-dump.c                          | 70 ++++++++++------------
 8 files changed, 52 insertions(+), 56 deletions(-)

diff --git a/ld/testsuite/ld-ctf/array.d b/ld/testsuite/ld-ctf/array.d
index e07d63e2243..6c3915a7cf8 100644
--- a/ld/testsuite/ld-ctf/array.d
+++ b/ld/testsuite/ld-ctf/array.d
@@ -20,8 +20,8 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    digits -> int \[10\]
-    digits_names -> char \*\[10\]
+    digits -> 0x[0-9a-f]*: int \[10\] .*
+    digits_names -> 0x[0-9a-f]*: char \*\[10\] .*
 
   Function objects:
 
diff --git a/ld/testsuite/ld-ctf/data-func-conflicted.d b/ld/testsuite/ld-ctf/data-func-conflicted.d
index 62855f8189e..e51bb763af1 100644
--- a/ld/testsuite/ld-ctf/data-func-conflicted.d
+++ b/ld/testsuite/ld-ctf/data-func-conflicted.d
@@ -20,12 +20,12 @@ Contents of CTF section \.ctf:
     String section:	.*
 #...
   Data objects:
-    bar -> struct var_3
-    var_1 -> foo_t
-    var_666 -> foo_t \*
+    bar -> 0x[0-9a-f]*: struct var_3 \(size 0x[0-9a-f]*\)
+    var_1 -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_666 -> 0x[0-9a-f]*: foo_t \* \(size 0x[0-9a-f]*\) -> .*
 
   Function objects:
-    func_[0-9]* -> void \*\(\*\) \(const char \*restrict, int \(\*\)\(\*\) \(const char \*\)\)
+    func_[0-9]* -> 0x[0-9a-f]*: void \*\(\*\) \(const char \*restrict, int \(\*\)\(\*\) \(const char \*\)\)
 #...
   Types:
 #...
@@ -46,13 +46,13 @@ CTF archive member: .*/data-func-1\.c:
   Labels:
 
   Data objects:
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
-    var_[0-9]* -> foo_t
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
 #...
   Function objects:
 
diff --git a/ld/testsuite/ld-ctf/diag-cttname-null.d b/ld/testsuite/ld-ctf/diag-cttname-null.d
index 00db4251a4d..86a7fd12da6 100644
--- a/ld/testsuite/ld-ctf/diag-cttname-null.d
+++ b/ld/testsuite/ld-ctf/diag-cttname-null.d
@@ -13,7 +13,7 @@ Contents of CTF section .ctf:
     Version: 4 \(CTF_VERSION_3\)
 #...
   Data objects:
-    a -> struct 
+    a -> 0x[0-9a-f]*: struct  \(size 0x[0-9a-f]*\)
 #...
   Types:
 #...
diff --git a/ld/testsuite/ld-ctf/diag-cuname.d b/ld/testsuite/ld-ctf/diag-cuname.d
index 19a4bfd80fa..20624fd8b7b 100644
--- a/ld/testsuite/ld-ctf/diag-cuname.d
+++ b/ld/testsuite/ld-ctf/diag-cuname.d
@@ -21,7 +21,7 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    a -> struct A
+    a -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
 #...
   Function objects:
 
diff --git a/ld/testsuite/ld-ctf/diag-parlabel.d b/ld/testsuite/ld-ctf/diag-parlabel.d
index b2b047cb10f..5ad58706b0e 100644
--- a/ld/testsuite/ld-ctf/diag-parlabel.d
+++ b/ld/testsuite/ld-ctf/diag-parlabel.d
@@ -20,7 +20,7 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    a -> struct A
+    a -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
 #...
   Function objects:
 
diff --git a/ld/testsuite/ld-ctf/function.d b/ld/testsuite/ld-ctf/function.d
index 241adc2fb3a..9bf26a48928 100644
--- a/ld/testsuite/ld-ctf/function.d
+++ b/ld/testsuite/ld-ctf/function.d
@@ -18,10 +18,10 @@ Contents of CTF section .ctf:
     String section:	.*
 #...
   Function objects:
-    foo -> int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\)
+    foo -> 0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\)
 #...
   Types:
 #...
-     0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\) \(size 0x0\)
+     0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\)
            *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 5\) int \(\*\) \(char, int[0-9]*, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
 #...
diff --git a/ld/testsuite/ld-ctf/slice.d b/ld/testsuite/ld-ctf/slice.d
index e42ffdf4b65..3967a2db537 100644
--- a/ld/testsuite/ld-ctf/slice.d
+++ b/ld/testsuite/ld-ctf/slice.d
@@ -19,7 +19,7 @@ Contents of CTF section .ctf:
     String section:	.*
 #...
   Data objects:
-    slices -> struct slices
+    slices -> 0x[0-9a-f]*: struct slices \(size 0x[0-9a-f]*\)
 #...
   Types:
 #...
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 83b27b213b2..fd64dd3a9a0 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -93,6 +93,8 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   do
     {
       ctf_encoding_t enc;
+      ctf_arinfo_t ar;
+      int kind, unsliced_kind;
       const char *nonroot_leader = "";
       const char *nonroot_trailer = "";
 
@@ -123,26 +125,25 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       bit = NULL;
 
       if (buf[0] != '\0')
-	{
-	  str = str_append (str, buf);
-	  str = str_append (str, " ");
-	}
+	str = str_append (str, buf);
 
       free (buf);
       buf = NULL;
+      unsliced_kind = ctf_type_kind_unsliced (fp, id);
+      kind = ctf_type_kind (fp, id);
 
       /* Slices get a different print representation.  */
-      if (ctf_type_kind_unsliced (fp, id) == CTF_K_SLICE)
+      if (unsliced_kind == CTF_K_SLICE)
 	{
 	  ctf_type_encoding (fp, id, &enc);
-	  if (asprintf (&bit, "[slice 0x%x:0x%x] ",
+	  if (asprintf (&bit, " [slice 0x%x:0x%x]",
 			enc.cte_offset, enc.cte_bits) < 0)
 	    goto oom;
 	}
-      else if (ctf_type_kind (fp, id) == CTF_K_INTEGER)
+      else if (kind == CTF_K_INTEGER)
 	{
 	  ctf_type_encoding (fp, id, &enc);
-	  if (asprintf (&bit, "[0x%x:0x%x] ",
+	  if (asprintf (&bit, " [0x%x:0x%x]",
 			enc.cte_offset, enc.cte_bits) < 0)
 	    goto oom;
 	}
@@ -150,16 +151,27 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       free (bit);
       bit = NULL;
 
-      if (asprintf (&bit, "(size 0x%lx)%s",
-		    (unsigned long) ctf_type_size (fp, id),
-		    nonroot_trailer) < 0)
-	goto oom;
+      if (kind != CTF_K_FUNCTION)
+	if (asprintf (&bit, " (size 0x%lx)%s",
+		      (unsigned long) ctf_type_size (fp, id),
+		      nonroot_trailer) < 0)
+	  goto oom;
 
       str = str_append (str, bit);
       free (bit);
       bit = NULL;
 
-      new_id = ctf_type_reference (fp, id);
+      /* Keep going as long as this type references another.  We consider arrays
+	 to "reference" their element type. */
+
+      if (kind == CTF_K_ARRAY)
+	{
+	  if (ctf_array_info (fp, id, &ar) < 0)
+	    goto err;
+	  new_id = ar.ctr_contents;
+	}
+      else
+	new_id = ctf_type_reference (fp, id);
       if (new_id != CTF_ERR)
 	str = str_append (str, " ->");
     } while (new_id != CTF_ERR);
@@ -383,36 +395,26 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
   while ((id = ctf_symbol_next (fp, &i, &name, functions)) != CTF_ERR)
     {
       char *typestr = NULL;
-      int err = 0;
 
-      /* Emit the name, if we know it.  */
+      /* Emit the name, if we know it.  No trailing space: ctf_dump_format_type
+	 has a leading one.   */
       if (name)
 	{
-	  if (asprintf (&str, "%s -> ", name) < 0)
+	  if (asprintf (&str, "%s ->", name) < 0)
 	    goto oom;
 	}
       else
 	str = xstrdup ("");
 
-      if ((typestr = ctf_type_aname (fp, id)) == NULL)
+      if ((typestr = ctf_dump_format_type (state->cds_fp, id,
+					   CTF_ADD_ROOT)) == NULL)
 	{
-	  if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
-	    {
-	      if (asprintf (&typestr, " (%s)", _("type not represented in CTF")) < 0)
-		goto oom;
-
-	      goto out;
-	    }
-
-	  if (asprintf (&typestr, _("error: %s"), ctf_errmsg (ctf_errno (fp))) < 0)
-	    goto oom;
-
-	  err = -1;
-	  goto out;
+	  ctf_dump_append (state, str);
+	  continue;				/* Swallow the error.  */
 	}
 
       str = str_append (str, typestr);
-      str = str_append (str, "\n");
+      free (typestr);
       ctf_dump_append (state, str);
       continue;
 
@@ -420,12 +422,6 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
       ctf_set_errno (fp, ENOMEM);
       ctf_next_destroy (i);
       return -1;
-    out:
-      str = str_append (str, typestr);
-      free (typestr);
-      ctf_dump_append (state, str);
-      ctf_next_destroy (i);
-      return err;				/* errno is set for us.  */
     }
   return 0;
 }
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (2 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 03/13] libctf, ld: more dumper improvements Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-27 17:43   ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 05/13] libctf, ld: dump enums: generally improve dump formatting Nick Alcock
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

C allows you to do only a very few things with entities of incomplete
type (as opposed to pointers to them): make pointers to them and give
them cv-quals, roughly. In particular you can't sizeof them and you
can't get their alignment.

While we explicitly do not impose all the requirements the standard
imposes on CTF users, and it *is* still desirable to be able to get size
and alignment info for incomplete array types (because of their use as
the last member of structures), it is meaningless to ask for the size or
alignment of forwards.  Worse, libctf didn't prohibit this and returned
nonsense from internal implementation details when you asked (it
returned the kind of the pointed-to type as both the size and alignment,
because forwards reuse ctt_type as a type kind, and ctt_type and
ctt_size overlap).  So introduce a new error, ECTF_INCOMPLETE, which is
returned when you try to get the size or alignment of forwards: we also
return it when you try to construct CTF dicts that do invalid things
with forwards, namely adding a forward member to a struct or union or
making an array of elements of forward type.

The dumper will not emit size or alignment info for forwards any more.

(This should not be an API break since ctf_type_size and ctf_type_align
could both return errors before now: any code that isn't expecting error
returns is already potentially broken.)

include/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-api.h (ECTF_INCOMPLETE): New.
	(ECTF_NERR): Adjust.

ld/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/conflicting-cycle-1.parent.d: Adjust for dumper
	changes.
	* testsuite/ld-ctf/cross-tu-cyclic-conflicting.d: Likewise.
	* testsuite/ld-ctf/forward.c: New test...
	* testsuite/ld-ctf/forward.d: ... and results.

libctf/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-types.c (ctf_type_resolve): Improve comment.
	(ctf_type_size): Return ECTF_INCOMPLETE when applied to forwards.
	(ctf_type_align): Likewise.
	* ctf-create.c (ctf_add_array): Likewise.
	(ctf_add_member_offset): Likewise.
	* ctf-dump.c (ctf_dump_format_type): Do not try to print the size of
	forwards.
	(ctf_dump_member): Do not try to print their alignment.
---
 include/ctf-api.h                             |  5 ++--
 .../ld-ctf/conflicting-cycle-1.parent.d       |  4 ++--
 .../ld-ctf/cross-tu-cyclic-conflicting.d      |  4 ++--
 ld/testsuite/ld-ctf/forward.c                 |  2 ++
 ld/testsuite/ld-ctf/forward.d                 | 23 +++++++++++++++++++
 libctf/ctf-create.c                           | 20 ++++++++++++++++
 libctf/ctf-dump.c                             | 17 +++++++++++---
 libctf/ctf-types.c                            | 13 ++++++++++-
 8 files changed, 78 insertions(+), 10 deletions(-)
 create mode 100644 ld/testsuite/ld-ctf/forward.c
 create mode 100644 ld/testsuite/ld-ctf/forward.d

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 9dd0592ab8a..16567ef3ab6 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -230,7 +230,8 @@ typedef struct ctf_snapshot_id
   _CTF_ITEM (ECTF_NEXT_WRONGFUN, "Wrong iteration function called.") \
   _CTF_ITEM (ECTF_NEXT_WRONGFP, "Iteration entity changed in mid-iterate.") \
   _CTF_ITEM (ECTF_FLAGS, "CTF header contains flags unknown to libctf.") \
-  _CTF_ITEM (ECTF_NEEDSBFD, "This feature needs a libctf with BFD support.")
+  _CTF_ITEM (ECTF_NEEDSBFD, "This feature needs a libctf with BFD support.") \
+  _CTF_ITEM (ECTF_INCOMPLETE, "Type is not a complete type.")
 
 #define	ECTF_BASE	1000	/* Base value for libctf errnos.  */
 
@@ -243,7 +244,7 @@ _CTF_ERRORS
 #undef _CTF_FIRST
   };
 
-#define ECTF_NERR (ECTF_NEEDSBFD - ECTF_BASE + 1) /* Count of CTF errors.  */
+#define ECTF_NERR (ECTF_INCOMPLETE - ECTF_BASE + 1) /* Count of CTF errors.  */
 
 /* The CTF data model is inferred to be the caller's data model or the data
    model of the given object, unless ctf_setmodel is explicitly called.  */
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
index 4cbe9b61f3c..5da66fda14c 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
@@ -29,8 +29,8 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct B \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B \(.*
+     0x[0-9a-f]*: struct B
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B
 #...
 CTF archive member: .*:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
index 3c975ebaa51..eff295edd30 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
@@ -23,8 +23,8 @@ Contents of CTF section \.ctf:
      0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
            *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 #...
-     0x[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A .*
+     0x[0-9a-f]*: struct A
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A
 #...
      0x[0-9a-f]*: struct C .*
            *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C .*
diff --git a/ld/testsuite/ld-ctf/forward.c b/ld/testsuite/ld-ctf/forward.c
new file mode 100644
index 00000000000..e41a7aececa
--- /dev/null
+++ b/ld/testsuite/ld-ctf/forward.c
@@ -0,0 +1,2 @@
+struct foo;
+struct foo *bar __attribute__((used));
diff --git a/ld/testsuite/ld-ctf/forward.d b/ld/testsuite/ld-ctf/forward.d
new file mode 100644
index 00000000000..9ff0dd2ba73
--- /dev/null
+++ b/ld/testsuite/ld-ctf/forward.d
@@ -0,0 +1,23 @@
+#as:
+#source: forward.c
+#objdump: --ctf=.ctf
+#ld: -shared
+#name: Forwards
+
+.*: +file format .*
+
+Contents of CTF section .ctf:
+
+  Header:
+    Magic number: 0xdff2
+    Version: 4 \(CTF_VERSION_3\)
+#...
+    Type section:	.* \(0x18 bytes\)
+#...
+  Types:
+
+     0x[0-9a-f]: struct foo
+          *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct foo
+     0x[0-9a-f]: struct foo \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]: struct foo
+          *\[0x0\] \(ID 0x[0-9a-f]\) \(kind 3\) struct foo \* \(aligned at 0x[0-9a-f]*\)
+#...
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index e03a04683dd..28c468372e8 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1690,6 +1690,22 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   if (ctf_lookup_by_id (&tmp, arp->ctr_index) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
 
+  if (ctf_type_kind (fp, arp->ctr_contents) == CTF_K_FORWARD)
+    {
+      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+		    _("ctf_add_array: content type %lx is incomplete"),
+		    arp->ctr_contents);
+      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+    }
+
+  if (ctf_type_kind (fp, arp->ctr_index) == CTF_K_FORWARD)
+    {
+      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+		    _("ctf_add_array: index type %lx is incomplete"),
+		    arp->ctr_contents);
+      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+    }
+
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
@@ -2123,6 +2139,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	      return -1;	/* errno is set for us.  */
 	    }
 
+	  /* We can rely on this type having a valid size due to the
+	     size/alignment checks above prohibiting forward member
+	     addition.  */
+
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
 	    off += linfo.cte_bits;
 	  else if ((lsize = ctf_type_size (fp, ltype)) > 0)
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index fd64dd3a9a0..a49f39e4569 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -151,7 +151,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       free (bit);
       bit = NULL;
 
-      if (kind != CTF_K_FUNCTION)
+      if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
 	if (asprintf (&bit, " (size 0x%lx)%s",
 		      (unsigned long) ctf_type_size (fp, id),
 		      nonroot_trailer) < 0)
@@ -476,6 +476,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   char *bit = NULL;
   ctf_encoding_t ep;
   int has_encoding = 0;
+  int opened_paren = 0;
 
   /* Align neatly.  */
 
@@ -520,8 +521,9 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
 		    ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
 								 id)) < 0)
 	goto oom;
+      opened_paren = 1;
     }
-  else
+  else if (ctf_type_kind (state->cdm_fp, id) != CTF_K_FORWARD)
     {
       if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
 		    "(aligned at 0x%lx", offset, id,
@@ -529,6 +531,14 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
 		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
 		    (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
 	goto oom;
+      opened_paren = 1;
+    }
+  else /* Forwards have no alignment.  */
+    {
+      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s\n", offset, id,
+		    ctf_type_kind (state->cdm_fp, id), typestr,
+		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name) < 0)
+	goto oom;
     }
 
   *state->cdm_str = str_append (*state->cdm_str, bit);
@@ -547,7 +557,8 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
       bit = NULL;
     }
 
-  *state->cdm_str = str_append (*state->cdm_str, ")\n");
+  if (opened_paren)
+    *state->cdm_str = str_append (*state->cdm_str, ")\n");
   return 0;
 
  oom:
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index dd8ee4fd0ee..9483930f40c 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -583,7 +583,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
    against infinite loops, we implement simplified cycle detection and check
    each link against itself, the previous node, and the topmost node.
 
-   Does not drill down through slices to their contained type.  */
+   Does not drill down through slices to their contained type.
+
+   Callers of this function must not presume that a type it returns must have a
+   valid ctt_size: forwards do not, and must be separately handled.  */
 
 ctf_id_t
 ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
@@ -948,6 +951,10 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 
       return size * ar.ctr_nelems;
 
+    case CTF_K_FORWARD:
+      /* Forwards do not have a meaningful size.  */
+      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
@@ -1043,6 +1050,10 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_ENUM:
       return fp->ctf_dmodel->ctd_int;
 
+    case CTF_K_FORWARD:
+      /* Forwards do not have a meaningful alignment.  */
+      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 05/13] libctf, ld: dump enums: generally improve dump formatting
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (3 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH REVIEW 06/13] libctf: rip out BFD_DEPENDENCIES / BFD_LIBADD Nick Alcock
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

This commit adds dumping of enumerands in this general form:

    0x3: (kind 8) enum eleven_els (size 0x4) (aligned at 0x4)
         ELEVEN_ONE: 10
         ELEVEN_TWO: 11
         ELEVEN_THREE: -256
         ELEVEN_FOUR: -255
         ELEVEN_FIVE: -254
         ...
         ELEVEN_SEVEN: -252
         ELEVEN_EIGHT: -251
         ELEVEN_NINE: -250
         ELEVEN_TEN: -249
         ELEVEN_ELEVEN: -248

The first and last enumerands in the enumerated type are printed so that
you can tell if they've been cut off at one end or the other.  (For now,
there is no way to control how many enumerands are printed.)

The dump output in general is improved, from this sort of thing a few
days ago:

     4c: char [0x0:0x8] (size 0x1)
        [0x0] (ID 0x4c) (kind 1) char:8 (aligned at 0x1, format 0x3, offset:bits 0x0:0x8)
     4d: char * (size 0x8) -> 4c: char [0x0:0x8] (size 0x1)
        [0x0] (ID 0x4d) (kind 3) char * (aligned at 0x8)
[...]
     5a: struct _IO_FILE (size 0xd8)
        [0x0] (ID 0x5a) (kind 6) struct _IO_FILE (aligned at 0x4)
            [0x0] (ID 0x3) (kind 1) int _flags:32 (aligned at 0x4, format 0x1, offset:bits 0x0:0x20)
            [0x40] (ID 0x4d) (kind 3) char * _IO_read_ptr (aligned at 0x8)
            [0x80] (ID 0x4d) (kind 3) char * _IO_read_end (aligned at 0x8)
            [0xc0] (ID 0x4d) (kind 3) char * _IO_read_base (aligned at 0x8)
     5b: __FILE (size 0xd8) -> 5a: struct _IO_FILE (size 0xd8)
        [0x0] (ID 0x5b) (kind 10) __FILE (aligned at 0x4)
            [0x0] (ID 0x3) (kind 1) int _flags:32 (aligned at 0x4, format 0x1, offset:bits 0x0:0x20)
            [0x40] (ID 0x4d) (kind 3) char * _IO_read_ptr (aligned at 0x8)
            [0x80] (ID 0x4d) (kind 3) char * _IO_read_end (aligned at 0x8)
            [0xc0] (ID 0x4d) (kind 3) char * _IO_read_base (aligned at 0x8)
[...]
     406: struct coff_link_hash_entry (size 0x60)
        [0x0] (ID 0x406) (kind 6) struct coff_link_hash_entry (aligned at 0x8)
            [0x0] (ID 0x2b3) (kind 6) struct bfd_link_hash_entry root (aligned at 0x8)
                [0x0] (ID 0x1d6) (kind 6) struct bfd_hash_entry root (aligned at 0x8)
                    [0x0] (ID 0x1d7) (kind 3) struct bfd_hash_entry * next (aligned at 0x8)
                    [0x40] (ID 0x61) (kind 3) const char * string (aligned at 0x8)
                    [0x80] (ID 0x1) (kind 1) long unsigned int hash:64 (aligned at 0x8, format 0x0, offset:bits 0x0:0x40)
                [0xc0] (ID 0x397) (kind 8) enum bfd_link_hash_type  type:8 (aligned at 0x1, format 0x0, offset:bits 0x0:0x8)
                [0xc8] (ID 0x1c7) (kind 1) unsigned int  non_ir_ref_regular:1 (aligned at 0x1, format 0x0, offset:bits 0x8:0x1)
                [0xc9] (ID 0x1c8) (kind 1) unsigned int  non_ir_ref_dynamic:1 (aligned at 0x1, format 0x0, offset:bits 0x9:0x1)
                [0xca] (ID 0x1c9) (kind 1) unsigned int  linker_def:1 (aligned at 0x1, format 0x0, offset:bits 0xa:0x1)
                [0xcb] (ID 0x1ca) (kind 1) unsigned int  ldscript_def:1 (aligned at 0x1, format 0x0, offset:bits 0xb:0x1)
                [0xcc] (ID 0x1cb) (kind 1) unsigned int  rel_from_abs:1 (aligned at 0x1, format 0x0, offset:bits 0xc:0x1)

... to this:

    0x4c: (kind 1) char (format 0x3) (size 0x1) (aligned at 0x1)
    0x4d: (kind 3) char * (size 0x8) (aligned at 0x8) -> 0x4c: (kind 1) char (format 0x3) (size 0x1) (aligned at 0x1)
    0x5a: (kind 6) struct _IO_FILE (size 0xd8) (aligned at 0x4)
          [0x0] _flags: ID 0x3: (kind 1) int (format 0x1) (size 0x4) (aligned at 0x4)
          [0x40] _IO_read_ptr: ID 0x4d: (kind 3) char * (size 0x8) (aligned at 0x8)
          [0x80] _IO_read_end: ID 0x4d: (kind 3) char * (size 0x8) (aligned at 0x8)
          [0xc0] _IO_read_base: ID 0x4d: (kind 3) char * (size 0x8) (aligned at 0x8)
          [0x100] _IO_write_base: ID 0x4d: (kind 3) char * (size 0x8) (aligned at 0x8)
    0x5b: (kind 10) __FILE (size 0xd8) (aligned at 0x4) -> 0x5a: (kind 6) struct _IO_FILE (size 0xd8) (aligned at 0x4)
[...]
    0x406: (kind 6) struct coff_link_hash_entry (size 0x60) (aligned at 0x8)
           [0x0] root: ID 0x2b3: (kind 6) struct bfd_link_hash_entry (size 0x38) (aligned at 0x8)
               [0x0] root: ID 0x1d6: (kind 6) struct bfd_hash_entry (size 0x18) (aligned at 0x8)
                   [0x0] next: ID 0x1d7: (kind 3) struct bfd_hash_entry * (size 0x8) (aligned at 0x8)
                   [0x40] string: ID 0x61: (kind 3) const char * (size 0x8) (aligned at 0x8)
                   [0x80] hash: ID 0x1: (kind 1) long unsigned int (format 0x0) (size 0x8) (aligned at 0x8)
               [0xc0] type: ID 0x397: (kind 8) enum bfd_link_hash_type (format 0x7f2e) (size 0x1) (aligned at 0x1)
               [0xc8] non_ir_ref_regular: ID 0x1c7: (kind 1) unsigned int:1 [slice 0x8:0x1] (format 0x0) (size 0x1) (aligned at 0x1)
               [0xc9] non_ir_ref_dynamic: ID 0x1c8: (kind 1) unsigned int:1 [slice 0x9:0x1] (format 0x0) (size 0x1) (aligned at 0x1)
               [0xca] linker_def: ID 0x1c9: (kind 1) unsigned int:1 [slice 0xa:0x1] (format 0x0) (size 0x1) (aligned at 0x1)
               [0xcb] ldscript_def: ID 0x1ca: (kind 1) unsigned int:1 [slice 0xb:0x1] (format 0x0) (size 0x1) (aligned at 0x1)
               [0xcc] rel_from_abs: ID 0x1cb: (kind 1) unsigned int:1 [slice 0xc:0x1] (format 0x0) (size 0x1) (aligned at 0x1)
[...]

In particular, indented subsections are only present for actual structs
and unions, not forwards to them, and the structure itself doesn't add a
spurious level of indentation; structure field names are easier to spot
(at the cost of not making them look so much like C field declarations
any more, but they weren't always shown in valid decl syntax even before
this change) the size, type kind, and alignment are shown for all types
for which they are meaningful; bitfield info is only shown for actual
bitfields within structures and not ordinary integral fields; and type
IDs are never omitted.  Type printing is in general much more consistent
and there is much less duplicated code in the type dumper.

There is one user-visible effect outside the dumper: ctf_type_(a)name
was erroneously emitting a trailing space on the name of slice types,
even though a slice of an int and an int with the corresponding encoding
represent the same type and should have the same print form.  This
trailing space is now gone.

ld/ChangeLog
2020-12-09  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/array.d: Adjust for dumper changes.
	* testsuite/ld-ctf/conflicting-cycle-1.B-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-1.B-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-1.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.A-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.A-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-2.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.C-1.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.C-2.d: Likewise.
	* testsuite/ld-ctf/conflicting-cycle-3.parent.d: Likewise.
	* testsuite/ld-ctf/conflicting-enums.d: Likewise.
	* testsuite/ld-ctf/conflicting-typedefs.d: Likewise.
	* testsuite/ld-ctf/cross-tu-cyclic-conflicting.d: Likewise.
	* testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d: Likewise.
	* testsuite/ld-ctf/cross-tu-into-cycle.d: Likewise.
	* testsuite/ld-ctf/cross-tu-noncyclic.d: Likewise.
	* testsuite/ld-ctf/cycle-1.d: Likewise.
	* testsuite/ld-ctf/cycle-2.A.d: Likewise.
	* testsuite/ld-ctf/cycle-2.B.d: Likewise.
	* testsuite/ld-ctf/cycle-2.C.d: Likewise.
	* testsuite/ld-ctf/data-func-conflicted.d: Likewise.
	* testsuite/ld-ctf/diag-cttname-null.d: Likewise.
	* testsuite/ld-ctf/diag-cuname.d: Likewise.
	* testsuite/ld-ctf/diag-parlabel.d: Likewise.
	* testsuite/ld-ctf/diag-wrong-magic-number-mixed.d: Likewise.
	* testsuite/ld-ctf/forward.d: Likewise.
	* testsuite/ld-ctf/function.d: Likewise.
	* testsuite/ld-ctf/slice.d: Likewise.
	* testsuite/ld-ctf/super-sub-cycles.d: Likewise.
	* testsuite/ld-ctf/enums.c: New test.
	* testsuite/ld-ctf/enums.d: New test.

libctf/ChangeLog
2020-12-09  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-decl.c (ctf_decl_push): Exclude slices from the decl stack.
	* ctf-types.c (ctf_type_aname): No longer deal with slices here.
	* ctf-dump.c (ctf_dump_membstate_t) <cdm_toplevel_indent>: Constify.
	(CTF_FT_REFS): New.
	(CTF_FT_BITFIELD): Likewise.
	(CTF_FT_ID): Likewise.
	(ctf_dump_member): Do not do indentation here. Migrate the
	type-printing parts of this into...
	(ctf_dump_format_type): ... here, to be shared by all type printers.
	Get the errno value for non-representable types right.  Do not print
	bitfield info for non-bitfields.  Improve the format and indentation
	of other type output.  Shuffle spacing around to make all indentation
	either 'width of column' or 4 chars.
	(ctf_dump_label): Pass CTF_FT_REFS to ctf_dump_format_type.
	(ctf_dump_objts): Likewise.  Spacing shuffle.
	(ctf_dump_var): Likewise.
	(type_hex_digits): Migrate down in the file, to above its new user.
	(ctf_dump_type): Indent here instead.  Pass CTF_FT_REFS to
	ctf_dump_format_type. Don't trim off excess linefeeds now we no
	longer generate them.  Dump enumerated types.
---
 ld/testsuite/ld-ctf/array.d                   |   8 +-
 ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d |   7 +-
 ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d |   9 +-
 .../ld-ctf/conflicting-cycle-1.parent.d       |   3 +-
 ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d |   7 +-
 ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d |   9 +-
 .../ld-ctf/conflicting-cycle-2.parent.d       |  11 +-
 ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d |   7 +-
 ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d |   9 +-
 .../ld-ctf/conflicting-cycle-3.parent.d       |   3 +-
 ld/testsuite/ld-ctf/conflicting-enums.d       |  20 +-
 ld/testsuite/ld-ctf/conflicting-typedefs.d    |  12 +-
 .../ld-ctf/cross-tu-cyclic-conflicting.d      |  31 +-
 .../ld-ctf/cross-tu-cyclic-nonconflicting.d   |  26 +-
 ld/testsuite/ld-ctf/cross-tu-into-cycle.d     |  22 +-
 ld/testsuite/ld-ctf/cross-tu-noncyclic.d      |  18 +-
 ld/testsuite/ld-ctf/cycle-1.d                 |   9 +-
 ld/testsuite/ld-ctf/cycle-2.A.d               |   7 +-
 ld/testsuite/ld-ctf/cycle-2.B.d               |   7 +-
 ld/testsuite/ld-ctf/cycle-2.C.d               |   7 +-
 ld/testsuite/ld-ctf/data-func-conflicted.d    |  27 +-
 ld/testsuite/ld-ctf/diag-cttname-null.d       |   7 +-
 ld/testsuite/ld-ctf/diag-cuname.d             |   7 +-
 ld/testsuite/ld-ctf/diag-parlabel.d           |   7 +-
 .../ld-ctf/diag-wrong-magic-number-mixed.d    |   6 +-
 ld/testsuite/ld-ctf/enums.c                   |   3 +
 ld/testsuite/ld-ctf/enums.d                   |  54 +++
 ld/testsuite/ld-ctf/forward.d                 |   6 +-
 ld/testsuite/ld-ctf/function.d                |   5 +-
 ld/testsuite/ld-ctf/slice.d                   |  14 +-
 ld/testsuite/ld-ctf/super-sub-cycles.d        |  27 +-
 libctf/ctf-decl.c                             |   5 +-
 libctf/ctf-dump.c                             | 308 ++++++++++--------
 libctf/ctf-types.c                            |   4 -
 34 files changed, 386 insertions(+), 326 deletions(-)
 create mode 100644 ld/testsuite/ld-ctf/enums.c
 create mode 100644 ld/testsuite/ld-ctf/enums.d

diff --git a/ld/testsuite/ld-ctf/array.d b/ld/testsuite/ld-ctf/array.d
index 6c3915a7cf8..16375620c03 100644
--- a/ld/testsuite/ld-ctf/array.d
+++ b/ld/testsuite/ld-ctf/array.d
@@ -20,8 +20,8 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    digits -> 0x[0-9a-f]*: int \[10\] .*
-    digits_names -> 0x[0-9a-f]*: char \*\[10\] .*
+    digits -> 0x[0-9a-f]*: \(kind 4\) int \[10\] .*
+    digits_names -> 0x[0-9a-f]*: \(kind 4\) char \*\[10\] .*
 
   Function objects:
 
@@ -29,7 +29,7 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: .*\[10\] .*
+    0x[0-9a-f]*: \(kind 4\) .*\[10\] \(size .*
 #...
-     0x[0-9a-f]*: .*\[10\] .*
+    0x[0-9a-f]*: \(kind 4\) .*\[10\] \(size .*
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
index 99b0564bad7..27273c5386f 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-1.d
@@ -30,12 +30,11 @@ CTF archive member: .*/B.c:
   Function objects:
 
   Variables:
-    b ->  0x80000001: struct B \(size 0x[0-9]*\)
+    b -> 0x80000001: \(kind 6\) struct B \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
-     0x8[0-9a-f]*: struct B .*
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+    0x8[0-9a-f]*: \(kind 6\) struct B .*
+        *\[0x0\] c: ID 0x[0-9a-f]*: \(kind 3\) struct C \* \(.*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
index 32bc5c24f05..28a92f4a73e 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.B-2.d
@@ -30,13 +30,12 @@ CTF archive member: .*/B-2.c:
   Function objects:
 
   Variables:
-    b ->  0x80000001: struct B \(.*
+    b -> 0x80000001: \(kind 6\) struct B \(.*
 
   Types:
-     0x8[0-9a-f]*: struct B \(.*
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct B \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x8[0-9a-f]*: \(kind 6\) struct B \(.*
+        *\[0x0\] c: ID 0x[0-9a-f]*: \(kind 3\) struct C \* \(.*
+        *\[0x[0-9a-f]*\] wombat: ID 0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
index 5da66fda14c..a9755e88db7 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
@@ -29,8 +29,7 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct B
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B
+    0x[0-9a-f]*: \(kind 9\) struct B
 #...
 CTF archive member: .*:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
index 5e5fade0af8..33ed6e843ce 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-1.d
@@ -29,12 +29,11 @@ CTF archive member: .*/A.c:
   Function objects:
 
   Variables:
-    a ->  0x80000001: struct A \(size 0x[0-9a-f]*\)
+    a -> 0x80000001: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
-     0x8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
+    0x8[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
index ff6785cfde2..a98b66c267e 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.A-2.d
@@ -29,13 +29,12 @@ CTF archive member: .*/A-2.c:
   Function objects:
 
   Variables:
-    a ->  0x80000001: struct A \(size 0x[0-9a-f]*\)
+    a -> 0x80000001: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
-     0x8[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:32 \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x8[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x[0-9a-f]*\] wombat: ID 0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
index d111ef7b994..87ec41d69e4 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-2.parent.d
@@ -28,13 +28,12 @@ Contents of CTF section .ctf:
   Function objects:
 
   Variables:
-    cycle_1 ->  0x[0-9a-f]*: struct cycle_1 \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
+    cycle_1 -> 0x[0-9a-f]*: \(kind 3\) struct cycle_1 \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 6\) struct cycle_1 \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
 #...
-     0x[0-9a-f]*: struct cycle_1 \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(aligned at 0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 6\) struct cycle_1 \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x[0-9a-f]*\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x[0-9a-f]*\] next: ID 0x[0-9a-f]*: \(kind 3\) struct cycle_1 \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
index df61153db2a..ac750a776db 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-1.d
@@ -28,12 +28,11 @@ CTF archive member: .*/C.c:
   Function objects:
 
   Variables:
-    c ->  0x80000001: struct C \(size 0x[0-9a-f]*\)
+    c -> 0x80000001: \(kind 6\) struct C \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
-     0x8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
+    0x80000001: \(kind 6\) struct C \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
index e1cfd0cf771..603432f05ad 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.C-2.d
@@ -28,13 +28,12 @@ CTF archive member: .*/C-2.c:
   Function objects:
 
   Variables:
-    c ->  0x80000001: struct C \(size 0x[0-9a-f]*\)
+    c -> 0x80000001: \(kind 6\) struct C \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Types:
-     0x8[0-9a-f]*: struct C \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 6\) struct C \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(aligned at 0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 1\) int wombat:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x80000001: \(kind 6\) struct C \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+                \[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+                \[0x[0-9a-f]*\] wombat: ID 0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
index 11d2a048618..24f080004cd 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-3.parent.d
@@ -30,8 +30,7 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/conflicting-enums.d b/ld/testsuite/ld-ctf/conflicting-enums.d
index b93d8124f36..f90aaef44b1 100644
--- a/ld/testsuite/ld-ctf/conflicting-enums.d
+++ b/ld/testsuite/ld-ctf/conflicting-enums.d
@@ -20,16 +20,28 @@ Contents of CTF section .ctf:
 CTF archive member: .*enum.*\.c:
 #...
   Types:
-     0x8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
+    0x80000001: \(kind 8\) enum day_of_the_week \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+                Sunday: 0
+                Monday: 1
+                Tuesday: 2
+                Wednesday: 3
+                Thursday: 4
+                Friday: 5
+                Saturday: 6
 
   Strings:
 #...
 CTF archive member: .*enum.*\.c:
 #...
   Types:
-     0x8[0-9a-f]*: enum day_of_the_week \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x8[0-9a-f]*\) \(kind 8\) enum day_of_the_week \(aligned at 0x[0-9a-f]*\)
+    0x80000001: \(kind 8\) enum day_of_the_week \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+                Monday: 0
+                Tuesday: 1
+                Wednesday: 2
+                Thursday: 3
+                Friday: 4
+                Saturday: 5
+                Sunday: 6
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/conflicting-typedefs.d b/ld/testsuite/ld-ctf/conflicting-typedefs.d
index 309e4535d7f..72082ba553b 100644
--- a/ld/testsuite/ld-ctf/conflicting-typedefs.d
+++ b/ld/testsuite/ld-ctf/conflicting-typedefs.d
@@ -14,20 +14,16 @@ Contents of CTF section .ctf:
     Version: 4 \(CTF_VERSION_3\)
 #...
   Types:
-     0x1: .*int .*
-          .*
-     0x[0-9]:.*int .*
-          .*
-     0x[0-9]: word .*
-           *\[0x0\] \(ID 0x[0-9]\) \(kind 10\) word \(aligned at 0x[48]\)
+    0x1: .*int .*
+    0x[0-9]:.*int .*
+    0x[0-9]: \(kind 10\) word .* -> 0x[0-9]: \(kind 1\) .*int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
 #...
 CTF archive member: .*typedef.*\.c:
 #...
   Types:
-     0x80000001: word .*
-           *\[0x0\] \(ID 0x80000001\) \(kind 10\) word \(aligned at 0x[48]\)
+    0x80000001: \(kind 10\) word .* -> 0x[0-9]: \(kind 1\) .*int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
index eff295edd30..eaf8e79c8ad 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
@@ -14,20 +14,15 @@ Contents of CTF section \.ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: long int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 1\) long int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
-     0x[0-9a-f]*: struct B .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
+    0x[0-9a-f]*: \(kind 6\) struct B .*
 #...
-     0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
-     0x[0-9a-f]*: struct A
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A
+    0x[0-9a-f]*: \(kind 9\) struct A
 #...
-     0x[0-9a-f]*: struct C .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C .*
+    0x[0-9a-f]*: \(kind 6\) struct C .*
 #...
 
   Strings:
@@ -36,10 +31,9 @@ Contents of CTF section \.ctf:
 CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-1\.c:
 #...
   Types:
-     0x80.*[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+    0x80[0-9a-f]*: \(kind 6\) struct A .*
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 1\) long int .*
+        *\[0x[0-9a-f]*\] foo: ID 0x[0-9a-f]*\: \(kind 3\) struct B \* .*
 
   Strings:
 #...
@@ -47,11 +41,10 @@ CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-1\.c:
 CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-2\.c:
 #...
   Types:
-     0x80.*[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x80.*\) \(kind 6\) struct A .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* bar .*
+    0x80[0-9a-f]*: \(kind 6\) struct A .*
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 1\) long int .*
+        *\[0x[0-9a-f]*\] foo: ID 0x[0-9a-f]*: \(kind 3\) struct B \* .*
+        *\[0x[0-9a-f]*\] bar: ID 0x[0-9a-f]*: \(kind 3\) struct C \* .*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
index 9b0d738434a..1a714846d32 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-nonconflicting.d
@@ -29,22 +29,16 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]\) \(kind 6\) struct A \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo \(aligned at 0x[0-9a-f]*\)
-     0x[0-9a-f]*: long int .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int:[0-9].*
-     0x[0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(aligned at 0x[0-9a-f]*\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* bar \(aligned at 0x[0-9a-f]*\)
-     0x[0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct B \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* \(aligned at 0x[0-9a-f]*\)
-     0x[0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* \(aligned at 0x[0-9a-f]*\)
-     0x[0-9a-f]*: int .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:.*
+    0x[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 1\) long int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x[0-9a-f]*\] foo: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 1\) long int .*
+    0x[0-9a-f]*: \(kind 6\) struct B \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] foo: ID 0x[0-9a-f]*: \(kind 1\) int \(format 0x1\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x[0-9a-f]*\] bar: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 6\) struct B \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 1\) int .*
 
   Strings:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-into-cycle.d b/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
index a21fedc8126..7f3aebc54b7 100644
--- a/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
+++ b/ld/testsuite/ld-ctf/cross-tu-into-cycle.d
@@ -27,20 +27,16 @@ Contents of CTF section .ctf:
   Function objects:
 
   Variables:
-    a ->  .*
-    conflicty ->  .*
+    a -> .*
+    conflicty -> .*
 
   Types:
-     0x[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
-     0x[0-9a-f]*: struct B .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* next .*
-     0x[0-9a-f]*: struct B \* .*
-           *\[0x0\] .*
-     0x[0-9a-f]*: struct A \* .*
-           *\[0x0\] .*
+    0x[0-9a-f]*: \(kind 6\) struct A .*
+        *\[0x0\] foo: ID 0x[0-9a-f]*: \(kind 3\) struct B \* .*
+    0x[0-9a-f]*: \(kind 6\) struct B .*
+        *\[0x0\] next: ID 0x[0-9a-f]*: \(kind 3\) struct B \* .*
+    0x[0-9a-f]*: \(kind 3\) struct B \* .*
+    0x[0-9a-f]*: \(kind 3\) struct A \* .*
 
   Strings:
 #...
@@ -56,7 +52,7 @@ CTF archive member: .*/ld/testsuite/ld-ctf/cross-tu-cyclic-[34].c:
   Function objects:
 
   Variables:
-    conflicty ->  .*
+    conflicty -> .*
 
   Types:
 
diff --git a/ld/testsuite/ld-ctf/cross-tu-noncyclic.d b/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
index d96e5d20ee8..e8fc7a49aa5 100644
--- a/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
+++ b/ld/testsuite/ld-ctf/cross-tu-noncyclic.d
@@ -29,18 +29,14 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) long int a:[0-9]* .*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* foo .*
+    0x[0-9a-f]*: \(kind 6\) struct A .*
+       *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 1\) long int .*
+       *\[0x[0-9a-f]*\] foo: ID 0x[0-9a-f]*: \(kind 3\) struct B \* .*
 #...
-     0x[0-9a-f]*: struct B .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B .*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int foo:[0-9]* .*
+    0x[0-9a-f]*: \(kind 6\) struct B .*
+       *\[0x0\] foo: ID 0x[0-9a-f]*: \(kind 1\) int .*
 #...
-     0x[0-9a-f]*: struct B \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct B .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* .*
+    0x[0-9a-f]*: \(kind 3\) struct B \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 6\) struct B .*
 #...
-     0x[0-9a-f]*: struct A \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* .*
+    0x[0-9a-f]*: \(kind 3\) struct A \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 6\) struct A .*
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-1.d b/ld/testsuite/ld-ctf/cycle-1.d
index 578709349fa..e64608e7571 100644
--- a/ld/testsuite/ld-ctf/cycle-1.d
+++ b/ld/testsuite/ld-ctf/cycle-1.d
@@ -28,9 +28,8 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct cycle_1 \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct cycle_1 \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct cycle_1 \* next \(.*
+    0x[0-9a-f]*: \(kind 6\) struct cycle_1 \(.*
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(.*
+        *\[0x[0-9a-f]*\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
+        *\[0x[0-9a-f]*\] next: ID 0x[0-9a-f]*: \(kind 3\) struct cycle_1 \* \(.*
 #...
diff --git a/ld/testsuite/ld-ctf/cycle-2.A.d b/ld/testsuite/ld-ctf/cycle-2.A.d
index ddb5381e93c..39d48c14c4b 100644
--- a/ld/testsuite/ld-ctf/cycle-2.A.d
+++ b/ld/testsuite/ld-ctf/cycle-2.A.d
@@ -25,13 +25,12 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    a ->  0x[0-9a-f]*: struct A \(.*
+    a -> 0x[0-9a-f]*: \(kind 6\) struct A \(.*
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct A \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+    0x[0-9a-f]*: \(kind 6\) struct A \(.*
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/cycle-2.B.d b/ld/testsuite/ld-ctf/cycle-2.B.d
index 1d1cdc5377d..4babd97bffe 100644
--- a/ld/testsuite/ld-ctf/cycle-2.B.d
+++ b/ld/testsuite/ld-ctf/cycle-2.B.d
@@ -25,13 +25,12 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    b ->  0x[0-9a-f]*: struct B \(.*
+    b -> 0x[0-9a-f]*: \(kind 6\) struct B \(.*
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct B \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+    0x[0-9a-f]*: \(kind 6\) struct B \(.*
+        *\[0x0\] c: ID 0x[0-9a-f]*: \(kind 3\) struct C \* \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/cycle-2.C.d b/ld/testsuite/ld-ctf/cycle-2.C.d
index 4d8f14513dd..757483ca7e2 100644
--- a/ld/testsuite/ld-ctf/cycle-2.C.d
+++ b/ld/testsuite/ld-ctf/cycle-2.C.d
@@ -25,13 +25,12 @@ Contents of CTF section .ctf:
 
   Variables:
 #...
-    c ->  0x[0-9a-f]*: struct C \(.*
+    c -> 0x[0-9a-f]*: \(kind 6\) struct C \(.*
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct C \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
+    0x[0-9a-f]*: \(kind 6\) struct C \(.*
+        *\[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/data-func-conflicted.d b/ld/testsuite/ld-ctf/data-func-conflicted.d
index e51bb763af1..6b1e9145a02 100644
--- a/ld/testsuite/ld-ctf/data-func-conflicted.d
+++ b/ld/testsuite/ld-ctf/data-func-conflicted.d
@@ -20,16 +20,16 @@ Contents of CTF section \.ctf:
     String section:	.*
 #...
   Data objects:
-    bar -> 0x[0-9a-f]*: struct var_3 \(size 0x[0-9a-f]*\)
-    var_1 -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_666 -> 0x[0-9a-f]*: foo_t \* \(size 0x[0-9a-f]*\) -> .*
+    bar -> 0x[0-9a-f]*: \(kind 6\) struct var_3 \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+    var_1 -> 0x[0-9a-f]*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_666 -> 0x[0-9a-f]*: \(kind 3\) foo_t \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
 
   Function objects:
-    func_[0-9]* -> 0x[0-9a-f]*: void \*\(\*\) \(const char \*restrict, int \(\*\)\(\*\) \(const char \*\)\)
+    func_[0-9]* -> 0x[0-9a-f]*: \(kind 5\) void \*\(\*\) \(const char \*restrict, int \(\*\)\(\*\) \(const char \*\)\) \(aligned at 0x[0-9a-f]*\)
 #...
   Types:
 #...
-   .*: struct var_3 .*
+    .*: \(kind 6\) struct var_3 .*
 #...
 CTF archive member: .*/data-func-1\.c:
 
@@ -46,18 +46,19 @@ CTF archive member: .*/data-func-1\.c:
   Labels:
 
   Data objects:
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
-    var_[0-9]* -> 0x[0-9a-f]*: foo_t \(size 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
+    var_[0-9]* -> 0x80000001*: \(kind 10\) foo_t \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> .*
 #...
   Function objects:
 
   Variables:
 
   Types:
-     0x80000001: foo_t .* -> .* int .*
+    0x80000001: \(kind 10\) foo_t .* -> .* int .*
 #...
diff --git a/ld/testsuite/ld-ctf/diag-cttname-null.d b/ld/testsuite/ld-ctf/diag-cttname-null.d
index 86a7fd12da6..d1ca0b10c15 100644
--- a/ld/testsuite/ld-ctf/diag-cttname-null.d
+++ b/ld/testsuite/ld-ctf/diag-cttname-null.d
@@ -13,11 +13,10 @@ Contents of CTF section .ctf:
     Version: 4 \(CTF_VERSION_3\)
 #...
   Data objects:
-    a -> 0x[0-9a-f]*: struct  \(size 0x[0-9a-f]*\)
+    a -> 0x[0-9a-f]*: \(kind 6\) struct  \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct  \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct  \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+    0x[0-9a-f]*: \(kind 6\) struct  \(.*
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
 #...
diff --git a/ld/testsuite/ld-ctf/diag-cuname.d b/ld/testsuite/ld-ctf/diag-cuname.d
index 20624fd8b7b..e4d49267a2a 100644
--- a/ld/testsuite/ld-ctf/diag-cuname.d
+++ b/ld/testsuite/ld-ctf/diag-cuname.d
@@ -21,7 +21,7 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    a -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+    a -> 0x[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
   Function objects:
 
@@ -29,9 +29,8 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: struct A \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+    0x[0-9a-f]*: \(kind 6\) struct A \(.*
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/diag-parlabel.d b/ld/testsuite/ld-ctf/diag-parlabel.d
index 5ad58706b0e..bba161cf309 100644
--- a/ld/testsuite/ld-ctf/diag-parlabel.d
+++ b/ld/testsuite/ld-ctf/diag-parlabel.d
@@ -20,7 +20,7 @@ Contents of CTF section .ctf:
   Labels:
 
   Data objects:
-    a -> 0x[0-9a-f]*: struct A \(size 0x[0-9a-f]*\)
+    a -> 0x[0-9a-f]*: \(kind 6\) struct A \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
 #...
   Function objects:
 
@@ -28,9 +28,8 @@ Contents of CTF section .ctf:
 
   Types:
 #...
-     0x[0-9a-f]*: struct A \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
+    0x[0-9a-f]*: \(kind 6\) struct A \(.*
+        *\[0x0\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
index 8fc1cc883da..668fa15bf49 100644
--- a/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
+++ b/ld/testsuite/ld-ctf/diag-wrong-magic-number-mixed.d
@@ -29,9 +29,9 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct B \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
+    0x[0-9a-f]*: struct B \(.*
+          *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B \(.*
+              *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct C \* c \(.*
 #...
   Strings:
     0x0: 
diff --git a/ld/testsuite/ld-ctf/enums.c b/ld/testsuite/ld-ctf/enums.c
new file mode 100644
index 00000000000..b7c55870cd3
--- /dev/null
+++ b/ld/testsuite/ld-ctf/enums.c
@@ -0,0 +1,3 @@
+enum nine_els { NINE_ONE, NINE_TWO, NINE_THREE = 256, NINE_FOUR, NINE_FIVE, NINE_SIX, NINE_SEVEN, NINE_EIGHT, NINE_NINE } nine;
+enum ten_els { TEN_ONE = 10, TEN_TWO, TEN_THREE = -256, TEN_FOUR, TEN_FIVE, TEN_SIX, TEN_SEVEN, TEN_EIGHT, TEN_NINE, TEN_TEN } ten;
+enum eleven_els { ELEVEN_ONE = 10, ELEVEN_TWO, ELEVEN_THREE = -256, ELEVEN_FOUR, ELEVEN_FIVE, ELEVEN_SIX, ELEVEN_SEVEN, ELEVEN_EIGHT, ELEVEN_NINE, ELEVEN_TEN, ELEVEN_ELEVEN } eleven;
diff --git a/ld/testsuite/ld-ctf/enums.d b/ld/testsuite/ld-ctf/enums.d
new file mode 100644
index 00000000000..f1cf70de5af
--- /dev/null
+++ b/ld/testsuite/ld-ctf/enums.d
@@ -0,0 +1,54 @@
+#as:
+#source: enums.c
+#objdump: --ctf=.ctf
+#ld: -shared
+#name: Enumerated types
+
+.*: +file format .*
+
+Contents of CTF section .ctf:
+
+  Header:
+    Magic number: 0xdff2
+    Version: 4 \(CTF_VERSION_3\)
+#...
+    Compilation unit name: .*enums.c
+#...
+    Type section:	.*\(0x114 bytes\)
+#...
+  Types:
+    0x1: \(kind 8\) enum nine_els \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+         NINE_ONE: 0
+         NINE_TWO: 1
+         NINE_THREE: 256
+         NINE_FOUR: 257
+         NINE_FIVE: 258
+         NINE_SIX: 259
+         NINE_SEVEN: 260
+         NINE_EIGHT: 261
+         NINE_NINE: 262
+    0x2: \(kind 8\) enum ten_els \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+         TEN_ONE: 10
+         TEN_TWO: 11
+         TEN_THREE: -256
+         TEN_FOUR: -255
+         TEN_FIVE: -254
+         TEN_SIX: -253
+         TEN_SEVEN: -252
+         TEN_EIGHT: -251
+         TEN_NINE: -250
+         TEN_TEN: -249
+    0x3: \(kind 8\) enum eleven_els \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+         ELEVEN_ONE: 10
+         ELEVEN_TWO: 11
+         ELEVEN_THREE: -256
+         ELEVEN_FOUR: -255
+         ELEVEN_FIVE: -254
+         \.\.\.
+         ELEVEN_SEVEN: -252
+         ELEVEN_EIGHT: -251
+         ELEVEN_NINE: -250
+         ELEVEN_TEN: -249
+         ELEVEN_ELEVEN: -248
+
+#...
diff --git a/ld/testsuite/ld-ctf/forward.d b/ld/testsuite/ld-ctf/forward.d
index 9ff0dd2ba73..bb929612125 100644
--- a/ld/testsuite/ld-ctf/forward.d
+++ b/ld/testsuite/ld-ctf/forward.d
@@ -16,8 +16,6 @@ Contents of CTF section .ctf:
 #...
   Types:
 
-     0x[0-9a-f]: struct foo
-          *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct foo
-     0x[0-9a-f]: struct foo \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]: struct foo
-          *\[0x0\] \(ID 0x[0-9a-f]\) \(kind 3\) struct foo \* \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]: \(kind 9\) struct foo
+    0x[0-9a-f]: \(kind 3\) struct foo \* \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]: \(kind 9\) struct foo
 #...
diff --git a/ld/testsuite/ld-ctf/function.d b/ld/testsuite/ld-ctf/function.d
index 9bf26a48928..1584bdbedfd 100644
--- a/ld/testsuite/ld-ctf/function.d
+++ b/ld/testsuite/ld-ctf/function.d
@@ -18,10 +18,9 @@ Contents of CTF section .ctf:
     String section:	.*
 #...
   Function objects:
-    foo -> 0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\)
+    foo -> 0x[0-9a-f]*: \(kind 5\) int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
 #...
   Types:
 #...
-     0x[0-9a-f]*: int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 5\) int \(\*\) \(char, int[0-9]*, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
+    0x[0-9a-f]*: \(kind 5\) int \(\*\) \(char, int, float, void \*, void \(\*\)\(\*\) \(int\)\) \(aligned at 0x[0-9a-f]*\)
 #...
diff --git a/ld/testsuite/ld-ctf/slice.d b/ld/testsuite/ld-ctf/slice.d
index 3967a2db537..d1167828f47 100644
--- a/ld/testsuite/ld-ctf/slice.d
+++ b/ld/testsuite/ld-ctf/slice.d
@@ -19,14 +19,14 @@ Contents of CTF section .ctf:
     String section:	.*
 #...
   Data objects:
-    slices -> 0x[0-9a-f]*: struct slices \(size 0x[0-9a-f]*\)
+    slices -> 0x[0-9a-f]*: \(kind 6\) struct slices \(size 0x[0-9a-f]*\) \(aligned at 0x1*\)
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct slices \(size 0x[0-9a-f]*\)
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct slices \(aligned at 0x1\)
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  one:1 \(aligned at 0x1, format 0x1, offset:bits 0x0:0x1\)
-               *\[0x1\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  two:2 \(aligned at 0x1, format 0x1, offset:bits 0x1:0x2\)
-               *\[0x3\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  six:6 \(aligned at 0x1, format 0x1, offset:bits 0x3:0x6\)
-               *\[0x9\] \(ID 0x[0-9a-f]*\) \(kind 1\) int  ten:10 \(aligned at 0x2, format 0x1, offset:bits 0x9:0xa\)
+    0x[0-9a-f]*: \(kind 6\) struct slices \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\)
+        *\[0x0\] one: ID 0x[0-9a-f]*: \(kind 1\) int:1 \[slice 0x0:0x1\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
+        *\[0x1\] two: ID 0x[0-9a-f]*: \(kind 1\) int:2 \[slice 0x1:0x2\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
+        *\[0x3\] six: ID 0x[0-9a-f]*: \(kind 1\) int:6 \[slice 0x3:0x6\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
+        *\[0x9\] ten: ID 0x[0-9a-f]*: \(kind 1\) int:10 \[slice 0x9:0xa\] \(format 0x1\) \(size 0x2\) \(aligned at 0x2\)
+
 #...
diff --git a/ld/testsuite/ld-ctf/super-sub-cycles.d b/ld/testsuite/ld-ctf/super-sub-cycles.d
index 65a43a4de9c..67fa358bc54 100644
--- a/ld/testsuite/ld-ctf/super-sub-cycles.d
+++ b/ld/testsuite/ld-ctf/super-sub-cycles.d
@@ -18,18 +18,17 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct A \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct A \(.*
-               *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct B b \(.*
-                   *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C c \(.*
-                       *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct A \* a \(.*
-                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
-                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-                   *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct D d \(.*
-                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct B \* b \(.*
-               *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct X x \(.*
-                   *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Y y \(.*
-                       *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct Z z \(.*
-                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct Y \* y \(.*
-                           *\[0x[0-9a-f]*\] \(ID 0x[0-9a-f]*\) \(kind 3\) struct D \* d \(.*
+    0x[0-9a-f]: \(kind 6\) struct A \(.*
+         \[0x0\] b: ID 0x[0-9a-f]*: \(kind 6\) struct B \(.*
+             \[0x0\] c: ID 0x[0-9a-f]*: \(kind 6\) struct C \(.*
+                 \[0x0\] a: ID 0x[0-9a-f]*: \(kind 3\) struct A \* \(.*
+                 \[0x[0-9a-f]*\] d: ID 0x[0-9a-f]*: \(kind 6\) struct D \(.*
+                     \[0x[0-9a-f]*\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
+             \[0x[0-9a-f]*\] d: ID 0x[0-9a-f]*: \(kind 6\) struct D \(.*
+                 \[0x[0-9a-f]*\] b: ID 0x[0-9a-f]*: \(kind 3\) struct B \* \(.*
+         \[0x[0-9a-f]*\] x: ID 0x[0-9a-f]*: \(kind 6\) struct X \(.*
+             \[0x[0-9a-f]*\] y: ID 0x[0-9a-f]*: \(kind 6\) struct Y \(.*
+                 \[0x[0-9a-f]*\] z: ID 0x[0-9a-f]*: \(kind 6\) struct Z \(.*
+                     \[0x[0-9a-f]*\] y: ID 0x[0-9a-f]*: \(kind 3\) struct Y \* \(.*
+                     \[0x[0-9a-f]*\] d: ID 0x[0-9a-f]*: \(kind 3\) struct D \* \(.*
 #...
diff --git a/libctf/ctf-decl.c b/libctf/ctf-decl.c
index f3939ea143d..2c1ca85d7d4 100644
--- a/libctf/ctf-decl.c
+++ b/libctf/ctf-decl.c
@@ -117,9 +117,10 @@ ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type)
       break;
 
     case CTF_K_SLICE:
+      /* Slices themselves have no print representation and should not appear in
+	 the decl stack.  */
       ctf_decl_push (cd, fp, ctf_type_reference (fp, type));
-      prec = CTF_PREC_BASE;
-      break;
+      return;
 
     case CTF_K_VOLATILE:
     case CTF_K_CONST:
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index a49f39e4569..07b6f38b17b 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -47,7 +47,7 @@ typedef struct ctf_dump_membstate
 {
   char **cdm_str;
   ctf_dict_t *cdm_fp;
-  char *cdm_toplevel_indent;
+  const char *cdm_toplevel_indent;
 } ctf_dump_membstate_t;
 
 static int
@@ -80,8 +80,12 @@ ctf_dump_free (ctf_dump_state_t *state)
     }
 }
 
-/* Return a dump for a single type, without member info: but do show the
-   type's references.  */
+/* Return a dump for a single type, without member info: but do optionally show
+   the type's references.  */
+
+#define CTF_FT_REFS     0x2 	/* Print referenced types.  */
+#define CTF_FT_BITFIELD 0x4	/* Print :BITS if a bitfield.  */
+#define CTF_FT_ID       0x8	/* Print "ID: " in front of type IDs.  */
 
 static char *
 ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
@@ -89,14 +93,16 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
   ctf_id_t new_id;
   char *str = NULL, *bit = NULL, *buf = NULL;
 
+  ctf_set_errno (fp, 0);
   new_id = id;
   do
     {
-      ctf_encoding_t enc;
+      ctf_encoding_t ep;
       ctf_arinfo_t ar;
       int kind, unsliced_kind;
       const char *nonroot_leader = "";
       const char *nonroot_trailer = "";
+      const char *idstr = "";
 
       id = new_id;
       if (flag == CTF_ADD_NONROOT)
@@ -110,15 +116,18 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 	{
 	  if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
 	    {
+	      ctf_set_errno (fp, ECTF_NONREPRESENTABLE);
 	      str = str_append (str, " (type not represented in CTF)");
-	      ctf_set_errno (fp, ECTF_NOTREF);
-	      break;
+	      return str;
 	    }
 
 	  goto err;
 	}
 
-      if (asprintf (&bit, " %s0x%lx: ", nonroot_leader, id) < 0)
+      if (flag & CTF_FT_ID)
+	idstr = "ID ";
+      if (asprintf (&bit, "%s%s0x%lx: (kind %i) ", nonroot_leader, idstr,
+		    id, ctf_type_kind (fp, id)) < 0)
 	goto oom;
       str = str_append (str, bit);
       free (bit);
@@ -129,37 +138,74 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 
       free (buf);
       buf = NULL;
+
       unsliced_kind = ctf_type_kind_unsliced (fp, id);
       kind = ctf_type_kind (fp, id);
 
-      /* Slices get a different print representation.  */
-      if (unsliced_kind == CTF_K_SLICE)
+      if (ctf_type_encoding (fp, id, &ep) == 0)
 	{
-	  ctf_type_encoding (fp, id, &enc);
-	  if (asprintf (&bit, " [slice 0x%x:0x%x]",
-			enc.cte_offset, enc.cte_bits) < 0)
+	  if (ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
+	      && flag & CTF_FT_BITFIELD)
+	    {
+	      if (asprintf (&bit, ":%i", ep.cte_bits) < 0)
+		goto oom;
+	      str = str_append (str, bit);
+	      free (bit);
+	      bit = NULL;
+	    }
+
+	  if (ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
+	      || ep.cte_offset != 0)
+	    {
+	      const char *slice = "";
+
+	      if (unsliced_kind == CTF_K_SLICE)
+		slice = "slice ";
+
+	      if (asprintf (&bit, " [%s0x%x:0x%x]",
+			    slice, ep.cte_offset, ep.cte_bits) < 0)
+		goto oom;
+	      str = str_append (str, bit);
+	      free (bit);
+	      bit = NULL;
+	    }
+
+	  if (asprintf (&bit, " (format 0x%x)", ep.cte_format) < 0)
 	    goto oom;
+	  str = str_append (str, bit);
+	  free (bit);
+	  bit = NULL;
 	}
-      else if (kind == CTF_K_INTEGER)
+
+      if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
 	{
-	  ctf_type_encoding (fp, id, &enc);
-	  if (asprintf (&bit, " [0x%x:0x%x]",
-			enc.cte_offset, enc.cte_bits) < 0)
+	  if (asprintf (&bit, " (size 0x%lx)",
+			(unsigned long) ctf_type_size (fp, id)) < 0)
 	    goto oom;
+
+	  str = str_append (str, bit);
+	  free (bit);
+	  bit = NULL;
 	}
-      str = str_append (str, bit);
-      free (bit);
-      bit = NULL;
 
-      if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
-	if (asprintf (&bit, " (size 0x%lx)%s",
-		      (unsigned long) ctf_type_size (fp, id),
-		      nonroot_trailer) < 0)
-	  goto oom;
+      if (kind != CTF_K_FORWARD)
+	{
+	  if (asprintf (&bit, " (aligned at 0x%lx)",
+			(unsigned long) ctf_type_align (fp, id)) < 0)
+	    goto oom;
 
-      str = str_append (str, bit);
-      free (bit);
-      bit = NULL;
+	  str = str_append (str, bit);
+	  free (bit);
+	  bit = NULL;
+	}
+
+      if (nonroot_trailer[0] != 0)
+	str = str_append (str, nonroot_trailer);
+
+      /* Just exit after one iteration if we are not showing the types this type
+	 references.  */
+      if (!(flag & CTF_FT_REFS))
+	return str;
 
       /* Keep going as long as this type references another.  We consider arrays
 	 to "reference" their element type. */
@@ -173,7 +219,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       else
 	new_id = ctf_type_reference (fp, id);
       if (new_id != CTF_ERR)
-	str = str_append (str, " ->");
+	str = str_append (str, " -> ");
     } while (new_id != CTF_ERR);
 
   if (ctf_errno (fp) != ECTF_NOTREF)
@@ -363,7 +409,7 @@ ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
     return (ctf_set_errno (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
-				       CTF_ADD_ROOT)) == NULL)
+				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
     {
       free (str);
       return 0;				/* Swallow the error.  */
@@ -400,14 +446,14 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
 	 has a leading one.   */
       if (name)
 	{
-	  if (asprintf (&str, "%s ->", name) < 0)
+	  if (asprintf (&str, "%s -> ", name) < 0)
 	    goto oom;
 	}
       else
 	str = xstrdup ("");
 
       if ((typestr = ctf_dump_format_type (state->cds_fp, id,
-					   CTF_ADD_ROOT)) == NULL)
+					   CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
 	{
 	  ctf_dump_append (state, str);
 	  continue;				/* Swallow the error.  */
@@ -438,7 +484,7 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
     return (ctf_set_errno (state->cds_fp, errno));
 
   if ((typestr = ctf_dump_format_type (state->cds_fp, type,
-				       CTF_ADD_ROOT)) == NULL)
+				       CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
     {
       free (str);
       return 0;			/* Swallow the error.  */
@@ -451,22 +497,7 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   return 0;
 }
 
-/* Report the number of digits in the hexadecimal representation of a type
-   ID.  */
-
-static int
-type_hex_digits (ctf_id_t id)
-{
-  int i = 0;
-
-  if (id == 0)
-    return 1;
-
-  for (; id > 0; id >>= 4, i++);
-  return i;
-}
-
-/* Dump a single member into the string in the membstate.  */
+/* Dump a single struct/union member into the string in the membstate.  */
 static int
 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
 		 int depth, void *arg)
@@ -474,72 +505,23 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   ctf_dump_membstate_t *state = arg;
   char *typestr = NULL;
   char *bit = NULL;
-  ctf_encoding_t ep;
-  int has_encoding = 0;
-  int opened_paren = 0;
-
-  /* Align neatly.  */
 
+  /* The struct/union itself has already been printed.  */
   if (depth == 0)
-    {
-      if (asprintf (&state->cdm_toplevel_indent, "     %*s",
-		    type_hex_digits (id), "") < 0)
-	goto oom;
-    }
+    return 0;
 
-  if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, depth * 4, "") < 0)
+  if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, (depth-1)*4, "") < 0)
     goto oom;
   *state->cdm_str = str_append (*state->cdm_str, bit);
   free (bit);
 
-  if ((typestr = ctf_type_aname (state->cdm_fp, id)) == NULL)
-    {
-      if (id == 0 || ctf_errno (state->cdm_fp) == ECTF_NONREPRESENTABLE)
-	{
-	  if (asprintf (&bit, "[0x%lx] (type not represented in CTF)",
-			offset) < 0)
-	    goto oom;
-
-	  *state->cdm_str = str_append (*state->cdm_str, bit);
-	  free (typestr);
-	  free (bit);
-	  return 0;
-	}
+  if ((typestr = ctf_dump_format_type (state->cdm_fp, id,
+				       CTF_ADD_ROOT | CTF_FT_BITFIELD
+				       | CTF_FT_ID)) == NULL)
+    return -1;				/* errno is set for us.  */
 
-      return -1;				/* errno is set for us.  */
-    }
-
-  if (ctf_type_encoding (state->cdm_fp, id, &ep) == 0)
-    {
-      has_encoding = 1;
-      ctf_type_encoding (state->cdm_fp, id, &ep);
-
-      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s:%i "
-		    "(aligned at 0x%lx", offset, id,
-		    ctf_type_kind (state->cdm_fp, id), typestr,
-		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
-		    ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
-								 id)) < 0)
-	goto oom;
-      opened_paren = 1;
-    }
-  else if (ctf_type_kind (state->cdm_fp, id) != CTF_K_FORWARD)
-    {
-      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
-		    "(aligned at 0x%lx", offset, id,
-		    ctf_type_kind (state->cdm_fp, id), typestr,
-		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
-		    (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
-	goto oom;
-      opened_paren = 1;
-    }
-  else /* Forwards have no alignment.  */
-    {
-      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s\n", offset, id,
-		    ctf_type_kind (state->cdm_fp, id), typestr,
-		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name) < 0)
-	goto oom;
-    }
+  if (asprintf (&bit, "[0x%lx] %s: %s\n", offset, name, typestr) < 0)
+    goto oom;
 
   *state->cdm_str = str_append (*state->cdm_str, bit);
   free (typestr);
@@ -547,18 +529,6 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   typestr = NULL;
   bit = NULL;
 
-  if (has_encoding)
-    {
-      if (asprintf (&bit, ", format 0x%x, offset:bits 0x%x:0x%x", ep.cte_format,
-		    ep.cte_offset, ep.cte_bits) < 0)
-	goto oom;
-      *state->cdm_str = str_append (*state->cdm_str, bit);
-      free (bit);
-      bit = NULL;
-    }
-
-  if (opened_paren)
-    *state->cdm_str = str_append (*state->cdm_str, ")\n");
   return 0;
 
  oom:
@@ -567,44 +537,112 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   return (ctf_set_errno (state->cdm_fp, errno));
 }
 
+/* Report the number of digits in the hexadecimal representation of a type
+   ID.  */
+
+static int
+type_hex_digits (ctf_id_t id)
+{
+  int i = 0;
+
+  if (id == 0)
+    return 1;
+
+  for (; id > 0; id >>= 4, i++);
+  return i;
+}
+
 /* Dump a single type into the cds_items.  */
 static int
 ctf_dump_type (ctf_id_t id, int flag, void *arg)
 {
   char *str;
+  char *indent;
+  int err = 0;
   ctf_dump_state_t *state = arg;
   ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
-  size_t len;
 
-  if ((str = ctf_dump_format_type (state->cds_fp, id, flag)) == NULL)
-    goto err;
+  /* Indent neatly.  */
+  if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
+    return (ctf_set_errno (state->cds_fp, ENOMEM));
 
+  /* Dump the type itself.  */
+  if ((str = ctf_dump_format_type (state->cds_fp, id,
+				   flag | CTF_FT_REFS)) == NULL)
+    goto err;
   str = str_append (str, "\n");
-  if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
+
+  membstate.cdm_toplevel_indent = indent;
+
+  /* Member dumping for structs, unions...  */
+  if (ctf_type_kind (state->cds_fp, id) == CTF_K_STRUCT
+      || ctf_type_kind (state->cds_fp, id) == CTF_K_UNION)
     {
-      if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
+      if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
 	{
-	  ctf_dump_append (state, str);
-	  return 0;
+	  if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
+	    {
+	      ctf_dump_append (state, str);
+	      return 0;
+	    }
+	  ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
+			_("cannot visit members dumping type 0x%lx"), id);
+	  goto err;
 	}
-      ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
-		    _("cannot visit members dumping type 0x%lx"), id);
-      goto err;
     }
-  free (membstate.cdm_toplevel_indent);
 
-  /* Trim off the last linefeed added by ctf_dump_member().  */
-  len = strlen (str);
-  if (str[len-1] == '\n')
-    str[len-1] = '\0';
+  /* ... and enums, for which we dump the first and last few members and skip
+     the ones in the middle.  */
+  if (ctf_type_kind (state->cds_fp, id) == CTF_K_ENUM)
+    {
+      int enum_count = ctf_member_count (state->cds_fp, id);
+      ctf_next_t *it = NULL;
+      int i = 0;
+      const char *enumerand;
+      char *bit;
+      int value;
+
+      while ((enumerand = ctf_enum_next (state->cds_fp, id,
+					 &it, &value)) != NULL)
+	{
+	  i++;
+	  if ((i > 5) && (i < enum_count - 4))
+	    continue;
+
+	  str = str_append (str, indent);
+
+	  if (asprintf (&bit, "%s: %i\n", enumerand, value) < 0)
+	    {
+	      err = ENOMEM;
+	      ctf_next_destroy (it);
+	      goto err;
+	    }
+	  str = str_append (str, bit);
+	  free (bit);
+
+	  if ((i == 5) && (enum_count > 10))
+	    {
+	      str = str_append (str, indent);
+	      str = str_append (str, "...\n");
+	    }
+	}
+      if (ctf_errno (state->cds_fp) != ECTF_NEXT_END)
+	{
+	  ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
+			_("cannot visit enumerands dumping type 0x%lx"), id);
+	  goto err;
+	}
+    }
 
   ctf_dump_append (state, str);
+  free (indent);
+
   return 0;
 
  err:
-  free (membstate.cdm_toplevel_indent);
+  free (indent);
   free (str);
-  return 0;				/* Swallow the error.  */
+  return ctf_set_errno (state->cds_fp, err);
 }
 
 /* Dump the string table into the cds_items.  */
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 9483930f40c..6f40f40b086 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -826,10 +826,6 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 	    case CTF_K_RESTRICT:
 	      ctf_decl_sprintf (&cd, "restrict");
 	      break;
-	    case CTF_K_SLICE:
-	      /* No representation: just changes encoding of contained type,
-		 which is not in any case printed.  Skip it.  */
-	      break;
 	    }
 
 	  k = cdp->cd_kind;
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH REVIEW 06/13] libctf: rip out BFD_DEPENDENCIES / BFD_LIBADD
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (4 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 05/13] libctf, ld: dump enums: generally improve dump formatting Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH REVIEW 07/13] libctf: new testsuite Nick Alcock
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

This complex morass inherited from libopcodes, which endeavours to
implement the effect of specifying ../bfd/libbfd.la in _LIBADD without
actually doing so, appears to be working around a libtool bug which as
far as I can see is no longer present (i.e., the install directory no
longer appears in -L arguments in libtool link-mode invocations, so
there is no danger of picking up old libbfds or other dependent
libraries).

Replaced with a simple reference to libbfd.la in the appropriate place.
Also adjusted things a little more so that libctf.la and libctf-nobfd.la
are self-contained, even when linking statically.  This opens up the
possibility of running libtool to link against libctf from inside the
(upcoming) testsuite.

libctf/ChangeLog
2020-12-09  Nick Alcock  <nick.alcock@oracle.com>

	* configure.ac (BFD_LIBADD): Remove.
	(BFD_DEPENDENCIES): Likewise. Remove associated cases.
	(SHARED_LIBADD): Rename to...
	(CTF_LIBADD): ... this.  Stick in a suitable libiberty even when
	linking statically.
	* Makefile.am (libctf_nobfd_la_LIBADD): Adjust accordingly.
	libctf uses libintl.
	(libctf_la_LIBADD): Reference libbfd.la directly, not via
	BFD_LIBADD.
	(libctf_la_DEPENDENCIES): Remove.
	* Makefile.in: Regenerate.
	* configure: Likewise.
---
 libctf/Makefile.am  |  5 ++---
 libctf/Makefile.in  | 15 +++++++--------
 libctf/configure    | 36 +++++++-----------------------------
 libctf/configure.ac | 30 +++++-------------------------
 4 files changed, 21 insertions(+), 65 deletions(-)

The REVIEW flag here is simply because if anyone knows of some weird
platform on which this _DEPENDENCIES dance is necessary, I'd be happy
to know of it.  Daniel Jacobowitz introduced the original kludge back
in 2004, in (what is now) commit 3ba7a1aacf86.

If there is no reason for it, we should probably take it out of
libopcodes too.

diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index fc1f229a4b4..a0d6cae2881 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -39,7 +39,7 @@ include_HEADERS =
 noinst_LTLIBRARIES = libctf.la libctf-nobfd.la
 endif
 
-libctf_nobfd_la_LIBADD = @SHARED_LIBADD@ $(ZLIB)
+libctf_nobfd_la_LIBADD = @CTF_LIBADD@ $(LIBINTL) $(ZLIB)
 libctf_nobfd_la_LDFLAGS = -version-info 0:0:0 @SHARED_LDFLAGS@ @VERSION_FLAGS@
 libctf_nobfd_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=1
 libctf_nobfd_la_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
@@ -50,8 +50,7 @@ if NEED_CTF_QSORT_R
 libctf_nobfd_la_SOURCES += ctf-qsort_r.c
 endif
 
-libctf_la_LIBADD = @BFD_LIBADD@ $(libctf_nobfd_la_LIBADD)
+libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
-libctf_la_DEPENDENCIES = @BFD_DEPENDENCIES@
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index 23b83b234cb..8037beaf16c 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -163,7 +163,8 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
-libctf_nobfd_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+libctf_nobfd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
 am__libctf_nobfd_la_SOURCES_DIST = ctf-archive.c ctf-dump.c \
 	ctf-create.c ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c \
 	ctf-dedup.c ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c \
@@ -189,7 +190,8 @@ libctf_nobfd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	-o $@
 @INSTALL_LIBBFD_FALSE@am_libctf_nobfd_la_rpath =
 @INSTALL_LIBBFD_TRUE@am_libctf_nobfd_la_rpath = -rpath $(libdir)
-am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+libctf_la_DEPENDENCIES = ../bfd/libbfd.la $(am__DEPENDENCIES_2)
 am__libctf_la_SOURCES_DIST = ctf-archive.c ctf-dump.c ctf-create.c \
 	ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c ctf-dedup.c \
 	ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c ctf-string.c \
@@ -307,8 +309,6 @@ AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@
 AWK = @AWK@
-BFD_DEPENDENCIES = @BFD_DEPENDENCIES@
-BFD_LIBADD = @BFD_LIBADD@
 CATALOGS = @CATALOGS@
 CATOBJEXT = @CATOBJEXT@
 CC = @CC@
@@ -316,6 +316,7 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CTF_LIBADD = @CTF_LIBADD@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DEFS = @DEFS@
@@ -370,7 +371,6 @@ RANLIB = @RANLIB@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHARED_LDFLAGS = @SHARED_LDFLAGS@
-SHARED_LIBADD = @SHARED_LIBADD@
 SHELL = @SHELL@
 STRIP = @STRIP@
 USE_NLS = @USE_NLS@
@@ -453,16 +453,15 @@ AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @
 @INSTALL_LIBBFD_FALSE@include_HEADERS = 
 @INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/ctf.h $(INCDIR)/ctf-api.h
 @INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libctf.la libctf-nobfd.la
-libctf_nobfd_la_LIBADD = @SHARED_LIBADD@ $(ZLIB)
+libctf_nobfd_la_LIBADD = @CTF_LIBADD@ $(LIBINTL) $(ZLIB)
 libctf_nobfd_la_LDFLAGS = -version-info 0:0:0 @SHARED_LDFLAGS@ @VERSION_FLAGS@
 libctf_nobfd_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=1
 libctf_nobfd_la_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c \
 	ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c ctf-dedup.c \
 	ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c ctf-string.c \
 	ctf-subr.c ctf-types.c ctf-util.c $(am__append_1)
-libctf_la_LIBADD = @BFD_LIBADD@ $(libctf_nobfd_la_LIBADD)
+libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
-libctf_la_DEPENDENCIES = @BFD_DEPENDENCIES@
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
 all: config.h
diff --git a/libctf/configure b/libctf/configure
index b7ca7cd5003..718c646436f 100755
--- a/libctf/configure
+++ b/libctf/configure
@@ -636,9 +636,7 @@ am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
 VERSION_FLAGS
-BFD_DEPENDENCIES
-BFD_LIBADD
-SHARED_LIBADD
+CTF_LIBADD
 SHARED_LDFLAGS
 NEED_CTF_QSORT_R_FALSE
 NEED_CTF_QSORT_R_TRUE
@@ -11519,7 +11517,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11522 "configure"
+#line 11520 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11625,7 +11623,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11628 "configure"
+#line 11626 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13338,10 +13336,9 @@ $as_echo "#define HAVE_O_CLOEXEC 1" >>confdefs.h
 fi
 
 # Horrible hacks to build DLLs on Windows and a shared library elsewhere.
-SHARED_LIBADD=
+
+CTF_LIBADD="-L`pwd`/../libiberty -liberty"
 SHARED_LDFLAGS=
-BFD_LIBADD=
-BFD_DEPENDENCIES=
 if test "$enable_shared" = "yes"; then
 # When building a shared libctf, link against the pic version of libiberty
 # so that apps that use libctf won't need libiberty just to satisfy any
@@ -13353,39 +13350,20 @@ if test "$enable_shared" = "yes"; then
 # since libbfd may not pull in the entirety of libiberty.
   x=`sed -n -e 's/^[ 	]*PICFLAG[ 	]*=[ 	]*//p' < ../libiberty/Makefile | sed -n '$p'`
   if test -n "$x"; then
-    SHARED_LIBADD="-L`pwd`/../libiberty/pic -liberty"
+    CTF_LIBADD="-L`pwd`/../libiberty/pic -liberty"
   fi
 
   case "${host}" in
   # More hacks to build DLLs on Windows.
     *-*-cygwin*)
       SHARED_LDFLAGS="-no-undefined"
-      SHARED_LIBADD="-L`pwd`/../libiberty -liberty -L`pwd`/../intl -lintl -lcygwin"
-      BFD_LIBADD="-L`pwd`/../bfd -lbfd"
-      ;;
-
-    *-*-darwin*)
-      BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.dylib"
-      BFD_DEPENDENCIES="../bfd/libbfd.la"
-      ;;
-    *)
-      case "$host_vendor" in
-	hp)
-	  BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.sl"
-	  ;;
-	*)
-	  BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.so"
-	  ;;
-      esac
-      BFD_DEPENDENCIES="../bfd/libbfd.la"
+      CTF_LIBADD="$CTF_LIBADD -L`pwd`/../intl -lintl -lcygwin"
       ;;
   esac
 fi
 
 
 
-
-
 # Use a version script, if possible, or an -export-symbols-regex otherwise.
 VERSION_FLAGS='-export-symbols-regex ctf_.*'
 if $LD --help 2>&1 | grep -- --version-script >/dev/null; then
diff --git a/libctf/configure.ac b/libctf/configure.ac
index 575da4677f3..3d774a62453 100644
--- a/libctf/configure.ac
+++ b/libctf/configure.ac
@@ -169,10 +169,9 @@ if test $ac_cv_libctf_macro_O_CLOEXEC = yes; then
 fi
 
 # Horrible hacks to build DLLs on Windows and a shared library elsewhere.
-SHARED_LIBADD=
+
+CTF_LIBADD="-L`pwd`/../libiberty -liberty"
 SHARED_LDFLAGS=
-BFD_LIBADD=
-BFD_DEPENDENCIES=
 if test "$enable_shared" = "yes"; then
 # When building a shared libctf, link against the pic version of libiberty
 # so that apps that use libctf won't need libiberty just to satisfy any
@@ -186,38 +185,19 @@ changequote(,)dnl
   x=`sed -n -e 's/^[ 	]*PICFLAG[ 	]*=[ 	]*//p' < ../libiberty/Makefile | sed -n '$p'`
 changequote([,])dnl
   if test -n "$x"; then
-    SHARED_LIBADD="-L`pwd`/../libiberty/pic -liberty"
+    CTF_LIBADD="-L`pwd`/../libiberty/pic -liberty"
   fi
 
   case "${host}" in
   # More hacks to build DLLs on Windows.
     *-*-cygwin*)
       SHARED_LDFLAGS="-no-undefined"
-      SHARED_LIBADD="-L`pwd`/../libiberty -liberty -L`pwd`/../intl -lintl -lcygwin"
-      BFD_LIBADD="-L`pwd`/../bfd -lbfd"
-      ;;
-
-    *-*-darwin*)
-      BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.dylib"
-      BFD_DEPENDENCIES="../bfd/libbfd.la"
-      ;;
-    *)
-      case "$host_vendor" in
-	hp)
-	  BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.sl"
-	  ;;
-	*)
-	  BFD_LIBADD="-Wl,`pwd`/../bfd/.libs/libbfd.so"
-	  ;;
-      esac
-      BFD_DEPENDENCIES="../bfd/libbfd.la"
+      CTF_LIBADD="$CTF_LIBADD -L`pwd`/../intl -lintl -lcygwin"
       ;;
   esac
 fi
 AC_SUBST(SHARED_LDFLAGS)
-AC_SUBST(SHARED_LIBADD)
-AC_SUBST(BFD_LIBADD)
-AC_SUBST(BFD_DEPENDENCIES)
+AC_SUBST(CTF_LIBADD)
 
 # Use a version script, if possible, or an -export-symbols-regex otherwise.
 VERSION_FLAGS='-export-symbols-regex ctf_.*'
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH REVIEW 07/13] libctf: new testsuite
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (5 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH REVIEW 06/13] libctf: rip out BFD_DEPENDENCIES / BFD_LIBADD Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-29 11:52   ` [PATCH v2] " Nick Alcock
  2020-12-18 19:51 ` [PATCH 08/13] libctf: new test of enum lookups with the _next iterator Nick Alcock
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

This introduces a new lookup testsuite under libctf, which operates by
compiling (with libtool) a "lookup" .c file that uses libctf to analyze
some other program, then compiling some number of test object files with
CTF and optionally linking them together and running the lookup program
on the test object files (or linked test binary), before diffing the
result much as run_dump_test does.

This lets us test the portions of libctf that are not previously
testable, notably the portions that do lookup on linked output and
that create dynamic dictionaries and then do lookup on them before
writing them out, something that is not tested by the ld-ctf testsuite
because the linker never does this.

A single simple test testing the functionality of enum lookups is
included as an example (and a simple sanity test).

ChangeLog
2020-12-14  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.def (libctf): No longer no_check.  Checking depends on
	all-ld.
	* Makefile.in: Regenerated.

libctf/ChangeLog
2020-12-14  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.am (EXPECT): New.
	(RUNTEST): Likewise.
	(RUNTESTFLAGS): Likewise.
	(CC_FOR_TARGET): Likewise.
	(check-DEJAGNU): Likewise.
	(AUTOMAKE_OPTIONS): Add dejagnu.
	* Makefile.in: Regenerated.
	* testsuite/config/default.exp: New.
	* testsuite/lib/ctf-lib.exp: Likewise.
	* testsuite/libctf-lookup/enum.lk: New test.
	* testsuite/libctf-lookup/enum-ctf.c: New CTF input.
	* testsuite/libctf-lookup/enum.c: New lookup test.
	* testsuite/libctf-lookup/lookup.exp: New.
---
 ChangeLog                                 |   6 +
 Makefile.def                              |   4 +-
 Makefile.in                               |  13 +
 libctf/Makefile.am                        |  35 +-
 libctf/Makefile.in                        | 113 ++++--
 libctf/testsuite/config/default.exp       |  59 ++++
 libctf/testsuite/lib/ctf-lib.exp          | 409 ++++++++++++++++++++++
 libctf/testsuite/libctf-lookup/enum-ctf.c |   8 +
 libctf/testsuite/libctf-lookup/enum.c     |  78 +++++
 libctf/testsuite/libctf-lookup/enum.lk    |  10 +
 libctf/testsuite/libctf-lookup/lookup.exp |  43 +++
 11 files changed, 752 insertions(+), 26 deletions(-)
 create mode 100644 libctf/testsuite/config/default.exp
 create mode 100644 libctf/testsuite/lib/ctf-lib.exp
 create mode 100644 libctf/testsuite/libctf-lookup/enum-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum.lk
 create mode 100644 libctf/testsuite/libctf-lookup/lookup.exp

The top-level change that adjusts the Makefile.def needs perfunctory
review.  (And, as ever, I'm happy to have eyes on any of the rest!)

diff --git a/ChangeLog b/ChangeLog
index 4629d15a305..36d467c9c55 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2020-12-14  Nick Alcock  <nick.alcock@oracle.com>
+
+	* Makefile.def (libctf): No longer no_check.  Checking depends on
+	all-ld.
+	* Makefile.in: Regenerated.
+
 2020-12-16  Martin Liska  <mliska@suse.cz>
 	    Tom de Vries  <tdevries@suse.de>
 
diff --git a/Makefile.def b/Makefile.def
index 089e70ae3ed..cc429aa8628 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -131,8 +131,7 @@ host_modules= { module= lto-plugin; bootstrap=true;
 		extra_make_flags='@extra_linker_plugin_flags@'; };
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
 host_modules= { module= gotools; };
-host_modules= { module= libctf; no_check=true;
-		bootstrap=true; };
+host_modules= { module= libctf; bootstrap=true; };
 
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
@@ -547,6 +546,7 @@ dependencies = { module=configure-libctf; on=all-bfd; };
 dependencies = { module=configure-libctf; on=all-intl; };
 dependencies = { module=configure-libctf; on=all-zlib; };
 dependencies = { module=configure-libctf; on=all-libiconv; };
+dependencies = { module=check-libctf; on=all-ld; };
 
 // The Makefiles in gdb and gdbserver pull in a file that configure
 // generates in the gnulib directory, so distclean gnulib only after
diff --git a/Makefile.in b/Makefile.in
index fe34132f9e5..4fe7321786e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34761,6 +34761,12 @@ maybe-check-libctf:
 maybe-check-libctf: check-libctf
 
 check-libctf:
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) $(EXTRA_HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(FLAGS_TO_PASS)  $(EXTRA_BOOTSTRAP_FLAGS) check)
 
 @endif libctf
 
@@ -52366,6 +52372,13 @@ configure-stage3-libctf: maybe-all-stage3-libiconv
 configure-stage4-libctf: maybe-all-stage4-libiconv
 configure-stageprofile-libctf: maybe-all-stageprofile-libiconv
 configure-stagefeedback-libctf: maybe-all-stagefeedback-libiconv
+check-libctf: maybe-all-ld
+check-stage1-libctf: maybe-all-stage1-ld
+check-stage2-libctf: maybe-all-stage2-ld
+check-stage3-libctf: maybe-all-stage3-ld
+check-stage4-libctf: maybe-all-stage4-ld
+check-stageprofile-libctf: maybe-all-stageprofile-ld
+check-stagefeedback-libctf: maybe-all-stagefeedback-ld
 distclean-gnulib: maybe-distclean-gdb
 distclean-gnulib: maybe-distclean-gdbserver
 all-bison: maybe-all-build-texinfo
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index a0d6cae2881..3af31b28c95 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -19,7 +19,7 @@
 
 ACLOCAL_AMFLAGS = -I .. -I ../config -I ../bfd
 
-AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 
 # This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
 # -I../zlib, unless we were configured with --with-system-zlib, in which
@@ -54,3 +54,36 @@ libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS =
+
+CC_FOR_TARGET = ` \
+  if [ -f $$r/../gcc/xgcc ] ; then \
+    if [ -f $$r/../newlib/Makefile ] ; then \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/ -idirafter $$r/../newlib/targ-include -idirafter $${srcroot}/../newlib/libc/include -nostdinc; \
+    else \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/; \
+    fi; \
+  else \
+    if [ "@host@" = "@target@" ] ; then \
+      echo $(CC); \
+    else \
+      echo gcc | sed '$(transform)'; \
+    fi; \
+  fi`
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+		CC="$(CC_FOR_TARGET)" CFLAGS="$(CFLAGS) -I$(INCDIR) -I$(srcdir) -I$(builddir) -I$(builddir)/../bfd $(ZLIBINC)" \
+		CC_FOR_HOST="$(CC)" LIBS="$(LIBS)" $(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index 8037beaf16c..883b363b0cf 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -278,6 +278,8 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 AM_RECURSIVE_TARGETS = cscope
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
 	$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
 	$(top_srcdir)/../config.guess $(top_srcdir)/../config.sub \
@@ -439,7 +441,7 @@ warn = @warn@
 zlibdir = @zlibdir@
 zlibinc = @zlibinc@
 ACLOCAL_AMFLAGS = -I .. -I ../config -I ../bfd
-AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 
 # This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
 # -I../zlib, unless we were configured with --with-system-zlib, in which
@@ -464,6 +466,26 @@ libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS = 
+CC_FOR_TARGET = ` \
+  if [ -f $$r/../gcc/xgcc ] ; then \
+    if [ -f $$r/../newlib/Makefile ] ; then \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/ -idirafter $$r/../newlib/targ-include -idirafter $${srcroot}/../newlib/libc/include -nostdinc; \
+    else \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/; \
+    fi; \
+  else \
+    if [ "@host@" = "@target@" ] ; then \
+      echo $(CC); \
+    else \
+      echo gcc | sed '$(transform)'; \
+    fi; \
+  fi`
+
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -966,6 +988,36 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
+	@echo 'Making a new site.exp file ...'
+	@echo '## these variables are automatically generated by make ##' >site.tmp
+	@echo '# Do not edit here.  If you wish to override these values' >>site.tmp
+	@echo '# edit the last section' >>site.tmp
+	@echo 'set srcdir "$(srcdir)"' >>site.tmp
+	@echo "set objdir `pwd`" >>site.tmp
+	@echo 'set build_alias "$(build_alias)"' >>site.tmp
+	@echo 'set build_triplet $(build_triplet)' >>site.tmp
+	@echo 'set host_alias "$(host_alias)"' >>site.tmp
+	@echo 'set host_triplet $(host_triplet)' >>site.tmp
+	@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
+	  echo "## Begin content included from file $$f.  Do not modify. ##" \
+	   && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
+	   && echo "## End content included from file $$f. ##" \
+	   || exit 1; \
+	 done >> site.tmp
+	@echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
+	@if test -f site.exp; then \
+	   sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
+	 fi
+	@-rm -f site.bak
+	@test ! -f site.exp || mv site.exp site.bak
+	@mv site.tmp site.exp
+
+distclean-DEJAGNU:
+	-rm -f site.exp site.bak
+	-l='$(DEJATOOL)'; for tool in $$l; do \
+	  rm -f $$tool.sum $$tool.log; \
+	done
 
 distdir: $(DISTFILES)
 	$(am__remove_distdir)
@@ -1131,6 +1183,7 @@ distcleancheck: distclean
 	       $(distcleancheck_listfiles) ; \
 	       exit 1; } >&2
 check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
 check: check-am
 all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
 installdirs:
@@ -1176,8 +1229,9 @@ distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
-	distclean-hdr distclean-libtool distclean-tags
+distclean-am: clean-am distclean-DEJAGNU distclean-compile \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-tags
 
 dvi: dvi-am
 
@@ -1241,30 +1295,43 @@ ps-am:
 
 uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
 
-.MAKE: all install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
-	clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
-	clean-noinstLTLIBRARIES cscope cscopelist-am ctags ctags-am \
-	dist dist-all dist-bzip2 dist-gzip dist-lzip dist-shar \
-	dist-tarZ dist-xz dist-zip distcheck distclean \
-	distclean-compile distclean-generic distclean-hdr \
-	distclean-libtool distclean-tags distcleancheck distdir \
-	distuninstallcheck dvi dvi-am html html-am info info-am \
-	install install-am install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-includeHEADERS install-info \
-	install-info-am install-libLTLIBRARIES install-man install-pdf \
-	install-pdf-am install-ps install-ps-am install-strip \
-	installcheck installcheck-am installdirs maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-compile \
-	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
-	uninstall-libLTLIBRARIES
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-DEJAGNU \
+	check-am clean clean-cscope clean-generic clean-libLTLIBRARIES \
+	clean-libtool clean-noinstLTLIBRARIES cscope cscopelist-am \
+	ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \
+	dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
+	distclean-DEJAGNU distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distcleancheck \
+	distdir distuninstallcheck dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-includeHEADERS \
+	install-info install-info-am install-libLTLIBRARIES \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-includeHEADERS uninstall-libLTLIBRARIES
 
 .PRECIOUS: Makefile
 
 
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+		CC="$(CC_FOR_TARGET)" CFLAGS="$(CFLAGS) -I$(INCDIR) -I$(srcdir) -I$(builddir) -I$(builddir)/../bfd $(ZLIBINC)" \
+		CC_FOR_HOST="$(CC)" LIBS="$(LIBS)" $(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libctf/testsuite/config/default.exp b/libctf/testsuite/config/default.exp
new file mode 100644
index 00000000000..ff231e0951a
--- /dev/null
+++ b/libctf/testsuite/config/default.exp
@@ -0,0 +1,59 @@
+# Basic expect script for libctf lookup tests
+#   Copyright (C) 1993-2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Written by Jeffrey Wheat (cassidy@cygnus.com)
+#
+
+if ![info exists ld] then {
+    set ld [findfile $base_dir/../ld/ld-new $base_dir/../ld/ld-new [transform ld]]
+}
+
+if ![info exists as] then {
+    set as [findfile $base_dir/../gas/as-new $base_dir/../gas/as-new [transform as]]
+}
+
+remote_exec host "mkdir -p tmpdir"
+
+# Make symlinks from tmpdir/libctf to the linker and assembler in the
+# build tree, so that we can use a -B option to gcc to force it to use
+# the newly built linker and assembler.
+if {![file isdirectory tmpdir/libctf]} then {
+    catch "exec mkdir tmpdir/libctf" status
+    catch "exec ln -s ../../../ld/ld-new tmpdir/libctf/ld" status
+    catch "exec ln -s ld tmpdir/libctf/collect-ld" status
+    catch "exec ln -s ../../../gas/as-new tmpdir/libctf/as" status
+}
+set gcc_B_opt "-B[pwd]/tmpdir/libctf/"
+
+# The "make check" target in the Makefile passes in
+# "CC=$(CC_FOR_TARGET)".  But, if the user invokes runtest directly,
+# these flags may not be set.
+if {![info exists CC]} {
+    set CC [find_gcc]
+}
+if {![info exists CC_FOR_HOST]} {
+    set CC_FOR_HOST $CC
+}
+if {![info exists CFLAGS]} {
+    set CFLAGS "-g -O2"
+}
+
+# load the utility procedures
+load_lib ctf-lib.exp
diff --git a/libctf/testsuite/lib/ctf-lib.exp b/libctf/testsuite/lib/ctf-lib.exp
new file mode 100644
index 00000000000..171c08d1805
--- /dev/null
+++ b/libctf/testsuite/lib/ctf-lib.exp
@@ -0,0 +1,409 @@
+# Support routines for libctf testsuite.
+#   Copyright (C) 1994-2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+proc load_common_lib { name } {
+    global srcdir
+    load_file $srcdir/../../binutils/testsuite/lib/$name
+}
+
+load_common_lib binutils-common.exp
+
+proc run_native_host_cmd { command } {
+    global link_output
+    global ld
+
+    verbose -log "$command"
+    set run_output ""
+    try {
+	set run_output [exec "sh" "-c" "$command" "2>@1"]
+	set status 0
+    } trap CHILDSTATUS {results options} {
+	set status [lindex [dict get $options -errorcode] 2]
+	set run_output $results
+    }
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+proc run_host_cmd { prog command } {
+    global link_output
+    global gcc_B_opt
+    global gcc_ld_B_opt_tested
+    global ld
+
+    if { ![is_remote host] && [which "$prog"] == 0 } then {
+	perror "$prog does not exist"
+	return 0
+    }
+
+    # If we are compiling with gcc, we want to add gcc_B_opt to flags.  However,
+    # if $prog already has -B options, which might be the case when running gcc
+    # out of a build directory, we want our -B options to come first.
+    set gccexe $prog
+    set gccparm [string first " " $gccexe]
+    set gccflags ""
+    if { $gccparm > 0 } then {
+	set gccflags [string range $gccexe $gccparm end]
+	set gccexe [string range $gccexe 0 $gccparm]
+	set prog $gccexe
+    }
+    set gccexe [string replace $gccexe 0 [string last "/" $gccexe] ""]
+    if {[string match "*cc*" $gccexe] || [string match "*++*" $gccexe]} then {
+	set gccflags "$gcc_B_opt $gccflags"
+	if {![info exists gcc_ld_B_opt_tested]} {
+	    set gcc_ld_B_opt_tested 1
+	    set ld_version_message [run_host_cmd "$ld" "--version"]
+	    set gcc_ld_version_message [run_host_cmd "$prog" "$gccflags -Wl,--version"]
+	    if {[string first $ld_version_message $gcc_ld_version_message] < 0} {
+		perror "************************************************************************"
+		perror "Your compiler driver ignores -B when choosing ld."
+		perror "You will not be testing the new ld in many of the following tests."
+		set gcc_ld_version [run_host_cmd "$prog" "$gccflags --print-prog-name=ld"]
+		if {![string match "" $gcc_ld_version] && ![string match "ld" $gcc_ld_version]} {
+		    perror "It seems you will be testing $gcc_ld_version instead."
+		}
+		perror "************************************************************************"
+	    }
+	}
+    }
+
+    verbose -log "$prog $gccflags $command"
+    set status [remote_exec host [concat sh -c [list "$prog $gccflags $command 2>&1"]] "" "/dev/null" "libctf.tmp"]
+    remote_upload host "libctf.tmp"
+    set run_output [file_contents "libctf.tmp"]
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+    remote_file build delete libctf.tmp
+    remote_file host delete libctf.tmp
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+proc run_host_cmd_yesno { prog command } {
+    global exec_output
+    global errcnt warncnt
+
+    set exec_output [prune_warnings [run_host_cmd "$prog" "$command"]]
+    # Ignore error and warning.
+    set errcnt 0
+    set warncnt 0
+    if [string match "" $exec_output] then {
+	return 1;
+    }
+    return 0;
+}
+
+# Return true if we can build a program with the compiler.
+# On some targets, CC might be defined, but libraries and startup
+# code might be missing or require special options that the ld test
+# harness doesn't know about.
+
+proc check_compiler_available { } {
+    global compiler_available_saved
+    global CC
+
+    if {![info exists compiler_available_saved]} {
+	if { [which $CC] == 0 } {
+	    set compiler_available_saved 0
+	    return 0
+	}
+
+	set flags ""
+	if [board_info [target_info name] exists cflags] {
+	    append flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append flags " [board_info [target_info name] ldflags]"
+	}
+
+	set basename "tmpdir/compiler[pid]"
+	set src ${basename}.c
+	set output ${basename}.out
+	set f [open $src "w"]
+	puts $f "int main (void)"
+	puts $f "{"
+	puts $f "  return 0; "
+	puts $f "}"
+	close $f
+	if [is_remote host] {
+	    set src [remote_download host $src]
+	}
+	set compiler_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+	remote_file host delete $src
+	remote_file host delete $output
+	file delete $src
+    }
+    return $compiler_available_saved
+}
+
+# Compile and link a C source file for execution on the host.
+proc compile_link_one_host_cc { src output additional_args } {
+    global CC_FOR_HOST
+    global CFLAGS
+
+    return [run_native_host_cmd "./libtool --quiet --tag=CC --mode=link $CC_FOR_HOST $CFLAGS $src -o $output $additional_args" ]
+}
+
+# Compile a C source file, with the specified additional_flags.
+proc compile_one_cc { src output additional_flags } {
+    global CC
+    global CFLAGS
+
+    set flags ""
+    if [board_info [target_info name] exists cflags] {
+	append flags " [board_info [target_info name] cflags]"
+    }
+    if [board_info [target_info name] exists ldflags] {
+	append flags " [board_info [target_info name] ldflags]"
+    }
+
+    if [is_remote host] {
+	set src [remote_download host $src]
+    }
+    return [run_host_cmd "$CC" "$flags $CFLAGS $additional_flags $src -o $output"]
+}
+
+# run_lookup_test FILE
+#
+# Compile with the host compiler and link a .c file into a "lookup" binary, then
+# compile and optionally link together a bunch of .s or .c files with CTF info
+# and pass the name of the resulting binary to the "lookup" binary and check the
+# output.  (If none is specified, the binary is expected to generate its own CTF
+# for testing purposes.)
+#
+# As with run_dump_test, this is all driven by a file (in this case, a .lk file)
+# beginning with zero or more option lines, which specify the names of the
+# lookup binary's source file, the source file(s) with CTF info to compile
+# together, and whether to link them.  The optional lines have the syntax:
+#
+#	# OPTION: VALUE
+#
+# OPTION is the name of some option, like "name" or "lookup", and
+# VALUE is OPTION's value.  The valid options are described below.
+# Whitespace is ignored everywhere, except within VALUE.  The option
+# list ends with the first line that doesn't match the above syntax.
+# However, a line within the options that begins with a #, but doesn't
+# have a recognizable option name followed by a colon, is considered a
+# comment and entirely ignored.
+#
+# The interesting options are:
+#
+#   name: TEST-NAME
+#	The name of this test, passed to DejaGNU's `pass' and `fail'
+#	commands.  If omitted, this defaults to FILE, the root of the
+#	lookup .c file's name.
+#
+#   lookup: SOURCE
+#	Compile the file SOURCE.c.  If omitted, the lookup source defaults
+#	to FILE.c.
+#
+#   source: SOURCE
+#	Assemble the file SOURCE.c and pass it to the LOOKUP program.
+#
+#   link:
+#	If set, link the SOURCE together even if only one file is specified.
+#
+#   link_flags:
+#	If set, extra flags to pass to the linker.
+#
+#   xfail: GLOB|PROC ...
+#	This test is expected to fail on a specified list of targets.
+#
+# Each option may occur at most once unless otherwise mentioned.
+#
+# After the option lines come regexp lines.  run_lookup_test calls
+# regexp_diff to compare the output of the lookup program against the
+# regexps in FILE.d.
+#
+proc run_lookup_test { name } {
+    global CC CFLAGS LIBS
+    global copyfile env runtests srcdir subdir verbose
+
+    if ![runtest_file_p $runtests $name] then {
+	return
+    }
+
+    if [string match "*/*" $name] {
+	set file $name
+	set name [file tail $name]
+    } else {
+	set file "$srcdir/$subdir/$name"
+    }
+
+    set opt_array [slurp_options "${file}.lk"]
+    if { $opt_array == -1 } {
+	perror "error reading options from $file.lk"
+	unresolved $subdir/$name
+	return
+    }
+    set run_ld 0
+    set opts(link) {}
+    set opts(link_flags) {}
+    set opts(lookup) {}
+    set opts(name) {}
+    set opts(source) {}
+    set opts(xfail) {}
+
+    foreach i $opt_array {
+	set opt_name [lindex $i 0]
+	set opt_val [lindex $i 1]
+	if { $opt_name == "" } {
+	    set in_extra 1
+	    continue
+	}
+	if ![info exists opts($opt_name)] {
+	    perror "unknown option $opt_name in file $file.lk"
+	    unresolved $subdir/$name
+	    return
+	}
+
+	set opts($opt_name) [concat $opts($opt_name) $opt_val]
+    }
+
+    if { [llength $opts(lookup)] == 0 } {
+	set opts(lookup) "$file.c"
+    } else {
+	set opts(lookup) "[file dirname $file]/$opts(lookup)"
+    }
+
+    if { [llength $opts(name)] == 0 } {
+	set opts(name) $opts(lookup)
+    }
+
+    if { [llength $opts(link)] != 0
+	 || [llength $opts(source)] > 1 } {
+	set run_ld 1
+    }
+
+    set testname $opts(name)
+    if { $opts(name) == "" } {
+	set testname "$subdir/$name"
+    }
+
+    # Compile and link the lookup program.
+    set comp_output [compile_link_one_host_cc $opts(lookup) "tmpdir/lookup" "libctf.la"]
+
+    if { $comp_output != ""} {
+	send_log "compilation of lookup program $opts(lookup) failed with <$comp_output>"
+	perror "compilation of lookup program $opts(lookup) failed"
+	fail $testname
+	return 0
+    }
+
+    # Compile the inputs and posibly link them together.
+
+    set lookup_output ""
+    if { [llength $opts(source)] > 0 } {
+	set lookup_flags ""
+	if { $run_ld } {
+	    set lookup_output "tmpdir/out.so"
+	    set lookup_flags "-gt -fPIC -shared $opts(link_flags)"
+	} else {
+	    set lookup_output "tmpdir/out.o"
+	    set lookup_flags "-gt -fPIC -c"
+	}
+	if [board_info [target_info name] exists cflags] {
+	    append lookup_flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append lookup_flags " [board_info [target_info name] ldflags]"
+	}
+	set src {}
+	foreach sfile $opts(source) {
+	    if [is_remote host] {
+		lappend src [remote_download host [file join [file dirname $file] $sfile]]
+	    } else {
+		lappend src [file join [file dirname $file] $sfile]
+	    }
+	}
+
+	set comp_output [run_host_cmd "$CC" "$CFLAGS $lookup_flags [concat $src] -o $lookup_output"]
+
+	if { $comp_output != ""} {
+	    send_log "compilation of CTF program [concat $src] failed with <$comp_output>"
+	    fail $testname
+	    return 0
+	}
+    }
+
+    # Time to setup xfailures.
+    foreach targ $opts(xfail) {
+	if [match_target $targ] {
+	    setup_xfail "*-*-*"
+	    break
+	}
+    }
+
+    # Invoke the lookup program on the outputs.
+
+    set results [run_host_cmd tmpdir/lookup $lookup_output]
+
+    set f [open "tmpdir/lookup.out" "w"]
+    puts $f $results
+    close $f
+
+    if { [regexp_diff "tmpdir/lookup.out" "${file}.lk"] } then {
+	fail $testname
+	if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/lookup.out]" 2 }
+	return 0
+    }
+
+    pass $testname
+    return 0
+}
+
+# Returns true if the target compiler supports -gt
+proc check_ctf_available { } {
+    global ctf_available_saved
+
+    if {![info exists ctf_available_saved]} {
+	if { ![check_compiler_available] } {
+	    set ctf_available_saved 0
+	} else {
+	    set basename "tmpdir/ctf_available[pid]"
+	    set src ${basename}.c
+	    set output ${basename}.o
+	    set f [open $src "w"]
+	    puts $f "int main() { return 0; }"
+	    close $f
+	    set ctf_available_saved [compile_one_cc $src $output "-gt -c"]
+	    remote_file host delete $src
+	    remote_file host delete $output
+	    file delete $src
+	}
+    }
+    return $ctf_available_saved
+}
diff --git a/libctf/testsuite/libctf-lookup/enum-ctf.c b/libctf/testsuite/libctf-lookup/enum-ctf.c
new file mode 100644
index 00000000000..aa60d72722e
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-ctf.c
@@ -0,0 +1,8 @@
+/* Looked up item by item. */
+enum e { ENUMSAMPLE_1 = 0, ENUMSAMPLE_2 = 1 };
+
+/* Looked up via both sorts of iterator in turn.  */
+enum ie { IENUMSAMPLE_1 = -10, IENUMSAMPLE_2, IENUMSAMPLE_3 };
+
+enum e foo;
+enum ie bar;
diff --git a/libctf/testsuite/libctf-lookup/enum.c b/libctf/testsuite/libctf-lookup/enum.c
new file mode 100644
index 00000000000..1804b23a69e
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum.c
@@ -0,0 +1,78 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+print_enum (const char *name, int val, void *unused)
+{
+  printf ("iter test: %s has value %i\n", name, val);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_id_t type;
+  const char *name;
+  ctf_next_t *i = NULL;
+  int val;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Try getting some enum values by hand.  */
+
+  if ((type = ctf_lookup_by_name (fp, "enum e") ) == CTF_ERR)
+    goto err;
+  if (ctf_enum_value (fp, type, "ENUMSAMPLE_1", &val) < 0)
+    goto err;
+  printf ("Enum e enumerand ENUMSAMPLE_1 has value %i\n", val);
+
+  if ((name = ctf_enum_name (fp, type, 1)) == NULL)
+    goto err;
+  printf ("Enum e enumerand %s has value 1\n", name);
+
+  /* Try getting some values using both sorts of iterator.  */
+
+  if ((type = ctf_lookup_by_name (fp, "enum ie") ) == CTF_ERR)
+    goto err;
+
+  if ((ctf_enum_iter (fp, type, print_enum, NULL)) < 0)
+    goto ierr;
+
+  while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)
+    {
+      printf ("next test: %s has value %i\n", name, val);
+    }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    goto nerr;
+
+  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;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ ierr:
+  fprintf (stderr, "_iter iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ nerr:
+  fprintf (stderr, "_next iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/enum.lk b/libctf/testsuite/libctf-lookup/enum.lk
new file mode 100644
index 00000000000..0b2b1571866
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum.lk
@@ -0,0 +1,10 @@
+# source: enum-ctf.c
+# link: on
+Enum e enumerand ENUMSAMPLE_1 has value 0
+Enum e enumerand ENUMSAMPLE_2 has value 1
+iter test: IENUMSAMPLE_1 has value -10
+iter test: IENUMSAMPLE_2 has value -9
+iter test: IENUMSAMPLE_3 has value -8
+next test: IENUMSAMPLE_1 has value -10
+next test: IENUMSAMPLE_2 has value -9
+next test: IENUMSAMPLE_3 has value -8
diff --git a/libctf/testsuite/libctf-lookup/lookup.exp b/libctf/testsuite/libctf-lookup/lookup.exp
new file mode 100644
index 00000000000..8908a37c17c
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/lookup.exp
@@ -0,0 +1,43 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if ![is_elf_format] {
+    unsupported "CTF needs bfd changes to be emitted on non-ELF"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach ctf_test $ctf_test_list {
+    verbose [file rootname $ctf_test]
+    verbose running lookup test on $ctf_test
+    run_lookup_test [file rootname $ctf_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 08/13] libctf: new test of enum lookups with the _next iterator
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (6 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH REVIEW 07/13] libctf: new testsuite Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 09/13] libctf: warn about information loss because of unreleased format changes Nick Alcock
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

I had reports that this doesn't work.  This test shows it working (and
also shows how annoying it is to do symbol lookup by name with the
present API: we need a ctf_arc_lookup_symbol_name for users that don't
already have a symtab handy).

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/libctf-lookup/enum-symbol.lk: New symbol-lookup test.
	* testsuite/libctf-lookup/enum-symbol-ctf.c: New CTF input.
	* testsuite/libctf-lookup/enum-symbol.c: New lookup test.
---
 .../testsuite/libctf-lookup/enum-symbol-ctf.c |   1 +
 libctf/testsuite/libctf-lookup/enum-symbol.c  | 153 ++++++++++++++++++
 libctf/testsuite/libctf-lookup/enum-symbol.lk |   6 +
 3 files changed, 160 insertions(+)
 create mode 100644 libctf/testsuite/libctf-lookup/enum-symbol-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum-symbol.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum-symbol.lk

diff --git a/libctf/testsuite/libctf-lookup/enum-symbol-ctf.c b/libctf/testsuite/libctf-lookup/enum-symbol-ctf.c
new file mode 100644
index 00000000000..f7f99c67c16
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-symbol-ctf.c
@@ -0,0 +1 @@
+enum {red1, green1, blue1} primary1;
diff --git a/libctf/testsuite/libctf-lookup/enum-symbol.c b/libctf/testsuite/libctf-lookup/enum-symbol.c
new file mode 100644
index 00000000000..4f63b61b803
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-symbol.c
@@ -0,0 +1,153 @@
+#include "config.h"
+#include <bfd.h>
+#include <elf.h>
+#include <ctf-api.h>
+#include <swap.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+ssize_t symidx_64 (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name)
+{
+  const char *strs = (const char *) strsect->cts_data;
+  size_t i;
+  Elf64_Sym *sym = (Elf64_Sym *) s->cts_data;
+  for (i = 0; i < s->cts_size / s->cts_entsize; i++, sym++)
+    {
+      Elf64_Word nameoff = sym->st_name;
+#ifdef WORDS_BIGENDIAN
+      if (little_endian)
+	swap_thing (nameoff);
+#else
+      if (!little_endian)
+	swap_thing (nameoff);
+#endif
+      if (strcmp (strs + nameoff, name) == 0)
+	return i;
+    }
+  return -1;
+}
+
+ssize_t symidx_32 (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name)
+{
+  const char *strs = (const char *) strsect->cts_data;
+  size_t i;
+  Elf32_Sym *sym = (Elf32_Sym *) s->cts_data;
+  for (i = 0; i < s->cts_size / s->cts_entsize; i++, sym++)
+    {
+      Elf32_Word nameoff = sym->st_name;
+#ifdef WORDS_BIGENDIAN
+      if (little_endian)
+	swap_thing (nameoff);
+#else
+      if (!little_endian)
+	swap_thing (nameoff);
+#endif
+      if (strcmp (strs + nameoff, name) == 0)
+	return i;
+    }
+  return -1;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  bfd *abfd;
+  ctf_archive_t *ctf;
+  ctf_sect_t symsect;
+  ctf_sect_t strsect;
+  ssize_t symidx;
+  int err;
+  ctf_id_t type;
+  ctf_next_t *i = NULL;
+  const char *name;
+  int val;
+  int little_endian;
+
+  ssize_t (*get_sym) (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name);
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  /* Figure out the endianness of the symtab(s).  */
+  if ((abfd = bfd_openr (argv[1], NULL)) == NULL
+      || !bfd_check_format (abfd, bfd_object))
+    goto bfd_open_err;
+  little_endian = bfd_little_endian (abfd);
+  bfd_close_all_done (abfd);
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  symsect = ctf_getsymsect (fp);
+  strsect = ctf_getstrsect (fp);
+  if (symsect.cts_data == NULL
+      || strsect.cts_data == NULL)
+    {
+      fprintf (stderr, "%s: no symtab or strtab\n", argv[0]);
+      return 1;
+    }
+
+  ctf_dict_close (fp);
+
+  if (symsect.cts_entsize != sizeof (Elf64_Sym) &&
+      symsect.cts_entsize != sizeof (Elf32_Sym))
+    {
+      fprintf (stderr, "%s: unknown symsize: %lx\n", argv[0],
+	       symsect.cts_size);
+      return 1;
+    }
+
+  switch (symsect.cts_entsize)
+    {
+    case sizeof (Elf64_Sym): get_sym = symidx_64; break;
+    case sizeof (Elf32_Sym): get_sym = symidx_32; break;
+    }
+
+  if ((symidx = get_sym (&symsect, &strsect, little_endian, "primary1")) < 0)
+    {
+      fprintf (stderr, "%s: symbol not found: primary1\n", argv[0]);
+      return 1;
+    }
+
+  /* Fish it out, then fish out all its enumerand/value pairs.  */
+
+  if ((fp = ctf_arc_lookup_symbol (ctf, symidx, &type, &err)) == NULL)
+    goto sym_err;
+
+  while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)
+    {
+      printf ("%s has value %i\n", name, val);
+    }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    goto nerr;
+
+  ctf_dict_close (fp);
+  ctf_close (ctf);
+
+  return 0;
+
+ bfd_open_err:
+  fprintf (stderr, "%s: cannot open: %s\n", argv[0], bfd_errmsg (bfd_get_error ()));
+  return 1;
+
+ open_err:
+  fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err));
+  return 1;
+ sym_err:
+  fprintf (stderr, "%s: Symbol lookup error: %s\n", argv[0], ctf_errmsg (err));
+  return 1;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ nerr:
+  fprintf (stderr, "iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/enum-symbol.lk b/libctf/testsuite/libctf-lookup/enum-symbol.lk
new file mode 100644
index 00000000000..e83030ea28f
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-symbol.lk
@@ -0,0 +1,6 @@
+# lookup: enum-symbol.c
+# source: enum-symbol-ctf.c
+# link: on
+red1 has value 0
+green1 has value 1
+blue1 has value 2
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 09/13] libctf: warn about information loss because of unreleased format changes
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (7 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 08/13] libctf: new test of enum lookups with the _next iterator Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 10/13] libctf, include: support unnamed structure members better Nick Alcock
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

In the last cycle there have been various changes that have replaced
parts of the CTF format with other parts without format
compatibility.  This was not a compat break, because the old format was
never accepted by any version of libctf (the not-in-official-release CTF
compiler patch was emitting an invalid func info section), but
nonetheless it can confuse users using that patch if they link together
object files and find the func info sections in the inputs silently
disappearing.

Scan the linker inputs for this problem and emit a warning if any are
found.

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-link.c (ctf_link_warn_outdated_inputs): New.
	(ctf_link_write): Call it.
---
 libctf/ctf-link.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index cdf3db3a7c3..d436b7b8abc 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -2004,6 +2004,34 @@ ctf_change_parent_name (void *key _libctf_unused_, void *value, void *arg)
   ctf_parent_name_set (fp, name);
 }
 
+/* Warn if we may suffer information loss because the CTF input files are too
+   old.  Usually we provide complete backward compatibility, but compiler
+   changes etc which never hit a release may have a flag in the header that
+   simply prevents those changes from being used.  */
+static void
+ctf_link_warn_outdated_inputs (ctf_dict_t *fp)
+{
+  ctf_next_t *i = NULL;
+  void *name_;
+  void *ifp_;
+  int err;
+
+  while ((err = ctf_dynhash_next (fp->ctf_link_inputs, &i, &name_, &ifp_)) == 0)
+    {
+      const char *name = (const char *) name_;
+      ctf_dict_t *ifp = (ctf_dict_t *) ifp_;
+
+      if (!(ifp->ctf_header->cth_flags & CTF_F_NEWFUNCINFO)
+	  && (ifp->ctf_header->cth_varoff - ifp->ctf_header->cth_funcoff) > 0)
+	ctf_err_warn (ifp, 1, 0, _("linker input %s has CTF func info but uses "
+				   "an old, unreleased func info format: "
+				   "this func info section will be dropped."),
+		      name);
+    }
+  if (err != ECTF_NEXT_END)
+    ctf_err_warn (fp, 0, err, _("error checking for outdated inputs"));
+}
+
 /* Write out a CTF archive (if there are per-CU CTF files) or a CTF file
    (otherwise) into a new dynamically-allocated string, and return it.
    Members with sizes above THRESHOLD are compressed.  */
@@ -2023,6 +2051,8 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold)
   memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t));
   arg.fp = fp;
 
+  ctf_link_warn_outdated_inputs (fp);
+
   if (fp->ctf_link_outputs)
     {
       ctf_dynhash_iter (fp->ctf_link_outputs, ctf_accumulate_archive_names, &arg);
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 10/13] libctf, include: support unnamed structure members better
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (8 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 09/13] libctf: warn about information loss because of unreleased format changes Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 11/13] libctf: remove outdated comment about parent dict importing Nick Alcock
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

libctf has no intrinsic support for the GCC unnamed structure member
extension.  This principally means that you can't look up named members
inside unnamed struct or union members via ctf_member_info: you have to
tiresomely find out the type ID of the unnamed members via iteration,
then look in each of these.

This is ridiculous.  Fix it by extending ctf_member_info so that it
recurses into unnamed members for you: this is still unambiguous because
GCC won't let you create ambiguously-named members even in the presence
of this extension.

For consistency, and because the release hasn't happened and we can
still do this, break the ctf_member_next API and add flags: we specify
one flag, CTF_MN_RECURSE, which if set causes ctf_member_next to
automatically recurse into unnamed members for you, returning not only
the members themselves but all their contained members, so that you can
use ctf_member_next to identify every member that it would be valid to
call ctf_member_info with.

New lookup tests are added for all of this.

include/ChangeLog
2020-12-16  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-api.h (CTF_MN_RECURSE): New.
	(ctf_member_next): Add flags argument.

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (struct ctf_next) <u.ctn_next>: Move to...
	<ctn_next>: ... here.
	* ctf-util.c (ctf_next_destroy): Unconditionally destroy it.
	* ctf-lookup.c (ctf_symbol_next): Adjust accordingly.
	* ctf-types.c (ctf_member_iter): Reimplement in terms of...
	(ctf_member_next): ... this.  Support recursive unnamed member
	iteration (off by default).
	(ctf_member_info): Look up members in unnamed sub-structs.
	* ctf-dedup.c (ctf_dedup_rhash_type): Adjust ctf_member_next call.
	(ctf_dedup_emit_struct_members): Likewise.
	* testsuite/libctf-lookup/struct-iteration-ctf.c: Test empty unnamed
	members, and a normal member after the end.
	* testsuite/libctf-lookup/struct-iteration.c: Verify that
	ctf_member_count is consistent with the number of successful returns
	from a non-recursive ctf_member_next.
	* testsuite/libctf-lookup/struct-iteration-*: New, test iteration
	over struct members.
	* testsuite/libctf-lookup/struct-lookup.c: New test.
	* testsuite/libctf-lookup/struct-lookup.lk: New test.
---
 include/ctf-api.h                             |   7 +-
 libctf/ctf-dedup.c                            |   6 +-
 libctf/ctf-impl.h                             |  12 +-
 libctf/ctf-lookup.c                           |   2 +-
 libctf/ctf-types.c                            | 227 +++++++++++-------
 libctf/ctf-util.c                             |   5 +-
 .../libctf-lookup/struct-iteration-ctf.c      |  28 +++
 .../libctf-lookup/struct-iteration.c          |  92 +++++++
 .../libctf-lookup/struct-iteration.lk         |  24 ++
 .../testsuite/libctf-lookup/struct-lookup.c   |  60 +++++
 .../testsuite/libctf-lookup/struct-lookup.lk  |   4 +
 11 files changed, 365 insertions(+), 102 deletions(-)
 create mode 100644 libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/struct-iteration.c
 create mode 100644 libctf/testsuite/libctf-lookup/struct-iteration.lk
 create mode 100644 libctf/testsuite/libctf-lookup/struct-lookup.c
 create mode 100644 libctf/testsuite/libctf-lookup/struct-lookup.lk

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 16567ef3ab6..112b8a42f89 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -264,6 +264,10 @@ _CTF_ERRORS
 #define	CTF_ADD_NONROOT	0	/* Type only visible in nested scope.  */
 #define	CTF_ADD_ROOT	1	/* Type visible at top-level scope.  */
 
+/* Flags for ctf_member_next.  */
+
+#define CTF_MN_RECURSE 0x1	/* Recurse into unnamed members.  */
+
 /* These typedefs are used to define the signature for callback functions that
    can be used with the iteration and visit functions below.  There is also a
    family of iteration functions that do not require callbacks.  */
@@ -411,7 +415,8 @@ extern int ctf_label_info (ctf_dict_t *, const char *, ctf_lblinfo_t *);
 extern int ctf_member_count (ctf_dict_t *, ctf_id_t);
 extern int ctf_member_iter (ctf_dict_t *, ctf_id_t, ctf_member_f *, void *);
 extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
-				const char **name, ctf_id_t *membtype);
+				const char **name, ctf_id_t *membtype,
+				int flags);
 extern int ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
 extern const char *ctf_enum_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
 				  int *);
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index b0be5a7044f..b77acc58a3e 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -887,8 +887,8 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	ctf_dedup_sha1_add (&hash, &size, sizeof (ssize_t), "struct size",
 			    depth);
 
-	while ((offset = ctf_member_next (input, type, &i, &mname,
-					  &membtype)) >= 0)
+	while ((offset = ctf_member_next (input, type, &i, &mname, &membtype,
+					  0)) >= 0)
 	  {
 	    if (mname == NULL)
 	      mname = "";
@@ -2956,7 +2956,7 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
       target_type = CTF_DEDUP_GID_TO_TYPE (target_id);
 
       while ((offset = ctf_member_next (input_fp, input_type, &j, &name,
-					&membtype)) >= 0)
+					&membtype, 0)) >= 0)
 	{
 	  err_fp = target;
 	  err_type = target_type;
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 84460ea2da4..df0d2ef8a1b 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -532,13 +532,15 @@ struct ctf_next
   ssize_t ctn_size;
   ssize_t ctn_increment;
   uint32_t ctn_n;
+
+  /* Some iterators contain other iterators, in addition to their other
+     state.  */
+  ctf_next_t *ctn_next;
+
   /* We can save space on this side of things by noting that a dictionary is
      either dynamic or not, as a whole, and a given iterator can only iterate
      over one kind of thing at once: so we can overlap the DTD and non-DTD
-     members, and the structure, variable and enum members, etc.
-
-     Some of the _next iterators actually thunk down to another _next iterator
-     themselves, so one of the options in here is a _next iterator!  */
+     members, and the structure, variable and enum members, etc.  */
   union
   {
     const ctf_member_t *ctn_mp;
@@ -546,10 +548,10 @@ struct ctf_next
     const ctf_dmdef_t *ctn_dmd;
     const ctf_enum_t *ctn_en;
     const ctf_dvdef_t *ctn_dvd;
-    ctf_next_t *ctn_next;
     ctf_next_hkv_t *ctn_sorted_hkv;
     void **ctn_hash_slot;
   } u;
+
   /* This union is of various sorts of dict we can iterate over:
      currently dictionaries and archives, dynhashes, and dynsets.  */
   union
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index a862b407bcb..9bbd9178356 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -442,7 +442,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 	  return (ctf_set_errno (fp, ECTF_NEXT_END));
 	}
 
-      err = ctf_dynhash_next (dynh, &i->u.ctn_next, &dyn_name, &dyn_value);
+      err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
       /* This covers errors and also end-of-iteration.  */
       if (err != 0)
 	{
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 6f40f40b086..1b808f6d487 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -41,76 +41,33 @@ ctf_type_ischild (ctf_dict_t * fp, ctf_id_t id)
 int
 ctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
 {
-  ctf_dict_t *ofp = fp;
-  const ctf_type_t *tp;
-  ctf_dtdef_t *dtd;
-  ssize_t size, increment;
-  uint32_t kind, n;
+  ctf_next_t *i = NULL;
+  ssize_t offset;
+  const char *name;
+  ctf_id_t membtype;
   int rc;
 
-  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
-    return -1;			/* errno is set for us.  */
-
-  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return -1;			/* errno is set for us.  */
-
-  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
-  kind = LCTF_INFO_KIND (fp, tp->ctt_info);
-
-  if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
-    return (ctf_set_errno (ofp, ECTF_NOTSOU));
-
-  if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
+  while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0)
     {
-      if (size < CTF_LSTRUCT_THRESH)
-	{
-	  const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
-							   increment);
-
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
-	    {
-	      const char *name = ctf_strptr (fp, mp->ctm_name);
-	      if ((rc = func (name, mp->ctm_type, mp->ctm_offset, arg)) != 0)
-	    return rc;
-	    }
-	}
-      else
-	{
-	  const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
-							      increment);
-
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
-	    {
-	      const char *name = ctf_strptr (fp, lmp->ctlm_name);
-	      if ((rc = func (name, lmp->ctlm_type,
-			      (unsigned long) CTF_LMEM_OFFSET (lmp), arg)) != 0)
-		return rc;
-	    }
-	}
-    }
-  else
-    {
-      ctf_dmdef_t *dmd;
-
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
+      if ((rc = func (name, membtype, offset, arg)) != 0)
 	{
-	  if ((rc = func (dmd->dmd_name, dmd->dmd_type,
-			  dmd->dmd_offset, arg)) != 0)
-	    return rc;
+	  ctf_next_destroy (i);
+	  return rc;
 	}
     }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    return -1;					/* errno is set for us.  */
 
   return 0;
 }
 
 /* Iterate over the members of a STRUCT or UNION, returning each member's
    offset and optionally name and member type in turn.  On end-of-iteration,
-   returns -1.  */
+   returns -1.  If FLAGS is CTF_MN_RECURSE, recurse into unnamed members.  */
 
 ssize_t
 ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
-		 const char **name, ctf_id_t *membtype)
+		 const char **name, ctf_id_t *membtype, int flags)
 {
   ctf_dict_t *ofp = fp;
   uint32_t kind;
@@ -121,6 +78,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
     {
       const ctf_type_t *tp;
       ctf_dtdef_t *dtd;
+      ssize_t increment;
 
       if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
 	return -1;			/* errno is set for us.  */
@@ -132,8 +90,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	return ctf_set_errno (ofp, ENOMEM);
       i->cu.ctn_fp = ofp;
 
-      (void) ctf_get_ctt_size (fp, tp, &i->ctn_size,
-			       &i->ctn_increment);
+      (void) ctf_get_ctt_size (fp, tp, &i->ctn_size, &increment);
       kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
@@ -156,11 +113,9 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	  i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
 
 	  if (i->ctn_size < CTF_LSTRUCT_THRESH)
-	    i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp +
-						  i->ctn_increment);
+	    i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment);
 	  else
-	    i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
-						    i->ctn_increment);
+	    i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment);
 	}
       else
 	i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
@@ -178,41 +133,112 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
     return (ctf_set_errno (ofp, ECTF_NOPARENT));
 
-  if (!(fp->ctf_flags & LCTF_RDWR))
-    {
-      if (i->ctn_n == 0)
-	goto end_iter;
+  /* When we hit an unnamed struct/union member, we set ctn_type to indicate
+     that we are inside one, then return the unnamed member: on the next call,
+     we must skip over top-level member iteration in favour of iteration within
+     the sub-struct until it later turns out that that iteration has ended.  */
 
-      if (i->ctn_size < CTF_LSTRUCT_THRESH)
+ retry:
+  if (!i->ctn_type)
+    {
+      if (!(fp->ctf_flags & LCTF_RDWR))
 	{
-	  if (name)
-	    *name = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
-	  if (membtype)
-	    *membtype = i->u.ctn_mp->ctm_type;
-	  offset = i->u.ctn_mp->ctm_offset;
-	  i->u.ctn_mp++;
+	  if (i->ctn_n == 0)
+	    goto end_iter;
+
+	  if (i->ctn_size < CTF_LSTRUCT_THRESH)
+	    {
+	      const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
+
+	      if (name)
+		*name = membname;
+	      if (membtype)
+		*membtype = i->u.ctn_mp->ctm_type;
+	      offset = i->u.ctn_mp->ctm_offset;
+
+	      if (membname[0] == 0
+		  && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
+		      || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
+		i->ctn_type = i->u.ctn_mp->ctm_type;
+
+	      i->u.ctn_mp++;
+	    }
+	  else
+	    {
+	      const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
+
+	      if (name)
+		*name = membname;
+	      if (membtype)
+		*membtype = i->u.ctn_lmp->ctlm_type;
+	      offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
+
+	      if (membname[0] == 0
+		  && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
+		      || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
+		i->ctn_type = i->u.ctn_lmp->ctlm_type;
+
+	      i->u.ctn_lmp++;
+	    }
+	  i->ctn_n--;
 	}
       else
 	{
+	  if (i->u.ctn_dmd == NULL)
+	    goto end_iter;
+	  /* The dmd contains a NULL for unnamed dynamic members.  Don't inflict
+	     this on our callers.  */
 	  if (name)
-	    *name = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
+	    {
+	      if (i->u.ctn_dmd->dmd_name)
+		*name = i->u.ctn_dmd->dmd_name;
+	      else
+		*name = "";
+	    }
 	  if (membtype)
-	    *membtype = i->u.ctn_lmp->ctlm_type;
-	  offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
-	  i->u.ctn_lmp++;
+	    *membtype = i->u.ctn_dmd->dmd_type;
+	  offset = i->u.ctn_dmd->dmd_offset;
+
+	  if (i->u.ctn_dmd->dmd_name == NULL
+	      && (ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_UNION))
+	    i->ctn_type = i->u.ctn_dmd->dmd_type;
+
+	  i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
 	}
-      i->ctn_n--;
+
+      /* The callers might want automatic recursive sub-struct traversal.  */
+      if (!(flags & CTF_MN_RECURSE))
+	i->ctn_type = 0;
+
+      /* Sub-struct traversal starting?  Take note of the offset of this member,
+	 for later boosting of sub-struct members' offsets.  */
+      if (i->ctn_type)
+	i->ctn_increment = offset;
     }
+  /* Traversing a sub-struct?  Just return it, with the offset adjusted.  */
   else
     {
-      if (i->u.ctn_dmd == NULL)
-	goto end_iter;
-      if (name)
-	*name = i->u.ctn_dmd->dmd_name;
-      if (membtype)
-	*membtype = i->u.ctn_dmd->dmd_type;
-      offset = i->u.ctn_dmd->dmd_offset;
-      i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
+      ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name,
+				     membtype, flags);
+
+      if (ret >= 0)
+	return ret + i->ctn_increment;
+
+      if (ctf_errno (fp) != ECTF_NEXT_END)
+	{
+	  ctf_next_destroy (i);
+	  *it = NULL;
+	  i->ctn_type = 0;
+	  return ret;				/* errno is set for us.  */
+	}
+
+      if (!ctf_assert (fp, (i->ctn_next == NULL)))
+	return -1;				/* errno is set for us.  */
+
+      i->ctn_type = 0;
+      /* This sub-struct has ended: on to the next real member.  */
+      goto retry;
     }
 
   return offset;
@@ -1376,7 +1402,7 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype,
 }
 
 /* Return the number of members in a STRUCT or UNION, or the number of
-   enumerators in an ENUM.  */
+   enumerators in an ENUM.  The count does not include unnamed sub-members.  */
 
 int
 ctf_member_count (ctf_dict_t *fp, ctf_id_t type)
@@ -1432,7 +1458,15 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 
 	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
 	    {
-	      if (strcmp (ctf_strptr (fp, mp->ctm_name), name) == 0)
+	      const char *membname = ctf_strptr (fp, mp->ctm_name);
+
+	      if (membname[0] == 0
+		  && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
+		      || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
+		  && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
+		return 0;
+
+	      if (strcmp (membname, name) == 0)
 		{
 		  mip->ctm_type = mp->ctm_type;
 		  mip->ctm_offset = mp->ctm_offset;
@@ -1447,7 +1481,15 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
 
 	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
 	    {
-	      if (strcmp (ctf_strptr (fp, lmp->ctlm_name), name) == 0)
+	      const char *membname = ctf_strptr (fp, lmp->ctlm_name);
+
+	      if (membname[0] == 0
+		  && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
+		      || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
+		  && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
+		return 0;
+
+	      if (strcmp (membname, name) == 0)
 		{
 		  mip->ctm_type = lmp->ctlm_type;
 		  mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
@@ -1463,7 +1505,14 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
       for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
 	   dmd != NULL; dmd = ctf_list_next (dmd))
 	{
-	  if (strcmp (dmd->dmd_name, name) == 0)
+	  if (dmd->dmd_name == NULL
+	      && (ctf_type_kind (fp, dmd->dmd_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, dmd->dmd_type) == CTF_K_UNION)
+	      && (ctf_member_info (fp, dmd->dmd_type, name, mip) == 0))
+	    return 0;
+
+	  if (dmd->dmd_name != NULL
+	      && strcmp (dmd->dmd_name, name) == 0)
 	    {
 	      mip->ctm_type = dmd->dmd_type;
 	      mip->ctm_offset = dmd->dmd_offset;
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
index ab34bc0732e..799e35ad22f 100644
--- a/libctf/ctf-util.c
+++ b/libctf/ctf-util.c
@@ -283,9 +283,8 @@ ctf_next_destroy (ctf_next_t *i)
 
   if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted)
     free (i->u.ctn_sorted_hkv);
-  if (i->ctn_iter_fun == (void (*) (void)) ctf_symbol_next
-      && i->cu.ctn_fp->ctf_flags & LCTF_RDWR)
-    ctf_next_destroy (i->u.ctn_next);
+  if (i->ctn_next)
+    ctf_next_destroy (i->ctn_next);
   free (i);
 }
 
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
new file mode 100644
index 00000000000..7df67adaad4
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
@@ -0,0 +1,28 @@
+#include <unistd.h>
+
+struct foo_t
+{
+  int foo;
+  size_t bar;
+  const char *baz;
+  struct foo_t *self;
+  union
+  {
+    double should_not_appear;
+    char *nor_should_this;
+  } named;
+  struct
+  {
+    long unnamed_sub_member;
+    union
+    {
+      double one_more_level;
+      long yes_really_one_more;
+    };
+  };
+  struct {};		/* Empty ones */
+  union {};
+  int after_the_end;
+};
+
+struct foo_t used;
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.c b/libctf/testsuite/libctf-lookup/struct-iteration.c
new file mode 100644
index 00000000000..03750604ecf
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/struct-iteration.c
@@ -0,0 +1,92 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+print_struct (const char *name, ctf_id_t membtype, unsigned long offset,
+              void *fp_)
+{
+  ctf_dict_t *fp = (ctf_dict_t *) fp_;
+  char *type_name = ctf_type_aname (fp, membtype);
+
+  printf ("iter test: %s, offset %lx, has type %lx/%s\n",
+          name, offset, membtype, type_name);
+  free (type_name);
+
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_id_t type;
+  ctf_next_t *i = NULL;
+  const char *name;
+  ctf_id_t membtype;
+  ssize_t offset;
+  ssize_t icount = 0;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Iterate over the structure members with each iterator type in turn.  */
+
+  if ((type = ctf_lookup_by_name (fp, "struct foo_t") ) == CTF_ERR)
+    goto err;
+
+  if (ctf_member_iter (fp, type, print_struct, fp) < 0)
+    goto ierr;
+
+  while ((offset = ctf_member_next (fp, type, &i, &name, &membtype,
+				    CTF_MN_RECURSE)) >= 0)
+    {
+      char *type_name = ctf_type_aname (fp, membtype);
+
+      printf ("next test: %s, offset %lx, has type %lx/%s\n",
+              name, offset, membtype, type_name);
+      free (type_name);
+    }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    goto nerr;
+
+  /* Now make sure the count of members does not include any recursive
+     members.  */
+  while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0)
+    icount++;
+
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    goto nerr;
+
+  if (icount != ctf_member_count (fp, type))
+    printf ("member counts differ: %li by direct iteration, "
+	    "%li by ctf_member_count\n", icount, ctf_member_count (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;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ ierr:
+  fprintf (stderr, "_iter iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ nerr:
+  fprintf (stderr, "_next iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.lk b/libctf/testsuite/libctf-lookup/struct-iteration.lk
new file mode 100644
index 00000000000..fd644547f20
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/struct-iteration.lk
@@ -0,0 +1,24 @@
+# source: struct-iteration-ctf.c
+# link: on
+iter test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int
+iter test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t
+iter test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \*
+iter test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \*
+iter test: named, offset [0-9a-f]*, has type [0-9a-f]*/union 
+iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+iter test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
+iter test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int
+next test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int
+next test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t
+next test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \*
+next test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \*
+next test: named, offset [0-9a-f]*, has type [0-9a-f]*/union 
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+next test: unnamed_sub_member, offset [0-9a-f]*, has type [0-9a-f]*/long int
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
+next test: one_more_level, offset [0-9a-f]*, has type [0-9a-f]*/double
+next test: yes_really_one_more, offset [0-9a-f]*, has type [0-9a-f]*/long int
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
+next test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int
diff --git a/libctf/testsuite/libctf-lookup/struct-lookup.c b/libctf/testsuite/libctf-lookup/struct-lookup.c
new file mode 100644
index 00000000000..9b95317bfa0
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/struct-lookup.c
@@ -0,0 +1,60 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_id_t type;
+  char *type_name;
+  ctf_membinfo_t mi;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Dig out some strucutre members by name.  */
+
+  if ((type = ctf_lookup_by_name (fp, "struct foo_t") ) == CTF_ERR)
+    goto err;
+
+  if (ctf_member_info (fp, type, "baz", &mi) < 0)
+    goto err;
+
+  type_name = ctf_type_aname (fp, mi.ctm_type);
+  printf ("baz is of type %s, at offset %lx\n", type_name, mi.ctm_offset);
+  free (type_name);
+
+  if (ctf_member_info (fp, type, "one_more_level", &mi) < 0)
+    goto err;
+
+  type_name = ctf_type_aname (fp, mi.ctm_type);
+  printf ("one_more_level is of type %s, at offset %lx\n", type_name, mi.ctm_offset);
+  free (type_name);
+
+  if (ctf_member_info (fp, type, "should_not_appear", &mi) >= 0
+      || ctf_errno (fp) != ECTF_NOMEMBNAM)
+    fprintf (stderr, "should_not_appear appeared.\n");
+
+  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;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/struct-lookup.lk b/libctf/testsuite/libctf-lookup/struct-lookup.lk
new file mode 100644
index 00000000000..b8488237489
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/struct-lookup.lk
@@ -0,0 +1,4 @@
+# source: struct-iteration-ctf.c
+# link: on
+baz is of type const char \*, at offset [0-9a-z]*
+one_more_level is of type double, at offset [0-9a-z]*
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 11/13] libctf: remove outdated comment about parent dict importing
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (9 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 10/13] libctf, include: support unnamed structure members better Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 12/13] libctf: fix lookups of pointers by name in parent dicts Nick Alcock
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

Parent dicts are nowadays imported automatically in most situations, so
the comment in ctf_archive_iter warning people that they need to import
parents by hand is wrong.  Remove it.

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-archive.c (ctf_archive_iter): Remove outdated comment.
---
 libctf/ctf-archive.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index a74ab47040e..81ba51bd7ea 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -1021,9 +1021,7 @@ ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
 
 /* Iterate over all CTF files in an archive, returning each dict in turn as a
    ctf_dict_t, and NULL on error or end of iteration.  It is the caller's
-   responsibility to close it.  Parent dicts may be skipped.  Regardless of
-   whether they are skipped or not, the caller must ctf_import the parent if
-   need be.
+   responsibility to close it.  Parent dicts may be skipped.
 
    The archive member is cached for rapid return on future calls.
 
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 12/13] libctf: fix lookups of pointers by name in parent dicts
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (10 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 11/13] libctf: remove outdated comment about parent dict importing Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-18 19:51 ` [PATCH 13/13] libctf, ld: fix formatting of forwards to unions and enums Nick Alcock
  2020-12-30  4:14 ` [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Alan Modra
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

When you look up a type by name using ctf_lookup_by_name, in most cases
libctf can just strip off any qualifiers and look for the name, but for
pointer types this doesn't work, since the caller will want the pointer
type itself.  But pointer types are nameless, and while they cite the
types they point to, looking up a type by name requires a link going the
*other way*, from the type pointed to to the pointer type that points to
it.

libctf has always built this up at open time: ctf_ptrtab is an array of
type indexes pointing from the index of every type to the index of the
type that points to it.  But because it is built up at open time (and
because it uses type indexes and not type IDs) it is restricted to
working within a single dict and ignoring parent/child
relationships. This is normally invisible, unless you manage to get a
dict with a type in the parent but the only pointer to it in a child.
The ctf_ptrtab will not track this relationship, so lookups of this
pointer type by name will fail.  Since which type is in the parent and
which in the child is largely opaque to the user (which goes where is up
to the deduplicator, and it can and does reshuffle things to save
space), this leads to a very bad user experience, with an
obviously-visible pointer type which ctf_lookup_by_name claims doesn't
exist.

The fix is to have another array, ctf_pptrtab, which is populated in
child dicts: like the parent's ctf_ptrtab, it has one element per type
in the parent, but is all zeroes except for those types which are
pointed to by types in the child: so it maps parent dict indices to
child dict indices.  The array is grown, and new child types scanned,
whenever a lookup happens and new types have been added to the child
since the last time a lookup happened that might need the pptrtab.
(So for non-writable dicts, this only happens once, since new types
cannot be added to non-writable dicts at all.)

Since this introduces new complexity (involving updating only part of
the ctf_pptrtab) which is only seen when a writable dict is in use, we
introduce a new libctf-writable testsuite that contains lookup tests
with no corresponding CTF-containing .c files (which can thus be run
even on platforms with no .ctf-section support in the linker yet), and
add a test to check that creation of pointers in children to types in
parents and a following lookup by name works as expected.  The non-
writable case is tested in a new libctf-regression testsuite which is
used to track now-fixed outright bugs in libctf.

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dict_t) <ctf_pptrtab>: New.
	<ctf_pptrtab_len>: New.
	<ctf_pptrtab_typemax>: New.
	* ctf-create.c (ctf_serialize): Update accordingly.
	(ctf_add_reftype): Note that we don't need to update pptrtab here,
	despite updating ptrtab.
	* ctf-open.c (ctf_dict_close): Destroy the pptrtab.
	(ctf_import): Likewise.
	(ctf_import_unref): Likewise.
	* ctf-lookup.c (grow_pptrtab): New.
	(refresh_pptrtab): New, update a pptrtab.
	(ctf_lookup_by_name): Turn into a wrapper around (and rename to)...
	(ctf_lookup_by_name_internal): ... this: construct the pptrtab, and
	use it in addition to the parent's ptrtab when parent dicts are
	searched.
	* testsuite/libctf-regression/regression.exp: New testsuite for
	regression tests.
	* testsuite/libctf-regression/pptrtab*: New test.
	* testsuite/libctf-writable/writable.exp: New testsuite for tests of
	writable CTF dicts.
	* testsuite/libctf-writable/pptrtab*: New test.
---
 libctf/ctf-create.c                           |   7 +-
 libctf/ctf-impl.h                             |   3 +
 libctf/ctf-lookup.c                           | 195 +++++++++++++++---
 libctf/ctf-open.c                             |  13 +-
 .../testsuite/libctf-regression/pptrtab-a.c   |   3 +
 .../testsuite/libctf-regression/pptrtab-b.c   |   4 +
 libctf/testsuite/libctf-regression/pptrtab.c  |  54 +++++
 libctf/testsuite/libctf-regression/pptrtab.lk |   4 +
 .../libctf-regression/regression.exp          |  43 ++++
 libctf/testsuite/libctf-writable/pptrtab.c    | 109 ++++++++++
 libctf/testsuite/libctf-writable/pptrtab.lk   |   3 +
 libctf/testsuite/libctf-writable/writable.exp |  38 ++++
 12 files changed, 443 insertions(+), 33 deletions(-)
 create mode 100644 libctf/testsuite/libctf-regression/pptrtab-a.c
 create mode 100644 libctf/testsuite/libctf-regression/pptrtab-b.c
 create mode 100644 libctf/testsuite/libctf-regression/pptrtab.c
 create mode 100644 libctf/testsuite/libctf-regression/pptrtab.lk
 create mode 100644 libctf/testsuite/libctf-regression/regression.exp
 create mode 100644 libctf/testsuite/libctf-writable/pptrtab.c
 create mode 100644 libctf/testsuite/libctf-writable/pptrtab.lk
 create mode 100644 libctf/testsuite/libctf-writable/writable.exp

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 28c468372e8..4a19731d0c6 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1142,9 +1142,11 @@ ctf_serialize (ctf_dict_t *fp)
   nfp->ctf_funchash = fp->ctf_funchash;
   nfp->ctf_dynsyms = fp->ctf_dynsyms;
   nfp->ctf_ptrtab = fp->ctf_ptrtab;
+  nfp->ctf_pptrtab = fp->ctf_pptrtab;
   nfp->ctf_dynsymidx = fp->ctf_dynsymidx;
   nfp->ctf_dynsymmax = fp->ctf_dynsymmax;
   nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len;
+  nfp->ctf_pptrtab_len = fp->ctf_pptrtab_len;
   nfp->ctf_link_inputs = fp->ctf_link_inputs;
   nfp->ctf_link_outputs = fp->ctf_link_outputs;
   nfp->ctf_errs_warnings = fp->ctf_errs_warnings;
@@ -1154,6 +1156,7 @@ ctf_serialize (ctf_dict_t *fp)
   nfp->ctf_objtidx_sxlate = fp->ctf_objtidx_sxlate;
   nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset;
   nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
+  nfp->ctf_pptrtab_typemax = fp->ctf_pptrtab_typemax;
   nfp->ctf_in_flight_dynsyms = fp->ctf_in_flight_dynsyms;
   nfp->ctf_link_in_cu_mapping = fp->ctf_link_in_cu_mapping;
   nfp->ctf_link_out_cu_mapping = fp->ctf_link_out_cu_mapping;
@@ -1186,6 +1189,7 @@ ctf_serialize (ctf_dict_t *fp)
   memset (&fp->ctf_errs_warnings, 0, sizeof (ctf_list_t));
   fp->ctf_add_processing = NULL;
   fp->ctf_ptrtab = NULL;
+  fp->ctf_pptrtab = NULL;
   fp->ctf_funcidx_names = NULL;
   fp->ctf_objtidx_names = NULL;
   fp->ctf_funcidx_sxlate = NULL;
@@ -1582,7 +1586,8 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
      type and (if an anonymous typedef node is being pointed at) the type that
      points at too.  Note that ctf_typemax is at this point one higher than we
      want to check against, because it's just been incremented for the addition
-     of this type.  */
+     of this type.  The pptrtab is lazily-updated as needed, so is not touched
+     here.  */
 
   uint32_t type_idx = LCTF_TYPE_TO_INDEX (fp, type);
   uint32_t ref_idx = LCTF_TYPE_TO_INDEX (fp, ref);
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index df0d2ef8a1b..26b71e5d1b7 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -406,6 +406,9 @@ struct ctf_dict
   uint32_t *ctf_txlate;		  /* Translation table for type IDs.  */
   uint32_t *ctf_ptrtab;		  /* Translation table for pointer-to lookups.  */
   size_t ctf_ptrtab_len;	  /* Num types storable in ptrtab currently.  */
+  uint32_t *ctf_pptrtab;	  /* Parent types pointed to by child dicts.  */
+  size_t ctf_pptrtab_len;	  /* Num types storable in pptrtab currently.  */
+  uint32_t ctf_pptrtab_typemax;	  /* Max child type when pptrtab last updated.  */
   uint32_t *ctf_funcidx_names;	  /* Name of each function symbol in symtypetab
 				     (if indexed).  */
   uint32_t *ctf_objtidx_names;	  /* Likewise, for object symbols.  */
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 9bbd9178356..fce8a048b0c 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -22,6 +22,88 @@
 #include <string.h>
 #include <assert.h>
 
+/* Grow the pptrtab so that it is at least NEW_LEN long.  */
+static int
+grow_pptrtab (ctf_dict_t *fp, size_t new_len)
+{
+  uint32_t *new_pptrtab;
+
+  if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
+			      * new_len)) == NULL)
+    return (ctf_set_errno (fp, ENOMEM));
+
+  fp->ctf_pptrtab = new_pptrtab;
+
+  memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0,
+	  sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len));
+
+  fp->ctf_pptrtab_len = new_len;
+  return 0;
+}
+
+/* Update entries in the pptrtab that relate to types newly added in the
+   child.  */
+static int
+refresh_pptrtab (ctf_dict_t *fp, ctf_dict_t *pfp)
+{
+  uint32_t i;
+  for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++)
+    {
+      ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1);
+      ctf_id_t reffed_type;
+      int updated;
+
+      if (ctf_type_kind (fp, type) != CTF_K_POINTER)
+	continue;
+
+      reffed_type = ctf_type_reference (fp, type);
+
+      if (LCTF_TYPE_ISPARENT (fp, reffed_type))
+	{
+	  uint32_t idx = LCTF_TYPE_TO_INDEX (fp, reffed_type);
+
+	  /* Guard against references to invalid types.  No need to consider
+	     the CTF dict corrupt in this case: this pointer just can't be a
+	     pointer to any type we know about.  */
+	  if (idx <= pfp->ctf_typemax)
+	    {
+	      if (idx >= fp->ctf_pptrtab_len
+		  && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0)
+		return -1;			/* errno is set for us.  */
+
+	      fp->ctf_pptrtab[idx] = i;
+	      updated = 1;
+	    }
+	}
+      if (!updated)
+	continue;
+
+      /* If we updated the ptrtab entry for this type's referent, and it's an
+	 anonymous typedef node, we also want to chase down its referent and
+	 change that as well.  */
+
+      if ((ctf_type_kind (fp, reffed_type) == CTF_K_TYPEDEF)
+	  && strcmp (ctf_type_name_raw (fp, reffed_type), "") == 0)
+	{
+	  uint32_t idx;
+	  idx = LCTF_TYPE_TO_INDEX (pfp, ctf_type_reference (fp, reffed_type));
+
+	  if (idx <= pfp->ctf_typemax)
+	    {
+	      if (idx >= fp->ctf_pptrtab_len
+		  && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0)
+		return -1;			/* errno is set for us.  */
+
+	      fp->ctf_pptrtab[idx] = i;
+	    }
+	}
+    }
+
+  fp->ctf_pptrtab_typemax = fp->ctf_typemax;
+
+  return 0;
+}
+
 /* Compare the given input string and length against a table of known C storage
    qualifier keywords.  We just ignore these in ctf_lookup_by_name, below.  To
    do this quickly, we use a pre-computed Perfect Hash Function similar to the
@@ -69,8 +151,9 @@ isqualifier (const char *s, size_t len)
    finds the things that we actually care about: structs, unions, enums,
    integers, floats, typedefs, and pointers to any of these named types.  */
 
-ctf_id_t
-ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
+static ctf_id_t
+ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
+			     const char *name)
 {
   static const char delimiters[] = " \t\n\r\v\f*";
 
@@ -95,30 +178,66 @@ ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
 
       if (*p == '*')
 	{
-	  /* Find a pointer to type by looking in fp->ctf_ptrtab.
-	     If we can't find a pointer to the given type, see if
-	     we can compute a pointer to the type resulting from
-	     resolving the type down to its base type and use
-	     that instead.  This helps with cases where the CTF
-	     data includes "struct foo *" but not "foo_t *" and
-	     the user tries to access "foo_t *" in the debugger.
+	  /* Find a pointer to type by looking in child->ctf_pptrtab (if child
+	     is set) and fp->ctf_ptrtab.  If we can't find a pointer to the
+	     given type, see if we can compute a pointer to the type resulting
+	     from resolving the type down to its base type and use that instead.
+	     This helps with cases where the CTF data includes "struct foo *"
+	     but not "foo_t *" and the user tries to access "foo_t *" in the
+	     debugger.  */
+
+	  uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type);
+	  int in_child = 0;
+
+	  ntype = type;
+	  if (child && idx <= child->ctf_pptrtab_len)
+	    {
+	      ntype = child->ctf_pptrtab[idx];
+	      if (ntype)
+		in_child = 1;
+	    }
 
-	     TODO need to handle parent dicts too.  */
+	  if (ntype == 0)
+	    ntype = fp->ctf_ptrtab[idx];
 
-	  ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)];
+	  /* Try resolving to its base type and check again.  */
 	  if (ntype == 0)
 	    {
-	      ntype = ctf_type_resolve_unsliced (fp, type);
-	      if (ntype == CTF_ERR
-		  || (ntype =
-		      fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, ntype)]) == 0)
+	      if (child)
+		ntype = ctf_type_resolve_unsliced (child, type);
+	      else
+		ntype = ctf_type_resolve_unsliced (fp, type);
+
+	      if (ntype == CTF_ERR)
+		goto notype;
+
+	      idx = LCTF_TYPE_TO_INDEX (fp, ntype);
+
+	      ntype = 0;
+	      if (child && idx <= child->ctf_pptrtab_len)
 		{
-		  (void) ctf_set_errno (fp, ECTF_NOTYPE);
-		  goto err;
+		  ntype = child->ctf_pptrtab[idx];
+		  if (ntype)
+		    in_child = 1;
 		}
+
+	      if (ntype == 0)
+		ntype = fp->ctf_ptrtab[idx];
+	      if (ntype == CTF_ERR)
+		goto notype;
 	    }
 
-	  type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD));
+	  type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)
+				     || in_child);
+
+	  /* We are looking up a type in the parent, but the pointed-to type is
+	     in the child.  Switch to looking in the child: if we need to go
+	     back into the parent, we can recurse again.  */
+	  if (in_child)
+	    {
+	      fp = child;
+	      child = NULL;
+	    }
 
 	  q = p + 1;
 	  continue;
@@ -157,27 +276,21 @@ ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
 		  fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
 		  if (fp->ctf_tmp_typeslice == NULL)
 		    {
-		      (void) ctf_set_errno (fp, ENOMEM);
+		      ctf_set_errno (fp, ENOMEM);
 		      return CTF_ERR;
 		    }
 		}
 
 	      if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash,
 						 fp->ctf_tmp_typeslice)) == 0)
-		{
-		  (void) ctf_set_errno (fp, ECTF_NOTYPE);
-		  goto err;
-		}
+		goto notype;
 
 	      break;
 	    }
 	}
 
       if (lp->ctl_prefix == NULL)
-	{
-	  (void) ctf_set_errno (fp, ECTF_NOTYPE);
-	  goto err;
-	}
+	goto notype;
     }
 
   if (*p != '\0' || type == 0)
@@ -185,14 +298,34 @@ ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
 
   return type;
 
-err:
-  if (fp->ctf_parent != NULL
-      && (ptype = ctf_lookup_by_name (fp->ctf_parent, name)) != CTF_ERR)
-    return ptype;
+ notype:
+  ctf_set_errno (fp, ECTF_NOTYPE);
+  if (fp->ctf_parent != NULL)
+    {
+      /* Need to look up in the parent, from the child's perspective.
+	 Make sure the pptrtab is up to date.  */
+
+      if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
+	{
+	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
+	    return -1;			/* errno is set for us.  */
+	}
+
+      if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
+						name)) != CTF_ERR)
+	return ptype;
+      return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
+    }
 
   return CTF_ERR;
 }
 
+ctf_id_t
+ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
+{
+  return ctf_lookup_by_name_internal (fp, NULL, name);
+}
+
 /* Return the pointer to the internal CTF type data corresponding to the
    given type ID.  If the ID is invalid, the function returns NULL.
    This function is not exported outside of the library.  */
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 7816fd0af10..88199851aab 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -1806,6 +1806,7 @@ ctf_dict_close (ctf_dict_t *fp)
   free (fp->ctf_sxlate);
   free (fp->ctf_txlate);
   free (fp->ctf_ptrtab);
+  free (fp->ctf_pptrtab);
 
   free (fp->ctf_header);
   free (fp);
@@ -1931,7 +1932,8 @@ ctf_cuname_set (ctf_dict_t *fp, const char *name)
 
 /* Import the types from the specified parent dict by storing a pointer to it in
    ctf_parent and incrementing its reference count.  Only one parent is allowed:
-   if a parent already exists, it is replaced by the new parent.  */
+   if a parent already exists, it is replaced by the new parent.  The pptrtab
+   is wiped, and will be refreshed by the next ctf_lookup_by_name call.  */
 int
 ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
 {
@@ -1945,6 +1947,11 @@ ctf_import (ctf_dict_t *fp, ctf_dict_t *pfp)
     ctf_dict_close (fp->ctf_parent);
   fp->ctf_parent = NULL;
 
+  free (fp->ctf_pptrtab);
+  fp->ctf_pptrtab = NULL;
+  fp->ctf_pptrtab_len = 0;
+  fp->ctf_pptrtab_typemax = 0;
+
   if (pfp != NULL)
     {
       int err;
@@ -1979,6 +1986,10 @@ ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp)
     ctf_dict_close (fp->ctf_parent);
   fp->ctf_parent = NULL;
 
+  free (fp->ctf_pptrtab);
+  fp->ctf_pptrtab = NULL;
+  fp->ctf_pptrtab_len = 0;
+  fp->ctf_pptrtab_typemax = 0;
   if (pfp != NULL)
     {
       int err;
diff --git a/libctf/testsuite/libctf-regression/pptrtab-a.c b/libctf/testsuite/libctf-regression/pptrtab-a.c
new file mode 100644
index 00000000000..e9f656a0bc8
--- /dev/null
+++ b/libctf/testsuite/libctf-regression/pptrtab-a.c
@@ -0,0 +1,3 @@
+typedef long a_t;
+
+a_t *a;
diff --git a/libctf/testsuite/libctf-regression/pptrtab-b.c b/libctf/testsuite/libctf-regression/pptrtab-b.c
new file mode 100644
index 00000000000..6142f194c19
--- /dev/null
+++ b/libctf/testsuite/libctf-regression/pptrtab-b.c
@@ -0,0 +1,4 @@
+typedef long a_t;
+
+a_t b;
+
diff --git a/libctf/testsuite/libctf-regression/pptrtab.c b/libctf/testsuite/libctf-regression/pptrtab.c
new file mode 100644
index 00000000000..5d3c2f2ee93
--- /dev/null
+++ b/libctf/testsuite/libctf-regression/pptrtab.c
@@ -0,0 +1,54 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_next_t *i = NULL;
+  ctf_id_t type;
+  const char *arcname;
+  char *type_name;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Make sure we can look up a_t * by name in all non-parent dicts, even though
+     the a_t * and the type it points to are in distinct dicts.  */
+
+  while ((fp = ctf_archive_next (ctf, &i, &arcname, 1, &err)) != NULL)
+    {
+      if ((type = ctf_lookup_by_name (fp, "a_t *")) == CTF_ERR)
+	goto err;
+
+      if (ctf_type_reference (fp, type) == CTF_ERR)
+	goto err;
+
+      printf ("%s: a_t * points to a type of kind %i\n", arcname,
+	      ctf_type_kind (fp, ctf_type_reference (fp, type)));
+
+      ctf_dict_close (fp);
+    }
+  if (err != ECTF_NEXT_END)
+    goto open_err;
+
+  ctf_close (ctf);
+
+  return 0;
+
+ open_err:
+  fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err));
+  return 1;
+ err:
+  fprintf (stderr, "Lookup failed in %s: %s\n", arcname, ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-regression/pptrtab.lk b/libctf/testsuite/libctf-regression/pptrtab.lk
new file mode 100644
index 00000000000..43aae7de758
--- /dev/null
+++ b/libctf/testsuite/libctf-regression/pptrtab.lk
@@ -0,0 +1,4 @@
+# source: pptrtab-a.c
+# source: pptrtab-b.c
+# link_flags: -Wl,--ctf-share-types=share-duplicated
+.*/pptrtab-[ab]\.c: .* points to a type of kind 10
diff --git a/libctf/testsuite/libctf-regression/regression.exp b/libctf/testsuite/libctf-regression/regression.exp
new file mode 100644
index 00000000000..8908a37c17c
--- /dev/null
+++ b/libctf/testsuite/libctf-regression/regression.exp
@@ -0,0 +1,43 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if ![is_elf_format] {
+    unsupported "CTF needs bfd changes to be emitted on non-ELF"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach ctf_test $ctf_test_list {
+    verbose [file rootname $ctf_test]
+    verbose running lookup test on $ctf_test
+    run_lookup_test [file rootname $ctf_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/libctf/testsuite/libctf-writable/pptrtab.c b/libctf/testsuite/libctf-writable/pptrtab.c
new file mode 100644
index 00000000000..68c356352d7
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/pptrtab.c
@@ -0,0 +1,109 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *pfp;
+  ctf_dict_t *cfp;
+  ctf_id_t base, base2, ptr, ptr2, type, last_type;
+  ctf_encoding_t encoding = { CTF_INT_SIGNED, 0, sizeof (int) };
+  ctf_encoding_t encoding2 = { CTF_INT_SIGNED, 0, sizeof (long) };
+  char *type_name;
+  int err;
+
+  if ((pfp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if ((cfp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if (ctf_import (cfp, pfp) < 0)
+    goto create_child;
+
+  /* First, try an int in the parent with a pointer in the child.  Also make
+     another pair of types we will chain to later: these end up before the
+     pptrtab lazy-update watermark.  */
+
+  if ((base = ctf_add_integer (pfp, CTF_ADD_ROOT, "int", &encoding)) == CTF_ERR)
+    goto create_parent;
+
+  if ((base2 = ctf_add_integer (pfp, CTF_ADD_ROOT, "long int", &encoding2)) == CTF_ERR)
+    goto create_parent;
+
+  if ((ptr = ctf_add_pointer (cfp, CTF_ADD_ROOT, base)) == CTF_ERR)
+    goto create_child;
+
+  if ((type = ctf_lookup_by_name (cfp, "int *") ) == CTF_ERR)
+    goto err;
+
+  type_name = ctf_type_aname (cfp, type);
+  printf ("First lookup: %s in the child points to a type of kind %i\n",
+	  type_name, ctf_type_kind (cfp, ctf_type_reference (cfp, type)));
+  free (type_name);
+
+  if (ctf_type_reference (cfp, type) != base)
+    printf ("First lookup ref diff: %lx versus %lx\n", base,
+	    ctf_type_reference (cfp, type));
+  last_type = type;
+
+  /* Add another pointer to the same type in the parent and try a lookup.  */
+
+  if ((ptr = ctf_add_pointer (pfp, CTF_ADD_ROOT, base2)) == CTF_ERR)
+    goto create_parent;
+
+  if ((type = ctf_lookup_by_name (cfp, "long int *") ) == CTF_ERR)
+    goto err;
+
+  type_name = ctf_type_aname (cfp, type);
+  printf ("Second lookup: %s in the child points to a type of kind %i\n",
+	  type_name, ctf_type_kind (cfp, ctf_type_reference (cfp, type)));
+  free (type_name);
+
+  if (ctf_type_reference (cfp, type) != base2)
+    printf ("Second lookup ref diff: %lx versus %lx\n", base2,
+	    ctf_type_reference (cfp, type));
+  if (last_type == type)
+    printf ("Second lookup should not return the same type as the first: %lx\n", type);
+
+  last_type = type;
+
+  /* Add another pointer to the same type in the child and try a lookup.  */
+
+  if ((ptr = ctf_add_pointer (cfp, CTF_ADD_ROOT, base2)) == CTF_ERR)
+    goto create_child;
+
+  if ((type = ctf_lookup_by_name (cfp, "long int *") ) == CTF_ERR)
+    goto err;
+
+  type_name = ctf_type_aname (cfp, type);
+  printf ("Third lookup: %s in the child points to a type of kind %i\n",
+	  type_name, ctf_type_kind (cfp, ctf_type_reference (cfp, type)));
+  free (type_name);
+
+  if (ctf_type_reference (cfp, type) != base2)
+    printf ("Third lookup ref diff: %lx versus %lx\n", base2,
+	    ctf_type_reference (cfp, type));
+
+  if (last_type == type)
+    printf ("Third lookup should not return the same type as the second: %lx\n", type);
+
+  ctf_file_close (cfp);
+  ctf_file_close (pfp);
+
+  return 0;
+
+ create_err:
+  fprintf (stderr, "Creation failed: %s\n", ctf_errmsg (err));
+  return 1;
+ create_parent:
+  fprintf (stderr, "Cannot create type: %s\n", ctf_errmsg (ctf_errno (pfp)));
+  return 1;
+ create_child:
+  fprintf (stderr, "Cannot create type: %s\n", ctf_errmsg (ctf_errno (cfp)));
+  return 1;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (cfp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-writable/pptrtab.lk b/libctf/testsuite/libctf-writable/pptrtab.lk
new file mode 100644
index 00000000000..56cd8c21918
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/pptrtab.lk
@@ -0,0 +1,3 @@
+First lookup: int \* in the child points to a type of kind 1
+Second lookup: long int \* in the child points to a type of kind 1
+Third lookup: long int \* in the child points to a type of kind 1
diff --git a/libctf/testsuite/libctf-writable/writable.exp b/libctf/testsuite/libctf-writable/writable.exp
new file mode 100644
index 00000000000..27c4d8f29ea
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/writable.exp
@@ -0,0 +1,38 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach ctf_test $ctf_test_list {
+    verbose [file rootname $ctf_test]
+    verbose running lookup test on $ctf_test
+    run_lookup_test [file rootname $ctf_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 13/13] libctf, ld: fix formatting of forwards to unions and enums
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (11 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 12/13] libctf: fix lookups of pointers by name in parent dicts Nick Alcock
@ 2020-12-18 19:51 ` Nick Alcock
  2020-12-30  4:14 ` [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Alan Modra
  13 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-18 19:51 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

The type printer was unconditionally printing these as if they were
forwards to structs, even if they were forwards to unions or enums.

ld/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/enum-forward.c: New test.
	* testsuite/ld-ctf/enum-forward.c: New results.

libctf/ChangeLog
2020-12-15  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-types.c (ctf_type_aname): Print forwards to unions and enums
	properly.
---
 ld/testsuite/ld-ctf/enum-forward.c |  2 ++
 ld/testsuite/ld-ctf/enum-forward.d | 20 ++++++++++++++++++++
 libctf/ctf-types.c                 | 21 ++++++++++++++++++++-
 3 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-ctf/enum-forward.c
 create mode 100644 ld/testsuite/ld-ctf/enum-forward.d

diff --git a/ld/testsuite/ld-ctf/enum-forward.c b/ld/testsuite/ld-ctf/enum-forward.c
new file mode 100644
index 00000000000..e0a64b85c74
--- /dev/null
+++ b/ld/testsuite/ld-ctf/enum-forward.c
@@ -0,0 +1,2 @@
+enum vibgyor;
+char * (*get_color_name) (enum vibgyor);
diff --git a/ld/testsuite/ld-ctf/enum-forward.d b/ld/testsuite/ld-ctf/enum-forward.d
new file mode 100644
index 00000000000..a83651eb4b8
--- /dev/null
+++ b/ld/testsuite/ld-ctf/enum-forward.d
@@ -0,0 +1,20 @@
+#as:
+#source: enum-forward.c
+#objdump: --ctf=.ctf
+#ld: -shared
+#name: Forwards to enums
+
+.*: +file format .*
+
+Contents of CTF section .ctf:
+
+  Header:
+    Magic number: 0xdff2
+    Version: 4 \(CTF_VERSION_3\)
+#...
+    Type section:	.* \(0x48 bytes\)
+#...
+  Data objects:
+    get_color_name -> 0x[0-9a-f]*: \(kind 3\) char \*\*\(\*\) \(enum vibgyor\) \(size 0x[0-9a-f]*\) \(aligned at 0x[0-9a-f]*\) -> 0x[0-9a-f]*: \(kind 5\) char \*\(\*\) \(enum vibgyor\) \(aligned at 0x[0-9a-f]*\)
+
+#...
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 1b808f6d487..a5bf85b008c 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -834,7 +834,6 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 	      }
 	      break;
 	    case CTF_K_STRUCT:
-	    case CTF_K_FORWARD:
 	      ctf_decl_sprintf (&cd, "struct %s", name);
 	      break;
 	    case CTF_K_UNION:
@@ -843,6 +842,26 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
 	    case CTF_K_ENUM:
 	      ctf_decl_sprintf (&cd, "enum %s", name);
 	      break;
+	    case CTF_K_FORWARD:
+	      {
+		switch (ctf_type_kind_forwarded (fp, cdp->cd_type))
+		  {
+		  case CTF_K_STRUCT:
+		    ctf_decl_sprintf (&cd, "struct %s", name);
+		    break;
+		  case CTF_K_UNION:
+		    ctf_decl_sprintf (&cd, "union %s", name);
+		    break;
+		  case CTF_K_ENUM:
+		    ctf_decl_sprintf (&cd, "enum %s", name);
+		    break;
+		  default:
+		    ctf_set_errno (fp, ECTF_CORRUPT);
+		    ctf_decl_fini (&cd);
+		    return NULL;
+		  }
+		break;
+	      }
 	    case CTF_K_VOLATILE:
 	      ctf_decl_sprintf (&cd, "volatile");
 	      break;
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C
  2020-12-18 19:51 ` [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C Nick Alcock
@ 2020-12-27 17:43   ` Nick Alcock
  2020-12-28  2:04     ` Nick Alcock
  0 siblings, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2020-12-27 17:43 UTC (permalink / raw)
  To: binutils

On 18 Dec 2020, Nick Alcock via Binutils uttered the following:

> C allows you to do only a very few things with entities of incomplete
> type (as opposed to pointers to them): make pointers to them and give
> them cv-quals, roughly. In particular you can't sizeof them and you
> can't get their alignment.
>
> While we explicitly do not impose all the requirements the standard
> imposes on CTF users, and it *is* still desirable to be able to get size
> and alignment info for incomplete array types (because of their use as
> the last member of structures), it is meaningless to ask for the size or
> alignment of forwards.  Worse, libctf didn't prohibit this and returned
> nonsense from internal implementation details when you asked (it
> returned the kind of the pointed-to type as both the size and alignment,
> because forwards reuse ctt_type as a type kind, and ctt_type and
> ctt_size overlap).  So introduce a new error, ECTF_INCOMPLETE, which is
> returned when you try to get the size or alignment of forwards: we also
> return it when you try to construct CTF dicts that do invalid things
> with forwards, namely adding a forward member to a struct or union or
> making an array of elements of forward type.

... aaand this one is firing on real code. I'll figure out why tomorrow.
I suspect it's falsely firing in the one case C permits, incomplete
array types as the last member of a struct (though I tested this case
and it seemed to work).

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C
  2020-12-27 17:43   ` Nick Alcock
@ 2020-12-28  2:04     ` Nick Alcock
  2020-12-29 11:52       ` [PATCH v2] libctf, ld: prohibit getting the size or alignment of forwards Nick Alcock
  0 siblings, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2020-12-28  2:04 UTC (permalink / raw)
  To: binutils

On 27 Dec 2020, Nick Alcock via Binutils uttered the following:

> On 18 Dec 2020, Nick Alcock via Binutils uttered the following:
>
>> returned when you try to get the size or alignment of forwards: we also
>> return it when you try to construct CTF dicts that do invalid things
>> with forwards, namely adding a forward member to a struct or union or
>> making an array of elements of forward type.
>
> ... aaand this one is firing on real code. I'll figure out why tomorrow.

So I couldn't stop thinking about this.  The problem is intrinsic to the
design of the deduplicator and will take a format rev to fix properly,
but we can do a good-enough fix that will get things working again.

The problem is this. Imagine you have these TUs:

A.c:
  struct A;
  struct B { struct A *a; };
  struct A { struct B b; long foo; long bar; struct B b2; };

B.c:
  struct A;
  struct B { struct A *a; };
  struct A { struct B b; int foo; struct B b2; };

Now struct A is ambiguously defined, so the deduplicator will emit a
forward for A in the shared CTF dict .ctf and emit two child dicts
for A.c and B.c with definitions of the real structs A in them:

Contents of CTF section .ctf:
  Types:
     1: struct B (size 0x8)
        [0x0] (ID 0x1) (kind 6) struct B (aligned at 0x8)
            [0x0] (ID 0x3) (kind 3) struct A * a (aligned at 0x8)
     2: struct A (size 0x6)
        [0x0] (ID 0x2) (kind 9) struct A (aligned at 0x6)
     3: struct A * (size 0x8) -> 2: struct A (size 0x6)
        [0x0] (ID 0x3) (kind 3) struct A * (aligned at 0x8)
     4: long int [0x0:0x40] (size 0x8)
        [0x0] (ID 0x4) (kind 1) long int:64 (aligned at 0x8, format 0x1, offset:bits 0x0:0x40)
     5: int [0x0:0x20] (size 0x4)
        [0x0] (ID 0x5) (kind 1) int:32 (aligned at 0x4, format 0x1, offset:bits 0x0:0x20)

CTF archive member: .../ambiguous-struct-A.c:
  Types:
     80000001: struct A (size 0x20)
        [0x0] (ID 0x80000001) (kind 6) struct A (aligned at 0x8)
            [0x0] (ID 0x1) (kind 6) struct B b (aligned at 0x8)
                [0x0] (ID 0x3) (kind 3) struct A * a (aligned at 0x8)
            [0x40] (ID 0x4) (kind 1) long int foo:64 (aligned at 0x8, format 0x1, offset:bits 0x0:0x40)
            [0x80] (ID 0x4) (kind 1) long int bar:64 (aligned at 0x8, format 0x1, offset:bits 0x0:0x40)
            [0xc0] (ID 0x1) (kind 6) struct B b2 (aligned at 0x8)
                [0xc0] (ID 0x3) (kind 3) struct A * a (aligned at 0x8)

CTF archive member: .../ambiguous-struct-B.c:
  Types:
     80000001: struct A (size 0x18)
        [0x0] (ID 0x80000001) (kind 6) struct A (aligned at 0x8)
            [0x0] (ID 0x1) (kind 6) struct B b (aligned at 0x8)
                [0x0] (ID 0x3) (kind 3) struct A * a (aligned at 0x8)
            [0x40] (ID 0x5) (kind 1) int foo:32 (aligned at 0x4, format 0x1, offset:bits 0x0:0x20)
            [0x80] (ID 0x1) (kind 6) struct B b2 (aligned at 0x8)
                [0x80] (ID 0x3) (kind 3) struct A * a (aligned at 0x8)

Note that the two structs A are different sizes, with corresponding
members at different offsets. But... it's perfectly possible for there
to be an array of one of those structs A, and that array is
unambiguously defined, so it's going to be promoted to the .ctf section:

     6: struct A [50] (size 0x12c)
        [0x0] (ID 0x6) (kind 4) struct A [50] (aligned at 0x6)

... and after the deduplicator's got through with it, that's an array
of, uh... a forward. Which has no size or alignment. Oh dear. And it's
not like it even *can* carry a size: the sizes of both struct A's are
different!

Now we can't stop the deduplicator doing this promotion-to-forward stuff
-- it's the way it breaks cycles. In format v4 we should at least make
it clearer to users what is going on by having the deduplicator emit a
new type kind for these forwards, an 'ambiguous type', CTF_K_AMBIGUOUS,
which is identical to a forward, but the different type kind can make it
possible for users to tell that this is actually a stand-in for an
ambiguous structure or union type which can be found in two or more
per-CU dicts (and we can add a function to the libctf API to return all
the relevant types from the various dicts easily).

Stopping the crashes for now is a simple matter of allowing the addition
of incomplete array types again (even though you can't get their sizes
and/or alignment and you'll get an ECTF_INCOMPLETE if you try, ugh:
ugly, but doesn't cause actual misbehaviour), and adjusting
ctf_add_member_offset so that it does not complain if ctf_type_size or
ctf_type_alignment yields ECTF_INCOMPLETE, but *does* complain if the
next type you try to add to that struct does not have an explicit offset
specified (which would require libctf to get the size and/or alignment
of the incomplete member). The deduplicator always specifies explicit
offsets, so the link-time crashes should go away.

I'll try that in the next day or two, and add a test for this stuff.
(Holiday? I scorn holiday! also a release *is* impending and I'd like
this to be working well enough to get in.)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2] libctf, ld: prohibit getting the size or alignment of forwards
  2020-12-28  2:04     ` Nick Alcock
@ 2020-12-29 11:52       ` Nick Alcock
  0 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-29 11:52 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

C allows you to do only a very few things with entities of incomplete
type (as opposed to pointers to them): make pointers to them and give
them cv-quals, roughly. In particular you can't sizeof them and you
can't get their alignment.

We cannot impose all the requirements the standard imposes on CTF users,
because the deduplicator can transform any structure type into a forward
for the purposes of breaking cycles: so CTF type graphs can easily
contain things like arrays of forward type (if you want to figure out
their size or alignment, you need to chase down the types this forward
might be a forward to in child TU dicts: we will soon add API functions
to make doing this much easier).

Nonetheless, it is still meaningless to ask for the size or alignment of
forwards: but libctf didn't prohibit this and returned nonsense from
internal implementation details when you asked (it returned the kind of
the pointed-to type as both the size and alignment, because forwards
reuse ctt_type as a type kind, and ctt_type and ctt_size overlap).  So
introduce a new error, ECTF_INCOMPLETE, which is returned when you try
to get the size or alignment of forwards: we also return it when you try
to do things that require libctf itself to get the size or alignment of
a forward, notably using a forward as an array index type (which C
should never do in any case) or adding forwards to structures without
specifying their offset explicitly.

The dumper will not emit size or alignment info for forwards any more.

(This should not be an API break since ctf_type_size and ctf_type_align
could both return errors before now: any code that isn't expecting error
returns is already potentially broken.)

include/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-api.h (ECTF_INCOMPLETE): New.
	(ECTF_NERR): Adjust.

ld/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/conflicting-cycle-1.parent.d: Adjust for dumper
	changes.
	* testsuite/ld-ctf/cross-tu-cyclic-conflicting.d: Likewise.
	* testsuite/ld-ctf/forward.c: New test...
	* testsuite/ld-ctf/forward.d: ... and results.

libctf/ChangeLog
2020-12-08  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-types.c (ctf_type_resolve): Improve comment.
	(ctf_type_size): Yield ECTF_INCOMPLETE when applied to forwards.
	Emit errors into the right dict.
	(ctf_type_align): Likewise.
	* ctf-create.c (ctf_add_member_offset): Yield ECTF_INCOMPLETE
	when adding a member without explicit offset when this member, or
	the previous member, is incomplete.
	* ctf-dump.c (ctf_dump_format_type): Do not try to print the size of
	forwards.
	(ctf_dump_member): Do not try to print their alignment.
---

Notes:
    v2: do not prohibit addition of anything other than struct members
        immediately following an incomplete type, and array indexes:
        the deduplicator can turn ambiguous structs and unions into
        forwards in all other cases.  Report errors into the right dict.

 include/ctf-api.h                             |  5 ++-
 .../ld-ctf/conflicting-cycle-1.parent.d       |  4 +-
 .../ld-ctf/cross-tu-cyclic-conflicting.d      |  4 +-
 ld/testsuite/ld-ctf/forward.c                 |  2 +
 ld/testsuite/ld-ctf/forward.d                 | 23 ++++++++++++
 libctf/ctf-create.c                           | 37 ++++++++++++++++++-
 libctf/ctf-dump.c                             | 17 +++++++--
 libctf/ctf-types.c                            | 28 ++++++++++----
 8 files changed, 102 insertions(+), 18 deletions(-)
 create mode 100644 ld/testsuite/ld-ctf/forward.c
 create mode 100644 ld/testsuite/ld-ctf/forward.d

diff --git a/include/ctf-api.h b/include/ctf-api.h
index 9dd0592ab8a..16567ef3ab6 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -230,7 +230,8 @@ typedef struct ctf_snapshot_id
   _CTF_ITEM (ECTF_NEXT_WRONGFUN, "Wrong iteration function called.") \
   _CTF_ITEM (ECTF_NEXT_WRONGFP, "Iteration entity changed in mid-iterate.") \
   _CTF_ITEM (ECTF_FLAGS, "CTF header contains flags unknown to libctf.") \
-  _CTF_ITEM (ECTF_NEEDSBFD, "This feature needs a libctf with BFD support.")
+  _CTF_ITEM (ECTF_NEEDSBFD, "This feature needs a libctf with BFD support.") \
+  _CTF_ITEM (ECTF_INCOMPLETE, "Type is not a complete type.")
 
 #define	ECTF_BASE	1000	/* Base value for libctf errnos.  */
 
@@ -243,7 +244,7 @@ _CTF_ERRORS
 #undef _CTF_FIRST
   };
 
-#define ECTF_NERR (ECTF_NEEDSBFD - ECTF_BASE + 1) /* Count of CTF errors.  */
+#define ECTF_NERR (ECTF_INCOMPLETE - ECTF_BASE + 1) /* Count of CTF errors.  */
 
 /* The CTF data model is inferred to be the caller's data model or the data
    model of the given object, unless ctf_setmodel is explicitly called.  */
diff --git a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
index 4cbe9b61f3c..5da66fda14c 100644
--- a/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
+++ b/ld/testsuite/ld-ctf/conflicting-cycle-1.parent.d
@@ -29,8 +29,8 @@ Contents of CTF section .ctf:
 #...
   Types:
 #...
-     0x[0-9a-f]*: struct B \(.*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B \(.*
+     0x[0-9a-f]*: struct B
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct B
 #...
 CTF archive member: .*:
 #...
diff --git a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
index 3c975ebaa51..eff295edd30 100644
--- a/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
+++ b/ld/testsuite/ld-ctf/cross-tu-cyclic-conflicting.d
@@ -23,8 +23,8 @@ Contents of CTF section \.ctf:
      0x[0-9a-f]*: int \[0x0:0x[0-9a-f]*\] \(size 0x[0-9a-f]*\)
            *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 1\) int:[0-9]* \(aligned at 0x[0-9a-f]*, format 0x1, offset:bits 0x0:0x[0-9a-f]*\)
 #...
-     0x[0-9a-f]*: struct A .*
-           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A .*
+     0x[0-9a-f]*: struct A
+           *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct A
 #...
      0x[0-9a-f]*: struct C .*
            *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 6\) struct C .*
diff --git a/ld/testsuite/ld-ctf/forward.c b/ld/testsuite/ld-ctf/forward.c
new file mode 100644
index 00000000000..e41a7aececa
--- /dev/null
+++ b/ld/testsuite/ld-ctf/forward.c
@@ -0,0 +1,2 @@
+struct foo;
+struct foo *bar __attribute__((used));
diff --git a/ld/testsuite/ld-ctf/forward.d b/ld/testsuite/ld-ctf/forward.d
new file mode 100644
index 00000000000..9ff0dd2ba73
--- /dev/null
+++ b/ld/testsuite/ld-ctf/forward.d
@@ -0,0 +1,23 @@
+#as:
+#source: forward.c
+#objdump: --ctf=.ctf
+#ld: -shared
+#name: Forwards
+
+.*: +file format .*
+
+Contents of CTF section .ctf:
+
+  Header:
+    Magic number: 0xdff2
+    Version: 4 \(CTF_VERSION_3\)
+#...
+    Type section:	.* \(0x18 bytes\)
+#...
+  Types:
+
+     0x[0-9a-f]: struct foo
+          *\[0x0\] \(ID 0x[0-9a-f]*\) \(kind 9\) struct foo
+     0x[0-9a-f]: struct foo \* \(size 0x[0-9a-f]*\) -> 0x[0-9a-f]: struct foo
+          *\[0x0\] \(ID 0x[0-9a-f]\) \(kind 3\) struct foo \* \(aligned at 0x[0-9a-f]*\)
+#...
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index e03a04683dd..1a1e65f7949 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1690,6 +1690,14 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   if (ctf_lookup_by_id (&tmp, arp->ctr_index) == NULL)
     return CTF_ERR;		/* errno is set for us.  */
 
+  if (ctf_type_kind (fp, arp->ctr_index) == CTF_K_FORWARD)
+    {
+      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+		    _("ctf_add_array: index type %lx is incomplete"),
+		    arp->ctr_contents);
+      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+    }
+
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
@@ -2040,6 +2048,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   ssize_t msize, malign, ssize;
   uint32_t kind, vlen, root;
   char *s = NULL;
+  int is_incomplete = 0;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     return (ctf_set_errno (fp, ECTF_RDONLY));
@@ -2075,7 +2084,9 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
     {
       /* 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
-	 types.  */
+	 types.  We allow incomplete types through since they are routinely
+	 added to the ends of structures, and can even be added elsewhere in
+	 structures by the deduplicator.  */
 
       if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
 	{
@@ -2083,6 +2094,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	  malign = 0;
 	  ctf_set_errno (fp, 0);
 	}
+      else if (ctf_errno (fp) == ECTF_INCOMPLETE)
+	is_incomplete = 1;
       else
 	return -1;		/* errno is set for us.  */
     }
@@ -2123,10 +2136,32 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	      return -1;	/* errno is set for us.  */
 	    }
 
+	  if (is_incomplete)
+	    {
+	      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+			    _("ctf_add_member_offset: cannot add member %s of "
+			      "incomplete type %lx to struct %lx without "
+			      "specifying explicit offset\n"),
+			    name ? name : _("(unnamed member)"), type, souid);
+	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+	    }
+
 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
 	    off += linfo.cte_bits;
 	  else if ((lsize = ctf_type_size (fp, ltype)) > 0)
 	    off += lsize * CHAR_BIT;
+	  else if (lsize == -1 && ctf_errno (fp) == ECTF_INCOMPLETE)
+	    {
+	      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+			    _("ctf_add_member_offset: cannot add member %s of "
+			      "type %lx to struct %lx without specifying "
+			      "explicit offset after member %s of type %lx, "
+			      "which is an incomplete type\n"),
+			    name ? name : _("(unnamed member)"), type, souid,
+			    lmd->dmd_name ? lmd->dmd_name
+			    : _("(unnamed member)"), ltype);
+	      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
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index fd64dd3a9a0..a49f39e4569 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -151,7 +151,7 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       free (bit);
       bit = NULL;
 
-      if (kind != CTF_K_FUNCTION)
+      if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
 	if (asprintf (&bit, " (size 0x%lx)%s",
 		      (unsigned long) ctf_type_size (fp, id),
 		      nonroot_trailer) < 0)
@@ -476,6 +476,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   char *bit = NULL;
   ctf_encoding_t ep;
   int has_encoding = 0;
+  int opened_paren = 0;
 
   /* Align neatly.  */
 
@@ -520,8 +521,9 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
 		    ep.cte_bits, (unsigned long) ctf_type_align (state->cdm_fp,
 								 id)) < 0)
 	goto oom;
+      opened_paren = 1;
     }
-  else
+  else if (ctf_type_kind (state->cdm_fp, id) != CTF_K_FORWARD)
     {
       if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s "
 		    "(aligned at 0x%lx", offset, id,
@@ -529,6 +531,14 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
 		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name,
 		    (unsigned long) ctf_type_align (state->cdm_fp, id)) < 0)
 	goto oom;
+      opened_paren = 1;
+    }
+  else /* Forwards have no alignment.  */
+    {
+      if (asprintf (&bit, "[0x%lx] (ID 0x%lx) (kind %i) %s%s%s\n", offset, id,
+		    ctf_type_kind (state->cdm_fp, id), typestr,
+		    (name[0] != 0 && typestr[0] != 0) ? " " : "", name) < 0)
+	goto oom;
     }
 
   *state->cdm_str = str_append (*state->cdm_str, bit);
@@ -547,7 +557,8 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
       bit = NULL;
     }
 
-  *state->cdm_str = str_append (*state->cdm_str, ")\n");
+  if (opened_paren)
+    *state->cdm_str = str_append (*state->cdm_str, ")\n");
   return 0;
 
  oom:
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index dd8ee4fd0ee..86d449534fc 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -583,7 +583,10 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
    against infinite loops, we implement simplified cycle detection and check
    each link against itself, the previous node, and the topmost node.
 
-   Does not drill down through slices to their contained type.  */
+   Does not drill down through slices to their contained type.
+
+   Callers of this function must not presume that a type it returns must have a
+   valid ctt_size: forwards do not, and must be separately handled.  */
 
 ctf_id_t
 ctf_type_resolve (ctf_dict_t *fp, ctf_id_t type)
@@ -911,6 +914,7 @@ ctf_type_aname_raw (ctf_dict_t *fp, ctf_id_t type)
 ssize_t
 ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
 {
+  ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
   ssize_t size;
   ctf_arinfo_t ar;
@@ -942,12 +946,16 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
       if ((size = ctf_get_ctt_size (fp, tp, NULL, NULL)) > 0)
 	return size;
 
-      if (ctf_array_info (fp, type, &ar) < 0
-	  || (size = ctf_type_size (fp, ar.ctr_contents)) < 0)
+      if (ctf_array_info (ofp, type, &ar) < 0
+	  || (size = ctf_type_size (ofp, ar.ctr_contents)) < 0)
 	return -1;		/* errno is set for us.  */
 
       return size * ar.ctr_nelems;
 
+    case CTF_K_FORWARD:
+      /* Forwards do not have a meaningful size.  */
+      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+
     default: /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
@@ -981,9 +989,9 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_ARRAY:
       {
 	ctf_arinfo_t r;
-	if (ctf_array_info (fp, type, &r) < 0)
+	if (ctf_array_info (ofp, type, &r) < 0)
 	  return -1;		/* errno is set for us.  */
-	return (ctf_type_align (fp, r.ctr_contents));
+	return (ctf_type_align (ofp, r.ctr_contents));
       }
 
     case CTF_K_STRUCT:
@@ -1009,7 +1017,7 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 		const ctf_member_t *mp = vmp;
 		for (; n != 0; n--, mp++)
 		  {
-		    ssize_t am = ctf_type_align (fp, mp->ctm_type);
+		    ssize_t am = ctf_type_align (ofp, mp->ctm_type);
 		    align = MAX (align, (size_t) am);
 		  }
 	      }
@@ -1018,7 +1026,7 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 		const ctf_lmember_t *lmp = vmp;
 		for (; n != 0; n--, lmp++)
 		  {
-		    ssize_t am = ctf_type_align (fp, lmp->ctlm_type);
+		    ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
 		    align = MAX (align, (size_t) am);
 		  }
 	      }
@@ -1030,7 +1038,7 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
 	      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
 		   dmd != NULL; dmd = ctf_list_next (dmd))
 		{
-		  ssize_t am = ctf_type_align (fp, dmd->dmd_type);
+		  ssize_t am = ctf_type_align (ofp, dmd->dmd_type);
 		  align = MAX (align, (size_t) am);
 		  if (kind == CTF_K_STRUCT)
 		    break;
@@ -1043,6 +1051,10 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_ENUM:
       return fp->ctf_dmodel->ctd_int;
 
+    case CTF_K_FORWARD:
+      /* Forwards do not have a meaningful alignment.  */
+      return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
+
     default:  /* including slices of enums, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2] libctf: new testsuite
  2020-12-18 19:51 ` [PATCH REVIEW 07/13] libctf: new testsuite Nick Alcock
@ 2020-12-29 11:52   ` Nick Alcock
  0 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2020-12-29 11:52 UTC (permalink / raw)
  To: binutils; +Cc: jose.marchesi, weimin.pan, Nick Alcock

This introduces a new lookup testsuite under libctf, which operates by
compiling (with libtool) a "lookup" .c file that uses libctf to analyze
some other program, then compiling some number of test object files with
CTF and optionally linking them together and running the lookup program
on the test object files (or linked test binary), before diffing the
result much as run_dump_test does.

This lets us test the portions of libctf that are not previously
testable, notably the portions that do lookup on linked output and
that create dynamic dictionaries and then do lookup on them before
writing them out, something that is not tested by the ld-ctf testsuite
because the linker never does this.

A couple of simple tests are added: one testing the functionality of
enum lookups, and one testing that the recently-added commit adding
extra paranoia to incomplete type handling doesn't break linking and
that the result of the link is an (otherwise-impossible) array of
forward type in the shared CTF dict.

ChangeLog
2020-12-14  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.def (libctf): No longer no_check.  Checking depends on
	all-ld.
	* Makefile.in: Regenerated.

libctf/ChangeLog
2020-12-14  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.am (EXPECT): New.
	(RUNTEST): Likewise.
	(RUNTESTFLAGS): Likewise.
	(CC_FOR_TARGET): Likewise.
	(check-DEJAGNU): Likewise.
	(AUTOMAKE_OPTIONS): Add dejagnu.
	* Makefile.in: Regenerated.
	* testsuite/config/default.exp: New.
	* testsuite/lib/ctf-lib.exp: Likewise.
	* testsuite/libctf-lookup/enum.lk: New test.
	* testsuite/libctf-lookup/enum-ctf.c: New CTF input.
	* testsuite/libctf-lookup/enum.c: New lookup test.
	* testsuite/libctf-lookup/ambiguous-struct*.c: New test.
	* testsuite/libctf-lookup/lookup.exp: New.
---

Notes:
    v2: add ambiguous-struct*.c.

 ChangeLog                                     |   6 +
 Makefile.def                                  |   4 +-
 Makefile.in                                   |  13 +
 libctf/Makefile.am                            |  35 +-
 libctf/Makefile.in                            | 113 ++++-
 libctf/testsuite/config/default.exp           |  59 +++
 libctf/testsuite/lib/ctf-lib.exp              | 409 ++++++++++++++++++
 .../libctf-lookup/ambiguous-struct-A.c        |   8 +
 .../libctf-lookup/ambiguous-struct-B.c        |   5 +
 .../libctf-lookup/ambiguous-struct.c          |  51 +++
 .../libctf-lookup/ambiguous-struct.lk         |   4 +
 libctf/testsuite/libctf-lookup/enum-ctf.c     |   8 +
 libctf/testsuite/libctf-lookup/enum.c         |  78 ++++
 libctf/testsuite/libctf-lookup/enum.lk        |  10 +
 libctf/testsuite/libctf-lookup/lookup.exp     |  43 ++
 15 files changed, 820 insertions(+), 26 deletions(-)
 create mode 100644 libctf/testsuite/config/default.exp
 create mode 100644 libctf/testsuite/lib/ctf-lib.exp
 create mode 100644 libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
 create mode 100644 libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
 create mode 100644 libctf/testsuite/libctf-lookup/ambiguous-struct.c
 create mode 100644 libctf/testsuite/libctf-lookup/ambiguous-struct.lk
 create mode 100644 libctf/testsuite/libctf-lookup/enum-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum.lk
 create mode 100644 libctf/testsuite/libctf-lookup/lookup.exp

diff --git a/Makefile.def b/Makefile.def
index 089e70ae3ed..cc429aa8628 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -131,8 +131,7 @@ host_modules= { module= lto-plugin; bootstrap=true;
 		extra_make_flags='@extra_linker_plugin_flags@'; };
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
 host_modules= { module= gotools; };
-host_modules= { module= libctf; no_check=true;
-		bootstrap=true; };
+host_modules= { module= libctf; bootstrap=true; };
 
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
@@ -547,6 +546,7 @@ dependencies = { module=configure-libctf; on=all-bfd; };
 dependencies = { module=configure-libctf; on=all-intl; };
 dependencies = { module=configure-libctf; on=all-zlib; };
 dependencies = { module=configure-libctf; on=all-libiconv; };
+dependencies = { module=check-libctf; on=all-ld; };
 
 // The Makefiles in gdb and gdbserver pull in a file that configure
 // generates in the gnulib directory, so distclean gnulib only after
diff --git a/Makefile.in b/Makefile.in
index fe34132f9e5..4fe7321786e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34761,6 +34761,12 @@ maybe-check-libctf:
 maybe-check-libctf: check-libctf
 
 check-libctf:
+	@: $(MAKE); $(unstage)
+	@r=`${PWD_COMMAND}`; export r; \
+	s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+	$(HOST_EXPORTS) $(EXTRA_HOST_EXPORTS) \
+	(cd $(HOST_SUBDIR)/libctf && \
+	  $(MAKE) $(FLAGS_TO_PASS)  $(EXTRA_BOOTSTRAP_FLAGS) check)
 
 @endif libctf
 
@@ -52366,6 +52372,13 @@ configure-stage3-libctf: maybe-all-stage3-libiconv
 configure-stage4-libctf: maybe-all-stage4-libiconv
 configure-stageprofile-libctf: maybe-all-stageprofile-libiconv
 configure-stagefeedback-libctf: maybe-all-stagefeedback-libiconv
+check-libctf: maybe-all-ld
+check-stage1-libctf: maybe-all-stage1-ld
+check-stage2-libctf: maybe-all-stage2-ld
+check-stage3-libctf: maybe-all-stage3-ld
+check-stage4-libctf: maybe-all-stage4-ld
+check-stageprofile-libctf: maybe-all-stageprofile-ld
+check-stagefeedback-libctf: maybe-all-stagefeedback-ld
 distclean-gnulib: maybe-distclean-gdb
 distclean-gnulib: maybe-distclean-gdbserver
 all-bison: maybe-all-build-texinfo
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index a0d6cae2881..3af31b28c95 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -19,7 +19,7 @@
 
 ACLOCAL_AMFLAGS = -I .. -I ../config -I ../bfd
 
-AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 
 # This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
 # -I../zlib, unless we were configured with --with-system-zlib, in which
@@ -54,3 +54,36 @@ libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS =
+
+CC_FOR_TARGET = ` \
+  if [ -f $$r/../gcc/xgcc ] ; then \
+    if [ -f $$r/../newlib/Makefile ] ; then \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/ -idirafter $$r/../newlib/targ-include -idirafter $${srcroot}/../newlib/libc/include -nostdinc; \
+    else \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/; \
+    fi; \
+  else \
+    if [ "@host@" = "@target@" ] ; then \
+      echo $(CC); \
+    else \
+      echo gcc | sed '$(transform)'; \
+    fi; \
+  fi`
+
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+		CC="$(CC_FOR_TARGET)" CFLAGS="$(CFLAGS) -I$(INCDIR) -I$(srcdir) -I$(builddir) -I$(builddir)/../bfd $(ZLIBINC)" \
+		CC_FOR_HOST="$(CC)" LIBS="$(LIBS)" $(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index 8037beaf16c..883b363b0cf 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -278,6 +278,8 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 AM_RECURSIVE_TARGETS = cscope
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
 	$(top_srcdir)/../ar-lib $(top_srcdir)/../compile \
 	$(top_srcdir)/../config.guess $(top_srcdir)/../config.sub \
@@ -439,7 +441,7 @@ warn = @warn@
 zlibdir = @zlibdir@
 zlibinc = @zlibinc@
 ACLOCAL_AMFLAGS = -I .. -I ../config -I ../bfd
-AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 
 # This is where we get zlib from.  zlibdir is -L../zlib and zlibinc is
 # -I../zlib, unless we were configured with --with-system-zlib, in which
@@ -464,6 +466,26 @@ libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
 libctf_la_SOURCES = $(libctf_nobfd_la_SOURCES) ctf-open-bfd.c
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS = 
+CC_FOR_TARGET = ` \
+  if [ -f $$r/../gcc/xgcc ] ; then \
+    if [ -f $$r/../newlib/Makefile ] ; then \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/ -idirafter $$r/../newlib/targ-include -idirafter $${srcroot}/../newlib/libc/include -nostdinc; \
+    else \
+      echo $$r/../gcc/xgcc -B$$r/../gcc/; \
+    fi; \
+  else \
+    if [ "@host@" = "@target@" ] ; then \
+      echo $(CC); \
+    else \
+      echo gcc | sed '$(transform)'; \
+    fi; \
+  fi`
+
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -966,6 +988,36 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
+	@echo 'Making a new site.exp file ...'
+	@echo '## these variables are automatically generated by make ##' >site.tmp
+	@echo '# Do not edit here.  If you wish to override these values' >>site.tmp
+	@echo '# edit the last section' >>site.tmp
+	@echo 'set srcdir "$(srcdir)"' >>site.tmp
+	@echo "set objdir `pwd`" >>site.tmp
+	@echo 'set build_alias "$(build_alias)"' >>site.tmp
+	@echo 'set build_triplet $(build_triplet)' >>site.tmp
+	@echo 'set host_alias "$(host_alias)"' >>site.tmp
+	@echo 'set host_triplet $(host_triplet)' >>site.tmp
+	@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
+	  echo "## Begin content included from file $$f.  Do not modify. ##" \
+	   && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
+	   && echo "## End content included from file $$f. ##" \
+	   || exit 1; \
+	 done >> site.tmp
+	@echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
+	@if test -f site.exp; then \
+	   sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
+	 fi
+	@-rm -f site.bak
+	@test ! -f site.exp || mv site.exp site.bak
+	@mv site.tmp site.exp
+
+distclean-DEJAGNU:
+	-rm -f site.exp site.bak
+	-l='$(DEJATOOL)'; for tool in $$l; do \
+	  rm -f $$tool.sum $$tool.log; \
+	done
 
 distdir: $(DISTFILES)
 	$(am__remove_distdir)
@@ -1131,6 +1183,7 @@ distcleancheck: distclean
 	       $(distcleancheck_listfiles) ; \
 	       exit 1; } >&2
 check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
 check: check-am
 all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
 installdirs:
@@ -1176,8 +1229,9 @@ distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf ./$(DEPDIR)
 	-rm -f Makefile
-distclean-am: clean-am distclean-compile distclean-generic \
-	distclean-hdr distclean-libtool distclean-tags
+distclean-am: clean-am distclean-DEJAGNU distclean-compile \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-tags
 
 dvi: dvi-am
 
@@ -1241,30 +1295,43 @@ ps-am:
 
 uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
 
-.MAKE: all install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
-	clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
-	clean-noinstLTLIBRARIES cscope cscopelist-am ctags ctags-am \
-	dist dist-all dist-bzip2 dist-gzip dist-lzip dist-shar \
-	dist-tarZ dist-xz dist-zip distcheck distclean \
-	distclean-compile distclean-generic distclean-hdr \
-	distclean-libtool distclean-tags distcleancheck distdir \
-	distuninstallcheck dvi dvi-am html html-am info info-am \
-	install install-am install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-includeHEADERS install-info \
-	install-info-am install-libLTLIBRARIES install-man install-pdf \
-	install-pdf-am install-ps install-ps-am install-strip \
-	installcheck installcheck-am installdirs maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-compile \
-	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
-	uninstall-libLTLIBRARIES
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-DEJAGNU \
+	check-am clean clean-cscope clean-generic clean-libLTLIBRARIES \
+	clean-libtool clean-noinstLTLIBRARIES cscope cscopelist-am \
+	ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \
+	dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
+	distclean-DEJAGNU distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distcleancheck \
+	distdir distuninstallcheck dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-includeHEADERS \
+	install-info install-info-am install-libLTLIBRARIES \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-includeHEADERS uninstall-libLTLIBRARIES
 
 .PRECIOUS: Makefile
 
 
+check-DEJAGNU: site.exp
+	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+	r=`pwd`; export r; \
+	LC_ALL=C; export LC_ALL; \
+	EXPECT=$(EXPECT); export EXPECT; \
+	runtest=$(RUNTEST); \
+	if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+	  $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+		CC="$(CC_FOR_TARGET)" CFLAGS="$(CFLAGS) -I$(INCDIR) -I$(srcdir) -I$(builddir) -I$(builddir)/../bfd $(ZLIBINC)" \
+		CC_FOR_HOST="$(CC)" LIBS="$(LIBS)" $(RUNTESTFLAGS); \
+	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+	fi
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libctf/testsuite/config/default.exp b/libctf/testsuite/config/default.exp
new file mode 100644
index 00000000000..ff231e0951a
--- /dev/null
+++ b/libctf/testsuite/config/default.exp
@@ -0,0 +1,59 @@
+# Basic expect script for libctf lookup tests
+#   Copyright (C) 1993-2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Written by Jeffrey Wheat (cassidy@cygnus.com)
+#
+
+if ![info exists ld] then {
+    set ld [findfile $base_dir/../ld/ld-new $base_dir/../ld/ld-new [transform ld]]
+}
+
+if ![info exists as] then {
+    set as [findfile $base_dir/../gas/as-new $base_dir/../gas/as-new [transform as]]
+}
+
+remote_exec host "mkdir -p tmpdir"
+
+# Make symlinks from tmpdir/libctf to the linker and assembler in the
+# build tree, so that we can use a -B option to gcc to force it to use
+# the newly built linker and assembler.
+if {![file isdirectory tmpdir/libctf]} then {
+    catch "exec mkdir tmpdir/libctf" status
+    catch "exec ln -s ../../../ld/ld-new tmpdir/libctf/ld" status
+    catch "exec ln -s ld tmpdir/libctf/collect-ld" status
+    catch "exec ln -s ../../../gas/as-new tmpdir/libctf/as" status
+}
+set gcc_B_opt "-B[pwd]/tmpdir/libctf/"
+
+# The "make check" target in the Makefile passes in
+# "CC=$(CC_FOR_TARGET)".  But, if the user invokes runtest directly,
+# these flags may not be set.
+if {![info exists CC]} {
+    set CC [find_gcc]
+}
+if {![info exists CC_FOR_HOST]} {
+    set CC_FOR_HOST $CC
+}
+if {![info exists CFLAGS]} {
+    set CFLAGS "-g -O2"
+}
+
+# load the utility procedures
+load_lib ctf-lib.exp
diff --git a/libctf/testsuite/lib/ctf-lib.exp b/libctf/testsuite/lib/ctf-lib.exp
new file mode 100644
index 00000000000..171c08d1805
--- /dev/null
+++ b/libctf/testsuite/lib/ctf-lib.exp
@@ -0,0 +1,409 @@
+# Support routines for libctf testsuite.
+#   Copyright (C) 1994-2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+proc load_common_lib { name } {
+    global srcdir
+    load_file $srcdir/../../binutils/testsuite/lib/$name
+}
+
+load_common_lib binutils-common.exp
+
+proc run_native_host_cmd { command } {
+    global link_output
+    global ld
+
+    verbose -log "$command"
+    set run_output ""
+    try {
+	set run_output [exec "sh" "-c" "$command" "2>@1"]
+	set status 0
+    } trap CHILDSTATUS {results options} {
+	set status [lindex [dict get $options -errorcode] 2]
+	set run_output $results
+    }
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+proc run_host_cmd { prog command } {
+    global link_output
+    global gcc_B_opt
+    global gcc_ld_B_opt_tested
+    global ld
+
+    if { ![is_remote host] && [which "$prog"] == 0 } then {
+	perror "$prog does not exist"
+	return 0
+    }
+
+    # If we are compiling with gcc, we want to add gcc_B_opt to flags.  However,
+    # if $prog already has -B options, which might be the case when running gcc
+    # out of a build directory, we want our -B options to come first.
+    set gccexe $prog
+    set gccparm [string first " " $gccexe]
+    set gccflags ""
+    if { $gccparm > 0 } then {
+	set gccflags [string range $gccexe $gccparm end]
+	set gccexe [string range $gccexe 0 $gccparm]
+	set prog $gccexe
+    }
+    set gccexe [string replace $gccexe 0 [string last "/" $gccexe] ""]
+    if {[string match "*cc*" $gccexe] || [string match "*++*" $gccexe]} then {
+	set gccflags "$gcc_B_opt $gccflags"
+	if {![info exists gcc_ld_B_opt_tested]} {
+	    set gcc_ld_B_opt_tested 1
+	    set ld_version_message [run_host_cmd "$ld" "--version"]
+	    set gcc_ld_version_message [run_host_cmd "$prog" "$gccflags -Wl,--version"]
+	    if {[string first $ld_version_message $gcc_ld_version_message] < 0} {
+		perror "************************************************************************"
+		perror "Your compiler driver ignores -B when choosing ld."
+		perror "You will not be testing the new ld in many of the following tests."
+		set gcc_ld_version [run_host_cmd "$prog" "$gccflags --print-prog-name=ld"]
+		if {![string match "" $gcc_ld_version] && ![string match "ld" $gcc_ld_version]} {
+		    perror "It seems you will be testing $gcc_ld_version instead."
+		}
+		perror "************************************************************************"
+	    }
+	}
+    }
+
+    verbose -log "$prog $gccflags $command"
+    set status [remote_exec host [concat sh -c [list "$prog $gccflags $command 2>&1"]] "" "/dev/null" "libctf.tmp"]
+    remote_upload host "libctf.tmp"
+    set run_output [file_contents "libctf.tmp"]
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+	append run_output "child process exited abnormally"
+    }
+    remote_file build delete libctf.tmp
+    remote_file host delete libctf.tmp
+
+    if [string match "" $run_output] then {
+	return ""
+    }
+
+    verbose -log "$run_output"
+    return "$run_output"
+}
+
+proc run_host_cmd_yesno { prog command } {
+    global exec_output
+    global errcnt warncnt
+
+    set exec_output [prune_warnings [run_host_cmd "$prog" "$command"]]
+    # Ignore error and warning.
+    set errcnt 0
+    set warncnt 0
+    if [string match "" $exec_output] then {
+	return 1;
+    }
+    return 0;
+}
+
+# Return true if we can build a program with the compiler.
+# On some targets, CC might be defined, but libraries and startup
+# code might be missing or require special options that the ld test
+# harness doesn't know about.
+
+proc check_compiler_available { } {
+    global compiler_available_saved
+    global CC
+
+    if {![info exists compiler_available_saved]} {
+	if { [which $CC] == 0 } {
+	    set compiler_available_saved 0
+	    return 0
+	}
+
+	set flags ""
+	if [board_info [target_info name] exists cflags] {
+	    append flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append flags " [board_info [target_info name] ldflags]"
+	}
+
+	set basename "tmpdir/compiler[pid]"
+	set src ${basename}.c
+	set output ${basename}.out
+	set f [open $src "w"]
+	puts $f "int main (void)"
+	puts $f "{"
+	puts $f "  return 0; "
+	puts $f "}"
+	close $f
+	if [is_remote host] {
+	    set src [remote_download host $src]
+	}
+	set compiler_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+	remote_file host delete $src
+	remote_file host delete $output
+	file delete $src
+    }
+    return $compiler_available_saved
+}
+
+# Compile and link a C source file for execution on the host.
+proc compile_link_one_host_cc { src output additional_args } {
+    global CC_FOR_HOST
+    global CFLAGS
+
+    return [run_native_host_cmd "./libtool --quiet --tag=CC --mode=link $CC_FOR_HOST $CFLAGS $src -o $output $additional_args" ]
+}
+
+# Compile a C source file, with the specified additional_flags.
+proc compile_one_cc { src output additional_flags } {
+    global CC
+    global CFLAGS
+
+    set flags ""
+    if [board_info [target_info name] exists cflags] {
+	append flags " [board_info [target_info name] cflags]"
+    }
+    if [board_info [target_info name] exists ldflags] {
+	append flags " [board_info [target_info name] ldflags]"
+    }
+
+    if [is_remote host] {
+	set src [remote_download host $src]
+    }
+    return [run_host_cmd "$CC" "$flags $CFLAGS $additional_flags $src -o $output"]
+}
+
+# run_lookup_test FILE
+#
+# Compile with the host compiler and link a .c file into a "lookup" binary, then
+# compile and optionally link together a bunch of .s or .c files with CTF info
+# and pass the name of the resulting binary to the "lookup" binary and check the
+# output.  (If none is specified, the binary is expected to generate its own CTF
+# for testing purposes.)
+#
+# As with run_dump_test, this is all driven by a file (in this case, a .lk file)
+# beginning with zero or more option lines, which specify the names of the
+# lookup binary's source file, the source file(s) with CTF info to compile
+# together, and whether to link them.  The optional lines have the syntax:
+#
+#	# OPTION: VALUE
+#
+# OPTION is the name of some option, like "name" or "lookup", and
+# VALUE is OPTION's value.  The valid options are described below.
+# Whitespace is ignored everywhere, except within VALUE.  The option
+# list ends with the first line that doesn't match the above syntax.
+# However, a line within the options that begins with a #, but doesn't
+# have a recognizable option name followed by a colon, is considered a
+# comment and entirely ignored.
+#
+# The interesting options are:
+#
+#   name: TEST-NAME
+#	The name of this test, passed to DejaGNU's `pass' and `fail'
+#	commands.  If omitted, this defaults to FILE, the root of the
+#	lookup .c file's name.
+#
+#   lookup: SOURCE
+#	Compile the file SOURCE.c.  If omitted, the lookup source defaults
+#	to FILE.c.
+#
+#   source: SOURCE
+#	Assemble the file SOURCE.c and pass it to the LOOKUP program.
+#
+#   link:
+#	If set, link the SOURCE together even if only one file is specified.
+#
+#   link_flags:
+#	If set, extra flags to pass to the linker.
+#
+#   xfail: GLOB|PROC ...
+#	This test is expected to fail on a specified list of targets.
+#
+# Each option may occur at most once unless otherwise mentioned.
+#
+# After the option lines come regexp lines.  run_lookup_test calls
+# regexp_diff to compare the output of the lookup program against the
+# regexps in FILE.d.
+#
+proc run_lookup_test { name } {
+    global CC CFLAGS LIBS
+    global copyfile env runtests srcdir subdir verbose
+
+    if ![runtest_file_p $runtests $name] then {
+	return
+    }
+
+    if [string match "*/*" $name] {
+	set file $name
+	set name [file tail $name]
+    } else {
+	set file "$srcdir/$subdir/$name"
+    }
+
+    set opt_array [slurp_options "${file}.lk"]
+    if { $opt_array == -1 } {
+	perror "error reading options from $file.lk"
+	unresolved $subdir/$name
+	return
+    }
+    set run_ld 0
+    set opts(link) {}
+    set opts(link_flags) {}
+    set opts(lookup) {}
+    set opts(name) {}
+    set opts(source) {}
+    set opts(xfail) {}
+
+    foreach i $opt_array {
+	set opt_name [lindex $i 0]
+	set opt_val [lindex $i 1]
+	if { $opt_name == "" } {
+	    set in_extra 1
+	    continue
+	}
+	if ![info exists opts($opt_name)] {
+	    perror "unknown option $opt_name in file $file.lk"
+	    unresolved $subdir/$name
+	    return
+	}
+
+	set opts($opt_name) [concat $opts($opt_name) $opt_val]
+    }
+
+    if { [llength $opts(lookup)] == 0 } {
+	set opts(lookup) "$file.c"
+    } else {
+	set opts(lookup) "[file dirname $file]/$opts(lookup)"
+    }
+
+    if { [llength $opts(name)] == 0 } {
+	set opts(name) $opts(lookup)
+    }
+
+    if { [llength $opts(link)] != 0
+	 || [llength $opts(source)] > 1 } {
+	set run_ld 1
+    }
+
+    set testname $opts(name)
+    if { $opts(name) == "" } {
+	set testname "$subdir/$name"
+    }
+
+    # Compile and link the lookup program.
+    set comp_output [compile_link_one_host_cc $opts(lookup) "tmpdir/lookup" "libctf.la"]
+
+    if { $comp_output != ""} {
+	send_log "compilation of lookup program $opts(lookup) failed with <$comp_output>"
+	perror "compilation of lookup program $opts(lookup) failed"
+	fail $testname
+	return 0
+    }
+
+    # Compile the inputs and posibly link them together.
+
+    set lookup_output ""
+    if { [llength $opts(source)] > 0 } {
+	set lookup_flags ""
+	if { $run_ld } {
+	    set lookup_output "tmpdir/out.so"
+	    set lookup_flags "-gt -fPIC -shared $opts(link_flags)"
+	} else {
+	    set lookup_output "tmpdir/out.o"
+	    set lookup_flags "-gt -fPIC -c"
+	}
+	if [board_info [target_info name] exists cflags] {
+	    append lookup_flags " [board_info [target_info name] cflags]"
+	}
+	if [board_info [target_info name] exists ldflags] {
+	    append lookup_flags " [board_info [target_info name] ldflags]"
+	}
+	set src {}
+	foreach sfile $opts(source) {
+	    if [is_remote host] {
+		lappend src [remote_download host [file join [file dirname $file] $sfile]]
+	    } else {
+		lappend src [file join [file dirname $file] $sfile]
+	    }
+	}
+
+	set comp_output [run_host_cmd "$CC" "$CFLAGS $lookup_flags [concat $src] -o $lookup_output"]
+
+	if { $comp_output != ""} {
+	    send_log "compilation of CTF program [concat $src] failed with <$comp_output>"
+	    fail $testname
+	    return 0
+	}
+    }
+
+    # Time to setup xfailures.
+    foreach targ $opts(xfail) {
+	if [match_target $targ] {
+	    setup_xfail "*-*-*"
+	    break
+	}
+    }
+
+    # Invoke the lookup program on the outputs.
+
+    set results [run_host_cmd tmpdir/lookup $lookup_output]
+
+    set f [open "tmpdir/lookup.out" "w"]
+    puts $f $results
+    close $f
+
+    if { [regexp_diff "tmpdir/lookup.out" "${file}.lk"] } then {
+	fail $testname
+	if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/lookup.out]" 2 }
+	return 0
+    }
+
+    pass $testname
+    return 0
+}
+
+# Returns true if the target compiler supports -gt
+proc check_ctf_available { } {
+    global ctf_available_saved
+
+    if {![info exists ctf_available_saved]} {
+	if { ![check_compiler_available] } {
+	    set ctf_available_saved 0
+	} else {
+	    set basename "tmpdir/ctf_available[pid]"
+	    set src ${basename}.c
+	    set output ${basename}.o
+	    set f [open $src "w"]
+	    puts $f "int main() { return 0; }"
+	    close $f
+	    set ctf_available_saved [compile_one_cc $src $output "-gt -c"]
+	    remote_file host delete $src
+	    remote_file host delete $output
+	    file delete $src
+	}
+    }
+    return $ctf_available_saved
+}
diff --git a/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c b/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
new file mode 100644
index 00000000000..67047c4411b
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
@@ -0,0 +1,8 @@
+struct A;
+struct B { struct A *a; };
+struct A { struct B b; long foo; long bar; struct B b2; };
+
+typedef struct A a_array[50];
+a_array *foo __attribute__((__used__));
+
+static struct A a __attribute ((__used__));
diff --git a/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c b/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
new file mode 100644
index 00000000000..95a9346963f
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
@@ -0,0 +1,5 @@
+struct A;
+struct B { struct A *a; };
+struct A { struct B b; int foo; struct B b2; };
+
+static struct A a __attribute__((__used__));
diff --git a/libctf/testsuite/libctf-lookup/ambiguous-struct.c b/libctf/testsuite/libctf-lookup/ambiguous-struct.c
new file mode 100644
index 00000000000..05b471e506b
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/ambiguous-struct.c
@@ -0,0 +1,51 @@
+/* Test ambiguous forward lookups post-deduplication.
+
+   This also makes sure that deduplication succeeds in this case and does not
+   throw spurious errors.  */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_id_t type;
+  ctf_arinfo_t ar;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Dig out the array type and resolve its element type.  */
+
+  if ((type = ctf_lookup_by_name (fp, "a_array") ) == CTF_ERR)
+    goto err;
+  if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
+    goto err;
+  if (ctf_array_info (fp, type, &ar) < 0)
+    goto err;
+  printf ("Kind of array element is %i\n", ctf_type_kind (fp, ar.ctr_contents));
+
+  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;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/ambiguous-struct.lk b/libctf/testsuite/libctf-lookup/ambiguous-struct.lk
new file mode 100644
index 00000000000..84f296d7619
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/ambiguous-struct.lk
@@ -0,0 +1,4 @@
+# source: ambiguous-struct-A.c
+# source: ambiguous-struct-B.c
+# link: on
+Kind of array element is 9
diff --git a/libctf/testsuite/libctf-lookup/enum-ctf.c b/libctf/testsuite/libctf-lookup/enum-ctf.c
new file mode 100644
index 00000000000..aa60d72722e
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-ctf.c
@@ -0,0 +1,8 @@
+/* Looked up item by item. */
+enum e { ENUMSAMPLE_1 = 0, ENUMSAMPLE_2 = 1 };
+
+/* Looked up via both sorts of iterator in turn.  */
+enum ie { IENUMSAMPLE_1 = -10, IENUMSAMPLE_2, IENUMSAMPLE_3 };
+
+enum e foo;
+enum ie bar;
diff --git a/libctf/testsuite/libctf-lookup/enum.c b/libctf/testsuite/libctf-lookup/enum.c
new file mode 100644
index 00000000000..1804b23a69e
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum.c
@@ -0,0 +1,78 @@
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+print_enum (const char *name, int val, void *unused)
+{
+  printf ("iter test: %s has value %i\n", name, val);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_archive_t *ctf;
+  ctf_id_t type;
+  const char *name;
+  ctf_next_t *i = NULL;
+  int val;
+  int err;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
+      exit(1);
+    }
+
+  if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
+    goto open_err;
+  if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
+    goto open_err;
+
+  /* Try getting some enum values by hand.  */
+
+  if ((type = ctf_lookup_by_name (fp, "enum e") ) == CTF_ERR)
+    goto err;
+  if (ctf_enum_value (fp, type, "ENUMSAMPLE_1", &val) < 0)
+    goto err;
+  printf ("Enum e enumerand ENUMSAMPLE_1 has value %i\n", val);
+
+  if ((name = ctf_enum_name (fp, type, 1)) == NULL)
+    goto err;
+  printf ("Enum e enumerand %s has value 1\n", name);
+
+  /* Try getting some values using both sorts of iterator.  */
+
+  if ((type = ctf_lookup_by_name (fp, "enum ie") ) == CTF_ERR)
+    goto err;
+
+  if ((ctf_enum_iter (fp, type, print_enum, NULL)) < 0)
+    goto ierr;
+
+  while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)
+    {
+      printf ("next test: %s has value %i\n", name, val);
+    }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    goto nerr;
+
+  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;
+ err:
+  fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ ierr:
+  fprintf (stderr, "_iter iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ nerr:
+  fprintf (stderr, "_next iteration failed: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-lookup/enum.lk b/libctf/testsuite/libctf-lookup/enum.lk
new file mode 100644
index 00000000000..0b2b1571866
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum.lk
@@ -0,0 +1,10 @@
+# source: enum-ctf.c
+# link: on
+Enum e enumerand ENUMSAMPLE_1 has value 0
+Enum e enumerand ENUMSAMPLE_2 has value 1
+iter test: IENUMSAMPLE_1 has value -10
+iter test: IENUMSAMPLE_2 has value -9
+iter test: IENUMSAMPLE_3 has value -8
+next test: IENUMSAMPLE_1 has value -10
+next test: IENUMSAMPLE_2 has value -9
+next test: IENUMSAMPLE_3 has value -8
diff --git a/libctf/testsuite/libctf-lookup/lookup.exp b/libctf/testsuite/libctf-lookup/lookup.exp
new file mode 100644
index 00000000000..8908a37c17c
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/lookup.exp
@@ -0,0 +1,43 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if ![is_elf_format] {
+    unsupported "CTF needs bfd changes to be emitted on non-ELF"
+    return 0
+}
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set ctf_test_list [lsort [glob -nocomplain $srcdir/$subdir/*.lk]]
+
+foreach ctf_test $ctf_test_list {
+    verbose [file rootname $ctf_test]
+    verbose running lookup test on $ctf_test
+    run_lookup_test [file rootname $ctf_test]
+}
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
-- 
2.29.2.250.g8336e49d6f.dirty


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
                   ` (12 preceding siblings ...)
  2020-12-18 19:51 ` [PATCH 13/13] libctf, ld: fix formatting of forwards to unions and enums Nick Alcock
@ 2020-12-30  4:14 ` Alan Modra
  2020-12-31 13:00   ` Nick Alcock
  2021-01-05 15:18   ` Nick Alcock
  13 siblings, 2 replies; 29+ messages in thread
From: Alan Modra @ 2020-12-30  4:14 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, weimin.pan

On Fri, Dec 18, 2020 at 07:51:34PM +0000, Nick Alcock via Binutils wrote:
> Because this involved build system changes, I tested it more than usual:
> with builds and make check-libctf check-ld on x86_64-pc-linux-gnu,
> sparc64-unknown-linux-gnu, x86_64-unknown-freebsd-12.2, and 64-bit Cygwin
> native builds and crosses to mingw32 and mingw64 hosts and
> x86_64-pc-linux-gnu targets; with --enable-targets=all, all combinations of
> -enable/--disable-static and -shared, and --disable-nls. GDB currently
> doesn't build with --disable-static but everything else seems happy.

Good.  :-)  Looks OK to commit.  Note that the top-level changes
should be committed to the gcc repo, otherwise they are likely to
disappear the next time someone syncs the binutils top-level from
gcc.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2020-12-30  4:14 ` [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Alan Modra
@ 2020-12-31 13:00   ` Nick Alcock
  2021-01-02  4:55     ` Alan Modra
  2021-01-05 15:18   ` Nick Alcock
  1 sibling, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2020-12-31 13:00 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Alcock, binutils, weimin.pan

On 30 Dec 2020, Alan Modra uttered the following:

> Good.  :-)  Looks OK to commit.  Note that the top-level changes
> should be committed to the gcc repo, otherwise they are likely to
> disappear the next time someone syncs the binutils top-level from
> gcc.

Hmm. I don't know if I have suitable permissions to do that :/
thankfully the top-level changes can be desynchronized from the rest...

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2020-12-31 13:00   ` Nick Alcock
@ 2021-01-02  4:55     ` Alan Modra
  0 siblings, 0 replies; 29+ messages in thread
From: Alan Modra @ 2021-01-02  4:55 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils, weimin.pan

On Thu, Dec 31, 2020 at 01:00:00PM +0000, Nick Alcock wrote:
> On 30 Dec 2020, Alan Modra uttered the following:
> 
> > Good.  :-)  Looks OK to commit.  Note that the top-level changes
> > should be committed to the gcc repo, otherwise they are likely to
> > disappear the next time someone syncs the binutils top-level from
> > gcc.
> 
> Hmm. I don't know if I have suitable permissions to do that :/
> thankfully the top-level changes can be desynchronized from the rest...

Yes, top-level patches ought to be posted to binutils, gcc and gdb
lists as per binutils/MAINTAINERS.  If there is any doubt about the
patch, ask for approval from a gcc maintainer before committing to
gcc.  In this case, just post it and commit as obvious.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2020-12-30  4:14 ` [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Alan Modra
  2020-12-31 13:00   ` Nick Alcock
@ 2021-01-05 15:18   ` Nick Alcock
  2021-01-05 15:53     ` H.J. Lu
  1 sibling, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2021-01-05 15:18 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils, weimin.pan

On 30 Dec 2020, Alan Modra via Binutils spake thusly:

> Good.  :-)  Looks OK to commit.  Note that the top-level changes
> should be committed to the gcc repo, otherwise they are likely to
> disappear the next time someone syncs the binutils top-level from
> gcc.

Pushed! I'll see about sending the top-level stuff out next (it's so
simple that it should be easy to get in before the next sync, and if we
*do* miss it, all that happens is that make check-libctf does nothing
for a bit: no harm).

(As usual, this works everywhere I can try it, with one exception I just
noticed: the new libctf-writable testsuite works on non-ELF platforms,
with tests that link to the newly-built libctf, but on a
cygwin-to-mingw64 cross in one of my cygwin64 installations -- but only
one -- I'm seeing very odd stuff that looks almost like a buffer overrun
in the dynamic linker: complaints that it can't find shared libraries
whose names are complete garbage. I've ignored that for now because
whatever it is it's not a libctf bug and shouldn't really hold up a
libctf testsuite finally landing for everyone else. So my apologies if
anyone sees ERROR or FAIL results in that situation.)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 15:18   ` Nick Alcock
@ 2021-01-05 15:53     ` H.J. Lu
  2021-01-05 17:13       ` Nick Alcock
  0 siblings, 1 reply; 29+ messages in thread
From: H.J. Lu @ 2021-01-05 15:53 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Alan Modra, Binutils, weimin.pan

On Tue, Jan 5, 2021 at 7:19 AM Nick Alcock via Binutils
<binutils@sourceware.org> wrote:
>
> On 30 Dec 2020, Alan Modra via Binutils spake thusly:
>
> > Good.  :-)  Looks OK to commit.  Note that the top-level changes
> > should be committed to the gcc repo, otherwise they are likely to
> > disappear the next time someone syncs the binutils top-level from
> > gcc.
>
> Pushed! I'll see about sending the top-level stuff out next (it's so
> simple that it should be easy to get in before the next sync, and if we
> *do* miss it, all that happens is that make check-libctf does nothing
> for a bit: no harm).
>
> (As usual, this works everywhere I can try it, with one exception I just
> noticed: the new libctf-writable testsuite works on non-ELF platforms,
> with tests that link to the newly-built libctf, but on a
> cygwin-to-mingw64 cross in one of my cygwin64 installations -- but only
> one -- I'm seeing very odd stuff that looks almost like a buffer overrun
> in the dynamic linker: complaints that it can't find shared libraries
> whose names are complete garbage. I've ignored that for now because
> whatever it is it's not a libctf bug and shouldn't really hold up a
> libctf testsuite finally landing for everyone else. So my apologies if
> anyone sees ERROR or FAIL results in that situation.)

All libctf tests failed for cross binutils without a cross compiler:

ERROR: aarch64-linux-cc does not exist

-- 
H.J.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 15:53     ` H.J. Lu
@ 2021-01-05 17:13       ` Nick Alcock
  2021-01-05 18:52         ` H.J. Lu
  0 siblings, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2021-01-05 17:13 UTC (permalink / raw)
  To: binutils; +Cc: H.J. Lu, weimin.pan

On 5 Jan 2021, H. J. Lu via Binutils said:

> All libctf tests failed for cross binutils without a cross compiler:
>
> ERROR: aarch64-linux-cc does not exist

Ugh. It helps to actually *call* check_compiler_available as well as
just defining it. How did I miss that?

Unusurprisingly since we never called it it was a crawling mass of bugs
as well. :(

Try this (not really tested yet since I don't have a non-libctf-capable
compiler to hand right now, so I only know it works in the positive
case!):

If it works for you, I'll push it.

Sorry about this.

8<----------------------------------------------->8
From 70d3120f32281980105169dee74440146e97702e Mon Sep 17 00:00:00 2001
From: Nick Alcock <nick.alcock@oracle.com>
Date: Tue, 5 Jan 2021 17:11:20 +0000
Subject: [PATCH] libctf, testsuite: don't run without a suitable compiler

We never actually check to see if the compiler supports CTF,
or even if a suitable compiler exists.

libctf/ChangeLog
2021-01-05  Nick Alcock  <nick.alcock@oracle.com>

	* Makefile.am (BASEDIR): New.
	(BFDDIR): Likewise.
	(check-DEJAGNU): Add development.exp to prerequisites.
	(development.exp): New.
	(CONFIG_STATUS_DEPENDENCIES): New.
	(EXTRA_DEJAGNU_SITE_CONFIG): Likewise.
	(DISTCLEANFILES): Likewise.
	* Makefile.in: Regenerated.
	* testsuite/lib/ctf-lib.exp (check_ctf_available): Return boolean.
	* testsuite/libctf-lookup/lookup.exp: Call check_ctf_available.
	* testsuite/libctf-regression/regression.exp: Likewise.
---
 libctf/ChangeLog                                  | 14 ++++++++++++++
 libctf/Makefile.am                                | 15 ++++++++++++++-
 libctf/Makefile.in                                | 14 +++++++++++++-
 libctf/testsuite/lib/ctf-lib.exp                  |  7 ++++++-
 libctf/testsuite/libctf-lookup/lookup.exp         |  5 +++++
 libctf/testsuite/libctf-regression/regression.exp |  5 +++++
 6 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index 0aaf3067ab6..0f5e96a2c83 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,17 @@
+2021-01-05  Nick Alcock  <nick.alcock@oracle.com>
+
+	* Makefile.am (BASEDIR): New.
+	(BFDDIR): Likewise.
+	(check-DEJAGNU): Add development.exp to prerequisites.
+	(development.exp): New.
+	(CONFIG_STATUS_DEPENDENCIES): New.
+	(EXTRA_DEJAGNU_SITE_CONFIG): Likewise.
+	(DISTCLEANFILES): Likewise.
+	* Makefile.in: Regenerated.
+	* testsuite/lib/ctf-lib.exp (check_ctf_available): Return boolean.
+	* testsuite/libctf-lookup/lookup.exp: Call check_ctf_available.
+	* testsuite/libctf-regression/regression.exp: Likewise.
+
 2021-01-05  Nick Alcock  <nick.alcock@oracle.com>
 
 	* ctf-types.c (ctf_type_aname): Print forwards to unions and enums
diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 3fe1994d96e..f45433483c0 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -27,6 +27,8 @@ AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
 
+BASEDIR = $(srcdir)/..
+BFDDIR = $(BASEDIR)/bfd
 INCDIR = $(srcdir)/../include
 AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd @INCINTL@
 AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
@@ -75,7 +77,7 @@ CC_FOR_TARGET = ` \
     fi; \
   fi`
 
-check-DEJAGNU: site.exp
+check-DEJAGNU: site.exp development.exp
 	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
 	r=`pwd`; export r; \
 	LC_ALL=C; export LC_ALL; \
@@ -87,3 +89,14 @@ check-DEJAGNU: site.exp
 		CC_FOR_HOST="$(CC)" LIBS="$(LIBS)" $(RUNTESTFLAGS); \
 	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
 	fi
+
+development.exp: $(BFDDIR)/development.sh
+	$(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh  \
+	  | $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
+
+# development.sh is used to determine -Werror default.
+CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
+
+EXTRA_DEJAGNU_SITE_CONFIG = development.exp
+
+DISTCLEANFILES = site.exp development.exp
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index c86ac7b2b68..d31d017c1f5 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -448,6 +448,8 @@ AUTOMAKE_OPTIONS = dejagnu foreign no-texinfo.tex
 # case both are empty.
 ZLIB = @zlibdir@ -lz
 ZLIBINC = @zlibinc@
+BASEDIR = $(srcdir)/..
+BFDDIR = $(BASEDIR)/bfd
 INCDIR = $(srcdir)/../include
 AM_CPPFLAGS = -D_GNU_SOURCE -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../bfd -I../bfd @INCINTL@
 AM_CFLAGS = -std=gnu99 @ac_libctf_warn_cflags@ @warn@ @c_warn@ @WARN_PEDANTIC@ @WERROR@ $(ZLIBINC)
@@ -486,6 +488,11 @@ CC_FOR_TARGET = ` \
     fi; \
   fi`
 
+
+# development.sh is used to determine -Werror default.
+CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
+EXTRA_DEJAGNU_SITE_CONFIG = development.exp
+DISTCLEANFILES = site.exp development.exp
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -1216,6 +1223,7 @@ clean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
@@ -1319,7 +1327,7 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
 .PRECIOUS: Makefile
 
 
-check-DEJAGNU: site.exp
+check-DEJAGNU: site.exp development.exp
 	srcroot=`cd $(srcdir) && pwd`; export srcroot; \
 	r=`pwd`; export r; \
 	LC_ALL=C; export LC_ALL; \
@@ -1332,6 +1340,10 @@ check-DEJAGNU: site.exp
 	else echo "WARNING: could not find \`runtest'" 1>&2; :;\
 	fi
 
+development.exp: $(BFDDIR)/development.sh
+	$(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh  \
+	  | $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libctf/testsuite/lib/ctf-lib.exp b/libctf/testsuite/lib/ctf-lib.exp
index 796342b96de..fe028122195 100644
--- a/libctf/testsuite/lib/ctf-lib.exp
+++ b/libctf/testsuite/lib/ctf-lib.exp
@@ -399,7 +399,12 @@ proc check_ctf_available { } {
 	    set f [open $src "w"]
 	    puts $f "int main() { return 0; }"
 	    close $f
-	    set ctf_available_saved [compile_one_cc $src $output "-gt -c"]
+	    set comp_output [compile_one_cc $src $output "-gt -c"]
+            if { $comp_output == ""} {
+                set ctf_available_saved 1
+            } else {
+                set ctf_available_saved 0
+            }
 	    remote_file host delete $src
 	    remote_file host delete $output
 	    file delete $src
diff --git a/libctf/testsuite/libctf-lookup/lookup.exp b/libctf/testsuite/libctf-lookup/lookup.exp
index 51ad257c94f..84ff46ce4d8 100644
--- a/libctf/testsuite/libctf-lookup/lookup.exp
+++ b/libctf/testsuite/libctf-lookup/lookup.exp
@@ -23,6 +23,11 @@ if ![is_elf_format] {
     return 0
 }
 
+if {![check_ctf_available]} {
+    unsupported "no CTF format support in the compiler"
+    return 0
+}
+
 if {[info exists env(LC_ALL)]} {
     set old_lc_all $env(LC_ALL)
 }
diff --git a/libctf/testsuite/libctf-regression/regression.exp b/libctf/testsuite/libctf-regression/regression.exp
index 51ad257c94f..605d96f57b7 100644
--- a/libctf/testsuite/libctf-regression/regression.exp
+++ b/libctf/testsuite/libctf-regression/regression.exp
@@ -18,6 +18,11 @@
 # MA 02110-1301, USA.
 #
 
+if {![check_ctf_available]} {
+    unsupported "no CTF format support in the compiler"
+    return 0
+}
+
 if ![is_elf_format] {
     unsupported "CTF needs bfd changes to be emitted on non-ELF"
     return 0
-- 
2.29.2.250.g8336e49d6f.dirty

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 17:13       ` Nick Alcock
@ 2021-01-05 18:52         ` H.J. Lu
  2021-01-05 19:05           ` Nick Alcock
  2021-01-05 19:56           ` Nick Alcock
  0 siblings, 2 replies; 29+ messages in thread
From: H.J. Lu @ 2021-01-05 18:52 UTC (permalink / raw)
  To: Nick Alcock; +Cc: Binutils, weimin.pan

On Tue, Jan 5, 2021 at 9:14 AM Nick Alcock <nick.alcock@oracle.com> wrote:
>
> On 5 Jan 2021, H. J. Lu via Binutils said:
>
> > All libctf tests failed for cross binutils without a cross compiler:
> >
> > ERROR: aarch64-linux-cc does not exist
>
> Ugh. It helps to actually *call* check_compiler_available as well as
> just defining it. How did I miss that?
>
> Unusurprisingly since we never called it it was a crawling mass of bugs
> as well. :(
>
> Try this (not really tested yet since I don't have a non-libctf-capable
> compiler to hand right now, so I only know it works in the positive
> case!):
>
> If it works for you, I'll push it.
>
> Sorry about this.
>
> 8<----------------------------------------------->8
> From 70d3120f32281980105169dee74440146e97702e Mon Sep 17 00:00:00 2001
> From: Nick Alcock <nick.alcock@oracle.com>
> Date: Tue, 5 Jan 2021 17:11:20 +0000
> Subject: [PATCH] libctf, testsuite: don't run without a suitable compiler
>
> We never actually check to see if the compiler supports CTF,
> or even if a suitable compiler exists.
>
> libctf/ChangeLog
> 2021-01-05  Nick Alcock  <nick.alcock@oracle.com>
>
>         * Makefile.am (BASEDIR): New.
>         (BFDDIR): Likewise.
>         (check-DEJAGNU): Add development.exp to prerequisites.
>         (development.exp): New.
>         (CONFIG_STATUS_DEPENDENCIES): New.
>         (EXTRA_DEJAGNU_SITE_CONFIG): Likewise.
>         (DISTCLEANFILES): Likewise.
>         * Makefile.in: Regenerated.
>         * testsuite/lib/ctf-lib.exp (check_ctf_available): Return boolean.
>         * testsuite/libctf-lookup/lookup.exp: Call check_ctf_available.
>         * testsuite/libctf-regression/regression.exp: Likewise.
> ---
>  libctf/ChangeLog                                  | 14 ++++++++++++++
>  libctf/Makefile.am                                | 15 ++++++++++++++-
>  libctf/Makefile.in                                | 14 +++++++++++++-
>  libctf/testsuite/lib/ctf-lib.exp                  |  7 ++++++-
>  libctf/testsuite/libctf-lookup/lookup.exp         |  5 +++++
>  libctf/testsuite/libctf-regression/regression.exp |  5 +++++
>  6 files changed, 57 insertions(+), 3 deletions(-)
>
> diff --git a/libctf/ChangeLog b/libctf/ChangeLog
> index 0aaf3067ab6..0f5e96a2c83 100644
> --- a/libctf/ChangeLog
> +++ b/libctf/ChangeLog
> @@ -1,3 +1,17 @@
> +2021-01-05  Nick Alcock  <nick.alcock@oracle.com>
> +
> +       * Makefile.am (BASEDIR): New.
> +       (BFDDIR): Likewise.
> +       (check-DEJAGNU): Add development.exp to prerequisites.
> +       (development.exp): New.
> +       (CONFIG_STATUS_DEPENDENCIES): New.
> +       (EXTRA_DEJAGNU_SITE_CONFIG): Likewise.
> +       (DISTCLEANFILES): Likewise.
> +       * Makefile.in: Regenerated.
> +       * testsuite/lib/ctf-lib.exp (check_ctf_available): Return boolean.
> +       * testsuite/libctf-lookup/lookup.exp: Call check_ctf_available.
> +       * testsuite/libctf-regression/regression.exp: Likewise.
> +

Can you verify and check in the check_ctf_available change first to
unbreak cross binutils?

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 18:52         ` H.J. Lu
@ 2021-01-05 19:05           ` Nick Alcock
  2021-01-05 19:09             ` H.J. Lu
  2021-01-05 19:56           ` Nick Alcock
  1 sibling, 1 reply; 29+ messages in thread
From: Nick Alcock @ 2021-01-05 19:05 UTC (permalink / raw)
  To: H.J. Lu via Binutils; +Cc: Nick Alcock, H.J. Lu, weimin.pan

On 5 Jan 2021, H. J. Lu via Binutils uttered the following:

> Can you verify and check in the check_ctf_available change first to
> unbreak cross binutils?

This is all the same change: check_ctf_available crashes without all the
other stuff :(

But yes, I'm verifying now. (I presume you see it not only in cross
builds but in any build with a non-ctf-capable compiler.)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 19:05           ` Nick Alcock
@ 2021-01-05 19:09             ` H.J. Lu
  2021-01-05 19:32               ` Nick Alcock
  0 siblings, 1 reply; 29+ messages in thread
From: H.J. Lu @ 2021-01-05 19:09 UTC (permalink / raw)
  To: Nick Alcock; +Cc: H.J. Lu via Binutils, weimin.pan

On Tue, Jan 5, 2021 at 11:07 AM Nick Alcock <nick.alcock@oracle.com> wrote:
>
> On 5 Jan 2021, H. J. Lu via Binutils uttered the following:
>
> > Can you verify and check in the check_ctf_available change first to
> > unbreak cross binutils?
>
> This is all the same change: check_ctf_available crashes without all the
> other stuff :(
>
> But yes, I'm verifying now. (I presume you see it not only in cross
> builds but in any build with a non-ctf-capable compiler.)

I also got

cc -B/export/build/gnu/tools-build/binutils/build-x86_64-linux/libctf/tmpdir/libctf/
 -O2 -g -Wformat -Werror=format-security   -fcf-protection
-I/export/gnu/import/git/sources/binutils-gdb/libctf/../include
-I/export/gnu/import/git/sources/binutils-gdb/libctf -I. -I./../bfd
-gt -fPIC -shared
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
-o tmpdir/out.so
Executing on host: sh -c {cc
-B/export/build/gnu/tools-build/binutils/build-x86_64-linux/libctf/tmpdir/libctf/
 -O2 -g -Wformat -Werror=format-security   -fcf-protection
-I/export/gnu/import/git/sources/binutils-gdb/libctf/../include
-I/export/gnu/import/git/sources/binutils-gdb/libctf -I. -I./../bfd
-gt -fPIC -shared
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
-o tmpdir/out.so 2>&1}  /dev/null libctf.tmp (timeout = 300)
spawn [open ...]^M
cc: error: unrecognized debug output level 't'
cc: error: unrecognized debug output level 't'

and

export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:
In function 'main':
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:72:13:
warning: format '%li' expects argument of type 'long int', but
argument 3 has type 'int' [-Wformat=]
   72 |     printf ("member counts differ: %li by direct iteration, "
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   73 |      "%li by ctf_member_count\n", icount, ctf_member_count (fp, type));
      |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                           |
      |                                           int
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:73:9:
note: format string is defined here
   73 |      "%li by ctf_member_count\n", icount, ctf_member_count (fp, type));
      |       ~~^
      |         |
      |         long int
      |       %i
compilation of lookup program
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c
failed with </export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:
In function 'main':
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:72:13:
warning: format '%li' expects argument of type 'long int', but
argument 3 has type 'int' [-Wformat=]
   72 |     printf ("member counts differ: %li by direct iteration, "
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   73 |      "%li by ctf_member_count\n", icount, ctf_member_count (fp, type));
      |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                           |
      |                                           int
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c:73:9:
note: format string is defined here
   73 |      "%li by ctf_member_count\n", icount, ctf_member_count (fp, type));
      |       ~~^
      |         |
      |         long int
      |       %i>ERROR: compilation of lookup program
/export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c
failed
UNRESOLVED: /export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/struct-iteration.c



-- 
H.J.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 19:09             ` H.J. Lu
@ 2021-01-05 19:32               ` Nick Alcock
  0 siblings, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2021-01-05 19:32 UTC (permalink / raw)
  To: binutils; +Cc: H.J. Lu, weimin.pan

On 5 Jan 2021, H. J. Lu via Binutils stated:

> On Tue, Jan 5, 2021 at 11:07 AM Nick Alcock <nick.alcock@oracle.com> wrote:
>>
>> On 5 Jan 2021, H. J. Lu via Binutils uttered the following:
>>
>> > Can you verify and check in the check_ctf_available change first to
>> > unbreak cross binutils?
>>
>> This is all the same change: check_ctf_available crashes without all the
>> other stuff :(
>>
>> But yes, I'm verifying now. (I presume you see it not only in cross
>> builds but in any build with a non-ctf-capable compiler.)
>
> I also got
>
> cc -B/export/build/gnu/tools-build/binutils/build-x86_64-linux/libctf/tmpdir/libctf/
>  -O2 -g -Wformat -Werror=format-security   -fcf-protection
> -I/export/gnu/import/git/sources/binutils-gdb/libctf/../include
> -I/export/gnu/import/git/sources/binutils-gdb/libctf -I. -I./../bfd
> -gt -fPIC -shared
> /export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
> /export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
> -o tmpdir/out.so
> Executing on host: sh -c {cc
> -B/export/build/gnu/tools-build/binutils/build-x86_64-linux/libctf/tmpdir/libctf/
>  -O2 -g -Wformat -Werror=format-security   -fcf-protection
> -I/export/gnu/import/git/sources/binutils-gdb/libctf/../include
> -I/export/gnu/import/git/sources/binutils-gdb/libctf -I. -I./../bfd
> -gt -fPIC -shared
> /export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-A.c
> /export/gnu/import/git/sources/binutils-gdb/libctf/testsuite/libctf-lookup/ambiguous-struct-B.c
> -o tmpdir/out.so 2>&1}  /dev/null libctf.tmp (timeout = 300)
> spawn [open ...]^M
> cc: error: unrecognized debug output level 't'
> cc: error: unrecognized debug output level 't'

OK, this is what the patch above is meant to fix. It's clearly not doing
what I thought it should: I've got a non-CTF-capable compiler now and
will iterate until I fix it.

More soon.

>       |       %i>ERROR: compilation of lookup program

OK that's a genuine bug, will fix (though honestly I'm wondering if I
should just prune warnings out in this testsuite).

Thanks for spotting these!


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes
  2021-01-05 18:52         ` H.J. Lu
  2021-01-05 19:05           ` Nick Alcock
@ 2021-01-05 19:56           ` Nick Alcock
  1 sibling, 0 replies; 29+ messages in thread
From: Nick Alcock @ 2021-01-05 19:56 UTC (permalink / raw)
  To: binutils; +Cc: H.J. Lu, weimin.pan

On 5 Jan 2021, H. J. Lu via Binutils stated:
> Can you verify and check in the check_ctf_available change first to
> unbreak cross binutils?

... pushed. It seems to work for me when make check-libctf'ing for a
target that I don't have a cross-compiler for yet, and with a target I
*do* have a compiler for that doesn't support -gt. (-gt is likely to
change soonish anyway: the compiler that will be upstreamed is likely to
use a different flag. I'll adapt the tests in binutils when that
happens.)

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2021-01-05 19:56 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-18 19:51 [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Nick Alcock
2020-12-18 19:51 ` [PATCH 01/13] libctf: do not print array declarators backwards Nick Alcock
2020-12-18 19:51 ` [PATCH 02/13] libctf, ld: CTF dumper changes for consistency Nick Alcock
2020-12-18 19:51 ` [PATCH 03/13] libctf, ld: more dumper improvements Nick Alcock
2020-12-18 19:51 ` [PATCH 04/13] libctf, ld: prohibit doing things with forwards prohibited in C Nick Alcock
2020-12-27 17:43   ` Nick Alcock
2020-12-28  2:04     ` Nick Alcock
2020-12-29 11:52       ` [PATCH v2] libctf, ld: prohibit getting the size or alignment of forwards Nick Alcock
2020-12-18 19:51 ` [PATCH 05/13] libctf, ld: dump enums: generally improve dump formatting Nick Alcock
2020-12-18 19:51 ` [PATCH REVIEW 06/13] libctf: rip out BFD_DEPENDENCIES / BFD_LIBADD Nick Alcock
2020-12-18 19:51 ` [PATCH REVIEW 07/13] libctf: new testsuite Nick Alcock
2020-12-29 11:52   ` [PATCH v2] " Nick Alcock
2020-12-18 19:51 ` [PATCH 08/13] libctf: new test of enum lookups with the _next iterator Nick Alcock
2020-12-18 19:51 ` [PATCH 09/13] libctf: warn about information loss because of unreleased format changes Nick Alcock
2020-12-18 19:51 ` [PATCH 10/13] libctf, include: support unnamed structure members better Nick Alcock
2020-12-18 19:51 ` [PATCH 11/13] libctf: remove outdated comment about parent dict importing Nick Alcock
2020-12-18 19:51 ` [PATCH 12/13] libctf: fix lookups of pointers by name in parent dicts Nick Alcock
2020-12-18 19:51 ` [PATCH 13/13] libctf, ld: fix formatting of forwards to unions and enums Nick Alcock
2020-12-30  4:14 ` [PATCH 00/13] CTF dumper improvements, a lookup testsuite, and bugfixes Alan Modra
2020-12-31 13:00   ` Nick Alcock
2021-01-02  4:55     ` Alan Modra
2021-01-05 15:18   ` Nick Alcock
2021-01-05 15:53     ` H.J. Lu
2021-01-05 17:13       ` Nick Alcock
2021-01-05 18:52         ` H.J. Lu
2021-01-05 19:05           ` Nick Alcock
2021-01-05 19:09             ` H.J. Lu
2021-01-05 19:32               ` Nick Alcock
2021-01-05 19:56           ` Nick Alcock

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).