diff options
author | Andy Fiddaman <omnios@citrus-it.co.uk> | 2020-11-04 12:07:58 +0000 |
---|---|---|
committer | Andy Fiddaman <omnios@citrus-it.co.uk> | 2020-12-17 21:17:56 +0000 |
commit | dd4422524768709a579a2a93a10c78a88a6b0ecb (patch) | |
tree | 7716bcc59f22cd4891503a8bc22e17710a774d28 /usr/src/lib/libctf/common/ctf_dwarf.c | |
parent | 93d78aba5b32996fc2ae893a6237a0d3972f86b2 (diff) | |
download | illumos-gate-dd4422524768709a579a2a93a10c78a88a6b0ecb.tar.gz |
13280 CTF: provide option to truncate and continue
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Approved by: Rich Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/lib/libctf/common/ctf_dwarf.c')
-rw-r--r-- | usr/src/lib/libctf/common/ctf_dwarf.c | 191 |
1 files changed, 125 insertions, 66 deletions
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c index 1618c8add4..6897dd3047 100644 --- a/usr/src/lib/libctf/common/ctf_dwarf.c +++ b/usr/src/lib/libctf/common/ctf_dwarf.c @@ -274,6 +274,7 @@ typedef struct ctf_die { avl_tree_t cu_map; /* map die offsets to CTF types */ char *cu_errbuf; /* error message buffer */ size_t cu_errlen; /* error message buffer length */ + ctf_convert_t *cu_handle; /* ctf convert handle */ size_t cu_ptrsz; /* object's pointer size */ boolean_t cu_bigend; /* is it big endian */ boolean_t cu_doweaks; /* should we convert weak symbols? */ @@ -485,7 +486,7 @@ ctf_dwarf_ref(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp) } (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to get unsigned attribute for type: %s\n", + "failed to get attribute descriptor offset: %s\n", dwarf_errmsg(derr)); return (ECTF_CONVBKERR); } @@ -535,7 +536,7 @@ ctf_dwarf_signed(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Half name, } (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to get unsigned attribute for type: %s\n", + "failed to get signed attribute for type: %s\n", dwarf_errmsg(derr)); return (ECTF_CONVBKERR); } @@ -649,7 +650,8 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) 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", + "failed to get dwarf attribute for for member " + "location: %s\n", dwarf_errmsg(derr)); ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ECTF_CONVBKERR); @@ -679,7 +681,7 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) if (sign < 0) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "encountered negative member data " - "location: %d", sign); + "location: %d\n", sign); } *valp = (Dwarf_Unsigned)sign; return (0); @@ -689,7 +691,7 @@ 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", + "failed to obtain location list for member offset: %s\n", dwarf_errmsg(derr)); ctf_dwarf_dealloc(cup, attr, DW_DLA_ATTR); return (ECTF_CONVBKERR); @@ -699,7 +701,7 @@ ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) 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"); + "failed to parse location structure for member\n"); ctf_dwarf_dealloc(cup, loc->ld_s, DW_DLA_LOC_BLOCK); ctf_dwarf_dealloc(cup, loc, DW_DLA_LOCDESC); return (ECTF_CONVBKERR); @@ -853,7 +855,7 @@ ctf_dwarf_die_elfenc(Elf *elf, ctf_cu_t *cup, char *errbuf, size_t errlen) VERIFY(ctf_setmodel(cup->cu_ctfp, CTF_MODEL_LP64) == 0); } else { (void) snprintf(errbuf, errlen, - "unknown ELF class %d", ehdr.e_ident[EI_CLASS]); + "unknown ELF class %d\n", ehdr.e_ident[EI_CLASS]); return (ECTF_CONVBKERR); } @@ -863,7 +865,7 @@ ctf_dwarf_die_elfenc(Elf *elf, ctf_cu_t *cup, char *errbuf, size_t errlen) cup->cu_bigend = B_TRUE; } else { (void) snprintf(errbuf, errlen, - "unknown ELF data encoding: %hhu", ehdr.e_ident[EI_DATA]); + "unknown ELF data encoding: %hhu\n", ehdr.e_ident[EI_DATA]); return (ECTF_CONVBKERR); } @@ -1031,7 +1033,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 unknown DWARF encoding: %d", type); + "encountered unknown DWARF encoding: %d\n", type); return (ECTF_CONVBKERR); } @@ -1230,7 +1232,7 @@ ctf_dwarf_member_offset(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t mid, if ((tsz = ctf_type_size(cup->cu_ctfp, mid)) == CTF_ERR) { int e = ctf_errno(cup->cu_ctfp); (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to get type size: %s", ctf_errmsg(e)); + "failed to get type size: %s\n", ctf_errmsg(e)); return (ECTF_CONVBKERR); } } else { @@ -1350,7 +1352,7 @@ ctf_dwarf_member_bitfield(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp) name, &e); if (cdb->cdb_id == CTF_ERR) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to get add bitfield type %s: %s", name, + "failed to get add bitfield type %s: %s\n", name, ctf_errmsg(ctf_errno(cup->cu_ctfp))); ctf_free(name, namesz + 1); ctf_free(cdb, sizeof (ctf_dwbitf_t)); @@ -1437,7 +1439,7 @@ ctf_dwarf_fixup_sou(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t base, boolean_t add) ret = ctf_add_member(cup->cu_ctfp, base, mname, mid, memboff); if (ret == CTF_ERR) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to add member %s: %s", + "failed to add member %s: %s\n", mname, ctf_errmsg(ctf_errno(cup->cu_ctfp))); if (mname != NULL) ctf_free(mname, strlen(mname) + 1); @@ -1466,7 +1468,7 @@ next: if ((ctf_set_size(cup->cu_ctfp, base, size)) == CTF_ERR) { int e = ctf_errno(cup->cu_ctfp); (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to set type size for %d to 0x%x: %s", base, + "failed to set type size for %d to 0x%x: %s\n", base, (uint32_t)size, ctf_errmsg(e)); return (ECTF_CONVBKERR); } @@ -1891,14 +1893,14 @@ ctf_dwarf_create_enum(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot) Dwarf_Die child; Dwarf_Unsigned dw; ctf_id_t id; - char *name; + char *enumname; int ret; - if ((ret = ctf_dwarf_string(cup, die, DW_AT_name, &name)) != 0 && - ret != ENOENT) + ret = ctf_dwarf_string(cup, die, DW_AT_name, &enumname); + if (ret != 0 && ret != ENOENT) return (ret); if (ret == ENOENT) - name = NULL; + enumname = NULL; /* * Enumerations may have a size associated with them, particularly if @@ -1910,20 +1912,21 @@ ctf_dwarf_create_enum(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot) size = (size_t)dw; } - id = ctf_add_enum(cup->cu_ctfp, isroot, name, size); - ctf_dprintf("added enum %s (%d)\n", name, id); - if (name != NULL) - ctf_free(name, strlen(name) + 1); - if (id == CTF_ERR) - return (ctf_errno(cup->cu_ctfp)); + id = ctf_add_enum(cup->cu_ctfp, isroot, enumname, size); + ctf_dprintf("added enum %s (%d)\n", + enumname == NULL ? "<anon>" : enumname, id); + if (id == CTF_ERR) { + ret = ctf_errno(cup->cu_ctfp); + goto out; + } *idp = id; if ((ret = ctf_dwmap_add(cup, id, die, B_FALSE)) != 0) - return (ret); + goto out; if ((ret = ctf_dwarf_child(cup, die, &child)) != 0) { if (ret == ENOENT) ret = 0; - return (ret); + goto out; } while (child != NULL) { @@ -1931,18 +1934,20 @@ ctf_dwarf_create_enum(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot) Dwarf_Signed sval; Dwarf_Unsigned uval; Dwarf_Die arg = child; + char *name; int eval; if ((ret = ctf_dwarf_sib(cup, arg, &child)) != 0) - return (ret); + break; if ((ret = ctf_dwarf_tag(cup, arg, &tag)) != 0) - return (ret); + break; if (tag != DW_TAG_enumerator) { if ((ret = ctf_dwarf_convert_type(cup, arg, NULL, - CTF_ADD_NONROOT)) != 0) - return (ret); + CTF_ADD_NONROOT)) != 0) { + break; + } continue; } @@ -1950,7 +1955,7 @@ ctf_dwarf_create_enum(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot) * DWARF v4 section 5.7 tells us we'll always have names. */ if ((ret = ctf_dwarf_string(cup, arg, DW_AT_name, &name)) != 0) - return (ret); + break; /* * We have to be careful here: newer GCCs generate DWARF where @@ -1961,32 +1966,62 @@ ctf_dwarf_create_enum(ctf_cu_t *cup, Dwarf_Die die, ctf_id_t *idp, int isroot) if ((ret = ctf_dwarf_unsigned(cup, arg, DW_AT_const_value, &uval)) == 0) { eval = (int)uval; - } else if ((ret = ctf_dwarf_signed(cup, arg, DW_AT_const_value, - &sval)) == 0) { - eval = sval; + } else { + /* + * ctf_dwarf_unsigned will have left an error in the + * buffer + */ + *cup->cu_errbuf = '\0'; + + if ((ret = ctf_dwarf_signed(cup, arg, DW_AT_const_value, + &sval)) == 0) { + eval = sval; + } } if (ret != 0) { - if (ret != ENOENT) - return (ret); - - (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "encountered enumeration without constant value\n"); - return (ECTF_CONVBKERR); + if (ret == ENOENT) { + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, + "encountered enumeration without constant " + "value\n"); + ret = ECTF_CONVBKERR; + } + ctf_free(name, strlen(name) + 1); + break; } ret = ctf_add_enumerator(cup->cu_ctfp, id, name, eval); if (ret == CTF_ERR) { - (void) snprintf(cup->cu_errbuf, cup->cu_errlen, - "failed to add enumarator %s (%d) to %d\n", - name, eval, id); + ret = ctf_errno(cup->cu_ctfp); + + if (ret == ECTF_DTFULL && (cup->cu_handle->cch_flags & + CTF_ALLOW_TRUNCATION)) { + if (cup->cu_handle->cch_warncb != NULL) { + cup->cu_handle->cch_warncb( + cup->cu_handle->cch_warncb_arg, + "truncating enumeration %s at %s\n", + name, enumname == NULL ? "<anon>" : + enumname); + } + ret = 0; + } else { + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, + "failed to add enumerator %s (%d) " + "to %s (%d)\n", name, eval, + enumname == NULL ? "<anon>" : enumname, id); + } ctf_free(name, strlen(name) + 1); - return (ctf_errno(cup->cu_ctfp)); + break; } ctf_free(name, strlen(name) + 1); } - return (0); +out: + + if (enumname != NULL) + ctf_free(enumname, strlen(enumname) + 1); + + return (ret); } /* @@ -3124,9 +3159,9 @@ ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, uint_t *ndies, * be able to finish the rest in a (potentially) multithreaded context. */ static int -ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw, +ctf_dwarf_preinit_dies(ctf_convert_t *cch, 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) + char *errbuf, size_t errlen) { Dwarf_Unsigned hdrlen, abboff, nexthdr; Dwarf_Half addrsz, vers; @@ -3144,6 +3179,7 @@ ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw, cup = &cdies[i++]; + cup->cu_handle = cch; cup->cu_fd = fd; cup->cu_elf = elf; cup->cu_dwarf = dw; @@ -3176,7 +3212,7 @@ ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw, 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"); + "file does not contain DWARF data\n"); return (ECTF_CONVNODEBUG); } @@ -3212,13 +3248,20 @@ ctf_dwarf_preinit_dies(int fd, Elf *elf, Dwarf_Debug dw, * Missing DEBUG data for a .c file, return an * error unless this is permitted. */ - if (!(flags & CTF_ALLOW_MISSING_DEBUG)) { + if (!(cch->cch_flags & + CTF_ALLOW_MISSING_DEBUG)) { (void) snprintf( cup->cu_errbuf, cup->cu_errlen, - "file %s is missing debug info", + "missing debug information " + "(first seen in %s)\n", cup->cu_name); return (ECTF_CONVNODEBUG); } + if (cch->cch_warncb != NULL) { + cch->cch_warncb(cch->cch_warncb_arg, + "file %s is missing debug " + "information\n", cup->cu_name); + } } } else { added++; @@ -3304,13 +3347,14 @@ c_source_has_debug(const char *file, ctf_cu_t *cus, size_t nr_cus) } static int -ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf, - char *errmsg, size_t errlen) +ctf_dwarf_check_missing(ctf_convert_t *cch, 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; + int ret = 0; scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { @@ -3369,13 +3413,22 @@ ctf_dwarf_check_missing(ctf_cu_t *cus, size_t nr_cus, Elf *elf, continue; if (!c_source_has_debug(file, cus, nr_cus)) { - (void) snprintf(errmsg, errlen, - "file %s is missing debug info", file); - return (ECTF_CONVNODEBUG); + if (cch->cch_warncb != NULL) { + cch->cch_warncb( + cch->cch_warncb_arg, + "file %s is missing debug information\n", + file); + } + if (ret != ECTF_CONVNODEBUG) { + (void) snprintf(errmsg, errlen, + "missing debug information " + "(first seen in %s)\n", file); + ret = ECTF_CONVNODEBUG; + } } } - return (0); + return (ret); } static int @@ -3488,11 +3541,11 @@ out: } int -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) +ctf_dwarf_convert(ctf_convert_t *cch, int fd, Elf *elf, ctf_file_t **fpp, + char *errbuf, size_t errlen) { int err, ret; - uint_t ndies, i; + uint_t ndies, i, bsize, nthrs; Dwarf_Debug dw; Dwarf_Error derr; ctf_cu_t *cdies = NULL, *cup; @@ -3542,15 +3595,21 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t bsize, uint_t nthrs, uint_t flags, bzero(cdies, sizeof (ctf_cu_t) * ndies); - if ((err = ctf_dwarf_preinit_dies(fd, elf, dw, &dwlock, &derr, - ndies, cdies, flags, errbuf, errlen)) != 0) { + if ((err = ctf_dwarf_preinit_dies(cch, fd, elf, dw, &dwlock, &derr, + ndies, cdies, 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 ((err = ctf_dwarf_check_missing(cch, cdies, ndies, elf, + errbuf, errlen)) != 0) { + if (!(cch->cch_flags & CTF_ALLOW_MISSING_DEBUG)) { + goto out; + } + if (err != ECTF_CONVNODEBUG && *errbuf != '\0' && + cch->cch_warncb != NULL) { + cch->cch_warncb(cch->cch_warncb_arg, "%s", errbuf); + *errbuf = '\0'; + } } /* Only one cu, no merge required */ @@ -3570,8 +3629,8 @@ ctf_dwarf_convert(int fd, Elf *elf, uint_t bsize, uint_t nthrs, uint_t flags, * 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); + nthrs = min(ndies, cch->cch_nthreads); + bsize = min(ndies, cch->cch_batchsize); if (workq_init(&wqp, nthrs) == -1) { err = errno; |