char *get_type_str(Dwarf_Die *die) { static char buf[256] = ""; char *ptr = NULL; Dwarf_Die tdie; Dwarf_Attribute attr; if (!dwarf_attr(die, DW_AT_type, &attr)) return "void"; dwarf_formref_die(&attr, &tdie); if (dwarf_tag(&tdie) == DW_TAG_array_type) ptr = "[]"; else if (dwarf_tag(&tdie) == DW_TAG_pointer_type) ptr = "*"; else goto end_ok; dwarf_attr(&tdie, DW_AT_type, &attr); dwarf_formref_die(&attr, &tdie); end_ok: sprintf(buf, "%s%s", dwarf_diename(&tdie), (ptr) ? ptr : ""); return buf; }
static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) { struct __instance_walk_param *iwp = data; Dwarf_Attribute attr_mem; Dwarf_Die origin_mem; Dwarf_Attribute *attr; Dwarf_Die *origin; int tmp; attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); if (attr == NULL) return DIE_FIND_CB_CONTINUE; origin = dwarf_formref_die(attr, &origin_mem); if (origin == NULL || origin->addr != iwp->addr) return DIE_FIND_CB_CONTINUE; /* Ignore redundant instances */ if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { dwarf_decl_line(origin, &tmp); if (die_get_call_lineno(inst) == tmp) { tmp = die_get_decl_fileno(origin); if (die_get_call_fileno(inst) == tmp) return DIE_FIND_CB_CONTINUE; } } iwp->retval = iwp->callback(inst, iwp->data); return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; }
/** * die_get_type - Get type DIE * @vr_die: a DIE of a variable * @die_mem: where to store a type DIE * * Get a DIE of the type of given variable (@vr_die), and store * it to die_mem. Return NULL if fails to get a type DIE. */ Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { Dwarf_Attribute attr; if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && dwarf_formref_die(&attr, die_mem)) return die_mem; else return NULL; }
static Dwarf_Off MC_dwarf_attr_dieoffset(Dwarf_Die * die, int attribute) { Dwarf_Attribute attr; if (dwarf_hasattr_integrate(die, attribute) == 0) return 0; dwarf_attr_integrate(die, attribute, &attr); Dwarf_Die subtype_die; if (dwarf_formref_die(&attr, &subtype_die) == nullptr) xbt_die("Could not find DIE"); return dwarf_dieoffset(&subtype_die); }
static void get_dwarf_attr(Dwarf_Die *parent, int attr, Dwarf_Attribute *attr_out, Dwarf_Die *die_out) { if (dwarf_attr_integrate(parent, attr, attr_out) == NULL) dwarf_err(EX_DATAERR, "dwarf_attr_integrate(%s/%d)", dwarf_diename(parent), attr); if (dwarf_formref_die(attr_out, die_out) == NULL) dwarf_err(EX_DATAERR, "dwarf_formref_die(%s)", dwarf_diename(parent)); }
/* Get type die, but skip qualifiers and typedef */ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { Dwarf_Attribute attr; int tag; do { if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || dwarf_formref_die(&attr, die_mem) == NULL) return NULL; tag = dwarf_tag(die_mem); vr_die = die_mem; } while (tag == DW_TAG_const_type || tag == DW_TAG_restrict_type || tag == DW_TAG_volatile_type || tag == DW_TAG_shared_type || tag == DW_TAG_typedef); return die_mem; }
static void print_vars (unsigned int indent, Dwarf_Die *die) { Dwarf_Die child; if (dwarf_child (die, &child) == 0) do switch (dwarf_tag (&child)) { case DW_TAG_variable: case DW_TAG_formal_parameter: printf ("%*s%-30s[%6" PRIx64 "]\n", indent, "", dwarf_diename (&child), (uint64_t) dwarf_dieoffset (&child)); break; default: break; } while (dwarf_siblingof (&child, &child) == 0); Dwarf_Attribute attr_mem; Dwarf_Die origin; if (dwarf_hasattr (die, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (die, DW_AT_abstract_origin, &attr_mem), &origin) != NULL && dwarf_child (&origin, &child) == 0) do switch (dwarf_tag (&child)) { case DW_TAG_variable: case DW_TAG_formal_parameter: printf ("%*s%s (abstract)\n", indent, "", dwarf_diename (&child)); break; default: break; } while (dwarf_siblingof (&child, &child) == 0); }
int ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { /* Start with the function's type, and get the DW_AT_type attribute, which is the type of the return value. */ Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); if (attr == NULL) /* The function has no return value, like a `void' function in C. */ return 0; Dwarf_Die die_mem; Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); int tag = DWARF_TAG_OR_RETURN (typedie); /* Follow typedefs and qualifiers to get to the actual type. */ while (tag == DW_TAG_typedef || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) { attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } Dwarf_Word size; switch (tag) { case -1: return -1; case DW_TAG_subrange_type: if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } /* Fall through. */ case DW_TAG_base_type: case DW_TAG_enumeration_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) { if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) size = 8; else return -1; } if (tag == DW_TAG_base_type) { Dwarf_Word encoding; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &attr_mem), &encoding) != 0) return -1; switch (encoding) { case DW_ATE_float: switch (size) { case 4: /* float */ *locp = loc_fpreg_4; return nloc_fpreg; case 8: /* double */ *locp = loc_fpreg_8; return nloc_fpreg; case 10: /* x86-style long double, not really used */ *locp = loc_fpreg_10; return nloc_fpreg; case 16: /* long double, IEEE quad format */ *locp = loc_intreg; return nloc_intregs (2); } return -2; case DW_ATE_complex_float: switch (size) { case 4 * 2: /* complex float */ *locp = loc_fpreg_4; return nloc_fpregs (2); case 8 * 2: /* complex double */ *locp = loc_fpreg_8; return nloc_fpregs (2); case 10 * 2: /* complex long double (x86-style) */ *locp = loc_fpreg_10; return nloc_fpregs (2); case 16 * 2: /* complex long double (IEEE quad) */ *locp = loc_intreg; return nloc_intregs (4); } return -2; } } intreg: *locp = loc_intreg; if (size <= 8) return nloc_intreg; if (size <= 32) return nloc_intregs ((size + 7) / 8); large: *locp = loc_aggregate; return nloc_aggregate; case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: case DW_TAG_array_type: if (dwarf_aggregate_size (typedie, &size) != 0) return -1; /* If this qualifies as an homogeneous floating-point aggregate (HFA), then it should be returned in FP regs. */ int nfpreg = hfa_type (typedie, size, locp, 0); if (nfpreg < 0) return nfpreg; else if (nfpreg > 0 && nfpreg <= 8) return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg); if (size > 32) goto large; goto intreg; } /* XXX We don't have a good way to return specific errors from ebl calls. This value means we do not understand the type, but it is well-formed DWARF and might be valid. */ return -2; }
int main (int argc, char *argv[]) { for (int i = 1; i < argc; ++i) { int fd = open (argv[i], O_RDONLY); Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); if (dbg != NULL) { Dwarf_Off off = 0; size_t cuhl; Dwarf_Off noff; while (dwarf_nextcu (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0) { Dwarf_Die die_mem; Dwarf_Die *die = dwarf_offdie (dbg, off + cuhl, &die_mem); Dwarf_Die iter_mem; Dwarf_Die *iter = &iter_mem; dwarf_child (die, &iter_mem); while (1) { if (dwarf_tag (iter) == DW_TAG_variable) { Dwarf_Attribute attr_mem; Dwarf_Die form_mem; dwarf_formref_die (dwarf_attr (iter, DW_AT_type, &attr_mem), &form_mem); } if (dwarf_siblingof (iter, &iter_mem) != 0) break; } off = noff; } off = 0; uint64_t type_sig; while (dwarf_next_unit (dbg, off, &noff, &cuhl, NULL, NULL, NULL, NULL, &type_sig, NULL) == 0) { Dwarf_Die die_mem; Dwarf_Die *die = dwarf_offdie_types (dbg, off + cuhl, &die_mem); if (die == NULL) printf ("fail\n"); else printf ("ok\n"); off = noff; } dwarf_end (dbg); } close (fd); } }
int ppc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { /* Start with the function's type, and get the DW_AT_type attribute, which is the type of the return value. */ Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); if (attr == NULL) /* The function has no return value, like a `void' function in C. */ return 0; Dwarf_Die die_mem; Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); int tag = dwarf_tag (typedie); /* Follow typedefs and qualifiers to get to the actual type. */ while (tag == DW_TAG_typedef || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = dwarf_tag (typedie); } Dwarf_Word size; switch (tag) { case -1: return -1; case DW_TAG_subrange_type: if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = dwarf_tag (typedie); } /* Fall through. */ case DW_TAG_base_type: case DW_TAG_enumeration_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) { if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) size = 4; else return -1; } if (size <= 8) { if (tag == DW_TAG_base_type) { Dwarf_Word encoding; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &attr_mem), &encoding) != 0) return -1; if (encoding == DW_ATE_float) { *locp = loc_fpreg; return nloc_fpreg; } } intreg: *locp = loc_intreg; return size <= 4 ? nloc_intreg : nloc_intregpair; } aggregate: *locp = loc_aggregate; return nloc_aggregate; case DW_TAG_array_type: { bool is_vector; if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector, &attr_mem), &is_vector) == 0 && is_vector && dwarf_aggregate_size (typedie, &size) == 0) switch (size) { case 16: if (ppc_altivec_abi ()) { *locp = loc_vmxreg; return nloc_vmxreg; } *locp = loc_intreg; return nloc_intregquad; } } /* Fall through. */ case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: if (SVR4_STRUCT_RETURN && dwarf_aggregate_size (typedie, &size) == 0 && size > 0 && size <= 8) goto intreg; goto aggregate; } /* XXX We don't have a good way to return specific errors from ebl calls. This value means we do not understand the type, but it is well-formed DWARF and might be valid. */ return -2; }
static struct variable* analyze_variable(Dwarf_Die *die, Dwarf_Files *files, struct expr_context *ctx) { int ret; Dwarf_Attribute at; struct variable* var; /* ignore declarations */ if (dwarf_attr_integrate(die, DW_AT_declaration, &at) != NULL) { bool flag; ret = dwarf_formflag(&at, &flag); fail_if(ret == -1, "dwarf_formflag"); if (flag) return NULL; } var = xalloc(sizeof(struct variable)); analyze_name_location(die, files, &var->name, &var->loc); if (dwarf_attr_integrate(die, DW_AT_type, &at) != NULL) { Dwarf_Die type_die; if (dwarf_formref_die(&at, &type_die) == NULL) fail("dwarf_formref_die"); analyze_type(&type_die, &(var->type)); } if (dwarf_attr_integrate(die, DW_AT_const_value, &at) != NULL) { Dwarf_Word w; Dwarf_Block bl; unsigned int form = dwarf_whatform(&at); debug("variable %s has constant value of form %x", var->name, form); if (dwarf_formudata(&at, &w) == 0) { fail_if(sizeof(w) < var->type.width, "constant value too small"); var->value = xalloc(var->type.width); memcpy(var->value, &w, var->type.width); } else if (dwarf_formblock(&at, &bl) == 0) { fail_if(bl.length < var->type.width, "constant value too small"); var->value = xalloc(var->type.width); memcpy(var->value, bl.data, var->type.width); } else { warn("unable to get constant value of variable %x (form %x)", var->name, form); } } else if (dwarf_attr_integrate(die, DW_AT_location, &at) != NULL) { size_t exprlen; Dwarf_Op *expr; ret = dwarf_getlocation_addr(&at, ctx->ip, &expr, &exprlen, 1); if (ret != 1) { if (ret == -1) /* it seems that elfutils have some kind of problem with * DW_OP_GNU_entry_value but that operation is useless for us * anyway */ warn("cannot get location for variable %s (ip: %lx), %s", var->name, ctx->ip, dwarf_errmsg(-1)); else if (ret == 0) debug("no location available for variable %s (ip: %lx)", var->name, ctx->ip); else fail("unreachable reached"); return var; } var->value = evaluate_loc_expr(expr, exprlen, ctx, var->type.width); } return var; }
int arm_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { /* Start with the function's type, and get the DW_AT_type attribute, which is the type of the return value. */ Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); if (attr == NULL) /* The function has no return value, like a `void' function in C. */ return 0; Dwarf_Die die_mem; Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); int tag = DWARF_TAG_OR_RETURN (typedie); /* Follow typedefs and qualifiers to get to the actual type. */ while (tag == DW_TAG_typedef || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } Dwarf_Word size; switch (tag) { case -1: return -1; case DW_TAG_subrange_type: if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } /* Fall through. */ case DW_TAG_base_type: case DW_TAG_enumeration_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) { if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) size = 4; else return -1; } if (size <= 16) { intreg: *locp = loc_intreg; return size <= 4 ? nloc_intreg : nloc_intregs ((size + 3) / 4); } aggregate: *locp = loc_aggregate; return nloc_aggregate; case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: case DW_TAG_array_type: if (dwarf_aggregate_size (typedie, &size) == 0 && size > 0 && size <= 4) goto intreg; goto aggregate; } /* XXX We don't have a good way to return specific errors from ebl calls. This value means we do not understand the type, but it is well-formed DWARF and might be valid. */ return -2; }
int x86_64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { /* Start with the function's type, and get the DW_AT_type attribute, which is the type of the return value. */ Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); if (attr == NULL) /* The function has no return value, like a `void' function in C. */ return 0; Dwarf_Die die_mem; Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); int tag = DWARF_TAG_OR_RETURN (typedie); /* Follow typedefs and qualifiers to get to the actual type. */ while (tag == DW_TAG_typedef || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } Dwarf_Word size; switch (tag) { case -1: return -1; case DW_TAG_subrange_type: if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = DWARF_TAG_OR_RETURN (typedie); } /* Fall through. */ case DW_TAG_base_type: case DW_TAG_enumeration_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) { if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) size = 8; else return -1; } if (tag == DW_TAG_base_type) { Dwarf_Word encoding; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &attr_mem), &encoding) != 0) return -1; switch (encoding) { case DW_ATE_complex_float: switch (size) { case 4 * 2: /* complex float */ case 8 * 2: /* complex double */ *locp = loc_ssereg; return nloc_sseregpair; case 16 * 2: /* complex long double */ *locp = loc_x87reg; return nloc_x87regpair; } return -2; case DW_ATE_float: switch (size) { case 4: /* float */ case 8: /* double */ *locp = loc_ssereg; return nloc_ssereg; case 16: /* long double */ /* XXX distinguish __float128, which is sseregpair?? */ *locp = loc_x87reg; return nloc_x87reg; } return -2; } } intreg: *locp = loc_intreg; if (size <= 8) return nloc_intreg; if (size <= 16) return nloc_intregpair; large: *locp = loc_aggregate; return nloc_aggregate; case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: case DW_TAG_array_type: if (dwarf_aggregate_size (typedie, &size) != 0) goto large; if (size > 16) goto large; /* XXX Must examine the fields in picayune ways to determine the actual answer. This will be right for small C structs containing integer types and similarly simple cases. */ goto intreg; } /* XXX We don't have a good way to return specific errors from ebl calls. This value means we do not understand the type, but it is well-formed DWARF and might be valid. */ return -2; }
struct refl_object * refl_access (struct refl *refl, struct refl_object *obj, char const *lookfor) { assert (refl != NULL); assert (obj != NULL); assert (lookfor != NULL); struct refl_type *type = obj->type; assert (type != NULL); Dwarf_Die die_mem, *die = &die_mem; if (dwarf_child (&type->die, &die_mem)) { err: __refl_seterr (REFL_E_DWARF); return NULL; } for (; die != NULL; checked_siblingof (&die, &die_mem)) { if (dwarf_tag (die) != DW_TAG_member) continue; Dwarf_Attribute attr_mem, *attr = dwarf_attr (die, DW_AT_name, &attr_mem); if (attr == NULL) goto err; char const *name = dwarf_formstring (attr); if (name == NULL) { err2: __refl_seterr (REFL_E_DWARF); return NULL; } if (strcmp (name, lookfor) != 0) continue; attr = dwarf_attr (die, DW_AT_data_member_location, &attr_mem); if (attr == NULL) goto err; Dwarf_Word location; if (dwarf_formudata (attr, &location) != 0) goto err2; attr = dwarf_attr (die, DW_AT_type, &attr_mem); if (attr == NULL) goto err; Dwarf_Die tdie_mem, *tdie = dwarf_formref_die (attr, &tdie_mem); if (tdie == NULL) goto err2; struct refl_type *field_type = __refl_type_begin (tdie); if (field_type == NULL) return NULL; struct refl_object *result = __refl_object_begin (field_type, (char *)obj->data + location); if (result == NULL) __refl_type_free (field_type); return result; } return NULL; }
/* If this type is an HFA small enough to be returned in FP registers, return the number of registers to use. Otherwise 9, or -1 for errors. */ static int hfa_type (Dwarf_Die *typedie, Dwarf_Word size, const Dwarf_Op **locp, int fpregs_used) { /* Descend the type structure, counting elements and finding their types. If we find a datum that's not an FP type (and not quad FP), punt. If we find a datum that's not the same FP type as the first datum, punt. If we count more than eight total homogeneous FP data, punt. */ inline int hfa (const Dwarf_Op *loc, int nregs) { if (fpregs_used == 0) *locp = loc; else if (*locp != loc) return 9; return fpregs_used + nregs; } int tag = DWARF_TAG_OR_RETURN (typedie); switch (tag) { Dwarf_Attribute attr_mem; case -1: return -1; case DW_TAG_base_type:; Dwarf_Word encoding; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &attr_mem), &encoding) != 0) return -1; switch (encoding) { case DW_ATE_float: switch (size) { case 4: /* float */ return hfa (loc_fpreg_4, 1); case 8: /* double */ return hfa (loc_fpreg_8, 1); case 10: /* x86-style long double, not really used */ return hfa (loc_fpreg_10, 1); } break; case DW_ATE_complex_float: switch (size) { case 4 * 2: /* complex float */ return hfa (loc_fpreg_4, 2); case 8 * 2: /* complex double */ return hfa (loc_fpreg_8, 2); case 10 * 2: /* complex long double (x86-style) */ return hfa (loc_fpreg_10, 2); } break; } break; case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type:; Dwarf_Die child_mem; switch (dwarf_child (typedie, &child_mem)) { default: return -1; case 1: /* No children: empty struct. */ break; case 0:; /* Look at each element. */ int max_used = fpregs_used; do switch (dwarf_tag (&child_mem)) { case -1: return -1; case DW_TAG_member:; Dwarf_Die child_type_mem; Dwarf_Die *child_typedie = dwarf_formref_die (dwarf_attr_integrate (&child_mem, DW_AT_type, &attr_mem), &child_type_mem); Dwarf_Word child_size; if (dwarf_aggregate_size (child_typedie, &child_size) != 0) return -1; if (tag == DW_TAG_union_type) { int used = hfa_type (child_typedie, child_size, locp, fpregs_used); if (used < 0 || used > 8) return used; if (used > max_used) max_used = used; } else { fpregs_used = hfa_type (child_typedie, child_size, locp, fpregs_used); if (fpregs_used < 0 || fpregs_used > 8) return fpregs_used; } } while (dwarf_siblingof (&child_mem, &child_mem) == 0); if (tag == DW_TAG_union_type) fpregs_used = max_used; break; } break; case DW_TAG_array_type: if (size == 0) break; Dwarf_Die base_type_mem; Dwarf_Die *base_typedie = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem), &base_type_mem); Dwarf_Word base_size; if (dwarf_aggregate_size (base_typedie, &base_size) != 0) return -1; int used = hfa_type (base_typedie, base_size, locp, 0); if (used < 0 || used > 8) return used; if (size % (*locp)[1].number != 0) return 0; fpregs_used += used * (size / (*locp)[1].number); break; default: return 9; } return fpregs_used; }
int ppc64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { /* Start with the function's type, and get the DW_AT_type attribute, which is the type of the return value. */ Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type, &attr_mem); if (attr == NULL) /* The function has no return value, like a `void' function in C. */ return 0; Dwarf_Die die_mem; Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem); int tag = dwarf_tag (typedie); /* Follow typedefs and qualifiers to get to the actual type. */ while (tag == DW_TAG_typedef || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = dwarf_tag (typedie); } Dwarf_Word size; switch (tag) { case -1: return -1; case DW_TAG_subrange_type: if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) { attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = dwarf_tag (typedie); } /* Fall through. */ case DW_TAG_base_type: case DW_TAG_enumeration_type: case DW_TAG_pointer_type: case DW_TAG_ptr_to_member_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) { if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) size = 8; else return -1; } if (tag == DW_TAG_base_type) { Dwarf_Word encoding; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &attr_mem), &encoding) != 0) return -1; if (encoding == DW_ATE_float || encoding == DW_ATE_complex_float) { *locp = loc_fpreg; if (size <= 8) return nloc_fpreg; if (size <= 16) return nloc_fp2regs; if (size <= 32) return nloc_fp4regs; } } if (size <= 8) { intreg: *locp = loc_intreg; return nloc_intreg; } /* Else fall through. */ case DW_TAG_structure_type: case DW_TAG_class_type: case DW_TAG_union_type: aggregate: *locp = loc_aggregate; return nloc_aggregate; case DW_TAG_string_type: case DW_TAG_array_type: if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) == 0 && size <= 8) { if (tag == DW_TAG_array_type) { /* Check if it's a character array. */ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); typedie = dwarf_formref_die (attr, &die_mem); tag = dwarf_tag (typedie); if (tag != DW_TAG_base_type) goto aggregate; if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) return -1; if (size != 1) goto aggregate; } goto intreg; } goto aggregate; } /* XXX We don't have a good way to return specific errors from ebl calls. This value means we do not understand the type, but it is well-formed DWARF and might be valid. */ return -2; }
static void analyze_type(Dwarf_Die *die, struct type *ty) { int ret; Dwarf_Attribute at; /* find out the values of name, byte_size and type attributes * even though not all of them make sense for all tags */ char *name = NULL; if (dwarf_attr(die, DW_AT_name, &at) != NULL) { name = xstrdup(dwarf_formstring(&at)); } struct type sub_type = { .name = NULL, .width = 0 }; if (dwarf_attr(die, DW_AT_type, &at) != NULL) { Dwarf_Die sub_die; if (dwarf_formref_die(&at, &sub_die) != NULL) analyze_type(&sub_die, &sub_type); } Dwarf_Word width = 0; if (dwarf_attr(die, DW_AT_byte_size, &at) != NULL) { ret = dwarf_formudata(&at, &width); fail_if(ret == -1, "dwarf_formudata"); } switch (dwarf_tag(die)) { case DW_TAG_base_type: ty->name = name; name = NULL; ty->width = (unsigned)width; /* TODO: what about encoding? */ break; /* type modifiers */ case DW_TAG_const_type: ty->name = xsprintf("const %s", sub_type.name ?: "void"); ty->width = sub_type.width; break; case DW_TAG_pointer_type: ty->width = (unsigned)width; ty->name = xsprintf("%s*", sub_type.name ?: "void"); break; case DW_TAG_restrict_type: ty->name = xsprintf("%s restrict", sub_type.name ?: "void"); ty->width = sub_type.width; break; case DW_TAG_volatile_type: ty->name = xsprintf("volatile %s", sub_type.name ?: "void"); ty->width = sub_type.width; break; case DW_TAG_typedef: ty->name = name; name = NULL; ty->width = sub_type.width; break; case DW_TAG_array_type: ty->name = xsprintf("%s[]", sub_type.name); ty->width = POINTER_SIZE; break; case DW_TAG_structure_type: if (name) ty->name = xsprintf("struct %s", name); else ty->name = xstrdup("struct"); ty->width = (unsigned)width; break; case DW_TAG_union_type: if (name) ty->name = xsprintf("union %s", name); else ty->name = xstrdup("union"); ty->width = (unsigned)width; break; case DW_TAG_class_type: ty->name = xsprintf("class %s", name); ty->width = (unsigned)width; break; case DW_TAG_enumeration_type: ty->name = xsprintf("enum %s", name); ty->width = (unsigned)width; break; case DW_TAG_subroutine_type: ty->name = xstrdup("FUNCTION"); ty->width = 0; /* TODO */ break; default: warn("Unknown type 0x%x named %s with width %u", dwarf_tag(die), name, (unsigned)width); break; } free(sub_type.name); free(name); } void analyze_name_location(Dwarf_Die *die, Dwarf_Files *files, char **name, struct location* loc) { int ret; Dwarf_Attribute at; Dwarf_Word w; if (dwarf_attr_integrate(die, DW_AT_name, &at) != NULL) { *name = xstrdup(dwarf_formstring(&at)); } if (dwarf_attr_integrate(die, DW_AT_decl_file, &at) != NULL) { ret = dwarf_formudata(&at, &w); fail_if(ret == -1, "dwarf_formudata"); loc->file = xstrdup(dwarf_filesrc(files, (size_t)w, NULL, NULL)); } if (dwarf_attr_integrate(die, DW_AT_decl_line, &at) != NULL) { ret = dwarf_formudata(&at, &w); fail_if(ret == -1, "dwarf_formudata"); loc->line = (unsigned)w; } }