summaryrefslogtreecommitdiff
path: root/usr/src/lib/libctf/common
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2020-11-16 16:37:31 +0000
committerJason King <jason.king@joyent.com>2020-11-16 16:37:31 +0000
commit5ffcb7f72a2f7a214b40ea8d0ef402f68aeada38 (patch)
tree86b767ee8b3625c219d1f5438eb25530c9703534 /usr/src/lib/libctf/common
parent45f7bf1d4508f8d85c7add1bdeb9f7ea099f0ab2 (diff)
parentde0f04687a2a3fe3692d9ad1254738343bf9c4eb (diff)
downloadillumos-joyent-5ffcb7f72a2f7a214b40ea8d0ef402f68aeada38.tar.gz
[illumos-gate merge]
commit de0f04687a2a3fe3692d9ad1254738343bf9c4eb 13310 Remove auto_ef.3ext as we don't have the software commit 25befe07d3c1488cbbdecdb765cd0558e12cc364 13302 pthread_attr_get_np.3c erroneously refers to pthread_getattr_np commit 509a605d87b8005c687f8d8264f1be379620e886 13304 bhyve ioport handling bungled on reinit commit 83cd75bb2949d26e6eb38ddefc60fdeed1909643 13309 bhyve movs emulation leaks mem refcnt commit b713c91e508f40be7797bedd4ae1146ef0652625 7537 want nextboot (one time boot) support commit 09fcda9fe16a733cc35aa3156a47ef4b909251a6 13172 Port OpenZFS: zfs label bootenv should store data as nvlist commit c4ecba8aa5f13f00c2439c06af2aa1198771ee66 13025 Port OpenZFS: Add support for boot environment data to be stored in the label commit 1a2acdcd3ce765904dbf2bfc511e92d68022d100 13308 testrunner/run needs updates for python 3.9 commit 04573c73a7ab1505c46b2c4db26bfde5176dd6a5 13286 bhyve ins/outs emulation misuses %rax commit 3dfdac06b0c70e672dbe56a2f38ec05fc0254d07 13278 CTF assertion failed cmp->cm_tmap[id].cmt_map == suid commit a676209deb2ce5d0c98f331659de25e2483f8c4c 13252 ctf_update()/ctf_dwarf_convert_function() leak memory commit effb27ee30c48fe502152c38487ced379d9f8693 13247 CTF conversion fails with large files 13251 CTF conversion fails if any CU is missing DWARF data Conflicts: usr/src/test/test-runner/cmd/run usr/src/lib/libctf/common/libctf.h usr/src/lib/libctf/common/ctf_convert.c
Diffstat (limited to 'usr/src/lib/libctf/common')
-rw-r--r--usr/src/lib/libctf/common/ctf_convert.c9
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c623
-rw-r--r--usr/src/lib/libctf/common/ctf_merge.c70
-rw-r--r--usr/src/lib/libctf/common/libctf_impl.h4
4 files changed, 466 insertions, 240 deletions
diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c
index 9441aa6ed7..07f344ebaa 100644
--- a/usr/src/lib/libctf/common/ctf_convert.c
+++ b/usr/src/lib/libctf/common/ctf_convert.c
@@ -139,7 +139,7 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
for (i = 0; i < NCONVERTS; i++) {
fp = NULL;
- err = ctf_converters[i](fd, elf, nthrs, flags,
+ err = ctf_converters[i](fd, elf, bsize, nthrs, flags,
&fp, errbuf, errlen);
if (err != ECTF_CONVNODEBUG)
@@ -169,8 +169,8 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
}
ctf_file_t *
-ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp,
- char *errbuf, size_t errlen)
+ctf_fdconvert(int fd, const char *label, uint_t bsize, uint_t nthrs,
+ uint_t flags, int *errp, char *errbuf, size_t errlen)
{
int err;
Elf *elf;
@@ -185,7 +185,8 @@ ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp,
return (NULL);
}
- fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen);
+ fp = ctf_elfconvert(fd, elf, label, bsize, nthrs, flags, errp, errbuf,
+ errlen);
(void) elf_end(elf);
return (fp);
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
index 388cb20489..d91888d6c1 100644
--- a/usr/src/lib/libctf/common/ctf_dwarf.c
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -30,6 +30,7 @@
/*
* Copyright 2020 Joyent, Inc.
* Copyright 2020 Robert Mustacchi
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -206,6 +207,8 @@
#include <dwarf.h>
#include <libgen.h>
#include <workq.h>
+#include <thread.h>
+#include <macros.h>
#include <errno.h>
#define DWARF_VERSION_TWO 2
@@ -254,12 +257,14 @@ typedef struct ctf_dwbitf {
*/
typedef struct ctf_die {
Elf *cu_elf; /* shared libelf handle */
+ int cu_fd; /* shared file descriptor */
char *cu_name; /* basename of the DIE */
ctf_merge_t *cu_cmh; /* merge handle */
ctf_list_t cu_vars; /* List of variables */
ctf_list_t cu_funcs; /* List of functions */
ctf_list_t cu_bitfields; /* Bit field members */
Dwarf_Debug cu_dwarf; /* libdwarf handle */
+ mutex_t *cu_dwlock; /* libdwarf lock */
Dwarf_Die cu_cu; /* libdwarf compilation unit */
Dwarf_Off cu_cuoff; /* cu's offset */
Dwarf_Off cu_maxoff; /* maximum offset */
@@ -277,6 +282,7 @@ typedef struct ctf_die {
ctf_id_t cu_longtid; /* id for a 'long' */
} ctf_cu_t;
+static int ctf_dwarf_init_die(ctf_cu_t *);
static int ctf_dwarf_offset(ctf_cu_t *, Dwarf_Die, Dwarf_Off *);
static int ctf_dwarf_convert_die(ctf_cu_t *, Dwarf_Die);
static int ctf_dwarf_convert_type(ctf_cu_t *, Dwarf_Die, ctf_id_t *, int);
@@ -286,6 +292,13 @@ static int ctf_dwarf_function_count(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
static int ctf_dwarf_convert_fargs(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *,
ctf_id_t *);
+#define DWARF_LOCK(cup) \
+ if ((cup)->cu_dwlock != NULL) \
+ mutex_enter((cup)->cu_dwlock)
+#define DWARF_UNLOCK(cup) \
+ if ((cup)->cu_dwlock != NULL) \
+ mutex_exit((cup)->cu_dwlock)
+
/*
* This is a generic way to set a CTF Conversion backend error depending on what
* we were doing. Unless it was one of a specific set of errors that don't
@@ -305,7 +318,8 @@ ctf_dwarf_error(ctf_cu_t *cup, ctf_file_t *cfp, int err, const char *fmt, ...)
if (err == ENOMEM)
return (err);
- ret = snprintf(cup->cu_errbuf, rem, "die %s: ", cup->cu_name);
+ ret = snprintf(cup->cu_errbuf, rem, "die %s: ",
+ cup->cu_name != NULL ? cup->cu_name : "NULL");
if (ret < 0)
goto err;
off += ret;
@@ -429,7 +443,10 @@ ctf_dwarf_attribute(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
int ret;
Dwarf_Error derr;
- if ((ret = dwarf_attr(die, name, attrp, &derr)) == DW_DLV_OK)
+ DWARF_LOCK(cup);
+ ret = dwarf_attr(die, name, attrp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK)
return (0);
if (ret == DW_DLV_NO_ENTRY) {
*attrp = NULL;
@@ -441,6 +458,14 @@ ctf_dwarf_attribute(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
return (ECTF_CONVBKERR);
}
+static void
+ctf_dwarf_dealloc(ctf_cu_t *cup, Dwarf_Ptr ptr, Dwarf_Unsigned type)
+{
+ DWARF_LOCK(cup);
+ dwarf_dealloc(cup->cu_dwarf, ptr, type);
+ DWARF_UNLOCK(cup);
+}
+
static int
ctf_dwarf_ref(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp)
{
@@ -451,8 +476,11 @@ ctf_dwarf_ref(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp)
if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0)
return (ret);
- if (dwarf_formref(attr, refp, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_LOCK(cup);
+ ret = dwarf_formref(attr, refp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK) {
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (0);
}
@@ -474,8 +502,10 @@ ctf_dwarf_refdie(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
return (ret);
off += cup->cu_cuoff;
- if ((ret = dwarf_offdie(cup->cu_dwarf, off, diep, &derr)) !=
- DW_DLV_OK) {
+ DWARF_LOCK(cup);
+ ret = dwarf_offdie(cup->cu_dwarf, off, diep, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret != DW_DLV_OK) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to get die from offset %" DW_PR_DUu ": %s\n",
off, dwarf_errmsg(derr));
@@ -496,8 +526,11 @@ ctf_dwarf_signed(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0)
return (ret);
- if (dwarf_formsdata(attr, valp, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_LOCK(cup);
+ ret = dwarf_formsdata(attr, valp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK) {
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (0);
}
@@ -518,8 +551,11 @@ ctf_dwarf_unsigned(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0)
return (ret);
- if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_LOCK(cup);
+ ret = dwarf_formudata(attr, valp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK) {
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (0);
}
@@ -540,8 +576,11 @@ ctf_dwarf_boolean(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name,
if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0)
return (ret);
- if (dwarf_formflag(attr, val, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_LOCK(cup);
+ ret = dwarf_formflag(attr, val, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK) {
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (0);
}
@@ -564,12 +603,15 @@ ctf_dwarf_string(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, char **strp)
if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0)
return (ret);
- if (dwarf_formstring(attr, &s, &derr) == DW_DLV_OK) {
+ DWARF_LOCK(cup);
+ ret = dwarf_formstring(attr, &s, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK) {
if ((*strp = ctf_strdup(s)) == NULL)
ret = ENOMEM;
else
ret = 0;
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (ret);
}
@@ -598,17 +640,22 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp)
enum Dwarf_Form_Class class;
if ((ret = ctf_dwarf_attribute(cup, die, DW_AT_data_member_location,
- &attr)) != 0)
+ &attr)) != 0) {
return (ret);
+ }
- if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) {
+ DWARF_LOCK(cup);
+ ret = dwarf_whatform(attr, &form, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret != DW_DLV_OK) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to get dwarf attribute for for member location: %s",
dwarf_errmsg(derr));
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (ECTF_CONVBKERR);
}
+ DWARF_LOCK(cup);
class = dwarf_get_form_class(cup->cu_vers, DW_AT_data_member_location,
cup->cu_addrsz, form);
if (class == DW_FORM_CLASS_CONSTANT) {
@@ -621,12 +668,14 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp)
* match, fall through to the normal path.
*/
if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_UNLOCK(cup);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (0);
}
if (dwarf_formsdata(attr, &sign, &derr) == DW_DLV_OK) {
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_UNLOCK(cup);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
if (sign < 0) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"encountered negative member data "
@@ -638,26 +687,28 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp)
}
if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) {
+ DWARF_UNLOCK(cup);
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to obtain location list for member offset: %s",
dwarf_errmsg(derr));
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (ECTF_CONVBKERR);
}
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_UNLOCK(cup);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to parse location structure for member");
- dwarf_dealloc(cup->cu_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
- dwarf_dealloc(cup->cu_dwarf, loc, DW_DLA_LOCDESC);
+ ctf_dwarf_dealloc(cup, loc->ld_s, DW_DLA_LOC_BLOCK);
+ ctf_dwarf_dealloc(cup, loc, DW_DLA_LOCDESC);
return (ECTF_CONVBKERR);
}
*valp = loc->ld_s->lr_number;
- dwarf_dealloc(cup->cu_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
- dwarf_dealloc(cup->cu_dwarf, loc, DW_DLA_LOCDESC);
+ ctf_dwarf_dealloc(cup, loc->ld_s, DW_DLA_LOC_BLOCK);
+ ctf_dwarf_dealloc(cup, loc, DW_DLA_LOCDESC);
return (0);
}
@@ -666,8 +717,12 @@ static int
ctf_dwarf_offset(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Off *offsetp)
{
Dwarf_Error derr;
+ int ret;
- if (dwarf_dieoffset(die, offsetp, &derr) == DW_DLV_OK)
+ DWARF_LOCK(cup);
+ ret = dwarf_dieoffset(die, offsetp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK)
return (0);
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
@@ -678,12 +733,14 @@ ctf_dwarf_offset(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Off *offsetp)
/* simpler variant for debugging output */
static Dwarf_Off
-ctf_die_offset(Dwarf_Die die)
+ctf_die_offset(ctf_cu_t *cup, Dwarf_Die die)
{
Dwarf_Off off = -1;
Dwarf_Error derr;
+ DWARF_LOCK(cup);
(void) dwarf_dieoffset(die, &off, &derr);
+ DWARF_UNLOCK(cup);
return (off);
}
@@ -691,8 +748,12 @@ static int
ctf_dwarf_tag(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half *tagp)
{
Dwarf_Error derr;
+ int ret;
- if (dwarf_tag(die, tagp, &derr) == DW_DLV_OK)
+ DWARF_LOCK(cup);
+ ret = dwarf_tag(die, tagp, &derr);
+ DWARF_UNLOCK(cup);
+ if (ret == DW_DLV_OK)
return (0);
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
@@ -708,7 +769,9 @@ ctf_dwarf_sib(ctf_cu_t *cup, Dwarf_Die base, Dwarf_Die *sibp)
int ret;
*sibp = NULL;
+ DWARF_LOCK(cup);
ret = dwarf_siblingof(cup->cu_dwarf, base, sibp, &derr);
+ DWARF_UNLOCK(cup);
if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
return (0);
@@ -725,7 +788,9 @@ ctf_dwarf_child(ctf_cu_t *cup, Dwarf_Die base, Dwarf_Die *childp)
int ret;
*childp = NULL;
+ DWARF_LOCK(cup);
ret = dwarf_child(base, childp, &derr);
+ DWARF_UNLOCK(cup);
if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
return (0);
@@ -1442,14 +1507,15 @@ ctf_dwarf_create_sou(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp,
decl = 0;
}
- if (decl != 0) {
+ if (decl == B_TRUE) {
base = ctf_add_forward(cup->cu_ctfp, isroot, name, kind);
} else if (kind == CTF_K_STRUCT) {
base = ctf_add_struct(cup->cu_ctfp, isroot, name);
} else {
base = ctf_add_union(cup->cu_ctfp, isroot, name);
}
- ctf_dprintf("added sou %s (%d) (%d)\n", name, kind, base);
+ ctf_dprintf("added sou %s (%d) (%ld) forward=%d\n",
+ name, kind, base, decl == B_TRUE);
if (name != NULL)
ctf_free(name, strlen(name) + 1);
if (base == CTF_ERR)
@@ -1545,7 +1611,9 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar)
}
}
- if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) {
+ DWARF_LOCK(cup);
+ ret = dwarf_whatform(attr, &form, &derr);
+ if (ret != DW_DLV_OK) {
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"failed to get DW_AT_upper_bound attribute form: %s\n",
dwarf_errmsg(derr));
@@ -1606,7 +1674,8 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar)
ret = ECTF_CONVBKERR;
done:
- dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR);
+ DWARF_UNLOCK(cup);
+ ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR);
return (ret);
}
@@ -2219,11 +2288,13 @@ ctf_dwarf_convert_function(ctf_cu_t *cup, Dwarf_Die die)
}
ctf_dprintf("beginning work on function %s (die %llx)\n",
- name, ctf_die_offset(die));
+ name, ctf_die_offset(cup, die));
if ((ret = ctf_dwarf_boolean(cup, die, DW_AT_declaration, &b)) != 0) {
- if (ret != ENOENT)
+ if (ret != ENOENT) {
+ ctf_free(name, strlen(name) + 1);
return (ret);
+ }
} else if (b != 0) {
/*
* GCC7 at least creates empty DW_AT_declarations for functions
@@ -2233,7 +2304,8 @@ ctf_dwarf_convert_function(ctf_cu_t *cup, Dwarf_Die die)
* DW_TAG_subprogram that is more complete.
*/
ctf_dprintf("ignoring declaration of function %s (die %llx)\n",
- name, ctf_die_offset(die));
+ name, ctf_die_offset(cup, die));
+ ctf_free(name, strlen(name) + 1);
return (0);
}
@@ -2347,7 +2419,7 @@ ctf_dwarf_convert_variable(ctf_cu_t *cup, Dwarf_Die die)
if ((ret = ctf_dwarf_offset(cup, tdie, &offset)) != 0)
return (ret);
ctf_dprintf("die 0x%llx DW_AT_specification -> die 0x%llx\n",
- ctf_die_offset(die), ctf_die_offset(tdie));
+ ctf_die_offset(cup, die), ctf_die_offset(cup, tdie));
die = tdie;
} else if (ret != ENOENT) {
return (ret);
@@ -2853,53 +2925,58 @@ ctf_dwarf_conv_weaks(ctf_cu_t *cup)
return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_weaks_cb, cup));
}
-/* ARGSUSED */
static int
ctf_dwarf_convert_one(void *arg, void *unused)
{
int ret;
ctf_file_t *dedup;
ctf_cu_t *cup = arg;
+ const char *name = cup->cu_name != NULL ? cup->cu_name : "NULL";
- ctf_dprintf("converting die: %s\n", cup->cu_name);
- ctf_dprintf("max offset: %x\n", cup->cu_maxoff);
VERIFY(cup != NULL);
+ if ((ret = ctf_dwarf_init_die(cup)) != 0)
+ return (ret);
+
+ ctf_dprintf("converting die: %s - max offset: %x\n", name,
+ cup->cu_maxoff);
+
ret = ctf_dwarf_convert_die(cup, cup->cu_cu);
- ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", cup->cu_name,
+ ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", name,
ret);
- if (ret != 0) {
+ if (ret != 0)
return (ret);
- }
+
if (ctf_update(cup->cu_ctfp) != 0) {
return (ctf_dwarf_error(cup, cup->cu_ctfp, 0,
"failed to update output ctf container"));
}
ret = ctf_dwarf_fixup_die(cup, B_FALSE);
- ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cup->cu_name,
+ ctf_dprintf("ctf_dwarf_fixup_die (%s, FALSE) returned %d\n", name,
ret);
- if (ret != 0) {
+ if (ret != 0)
return (ret);
- }
+
if (ctf_update(cup->cu_ctfp) != 0) {
return (ctf_dwarf_error(cup, cup->cu_ctfp, 0,
"failed to update output ctf container"));
}
ret = ctf_dwarf_fixup_die(cup, B_TRUE);
- ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cup->cu_name,
+ ctf_dprintf("ctf_dwarf_fixup_die (%s, TRUE) returned %d\n", name,
ret);
- if (ret != 0) {
+ if (ret != 0)
return (ret);
- }
+
if (ctf_update(cup->cu_ctfp) != 0) {
return (ctf_dwarf_error(cup, cup->cu_ctfp, 0,
"failed to update output ctf container"));
}
-
if ((ret = ctf_dwarf_conv_funcvars(cup)) != 0) {
+ ctf_dprintf("ctf_dwarf_conv_funcvars (%s) returned %d\n",
+ name, ret);
return (ctf_dwarf_error(cup, NULL, ret,
"failed to convert strong functions and variables"));
}
@@ -2911,6 +2988,8 @@ ctf_dwarf_convert_one(void *arg, void *unused)
if (cup->cu_doweaks == B_TRUE) {
if ((ret = ctf_dwarf_conv_weaks(cup)) != 0) {
+ ctf_dprintf("ctf_dwarf_conv_weaks (%s) returned %d\n",
+ name, ret);
return (ctf_dwarf_error(cup, NULL, ret,
"failed to convert weak functions and variables"));
}
@@ -2921,30 +3000,26 @@ ctf_dwarf_convert_one(void *arg, void *unused)
}
}
- ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", cup->cu_name);
+ ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", name);
ctf_dprintf("adding inputs for dedup\n");
if ((ret = ctf_merge_add(cup->cu_cmh, cup->cu_ctfp)) != 0) {
return (ctf_dwarf_error(cup, NULL, ret,
"failed to add inputs for merge"));
}
- ctf_dprintf("starting dedup of %s\n", cup->cu_name);
+ ctf_dprintf("starting dedup of %s\n", name);
if ((ret = ctf_merge_dedup(cup->cu_cmh, &dedup)) != 0) {
return (ctf_dwarf_error(cup, NULL, ret,
"failed to deduplicate die"));
}
+
ctf_close(cup->cu_ctfp);
cup->cu_ctfp = dedup;
- ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", cup->cu_name);
+ ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", name);
return (0);
}
-/*
- * Note, we expect that if we're returning a ctf_file_t from one of the dies,
- * say in the single node case, it's been saved and the entry here has been set
- * to NULL, which ctf_close happily ignores.
- */
static void
ctf_dwarf_free_die(ctf_cu_t *cup)
{
@@ -2953,13 +3028,18 @@ ctf_dwarf_free_die(ctf_cu_t *cup)
ctf_dwbitf_t *cdb, *ndb;
ctf_dwmap_t *map;
void *cookie;
- Dwarf_Error derr;
ctf_dprintf("Beginning to free die: %p\n", cup);
+
+ VERIFY3P(cup->cu_elf, !=, NULL);
cup->cu_elf = NULL;
+
ctf_dprintf("Trying to free name: %p\n", cup->cu_name);
- if (cup->cu_name != NULL)
+ if (cup->cu_name != NULL) {
ctf_free(cup->cu_name, strlen(cup->cu_name) + 1);
+ cup->cu_name = NULL;
+ }
+
ctf_dprintf("Trying to free merge handle: %p\n", cup->cu_cmh);
if (cup->cu_cmh != NULL) {
ctf_merge_fini(cup->cu_cmh);
@@ -2990,35 +3070,25 @@ ctf_dwarf_free_die(ctf_cu_t *cup)
ctf_free(cdb, sizeof (ctf_dwbitf_t));
}
- ctf_dprintf("Trying to clean up dwarf_t: %p\n", cup->cu_dwarf);
- if (cup->cu_dwarf != NULL)
- (void) dwarf_finish(cup->cu_dwarf, &derr);
- cup->cu_dwarf = NULL;
- ctf_close(cup->cu_ctfp);
+ if (cup->cu_ctfp != NULL) {
+ ctf_close(cup->cu_ctfp);
+ cup->cu_ctfp = NULL;
+ }
cookie = NULL;
- while ((map = avl_destroy_nodes(&cup->cu_map, &cookie)) != NULL) {
+ while ((map = avl_destroy_nodes(&cup->cu_map, &cookie)) != NULL)
ctf_free(map, sizeof (ctf_dwmap_t));
- }
avl_destroy(&cup->cu_map);
cup->cu_errbuf = NULL;
-}
-
-static void
-ctf_dwarf_free_dies(ctf_cu_t *cdies, int ndies)
-{
- int i;
- ctf_dprintf("Beginning to free dies\n");
- for (i = 0; i < ndies; i++) {
- ctf_dwarf_free_die(&cdies[i]);
+ if (cup->cu_cu != NULL) {
+ ctf_dwarf_dealloc(cup, cup->cu_cu, DW_DLA_DIE);
+ cup->cu_cu = NULL;
}
-
- ctf_free(cdies, sizeof (ctf_cu_t) * ndies);
}
static int
-ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
+ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, uint_t *ndies,
char *errbuf, size_t errlen)
{
int ret;
@@ -3049,88 +3119,146 @@ ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
return (0);
}
+/*
+ * Fill out just enough of each ctf_cu_t for the conversion process to
+ * be able to finish the rest in a (potentially) multithreaded context.
+ */
static int
-ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
- size_t errlen)
+ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw,
+ mutex_t *dwlock, Dwarf_Error *derr, uint_t ndies, ctf_cu_t *cdies,
+ uint_t flags, char *errbuf, size_t errlen)
{
- int ret;
Dwarf_Unsigned hdrlen, abboff, nexthdr;
Dwarf_Half addrsz, vers;
Dwarf_Unsigned offset = 0;
- Dwarf_Error derr;
+ uint_t added = 0;
+ int ret, i = 0;
- while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, &vers,
- &abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) {
+ while ((ret = dwarf_next_cu_header(dw, &hdrlen, &vers, &abboff,
+ &addrsz, &nexthdr, derr)) != DW_DLV_NO_ENTRY) {
+ Dwarf_Die cu;
+ ctf_cu_t *cup;
char *name;
- Dwarf_Die cu, child;
- /* Based on the counting above, we should be good to go */
- VERIFY(ret == DW_DLV_OK);
- if (ndie > 0) {
- ndie--;
- offset = nexthdr;
- continue;
+ VERIFY3U(i, <, ndies);
+
+ cup = &cdies[i++];
+
+ cup->cu_fd = fd;
+ cup->cu_elf = elf;
+ cup->cu_dwarf = dw;
+ cup->cu_errbuf = errbuf;
+ cup->cu_errlen = errlen;
+ cup->cu_dwarf = dw;
+ if (ndies > 1) {
+ /*
+ * Only need to lock calls into libdwarf if there are
+ * multiple CUs.
+ */
+ cup->cu_dwlock = dwlock;
+ cup->cu_doweaks = B_FALSE;
+ } else {
+ cup->cu_doweaks = B_TRUE;
}
- /*
- * Compilers are apparently inconsistent. Some emit no DWARF for
- * empty files and others emit empty compilation unit.
- */
cup->cu_voidtid = CTF_ERR;
cup->cu_longtid = CTF_ERR;
- cup->cu_elf = elf;
+ cup->cu_cuoff = offset;
cup->cu_maxoff = nexthdr - 1;
cup->cu_vers = vers;
cup->cu_addrsz = addrsz;
- cup->cu_ctfp = ctf_fdcreate(fd, &ret);
- if (cup->cu_ctfp == NULL)
- return (ret);
-
- avl_create(&cup->cu_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t),
- offsetof(ctf_dwmap_t, cdm_avl));
- cup->cu_errbuf = errbuf;
- cup->cu_errlen = errlen;
- bzero(&cup->cu_vars, sizeof (ctf_list_t));
- bzero(&cup->cu_funcs, sizeof (ctf_list_t));
- bzero(&cup->cu_bitfields, sizeof (ctf_list_t));
-
- if ((ret = ctf_dwarf_die_elfenc(elf, cup, errbuf,
- errlen)) != 0)
- return (ret);
- if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0)
+ if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0) {
+ ctf_dprintf("cu %d - no cu %d\n", i, ret);
return (ret);
-
- if (cu == NULL) {
- (void) snprintf(errbuf, errlen,
- "file does not contain DWARF data");
- return (ECTF_CONVNODEBUG);
}
- if ((ret = ctf_dwarf_child(cup, cu, &child)) != 0)
- return (ret);
-
- if (child == NULL) {
- (void) snprintf(errbuf, errlen,
+ if (cu == NULL) {
+ ctf_dprintf("cu %d - no cu data\n", i);
+ (void) snprintf(cup->cu_errbuf, cup->cu_errlen,
"file does not contain DWARF data");
return (ECTF_CONVNODEBUG);
}
- cup->cu_cuoff = offset;
- cup->cu_cu = child;
-
- if ((cup->cu_cmh = ctf_merge_init(fd, &ret)) == NULL)
- return (ret);
-
if (ctf_dwarf_string(cup, cu, DW_AT_name, &name) == 0) {
size_t len = strlen(name) + 1;
char *b = basename(name);
+
cup->cu_name = strdup(b);
ctf_free(name, len);
+ if (cup->cu_name == NULL)
+ return (ENOMEM);
}
- break;
+
+ ret = ctf_dwarf_child(cup, cu, &cup->cu_cu);
+ dwarf_dealloc(cup->cu_dwarf, cu, DW_DLA_DIE);
+ if (ret != 0) {
+ ctf_dprintf("cu %d - no child '%s' %d\n",
+ i, cup->cu_name != NULL ? cup->cu_name : "NULL",
+ ret);
+ return (ret);
+ }
+
+ if (cup->cu_cu == NULL) {
+ size_t len;
+
+ ctf_dprintf("cu %d - no child data '%s' %d\n",
+ i, cup->cu_name != NULL ? cup->cu_name : "NULL",
+ ret);
+ if (cup->cu_name != NULL &&
+ (len = strlen(cup->cu_name)) > 2 &&
+ strncmp(".c", &cup->cu_name[len - 2], 2) == 0) {
+ /*
+ * Missing DEBUG data for a .c file, return an
+ * error unless this is permitted.
+ */
+ if (!(flags & CTF_ALLOW_MISSING_DEBUG)) {
+ (void) snprintf(
+ cup->cu_errbuf, cup->cu_errlen,
+ "file %s is missing debug info",
+ cup->cu_name);
+ return (ECTF_CONVNODEBUG);
+ }
+ }
+ } else {
+ added++;
+ }
+
+ ctf_dprintf("Pre-initialised cu %d - '%s'\n", i,
+ cup->cu_name != NULL ? cup->cu_name : "NULL");
+
+ offset = nexthdr;
}
+ /*
+ * If none of the CUs had debug data, return an error.
+ */
+ if (added == 0)
+ return (ECTF_CONVNODEBUG);
+
+ return (0);
+}
+
+static int
+ctf_dwarf_init_die(ctf_cu_t *cup)
+{
+ int ret;
+
+ cup->cu_ctfp = ctf_fdcreate(cup->cu_fd, &ret);
+ if (cup->cu_ctfp == NULL)
+ return (ret);
+
+ avl_create(&cup->cu_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t),
+ offsetof(ctf_dwmap_t, cdm_avl));
+
+ if ((ret = ctf_dwarf_die_elfenc(cup->cu_elf, cup,
+ cup->cu_errbuf, cup->cu_errlen)) != 0) {
+ return (ret);
+ }
+
+ if ((cup->cu_cmh = ctf_merge_init(cup->cu_fd, &ret)) == NULL)
+ return (ret);
+
return (0);
}
@@ -3165,8 +3293,10 @@ c_source_has_debug(const char *file, ctf_cu_t *cus, size_t nr_cus)
return (B_TRUE);
for (size_t i = 0; i < nr_cus; i++) {
- if (strcmp(basename, cus[i].cu_name) == 0)
+ if (cus[i].cu_name != NULL &&
+ strcmp(basename, cus[i].cu_name) == 0) {
return (B_TRUE);
+ }
}
return (B_FALSE);
@@ -3239,7 +3369,7 @@ ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf,
if (!c_source_has_debug(file, cus, nr_cus)) {
(void) snprintf(errmsg, errlen,
- "file %s is missing debug info\n", file);
+ "file %s is missing debug info", file);
return (ECTF_CONVNODEBUG);
}
}
@@ -3247,15 +3377,126 @@ ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf,
return (0);
}
+static int
+ctf_dwarf_convert_batch(uint_t start, uint_t end, int fd, uint_t nthrs,
+ workq_t *wqp, ctf_cu_t *cdies, ctf_file_t **fpp)
+{
+ ctf_file_t *fpprev = NULL;
+ uint_t i, added;
+ ctf_cu_t *cup;
+ int ret, err;
+
+ ctf_dprintf("Processing CU batch %u - %u\n", start, end - 1);
+
+ added = 0;
+ for (i = start; i < end; i++) {
+ cup = &cdies[i];
+ if (cup->cu_cu == NULL)
+ continue;
+ ctf_dprintf("adding cu %s: %p, %x %x\n",
+ cup->cu_name != NULL ? cup->cu_name : "NULL",
+ cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff);
+ if (workq_add(wqp, cup) == -1) {
+ err = errno;
+ goto out;
+ }
+ added++;
+ }
+
+ /*
+ * No debug data found in this batch, move on to the next.
+ * NB: ctf_dwarf_preinit_dies() has already checked that there is at
+ * least one CU with debug data present.
+ */
+ if (added == 0) {
+ err = 0;
+ goto out;
+ }
+
+ ctf_dprintf("Running conversion phase\n");
+
+ /* Run the conversions */
+ ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, &err);
+ if (ret == WORKQ_ERROR) {
+ err = errno;
+ goto out;
+ } else if (ret == WORKQ_UERROR) {
+ ctf_dprintf("internal convert failed: %s\n",
+ ctf_errmsg(err));
+ goto out;
+ }
+
+ ctf_dprintf("starting merge phase\n");
+
+ ctf_merge_t *cmp = ctf_merge_init(fd, &err);
+ if (cmp == NULL)
+ goto out;
+
+ if ((err = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
+ ctf_merge_fini(cmp);
+ goto out;
+ }
+
+ /*
+ * If we have the result of a previous merge then add it as an input to
+ * the next one.
+ */
+ if (*fpp != NULL) {
+ ctf_dprintf("adding previous merge CU\n");
+ fpprev = *fpp;
+ *fpp = NULL;
+ if ((err = ctf_merge_add(cmp, fpprev)) != 0) {
+ ctf_merge_fini(cmp);
+ goto out;
+ }
+ }
+
+ ctf_dprintf("adding CUs to merge\n");
+ for (i = start; i < end; i++) {
+ cup = &cdies[i];
+ if (cup->cu_cu == NULL)
+ continue;
+ if ((err = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
+ ctf_merge_fini(cmp);
+ *fpp = NULL;
+ goto out;
+ }
+ }
+
+ ctf_dprintf("performing merge\n");
+ err = ctf_merge_merge(cmp, fpp);
+ if (err != 0) {
+ ctf_dprintf("failed merge!\n");
+ *fpp = NULL;
+ ctf_merge_fini(cmp);
+ goto out;
+ }
+
+ ctf_merge_fini(cmp);
+
+ ctf_dprintf("freeing CUs\n");
+ for (i = start; i < end; i++) {
+ cup = &cdies[i];
+ ctf_dprintf("freeing cu %d\n", i);
+ ctf_dwarf_free_die(cup);
+ }
+
+out:
+ ctf_close(fpprev);
+ return (err);
+}
+
int
-ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, uint_t flags,
+ctf_dwarf_convert(int fd, Elf *elf, uint_t bsize, uint_t nthrs, uint_t flags,
ctf_file_t **fpp, char *errbuf, size_t errlen)
{
- int err, ret, ndies, i;
+ int err, ret;
+ uint_t ndies, i;
Dwarf_Debug dw;
Dwarf_Error derr;
ctf_cu_t *cdies = NULL, *cup;
workq_t *wqp = NULL;
+ mutex_t dwlock = ERRORCHECKMUTEX;
*fpp = NULL;
@@ -3288,116 +3529,74 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, uint_t flags,
if (ndies == 0) {
(void) snprintf(errbuf, errlen,
"file does not contain DWARF data\n");
+ (void) dwarf_finish(dw, &derr);
return (ECTF_CONVNODEBUG);
}
- (void) dwarf_finish(dw, &derr);
cdies = ctf_alloc(sizeof (ctf_cu_t) * ndies);
if (cdies == NULL) {
+ (void) dwarf_finish(dw, &derr);
return (ENOMEM);
}
bzero(cdies, sizeof (ctf_cu_t) * ndies);
- for (i = 0; i < ndies; i++) {
- cup = &cdies[i];
- ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL,
- &cup->cu_dwarf, &derr);
- if (ret != 0) {
- ctf_free(cdies, sizeof (ctf_cu_t) * ndies);
- (void) snprintf(errbuf, errlen,
- "failed to initialize DWARF: %s\n",
- dwarf_errmsg(derr));
- return (ECTF_CONVBKERR);
- }
-
- err = ctf_dwarf_init_die(fd, elf, cup, i, errbuf, errlen);
- if (err != 0)
- goto out;
-
- cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE;
+ if ((err = ctf_dwarf_preinit_dies(fd, elf, dw, &dwlock, &derr,
+ ndies, cdies, flags, errbuf, errlen)) != 0) {
+ goto out;
}
if (!(flags & CTF_ALLOW_MISSING_DEBUG) &&
(err = ctf_dwarf_check_missing(cdies, ndies,
- elf, errbuf, errlen)) != 0)
- goto out;
-
- /*
- * If we only have one compilation unit, there's no reason to use
- * multiple threads, even if the user requested them. After all, they
- * just gave us an upper bound.
- */
- if (ndies == 1)
- nthrs = 1;
-
- if (workq_init(&wqp, nthrs) == -1) {
- err = errno;
+ elf, errbuf, errlen)) != 0) {
goto out;
}
- for (i = 0; i < ndies; i++) {
- cup = &cdies[i];
- ctf_dprintf("adding cu %s: %p, %x %x\n", cup->cu_name,
- cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff);
- if (workq_add(wqp, cup) == -1) {
- err = errno;
+ /* Only one cu, no merge required */
+ if (ndies == 1) {
+ cup = cdies;
+
+ if ((err = ctf_dwarf_convert_one(cup, NULL)) != 0)
goto out;
- }
+
+ *fpp = cup->cu_ctfp;
+ cup->cu_ctfp = NULL;
+ ctf_dwarf_free_die(cup);
+ goto success;
}
- ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, &err);
- if (ret == WORKQ_ERROR) {
+ /*
+ * There's no need to have either more threads or a batch size larger
+ * than the total number of dies, even if the user requested them.
+ */
+ nthrs = min(ndies, nthrs);
+ bsize = min(ndies, bsize);
+
+ if (workq_init(&wqp, nthrs) == -1) {
err = errno;
goto out;
- } else if (ret == WORKQ_UERROR) {
- ctf_dprintf("internal convert failed: %s\n",
- ctf_errmsg(err));
- goto out;
}
- ctf_dprintf("Determining next phase: have %d CUs\n", ndies);
- if (ndies != 1) {
- ctf_merge_t *cmp;
-
- cmp = ctf_merge_init(fd, &err);
- if (cmp == NULL)
- goto out;
-
- ctf_dprintf("setting threads\n");
- if ((err = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
- ctf_merge_fini(cmp);
- goto out;
- }
-
- for (i = 0; i < ndies; i++) {
- cup = &cdies[i];
- if ((err = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
- ctf_merge_fini(cmp);
- goto out;
- }
- }
-
- ctf_dprintf("performing merge\n");
- err = ctf_merge_merge(cmp, fpp);
+ /*
+ * In order to avoid exhausting memory limits when converting files
+ * with a large number of dies, we process them in batches.
+ */
+ for (i = 0; i < ndies; i += bsize) {
+ err = ctf_dwarf_convert_batch(i, min(i + bsize, ndies),
+ fd, nthrs, wqp, cdies, fpp);
if (err != 0) {
- ctf_dprintf("failed merge!\n");
*fpp = NULL;
- ctf_merge_fini(cmp);
goto out;
}
- ctf_merge_fini(cmp);
- err = 0;
- ctf_dprintf("successfully converted!\n");
- } else {
- err = 0;
- *fpp = cdies->cu_ctfp;
- cdies->cu_ctfp = NULL;
- ctf_dprintf("successfully converted!\n");
}
+success:
+ err = 0;
+ ctf_dprintf("successfully converted!\n");
+
out:
+ (void) dwarf_finish(dw, &derr);
workq_fini(wqp);
- ctf_dwarf_free_dies(cdies, ndies);
+ ctf_free(cdies, sizeof (ctf_cu_t) * ndies);
return (err);
}
diff --git a/usr/src/lib/libctf/common/ctf_merge.c b/usr/src/lib/libctf/common/ctf_merge.c
index a18a2f46ef..a5888de8c0 100644
--- a/usr/src/lib/libctf/common/ctf_merge.c
+++ b/usr/src/lib/libctf/common/ctf_merge.c
@@ -129,10 +129,11 @@ ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
{
ctf_merge_types_t *cmp = arg;
ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
+ uint_t kind;
if (same == B_TRUE) {
if (ctf_type_kind(ifp, iid) == CTF_K_FORWARD &&
- ctf_type_kind(ofp, oid) != CTF_K_FORWARD) {
+ (kind = ctf_type_kind(ofp, oid)) != CTF_K_FORWARD) {
VERIFY(cmt[oid].cmt_map == 0);
/*
@@ -153,8 +154,8 @@ ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
cmt[oid].cmt_map = iid;
cmt[oid].cmt_forward = B_TRUE;
- ctf_dprintf("merge diff forward mapped %d->%d\n", oid,
- iid);
+ ctf_dprintf("merge diff forward mapped %ld->%ld (%u)\n",
+ oid, iid, kind);
return;
}
@@ -421,7 +422,7 @@ ctf_merge_add_func(ctf_merge_types_t *cmp, ctf_id_t id)
}
static int
-ctf_merge_add_forward(ctf_merge_types_t *cmp, ctf_id_t id)
+ctf_merge_add_forward(ctf_merge_types_t *cmp, ctf_id_t id, uint_t kind)
{
int ret, flags;
const ctf_type_t *tp;
@@ -434,14 +435,7 @@ ctf_merge_add_forward(ctf_merge_types_t *cmp, ctf_id_t id)
else
flags = CTF_ADD_NONROOT;
- /*
- * ctf_add_forward tries to check to see if a given forward already
- * exists in one of its hash tables. If we're here then we know that we
- * have a forward in a container that isn't present in another.
- * Therefore, we choose a token hash table to satisfy the API choice
- * here.
- */
- ret = ctf_add_forward(cmp->cm_out, flags, name, CTF_K_STRUCT);
+ ret = ctf_add_forward(cmp->cm_out, flags, name, kind);
if (ret == CTF_ERR)
return (CTF_ERR);
@@ -494,19 +488,32 @@ ctf_merge_add_sou(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
else
suid = ctf_add_union(cmp->cm_out, flags, name);
+ ctf_dprintf("added sou \"%s\" as (%d) %d->%d\n", name, kind, id, suid);
+
if (suid == CTF_ERR)
return (suid);
- /*
- * If this is a forward reference then its mapping should already
- * exist.
- */
if (forward == B_FALSE) {
VERIFY(cmp->cm_tmap[id].cmt_map == 0);
cmp->cm_tmap[id].cmt_map = suid;
- ctf_dprintf("added sou \"%s\" as (%d) %d->%d\n", name, kind, id,
- suid);
} else {
+ /*
+ * If this is a forward reference then its mapping should
+ * already exist.
+ */
+ if (cmp->cm_tmap[id].cmt_map != suid) {
+ ctf_dprintf(
+ "mismatch sou \"%s\" as (%d) %d->%d (exp %d)\n",
+ name, kind, id, suid, cmp->cm_tmap[id].cmt_map);
+ ctf_hash_dump("src structs",
+ &cmp->cm_src->ctf_structs, cmp->cm_src);
+ ctf_hash_dump("src unions",
+ &cmp->cm_src->ctf_unions, cmp->cm_src);
+ ctf_hash_dump("out structs",
+ &cmp->cm_out->ctf_structs, cmp->cm_out);
+ ctf_hash_dump("out unions",
+ &cmp->cm_out->ctf_unions, cmp->cm_out);
+ }
VERIFY(cmp->cm_tmap[id].cmt_map == suid);
}
cmp->cm_tmap[id].cmt_fixup = B_TRUE;
@@ -551,9 +558,27 @@ ctf_merge_add_type(ctf_merge_types_t *cmp, ctf_id_t id)
case CTF_K_FUNCTION:
ret = ctf_merge_add_func(cmp, id);
break;
- case CTF_K_FORWARD:
- ret = ctf_merge_add_forward(cmp, id);
+ case CTF_K_FORWARD: {
+ const ctf_type_t *tp;
+ uint_t kind;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+
+ /*
+ * For forward declarations, ctt_type is the CTF_K_*
+ * kind for the tag. Older versions of the CTF tools may
+ * not have filled this in so if ctt_type is unknown or
+ * invalid, treat it as a struct. This mirrors the logic in
+ * ctf_bufopen().
+ */
+
+ kind = tp->ctt_type;
+ if (kind == CTF_K_UNKNOWN || kind >= CTF_K_MAX)
+ kind = CTF_K_STRUCT;
+
+ ret = ctf_merge_add_forward(cmp, id, kind);
break;
+ }
case CTF_K_STRUCT:
case CTF_K_UNION:
ret = ctf_merge_add_sou(cmp, id, B_FALSE);
@@ -690,6 +715,7 @@ ctf_merge_common(ctf_merge_types_t *cmp)
/* Pass 1 */
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
if (cmp->cm_tmap[i].cmt_forward == B_TRUE) {
+ ctf_dprintf("Forward %d\n", i);
ret = ctf_merge_add_sou(cmp, i, B_TRUE);
if (ret != 0) {
return (ret);
@@ -1566,11 +1592,11 @@ ctf_dedup_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
while (cmt[oid].cmt_missing == B_FALSE)
oid = cmt[oid].cmt_map;
cmt[iid].cmt_map = oid;
- ctf_dprintf("%d->%d \n", iid, oid);
+ ctf_dprintf("dedup %d->%d \n", iid, oid);
} else {
VERIFY(cmt[iid].cmt_map == 0);
cmt[iid].cmt_missing = B_TRUE;
- ctf_dprintf("%d is missing\n", iid);
+ ctf_dprintf("dedup %d is missing\n", iid);
}
}
diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h
index 5c88b9454d..0921a3ec1a 100644
--- a/usr/src/lib/libctf/common/libctf_impl.h
+++ b/usr/src/lib/libctf/common/libctf_impl.h
@@ -29,9 +29,9 @@
extern "C" {
#endif
-typedef int (*ctf_convert_f)(int, Elf *, uint_t, uint_t,
+typedef int (*ctf_convert_f)(int, Elf *, uint_t, uint_t, uint_t,
ctf_file_t **, char *, size_t);
-extern int ctf_dwarf_convert(int, Elf *, uint_t, uint_t,
+extern int ctf_dwarf_convert(int, Elf *, uint_t, uint_t, uint_t,
ctf_file_t **, char *, size_t);
/*