Beispiel #1
0
Dwarf_Unsigned DieHolder::get_bytesize(void)
{
  Dwarf_Unsigned bytesize = 0;
  Dwarf_Error err = NULL;

  CHECK_DWERR(dwarf_bytesize(m_die, &bytesize, &err), err,
              "cannot get DIE byte size");

  return bytesize;
}
Beispiel #2
0
Datei: types.c Projekt: adk9/ohm
int
add_basetype_from_die(Dwarf_Debug dbg, Dwarf_Die parent_die, Dwarf_Die die)
{
    int ret = DW_DLV_ERROR;
    Dwarf_Error err = 0;
    Dwarf_Off offset = 0;
    Dwarf_Unsigned bsz = 0;
    basetype_t *t;

    if (is_base_type(die) != 1)
        return -1;

    ret = dwarf_die_CU_offset(die, &offset, &err);
    if (ret != DW_DLV_OK) {
        derror("error in dwarf_die_CU_offset()");
        goto error;
    }

    ret = dwarf_bytesize(die, &bsz, &err);
    if (ret != DW_DLV_OK) {
        derror("error in dwarf_bytesize()");
        goto error;
    }

    /* We construct a table of base types here so that we can iœndex it
     * later to find the types of some of the probes on the stack. */

    t = get_or_add_type(offset);
    get_child_name(dbg, die, t->name, 128);
    t->ohm_type = get_type_ohmtype(t);
    t->size = bsz;
    t->nelem = 1;
    t->elems = NULL;
    return 1;

error:
    derror("error in add_basetype_from_die()");
    return -1;
}
static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
				    struct perf_probe_arg_field *field,
				    struct probe_trace_arg_ref **ref_ptr,
				    Dwarf_Die *die_mem)
{
	struct probe_trace_arg_ref *ref = *ref_ptr;
	Dwarf_Die type;
	Dwarf_Word offs;
	int ret, tag;

	pr_debug("converting %s in %s\n", field->name, varname);
	if (die_get_real_type(vr_die, &type) == NULL) {
		pr_warning("Failed to get the type of %s.\n", varname);
		return -ENOENT;
	}
	pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
	tag = dwarf_tag(&type);

	if (field->name[0] == '[' &&
	    (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
		if (field->next)
			
			memcpy(die_mem, &type, sizeof(*die_mem));
		
		if (die_get_real_type(&type, &type) == NULL) {
			pr_warning("Failed to get the type of %s.\n", varname);
			return -ENOENT;
		}
		pr_debug2("Array real type: (%x)\n",
			 (unsigned)dwarf_dieoffset(&type));
		if (tag == DW_TAG_pointer_type) {
			ref = zalloc(sizeof(struct probe_trace_arg_ref));
			if (ref == NULL)
				return -ENOMEM;
			if (*ref_ptr)
				(*ref_ptr)->next = ref;
			else
				*ref_ptr = ref;
		}
		ref->offset += dwarf_bytesize(&type) * field->index;
		if (!field->next)
			
			memcpy(die_mem, vr_die, sizeof(*die_mem));
		goto next;
	} else if (tag == DW_TAG_pointer_type) {
		
		if (!field->ref) {
			pr_err("Semantic error: %s must be referred by '->'\n",
			       field->name);
			return -EINVAL;
		}
		
		if (die_get_real_type(&type, &type) == NULL) {
			pr_warning("Failed to get the type of %s.\n", varname);
			return -ENOENT;
		}
		
		if (dwarf_tag(&type) != DW_TAG_structure_type) {
			pr_warning("%s is not a data structure.\n", varname);
			return -EINVAL;
		}

		ref = zalloc(sizeof(struct probe_trace_arg_ref));
		if (ref == NULL)
			return -ENOMEM;
		if (*ref_ptr)
			(*ref_ptr)->next = ref;
		else
			*ref_ptr = ref;
	} else {
		
		if (tag != DW_TAG_structure_type) {
			pr_warning("%s is not a data structure.\n", varname);
			return -EINVAL;
		}
		if (field->name[0] == '[') {
			pr_err("Semantic error: %s is not a pointor"
			       " nor array.\n", varname);
			return -EINVAL;
		}
		if (field->ref) {
			pr_err("Semantic error: %s must be referred by '.'\n",
			       field->name);
			return -EINVAL;
		}
		if (!ref) {
			pr_warning("Structure on a register is not "
				   "supported yet.\n");
			return -ENOTSUP;
		}
	}

	if (die_find_member(&type, field->name, die_mem) == NULL) {
		pr_warning("%s(tyep:%s) has no member %s.\n", varname,
			   dwarf_diename(&type), field->name);
		return -EINVAL;
	}

	
	ret = die_get_data_member_location(die_mem, &offs);
	if (ret < 0) {
		pr_warning("Failed to get the offset of %s.\n", field->name);
		return ret;
	}
	ref->offset += (long)offs;

next:
	
	if (field->next)
		return convert_variable_fields(die_mem, field->name,
					field->next, &ref, die_mem);
	else
		return 0;
}
static int convert_variable_type(Dwarf_Die *vr_die,
				 struct probe_trace_arg *tvar,
				 const char *cast)
{
	struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
	Dwarf_Die type;
	char buf[16];
	int bsize, boffs, total;
	int ret;

	
	if (cast && strcmp(cast, "string") != 0) {
		
		tvar->type = strdup(cast);
		return (tvar->type == NULL) ? -ENOMEM : 0;
	}

	bsize = dwarf_bitsize(vr_die);
	if (bsize > 0) {
		
		boffs = dwarf_bitoffset(vr_die);
		total = dwarf_bytesize(vr_die);
		if (boffs < 0 || total < 0)
			return -ENOENT;
		ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs,
				BYTES_TO_BITS(total));
		goto formatted;
	}

	if (die_get_real_type(vr_die, &type) == NULL) {
		pr_warning("Failed to get a type information of %s.\n",
			   dwarf_diename(vr_die));
		return -ENOENT;
	}

	pr_debug("%s type is %s.\n",
		 dwarf_diename(vr_die), dwarf_diename(&type));

	if (cast && strcmp(cast, "string") == 0) {	
		ret = dwarf_tag(&type);
		if (ret != DW_TAG_pointer_type &&
		    ret != DW_TAG_array_type) {
			pr_warning("Failed to cast into string: "
				   "%s(%s) is not a pointer nor array.\n",
				   dwarf_diename(vr_die), dwarf_diename(&type));
			return -EINVAL;
		}
		if (ret == DW_TAG_pointer_type) {
			if (die_get_real_type(&type, &type) == NULL) {
				pr_warning("Failed to get a type"
					   " information.\n");
				return -ENOENT;
			}
			while (*ref_ptr)
				ref_ptr = &(*ref_ptr)->next;
			
			*ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
			if (*ref_ptr == NULL) {
				pr_warning("Out of memory error\n");
				return -ENOMEM;
			}
		}
		if (!die_compare_name(&type, "char") &&
		    !die_compare_name(&type, "unsigned char")) {
			pr_warning("Failed to cast into string: "
				   "%s is not (unsigned) char *.\n",
				   dwarf_diename(vr_die));
			return -EINVAL;
		}
		tvar->type = strdup(cast);
		return (tvar->type == NULL) ? -ENOMEM : 0;
	}

	ret = dwarf_bytesize(&type);
	if (ret <= 0)
		
		return 0;
	ret = BYTES_TO_BITS(ret);

	
	if (ret > MAX_BASIC_TYPE_BITS) {
		pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
			dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
		ret = MAX_BASIC_TYPE_BITS;
	}
	ret = snprintf(buf, 16, "%c%d",
		       die_is_signed_type(&type) ? 's' : 'u', ret);

formatted:
	if (ret < 0 || ret >= 16) {
		if (ret >= 16)
			ret = -E2BIG;
		pr_warning("Failed to convert variable type: %s\n",
			   strerror(-ret));
		return ret;
	}
	tvar->type = strdup(buf);
	if (tvar->type == NULL)
		return -ENOMEM;
	return 0;
}
Beispiel #5
0
static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
				    struct perf_probe_arg_field *field,
				    struct probe_trace_arg_ref **ref_ptr,
				    Dwarf_Die *die_mem)
{
	struct probe_trace_arg_ref *ref = *ref_ptr;
	Dwarf_Die type;
	Dwarf_Word offs;
	int ret, tag;

	pr_debug("converting %s in %s\n", field->name, varname);
	if (die_get_real_type(vr_die, &type) == NULL) {
		pr_warning("Failed to get the type of %s.\n", varname);
		return -ENOENT;
	}
	pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
	tag = dwarf_tag(&type);

	if (field->name[0] == '[' &&
	    (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
		if (field->next)
			/* Save original type for next field */
			memcpy(die_mem, &type, sizeof(*die_mem));
		/* Get the type of this array */
		if (die_get_real_type(&type, &type) == NULL) {
			pr_warning("Failed to get the type of %s.\n", varname);
			return -ENOENT;
		}
		pr_debug2("Array real type: (%x)\n",
			 (unsigned)dwarf_dieoffset(&type));
		if (tag == DW_TAG_pointer_type) {
			ref = zalloc(sizeof(struct probe_trace_arg_ref));
			if (ref == NULL)
				return -ENOMEM;
			if (*ref_ptr)
				(*ref_ptr)->next = ref;
			else
				*ref_ptr = ref;
		}
		ref->offset += dwarf_bytesize(&type) * field->index;
		if (!field->next)
			/* Save vr_die for converting types */
			memcpy(die_mem, vr_die, sizeof(*die_mem));
		goto next;
	} else if (tag == DW_TAG_pointer_type) {
		/* Check the pointer and dereference */
		if (!field->ref) {
			pr_err("Semantic error: %s must be referred by '->'\n",
			       field->name);
			return -EINVAL;
		}
		/* Get the type pointed by this pointer */
		if (die_get_real_type(&type, &type) == NULL) {
			pr_warning("Failed to get the type of %s.\n", varname);
			return -ENOENT;
		}
		/* Verify it is a data structure  */
		tag = dwarf_tag(&type);
		if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
			pr_warning("%s is not a data structure nor an union.\n",
				   varname);
			return -EINVAL;
		}

		ref = zalloc(sizeof(struct probe_trace_arg_ref));
		if (ref == NULL)
			return -ENOMEM;
		if (*ref_ptr)
			(*ref_ptr)->next = ref;
		else
			*ref_ptr = ref;
	} else {
		/* Verify it is a data structure  */
		if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
			pr_warning("%s is not a data structure nor an union.\n",
				   varname);
			return -EINVAL;
		}
		if (field->name[0] == '[') {
			pr_err("Semantic error: %s is not a pointer"
			       " nor array.\n", varname);
			return -EINVAL;
		}
		/* While prcessing unnamed field, we don't care about this */
		if (field->ref && dwarf_diename(vr_die)) {
			pr_err("Semantic error: %s must be referred by '.'\n",
			       field->name);
			return -EINVAL;
		}
		if (!ref) {
			pr_warning("Structure on a register is not "
				   "supported yet.\n");
			return -ENOTSUP;
		}
	}

	if (die_find_member(&type, field->name, die_mem) == NULL) {
		pr_warning("%s(type:%s) has no member %s.\n", varname,
			   dwarf_diename(&type), field->name);
		return -EINVAL;
	}

	/* Get the offset of the field */
	if (tag == DW_TAG_union_type) {
		offs = 0;
	} else {
		ret = die_get_data_member_location(die_mem, &offs);
		if (ret < 0) {
			pr_warning("Failed to get the offset of %s.\n",
				   field->name);
			return ret;
		}
	}
	ref->offset += (long)offs;

	/* If this member is unnamed, we need to reuse this field */
	if (!dwarf_diename(die_mem))
		return convert_variable_fields(die_mem, varname, field,
						&ref, die_mem);

next:
	/* Converting next field */
	if (field->next)
		return convert_variable_fields(die_mem, field->name,
					field->next, &ref, die_mem);
	else
		return 0;
}
Beispiel #6
0
Datei: types.c Projekt: adk9/ohm
int
add_complextype_from_die(Dwarf_Debug dbg, Dwarf_Die parent_die, Dwarf_Die die)
{
    int ret = DW_DLV_ERROR, i, nsib;
    Dwarf_Error err = 0;
    Dwarf_Off offset = 0;
    Dwarf_Half tag = 0;
    Dwarf_Attribute attr;
    Dwarf_Unsigned bsz = 0, tid = 0;
    Dwarf_Die grandchild;
    basetype_t *t, *t2;

    ret = dwarf_tag(die, &tag, &err);
    if (ret != DW_DLV_OK) {
        derror("error in dwarf_tag()");
        goto error;
    }

    if ((tag != DW_TAG_array_type) && (tag != DW_TAG_structure_type) &&
        (tag != DW_TAG_typedef) && (tag != DW_TAG_pointer_type))
        return -1;

    switch (tag) {
        case DW_TAG_array_type:
            ret = get_offset_tid(die, &offset, &tid);
            if (ret < 0) {
                derror("error in get_offset_tid()");
                goto error;
            }

            // get the child
            dwarf_child(die, &grandchild, &err);
            ret = dwarf_attr(grandchild, DW_AT_upper_bound, &attr, &err);
            if (ret == DW_DLV_ERROR) {
                derror("error in dwarf_attr(DW_AT_upper_bound)");
                goto error;
            } else if (ret == DW_DLV_OK)
                get_number(attr, &bsz);
            else
                return 0;

            t = get_or_add_type(offset);
            snprintf(t->name, 128, "arr%u[]", (unsigned int)offset);
            t->ohm_type = OHM_TYPE_ARRAY;
            t->nelem = bsz+1;
            t2 = get_or_add_type(tid);
            t->size = t->nelem * get_type_size(t2);
            t->elems = malloc(sizeof(t));
            t->elems[0] = t2;
            break;

        case DW_TAG_structure_type:
            ret = dwarf_die_CU_offset(die, &offset, &err);
            if (ret != DW_DLV_OK) {
                derror("error in dwarf_die_CU_offset()");
                goto error;
            }

            t = get_or_add_type(offset);
            strncpy(t->name, "struct ", 7);
            ret = get_child_name(dbg, die, t->name+7, 128);
            if (ret < 0)
                strncpy(t->name, "<unknown-struct>", 128);
            t->ohm_type = OHM_TYPE_STRUCT;
            ret = dwarf_bytesize(die, &bsz, &err);
            t->size = ((ret == DW_DLV_OK) ? bsz : 0);

            // ensure that struct members get added to the table
            nsib = traverse_die(&add_structmember_from_die, dbg, parent_die, die);
            if (nsib < 0)
                goto error;
            t->nelem = nsib;
            t->elems = malloc((t->nelem)*sizeof(t));
            for (i = 0; i < t->nelem; i++)
                t->elems[i] = &types_table[types_table_size-t->nelem-1+i];
            break;

        case DW_TAG_typedef:
            ret = get_offset_tid(die, &offset, &tid);
            if (ret < 0) {
                derror("error in get_offset_tid()");
                goto error;
            }

            t = get_or_add_type(offset);
            t->ohm_type = OHM_TYPE_ALIAS;
            t->size = 0;
            t->nelem = 1;
            t2 = get_or_add_type(tid);
            t->elems = malloc(sizeof(t));
            t->elems[0] = t2;
            ret = get_child_name(dbg, die, t->name, 128);
            if (ret < 0)
                strncpy(t->name, "<unknown-typedef>", 128);
            break;

        case DW_TAG_pointer_type:
            ret = get_offset_tid(die, &offset, &tid);
            if (ret < 0) {
                derror("error in get_offset_tid()");
                goto error;
            }

            t = get_or_add_type(offset);
            strncpy(t->name, "ptr", 128);
            t->ohm_type = OHM_TYPE_PTR;
            t->nelem = 1;
            t->size = sizeof(void*);
            t2 = get_type(tid);
            t->size = get_type_size(t2);
            t->elems = malloc(sizeof(t));
            t->elems[0] = t2;
            break;
            
        default:
            break;
    }

    return 1;

error:
    derror("error in add_complextype_from_die()");
    return -1;
}
void
handle (Dwarf *dbg, Dwarf_Die *die, int n)
{
  Dwarf_Die child;
  unsigned int tag;
  const char *str;
  char buf[30];
  const char *name;
  Dwarf_Off off;
  Dwarf_Off cuoff;
  size_t cnt;
  Dwarf_Addr addr;
  int i;

  tag = dwarf_tag (die);
  if (tag != DW_TAG_invalid)
    {
      if (tag < ntagnames)
	str = tagnames[tag];
      else
	{
	  snprintf (buf, sizeof buf, "%#x", tag);
	  str = buf;
	}
    }
  else
    str = "* NO TAG *";

  name = dwarf_diename (die);
  if (name == 0)
    name = "* NO NAME *";

  off = dwarf_dieoffset (die);
  cuoff = dwarf_cuoffset (die);

  printf ("%*s%s\n", n * 5, "", str);
  printf ("%*s Name      : %s\n", n * 5, "", name);
  printf ("%*s Offset    : %lld\n", n * 5, "", (long long int) off);
  printf ("%*s CU offset : %lld\n", n * 5, "", (long long int) cuoff);

  printf ("%*s Attrs     :", n * 5, "");
  for (cnt = 0; cnt < nattrs; ++cnt)
    if (dwarf_hasattr (die, attrs[cnt].code))
      printf (" %s", attrs[cnt].name);
  puts ("");

  if (dwarf_hasattr (die, DW_AT_low_pc) && dwarf_lowpc (die, &addr) == 0)
    {
      Dwarf_Attribute attr;
      Dwarf_Addr addr2;
      printf ("%*s low PC    : %#llx\n",
	      n * 5, "", (unsigned long long int) addr);

      if (dwarf_attr (die, DW_AT_low_pc, &attr) == NULL
	  || dwarf_formaddr (&attr, &addr2) != 0
	  || addr != addr2)
	puts ("************* DW_AT_low_pc verify failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_addr))
	puts ("************* DW_AT_low_pc form failed ************");
      else if (dwarf_whatform (&attr) != DW_FORM_addr)
	puts ("************* DW_AT_low_pc form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_low_pc)
	puts ("************* DW_AT_low_pc attr failed ************");
    }
  if (dwarf_hasattr (die, DW_AT_high_pc) && dwarf_highpc (die, &addr) == 0)
    {
      Dwarf_Attribute attr;
      Dwarf_Addr addr2;
      printf ("%*s high PC   : %#llx\n",
	      n * 5, "", (unsigned long long int) addr);
      if (dwarf_attr (die, DW_AT_high_pc, &attr) == NULL
	  || dwarf_formaddr (&attr, &addr2) != 0
	  || addr != addr2)
	puts ("************* DW_AT_high_pc verify failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_addr))
	puts ("************* DW_AT_high_pc form failed ************");
      else if (dwarf_whatform (&attr) != DW_FORM_addr)
	puts ("************* DW_AT_high_pc form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_high_pc)
	puts ("************* DW_AT_high_pc attr failed ************");
    }

  if (dwarf_hasattr (die, DW_AT_byte_size) && (i = dwarf_bytesize (die)) != -1)
    {
      Dwarf_Attribute attr;
      Dwarf_Word u2;
      unsigned int u;
      printf ("%*s byte size : %d\n", n * 5, "", i);
      if (dwarf_attr (die, DW_AT_byte_size, &attr) == NULL
	  || dwarf_formudata (&attr, &u2) != 0
	  || i != (int) u2)
	puts ("************* DW_AT_byte_size verify failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_data1)
	       && ! dwarf_hasform (&attr, DW_FORM_data2)
	       && ! dwarf_hasform (&attr, DW_FORM_data4)
	       && ! dwarf_hasform (&attr, DW_FORM_data8)
	       && ! dwarf_hasform (&attr, DW_FORM_sdata)
	       && ! dwarf_hasform (&attr, DW_FORM_udata))
	puts ("************* DW_AT_byte_size form failed ************");
      else if ((u = dwarf_whatform (&attr)) == 0
	       || (u != DW_FORM_data1
		   && u != DW_FORM_data2
		   && u != DW_FORM_data4
		   && u != DW_FORM_data8
		   && u != DW_FORM_sdata
		   && u != DW_FORM_udata))
	puts ("************* DW_AT_byte_size form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_byte_size)
	puts ("************* DW_AT_byte_size attr failed ************");
    }
  if (dwarf_hasattr (die, DW_AT_bit_size) && (i = dwarf_bitsize (die)) != -1)
    {
      Dwarf_Attribute attr;
      Dwarf_Word u2;
      unsigned int u;
      printf ("%*s bit size  : %d\n", n * 5, "", i);
      if (dwarf_attr (die, DW_AT_bit_size, &attr) == NULL
	  || dwarf_formudata (&attr, &u2) != 0
	  || i != (int) u2)
	puts ("************* DW_AT_bit_size test failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_data1)
	       && ! dwarf_hasform (&attr, DW_FORM_data2)
	       && ! dwarf_hasform (&attr, DW_FORM_data4)
	       && ! dwarf_hasform (&attr, DW_FORM_data8)
	       && ! dwarf_hasform (&attr, DW_FORM_sdata)
	       && ! dwarf_hasform (&attr, DW_FORM_udata))
	puts ("************* DW_AT_bit_size form failed ************");
      else if ((u = dwarf_whatform (&attr)) == 0
	       || (u != DW_FORM_data1
		   && u != DW_FORM_data2
		   && u != DW_FORM_data4
		   && u != DW_FORM_data8
		   && u != DW_FORM_sdata
		   && u != DW_FORM_udata))
	puts ("************* DW_AT_bit_size form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_bit_size)
	puts ("************* DW_AT_bit_size attr failed ************");
    }
  if (dwarf_hasattr (die, DW_AT_bit_offset)
      && (i = dwarf_bitoffset (die)) != -1)
    {
      Dwarf_Attribute attr;
      Dwarf_Word u2;
      unsigned int u;
      printf ("%*s bit offset: %d\n", n * 5, "", i);
      if (dwarf_attr (die, DW_AT_bit_offset, &attr) == NULL
	  || dwarf_formudata (&attr, &u2) != 0
	  || i != (int) u2)
	puts ("************* DW_AT_bit_offset test failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_data1)
	       && ! dwarf_hasform (&attr, DW_FORM_data2)
	       && ! dwarf_hasform (&attr, DW_FORM_data4)
	       && ! dwarf_hasform (&attr, DW_FORM_data8)
	       && ! dwarf_hasform (&attr, DW_FORM_sdata)
	       && ! dwarf_hasform (&attr, DW_FORM_udata))
	puts ("************* DW_AT_bit_offset form failed ************");
      else if ((u = dwarf_whatform (&attr)) == 0
	       || (u != DW_FORM_data1
		   && u != DW_FORM_data2
		   && u != DW_FORM_data4
		   && u != DW_FORM_data8
		   && u != DW_FORM_sdata
		   && u != DW_FORM_udata))
	puts ("************* DW_AT_bit_offset form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_bit_offset)
	puts ("************* DW_AT_bit_offset attr failed ************");
    }

  if (dwarf_hasattr (die, DW_AT_language) && (i = dwarf_srclang (die)) != -1)
    {
      Dwarf_Attribute attr;
      Dwarf_Word u2;
      unsigned int u;
      printf ("%*s language  : %d\n", n * 5, "", i);
      if (dwarf_attr (die, DW_AT_language, &attr) == NULL
	  || dwarf_formudata (&attr, &u2) != 0
	  || i != (int) u2)
	puts ("************* DW_AT_language test failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_data1)
	       && ! dwarf_hasform (&attr, DW_FORM_data2)
	       && ! dwarf_hasform (&attr, DW_FORM_data4)
	       && ! dwarf_hasform (&attr, DW_FORM_data8)
	       && ! dwarf_hasform (&attr, DW_FORM_sdata)
	       && ! dwarf_hasform (&attr, DW_FORM_udata))
	puts ("************* DW_AT_language form failed ************");
      else if ((u = dwarf_whatform (&attr)) == 0
	       || (u != DW_FORM_data1
		   && u != DW_FORM_data2
		   && u != DW_FORM_data4
		   && u != DW_FORM_data8
		   && u != DW_FORM_sdata
		   && u != DW_FORM_udata))
	puts ("************* DW_AT_language form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_language)
	puts ("************* DW_AT_language attr failed ************");
    }

  if (dwarf_hasattr (die, DW_AT_ordering)
      && (i = dwarf_arrayorder (die)) != -1)
    {
      Dwarf_Attribute attr;
      Dwarf_Word u2;
      unsigned int u;
      printf ("%*s ordering  : %d\n", n * 5, "", i);
      if (dwarf_attr (die, DW_AT_ordering, &attr) == NULL
	  || dwarf_formudata (&attr, &u2) != 0
	  || i != (int) u2)
	puts ("************* DW_AT_ordering test failed ************");
      else if (! dwarf_hasform (&attr, DW_FORM_data1)
	       && ! dwarf_hasform (&attr, DW_FORM_data2)
	       && ! dwarf_hasform (&attr, DW_FORM_data4)
	       && ! dwarf_hasform (&attr, DW_FORM_data8)
	       && ! dwarf_hasform (&attr, DW_FORM_sdata)
	       && ! dwarf_hasform (&attr, DW_FORM_udata))
	puts ("************* DW_AT_ordering failed ************");
      else if ((u = dwarf_whatform (&attr)) == 0
	       || (u != DW_FORM_data1
		   && u != DW_FORM_data2
		   && u != DW_FORM_data4
		   && u != DW_FORM_data8
		   && u != DW_FORM_sdata
		   && u != DW_FORM_udata))
	puts ("************* DW_AT_ordering form (2) failed ************");
      else if (dwarf_whatattr (&attr) != DW_AT_ordering)
	puts ("************* DW_AT_ordering attr failed ************");
    }

  if (dwarf_hasattr (die, DW_AT_comp_dir))
    {
      Dwarf_Attribute attr;
      if (dwarf_attr (die, DW_AT_comp_dir, &attr) == NULL
	  || (name = dwarf_formstring (&attr)) == NULL)
	puts ("************* DW_AT_comp_dir attr failed ************");
      else
	printf ("%*s directory : %s\n", n * 5, "", name);
    }

  if (dwarf_hasattr (die, DW_AT_producer))
    {
      Dwarf_Attribute attr;
      if (dwarf_attr (die, DW_AT_producer, &attr) == NULL
	  || (name = dwarf_formstring (&attr)) == NULL)
	puts ("************* DW_AT_comp_dir attr failed ************");
      else
	printf ("%*s producer  : %s\n", n * 5, "", name);
    }

  if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0)
    handle (dbg, &child, n + 1);
  if (dwarf_siblingof (die, die) == 0)
    handle (dbg, die, n);
}