summaryrefslogtreecommitdiff
path: root/usr/src/lib/libctf/common/ctf_dwarf.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libctf/common/ctf_dwarf.c')
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c80
1 files changed, 59 insertions, 21 deletions
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
index 13a049d243..f490c8f351 100644
--- a/usr/src/lib/libctf/common/ctf_dwarf.c
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -469,7 +469,7 @@ ctf_dwarf_refdie(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
Dwarf_Off off;
Dwarf_Error derr;
- if ((ret = ctf_dwarf_ref(cdp, die, DW_AT_type, &off)) != 0)
+ if ((ret = ctf_dwarf_ref(cdp, die, name, &off)) != 0)
return (ret);
off += cdp->cd_cuoff;
@@ -630,6 +630,17 @@ ctf_dwarf_offset(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Off *offsetp)
return (ECTF_CONVBKERR);
}
+/* simpler variant for debugging output */
+static Dwarf_Off
+ctf_die_offset(Dwarf_Die die)
+{
+ Dwarf_Off off = -1;
+ Dwarf_Error derr;
+
+ (void) dwarf_dieoffset(die, &off, &derr);
+ return (off);
+}
+
static int
ctf_dwarf_tag(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half *tagp)
{
@@ -1547,7 +1558,6 @@ ctf_dwarf_create_enum(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
if ((ret = ctf_dwmap_add(cdp, id, die, B_FALSE)) != 0)
return (ret);
-
if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0) {
if (ret == ENOENT)
ret = 0;
@@ -1574,27 +1584,35 @@ ctf_dwarf_create_enum(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
continue;
}
- if ((ret = ctf_dwarf_signed(cdp, arg, DW_AT_const_value,
- &sval)) == 0) {
- eval = sval;
- } else if (ret != ENOENT) {
+ /*
+ * DWARF v4 section 5.7 tells us we'll always have names.
+ */
+ if ((ret = ctf_dwarf_string(cdp, arg, DW_AT_name, &name)) != 0)
return (ret);
- } else if ((ret = ctf_dwarf_unsigned(cdp, arg,
- DW_AT_const_value, &uval)) == 0) {
+
+ /*
+ * We have to be careful here: newer GCCs generate DWARF where
+ * an unsigned value will happily pass ctf_dwarf_signed().
+ * Since negative values will fail ctf_dwarf_unsigned(), we try
+ * that first to make sure we get the right value.
+ */
+ if ((ret = ctf_dwarf_unsigned(cdp, arg, DW_AT_const_value,
+ &uval)) == 0) {
eval = (int)uval;
- } else {
+ } else if ((ret = ctf_dwarf_signed(cdp, arg, DW_AT_const_value,
+ &sval)) == 0) {
+ eval = sval;
+ }
+
+ if (ret != 0) {
+ if (ret != ENOENT)
+ return (ret);
+
(void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
- "encountered enumration without constant value\n");
+ "encountered enumeration without constant value\n");
return (ECTF_CONVBKERR);
}
- /*
- * DWARF v4 section 5.7 tells us we'll always have names.
- */
- if ((ret = ctf_dwarf_string(cdp, arg, DW_AT_name,
- &name)) != 0)
- return (ret);
-
ret = ctf_add_enumerator(cdp->cd_ctfp, id, name, eval);
if (ret == CTF_ERR) {
(void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
@@ -1995,11 +2013,31 @@ ctf_dwarf_convert_variable(ctf_die_t *cdp, Dwarf_Die die)
ctf_id_t id;
ctf_dwvar_t *cdv;
- if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) != 0) {
- if (ret != ENOENT)
+ /* Skip "Non-Defining Declarations" */
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) == 0) {
+ if (b != 0)
+ return (0);
+ } else if (ret != ENOENT) {
+ return (ret);
+ }
+
+ /*
+ * If we find a DIE of "Declarations Completing Non-Defining
+ * Declarations", we will use the referenced type's DIE. This isn't
+ * quite correct, e.g. DW_AT_decl_line will be the forward declaration
+ * not this site. It's sufficient for what we need, however: in
+ * particular, we should find DW_AT_external as needed there.
+ */
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_specification,
+ &tdie)) == 0) {
+ Dwarf_Off offset;
+ if ((ret = ctf_dwarf_offset(cdp, tdie, &offset)) != 0)
return (ret);
- } else if (b != 0) {
- return (0);
+ ctf_dprintf("die 0x%llx DW_AT_specification -> die 0x%llx\n",
+ ctf_die_offset(die), ctf_die_offset(tdie));
+ die = tdie;
+ } else if (ret != ENOENT) {
+ return (ret);
}
if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&