summaryrefslogtreecommitdiff
path: root/usr/src/lib/libctf
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libctf')
-rw-r--r--usr/src/lib/libctf/common/ctf_convert.c142
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c485
-rw-r--r--usr/src/lib/libctf/common/ctf_lib.c125
-rw-r--r--usr/src/lib/libctf/common/ctf_merge.c496
-rw-r--r--usr/src/lib/libctf/common/libctf.h20
-rw-r--r--usr/src/lib/libctf/common/libctf_impl.h22
-rw-r--r--usr/src/lib/libctf/common/mapfile-vers4
7 files changed, 809 insertions, 485 deletions
diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c
index cbb4d48c76..9441aa6ed7 100644
--- a/usr/src/lib/libctf/common/ctf_convert.c
+++ b/usr/src/lib/libctf/common/ctf_convert.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -21,6 +21,7 @@
*/
#include <libctf_impl.h>
+#include <assert.h>
#include <gelf.h>
ctf_convert_f ctf_converters[] = {
@@ -29,86 +30,81 @@ ctf_convert_f ctf_converters[] = {
#define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f))
-typedef enum ctf_convert_source {
- CTFCONV_SOURCE_NONE = 0x0,
- CTFCONV_SOURCE_UNKNOWN = 0x01,
- CTFCONV_SOURCE_C = 0x02,
- CTFCONV_SOURCE_S = 0x04
-} ctf_convert_source_t;
-
-static void
-ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types)
+ctf_hsc_ret_t
+ctf_has_c_source(Elf *elf, char *errmsg, size_t errlen)
{
- int i;
- Elf_Scn *scn = NULL, *strscn;
- *types = CTFCONV_SOURCE_NONE;
- GElf_Shdr shdr;
+ ctf_hsc_ret_t ret = CHR_NO_C_SOURCE;
+ Elf_Scn *scn, *strscn;
Elf_Data *data, *strdata;
+ GElf_Shdr shdr;
+ ulong_t i;
+ scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
-
- if (gelf_getshdr(scn, &shdr) == NULL)
- return;
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to get section header: %s",
+ elf_errmsg(elf_errno()));
+ return (CHR_ERROR);
+ }
if (shdr.sh_type == SHT_SYMTAB)
break;
}
if (scn == NULL)
- return;
+ return (CHR_NO_C_SOURCE);
- if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
- return;
+ if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) {
+ (void) snprintf(errmsg, errlen, "failed to get str section: %s",
+ elf_errmsg(elf_errno()));
+ return (CHR_ERROR);
+ }
- if ((data = elf_getdata(scn, NULL)) == NULL)
- return;
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ (void) snprintf(errmsg, errlen, "failed to read section: %s",
+ elf_errmsg(elf_errno()));
+ return (CHR_ERROR);
+ }
- if ((strdata = elf_getdata(strscn, NULL)) == NULL)
- return;
+ if ((strdata = elf_getdata(strscn, NULL)) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to read string table: %s", elf_errmsg(elf_errno()));
+ return (CHR_ERROR);
+ }
for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
GElf_Sym sym;
const char *file;
size_t len;
- if (gelf_getsym(data, i, &sym) == NULL)
- return;
+ if (gelf_getsym(data, i, &sym) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to read sym %lu: %s",
+ i, elf_errmsg(elf_errno()));
+ return (CHR_ERROR);
+ }
if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
continue;
file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
len = strlen(file);
- if (len < 2 || file[len - 2] != '.') {
- *types |= CTFCONV_SOURCE_UNKNOWN;
- continue;
- }
-
- switch (file[len - 1]) {
- case 'c':
- *types |= CTFCONV_SOURCE_C;
- break;
- case 'h':
- /* We traditionally ignore header files... */
- break;
- case 's':
- *types |= CTFCONV_SOURCE_S;
- break;
- default:
- *types |= CTFCONV_SOURCE_UNKNOWN;
+ if (len >= 2 && strncmp(".c", &file[len - 2], 2) == 0) {
+ ret = CHR_HAS_C_SOURCE;
break;
}
}
+
+ return (ret);
}
-static ctf_file_t *
+ctf_file_t *
ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
int *errp, char *errbuf, size_t errlen)
{
int err, i;
ctf_file_t *fp = NULL;
- boolean_t notsup = B_TRUE;
- ctf_convert_source_t type;
if (errp == NULL)
errp = &err;
@@ -118,7 +114,7 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
return (NULL);
}
- if (flags & ~CTF_CONVERT_F_IGNNONC) {
+ if (flags & ~CTF_ALLOW_MISSING_DEBUG) {
*errp = EINVAL;
return (NULL);
}
@@ -128,49 +124,35 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
return (NULL);
}
- ctf_convert_ftypes(elf, &type);
- ctf_dprintf("got types: %d\n", type);
- if (flags & CTF_CONVERT_F_IGNNONC) {
- if (type == CTFCONV_SOURCE_NONE ||
- (type & CTFCONV_SOURCE_UNKNOWN)) {
- *errp = ECTF_CONVNOCSRC;
- return (NULL);
- }
+ switch (ctf_has_c_source(elf, errbuf, errlen)) {
+ case CHR_ERROR:
+ *errp = ECTF_ELF;
+ return (NULL);
+
+ case CHR_NO_C_SOURCE:
+ *errp = ECTF_CONVNOCSRC;
+ return (NULL);
+
+ default:
+ break;
}
for (i = 0; i < NCONVERTS; i++) {
- ctf_conv_status_t cs;
-
fp = NULL;
- cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf,
- errlen);
- if (cs == CTF_CONV_SUCCESS) {
- notsup = B_FALSE;
- break;
- }
- if (cs == CTF_CONV_ERROR) {
- fp = NULL;
- notsup = B_FALSE;
+ err = ctf_converters[i](fd, elf, nthrs, flags,
+ &fp, errbuf, errlen);
+
+ if (err != ECTF_CONVNODEBUG)
break;
- }
}
- if (notsup == B_TRUE) {
- if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
- (type & CTFCONV_SOURCE_C) == 0) {
- *errp = ECTF_CONVNOCSRC;
- return (NULL);
- }
- *errp = ECTF_NOCONVBKEND;
+ if (err != 0) {
+ assert(fp == NULL);
+ *errp = err;
return (NULL);
}
- /*
- * Succsesful conversion.
- */
- if (fp != NULL) {
- if (label == NULL)
- label = "";
+ if (label != NULL) {
if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) {
*errp = ctf_errno(fp);
ctf_close(fp);
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
index 18be598ed9..aa55127d26 100644
--- a/usr/src/lib/libctf/common/ctf_dwarf.c
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -28,7 +28,7 @@
*/
/*
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
/*
@@ -282,9 +282,6 @@ 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 *);
-typedef int (ctf_dwarf_symtab_f)(ctf_cu_t *, const GElf_Sym *, ulong_t,
- const char *, const char *, void *);
-
/*
* 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
@@ -886,7 +883,7 @@ ctf_dwarf_dwarf_base(ctf_cu_t *cup, Dwarf_Die die, int *kindp,
break;
default:
(void) snprintf(cup->cu_errbuf, cup->cu_errlen,
- "encountered unkown DWARF encoding: %d", type);
+ "encountered unknown DWARF encoding: %d", type);
return (ECTF_CONVBKERR);
}
@@ -1781,6 +1778,7 @@ ctf_dwarf_convert_type(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp,
break;
default:
ctf_dprintf("ignoring tag type %x\n", tag);
+ *idp = CTF_ERR;
ret = 0;
break;
}
@@ -2166,126 +2164,132 @@ ctf_dwarf_fixup_die(ctf_cu_t *cup, boolean_t addpass)
return (0);
}
+/*
+ * The DWARF information about a symbol and the information in the symbol table
+ * may not be the same due to symbol reduction that is performed by ld due to a
+ * mapfile or other such directive. We process weak symbols at a later time.
+ *
+ * The following are the rules that we employ:
+ *
+ * 1. A DWARF function that is considered exported matches STB_GLOBAL entries
+ * with the same name.
+ *
+ * 2. A DWARF function that is considered exported matches STB_LOCAL entries
+ * with the same name and the same file. This case may happen due to mapfile
+ * reduction.
+ *
+ * 3. A DWARF function that is not considered exported matches STB_LOCAL entries
+ * with the same name and the same file.
+ *
+ * 4. A DWARF function that has the same name as the symbol table entry, but the
+ * files do not match. This is considered a 'fuzzy' match. This may also happen
+ * due to a mapfile reduction. Fuzzy matching is only used when we know that the
+ * file in question refers to the primary object. This is because when a symbol
+ * is reduced in a mapfile, it's always going to be tagged as a local value in
+ * the generated output and it is considered as to belong to the primary file
+ * which is the first STT_FILE symbol we see.
+ */
+static boolean_t
+ctf_dwarf_symbol_match(const char *symtab_file, const char *symtab_name,
+ uint_t symtab_bind, const char *dwarf_file, const char *dwarf_name,
+ boolean_t dwarf_global, boolean_t *is_fuzzy)
+{
+ *is_fuzzy = B_FALSE;
+
+ if (symtab_bind != STB_LOCAL && symtab_bind != STB_GLOBAL) {
+ return (B_FALSE);
+ }
+
+ if (strcmp(symtab_name, dwarf_name) != 0) {
+ return (B_FALSE);
+ }
+
+ if (symtab_bind == STB_GLOBAL) {
+ return (dwarf_global);
+ }
+
+ if (strcmp(symtab_file, dwarf_file) == 0) {
+ return (B_TRUE);
+ }
+
+ if (dwarf_global) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
static ctf_dwfunc_t *
ctf_dwarf_match_func(ctf_cu_t *cup, const char *file, const char *name,
- int bind)
+ uint_t bind, boolean_t primary)
{
- ctf_dwfunc_t *cdf;
+ ctf_dwfunc_t *cdf, *fuzzy = NULL;
if (bind == STB_WEAK)
return (NULL);
- /* Nothing we can do if we can't find a name to compare it to. */
if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
return (NULL);
for (cdf = ctf_list_next(&cup->cu_funcs); cdf != NULL;
cdf = ctf_list_next(cdf)) {
- if (bind == STB_GLOBAL && cdf->cdf_global == B_FALSE)
- continue;
- if (bind == STB_LOCAL && cdf->cdf_global == B_TRUE)
- continue;
- if (strcmp(name, cdf->cdf_name) != 0)
- continue;
- if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
- continue;
- return (cdf);
+ boolean_t is_fuzzy = B_FALSE;
+
+ if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
+ cdf->cdf_name, cdf->cdf_global, &is_fuzzy)) {
+ if (is_fuzzy) {
+ if (primary) {
+ fuzzy = cdf;
+ }
+ continue;
+ } else {
+ return (cdf);
+ }
+ }
}
- return (NULL);
+ return (fuzzy);
}
+
static ctf_dwvar_t *
ctf_dwarf_match_var(ctf_cu_t *cup, const char *file, const char *name,
- int bind)
+ uint_t bind, boolean_t primary)
{
- ctf_dwvar_t *cdv;
+ ctf_dwvar_t *cdv, *fuzzy = NULL;
+
+ if (bind == STB_WEAK)
+ return (NULL);
- /* Nothing we can do if we can't find a name to compare it to. */
if (bind == STB_LOCAL && (file == NULL || cup->cu_name == NULL))
return (NULL);
- ctf_dprintf("Still considering %s\n", name);
for (cdv = ctf_list_next(&cup->cu_vars); cdv != NULL;
cdv = ctf_list_next(cdv)) {
- if (bind == STB_GLOBAL && cdv->cdv_global == B_FALSE)
- continue;
- if (bind == STB_LOCAL && cdv->cdv_global == B_TRUE)
- continue;
- if (strcmp(name, cdv->cdv_name) != 0)
- continue;
- if (bind == STB_LOCAL && strcmp(file, cup->cu_name) != 0)
- continue;
- return (cdv);
- }
-
- return (NULL);
-}
-
-static int
-ctf_dwarf_symtab_iter(ctf_cu_t *cup, ctf_dwarf_symtab_f *func, void *arg)
-{
- int ret;
- ulong_t i;
- ctf_file_t *fp = cup->cu_ctfp;
- const char *file = NULL;
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- int type;
- GElf_Sym gsym;
- const GElf_Sym *gsymp;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- type = ELF32_ST_TYPE(symp->st_info);
- if (type == STT_FILE) {
- file = (char *)(strbase + symp->st_name);
- continue;
- }
- if (type != STT_OBJECT && type != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- gsym.st_name = symp->st_name;
- gsym.st_value = symp->st_value;
- gsym.st_size = symp->st_size;
- gsym.st_info = symp->st_info;
- gsym.st_other = symp->st_other;
- gsym.st_shndx = symp->st_shndx;
- gsymp = &gsym;
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- type = ELF64_ST_TYPE(symp->st_info);
- if (type == STT_FILE) {
- file = (char *)(strbase + symp->st_name);
- continue;
+ boolean_t is_fuzzy = B_FALSE;
+
+ if (ctf_dwarf_symbol_match(file, name, bind, cup->cu_name,
+ cdv->cdv_name, cdv->cdv_global, &is_fuzzy)) {
+ if (is_fuzzy) {
+ if (primary) {
+ fuzzy = cdv;
+ }
+ } else {
+ return (cdv);
}
- if (type != STT_OBJECT && type != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- gsymp = symp;
}
-
- ret = func(cup, gsymp, i, file, name, arg);
- if (ret != 0)
- return (ret);
}
- return (0);
+ return (fuzzy);
}
static int
-ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
- const char *file, const char *name, void *arg)
+ctf_dwarf_conv_funcvars_cb(const Elf64_Sym *symp, ulong_t idx,
+ const char *file, const char *name, boolean_t primary, void *arg)
{
- int ret, bind, type;
+ int ret;
+ uint_t bind, type;
+ ctf_cu_t *cup = arg;
bind = GELF_ST_BIND(symp->st_info);
type = GELF_ST_TYPE(symp->st_info);
@@ -2298,19 +2302,19 @@ ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
if (type == STT_OBJECT) {
ctf_dwvar_t *cdv = ctf_dwarf_match_var(cup, file, name,
- bind);
- ctf_dprintf("match for %s (%d): %p\n", name, idx, cdv);
+ bind, primary);
if (cdv == NULL)
return (0);
ret = ctf_add_object(cup->cu_ctfp, idx, cdv->cdv_type);
- ctf_dprintf("added object %s\n", name);
+ ctf_dprintf("added object %s->%ld\n", name, cdv->cdv_type);
} else {
ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cup, file, name,
- bind);
+ bind, primary);
if (cdf == NULL)
return (0);
ret = ctf_add_function(cup->cu_ctfp, idx, &cdf->cdf_fip,
cdf->cdf_argv);
+ ctf_dprintf("added function %s\n", name);
}
if (ret == CTF_ERR) {
@@ -2323,7 +2327,7 @@ ctf_dwarf_conv_funcvars_cb(ctf_cu_t *cup, const GElf_Sym *symp, ulong_t idx,
static int
ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
{
- return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_funcvars_cb, NULL));
+ return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_funcvars_cb, cup));
}
/*
@@ -2365,18 +2369,19 @@ ctf_dwarf_conv_funcvars(ctf_cu_t *cup)
* that we can consume.
*/
typedef struct ctf_dwarf_weak_arg {
- const GElf_Sym *cweak_symp;
+ const Elf64_Sym *cweak_symp;
const char *cweak_file;
boolean_t cweak_candidate;
ulong_t cweak_idx;
} ctf_dwarf_weak_arg_t;
static int
-ctf_dwarf_conv_check_weak(ctf_cu_t *cup, const GElf_Sym *symp,
- ulong_t idx, const char *file, const char *name, void *arg)
+ctf_dwarf_conv_check_weak(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
ctf_dwarf_weak_arg_t *cweak = arg;
- const GElf_Sym *wsymp = cweak->cweak_symp;
+
+ const Elf64_Sym *wsymp = cweak->cweak_symp;
ctf_dprintf("comparing weak to %s\n", name);
@@ -2476,11 +2481,12 @@ ctf_dwarf_duplicate_func(ctf_cu_t *cup, ulong_t idx, ulong_t matchidx)
}
static int
-ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
- ulong_t idx, const char *file, const char *name, void *arg)
+ctf_dwarf_conv_weaks_cb(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
int ret, type;
ctf_dwarf_weak_arg_t cweak;
+ ctf_cu_t *cup = arg;
/*
* We only care about weak symbols.
@@ -2503,7 +2509,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
ctf_dprintf("Trying to find weak equiv for %s\n", name);
- ret = ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_check_weak, &cweak);
+ ret = ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_check_weak, &cweak);
VERIFY(ret == 0 || ret == 1);
/*
@@ -2518,6 +2524,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
/*
* Now, finally go and add the type based on the match.
*/
+ ctf_dprintf("matched weak symbol %lu to %lu\n", idx, cweak.cweak_idx);
if (type == STT_OBJECT) {
ret = ctf_dwarf_duplicate_sym(cup, idx, cweak.cweak_idx);
} else {
@@ -2530,7 +2537,7 @@ ctf_dwarf_conv_weaks_cb(ctf_cu_t *cup, const GElf_Sym *symp,
static int
ctf_dwarf_conv_weaks(ctf_cu_t *cup)
{
- return (ctf_dwarf_symtab_iter(cup, ctf_dwarf_conv_weaks_cb, NULL));
+ return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_weaks_cb, cup));
}
/* ARGSUSED */
@@ -2601,20 +2608,21 @@ ctf_dwarf_convert_one(void *arg, void *unused)
}
}
- ctf_phase_dump(cup->cu_ctfp, "pre-dedup");
+ ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", cup->cu_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 merge\n");
+ ctf_dprintf("starting dedup of %s\n", cup->cu_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);
return (0);
}
@@ -2670,7 +2678,8 @@ ctf_dwarf_free_die(ctf_cu_t *cup)
}
ctf_dprintf("Trying to clean up dwarf_t: %p\n", cup->cu_dwarf);
- (void) dwarf_finish(cup->cu_dwarf, &derr);
+ if (cup->cu_dwarf != NULL)
+ (void) dwarf_finish(cup->cu_dwarf, &derr);
cup->cu_dwarf = NULL;
ctf_close(cup->cu_ctfp);
@@ -2720,13 +2729,6 @@ ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
*ndies = *ndies + 1;
}
- if (*ndies == 0) {
- (void) snprintf(errbuf, errlen,
- "file does not contain valid DWARF data: %s\n",
- dwarf_errmsg(*derr));
- return (ECTF_CONVBKERR);
- }
-
return (0);
}
@@ -2762,10 +2764,9 @@ ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
cup->cu_elf = elf;
cup->cu_maxoff = nexthdr - 1;
cup->cu_ctfp = ctf_fdcreate(fd, &ret);
- if (cup->cu_ctfp == NULL) {
- ctf_free(cup, sizeof (ctf_cu_t));
+ 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;
@@ -2775,46 +2776,32 @@ ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
bzero(&cup->cu_bitfields, sizeof (ctf_list_t));
if ((ret = ctf_dwarf_die_elfenc(elf, cup, errbuf,
- errlen)) != 0) {
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
+ errlen)) != 0)
return (ret);
- }
- if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0) {
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
+ if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0)
return (ret);
- }
+
if (cu == NULL) {
(void) snprintf(errbuf, errlen,
- "file does not contain DWARF data\n");
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
- return (ECTF_CONVBKERR);
+ "file does not contain DWARF data");
+ return (ECTF_CONVNODEBUG);
}
- if ((ret = ctf_dwarf_child(cup, cu, &child)) != 0) {
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
+ if ((ret = ctf_dwarf_child(cup, cu, &child)) != 0)
return (ret);
- }
+
if (child == NULL) {
(void) snprintf(errbuf, errlen,
- "file does not contain DWARF data\n");
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
- return (ECTF_CONVBKERR);
+ "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) {
- avl_destroy(&cup->cu_map);
- ctf_free(cup, sizeof (ctf_cu_t));
+ 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;
@@ -2828,41 +2815,143 @@ ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf,
return (0);
}
+/*
+ * This is our only recourse to identify a C source file that is missing debug
+ * info: it will be mentioned as an STT_FILE, but not have a compile unit entry.
+ * (A traditional ctfmerge works on individual files, so can identify missing
+ * DWARF more directly, via ctf_has_c_source() on the .o file.)
+ *
+ * As we operate on basenames, this can of course miss some cases, but it's
+ * better than not checking at all.
+ *
+ * We explicitly whitelist some CRT components. Failing that, there's always
+ * the -m option.
+ */
+static boolean_t
+c_source_has_debug(const char *file, ctf_cu_t *cus, size_t nr_cus)
+{
+ const char *basename = strrchr(file, '/');
+
+ if (basename == NULL)
+ basename = file;
+ else
+ basename++;
+
+ if (strcmp(basename, "common-crt.c") == 0 ||
+ strcmp(basename, "gmon.c") == 0 ||
+ strcmp(basename, "dlink_init.c") == 0 ||
+ strcmp(basename, "dlink_common.c") == 0 ||
+ strncmp(basename, "crt", strlen("crt")) == 0 ||
+ strncmp(basename, "values-", strlen("values-")) == 0)
+ return (B_TRUE);
+
+ for (size_t i = 0; i < nr_cus; i++) {
+ if (strcmp(basename, cus[i].cu_name) == 0)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
-ctf_conv_status_t
-ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
+static int
+ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf,
char *errmsg, size_t errlen)
{
+ Elf_Scn *scn, *strscn;
+ Elf_Data *data, *strdata;
+ GElf_Shdr shdr;
+ ulong_t i;
+
+ scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to get section header: %s\n",
+ elf_errmsg(elf_errno()));
+ return (EINVAL);
+ }
+
+ if (shdr.sh_type == SHT_SYMTAB)
+ break;
+ }
+
+ if (scn == NULL)
+ return (0);
+
+ if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to get str section: %s\n",
+ elf_errmsg(elf_errno()));
+ return (EINVAL);
+ }
+
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ (void) snprintf(errmsg, errlen, "failed to read section: %s\n",
+ elf_errmsg(elf_errno()));
+ return (EINVAL);
+ }
+
+ if ((strdata = elf_getdata(strscn, NULL)) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to read string table: %s\n",
+ elf_errmsg(elf_errno()));
+ return (EINVAL);
+ }
+
+ for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
+ GElf_Sym sym;
+ const char *file;
+ size_t len;
+
+ if (gelf_getsym(data, i, &sym) == NULL) {
+ (void) snprintf(errmsg, errlen,
+ "failed to read sym %lu: %s\n",
+ i, elf_errmsg(elf_errno()));
+ return (EINVAL);
+ }
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
+ continue;
+
+ file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
+ len = strlen(file);
+ if (len < 2 || strncmp(".c", &file[len - 2], 2) != 0)
+ continue;
+
+ if (!c_source_has_debug(file, cus, nr_cus)) {
+ (void) snprintf(errmsg, errlen,
+ "file %s is missing debug info\n", file);
+ return (ECTF_CONVNODEBUG);
+ }
+ }
+
+ return (0);
+}
+
+int
+ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, uint_t flags,
+ ctf_file_t **fpp, char *errbuf, size_t errlen)
+{
int err, ret, ndies, i;
Dwarf_Debug dw;
Dwarf_Error derr;
ctf_cu_t *cdies = NULL, *cup;
workq_t *wqp = NULL;
- if (errp == NULL)
- errp = &err;
- *errp = 0;
*fpp = NULL;
ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw, &derr);
if (ret != DW_DLV_OK) {
- /*
- * We may want to expect DWARF data here and fail conversion if
- * it's missing. In this case, if we actually have some amount
- * of DWARF, but no section, for now, just go ahead and create
- * an empty CTF file.
- */
if (ret == DW_DLV_NO_ENTRY ||
dwarf_errno(derr) == DW_DLE_DEBUG_INFO_NULL) {
- *fpp = ctf_create(errp);
- return (*fpp != NULL ? CTF_CONV_SUCCESS :
- CTF_CONV_ERROR);
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ return (ECTF_CONVNODEBUG);
}
- (void) snprintf(errmsg, errlen,
- "failed to initialize DWARF: %s\n",
- dwarf_errmsg(derr));
- *errp = ECTF_CONVBKERR;
- return (CTF_CONV_ERROR);
+
+ (void) snprintf(errbuf, errlen,
+ "dwarf_elf_init() failed: %s\n", dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
}
/*
@@ -2873,41 +2962,47 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
* only a single Dwarf_Debug as well.
*/
ndies = 0;
- ret = ctf_dwarf_count_dies(dw, &derr, &ndies, errmsg, errlen);
- if (ret != 0) {
- *errp = ret;
- goto out;
+ err = ctf_dwarf_count_dies(dw, &derr, &ndies, errbuf, errlen);
+
+ ctf_dprintf("found %d DWARF CUs\n", ndies);
+
+ if (ndies == 0) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ return (ECTF_CONVNODEBUG);
}
(void) dwarf_finish(dw, &derr);
cdies = ctf_alloc(sizeof (ctf_cu_t) * ndies);
if (cdies == NULL) {
- *errp = ENOMEM;
- return (CTF_CONV_ERROR);
+ 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(errmsg, errlen,
+ (void) snprintf(errbuf, errlen,
"failed to initialize DWARF: %s\n",
dwarf_errmsg(derr));
- *errp = ECTF_CONVBKERR;
- return (CTF_CONV_ERROR);
+ return (ECTF_CONVBKERR);
}
- ret = ctf_dwarf_init_die(fd, elf, &cdies[i], i, errmsg, errlen);
- if (ret != 0) {
- *errp = ret;
+ 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;
}
- ctf_dprintf("found %d DWARF die(s)\n", ndies);
+ 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
@@ -2918,71 +3013,65 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
nthrs = 1;
if (workq_init(&wqp, nthrs) == -1) {
- *errp = errno;
+ err = errno;
goto out;
}
for (i = 0; i < ndies; i++) {
cup = &cdies[i];
- ctf_dprintf("adding die %s: %p, %x %x\n", cup->cu_name,
+ 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) {
- *errp = errno;
+ err = errno;
goto out;
}
}
- ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, errp);
+ ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, &err);
if (ret == WORKQ_ERROR) {
- *errp = errno;
+ err = errno;
goto out;
} else if (ret == WORKQ_UERROR) {
ctf_dprintf("internal convert failed: %s\n",
- ctf_errmsg(*errp));
+ ctf_errmsg(err));
goto out;
}
- ctf_dprintf("Determining next phase: have %d dies\n", ndies);
+ ctf_dprintf("Determining next phase: have %d CUs\n", ndies);
if (ndies != 1) {
ctf_merge_t *cmp;
- cmp = ctf_merge_init(fd, &ret);
- if (cmp == NULL) {
- *errp = ret;
+ cmp = ctf_merge_init(fd, &err);
+ if (cmp == NULL)
goto out;
- }
ctf_dprintf("setting threads\n");
- if ((ret = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
+ if ((err = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
ctf_merge_fini(cmp);
- *errp = ret;
goto out;
}
- ctf_dprintf("adding dies\n");
for (i = 0; i < ndies; i++) {
cup = &cdies[i];
- if ((ret = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
+ if ((err = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) {
ctf_merge_fini(cmp);
- *errp = ret;
goto out;
}
}
ctf_dprintf("performing merge\n");
- ret = ctf_merge_merge(cmp, fpp);
- if (ret != 0) {
+ err = ctf_merge_merge(cmp, fpp);
+ if (err != 0) {
ctf_dprintf("failed merge!\n");
*fpp = NULL;
ctf_merge_fini(cmp);
- *errp = ret;
goto out;
}
ctf_merge_fini(cmp);
- *errp = 0;
+ err = 0;
ctf_dprintf("successfully converted!\n");
} else {
- *errp = 0;
+ err = 0;
*fpp = cdies->cu_ctfp;
cdies->cu_ctfp = NULL;
ctf_dprintf("successfully converted!\n");
@@ -2991,5 +3080,5 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
out:
workq_fini(wqp);
ctf_dwarf_free_dies(cdies, ndies);
- return (*fpp != NULL ? CTF_CONV_SUCCESS : CTF_CONV_ERROR);
+ return (err);
}
diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c
index e183b15f52..5177409200 100644
--- a/usr/src/lib/libctf/common/ctf_lib.c
+++ b/usr/src/lib/libctf/common/ctf_lib.c
@@ -24,19 +24,20 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <ctf_impl.h>
+#include <libctf_impl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <gelf.h>
#include <zlib.h>
+#include <zone.h>
#include <sys/debug.h>
#ifdef _LP64
@@ -92,15 +93,36 @@ _libctf_init(void)
void *
ctf_zopen(int *errp)
{
- ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
+ char buf[MAXPATHLEN];
+ const char *path = _libctf_zlib, *zroot;
if (zlib.z_dlp != NULL)
return (zlib.z_dlp); /* library is already loaded */
- if (access(_libctf_zlib, R_OK) == -1)
+ /*
+ * Get the zone native root. For the tools build, we don't need
+ * this (it seems fair to impose that we always build the system in
+ * a native zone), and we want to allow build machines that are older
+ * that the notion of the native root, so we only actually make this
+ * call if we're not the tools build.
+ */
+#ifndef CTF_TOOLS_BUILD
+ zroot = zone_get_nroot();
+#else
+ zroot = NULL;
+#endif
+
+ if (zroot != NULL) {
+ (void) snprintf(buf, MAXPATHLEN, "%s/%s", zroot, _libctf_zlib);
+ path = buf;
+ }
+
+ ctf_dprintf("decompressing CTF data using %s\n", path);
+
+ if (access(path, R_OK) == -1)
return (ctf_set_open_errno(errp, ECTF_ZMISSING));
- if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
+ if ((zlib.z_dlp = dlopen(path, RTLD_LAZY | RTLD_LOCAL)) == NULL)
return (ctf_set_open_errno(errp, ECTF_ZINIT));
zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress");
@@ -747,7 +769,7 @@ ctf_version(int version)
* A utility function for folks debugging CTF conversion and merging.
*/
void
-ctf_phase_dump(ctf_file_t *fp, const char *phase)
+ctf_phase_dump(ctf_file_t *fp, const char *phase, const char *name)
{
int fd;
static char *base;
@@ -756,7 +778,10 @@ ctf_phase_dump(ctf_file_t *fp, const char *phase)
if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
return;
- (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
+ if (name == NULL)
+ name = "libctf";
+
+ (void) snprintf(path, sizeof (path), "%s/%s.%s.%d.ctf", base, name,
phase != NULL ? phase : "",
ctf_phase);
if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
@@ -764,3 +789,89 @@ ctf_phase_dump(ctf_file_t *fp, const char *phase)
(void) ctf_write(fp, fd);
(void) close(fd);
}
+
+void
+ctf_phase_bump(void)
+{
+ ctf_phase++;
+}
+
+int
+ctf_symtab_iter(ctf_file_t *fp, ctf_symtab_f func, void *arg)
+{
+ ulong_t i;
+ uintptr_t symbase;
+ uintptr_t strbase;
+ const char *file = NULL;
+ boolean_t primary = B_TRUE;
+
+ if (fp->ctf_symtab.cts_data == NULL ||
+ fp->ctf_strtab.cts_data == NULL) {
+ return (ECTF_NOSYMTAB);
+ }
+
+ symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ int ret;
+ uint_t type;
+ Elf64_Sym sym;
+
+ /*
+ * The CTF library has historically tried to handle large file
+ * offsets itself so that way clients can be unaware of such
+ * isseus. Therefore, we translate everything to a 64-bit ELF
+ * symbol, this is done to make it so that the rest of the
+ * library doesn't have to know about these differences. For
+ * more information see, lib/libctf/common/ctf_lib.c.
+ */
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ uint_t bind, itype;
+
+ sym.st_name = symp->st_name;
+ sym.st_value = symp->st_value;
+ sym.st_size = symp->st_size;
+ bind = ELF32_ST_BIND(symp->st_info);
+ itype = ELF32_ST_TYPE(symp->st_info);
+ sym.st_info = ELF64_ST_INFO(bind, itype);
+ sym.st_other = symp->st_other;
+ sym.st_shndx = symp->st_shndx;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+
+ sym = *symp;
+ }
+
+ type = ELF64_ST_TYPE(sym.st_info);
+ name = (const char *)(strbase + sym.st_name);
+
+ /*
+ * Check first if we have an STT_FILE entry. This is used to
+ * distinguish between various local symbols when merging.
+ */
+ if (type == STT_FILE) {
+ if (file != NULL) {
+ primary = B_FALSE;
+ }
+ file = name;
+ continue;
+ }
+
+ /*
+ * Check if this is a symbol that we care about.
+ */
+ if (!ctf_sym_valid(strbase, type, sym.st_shndx, sym.st_value,
+ sym.st_name)) {
+ continue;
+ }
+
+ if ((ret = func(&sym, i, file, name, primary, arg)) != 0) {
+ return (ret);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libctf/common/ctf_merge.c b/usr/src/lib/libctf/common/ctf_merge.c
index c93a2a4f7c..755c6ebc9e 100644
--- a/usr/src/lib/libctf/common/ctf_merge.c
+++ b/usr/src/lib/libctf/common/ctf_merge.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2015 Joyent, Inc.
+ * Copyright (c) 2019 Joyent, Inc.
*/
/*
@@ -60,14 +60,18 @@ typedef struct ctf_merge_types {
typedef struct ctf_merge_objmap {
list_node_t cmo_node;
const char *cmo_name; /* Symbol name */
+ const char *cmo_file; /* Symbol file */
ulong_t cmo_idx; /* Symbol ID */
+ Elf64_Sym cmo_sym; /* Symbol Entry */
ctf_id_t cmo_tid; /* Type ID */
} ctf_merge_objmap_t;
typedef struct ctf_merge_funcmap {
list_node_t cmf_node;
const char *cmf_name; /* Symbol name */
+ const char *cmf_file; /* Symbol file */
ulong_t cmf_idx; /* Symbol ID */
+ Elf64_Sym cmf_sym; /* Symbol Entry */
ctf_id_t cmf_rtid; /* Type ID */
uint_t cmf_flags; /* ctf_funcinfo_t ctc_flags */
uint_t cmf_argc; /* Number of arguments */
@@ -94,6 +98,13 @@ struct ctf_merge_handle {
char *cmh_pname; /* Parent name */
};
+typedef struct ctf_merge_symbol_arg {
+ list_t *cmsa_objmap;
+ list_t *cmsa_funcmap;
+ ctf_file_t *cmsa_out;
+ boolean_t cmsa_dedup;
+} ctf_merge_symbol_arg_t;
+
static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
static ctf_id_t
@@ -661,8 +672,8 @@ ctf_merge_common(ctf_merge_types_t *cmp)
{
int ret, i;
- ctf_phase_dump(cmp->cm_src, "merge-common-src");
- ctf_phase_dump(cmp->cm_out, "merge-common-dest");
+ ctf_phase_dump(cmp->cm_src, "merge-common-src", NULL);
+ ctf_phase_dump(cmp->cm_out, "merge-common-dest", NULL);
/* Pass 1 */
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
@@ -764,6 +775,37 @@ ctf_merge_types_fini(ctf_merge_types_t *cmp)
}
/*
+ * After performing a pass, we need to go through the object and function type
+ * maps and potentially fix them up based on the new maps that we have.
+ */
+static void
+ctf_merge_fixup_symmaps(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
+{
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ VERIFY3S(cmo->cmo_tid, !=, 0);
+ VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
+ cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
+ cmf->cmf_args[i] =
+ cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+}
+
+/*
* Merge the types contained inside of two input files. The second input file is
* always going to be the destination. We're guaranteed that it's always
* writeable.
@@ -774,8 +816,6 @@ ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
int ret;
ctf_merge_types_t cm;
ctf_diff_t *cdp;
- ctf_merge_objmap_t *cmo;
- ctf_merge_funcmap_t *cmf;
ctf_merge_input_t *scmi = arg;
ctf_merge_input_t *dcmi = arg2;
ctf_file_t *out = dcmi->cmi_input;
@@ -817,25 +857,7 @@ ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
/*
* Now we need to fix up the object and function maps.
*/
- for (cmo = list_head(&scmi->cmi_omap); cmo != NULL;
- cmo = list_next(&scmi->cmi_omap, cmo)) {
- if (cmo->cmo_tid == 0)
- continue;
- VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
- cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
- }
-
- for (cmf = list_head(&scmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&scmi->cmi_fmap, cmf)) {
- int i;
-
- VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
- cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
- for (i = 0; i < cmf->cmf_argc; i++) {
- VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
- cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
- }
- }
+ ctf_merge_fixup_symmaps(&cm, scmi);
/*
* Now that we've fixed things up, we need to give our function and
@@ -852,42 +874,10 @@ cleanup:
ctf_diff_fini(cdp);
if (ret != 0)
return (ctf_errno(out));
+ ctf_phase_bump();
return (0);
}
-/*
- * After performing a pass, we need to go through the object and function type
- * maps and potentially fix them up based on the new maps that we haev.
- */
-static void
-ctf_merge_fixup_nontypes(ctf_merge_types_t *cmp, ctf_merge_input_t *cmi)
-{
- ctf_merge_objmap_t *cmo;
- ctf_merge_funcmap_t *cmf;
-
- for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
- cmo = list_next(&cmi->cmi_omap, cmo)) {
- if (cmo->cmo_tid == 0)
- continue;
- VERIFY(cmp->cm_tmap[cmo->cmo_tid].cmt_map != 0);
- cmo->cmo_tid = cmp->cm_tmap[cmo->cmo_tid].cmt_map;
- }
-
- for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&cmi->cmi_fmap, cmf)) {
- int i;
-
- VERIFY(cmp->cm_tmap[cmf->cmf_rtid].cmt_map != 0);
- cmf->cmf_rtid = cmp->cm_tmap[cmf->cmf_rtid].cmt_map;
- for (i = 0; i < cmf->cmf_argc; i++) {
- VERIFY(cmp->cm_tmap[cmf->cmf_args[i]].cmt_map !=
- 0);
- cmf->cmf_args[i] =
- cmp->cm_tmap[cmf->cmf_args[i]].cmt_map;
- }
- }
-}
-
static int
ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
{
@@ -948,7 +938,7 @@ ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
cmi = list_next(&cmh->cmh_inputs, cmi)) {
- ctf_merge_fixup_nontypes(&cm, cmi);
+ ctf_merge_fixup_symmaps(&cm, cmi);
}
ctf_merge_types_fini(&cm);
@@ -1060,10 +1050,9 @@ ctf_merge_label(ctf_merge_t *cmh, const char *label)
}
static int
-ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
- void *arg)
+ctf_merge_add_function(ctf_merge_input_t *cmi, ctf_funcinfo_t *fip, ulong_t idx,
+ const char *file, const char *name, const Elf64_Sym *symp)
{
- ctf_merge_input_t *cmi = arg;
ctf_merge_funcmap_t *fmap;
fmap = ctf_alloc(sizeof (ctf_merge_funcmap_t) +
@@ -1072,10 +1061,16 @@ ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
return (ENOMEM);
fmap->cmf_idx = idx;
+ fmap->cmf_sym = *symp;
fmap->cmf_rtid = fip->ctc_return;
fmap->cmf_flags = fip->ctc_flags;
fmap->cmf_argc = fip->ctc_argc;
fmap->cmf_name = name;
+ if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
+ fmap->cmf_file = file;
+ } else {
+ fmap->cmf_file = NULL;
+ }
if (ctf_func_args(cmi->cmi_input, idx, fmap->cmf_argc,
fmap->cmf_args) != 0) {
@@ -1084,14 +1079,17 @@ ctf_merge_add_funcs_cb(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
return (ctf_errno(cmi->cmi_input));
}
+ ctf_dprintf("added initial function %s, %lu, %s %u\n", name, idx,
+ fmap->cmf_file != NULL ? fmap->cmf_file : "global",
+ ELF64_ST_BIND(symp->st_info));
list_insert_tail(&cmi->cmi_fmap, fmap);
return (0);
}
static int
-ctf_merge_add_objs_cb(const char *name, ctf_id_t id, ulong_t idx, void *arg)
+ctf_merge_add_object(ctf_merge_input_t *cmi, ctf_id_t id, ulong_t idx,
+ const char *file, const char *name, const Elf64_Sym *symp)
{
- ctf_merge_input_t *cmi = arg;
ctf_merge_objmap_t *cmo;
cmo = ctf_alloc(sizeof (ctf_merge_objmap_t));
@@ -1099,12 +1097,71 @@ ctf_merge_add_objs_cb(const char *name, ctf_id_t id, ulong_t idx, void *arg)
return (ENOMEM);
cmo->cmo_name = name;
+ if (ELF64_ST_BIND(symp->st_info) == STB_LOCAL) {
+ cmo->cmo_file = file;
+ } else {
+ cmo->cmo_file = NULL;
+ }
cmo->cmo_idx = idx;
cmo->cmo_tid = id;
+ cmo->cmo_sym = *symp;
list_insert_tail(&cmi->cmi_omap, cmo);
+
+ ctf_dprintf("added initial object %s, %lu, %ld, %s\n", name, idx, id,
+ cmo->cmo_file != NULL ? cmo->cmo_file : "global");
+
return (0);
}
+static int
+ctf_merge_add_symbol(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
+{
+ ctf_merge_input_t *cmi = arg;
+ ctf_file_t *fp = cmi->cmi_input;
+ ushort_t *data, funcbase;
+ uint_t type;
+ ctf_funcinfo_t fi;
+
+ /*
+ * See if there is type information for this. If there is no
+ * type information for this entry or no translation, then we
+ * will find the value zero. This indicates no type ID for
+ * objects and encodes unknown information for functions.
+ */
+ if (fp->ctf_sxlate[idx] == -1u)
+ return (0);
+ data = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[idx]);
+ if (*data == 0)
+ return (0);
+
+ type = ELF64_ST_TYPE(symp->st_info);
+
+ switch (type) {
+ case STT_FUNC:
+ funcbase = *data;
+ if (LCTF_INFO_KIND(fp, funcbase) != CTF_K_FUNCTION)
+ return (0);
+ data++;
+ fi.ctc_return = *data;
+ data++;
+ fi.ctc_argc = LCTF_INFO_VLEN(fp, funcbase);
+ fi.ctc_flags = 0;
+
+ if (fi.ctc_argc != 0 && data[fi.ctc_argc - 1] == 0) {
+ fi.ctc_flags |= CTF_FUNC_VARARG;
+ fi.ctc_argc--;
+ }
+ return (ctf_merge_add_function(cmi, &fi, idx, file, name,
+ symp));
+ case STT_OBJECT:
+ return (ctf_merge_add_object(cmi, *data, idx, file, name,
+ symp));
+ default:
+ return (0);
+ }
+}
+
/*
* Whenever we create an entry to merge, we then go and add a second empty
* ctf_file_t which we use for the purposes of our merging. It's not the best,
@@ -1117,6 +1174,8 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
ctf_merge_input_t *cmi;
ctf_file_t *empty;
+ ctf_dprintf("adding input %p\n", input);
+
if (input->ctf_flags & LCTF_CHILD)
return (ECTF_MCHILD);
@@ -1132,13 +1191,7 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
offsetof(ctf_merge_objmap_t, cmo_node));
if (cmh->cmh_msyms == B_TRUE) {
- if ((ret = ctf_function_iter(input, ctf_merge_add_funcs_cb,
- cmi)) != 0) {
- ctf_merge_fini_input(cmi);
- return (ret);
- }
-
- if ((ret = ctf_object_iter(input, ctf_merge_add_objs_cb,
+ if ((ret = ctf_symtab_iter(input, ctf_merge_add_symbol,
cmi)) != 0) {
ctf_merge_fini_input(cmi);
return (ret);
@@ -1194,122 +1247,193 @@ ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
return (0);
}
-static int
-ctf_merge_symbols(ctf_merge_t *cmh, ctf_file_t *fp)
+/*
+ * Symbol matching rules: the purpose of this is to verify that the type
+ * information that we have for a given symbol actually matches the output
+ * symbol. This is unfortunately complicated by several different factors:
+ *
+ * 1. When merging multiple .o's into a single item, the symbol table index will
+ * not match.
+ *
+ * 2. Visibility of a symbol may not be identical to the object file or the
+ * DWARF information due to symbol reduction via a mapfile.
+ *
+ * As such, we have to employ the following rules:
+ *
+ * 1. A global symbol table entry always matches a global CTF symbol with the
+ * same name.
+ *
+ * 2. A local symbol table entry always matches a local CTF symbol if they have
+ * the same name and they belong to the same file.
+ *
+ * 3. A weak symbol matches a non-weak symbol. This happens if we find that the
+ * types match, the values match, the sizes match, and the section indexes
+ * match. This happens when we do a conversion in one pass, it almost never
+ * happens when we're merging multiple object files. If we match a CTF global
+ * symbol, that's a fixed match, otherwise it's a fuzzy match.
+ *
+ * 4. A local symbol table entry matches a global CTF entry if the
+ * other pieces fail, but they have the same name. This is considered a fuzzy
+ * match and is not used unless we have no other options.
+ *
+ * 5. A weak symbol table entry matches a weak CTF entry if the other pieces
+ * fail, but they have the same name. This is considered a fuzzy match and is
+ * not used unless we have no other options. When merging independent .o files,
+ * this is often the only recourse we have to matching weak symbols.
+ *
+ * In the end, this would all be much simpler if we were able to do this as part
+ * of libld which would be able to do all the symbol transformations.
+ */
+static boolean_t
+ctf_merge_symbol_match(const char *ctf_file, const char *ctf_name,
+ const Elf64_Sym *ctf_symp, const char *symtab_file, const char *symtab_name,
+ const Elf64_Sym *symtab_symp, boolean_t *is_fuzzy)
{
- int err;
- ulong_t i;
-
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- ctf_merge_input_t *cmi;
- ctf_merge_objmap_t *cmo;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- int type = ELF32_ST_TYPE(symp->st_info);
- if (type != STT_OBJECT)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- int type = ELF64_ST_TYPE(symp->st_info);
- if (type != STT_OBJECT)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- }
+ *is_fuzzy = B_FALSE;
+ uint_t symtab_bind, ctf_bind;
- cmo = NULL;
- for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
- cmi = list_next(&cmh->cmh_inputs, cmi)) {
- for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
- cmo = list_next(&cmi->cmi_omap, cmo)) {
- if (strcmp(cmo->cmo_name, name) == 0)
- goto found;
- }
+ symtab_bind = ELF64_ST_BIND(symtab_symp->st_info);
+ ctf_bind = ELF64_ST_BIND(ctf_symp->st_info);
+
+ ctf_dprintf("comparing merge match for %s/%s/%u->%s/%s/%u\n",
+ symtab_file, symtab_name, symtab_bind,
+ ctf_file, ctf_name, ctf_bind);
+ if (strcmp(ctf_name, symtab_name) != 0) {
+ return (B_FALSE);
+ }
+
+ if (symtab_bind == STB_GLOBAL && ctf_bind == STB_GLOBAL) {
+ return (B_TRUE);
+ } else if (symtab_bind == STB_GLOBAL) {
+ return (B_FALSE);
+ }
+
+ if (ctf_bind == STB_LOCAL && ctf_bind == symtab_bind &&
+ ctf_file != NULL && symtab_file != NULL &&
+ strcmp(ctf_file, symtab_file) == 0) {
+ return (B_TRUE);
+ }
+
+ if (symtab_bind == STB_WEAK && ctf_bind != STB_WEAK &&
+ ELF64_ST_TYPE(symtab_symp->st_info) ==
+ ELF64_ST_TYPE(ctf_symp->st_info) &&
+ symtab_symp->st_value == ctf_symp->st_value &&
+ symtab_symp->st_size == ctf_symp->st_size &&
+ symtab_symp->st_shndx == ctf_symp->st_shndx) {
+ if (ctf_bind == STB_GLOBAL) {
+ return (B_TRUE);
}
-found:
- if (cmo != NULL) {
- if (cmo->cmo_tid == 0)
- continue;
- if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0) {
- ctf_dprintf("Failed to add symbol %s->%d: %s\n",
- name, cmo->cmo_tid,
- ctf_errmsg(ctf_errno(fp)));
- return (err);
- }
+
+ if (ctf_bind == STB_LOCAL && ctf_file != NULL &&
+ symtab_file != NULL && strcmp(ctf_file, symtab_file) == 0) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
}
}
- return (0);
+ if (ctf_bind == STB_GLOBAL ||
+ (ctf_bind == STB_WEAK && symtab_bind == STB_WEAK)) {
+ *is_fuzzy = B_TRUE;
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
}
+/*
+ * For each symbol, try and find a match. We will attempt to find an exact
+ * match; however, we will settle for a fuzzy match in general. There is one
+ * case where we will not opt to use a fuzzy match, which is when performing the
+ * deduplication of a container. In such a case we are trying to reduce common
+ * types and a fuzzy match would be inappropriate as if we're in the context of
+ * a single container, the conversion process should have identified any exact
+ * or fuzzy matches that were required.
+ */
static int
-ctf_merge_functions(ctf_merge_t *cmh, ctf_file_t *fp)
+ctf_merge_symbols(const Elf64_Sym *symp, ulong_t idx, const char *file,
+ const char *name, boolean_t primary, void *arg)
{
int err;
- ulong_t i;
- ctf_funcinfo_t fi;
+ uint_t type, bind;
+ ctf_merge_symbol_arg_t *csa = arg;
+ ctf_file_t *fp = csa->cmsa_out;
+
+ type = ELF64_ST_TYPE(symp->st_info);
+ bind = ELF64_ST_BIND(symp->st_info);
+
+ ctf_dprintf("Trying to find match for %s/%s/%u\n", file, name,
+ ELF64_ST_BIND(symp->st_info));
+
+ if (type == STT_OBJECT) {
+ ctf_merge_objmap_t *cmo, *match = NULL;
+
+ for (cmo = list_head(csa->cmsa_objmap); cmo != NULL;
+ cmo = list_next(csa->cmsa_objmap, cmo)) {
+ boolean_t is_fuzzy = B_FALSE;
+ if (ctf_merge_symbol_match(cmo->cmo_file, cmo->cmo_name,
+ &cmo->cmo_sym, file, name, symp, &is_fuzzy)) {
+ if (is_fuzzy && csa->cmsa_dedup &&
+ bind != STB_WEAK) {
+ continue;
+ }
+ match = cmo;
+ if (is_fuzzy) {
+ continue;
+ }
+ break;
+ }
+ }
- uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
- uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
-
- for (i = 0; i < fp->ctf_nsyms; i++) {
- const char *name;
- ctf_merge_input_t *cmi;
- ctf_merge_funcmap_t *cmf;
-
- if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
- const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
- int type = ELF32_ST_TYPE(symp->st_info);
- if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
- } else {
- const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
- int type = ELF64_ST_TYPE(symp->st_info);
- if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
- continue;
- if (ctf_sym_valid(strbase, type, symp->st_shndx,
- symp->st_value, symp->st_name) == B_FALSE)
- continue;
- name = (char *)(strbase + symp->st_name);
+ if (match == NULL) {
+ return (0);
}
- cmf = NULL;
- for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
- cmi = list_next(&cmh->cmh_inputs, cmi)) {
- for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&cmi->cmi_fmap, cmf)) {
- if (strcmp(cmf->cmf_name, name) == 0)
- goto found;
+ if ((err = ctf_add_object(fp, idx, match->cmo_tid)) != 0) {
+ ctf_dprintf("Failed to add symbol %s->%d: %s\n", name,
+ match->cmo_tid, ctf_errmsg(ctf_errno(fp)));
+ return (ctf_errno(fp));
+ }
+ ctf_dprintf("mapped object into output %s/%s->%ld\n", file,
+ name, match->cmo_tid);
+ } else {
+ ctf_merge_funcmap_t *cmf, *match = NULL;
+ ctf_funcinfo_t fi;
+
+ for (cmf = list_head(csa->cmsa_funcmap); cmf != NULL;
+ cmf = list_next(csa->cmsa_funcmap, cmf)) {
+ boolean_t is_fuzzy = B_FALSE;
+ if (ctf_merge_symbol_match(cmf->cmf_file, cmf->cmf_name,
+ &cmf->cmf_sym, file, name, symp, &is_fuzzy)) {
+ if (is_fuzzy && csa->cmsa_dedup &&
+ bind != STB_WEAK) {
+ continue;
+ }
+ match = cmf;
+ if (is_fuzzy) {
+ continue;
+ }
+ break;
}
}
-found:
- if (cmf != NULL) {
- fi.ctc_return = cmf->cmf_rtid;
- fi.ctc_argc = cmf->cmf_argc;
- fi.ctc_flags = cmf->cmf_flags;
- if ((err = ctf_add_function(fp, i, &fi,
- cmf->cmf_args)) != 0)
- return (err);
+
+ if (match == NULL) {
+ return (0);
}
+
+ fi.ctc_return = match->cmf_rtid;
+ fi.ctc_argc = match->cmf_argc;
+ fi.ctc_flags = match->cmf_flags;
+ if ((err = ctf_add_function(fp, idx, &fi, match->cmf_args)) !=
+ 0) {
+ ctf_dprintf("Failed to add function %s: %s\n", name,
+ ctf_errmsg(ctf_errno(fp)));
+ return (ctf_errno(fp));
+ }
+ ctf_dprintf("mapped function into output %s/%s\n", file,
+ name);
}
return (0);
-
}
int
@@ -1322,6 +1446,7 @@ ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
ctf_merge_input_t *final;
ctf_file_t *out;
+ ctf_dprintf("Beginning ctf_merge_merge()\n");
if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
const char *label = ctf_label_topmost(cmh->cmh_unique);
if (label == NULL)
@@ -1387,23 +1512,23 @@ ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
ctf_dprintf("merging symbols and the like\n");
if (cmh->cmh_msyms == B_TRUE) {
- err = ctf_merge_symbols(cmh, out);
- if (err != 0) {
- ctf_close(out);
- return (ctf_errno(out));
- }
-
- err = ctf_merge_functions(cmh, out);
+ ctf_merge_symbol_arg_t arg;
+ arg.cmsa_objmap = &final->cmi_omap;
+ arg.cmsa_funcmap = &final->cmi_fmap;
+ arg.cmsa_out = out;
+ arg.cmsa_dedup = B_FALSE;
+ err = ctf_symtab_iter(out, ctf_merge_symbols, &arg);
if (err != 0) {
ctf_close(out);
- return (ctf_errno(out));
+ return (err);
}
}
err = ctf_update(out);
if (err != 0) {
+ err = ctf_errno(out);
ctf_close(out);
- return (ctf_errno(out));
+ return (err);
}
*outp = out;
@@ -1505,29 +1630,25 @@ ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
goto err;
ctf_dprintf("Successfully deduped types\n");
- ctf_phase_dump(cm.cm_out, "dedup-pre-syms");
+ ctf_phase_dump(cm.cm_out, "dedup-pre-syms", NULL);
/*
* Now we need to fix up the object and function maps.
*/
- ctf_merge_fixup_nontypes(&cm, cmi);
+ ctf_merge_fixup_symmaps(&cm, cmi);
if (cmp->cmh_msyms == B_TRUE) {
- ret = ctf_merge_symbols(cmp, cm.cm_out);
+ ctf_merge_symbol_arg_t arg;
+ arg.cmsa_objmap = &cmi->cmi_omap;
+ arg.cmsa_funcmap = &cmi->cmi_fmap;
+ arg.cmsa_out = cm.cm_out;
+ arg.cmsa_dedup = B_TRUE;
+ ret = ctf_symtab_iter(cm.cm_out, ctf_merge_symbols, &arg);
if (ret != 0) {
- ret = ctf_errno(cm.cm_out);
ctf_dprintf("failed to dedup symbols: %s\n",
ctf_errmsg(ret));
goto err;
}
-
- ret = ctf_merge_functions(cmp, cm.cm_out);
- if (ret != 0) {
- ret = ctf_errno(cm.cm_out);
- ctf_dprintf("failed to dedup functions: %s\n",
- ctf_errmsg(ret));
- goto err;
- }
}
ret = ctf_update(cm.cm_out);
@@ -1535,6 +1656,7 @@ ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
cmc->cmi_input = NULL;
*outp = cm.cm_out;
}
+ ctf_phase_dump(cm.cm_out, "dedup-post-syms", NULL);
err:
ctf_merge_types_fini(&cm);
ctf_diff_fini(cdp);
diff --git a/usr/src/lib/libctf/common/libctf.h b/usr/src/lib/libctf/common/libctf.h
index 0951ae0606..78b0a7a786 100644
--- a/usr/src/lib/libctf/common/libctf.h
+++ b/usr/src/lib/libctf/common/libctf.h
@@ -24,7 +24,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright (c) 2019, Joyent, Inc.
*/
/*
@@ -44,6 +44,7 @@
#define _LIBCTF_H
#include <sys/ctf_api.h>
+#include <libelf.h>
#ifdef __cplusplus
extern "C" {
@@ -74,10 +75,25 @@ extern int ctf_diff_functions(ctf_diff_t *, ctf_diff_func_f, void *);
extern int ctf_diff_objects(ctf_diff_t *, ctf_diff_obj_f, void *);
extern void ctf_diff_fini(ctf_diff_t *);
-#define CTF_CONVERT_F_IGNNONC 0x01
+/*
+ * Normally, we return a failure if we find a C-derived compilation unit that
+ * lacks DWARF or CTF (as required). This flag over-rides this check.
+ */
+#define CTF_ALLOW_MISSING_DEBUG 0x01
+
+extern ctf_file_t *ctf_elfconvert(int, Elf *, const char *, uint_t, uint_t,
+ int *, char *, size_t);
extern ctf_file_t *ctf_fdconvert(int, const char *, uint_t, uint_t, int *,
char *, size_t);
+typedef enum ctf_hsc_ret {
+ CHR_ERROR = -1,
+ CHR_NO_C_SOURCE = 0,
+ CHR_HAS_C_SOURCE = 1
+} ctf_hsc_ret_t;
+
+extern ctf_hsc_ret_t ctf_has_c_source(Elf *, char *, size_t);
+
typedef struct ctf_merge_handle ctf_merge_t;
extern ctf_merge_t *ctf_merge_init(int, int *);
extern int ctf_merge_add(ctf_merge_t *, ctf_file_t *);
diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h
index 11193e97d0..5c88b9454d 100644
--- a/usr/src/lib/libctf/common/libctf_impl.h
+++ b/usr/src/lib/libctf/common/libctf_impl.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
*/
#ifndef _LIBCTF_IMPL_H
@@ -29,18 +29,19 @@
extern "C" {
#endif
-typedef enum ctf_conv_status {
- CTF_CONV_SUCCESS = 0,
- CTF_CONV_ERROR = 1,
- CTF_CONV_NOTSUP = 2
-} ctf_conv_status_t;
-
-typedef ctf_conv_status_t (*ctf_convert_f)(int, Elf *, uint_t, int *,
+typedef int (*ctf_convert_f)(int, Elf *, uint_t, uint_t,
ctf_file_t **, char *, size_t);
-extern ctf_conv_status_t ctf_dwarf_convert(int, Elf *, uint_t, int *,
+extern int ctf_dwarf_convert(int, Elf *, uint_t, uint_t,
ctf_file_t **, char *, size_t);
/*
+ * Symbol walking
+ */
+typedef int (*ctf_symtab_f)(const Elf64_Sym *, ulong_t, const char *,
+ const char *, boolean_t, void *);
+extern int ctf_symtab_iter(ctf_file_t *, ctf_symtab_f, void *);
+
+/*
* zlib compression routines
*/
extern int ctf_compress(ctf_file_t *fp, void **, size_t *, size_t *);
@@ -50,7 +51,8 @@ extern int ctf_diff_self(ctf_diff_t *, ctf_diff_type_f, void *);
/*
* Internal debugging aids
*/
-extern void ctf_phase_dump(ctf_file_t *, const char *);
+extern void ctf_phase_dump(ctf_file_t *, const char *, const char *);
+extern void ctf_phase_bump(void);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libctf/common/mapfile-vers b/usr/src/lib/libctf/common/mapfile-vers
index b26ee8ceb4..9281bbfff5 100644
--- a/usr/src/lib/libctf/common/mapfile-vers
+++ b/usr/src/lib/libctf/common/mapfile-vers
@@ -23,7 +23,7 @@
#
#
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
#
@@ -78,6 +78,7 @@ SYMBOL_VERSION SUNWprivate_1.2 {
ctf_diff_types;
ctf_discard;
ctf_dup;
+ ctf_elfconvert;
ctf_elffdwrite;
ctf_elfwrite;
ctf_enum_value;
@@ -86,6 +87,7 @@ SYMBOL_VERSION SUNWprivate_1.2 {
ctf_func_args_by_id;
ctf_func_info_by_id;
ctf_function_iter;
+ ctf_has_c_source;
ctf_kind_name;
ctf_label_info;
ctf_label_iter;