[PATCH 11/13] dbghelp/pdb: added support for inline sites

Eric Pouech eric.pouech at gmail.com
Mon Nov 8 07:59:34 CST 2021


- support S_INLINESITE and S_INLINESITE_END

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

---
 dlls/dbghelp/msc.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 241 insertions(+), 22 deletions(-)

diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c
index 12334a2e69d..4fba245d815 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -1762,11 +1762,180 @@ static unsigned codeview_transform_defrange(const struct msc_debug_info* msc_dbg
     return len;
 }
 
+static unsigned codeview_binannot_uncompress(const unsigned char** pptr)
+{
+    unsigned res = (unsigned)(-1);
+    const unsigned char* ptr = *pptr;
+
+    if ((*ptr & 0x80) == 0x00)
+        res = (unsigned)(*ptr++);
+    else if ((*ptr & 0xC0) == 0x80)
+    {
+        res = (unsigned)((*ptr++ & 0x3f) << 8);
+        res |= *ptr++;
+    }
+    else if ((*ptr & 0xE0) == 0xC0)
+    {
+        res = (*ptr++ & 0x1f) << 24;
+        res |= *ptr++ << 16;
+        res |= *ptr++ << 8;
+        res |= *ptr++;
+    }
+    else res = (unsigned)(-1);
+    *pptr = ptr;
+    return res;
+}
+
+struct cv_binannot
+{
+    const unsigned char* annot; /* current pointer */
+    const unsigned char* last_annot; /* end of binary annotation stream (first byte after) */
+    unsigned opcode; /* last decoded opcode */
+    unsigned arg1, arg2;
+};
+
+static BOOL codeview_advance_binannot(struct cv_binannot* cvba)
+{
+    if (cvba->annot >= cvba->last_annot) return FALSE;
+    cvba->opcode = codeview_binannot_uncompress(&cvba->annot);
+    if (cvba->opcode <= BA_OP_Invalid || cvba->opcode > BA_OP_ChangeColumnEnd) return FALSE;
+    if (cvba->annot >= cvba->last_annot) return FALSE;
+    cvba->arg1 = codeview_binannot_uncompress(&cvba->annot);
+    if (cvba->opcode == BA_OP_ChangeCodeOffsetAndLineOffset)
+    {
+        cvba->arg2 = cvba->arg1 >> 4;
+        cvba->arg1 &= 0x0F;
+    }
+    else if (cvba->opcode == BA_OP_ChangeCodeLengthAndCodeOffset)
+    {
+        if (cvba->annot >= cvba->last_annot) return FALSE;
+        cvba->arg2 = codeview_binannot_uncompress(&cvba->annot);
+    }
+    else cvba->arg2 = 0;
+    return TRUE;
+}
+
+static struct symt_inlinesite* codeview_create_inline_site(const struct msc_debug_info* msc_dbg,
+                                                           const struct cv_module_snarf* cvmod,
+                                                           struct symt_function* top_func,
+                                                           struct symt* container,
+                                                           cv_itemid_t inlinee,
+                                                           const unsigned char* annot,
+                                                           const unsigned char* last_annot)
+{
+    const struct CV_DebugSSubsectionHeader_t* hdr_files = NULL;
+    const union codeview_type* cvt;
+    DWORD64 addr;
+    struct symt_inlinesite* inlined;
+    struct cv_binannot cvba;
+    BOOL found = FALSE;
+    unsigned first, offset, length;
+
+    if (!cvmod->ipi_ctp || !(cvt = codeview_jump_to_type(cvmod->ipi_ctp, inlinee)))
+    {
+        FIXME("Couldn't find type %x in IPI stream\n", inlinee);
+        return NULL;
+    }
+
+    addr = top_func->address;
+    /* grasp first code offset in binary annotation to compute inline site start address */
+    cvba.annot = annot;
+    cvba.last_annot = last_annot;
+    while (codeview_advance_binannot(&cvba))
+        if (cvba.opcode == BA_OP_CodeOffset ||
+            cvba.opcode == BA_OP_ChangeCodeOffset ||
+            cvba.opcode == BA_OP_ChangeCodeOffsetAndLineOffset)
+        {
+            addr += first = cvba.arg1;
+            length = 0;
+            found = TRUE;
+            break;
+        }
+        else if (cvba.opcode == BA_OP_ChangeCodeLengthAndCodeOffset)
+        {
+            addr += first = cvba.arg2;
+            length = cvba.arg1;
+            found = TRUE;
+            break;
+        }
+    offset = first;
+
+    if (!found)
+    {
+        FIXME("Couldn't find start address of inlined\n");
+        return NULL;
+    }
+
+    switch (cvt->generic.id)
+    {
+    case LF_FUNC_ID:
+        inlined = symt_new_inlinesite(msc_dbg->module, top_func, container,
+                                      cvt->func_id_v3.name, addr,
+                                      codeview_get_type(cvt->func_id_v3.type, FALSE));
+        break;
+    case LF_MFUNC_ID:
+        /* FIXME we just declare a function, not a method */
+        inlined = symt_new_inlinesite(msc_dbg->module, top_func, container,
+                                      cvt->mfunc_id_v3.name, addr,
+                                      codeview_get_type(cvt->mfunc_id_v3.type, FALSE));
+        break;
+    default:
+        FIXME("unsupported inlinee kind %x\n", cvt->generic.id);
+        return NULL;
+    }
+
+    for (hdr_files = cvmod->dbgsubsect;
+         CV_IS_INSIDE(hdr_files, cvmod->dbgsubsect + cvmod->dbgsubsect_size);
+         hdr_files = CV_RECORD_GAP(hdr_files, hdr_files->cbLen))
+    {
+        if (hdr_files->type == DEBUG_S_FILECHKSMS)
+            break;
+    }
+    if (!hdr_files) return FALSE;
+
+    for (;;)
+    {
+        if (!codeview_advance_binannot(&cvba)) break;
+        switch (cvba.opcode)
+        {
+        case BA_OP_CodeOffset:
+            first = offset = cvba.arg1;
+            length = 1;
+            break;
+        case BA_OP_ChangeCodeOffset:
+            offset += cvba.arg1;
+            length = 1;
+            break;
+        case BA_OP_ChangeCodeLength:
+            length = cvba.arg1;
+            break;
+        case BA_OP_ChangeFile:
+            break;
+        case BA_OP_ChangeLineOffset:
+            break;
+        case BA_OP_ChangeCodeOffsetAndLineOffset:
+            offset += cvba.arg1;
+            length = 1;
+            break;
+        case BA_OP_ChangeCodeLengthAndCodeOffset:
+            offset += cvba.arg2;
+            length = cvba.arg1;
+            break;
+        default:
+            WARN("Unsupported op %d\n", cvba.opcode);
+            break;
+        }
+    }
+    symt_add_inlinesite_range(msc_dbg->module, inlined, top_func->address + first, top_func->address + offset + length);
+    return inlined;
+}
+
 static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
                            const BYTE* root, unsigned offset, unsigned size,
                            const struct cv_module_snarf* cvmod,
                            BOOL do_globals)
 {
+    struct symt_function*               top_func = NULL;
     struct symt_function*               curr_func = NULL;
     int                                 i, length;
     struct symt_block*                  block = NULL;
@@ -1869,12 +2038,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
          */
 	case S_GPROC32_16t:
 	case S_LPROC32_16t:
-            if (curr_func) FIXME("nested function\n");
-            curr_func = symt_new_function(msc_dbg->module, compiland,
-                                          terminate_string(&sym->proc_v1.p_name),
-                                          codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset),
-                                          sym->proc_v1.proc_len,
-                                          codeview_get_type(sym->proc_v1.proctype, FALSE));
+            if (top_func) FIXME("nested function\n");
+            top_func = symt_new_function(msc_dbg->module, compiland,
+                                         terminate_string(&sym->proc_v1.p_name),
+                                         codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset),
+                                         sym->proc_v1.proc_len,
+                                         codeview_get_type(sym->proc_v1.proctype, FALSE));
+            curr_func = top_func;
             loc.kind = loc_absolute;
             loc.offset = sym->proc_v1.debug_start;
             symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
@@ -1883,12 +2053,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
 	    break;
 	case S_GPROC32_ST:
 	case S_LPROC32_ST:
-            if (curr_func) FIXME("nested function\n");
-            curr_func = symt_new_function(msc_dbg->module, compiland,
-                                          terminate_string(&sym->proc_v2.p_name),
-                                          codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset),
-                                          sym->proc_v2.proc_len,
-                                          codeview_get_type(sym->proc_v2.proctype, FALSE));
+            if (top_func) FIXME("nested function\n");
+            top_func = symt_new_function(msc_dbg->module, compiland,
+                                         terminate_string(&sym->proc_v2.p_name),
+                                         codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset),
+                                         sym->proc_v2.proc_len,
+                                         codeview_get_type(sym->proc_v2.proctype, FALSE));
+            curr_func = top_func;
             loc.kind = loc_absolute;
             loc.offset = sym->proc_v2.debug_start;
             symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
@@ -1897,12 +2068,13 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
 	    break;
 	case S_GPROC32:
 	case S_LPROC32:
-            if (curr_func) FIXME("nested function\n");
-            curr_func = symt_new_function(msc_dbg->module, compiland,
-                                          sym->proc_v3.name,
-                                          codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset),
-                                          sym->proc_v3.proc_len,
-                                          codeview_get_type(sym->proc_v3.proctype, FALSE));
+            if (top_func) FIXME("nested function\n");
+            top_func = symt_new_function(msc_dbg->module, compiland,
+                                         sym->proc_v3.name,
+                                         codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset),
+                                         sym->proc_v3.proc_len,
+                                         codeview_get_type(sym->proc_v3.proctype, FALSE));
+            curr_func = top_func;
             loc.kind = loc_absolute;
             loc.offset = sym->proc_v3.debug_start;
             symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
@@ -2007,9 +2179,10 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
             {
                 block = symt_close_func_block(msc_dbg->module, curr_func, block, 0);
             }
-            else if (curr_func)
+            else if (top_func)
             {
-                curr_func = NULL;
+                if (curr_func != top_func) FIXME("shouldn't close a top function with an opened inlined function\n");
+                top_func = curr_func = NULL;
             }
             break;
 
@@ -2164,6 +2337,54 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
                                 codeview_get_type(sym->local_v3.symtype, FALSE),
                                 sym->local_v3.name);
             break;
+        case S_INLINESITE:
+            {
+                struct symt_inlinesite* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func,
+                                                                              block ? &block->symt : &curr_func->symt,
+                                                                              sym->inline_site_v3.inlinee,
+                                                                              sym->inline_site_v3.binaryAnnotations,
+                                                                              (const unsigned char*)sym + length);
+                if (inlined)
+                {
+                    curr_func = (struct symt_function*)inlined;
+                    block = NULL;
+                }
+                else
+                {
+                    /* skip all records until paired S_INLINESITE_END */
+                    sym = (const union codeview_symbol*)(root + sym->inline_site_v3.pEnd);
+                    if (sym->generic.id != S_INLINESITE_END) FIXME("complete wreckage\n");
+                    length = sym->inline_site_v3.pEnd - i + sym->generic.len;
+                }
+            }
+            break;
+        case S_INLINESITE2:
+            {
+                struct symt_inlinesite* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func,
+                                                                              block ? &block->symt : &curr_func->symt,
+                                                                              sym->inline_site2_v3.inlinee,
+                                                                              sym->inline_site2_v3.binaryAnnotations,
+                                                                              (const unsigned char*)sym + length);
+                if (inlined)
+                {
+                    curr_func = (struct symt_function*)inlined;
+                    block = NULL;
+                }
+                else
+                {
+                    /* skip all records until paired S_INLINESITE_END */
+                    sym = (const union codeview_symbol*)(root + sym->inline_site2_v3.pEnd);
+                    if (sym->generic.id != S_INLINESITE_END) FIXME("complete wreckage\n");
+                    length = sym->inline_site_v3.pEnd - i + sym->generic.len;
+                }
+            }
+            break;
+
+        case S_INLINESITE_END:
+            block = symt_check_tag(curr_func->container, SymTagBlock) ?
+                (struct symt_block*)curr_func->container : NULL;
+            curr_func = (struct symt_function*)symt_get_upper_inlined((struct symt_inlinesite*)curr_func);
+            break;
 
          /*
          * These are special, in that they are always followed by an
@@ -2213,8 +2434,6 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg,
         case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
         case S_DEFRANGE_REGISTER_REL:
         case S_BUILDINFO:
-        case S_INLINESITE:
-        case S_INLINESITE_END:
         case S_FILESTATIC:
         case S_CALLEES:
         case S_UNAMESPACE:




More information about the wine-devel mailing list