[PATCH 01/15] dbghelp: introduce symt_inlinesite (SymTagInlineSite) to support inline sites

Eric Pouech eric.pouech at gmail.com
Fri Oct 22 02:14:58 CDT 2021


Signed-off-by: Eric Pouech <eric.pouech at gmail.com>

---
 dlls/dbghelp/dbghelp_private.h |   70 +++++++++++++++++++++++++++++++
 dlls/dbghelp/dwarf.c           |    2 -
 dlls/dbghelp/msc.c             |    4 +-
 dlls/dbghelp/symbol.c          |   89 ++++++++++++++++++++++++++++------------
 dlls/dbghelp/type.c            |   16 +++++++
 5 files changed, 150 insertions(+), 31 deletions(-)

diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h
index 2ebe6699a1d..761af2ef9e1 100644
--- a/dlls/dbghelp/dbghelp_private.h
+++ b/dlls/dbghelp/dbghelp_private.h
@@ -216,16 +216,75 @@ struct symt_data
     } u;
 };
 
+/* We must take into account that most debug formats (dwarf and pdb) report for
+ * code (esp. inlined functions) inside functions the following way:
+ * - block
+ *   + is represented by a contiguous area of memory,
+ *     or at least have lo/hi addresses to encompass it's contents
+ *   + but most importantly, block A's lo/hi range is always embedded within
+ *     its parent (block or function)
+ * - inline site:
+ *   + is most of the times represented by a set of ranges (instead of a
+ *     contiguous block)
+ *   + native dbghelp only exports the start address, not its size
+ *   + the set of ranges isn't always embedded in enclosing block (if any)
+ *   + the set of ranges is always embedded in top function
+ * - (top) function
+ *   + is described as a contiguous block of memory
+ *
+ * On top of the items above (taken as assumptions), we also assume that:
+ * - a range in inline site A, is disjoint from all the other ranges in
+ *   inline site A
+ * - a range in inline site A, is either disjoint or embedded into any of
+ *   the ranges of inline sites parent of A
+ *
+ * Therefore, we also store all inline sites inside a function:
+ * - available as a linked list to simplify the walk among them
+ * - this linked list shall preserve the weak order of the lexical-parent
+ *   relationship (eg for any inline site A, which has inline site B
+ *   as lexical parent, then A is present before B in the linked list)
+ * - hence (from the assumptions above), when looking up which inline site
+ *   contains a given address, the first range containing that address found
+ *   while walking the list of inline sites is the right one.
+ */
+
 struct symt_function
 {
-    struct symt                 symt;
+    struct symt                 symt;           /* SymTagFunction (or SymTagInlineSite when embedded in symt_inlinesite) */
     struct hash_table_elt       hash_elt;       /* if global symbol */
     ULONG_PTR                   address;
     struct symt*                container;      /* compiland */
     struct symt*                type;           /* points to function_signature */
     ULONG_PTR                   size;
     struct vector               vlines;
-    struct vector               vchildren;      /* locals, params, blocks, start/end, labels */
+    struct vector               vchildren;      /* locals, params, blocks, start/end, labels, inline sites */
+    struct symt_inlinesite*     next_inlinesite;/* linked list of inline sites in this function */
+};
+
+/* FIXME: this could be optimized later on by using relative offsets and smaller integral sizes */
+struct addr_range
+{
+    DWORD64                     low;            /* absolute address of first byte of the range */
+    DWORD64                     high;           /* absolute address of first byte after the range */
+};
+
+/* tests whether ar2 in inside ar1 */
+static inline BOOL addr_range_inside(const struct addr_range* ar1, const struct addr_range* ar2)
+{
+    return ar1->low <= ar2->low && ar2->high <= ar2->high;
+}
+
+/* tests whether ar1 and ar2 are disjoint */
+static inline BOOL addr_range_disjoint(const struct addr_range* ar1, const struct addr_range* ar2)
+{
+    return ar1->high <= ar2->low || ar2->high <= ar1->low;
+}
+
+/* a symt_inlinesite* can be casted to a symt_function* to access all function bits */
+struct symt_inlinesite
+{
+    struct symt_function        func;
+    struct vector               vranges;        /* of addr_range: where the inline site is actually defined */
 };
 
 struct symt_hierarchy_point
@@ -756,6 +815,13 @@ extern struct symt_function*
                                       const char* name,
                                       ULONG_PTR addr, ULONG_PTR size,
                                       struct symt* type) DECLSPEC_HIDDEN;
+extern struct symt_inlinesite*
+                    symt_new_inlinesite(struct module* module,
+                                        struct symt_function* func,
+                                        struct symt* parent,
+                                        const char* name,
+                                        ULONG_PTR addr,
+                                        struct symt* type) DECLSPEC_HIDDEN;
 extern void         symt_add_func_line(struct module* module,
                                        struct symt_function* func, 
                                        unsigned source_idx, int line_num, 
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c
index e1c77569622..bde83aca0aa 100644
--- a/dlls/dbghelp/dwarf.c
+++ b/dlls/dbghelp/dwarf.c
@@ -2438,7 +2438,7 @@ static void dwarf2_set_line_number(struct module* module, ULONG_PTR address,
     TRACE("%s %lx %s %u\n",
           debugstr_w(module->modulename), address, debugstr_a(source_get(module, *psrc)), line);
     symt = symt_find_nearest(module, address);
-    if (symt && symt_check_tag(&symt->symt, SymTagFunction))
+    if (symt_check_tag(&symt->symt, SymTagFunction))
     {
         func = (struct symt_function*)symt;
         symt_add_func_line(module, func, *psrc, line, address - func->address);
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c
index 2468051acc7..c557cb24636 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -1446,7 +1446,7 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B
                 {
                     func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
                     /* FIXME: at least labels support line numbers */
-                    if (!func || func->symt.tag != SymTagFunction)
+                    if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite))
                     {
                         WARN("--not a func at %04x:%08x %lx tag=%d\n",
                              ltb->seg, ltb->offsets[k], addr, func ? func->symt.tag : -1);
@@ -1509,7 +1509,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const
             source = source_new(msc_dbg->module, NULL, strimage + fd->offset);
             func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
             /* FIXME: at least labels support line numbers */
-            if (!func || func->symt.tag != SymTagFunction)
+            if (!symt_check_tag(&func->symt, SymTagFunction) && !symt_check_tag(&func->symt, SymTagInlineSite))
             {
                 WARN("--not a func at %04x:%08x %lx tag=%d\n",
                      lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1);
diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c
index 19374999070..cb39fd5b422 100644
--- a/dlls/dbghelp/symbol.c
+++ b/dlls/dbghelp/symbol.c
@@ -318,35 +318,74 @@ struct symt_data* symt_new_global_variable(struct module* module,
     return sym;
 }
 
-struct symt_function* symt_new_function(struct module* module, 
-                                        struct symt_compiland* compiland, 
+static void init_function_or_inlinesite(struct symt_function* sym,
+                                        struct module* module,
+                                        DWORD tag,
+                                        struct symt* container,
                                         const char* name,
                                         ULONG_PTR addr, ULONG_PTR size,
                                         struct symt* sig_type)
 {
-    struct symt_function*       sym;
-    struct symt**               p;
+    assert(!sig_type || sig_type->tag == SymTagFunctionType);
+    sym->symt.tag  = tag;
+    sym->hash_elt.name = pool_strdup(&module->pool, name);
+    sym->container = container;
+    sym->address   = addr;
+    sym->type      = sig_type;
+    sym->size      = size;
+    vector_init(&sym->vlines,  sizeof(struct line_info), 64);
+    vector_init(&sym->vchildren, sizeof(struct symt*), 8);
+}
+
+struct symt_function* symt_new_function(struct module* module,
+                                        struct symt_compiland* compiland,
+                                        const char* name,
+                                        ULONG_PTR addr, ULONG_PTR size,
+                                        struct symt* sig_type)
+{
+    struct symt_function* sym;
 
     TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n",
                          debugstr_w(module->modulename), name, addr, addr + size - 1);
-
-    assert(!sig_type || sig_type->tag == SymTagFunctionType);
     if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
     {
-        sym->symt.tag  = SymTagFunction;
-        sym->hash_elt.name = pool_strdup(&module->pool, name);
-        sym->container = &compiland->symt;
-        sym->address   = addr;
-        sym->type      = sig_type;
-        sym->size      = size;
-        vector_init(&sym->vlines,  sizeof(struct line_info), 64);
-        vector_init(&sym->vchildren, sizeof(struct symt*), 8);
+        struct symt** p;
+        init_function_or_inlinesite(sym, module, SymTagFunction, &compiland->symt, name, addr, size, sig_type);
+        sym->next_inlinesite = NULL; /* first of list */
         symt_add_module_ht(module, (struct symt_ht*)sym);
-        if (compiland)
+        p = vector_add(&compiland->vchildren, &module->pool);
+        *p = &sym->symt;
+    }
+    return sym;
+}
+
+struct symt_inlinesite* symt_new_inlinesite(struct module* module,
+                                            struct symt_function* func,
+                                            struct symt* container,
+                                            const char* name,
+                                            ULONG_PTR addr,
+                                            struct symt* sig_type)
+{
+    struct symt_inlinesite* sym;
+
+    TRACE_(dbghelp_symt)("Adding inline site %s @%lx\n", name, addr);
+    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
+    {
+        struct symt** p;
+        assert(container);
+        init_function_or_inlinesite(&sym->func, module, SymTagInlineSite, container, name, addr, 0, sig_type);
+        vector_init(&sym->vranges, sizeof(struct addr_range), 2); /* FIXME: number of elts => to be set on input */
+        /* chain inline sites */
+        sym->func.next_inlinesite = func->next_inlinesite;
+        func->next_inlinesite = sym;
+        if (container->tag == SymTagFunction || container->tag == SymTagInlineSite)
+            p = vector_add(&((struct symt_function*)container)->vchildren, &module->pool);
+        else
         {
-            p = vector_add(&compiland->vchildren, &module->pool);
-            *p = &sym->symt;
+            assert(container->tag == SymTagBlock);
+            p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool);
         }
+        *p = &sym->func.symt;
     }
     return sym;
 }
@@ -366,7 +405,7 @@ void symt_add_func_line(struct module* module, struct symt_function* func,
                          func, func->hash_elt.name, offset, 
                          source_get(module, source_idx), line_num);
 
-    assert(func->symt.tag == SymTagFunction);
+    assert(func->symt.tag == SymTagFunction || func->symt.tag == SymTagInlineSite);
 
     for (i=vector_length(&func->vlines)-1; i>=0; i--)
     {
@@ -424,8 +463,7 @@ struct symt_data* symt_add_func_local(struct module* module,
                          debugstr_w(module->modulename), func->hash_elt.name,
                          name, type);
 
-    assert(func);
-    assert(func->symt.tag == SymTagFunction);
+    assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
     assert(dt == DataIsParam || dt == DataIsLocal);
 
     locsym = pool_alloc(&module->pool, sizeof(*locsym));
@@ -462,8 +500,7 @@ struct symt_data* symt_add_func_constant(struct module* module,
                          debugstr_w(module->modulename), func->hash_elt.name,
                          name, type);
 
-    assert(func);
-    assert(func->symt.tag == SymTagFunction);
+    assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
 
     locsym = pool_alloc(&module->pool, sizeof(*locsym));
     locsym->symt.tag      = SymTagData;
@@ -489,8 +526,7 @@ struct symt_block* symt_open_func_block(struct module* module,
     struct symt_block*  block;
     struct symt**       p;
 
-    assert(func);
-    assert(func->symt.tag == SymTagFunction);
+    assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
 
     assert(!parent_block || parent_block->symt.tag == SymTagBlock);
     block = pool_alloc(&module->pool, sizeof(*block));
@@ -512,8 +548,7 @@ struct symt_block* symt_close_func_block(struct module* module,
                                          const struct symt_function* func,
                                          struct symt_block* block, unsigned pc)
 {
-    assert(func);
-    assert(func->symt.tag == SymTagFunction);
+    assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite));
 
     if (pc) block->size = func->address + pc - block->address;
     return (block->container->tag == SymTagBlock) ? 
@@ -781,6 +816,7 @@ static void symt_fill_sym_info(struct module_pair* pair,
         }
         break;
     case SymTagFunction:
+    case SymTagInlineSite:
         symt_get_address(sym, &sym_info->Address);
         break;
     case SymTagThunk:
@@ -1061,6 +1097,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair,
         case SymTagFuncDebugStart:
         case SymTagFuncDebugEnd:
         case SymTagCustom:
+        case SymTagInlineSite:
             break;
         default:
             FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag);
diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c
index 80f8eca768e..3a7ebfb6a0a 100644
--- a/dlls/dbghelp/type.c
+++ b/dlls/dbghelp/type.c
@@ -95,6 +95,7 @@ const char* symt_get_name(const struct symt* sym)
     /* lexical tree */
     case SymTagData:            return ((const struct symt_data*)sym)->hash_elt.name;
     case SymTagFunction:        return ((const struct symt_function*)sym)->hash_elt.name;
+    case SymTagInlineSite:      return ((const struct symt_inlinesite*)sym)->func.hash_elt.name;
     case SymTagPublicSymbol:    return ((const struct symt_public*)sym)->hash_elt.name;
     case SymTagBaseType:        return ((const struct symt_basic*)sym)->hash_elt.name;
     case SymTagLabel:           return ((const struct symt_hierarchy_point*)sym)->hash_elt.name;
@@ -153,6 +154,9 @@ BOOL symt_get_address(const struct symt* type, ULONG64* addr)
     case SymTagFunction:
         *addr = ((const struct symt_function*)type)->address;
         break;
+    case SymTagInlineSite:
+        *addr = ((const struct symt_inlinesite*)type)->func.address;
+        break;
     case SymTagPublicSymbol:
         *addr = ((const struct symt_public*)type)->address;
         break;
@@ -572,6 +576,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
             case SymTagEnum:         v = &((const struct symt_enum*)type)->vchildren; break;
             case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break;
             case SymTagFunction:     v = &((const struct symt_function*)type)->vchildren; break;
+            case SymTagInlineSite:   v = &((const struct symt_inlinesite*)type)->func.vchildren; break;
             case SymTagBlock:        v = &((const struct symt_block*)type)->vchildren; break;
             case SymTagPointerType:
             case SymTagArrayType:
@@ -644,6 +649,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
         case SymTagFunction:
             X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren);
             break;
+        case SymTagInlineSite:
+            X(DWORD) = vector_length(&((const struct symt_inlinesite*)type)->func.vchildren);
+            break;
         case SymTagBlock:
             X(DWORD) = vector_length(&((const struct symt_block*)type)->vchildren);
             break;
@@ -745,6 +753,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
         case SymTagCompiland:
         case SymTagFunctionType:
         case SymTagFunctionArgType:
+        case SymTagInlineSite: /* native doesn't expose it, perhaps because of non-contiguous range */
         case SymTagLabel:
         case SymTagFuncDebugStart:
         case SymTagFuncDebugEnd:
@@ -767,6 +776,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
         case SymTagFunction:
             X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container);
             break;
+        case SymTagInlineSite:
+            X(DWORD) = symt_ptr2index(module, ((const struct symt_inlinesite*)type)->func.container);
+            break;
         case SymTagThunk:
             X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container);
             break;
@@ -846,6 +858,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
         case SymTagFuncDebugStart:
         case SymTagFuncDebugEnd:
         case SymTagLabel:
+        case SymTagInlineSite:
         case SymTagCustom:
             return FALSE;
         }
@@ -899,6 +912,9 @@ BOOL symt_get_info(struct module* module, const struct symt* type,
         case SymTagFunction:
             X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type);
             break;
+        case SymTagInlineSite:
+            X(DWORD) = symt_ptr2index(module, ((const struct symt_inlinesite*)type)->func.type);
+            break;
         case SymTagEnum:
             X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type);
             break;




More information about the wine-devel mailing list