[PATCH 15/22] [DbgHelp]: dwarf & inlined function support

Eric Pouech eric.pouech at wanadoo.fr
Fri Nov 24 15:18:20 CST 2006


- extended support for inlined functions (and handle them
  as generic blocks inside functions (except for parameters
  which are converted into local variables)
- rewrote dwarf2_find_attribute so that it takes into account
  the abstract origin information when available

A+
---

 dlls/dbghelp/dwarf.c |  285 ++++++++++++++++++++++++++++----------------------
 1 files changed, 162 insertions(+), 123 deletions(-)

diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c
index a61c833..75fe839 100644
--- a/dlls/dbghelp/dwarf.c
+++ b/dlls/dbghelp/dwarf.c
@@ -330,7 +330,7 @@ static const char* dwarf2_debug_ctx(cons
     return wine_dbg_sprintf("ctx(%p,%s)", ctx, ctx->module->module.ModuleName);
 }
 
-static const char* dwarf2_debug_di(dwarf2_debug_info_t* di) 
+static const char* dwarf2_debug_di(const dwarf2_debug_info_t* di) 
 {
     return wine_dbg_sprintf("debug_info(abbrev:%p,symt:%p)",
                             di->abbrev, di->symt);
@@ -442,118 +442,143 @@ static void dwarf2_swallow_attribute(dwa
     ctx->data += step;
 }
 
-static BOOL dwarf2_find_attribute(const dwarf2_parse_context_t* ctx,
-                                  const dwarf2_debug_info_t* di,
-                                  unsigned at, struct attribute* attr)
+static void dwarf2_fill_attr(const dwarf2_parse_context_t* ctx,
+                             const dwarf2_abbrev_entry_attr_t* abbrev_attr,
+                             const unsigned char* data,
+                             struct attribute* attr)
 {
-    unsigned                    i;
-    dwarf2_abbrev_entry_attr_t* abbrev_attr;
-
-    for (i = 0, abbrev_attr = di->abbrev->attrs; abbrev_attr; i++, abbrev_attr = abbrev_attr->next)
+    attr->form = abbrev_attr->form;
+    switch (attr->form)
     {
-        if (abbrev_attr->attribute == at)
-        {
-            attr->form = abbrev_attr->form;
-            switch (attr->form)
-            {
-            case DW_FORM_ref_addr:
-            case DW_FORM_addr:
-                attr->u.uvalue = dwarf2_get_addr(di->data[i], ctx->word_size);
-                TRACE("addr<0x%lx>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_ref_addr:
+    case DW_FORM_addr:
+        attr->u.uvalue = dwarf2_get_addr(data, ctx->word_size);
+        TRACE("addr<0x%lx>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_flag:
-                attr->u.uvalue = dwarf2_get_byte(di->data[i]);
-                TRACE("flag<0x%lx>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_flag:
+        attr->u.uvalue = dwarf2_get_byte(data);
+        TRACE("flag<0x%lx>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_data1:
-                attr->u.uvalue = dwarf2_get_byte(di->data[i]);
-                TRACE("data1<%lu>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_data1:
+        attr->u.uvalue = dwarf2_get_byte(data);
+        TRACE("data1<%lu>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_data2:
-                attr->u.uvalue = dwarf2_get_u2(di->data[i]);
-                TRACE("data2<%lu>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_data2:
+        attr->u.uvalue = dwarf2_get_u2(data);
+        TRACE("data2<%lu>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_data4:
-                attr->u.uvalue = dwarf2_get_u4(di->data[i]);
-                TRACE("data4<%lu>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_data4:
+        attr->u.uvalue = dwarf2_get_u4(data);
+        TRACE("data4<%lu>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_data8:
-                FIXME("Unhandled 64bits support\n");
-                break;
+    case DW_FORM_data8:
+        FIXME("Unhandled 64bits support\n");
+        break;
 
-            case DW_FORM_ref1:
-                attr->u.uvalue = ctx->ref_offset + dwarf2_get_byte(di->data[i]);
-                TRACE("ref1<0x%lx>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_ref1:
+        attr->u.uvalue = ctx->ref_offset + dwarf2_get_byte(data);
+        TRACE("ref1<0x%lx>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_ref2:
-                attr->u.uvalue = ctx->ref_offset + dwarf2_get_u2(di->data[i]);
-                TRACE("ref2<0x%lx>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_ref2:
+        attr->u.uvalue = ctx->ref_offset + dwarf2_get_u2(data);
+        TRACE("ref2<0x%lx>\n", attr->u.uvalue);
+        break;
 
-            case DW_FORM_ref4:
-                attr->u.uvalue = ctx->ref_offset + dwarf2_get_u4(di->data[i]);
-                TRACE("ref4<0x%lx>\n", attr->u.uvalue);
-                break;
+    case DW_FORM_ref4:
+        attr->u.uvalue = ctx->ref_offset + dwarf2_get_u4(data);
+        TRACE("ref4<0x%lx>\n", attr->u.uvalue);
+        break;
     
-            case DW_FORM_ref8:
-                FIXME("Unhandled 64 bit support\n");
-                break;
+    case DW_FORM_ref8:
+        FIXME("Unhandled 64 bit support\n");
+        break;
 
-            case DW_FORM_sdata:
-                attr->u.svalue = dwarf2_get_leb128_as_signed(di->data[i], NULL);
-                break;
+    case DW_FORM_sdata:
+        attr->u.svalue = dwarf2_get_leb128_as_signed(data, NULL);
+        break;
 
-            case DW_FORM_ref_udata:
-                attr->u.uvalue = dwarf2_get_leb128_as_unsigned(di->data[i], NULL);
-                break;
+    case DW_FORM_ref_udata:
+        attr->u.uvalue = dwarf2_get_leb128_as_unsigned(data, NULL);
+        break;
 
-            case DW_FORM_udata:
-                attr->u.uvalue = dwarf2_get_leb128_as_unsigned(di->data[i], NULL);
-                break;
+    case DW_FORM_udata:
+        attr->u.uvalue = dwarf2_get_leb128_as_unsigned(data, NULL);
+        break;
 
-            case DW_FORM_string:
-                attr->u.string = (const char *)di->data[i];
-                TRACE("string<%s>\n", attr->u.string);
-                break;
+    case DW_FORM_string:
+        attr->u.string = (const char *)data;
+        TRACE("string<%s>\n", attr->u.string);
+        break;
 
-            case DW_FORM_strp:
-            {
-                unsigned long offset = dwarf2_get_u4(di->data[i]);
-                attr->u.string = (const char*)ctx->sections[section_string].address + offset;
-            }
-            TRACE("strp<%s>\n", attr->u.string);
-            break;
-            case DW_FORM_block:
-                attr->u.block.size = dwarf2_get_leb128_as_unsigned(di->data[i], &attr->u.block.ptr);
-                break;
+    case DW_FORM_strp:
+    {
+        unsigned long offset = dwarf2_get_u4(data);
+        attr->u.string = (const char*)ctx->sections[section_string].address + offset;
+    }
+    TRACE("strp<%s>\n", attr->u.string);
+    break;
+        
+    case DW_FORM_block:
+        attr->u.block.size = dwarf2_get_leb128_as_unsigned(data, &attr->u.block.ptr);
+        break;
 
-            case DW_FORM_block1:
-                attr->u.block.size = dwarf2_get_byte(di->data[i]);
-                attr->u.block.ptr  = di->data[i] + 1;
-                break;
+    case DW_FORM_block1:
+        attr->u.block.size = dwarf2_get_byte(data);
+        attr->u.block.ptr  = data + 1;
+        break;
 
-            case DW_FORM_block2:
-                attr->u.block.size = dwarf2_get_u2(di->data[i]);
-                attr->u.block.ptr  = di->data[i] + 2;
-                break;
+    case DW_FORM_block2:
+        attr->u.block.size = dwarf2_get_u2(data);
+        attr->u.block.ptr  = data + 2;
+        break;
 
-            case DW_FORM_block4:
-                attr->u.block.size = dwarf2_get_u4(di->data[i]);
-                attr->u.block.ptr  = di->data[i] + 4;
-                break;
+    case DW_FORM_block4:
+        attr->u.block.size = dwarf2_get_u4(data);
+        attr->u.block.ptr  = data + 4;
+        break;
 
-            default:
-                FIXME("Unhandled attribute form %lx\n", abbrev_attr->form);
-                break;
+    default:
+        FIXME("Unhandled attribute form %lx\n", abbrev_attr->form);
+        break;
+    }
+}
+
+static BOOL dwarf2_find_attribute(const dwarf2_parse_context_t* ctx,
+                                  const dwarf2_debug_info_t* di,
+                                  unsigned at, struct attribute* attr)
+{
+    unsigned                    i, ai = 0;
+    dwarf2_abbrev_entry_attr_t* abbrev_attr;
+    dwarf2_abbrev_entry_attr_t* abstract_abbrev_attr;
+
+    while (di)
+    {
+        abstract_abbrev_attr = NULL;
+        for (i = 0, abbrev_attr = di->abbrev->attrs; abbrev_attr; i++, abbrev_attr = abbrev_attr->next)
+        {
+            if (abbrev_attr->attribute == at)
+            {
+                dwarf2_fill_attr(ctx, abbrev_attr, di->data[i], attr);
+                return TRUE;
+            }
+            if (abbrev_attr->attribute == DW_AT_abstract_origin &&
+                at != DW_AT_sibling)
+            {
+                abstract_abbrev_attr = abbrev_attr;
+                ai = i;
             }
-            return TRUE;
         }
+        /* do we have an abstract origin debug entry to look into ? */
+        if (!abstract_abbrev_attr) break;
+        dwarf2_fill_attr(ctx, abstract_abbrev_attr, di->data[ai], attr);
+        if (!(di = sparse_array_find(&ctx->debug_info_table, attr->u.uvalue)))
+            FIXME("Should have found the debug info entry\n");
     }
     return FALSE;
 }
@@ -1101,7 +1126,8 @@ static void dwarf2_parse_udt_member(dwar
     }
     else
         loc.offset = 0;
-    if (!dwarf2_find_attribute(ctx, di, DW_AT_bit_size, &bit_size))   bit_size.u.uvalue = 0;
+    if (!dwarf2_find_attribute(ctx, di, DW_AT_bit_size, &bit_size))
+        bit_size.u.uvalue = 0;
     if (dwarf2_find_attribute(ctx, di, DW_AT_bit_offset, &bit_offset))
     {
         /* FIXME: we should only do this when implementation is LSB (which is
@@ -1247,15 +1273,17 @@ static void dwarf2_parse_variable(dwarf2
                                   struct symt_block* block,
                                   dwarf2_debug_info_t* di)
 {
-    struct symt* param_type;
-    struct attribute name, value;
-    struct location loc;
-    BOOL is_pmt = di->abbrev->tag == DW_TAG_formal_parameter;
+    struct symt*        param_type;
+    struct attribute    name, value;
+    struct location     loc;
+    BOOL                is_pmt;
 
     TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
 
+    is_pmt = !block && di->abbrev->tag == DW_TAG_formal_parameter;
     param_type = dwarf2_lookup_type(subpgm->ctx, di);
-    dwarf2_find_name(subpgm->ctx, di, &name, "parameter");
+        
+    dwarf2_find_name(subpgm->ctx, di, &name, NULL);
     if (dwarf2_compute_location_attr(subpgm->ctx, di, DW_AT_location,
                                      &loc, &subpgm->frame))
     {
@@ -1314,7 +1342,7 @@ static void dwarf2_parse_subprogram_labe
     TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
 
     if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_low_pc, &low_pc)) low_pc.u.uvalue = 0;
-    dwarf2_find_name(subpgm->ctx, di, &name, "label");
+    dwarf2_find_name(subpgm->ctx, di, &name, NULL);
 
     loc.kind = loc_absolute;
     loc.offset = subpgm->ctx->module->module.BaseOfImage + low_pc.u.uvalue,
@@ -1323,19 +1351,24 @@ static void dwarf2_parse_subprogram_labe
 }
 
 static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm,
-                                          struct symt_block* block_parent,
+                                          struct symt_block* parent_block,
 					  dwarf2_debug_info_t* di);
 
 static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm,
+                                            struct symt_block* parent_block,
                                             dwarf2_debug_info_t* di)
 {
+    struct symt_block*  block;
+    struct attribute    low_pc;
+    struct attribute    high_pc;
+
     TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
 
-    /* FIXME: attributes to handle:
-       DW_AT_low_pc:
-       DW_AT_high_pc:
-       DW_AT_name:
-    */
+    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_low_pc, &low_pc)) low_pc.u.uvalue = 0;
+    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_high_pc, &high_pc)) high_pc.u.uvalue = 0;
+
+    block = symt_open_func_block(subpgm->ctx->module, subpgm->func, parent_block,
+                                 low_pc.u.uvalue, high_pc.u.uvalue - low_pc.u.uvalue);
 
     if (di->abbrev->have_child) /** any interest to not have child ? */
     {
@@ -1349,23 +1382,14 @@ static void dwarf2_parse_inlined_subrout
             switch (child->abbrev->tag)
             {
             case DW_TAG_formal_parameter:
-                /* FIXME: this is not properly supported yet
-                 * dwarf2_parse_subprogram_parameter(ctx, child, NULL);
-                 */
-                break;
             case DW_TAG_variable:
-                /* FIXME:
-                 * dwarf2_parse_variable(ctx, child);
-                 */
+                dwarf2_parse_variable(subpgm, block, child);
                 break;
             case DW_TAG_lexical_block:
-                /* FIXME:
-                   dwarf2_parse_subprogram_block(ctx, child, func);
-                */
+                dwarf2_parse_subprogram_block(subpgm, block, child);
                 break;
             case DW_TAG_inlined_subroutine:
-                /* FIXME */
-                dwarf2_parse_inlined_subroutine(subpgm, child);
+                dwarf2_parse_inlined_subroutine(subpgm, block, child);
                 break;
             case DW_TAG_label:
                 dwarf2_parse_subprogram_label(subpgm, child);
@@ -1377,6 +1401,7 @@ static void dwarf2_parse_inlined_subrout
             }
         }
     }
+    symt_close_func_block(subpgm->ctx->module, subpgm->func, block, 0);
 }
 
 static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, 
@@ -1389,8 +1414,10 @@ static void dwarf2_parse_subprogram_bloc
 
     TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
 
-    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_low_pc, &low_pc)) low_pc.u.uvalue = 0;
-    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_high_pc, &high_pc)) high_pc.u.uvalue = 0;
+    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_low_pc, &low_pc))
+        low_pc.u.uvalue = 0;
+    if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_high_pc, &high_pc))
+        high_pc.u.uvalue = 0;
 
     block = symt_open_func_block(subpgm->ctx->module, subpgm->func, parent_block,
                                  low_pc.u.uvalue, high_pc.u.uvalue - low_pc.u.uvalue);
@@ -1407,7 +1434,7 @@ static void dwarf2_parse_subprogram_bloc
             switch (child->abbrev->tag)
             {
             case DW_TAG_inlined_subroutine:
-                dwarf2_parse_inlined_subroutine(subpgm, child);
+                dwarf2_parse_inlined_subroutine(subpgm, block, child);
                 break;
             case DW_TAG_variable:
                 dwarf2_parse_variable(subpgm, block, child);
@@ -1461,6 +1488,17 @@ static struct symt* dwarf2_parse_subprog
 
     TRACE("%s, for %s\n", dwarf2_debug_ctx(ctx), dwarf2_debug_di(di));
 
+    /* if it's an abstract representation of an inline function, there should be
+     * a concrete object that we'll handle
+     */
+    if (dwarf2_find_attribute(ctx, di, DW_AT_inline, &inline_flags))
+    {
+        dwarf2_find_name(ctx, di, &name, "subprogram");
+        TRACE("Function %s declared as inlined (%ld)... skipping\n",
+              name.u.string, inline_flags.u.uvalue);
+        return NULL;
+    }
+
     if (!dwarf2_find_attribute(ctx, di, DW_AT_low_pc, &low_pc)) low_pc.u.uvalue = 0;
     if (!dwarf2_find_attribute(ctx, di, DW_AT_high_pc, &high_pc)) high_pc.u.uvalue = 0;
     /* As functions (defined as inline assembly) get debug info with dwarf
@@ -1470,9 +1508,10 @@ static struct symt* dwarf2_parse_subprog
     if (elf_is_in_thunk_area(ctx->module->module.BaseOfImage + low_pc.u.uvalue,
                              ctx->thunks) >= 0)
         return NULL;
-    if (!dwarf2_find_attribute(ctx, di, DW_AT_declaration, &is_decl)) is_decl.u.uvalue = 0;
-    if (!dwarf2_find_attribute(ctx, di, DW_AT_inline, &inline_flags)) inline_flags.u.uvalue = 0;
-    dwarf2_find_name(ctx, di, &name, "subprogram");
+    if (!dwarf2_find_attribute(ctx, di, DW_AT_declaration, &is_decl))
+        is_decl.u.uvalue = 0;
+        
+    dwarf2_find_name(ctx, di, &name, NULL);
     ret_type = dwarf2_lookup_type(ctx, di);
 
     /* FIXME: assuming C source code */
@@ -1518,7 +1557,7 @@ static struct symt* dwarf2_parse_subprog
                 dwarf2_parse_subprogram_block(&subpgm, NULL, child);
                 break;
             case DW_TAG_inlined_subroutine:
-                dwarf2_parse_inlined_subroutine(&subpgm, child);
+                dwarf2_parse_inlined_subroutine(&subpgm, NULL, child);
                 break;
             case DW_TAG_subprogram:
                 /* FIXME: likely a declaration (to be checked)



More information about the wine-patches mailing list