diff options
-rw-r--r-- | usr/src/cmd/ctfconvert/ctfconvert.c | 54 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_convert.c | 13 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/ctf_dwarf.c | 605 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/libctf.h | 4 | ||||
-rw-r--r-- | usr/src/lib/libctf/common/libctf_impl.h | 4 | ||||
-rw-r--r-- | usr/src/pkg/manifests/developer-build-onbld.mf | 1 | ||||
-rw-r--r-- | usr/src/tools/scripts/Makefile | 2 | ||||
-rw-r--r-- | usr/src/tools/scripts/ctfconvert.1onbld | 116 |
8 files changed, 562 insertions, 237 deletions
diff --git a/usr/src/cmd/ctfconvert/ctfconvert.c b/usr/src/cmd/ctfconvert/ctfconvert.c index 0e37d070f1..bae355be22 100644 --- a/usr/src/cmd/ctfconvert/ctfconvert.c +++ b/usr/src/cmd/ctfconvert/ctfconvert.c @@ -37,6 +37,7 @@ #define CTFCONVERT_FATAL 1 #define CTFCONVERT_USAGE 2 +#define CTFCONVERT_DEFAULT_BATCHSIZE 256 #define CTFCONVERT_DEFAULT_NTHREADS 4 static char *ctfconvert_progname; @@ -67,17 +68,21 @@ ctfconvert_usage(const char *fmt, ...) va_end(ap); } - (void) fprintf(stderr, "Usage: %s [-ims] [-j nthrs] [-l label | " - "-L labelenv] [-o outfile] input\n" + (void) fprintf(stderr, "Usage: %s [-ikm] [-j nthrs] [-l label | " + "-L labelenv] [-b batchsize]\n" + " [-o outfile] input\n" "\n" + "\t-b batch process this many dies at a time (default %d)\n" "\t-i ignore files not built partially from C sources\n" - "\t-j use nthrs threads to perform the merge\n" + "\t-j use nthrs threads to perform the merge (default %d)\n" "\t-k keep around original input file on failure\n" - "\t-m allow input to have missing debug info\n" - "\t-o copy input to outfile and add CTF\n" "\t-l set output container's label to specified value\n" - "\t-L set output container's label to value from environment\n", - ctfconvert_progname); + "\t-L set output container's label to value from environment\n" + "\t-m allow input to have missing debug info\n" + "\t-o copy input to outfile and add CTF\n", + ctfconvert_progname, + CTFCONVERT_DEFAULT_BATCHSIZE, + CTFCONVERT_DEFAULT_NTHREADS); } /* @@ -226,35 +231,48 @@ main(int argc, char *argv[]) int c, ifd, err; boolean_t keep = B_FALSE; uint_t flags = 0; + uint_t bsize = CTFCONVERT_DEFAULT_BATCHSIZE; uint_t nthreads = CTFCONVERT_DEFAULT_NTHREADS; const char *outfile = NULL; const char *label = NULL; const char *infile = NULL; char *tmpfile; ctf_file_t *ofp; - long argj; - char *eptr; char buf[4096]; boolean_t optx = B_FALSE; boolean_t ignore_non_c = B_FALSE; ctfconvert_progname = basename(argv[0]); - while ((c = getopt(argc, argv, ":ij:kl:L:mo:X")) != -1) { + while ((c = getopt(argc, argv, ":b:ij:kl:L:mo:X")) != -1) { switch (c) { + case 'b': { + long argno; + const char *errstr; + + argno = strtonum(optarg, 1, UINT_MAX, &errstr); + if (errstr != NULL) { + ctfconvert_fatal("invalid argument for -b: " + "%s - %s\n", optarg, errstr); + } + bsize = (uint_t)argno; + break; + } case 'i': ignore_non_c = B_TRUE; break; - case 'j': - errno = 0; - argj = strtol(optarg, &eptr, 10); - if (errno != 0 || argj == LONG_MAX || - argj > 1024 || *eptr != '\0') { + case 'j': { + long argno; + const char *errstr; + + argno = strtonum(optarg, 1, 1024, &errstr); + if (errstr != NULL) { ctfconvert_fatal("invalid argument for -j: " - "%s\n", optarg); + "%s - %s\n", optarg, errstr); } - nthreads = (uint_t)argj; + nthreads = (uint_t)argno; break; + } case 'k': keep = B_TRUE; break; @@ -309,7 +327,7 @@ main(int argc, char *argv[]) if (outfile != NULL && strcmp(infile, outfile) != 0) keep = B_TRUE; - ofp = ctf_fdconvert(ifd, label, nthreads, flags, &err, buf, + ofp = ctf_fdconvert(ifd, label, bsize, nthreads, flags, &err, buf, sizeof (buf)); if (ofp == NULL) { /* diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c index 06f4135593..a55c811386 100644 --- a/usr/src/lib/libctf/common/ctf_convert.c +++ b/usr/src/lib/libctf/common/ctf_convert.c @@ -100,8 +100,8 @@ ctf_has_c_source(Elf *elf, char *errmsg, size_t errlen) } static 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) +ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t bsize, uint_t nthrs, + uint_t flags, int *errp, char *errbuf, size_t errlen) { int err, i; ctf_file_t *fp = NULL; @@ -139,7 +139,7 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, for (i = 0; i < NCONVERTS; i++) { fp = NULL; - err = ctf_converters[i](fd, elf, nthrs, flags, + err = ctf_converters[i](fd, elf, bsize, nthrs, flags, &fp, errbuf, errlen); if (err != ECTF_CONVNODEBUG) @@ -169,8 +169,8 @@ ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags, } ctf_file_t * -ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp, - char *errbuf, size_t errlen) +ctf_fdconvert(int fd, const char *label, uint_t bsize, uint_t nthrs, + uint_t flags, int *errp, char *errbuf, size_t errlen) { int err; Elf *elf; @@ -185,7 +185,8 @@ ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp, return (NULL); } - fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen); + fp = ctf_elfconvert(fd, elf, label, bsize, nthrs, flags, errp, errbuf, + errlen); (void) elf_end(elf); return (fp); diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c index 388cb20489..e2cd9414dc 100644 --- a/usr/src/lib/libctf/common/ctf_dwarf.c +++ b/usr/src/lib/libctf/common/ctf_dwarf.c @@ -30,6 +30,7 @@ /* * Copyright 2020 Joyent, Inc. * Copyright 2020 Robert Mustacchi + * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. */ /* @@ -206,6 +207,8 @@ #include <dwarf.h> #include <libgen.h> #include <workq.h> +#include <thread.h> +#include <macros.h> #include <errno.h> #define DWARF_VERSION_TWO 2 @@ -254,12 +257,14 @@ typedef struct ctf_dwbitf { */ typedef struct ctf_die { Elf *cu_elf; /* shared libelf handle */ + int cu_fd; /* shared file descriptor */ char *cu_name; /* basename of the DIE */ ctf_merge_t *cu_cmh; /* merge handle */ ctf_list_t cu_vars; /* List of variables */ ctf_list_t cu_funcs; /* List of functions */ ctf_list_t cu_bitfields; /* Bit field members */ Dwarf_Debug cu_dwarf; /* libdwarf handle */ + mutex_t *cu_dwlock; /* libdwarf lock */ Dwarf_Die cu_cu; /* libdwarf compilation unit */ Dwarf_Off cu_cuoff; /* cu's offset */ Dwarf_Off cu_maxoff; /* maximum offset */ @@ -277,6 +282,7 @@ typedef struct ctf_die { ctf_id_t cu_longtid; /* id for a 'long' */ } ctf_cu_t; +static int ctf_dwarf_init_die(ctf_cu_t *); static int ctf_dwarf_offset(ctf_cu_t *, Dwarf_Die, Dwarf_Off *); static int ctf_dwarf_convert_die(ctf_cu_t *, Dwarf_Die); static int ctf_dwarf_convert_type(ctf_cu_t *, Dwarf_Die, ctf_id_t *, int); @@ -286,6 +292,13 @@ static int ctf_dwarf_function_count(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *, static int ctf_dwarf_convert_fargs(ctf_cu_t *, Dwarf_Die, ctf_funcinfo_t *, ctf_id_t *); +#define DWARF_LOCK(cup) \ + if ((cup)->cu_dwlock != NULL) \ + mutex_enter((cup)->cu_dwlock) +#define DWARF_UNLOCK(cup) \ + if ((cup)->cu_dwlock != NULL) \ + mutex_exit((cup)->cu_dwlock) + /* * This is a generic way to set a CTF Conversion backend error depending on what * we were doing. Unless it was one of a specific set of errors that don't @@ -305,7 +318,8 @@ ctf_dwarf_error(ctf_cu_t *cup, ctf_file_t *cfp, int err, const char *fmt, ...) if (err == ENOMEM) return (err); - ret = snprintf(cup->cu_errbuf, rem, "die %s: ", cup->cu_name); + ret = snprintf(cup->cu_errbuf, rem, "die %s: ", + cup->cu_name != NULL ? cup->cu_name : "NULL"); if (ret < 0) goto err; off += ret; @@ -429,7 +443,10 @@ ctf_dwarf_attribute(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, int ret; Dwarf_Error derr; - if ((ret = dwarf_attr(die, name, attrp, &derr)) == DW_DLV_OK) + DWARF_LOCK(cup); + ret = dwarf_attr(die, name, attrp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) return (0); if (ret == DW_DLV_NO_ENTRY) { *attrp = NULL; @@ -441,6 +458,14 @@ ctf_dwarf_attribute(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, return (ECTF_CONVBKERR); } +static void +ctf_dwarf_dealloc(ctf_cu_t *cup, Dwarf_Ptr ptr, Dwarf_Unsigned type) +{ + DWARF_LOCK(cup); + dwarf_dealloc(cup->cu_dwarf, ptr, type); + DWARF_UNLOCK(cup); +} + static int ctf_dwarf_ref(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp) { @@ -451,8 +476,11 @@ ctf_dwarf_ref(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp) if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0) return (ret); - if (dwarf_formref(attr, refp, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_LOCK(cup); + ret = dwarf_formref(attr, refp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) { + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (0); } @@ -474,8 +502,10 @@ ctf_dwarf_refdie(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, return (ret); off += cup->cu_cuoff; - if ((ret = dwarf_offdie(cup->cu_dwarf, off, diep, &derr)) != - DW_DLV_OK) { + DWARF_LOCK(cup); + ret = dwarf_offdie(cup->cu_dwarf, off, diep, &derr); + DWARF_UNLOCK(cup); + if (ret != DW_DLV_OK) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to get die from offset %" DW_PR_DUu ": %s\n", off, dwarf_errmsg(derr)); @@ -496,8 +526,11 @@ ctf_dwarf_signed(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0) return (ret); - if (dwarf_formsdata(attr, valp, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_LOCK(cup); + ret = dwarf_formsdata(attr, valp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) { + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (0); } @@ -518,8 +551,11 @@ ctf_dwarf_unsigned(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0) return (ret); - if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_LOCK(cup); + ret = dwarf_formudata(attr, valp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) { + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (0); } @@ -540,8 +576,11 @@ ctf_dwarf_boolean(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0) return (ret); - if (dwarf_formflag(attr, val, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_LOCK(cup); + ret = dwarf_formflag(attr, val, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) { + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (0); } @@ -564,12 +603,15 @@ ctf_dwarf_string(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, char **strp) if ((ret = ctf_dwarf_attribute(cup, die, name, &attr)) != 0) return (ret); - if (dwarf_formstring(attr, &s, &derr) == DW_DLV_OK) { + DWARF_LOCK(cup); + ret = dwarf_formstring(attr, &s, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) { if ((*strp = ctf_strdup(s)) == NULL) ret = ENOMEM; else ret = 0; - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ret); } @@ -598,17 +640,22 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) enum Dwarf_Form_Class class; if ((ret = ctf_dwarf_attribute(cup, die, DW_AT_data_member_location, - &attr)) != 0) + &attr)) != 0) { return (ret); + } - if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) { + DWARF_LOCK(cup); + ret = dwarf_whatform(attr, &form, &derr); + DWARF_UNLOCK(cup); + if (ret != DW_DLV_OK) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to get dwarf attribute for for member location: %s", dwarf_errmsg(derr)); - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ECTF_CONVBKERR); } + DWARF_LOCK(cup); class = dwarf_get_form_class(cup->cu_vers, DW_AT_data_member_location, cup->cu_addrsz, form); if (class == DW_FORM_CLASS_CONSTANT) { @@ -621,12 +668,14 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) * match, fall through to the normal path. */ if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_UNLOCK(cup); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (0); } if (dwarf_formsdata(attr, &sign, &derr) == DW_DLV_OK) { - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_UNLOCK(cup); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); if (sign < 0) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "encountered negative member data " @@ -638,26 +687,28 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) } if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) { + DWARF_UNLOCK(cup); (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to obtain location list for member offset: %s", dwarf_errmsg(derr)); - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ECTF_CONVBKERR); } - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_UNLOCK(cup); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to parse location structure for member"); - dwarf_dealloc(cup->cu_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK); - dwarf_dealloc(cup->cu_dwarf, loc, DW_DLA_LOCDESC); + ctf_dwarf_dealloc(cup, loc->ld_s, DW_DLA_LOC_BLOCK); + ctf_dwarf_dealloc(cup, loc, DW_DLA_LOCDESC); return (ECTF_CONVBKERR); } *valp = loc->ld_s->lr_number; - dwarf_dealloc(cup->cu_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK); - dwarf_dealloc(cup->cu_dwarf, loc, DW_DLA_LOCDESC); + ctf_dwarf_dealloc(cup, loc->ld_s, DW_DLA_LOC_BLOCK); + ctf_dwarf_dealloc(cup, loc, DW_DLA_LOCDESC); return (0); } @@ -666,8 +717,12 @@ static int ctf_dwarf_offset(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Off *offsetp) { Dwarf_Error derr; + int ret; - if (dwarf_dieoffset(die, offsetp, &derr) == DW_DLV_OK) + DWARF_LOCK(cup); + ret = dwarf_dieoffset(die, offsetp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) return (0); (void) snprintf(cup->cu_errbuf, cup->cu_errlen, @@ -678,12 +733,14 @@ ctf_dwarf_offset(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Off *offsetp) /* simpler variant for debugging output */ static Dwarf_Off -ctf_die_offset(Dwarf_Die die) +ctf_die_offset(ctf_cu_t *cup, Dwarf_Die die) { Dwarf_Off off = -1; Dwarf_Error derr; + DWARF_LOCK(cup); (void) dwarf_dieoffset(die, &off, &derr); + DWARF_UNLOCK(cup); return (off); } @@ -691,8 +748,12 @@ static int ctf_dwarf_tag(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half *tagp) { Dwarf_Error derr; + int ret; - if (dwarf_tag(die, tagp, &derr) == DW_DLV_OK) + DWARF_LOCK(cup); + ret = dwarf_tag(die, tagp, &derr); + DWARF_UNLOCK(cup); + if (ret == DW_DLV_OK) return (0); (void) snprintf(cup->cu_errbuf, cup->cu_errlen, @@ -708,7 +769,9 @@ ctf_dwarf_sib(ctf_cu_t *cup, Dwarf_Die base, Dwarf_Die *sibp) int ret; *sibp = NULL; + DWARF_LOCK(cup); ret = dwarf_siblingof(cup->cu_dwarf, base, sibp, &derr); + DWARF_UNLOCK(cup); if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY) return (0); @@ -725,7 +788,9 @@ ctf_dwarf_child(ctf_cu_t *cup, Dwarf_Die base, Dwarf_Die *childp) int ret; *childp = NULL; + DWARF_LOCK(cup); ret = dwarf_child(base, childp, &derr); + DWARF_UNLOCK(cup); if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY) return (0); @@ -1545,7 +1610,9 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar) } } - if (dwarf_whatform(attr, &form, &derr) != DW_DLV_OK) { + DWARF_LOCK(cup); + ret = dwarf_whatform(attr, &form, &derr); + if (ret != DW_DLV_OK) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to get DW_AT_upper_bound attribute form: %s\n", dwarf_errmsg(derr)); @@ -1606,7 +1673,8 @@ ctf_dwarf_array_upper_bound(ctf_cu_t *cup, Dwarf_Die range, ctf_arinfo_t *ar) ret = ECTF_CONVBKERR; done: - dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + DWARF_UNLOCK(cup); + ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ret); } @@ -2219,7 +2287,7 @@ ctf_dwarf_convert_function(ctf_cu_t *cup, Dwarf_Die die) } ctf_dprintf("beginning work on function %s (die %llx)\n", - name, ctf_die_offset(die)); + name, ctf_die_offset(cup, die)); if ((ret = ctf_dwarf_boolean(cup, die, DW_AT_declaration, &b)) != 0) { if (ret != ENOENT) @@ -2233,7 +2301,7 @@ ctf_dwarf_convert_function(ctf_cu_t *cup, Dwarf_Die die) * DW_TAG_subprogram that is more complete. */ ctf_dprintf("ignoring declaration of function %s (die %llx)\n", - name, ctf_die_offset(die)); + name, ctf_die_offset(cup, die)); return (0); } @@ -2347,7 +2415,7 @@ ctf_dwarf_convert_variable(ctf_cu_t *cup, Dwarf_Die die) if ((ret = ctf_dwarf_offset(cup, tdie, &offset)) != 0) return (ret); ctf_dprintf("die 0x%llx DW_AT_specification -> die 0x%llx\n", - ctf_die_offset(die), ctf_die_offset(tdie)); + ctf_die_offset(cup, die), ctf_die_offset(cup, tdie)); die = tdie; } else if (ret != ENOENT) { return (ret); @@ -2853,52 +2921,55 @@ ctf_dwarf_conv_weaks(ctf_cu_t *cup) return (ctf_symtab_iter(cup->cu_ctfp, ctf_dwarf_conv_weaks_cb, cup)); } -/* ARGSUSED */ static int ctf_dwarf_convert_one(void *arg, void *unused) { int ret; ctf_file_t *dedup; ctf_cu_t *cup = arg; + const char *name = cup->cu_name != NULL ? cup->cu_name : "NULL"; - ctf_dprintf("converting die: %s\n", cup->cu_name); - ctf_dprintf("max offset: %x\n", cup->cu_maxoff); VERIFY(cup != NULL); + if ((ret = ctf_dwarf_init_die(cup)) != 0) + return (ret); + + ctf_dprintf("converting die: %s - max offset: %x\n", name, + cup->cu_maxoff); + ret = ctf_dwarf_convert_die(cup, cup->cu_cu); - ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", cup->cu_name, + ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", name, ret); - if (ret != 0) { + if (ret != 0) return (ret); - } + if (ctf_update(cup->cu_ctfp) != 0) { return (ctf_dwarf_error(cup, cup->cu_ctfp, 0, "failed to update output ctf container")); } ret = ctf_dwarf_fixup_die(cup, B_FALSE); - ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cup->cu_name, + ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", name, ret); - if (ret != 0) { + if (ret != 0) return (ret); - } + if (ctf_update(cup->cu_ctfp) != 0) { return (ctf_dwarf_error(cup, cup->cu_ctfp, 0, "failed to update output ctf container")); } ret = ctf_dwarf_fixup_die(cup, B_TRUE); - ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cup->cu_name, + ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", name, ret); - if (ret != 0) { + if (ret != 0) return (ret); - } + if (ctf_update(cup->cu_ctfp) != 0) { return (ctf_dwarf_error(cup, cup->cu_ctfp, 0, "failed to update output ctf container")); } - if ((ret = ctf_dwarf_conv_funcvars(cup)) != 0) { return (ctf_dwarf_error(cup, NULL, ret, "failed to convert strong functions and variables")); @@ -2921,30 +2992,26 @@ ctf_dwarf_convert_one(void *arg, void *unused) } } - ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", cup->cu_name); + ctf_phase_dump(cup->cu_ctfp, "pre-dwarf-dedup", name); ctf_dprintf("adding inputs for dedup\n"); if ((ret = ctf_merge_add(cup->cu_cmh, cup->cu_ctfp)) != 0) { return (ctf_dwarf_error(cup, NULL, ret, "failed to add inputs for merge")); } - ctf_dprintf("starting dedup of %s\n", cup->cu_name); + ctf_dprintf("starting dedup of %s\n", name); if ((ret = ctf_merge_dedup(cup->cu_cmh, &dedup)) != 0) { return (ctf_dwarf_error(cup, NULL, ret, "failed to deduplicate die")); } + ctf_close(cup->cu_ctfp); cup->cu_ctfp = dedup; - ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", cup->cu_name); + ctf_phase_dump(cup->cu_ctfp, "post-dwarf-dedup", name); return (0); } -/* - * Note, we expect that if we're returning a ctf_file_t from one of the dies, - * say in the single node case, it's been saved and the entry here has been set - * to NULL, which ctf_close happily ignores. - */ static void ctf_dwarf_free_die(ctf_cu_t *cup) { @@ -2953,13 +3020,18 @@ ctf_dwarf_free_die(ctf_cu_t *cup) ctf_dwbitf_t *cdb, *ndb; ctf_dwmap_t *map; void *cookie; - Dwarf_Error derr; ctf_dprintf("Beginning to free die: %p\n", cup); + + VERIFY3P(cup->cu_elf, !=, NULL); cup->cu_elf = NULL; + ctf_dprintf("Trying to free name: %p\n", cup->cu_name); - if (cup->cu_name != NULL) + if (cup->cu_name != NULL) { ctf_free(cup->cu_name, strlen(cup->cu_name) + 1); + cup->cu_name = NULL; + } + ctf_dprintf("Trying to free merge handle: %p\n", cup->cu_cmh); if (cup->cu_cmh != NULL) { ctf_merge_fini(cup->cu_cmh); @@ -2990,35 +3062,25 @@ ctf_dwarf_free_die(ctf_cu_t *cup) ctf_free(cdb, sizeof (ctf_dwbitf_t)); } - ctf_dprintf("Trying to clean up dwarf_t: %p\n", cup->cu_dwarf); - if (cup->cu_dwarf != NULL) - (void) dwarf_finish(cup->cu_dwarf, &derr); - cup->cu_dwarf = NULL; - ctf_close(cup->cu_ctfp); + if (cup->cu_ctfp != NULL) { + ctf_close(cup->cu_ctfp); + cup->cu_ctfp = NULL; + } cookie = NULL; - while ((map = avl_destroy_nodes(&cup->cu_map, &cookie)) != NULL) { + while ((map = avl_destroy_nodes(&cup->cu_map, &cookie)) != NULL) ctf_free(map, sizeof (ctf_dwmap_t)); - } avl_destroy(&cup->cu_map); cup->cu_errbuf = NULL; -} - -static void -ctf_dwarf_free_dies(ctf_cu_t *cdies, int ndies) -{ - int i; - ctf_dprintf("Beginning to free dies\n"); - for (i = 0; i < ndies; i++) { - ctf_dwarf_free_die(&cdies[i]); + if (cup->cu_cu != NULL) { + ctf_dwarf_dealloc(cup, cup->cu_cu, DW_DLA_DIE); + cup->cu_cu = NULL; } - - ctf_free(cdies, sizeof (ctf_cu_t) * ndies); } static int -ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies, +ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, uint_t *ndies, char *errbuf, size_t errlen) { int ret; @@ -3049,88 +3111,146 @@ ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies, return (0); } +/* + * Fill out just enough of each ctf_cu_t for the conversion process to + * be able to finish the rest in a (potentially) multithreaded context. + */ static int -ctf_dwarf_init_die(int fd, Elf *elf, ctf_cu_t *cup, int ndie, char *errbuf, - size_t errlen) +ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw, + mutex_t *dwlock, Dwarf_Error *derr, uint_t ndies, ctf_cu_t *cdies, + uint_t flags, char *errbuf, size_t errlen) { - int ret; Dwarf_Unsigned hdrlen, abboff, nexthdr; Dwarf_Half addrsz, vers; Dwarf_Unsigned offset = 0; - Dwarf_Error derr; + uint_t added = 0; + int ret, i = 0; - while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, &vers, - &abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) { + while ((ret = dwarf_next_cu_header(dw, &hdrlen, &vers, &abboff, + &addrsz, &nexthdr, derr)) != DW_DLV_NO_ENTRY) { + Dwarf_Die cu; + ctf_cu_t *cup; char *name; - Dwarf_Die cu, child; - /* Based on the counting above, we should be good to go */ - VERIFY(ret == DW_DLV_OK); - if (ndie > 0) { - ndie--; - offset = nexthdr; - continue; + VERIFY3U(i, <, ndies); + + cup = &cdies[i++]; + + cup->cu_fd = fd; + cup->cu_elf = elf; + cup->cu_dwarf = dw; + cup->cu_errbuf = errbuf; + cup->cu_errlen = errlen; + cup->cu_dwarf = dw; + if (ndies > 1) { + /* + * Only need to lock calls into libdwarf if there are + * multiple CUs. + */ + cup->cu_dwlock = dwlock; + cup->cu_doweaks = B_FALSE; + } else { + cup->cu_doweaks = B_TRUE; } - /* - * Compilers are apparently inconsistent. Some emit no DWARF for - * empty files and others emit empty compilation unit. - */ cup->cu_voidtid = CTF_ERR; cup->cu_longtid = CTF_ERR; - cup->cu_elf = elf; + cup->cu_cuoff = offset; cup->cu_maxoff = nexthdr - 1; cup->cu_vers = vers; cup->cu_addrsz = addrsz; - cup->cu_ctfp = ctf_fdcreate(fd, &ret); - if (cup->cu_ctfp == NULL) - return (ret); - avl_create(&cup->cu_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t), - offsetof(ctf_dwmap_t, cdm_avl)); - cup->cu_errbuf = errbuf; - cup->cu_errlen = errlen; - bzero(&cup->cu_vars, sizeof (ctf_list_t)); - bzero(&cup->cu_funcs, sizeof (ctf_list_t)); - bzero(&cup->cu_bitfields, sizeof (ctf_list_t)); - - if ((ret = ctf_dwarf_die_elfenc(elf, cup, errbuf, - errlen)) != 0) + if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0) { + ctf_dprintf("cu %d - no cu %d\n", i, ret); return (ret); - - if ((ret = ctf_dwarf_sib(cup, NULL, &cu)) != 0) - return (ret); - - if (cu == NULL) { - (void) snprintf(errbuf, errlen, - "file does not contain DWARF data"); - return (ECTF_CONVNODEBUG); } - if ((ret = ctf_dwarf_child(cup, cu, &child)) != 0) - return (ret); - - if (child == NULL) { - (void) snprintf(errbuf, errlen, + if (cu == NULL) { + ctf_dprintf("cu %d - no cu data\n", i); + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "file does not contain DWARF data"); return (ECTF_CONVNODEBUG); } - cup->cu_cuoff = offset; - cup->cu_cu = child; - - if ((cup->cu_cmh = ctf_merge_init(fd, &ret)) == NULL) - return (ret); - if (ctf_dwarf_string(cup, cu, DW_AT_name, &name) == 0) { size_t len = strlen(name) + 1; char *b = basename(name); + cup->cu_name = strdup(b); ctf_free(name, len); + if (cup->cu_name == NULL) + return (ENOMEM); } - break; + + ret = ctf_dwarf_child(cup, cu, &cup->cu_cu); + dwarf_dealloc(cup->cu_dwarf, cu, DW_DLA_DIE); + if (ret != 0) { + ctf_dprintf("cu %d - no child '%s' %d\n", + i, cup->cu_name != NULL ? cup->cu_name : "NULL", + ret); + return (ret); + } + + if (cup->cu_cu == NULL) { + size_t len; + + ctf_dprintf("cu %d - no child data '%s' %d\n", + i, cup->cu_name != NULL ? cup->cu_name : "NULL", + ret); + if (cup->cu_name != NULL && + (len = strlen(cup->cu_name)) > 2 && + strncmp(".c", &cup->cu_name[len - 2], 2) == 0) { + /* + * Missing DEBUG data for a .c file, return an + * error unless this is permitted. + */ + if (!(flags & CTF_ALLOW_MISSING_DEBUG)) { + (void) snprintf( + cup->cu_errbuf, cup->cu_errlen, + "file %s is missing debug info", + cup->cu_name); + return (ECTF_CONVNODEBUG); + } + } + } else { + added++; + } + + ctf_dprintf("Pre-initialised cu %d - '%s'\n", i, + cup->cu_name != NULL ? cup->cu_name : "NULL"); + + offset = nexthdr; + } + + /* + * If none of the CUs had debug data, return an error. + */ + if (added == 0) + return (ECTF_CONVNODEBUG); + + return (0); +} + +static int +ctf_dwarf_init_die(ctf_cu_t *cup) +{ + int ret; + + cup->cu_ctfp = ctf_fdcreate(cup->cu_fd, &ret); + if (cup->cu_ctfp == NULL) + return (ret); + + avl_create(&cup->cu_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t), + offsetof(ctf_dwmap_t, cdm_avl)); + + if ((ret = ctf_dwarf_die_elfenc(cup->cu_elf, cup, + cup->cu_errbuf, cup->cu_errlen)) != 0) { + return (ret); } + if ((cup->cu_cmh = ctf_merge_init(cup->cu_fd, &ret)) == NULL) + return (ret); + return (0); } @@ -3165,8 +3285,10 @@ c_source_has_debug(const char *file, ctf_cu_t *cus, size_t nr_cus) return (B_TRUE); for (size_t i = 0; i < nr_cus; i++) { - if (strcmp(basename, cus[i].cu_name) == 0) + if (cus[i].cu_name != NULL && + strcmp(basename, cus[i].cu_name) == 0) { return (B_TRUE); + } } return (B_FALSE); @@ -3239,7 +3361,7 @@ ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf, if (!c_source_has_debug(file, cus, nr_cus)) { (void) snprintf(errmsg, errlen, - "file %s is missing debug info\n", file); + "file %s is missing debug info", file); return (ECTF_CONVNODEBUG); } } @@ -3247,15 +3369,122 @@ ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf, return (0); } +static int +ctf_dwarf_convert_batch(uint_t start, uint_t end, int fd, uint_t nthrs, + workq_t *wqp, ctf_cu_t *cdies, ctf_file_t **fpp) +{ + ctf_file_t *fpprev = NULL; + uint_t i, added; + ctf_cu_t *cup; + int ret, err; + + ctf_dprintf("Processing CU batch %u - %u\n", start, end - 1); + + added = 0; + for (i = start; i < end; i++) { + cup = &cdies[i]; + if (cup->cu_cu == NULL) + continue; + ctf_dprintf("adding cu %s: %p, %x %x\n", + cup->cu_name != NULL ? cup->cu_name : "NULL", + cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff); + if (workq_add(wqp, cup) == -1) { + err = errno; + goto out; + } + added++; + } + + /* + * No debug data found in this batch, move on to the next. + * NB: ctf_dwarf_preinit_dies() has already checked that there is at + * least one CU with debug data present. + */ + if (added == 0) { + err = 0; + goto out; + } + + /* Run the conversions */ + ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, &err); + if (ret == WORKQ_ERROR) { + err = errno; + goto out; + } else if (ret == WORKQ_UERROR) { + ctf_dprintf("internal convert failed: %s\n", + ctf_errmsg(err)); + goto out; + } + + ctf_merge_t *cmp = ctf_merge_init(fd, &err); + if (cmp == NULL) + goto out; + + if ((err = ctf_merge_set_nthreads(cmp, nthrs)) != 0) { + ctf_merge_fini(cmp); + goto out; + } + + /* + * If we have the result of a previous merge then add it as an input to + * the next one. + */ + if (*fpp != NULL) { + ctf_dprintf("adding previous merge CU\n"); + fpprev = *fpp; + *fpp = NULL; + if ((err = ctf_merge_add(cmp, fpprev)) != 0) { + ctf_merge_fini(cmp); + goto out; + } + } + + ctf_dprintf("adding CUs to merge\n"); + for (i = start; i < end; i++) { + cup = &cdies[i]; + if (cup->cu_cu == NULL) + continue; + if ((err = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) { + ctf_merge_fini(cmp); + *fpp = NULL; + goto out; + } + } + + ctf_dprintf("performing merge\n"); + err = ctf_merge_merge(cmp, fpp); + if (err != 0) { + ctf_dprintf("failed merge!\n"); + *fpp = NULL; + ctf_merge_fini(cmp); + goto out; + } + + ctf_merge_fini(cmp); + + ctf_dprintf("freeing CUs\n"); + for (i = start; i < end; i++) { + cup = &cdies[i]; + ctf_dprintf("freeing cu %d\n", i); + ctf_dwarf_free_die(cup); + } + +out: + ctf_close(fpprev); + return (err); +} + int -ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, uint_t flags, +ctf_dwarf_convert(int fd, Elf *elf, uint_t bsize, uint_t nthrs, uint_t flags, ctf_file_t **fpp, char *errbuf, size_t errlen) { - int err, ret, ndies, i; + int err, ret; + uint_t ndies, i; Dwarf_Debug dw; Dwarf_Error derr; ctf_cu_t *cdies = NULL, *cup; workq_t *wqp = NULL; + mutex_t dwlock = ERRORCHECKMUTEX; *fpp = NULL; @@ -3288,116 +3517,74 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, uint_t flags, if (ndies == 0) { (void) snprintf(errbuf, errlen, "file does not contain DWARF data\n"); + (void) dwarf_finish(dw, &derr); return (ECTF_CONVNODEBUG); } - (void) dwarf_finish(dw, &derr); cdies = ctf_alloc(sizeof (ctf_cu_t) * ndies); if (cdies == NULL) { + (void) dwarf_finish(dw, &derr); return (ENOMEM); } bzero(cdies, sizeof (ctf_cu_t) * ndies); - for (i = 0; i < ndies; i++) { - cup = &cdies[i]; - ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, - &cup->cu_dwarf, &derr); - if (ret != 0) { - ctf_free(cdies, sizeof (ctf_cu_t) * ndies); - (void) snprintf(errbuf, errlen, - "failed to initialize DWARF: %s\n", - dwarf_errmsg(derr)); - return (ECTF_CONVBKERR); - } - - err = ctf_dwarf_init_die(fd, elf, cup, i, errbuf, errlen); - if (err != 0) - goto out; - - cup->cu_doweaks = ndies > 1 ? B_FALSE : B_TRUE; + if ((err = ctf_dwarf_preinit_dies(fd, elf, dw, &dwlock, &derr, + ndies, cdies, flags, errbuf, errlen)) != 0) { + goto out; } if (!(flags & CTF_ALLOW_MISSING_DEBUG) && (err = ctf_dwarf_check_missing(cdies, ndies, - elf, errbuf, errlen)) != 0) - goto out; - - /* - * If we only have one compilation unit, there's no reason to use - * multiple threads, even if the user requested them. After all, they - * just gave us an upper bound. - */ - if (ndies == 1) - nthrs = 1; - - if (workq_init(&wqp, nthrs) == -1) { - err = errno; + elf, errbuf, errlen)) != 0) { goto out; } - for (i = 0; i < ndies; i++) { - cup = &cdies[i]; - ctf_dprintf("adding cu %s: %p, %x %x\n", cup->cu_name, - cup->cu_cu, cup->cu_cuoff, cup->cu_maxoff); - if (workq_add(wqp, cup) == -1) { - err = errno; + /* Only one cu, no merge required */ + if (ndies == 1) { + cup = cdies; + + if ((err = ctf_dwarf_convert_one(cup, NULL)) != 0) goto out; - } + + *fpp = cup->cu_ctfp; + cup->cu_ctfp = NULL; + ctf_dwarf_free_die(cup); + goto success; } - ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, &err); - if (ret == WORKQ_ERROR) { + /* + * There's no need to have either more threads or a batch size larger + * than the total number of dies, even if the user requested them. + */ + nthrs = min(ndies, nthrs); + bsize = min(ndies, bsize); + + if (workq_init(&wqp, nthrs) == -1) { err = errno; goto out; - } else if (ret == WORKQ_UERROR) { - ctf_dprintf("internal convert failed: %s\n", - ctf_errmsg(err)); - goto out; } - ctf_dprintf("Determining next phase: have %d CUs\n", ndies); - if (ndies != 1) { - ctf_merge_t *cmp; - - cmp = ctf_merge_init(fd, &err); - if (cmp == NULL) - goto out; - - ctf_dprintf("setting threads\n"); - if ((err = ctf_merge_set_nthreads(cmp, nthrs)) != 0) { - ctf_merge_fini(cmp); - goto out; - } - - for (i = 0; i < ndies; i++) { - cup = &cdies[i]; - if ((err = ctf_merge_add(cmp, cup->cu_ctfp)) != 0) { - ctf_merge_fini(cmp); - goto out; - } - } - - ctf_dprintf("performing merge\n"); - err = ctf_merge_merge(cmp, fpp); + /* + * In order to avoid exhausting memory limits when converting files + * with a large number of dies, we process them in batches. + */ + for (i = 0; i < ndies; i += bsize) { + err = ctf_dwarf_convert_batch(i, min(i + bsize, ndies), + fd, nthrs, wqp, cdies, fpp); if (err != 0) { - ctf_dprintf("failed merge!\n"); *fpp = NULL; - ctf_merge_fini(cmp); goto out; } - ctf_merge_fini(cmp); - err = 0; - ctf_dprintf("successfully converted!\n"); - } else { - err = 0; - *fpp = cdies->cu_ctfp; - cdies->cu_ctfp = NULL; - ctf_dprintf("successfully converted!\n"); } +success: + err = 0; + ctf_dprintf("successfully converted!\n"); + out: + (void) dwarf_finish(dw, &derr); workq_fini(wqp); - ctf_dwarf_free_dies(cdies, ndies); + ctf_free(cdies, sizeof (ctf_cu_t) * ndies); return (err); } diff --git a/usr/src/lib/libctf/common/libctf.h b/usr/src/lib/libctf/common/libctf.h index 57b8376eed..9ad878a107 100644 --- a/usr/src/lib/libctf/common/libctf.h +++ b/usr/src/lib/libctf/common/libctf.h @@ -81,8 +81,8 @@ extern void ctf_diff_fini(ctf_diff_t *); */ #define CTF_ALLOW_MISSING_DEBUG 0x01 -extern ctf_file_t *ctf_fdconvert(int, const char *, uint_t, uint_t, int *, - char *, size_t); +extern ctf_file_t *ctf_fdconvert(int, const char *, uint_t, uint_t, uint_t, + int *, char *, size_t); typedef enum ctf_hsc_ret { CHR_ERROR = -1, diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h index 5c88b9454d..0921a3ec1a 100644 --- a/usr/src/lib/libctf/common/libctf_impl.h +++ b/usr/src/lib/libctf/common/libctf_impl.h @@ -29,9 +29,9 @@ extern "C" { #endif -typedef int (*ctf_convert_f)(int, Elf *, uint_t, uint_t, +typedef int (*ctf_convert_f)(int, Elf *, uint_t, uint_t, uint_t, ctf_file_t **, char *, size_t); -extern int ctf_dwarf_convert(int, Elf *, uint_t, uint_t, +extern int ctf_dwarf_convert(int, Elf *, uint_t, uint_t, uint_t, ctf_file_t **, char *, size_t); /* diff --git a/usr/src/pkg/manifests/developer-build-onbld.mf b/usr/src/pkg/manifests/developer-build-onbld.mf index 53a9df7eb8..cfedad950b 100644 --- a/usr/src/pkg/manifests/developer-build-onbld.mf +++ b/usr/src/pkg/manifests/developer-build-onbld.mf @@ -376,6 +376,7 @@ file path=opt/onbld/man/man1onbld/cddlchk.1onbld file path=opt/onbld/man/man1onbld/check_rtime.1onbld file path=opt/onbld/man/man1onbld/checkpaths.1onbld file path=opt/onbld/man/man1onbld/cstyle.1onbld +file path=opt/onbld/man/man1onbld/ctfconvert.1onbld file path=opt/onbld/man/man1onbld/cw.1onbld file path=opt/onbld/man/man1onbld/find_elf.1onbld file path=opt/onbld/man/man1onbld/findunref.1onbld diff --git a/usr/src/tools/scripts/Makefile b/usr/src/tools/scripts/Makefile index 85ed6fb789..d6cd4cbfda 100644 --- a/usr/src/tools/scripts/Makefile +++ b/usr/src/tools/scripts/Makefile @@ -24,6 +24,7 @@ # Copyright 2010, Richard Lowe # # Copyright 2020 Joyent, Inc. +# Copyright 2020 OmniOS Community Edition (OmniOSce) Association. SHELL=/usr/bin/ksh93 @@ -83,6 +84,7 @@ MAN1ONBLDFILES= \ cddlchk.1onbld \ checkpaths.1onbld \ check_rtime.1onbld \ + ctfconvert.1onbld \ cstyle.1onbld \ find_elf.1onbld \ flg.flp.1onbld \ diff --git a/usr/src/tools/scripts/ctfconvert.1onbld b/usr/src/tools/scripts/ctfconvert.1onbld new file mode 100644 index 0000000000..3a75cc0b16 --- /dev/null +++ b/usr/src/tools/scripts/ctfconvert.1onbld @@ -0,0 +1,116 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +.\" +.Dd October 23, 2020 +.Dt ctfconvert 1ONBLD +.Os +.Sh NAME +.Nm ctfconvert +.Nd Convert ELF object debug data to CTF container +.Sh SYNOPSIS +.Nm +.Op Fl ikm +.Op Fl b Ar batchsize +.Op Fl j Ar threads +.Op Fl l Ar label | Fl L Ar labelenv +.Op Fl o Ar outfile +.Ar ELF_object +.Sh DESCRIPTION +The +.Nm +utility converts debug information found within +.Ar ELF_object +to CTF data and adds this to a CTF container. +.Ar ELF_object +can be a single object file or a fully linked object such as a shared library +or binary. +.Nm +currently supports input debug data in DWARFv2 or DWARFv4 format. +Unless the +.Fl o +option is present, this is done in-place; the original file being modified +with a new CTF container being added. +For in-place processing, unless the +.Fl k +option is present, the source file will be removed if an error occurs. +.Sh OPTIONS +The following options are supported: +.Bl -tag -width Ar +.It Fl i +Ignore files not built partially from C sources. +.Nm +will usually check +.Ar ELF_object +to see if at least one of the input files was a +.Sq .c +file, and exit with an error if not. +The +.Fl i +option overrides this check and allows processing to continue. +.It Fl k +When processing a file in-place and an error occurs, keep the input file +rather than deleting it. +.It Fl m +Allow +.Ar ELF_object +to have missing debug data. +By default, +.Nm +requires that each C source compilation unit in +.Ar ELF_object +contains debug data, and will exit with an error if this is not the case. +The +.Fl m +option relaxes this restriction allowing processing of such files. +Note that if the file contains no debug data in any of the compilation units +then this flag will cause +.Nm +to exit successfully without taking any action, and can mask missing CTF data. +.It Fl b Ar batchsize +Batch-process this many compilation units from the source file at once (default +256). This helps to reduce memory usage when processing large objects which +were built from many source files. +.It Fl j Ar threads +Use this many threads to perform the merge (default 4). +.It Fl l Ar label +Set the output container's label to the specified value. +.It Fl L Ar labelenv +Set the output container's label to the value of the specified environment +variable. +.It Fl o Ar outfile +Write the new object with added CTF ta to the specified output file, rather +than updating the input in-place. +.El +.Sh OPERANDS +The following operands are supported: +.Bl -tag -width Ar +.It Ar object_file +The source object file to process. +.El +.Sh EXIT STATUS +.Bl -inset +.It Sy 0 +.Dl Execution completed successfully. +.It Sy 1 +.Dl A fatal error occurred. +.It Sy 2 +.Dl Invalid command line options were specified. +.El +.Sh INTERFACE STABILITY +The command line interface of +.Nm +is +.Sy Uncommitted . +.Sh SEE ALSO +.Xr ctfdiff 1 , +.Xr ctfdump 1 , +.Xr ctf 4 |