Dwarf_Op *ops;
size_t nops;
struct die_var_type *vt;
+ ptrdiff_t off;
if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter)
return DIE_FIND_CB_SIBLING;
if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL)
return DIE_FIND_CB_SIBLING;
- /*
- * Only collect the first location as it can reconstruct the
- * remaining state by following the instructions.
- * start = 0 means it covers the whole range.
- */
- if (dwarf_getlocations(&attr, 0, &base, &start, &end, &ops, &nops) <= 0)
- return DIE_FIND_CB_SIBLING;
-
- if (!check_allowed_ops(ops, nops))
- return DIE_FIND_CB_SIBLING;
-
if (__die_get_real_type(die_mem, &type_die) == NULL)
return DIE_FIND_CB_SIBLING;
- vt = malloc(sizeof(*vt));
- if (vt == NULL)
- return DIE_FIND_CB_END;
-
- /* Usually a register holds the value of a variable */
- vt->is_reg_var_addr = false;
+ /*
+ * Collect all location entries as variables may have different
+ * locations across different address ranges.
+ */
+ off = 0;
+ while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
+ if (!check_allowed_ops(ops, nops))
+ continue;
- if (((ops->atom >= DW_OP_breg0 && ops->atom <= DW_OP_breg31) ||
- ops->atom == DW_OP_bregx || ops->atom == DW_OP_fbreg) &&
- !is_breg_access_indirect(ops, nops))
- /* The register contains an address of the variable. */
- vt->is_reg_var_addr = true;
+ vt = malloc(sizeof(*vt));
+ if (vt == NULL)
+ return DIE_FIND_CB_END;
- vt->die_off = dwarf_dieoffset(&type_die);
- vt->addr = start;
- vt->end = end;
- vt->has_range = (end != 0 || start != 0);
- vt->reg = reg_from_dwarf_op(ops);
- vt->offset = offset_from_dwarf_op(ops);
- vt->next = *var_types;
- *var_types = vt;
+ /* Usually a register holds the value of a variable */
+ vt->is_reg_var_addr = false;
+
+ if (((ops->atom >= DW_OP_breg0 && ops->atom <= DW_OP_breg31) ||
+ ops->atom == DW_OP_bregx || ops->atom == DW_OP_fbreg) &&
+ !is_breg_access_indirect(ops, nops))
+ /* The register contains an address of the variable. */
+ vt->is_reg_var_addr = true;
+
+ vt->die_off = dwarf_dieoffset(&type_die);
+ vt->addr = start;
+ vt->end = end;
+ vt->has_range = (end != 0 || start != 0);
+ vt->reg = reg_from_dwarf_op(ops);
+ vt->offset = offset_from_dwarf_op(ops);
+ vt->next = *var_types;
+ *var_types = vt;
+ }
return DIE_FIND_CB_SIBLING;
}