# HG changeset patch # User Robert Mustacchi # Date 1578693608 0 # Node ID 2d1e73c83a13d3edbed712070531ce01c18a865f # Parent 4076af232ed948794a6f6ae6a22bd2dcebf9cedc 12228 libctf could handle gcc dwarf4 Reviewed by: John Levon Approved by: Dan McDonald diff -r 4076af232ed9 -r 2d1e73c83a13 usr/src/lib/libctf/common/ctf_dwarf.c --- a/usr/src/lib/libctf/common/ctf_dwarf.c Thu Jul 09 09:08:47 2020 -0700 +++ b/usr/src/lib/libctf/common/ctf_dwarf.c Fri Jan 10 22:00:08 2020 +0000 @@ -209,6 +209,7 @@ #include #define DWARF_VERSION_TWO 2 +#define DWARF_VERSION_FOUR 4 #define DWARF_VARARGS_NAME "..." /* @@ -262,6 +263,8 @@ Dwarf_Die cu_cu; /* libdwarf compilation unit */ Dwarf_Off cu_cuoff; /* cu's offset */ Dwarf_Off cu_maxoff; /* maximum offset */ + Dwarf_Half cu_vers; /* Dwarf Version */ + Dwarf_Half cu_addrsz; /* Dwarf Address Size */ ctf_file_t *cu_ctfp; /* output CTF file */ avl_tree_t cu_map; /* map die offsets to CTF types */ char *cu_errbuf; /* error message buffer */ @@ -576,6 +579,13 @@ return (ECTF_CONVBKERR); } +/* + * The encoding of a DW_AT_data_member_location has changed between different + * revisions of the specification. It may be a general udata form or it may be + * location data information. In DWARF 2, it is only the latter. In later + * revisions of the spec, it may be either. To determine the form, we ask the + * class, which will be of type CONSTANT. + */ static int ctf_dwarf_member_location(ctf_cu_t *cup, Dwarf_Die die, Dwarf_Unsigned *valp) { @@ -584,11 +594,49 @@ Dwarf_Attribute attr; Dwarf_Locdesc *loc; Dwarf_Signed locnum; + Dwarf_Half form; + enum Dwarf_Form_Class class; if ((ret = ctf_dwarf_attribute(cup, die, DW_AT_data_member_location, &attr)) != 0) return (ret); + if (dwarf_whatform(attr, &form, &derr) != 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); + return (ECTF_CONVBKERR); + } + + class = dwarf_get_form_class(cup->cu_vers, DW_AT_data_member_location, + cup->cu_addrsz, form); + if (class == DW_FORM_CLASS_CONSTANT) { + Dwarf_Signed sign; + + /* + * We have a constant. We need to try to get both this as signed + * and unsigned data, as unfortunately, DWARF doesn't define the + * sign. Which is a joy. We try unsigned first. If neither + * 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); + return (0); + } + + if (dwarf_formsdata(attr, &sign, &derr) == DW_DLV_OK) { + dwarf_dealloc(cup->cu_dwarf, attr, DW_DLA_ATTR); + if (sign < 0) { + (void) snprintf(cup->cu_errbuf, cup->cu_errlen, + "encountered negative member data " + "location: %d", sign); + } + *valp = (Dwarf_Unsigned)sign; + return (0); + } + } + if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) { (void) snprintf(cup->cu_errbuf, cup->cu_errlen, "failed to obtain location list for member offset: %s", @@ -2986,7 +3034,11 @@ return (ECTF_CONVBKERR); } - if (vers != DWARF_VERSION_TWO) { + switch (vers) { + case DWARF_VERSION_TWO: + case DWARF_VERSION_FOUR: + break; + default: (void) snprintf(errbuf, errlen, "unsupported DWARF version: %d\n", vers); return (ECTF_CONVBKERR); @@ -3003,11 +3055,11 @@ { int ret; Dwarf_Unsigned hdrlen, abboff, nexthdr; - Dwarf_Half addrsz; + Dwarf_Half addrsz, vers; Dwarf_Unsigned offset = 0; Dwarf_Error derr; - while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, NULL, + while ((ret = dwarf_next_cu_header(cup->cu_dwarf, &hdrlen, &vers, &abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) { char *name; Dwarf_Die cu, child; @@ -3028,6 +3080,8 @@ cup->cu_longtid = CTF_ERR; cup->cu_elf = elf; 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);