diff options
-rw-r--r-- | usr/src/common/ctf/ctf_create.c | 3 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_convert.c | 6 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_dwarf.c | 231 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_lib.c | 97 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_merge.c | 496 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/libctf_impl.h | 12 |
6 files changed, 536 insertions, 309 deletions
diff --git a/usr/src/common/ctf/ctf_create.c b/usr/src/common/ctf/ctf_create.c index 355165eb12..d88283e8f5 100644 --- a/usr/src/common/ctf/ctf_create.c +++ b/usr/src/common/ctf/ctf_create.c @@ -25,7 +25,7 @@ * Use is subject to license terms. */ /* - * Copyright (c) 2015, Joyent, Inc. + * Copyright (c) 2019, Joyent, Inc. */ #include <sys/sysmacros.h> @@ -2126,6 +2126,7 @@ ctf_add_label(ctf_file_t *fp, const char *name, ctf_id_t type, uint_t position) return (ctf_set_errno(fp, EAGAIN)); } + ctf_dprintf("adding label %s, %ld\n", name, type); dld->dld_type = type; fp->ctf_dtstrlen += strlen(name) + 1; ctf_dld_insert(fp, dld, position); diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c index 1a433d17db..7190e66718 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. */ /* @@ -168,9 +168,7 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, /* * Succsesful conversion. */ - if (fp != NULL) { - if (label == NULL) - label = ""; + if (fp != NULL && 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..7cd02db43c 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 @@ -2166,126 +2163,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; + 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); - 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; - } - 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 +2301,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 +2326,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 +2368,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 +2480,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 +2508,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 +2523,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 +2536,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 +2607,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); } @@ -2904,10 +2911,11 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp, *errp = ret; goto out; } + cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE; } - ctf_dprintf("found %d DWARF die(s)\n", ndies); + ctf_dprintf("found %d DWARF CUs\n", ndies); /* * If we only have one compilation unit, there's no reason to use @@ -2924,7 +2932,7 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp, 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; @@ -2942,7 +2950,7 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp, 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; @@ -2959,9 +2967,10 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp, goto out; } - ctf_dprintf("adding dies\n"); for (i = 0; i < ndies; i++) { cup = &cdies[i]; + ctf_dprintf("adding cu %s (%p)\n", cup->cu_name, + cup->cu_ctfp); if ((ret = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) { ctf_merge_fini(cmp); *errp = ret; diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c index bc533b766e..5177409200 100644 --- a/usr/src/lib/libctf/common/ctf_lib.c +++ b/usr/src/lib/libctf/common/ctf_lib.c @@ -24,13 +24,13 @@ * 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> @@ -769,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; @@ -778,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) @@ -786,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_impl.h b/usr/src/lib/libctf/common/libctf_impl.h index 11193e97d0..be091ef199 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 @@ -41,6 +41,13 @@ extern ctf_conv_status_t ctf_dwarf_convert(int, Elf *, uint_t, int *, 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 +57,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 } |