aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2019-08-03 00:46:01 +0100
committerNick Alcock <nick.alcock@oracle.com>2019-09-23 14:12:54 +0100
commitc37135b645c3344808641a91422bad0cb916a514 (patch)
tree615c43fb0bb6849d44a125859b38a9a2f121e043
parent2091d7d550bf2c718ca1b4d613f81290868ed4c3 (diff)
downloadgdb-c37135b645c3344808641a91422bad0cb916a514.zip
gdb-c37135b645c3344808641a91422bad0cb916a514.tar.gz
gdb-c37135b645c3344808641a91422bad0cb916a514.tar.bz2
libctf: teach ctf_add_type how forwards work
This machinery has been broken for as long as Solaris has existed. Forwards are meant to encode "struct foo;", "enum foo;" or "union foo;". Obviously these all exist in distinct namespaces, so forwards store the type kind they forward to in their ctt_type member (which makes conceptual sense if you squint at it). The addition machinery uses this to promote forwards to the appropriate type as needed. Unfortunately ctf_add_type does not: it checks the global namespace (which is always wrong), and so fails with a spurious conflict if you have, say, a typedef and then a forward comes along with the same name, even if it's a forward to something like a struct. (This was observed with <libio.h>, which has "struct _IO_FILE;" and also "typedef struct _IO_FILE _IO_FILE"). We should look at the recorded type kind and look in the appropriate namespace. We should also, when creating the forward in the new container, use that type kind, rather than just defaulting to CTF_K_STRUCT and hoping that what eventually comes along is a struct. This bug is as old as the first implementation of ctf_add_type in Solaris. But we also want a new feature for the linker, closely-related and touching the same code so we add it here: not only do we want a forward followed by a struct/union/enum to promote the forward, but we want want a struct/union/enum followed by a forward to act as a NOP and return the existing type, because when we're adding many files in succession to a target link, there will often be already-promoted forwards (in the shape of a struct/union/enum) that want to unify with duplicate forwards coming from other object files. libctf/ * ctf-create.c (ctf_add_type): Look up and use the forwarded-to type kind. Allow forwards to unify with pre-existing structs/ unions/enums.
-rw-r--r--libctf/ChangeLog6
-rw-r--r--libctf/ctf-create.c43
2 files changed, 35 insertions, 14 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index 3946b9b..42608b8 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,9 @@
+2019-08-03 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-create.c (ctf_add_type): Look up and use the forwarded-to
+ type kind. Allow forwards to unify with pre-existing structs/
+ unions/enums.
+
2019-07-30 Nick Alcock <nick.alcock@oracle.com>
* ctf-impl.h (ctf_file_t) <ctf_link_cu_mappping>: New.
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index c1cf55f..fc158d4 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1552,7 +1552,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
ctf_id_t tmp;
const char *name;
- uint32_t kind, flag, vlen;
+ uint32_t kind, forward_kind, flag, vlen;
const ctf_type_t *src_tp, *dst_tp;
ctf_bundle_t src, dst;
@@ -1576,7 +1576,11 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
flag = LCTF_INFO_ISROOT (src_fp, src_tp->ctt_info);
vlen = LCTF_INFO_VLEN (src_fp, src_tp->ctt_info);
- switch (kind)
+ forward_kind = kind;
+ if (kind == CTF_K_FORWARD)
+ forward_kind = src_tp->ctt_type;
+
+ switch (forward_kind)
{
case CTF_K_STRUCT:
hp = dst_fp->ctf_structs;
@@ -1605,16 +1609,30 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
/* If an identically named dst_type exists, fail with ECTF_CONFLICT
unless dst_type is a forward declaration and src_type is a struct,
- union, or enum (i.e. the definition of the previous forward decl). */
+ union, or enum (i.e. the definition of the previous forward decl).
- if (dst_type != CTF_ERR && dst_kind != kind
- && (dst_kind != CTF_K_FORWARD
- || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
- && kind != CTF_K_UNION)))
+ We also allow addition in the opposite order (addition of a forward when a
+ struct, union, or enum already exists), which is a NOP and returns the
+ already-present struct, union, or enum. */
+
+ if (dst_type != CTF_ERR && dst_kind != kind)
{
- ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
- "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
- return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+ if (kind == CTF_K_FORWARD
+ && (dst_kind == CTF_K_ENUM || dst_kind == CTF_K_STRUCT
+ || dst_kind == CTF_K_UNION))
+ {
+ ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
+ return dst_type;
+ }
+
+ if (dst_kind != CTF_K_FORWARD
+ || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
+ && kind != CTF_K_UNION))
+ {
+ ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
+ "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
+ return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+ }
}
/* We take special action for an integer, float, or slice since it is
@@ -1924,10 +1942,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
case CTF_K_FORWARD:
if (dst_type == CTF_ERR)
- {
- dst_type = ctf_add_forward (dst_fp, flag,
- name, CTF_K_STRUCT); /* Assume STRUCT. */
- }
+ dst_type = ctf_add_forward (dst_fp, flag, name, forward_kind);
break;
case CTF_K_TYPEDEF: