Author: dim
Date: Sat Mar 29 17:18:23 2014
New Revision: 263915
URL: http://svnweb.freebsd.org/changeset/base/263915

Log:
  MFC r260880 (by kaiw, from projects/elftoolchain):
  
    * Make die_mem_offset() be able to handle DW_AT_data_member_location
      attributes generated by Clang 3.4.
    * Document how different compilers generate DW_AT_data_member_location
      attributes differently.
    * Document the quirks about DW_FORM_data[48].
  
  This is a slightly modified version, adapted to work with the old
  libdwarf in stable/9 and stable/10.  It should fix DTrace on these
  branches, when the kernel is compiled with clang 3.4.
  
  Note that you have to build *and* install the CTF tools first, before
  building the kernel.  Otherwise you can possibly still get error
  messages similar to "failed to copy type of 'pr_uid': Type information
  is in parent and unavailable", when attempting to run dtrace(1).
  
  Submitted by: kaiw

Modified:
  stable/9/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
Directory Properties:
  stable/9/cddl/contrib/opensolaris/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/10/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/9/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c
==============================================================================
--- stable/9/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c     Sat Mar 29 
14:35:36 2014        (r263914)
+++ stable/9/cddl/contrib/opensolaris/tools/ctf/cvt/dwarf.c     Sat Mar 29 
17:18:23 2014        (r263915)
@@ -489,16 +489,59 @@ die_mem_offset(dwarf_t *dw, Dwarf_Die di
 {
        Dwarf_Locdesc *loc = NULL;
        Dwarf_Signed locnum = 0;
+       Dwarf_Attribute at;
+       Dwarf_Half form;
 
-       if (dwarf_locdesc(die, name, &loc, &locnum, &dw->dw_err) != DW_DLV_OK)
+       if (name != DW_AT_data_member_location)
+               terminate("die %llu: can only process attribute "
+                   "DW_AT_data_member_location\n", die_off(dw, die));
+
+       if ((at = die_attr(dw, die, name, 0)) == NULL)
                return (0);
 
-       if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
-               terminate("die %llu: cannot parse member offset\n",
-                   die_off(dw, die));
-       }
+       if (dwarf_whatform(at, &form, &dw->dw_err) != DW_DLV_OK)
+               return (0);
 
-       *valp = loc->ld_s->lr_number;
+       switch (form) {
+       case DW_FORM_block:
+       case DW_FORM_block1:
+       case DW_FORM_block2:
+       case DW_FORM_block4:
+               /*
+                * GCC in base and Clang (3.3 or below) generates
+                * DW_AT_data_member_location attribute with DW_FORM_block*
+                * form. The attribute contains one DW_OP_plus_uconst
+                * operator. The member offset stores in the operand.
+                */
+               if (dwarf_locdesc(die, name, &loc, &locnum, &dw->dw_err) !=
+                   DW_DLV_OK)
+                       return (0);
+               if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
+                       terminate("die %llu: cannot parse member offset\n",
+                           die_off(dw, die));
+               }
+               *valp = loc->ld_s->lr_number;
+               break;
+
+       case DW_FORM_data1:
+       case DW_FORM_data2:
+       case DW_FORM_data4:
+       case DW_FORM_data8:
+       case DW_FORM_udata:
+               /*
+                * Clang 3.4 generates DW_AT_data_member_location attribute
+                * with DW_FORM_data* form (constant class). The attribute
+                * stores a contant value which is the member offset.
+                */
+               if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) !=
+                   DW_DLV_OK)
+                       return (0);
+               break;
+
+       default:
+               terminate("die %llu: cannot parse member offset with form "
+                   "%u\n", die_off(dw, die), form);
+       }
 
        if (loc != NULL)
                if (dwarf_locdesc_free(loc, &dw->dw_err) != DW_DLV_OK)
@@ -872,6 +915,9 @@ die_sou_create(dwarf_t *dw, Dwarf_Die st
     int type, const char *typename)
 {
        Dwarf_Unsigned sz, bitsz, bitoff;
+#if BYTE_ORDER == _LITTLE_ENDIAN
+       Dwarf_Unsigned bysz;
+#endif
        Dwarf_Die mem;
        mlist_t *ml, **mlastp;
        iidesc_t *ii;
@@ -944,8 +990,26 @@ die_sou_create(dwarf_t *dw, Dwarf_Die st
 #if BYTE_ORDER == _BIG_ENDIAN
                        ml->ml_offset += bitoff;
 #else
-                       ml->ml_offset += tdesc_bitsize(ml->ml_type) - bitoff -
-                           ml->ml_size;
+                       /*
+                        * Note that Clang 3.4 will sometimes generate
+                        * member DIE before generating the DIE for the
+                        * member's type. The code can not handle this
+                        * properly so that tdesc_bitsize(ml->ml_type) will
+                        * return 0 because ml->ml_type is unknown. As a
+                        * result, a wrong member offset will be calculated.
+                        * To workaround this, we can instead try to
+                        * retrieve the value of DW_AT_byte_size attribute
+                        * which stores the byte size of the space occupied
+                        * by the type. If this attribute exists, its value
+                        * should equal to tdesc_bitsize(ml->ml_type)/NBBY.
+                        */
+                       if (die_unsigned(dw, mem, DW_AT_byte_size, &bysz, 0) &&
+                           bysz > 0)
+                               ml->ml_offset += bysz * NBBY - bitoff -
+                                       ml->ml_size;
+                       else
+                               ml->ml_offset += tdesc_bitsize(ml->ml_type) -
+                                       bitoff - ml->ml_size;
 #endif
                }
 
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to