diff options
-rw-r--r-- | dwflpp.cxx | 20 | ||||
-rw-r--r-- | loc2c-test.c | 33 | ||||
-rw-r--r-- | loc2c.c | 31 | ||||
-rw-r--r-- | loc2c.h | 7 |
4 files changed, 86 insertions, 5 deletions
@@ -1449,6 +1449,24 @@ dwflpp::translate_location(struct obstack *pool, struct location **tail, const target_symbol *e) { + + /* DW_AT_data_member_location, can be either constant offsets + (struct member fields), or full blown location expressions. */ + if (dwarf_whatattr (attr) == DW_AT_data_member_location) + { + unsigned int form = dwarf_whatform (attr); + if (form == DW_FORM_data1 || form == DW_FORM_data2 + || form == DW_FORM_sdata || form == DW_FORM_udata) + { + Dwarf_Sword off; + if (dwarf_formsdata (attr, &off) != 0) + throw semantic_error (string ("dwarf_formsdata failed, ") + + string (dwarf_errmsg (-1)), e->tok); + c_translate_add_offset (pool, 1, NULL, off, tail); + return *tail; + } + } + Dwarf_Op *expr; size_t len; @@ -1470,7 +1488,7 @@ dwflpp::translate_location(struct obstack *pool, default: /* Shouldn't happen. */ case -1: - throw semantic_error (string ("dwarf_getlocation_addr failed") + + throw semantic_error (string ("dwarf_getlocation_addr failed, ") + string (dwarf_errmsg (-1)), e->tok); } diff --git a/loc2c-test.c b/loc2c-test.c index 01108573..688f4a8b 100644 --- a/loc2c-test.c +++ b/loc2c-test.c @@ -214,10 +214,35 @@ handle_variable (Dwarf_Die *scopes, int nscopes, int out, } else { - locexpr = get_location (cubias, pc, &attr_mem, &locexpr_len); - c_translate_location (&pool, NULL, NULL, NULL, - 1, cubias, pc, locexpr, locexpr_len, - &tail, NULL); + /* We are expection a block, constant or loclistptr. */ + unsigned int form = dwarf_whatform (&attr_mem); + Dwarf_Sword off; + switch (form) + { + /* constant */ + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_sdata: + case DW_FORM_udata: + if (dwarf_formsdata (&attr_mem, &off) != 0) + error (2, 0, _("Bad offset for %s %s: %s"), + typetag == DW_TAG_union_type ? "union" : "struct", + dwarf_diename_integrate (die) ?: "<anonymous>", + dwarf_errmsg (-1)); + if (off != 0) + c_translate_add_offset (&pool, 1, + dwarf_diename_integrate (die) + ?: "", off, &tail); + break; + + default: + locexpr = get_location (cubias, pc, &attr_mem, + &locexpr_len); + c_translate_location (&pool, NULL, NULL, NULL, + 1, cubias, pc, locexpr, locexpr_len, + &tail, NULL); + break; + } } ++fields; break; @@ -1669,7 +1669,38 @@ c_translate_pointer_store (struct obstack *pool, int indent, } +/* Translate a fragment to add an offset to the currently calculated + address of the input location. Used for struct fields. Only works + when location is already an actual base address. +*/ +void +c_translate_add_offset (struct obstack *pool, int indent, const char *comment, + Dwarf_Sword off, struct location **input) +{ + indent++; + if (comment == NULL || comment[0] == '\0') + comment = "field offset"; + switch ((*input)->type) + { + case loc_address: + obstack_printf (pool, "%*saddr += " SFORMAT "; // %s\n", + indent * 2 + 2, "", off, comment); + *input = (*input)->next = new_synthetic_loc (pool, *input, false); + break; + + case loc_register: + FAIL (*input, N_("cannot add offset of object in register")); + break; + case loc_noncontiguous: + FAIL (*input, N_("cannot add offset of noncontiguous object")); + break; + + default: + abort (); + break; + } +} /* Determine the element stride of an array type. */ static Dwarf_Word @@ -85,6 +85,13 @@ c_translate_pointer_store (struct obstack *pool, int indent, Dwarf_Die *typedie, struct location **input, const char *rvalue); +/* Translate a fragment to add an offset to the currently calculated + address of the input location. Used for struct fields. Only works + when location is already an actual base address. */ +void +c_translate_add_offset (struct obstack *pool, int indent, const char *comment, + Dwarf_Sword off, struct location **input); + /* Translate a C fragment for a direct argument VALUE. On errors, call FAIL, which should not return. Any later errors will use FAIL and FAIL_ARG from this translate call. On success, return the fragment created. */ |