[PATCH 12/17] programs/winedbg: add helper to compare types and use it to detect wrong assigments

Eric Pouech eric.pouech at gmail.com
Tue Dec 7 11:46:27 CST 2021


DbgHelp exposes in SymGetTypeInfo() requests for testing type equivalence,
but native implementation is more than broken.
So don't rely on DbgHelp (in sake of portability) and keep implementation
inside debugger instead.

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

---
 programs/winedbg/debugger.h |    2 +
 programs/winedbg/types.c    |  164 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 160 insertions(+), 6 deletions(-)

diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index 2e316548511..35829e83f96 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -493,6 +493,8 @@ extern BOOL             types_get_info(const struct dbg_type*, IMAGEHLP_SYMBOL_T
 extern BOOL             types_get_real_type(struct dbg_type* type, DWORD* tag);
 extern struct dbg_type  types_find_pointer(const struct dbg_type* type);
 extern struct dbg_type  types_find_type(DWORD64 linear, const char* name, enum SymTagEnum tag);
+extern BOOL             types_compare(const struct dbg_type, const struct dbg_type, BOOL* equal);
+extern BOOL             types_is_integral_type(const struct dbg_lvalue*);
 
   /* winedbg.c */
 extern void	        dbg_outputW(const WCHAR* buffer, int len);
diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c
index 8f16a535606..2d7bce5de7e 100644
--- a/programs/winedbg/types.c
+++ b/programs/winedbg/types.c
@@ -164,16 +164,33 @@ BOOL types_store_value(struct dbg_lvalue* lvalue_to, const struct dbg_lvalue* lv
 {
     dbg_lgint_t val;
     DWORD64     size;
+    BOOL        equal;
 
-    if (!types_get_info(&lvalue_to->type, TI_GET_LENGTH, &size)) return FALSE;
-    if (sizeof(val) < size)
+    if (!lvalue_to->bitlen && !lvalue_from->bitlen)
     {
-        dbg_printf("Insufficient size\n");
-        return FALSE;
+        if (!types_compare(lvalue_to->type, lvalue_from->type, &equal)) return FALSE;
+        if (equal)
+        {
+            if (!types_get_info(&lvalue_to->type, TI_GET_LENGTH, &size)) return FALSE;
+            if (sizeof(val) < size)
+            {
+                return memory_read_value(lvalue_from, size, &val) &&
+                    memory_write_value(lvalue_to, size, &val);
+            }
+            dbg_printf("NIY\n");
+            /* else: should allocate intermediate buffer... */
+            return FALSE;
+        }
+    }
+    if (types_is_integral_type(lvalue_from) && types_is_integral_type(lvalue_to))
+    {
+        /* doing integer conversion (about sign, size) */
+        val = types_extract_as_integer(lvalue_from);
+        return memory_store_integer(lvalue_to, val);
     }
     /* FIXME: should support floats as well */
-    val = types_extract_as_integer(lvalue_from);
-    return memory_store_integer(lvalue_to, val);
+    dbg_printf("Cannot assign (different types)\n"); return FALSE;
+    return FALSE;
 }
 
 /******************************************************************
@@ -910,3 +927,138 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v
 #undef X
     return TRUE;
 }
+
+BOOL types_compare(struct dbg_type type1, struct dbg_type type2, BOOL* equal);
+
+static BOOL types_compare_children(struct dbg_type type1, struct dbg_type type2, BOOL* equal)
+{
+    DWORD count1, count2, i;
+    DWORD* children;
+    BOOL ret = FALSE;
+    if (!types_get_info(&type1, TI_GET_CHILDRENCOUNT, &count1) ||
+        !types_get_info(&type2, TI_GET_CHILDRENCOUNT, &count2)) return FALSE;
+    if (count1 != count2) {*equal = FALSE; return TRUE;}
+    if ((children = malloc(sizeof(*children) * 2 * count1)) == NULL) return FALSE;
+    if (types_get_info(&type1, TI_FINDCHILDREN, &children[0]) &&
+        types_get_info(&type2, TI_FINDCHILDREN, &children[count1]))
+    {
+        for (i = 0; i < count1; ++i)
+        {
+            type1.id = children[i];
+            type2.id = children[count1 + i];
+            if (!types_compare(type1, type2, equal)) return FALSE;
+            if (!*equal) return TRUE;
+        }
+        ret = *equal = TRUE;
+    }
+    else ret = FALSE;
+    free(children);
+    return ret;
+}
+
+BOOL types_compare(struct dbg_type type1, struct dbg_type type2, BOOL* equal)
+{
+    DWORD           tag1, tag2;
+    DWORD64         size1, size2;
+    DWORD           bt1, bt2;
+    LPWSTR          name1, name2;
+    DWORD           count1, count2;
+
+    do
+    {
+        if (type1.module == type2.module && type1.id == type2.id)
+            return *equal = TRUE;
+
+        if (!types_get_real_type(&type1, &tag1) ||
+            !types_get_real_type(&type2, &tag2)) return FALSE;
+
+        if (type1.module == type2.module && type1.id == type2.id)
+            return *equal = TRUE;
+
+        if (tag1 != tag2) return !(*equal = FALSE);
+
+        switch (tag1)
+        {
+        case SymTagBaseType:
+            if (!types_get_info(&type1, TI_GET_BASETYPE, &bt1) ||
+                !types_get_info(&type2, TI_GET_BASETYPE, &bt2) ||
+                !types_get_info(&type1, TI_GET_LENGTH,   &size1) ||
+                !types_get_info(&type2, TI_GET_LENGTH,   &size2))
+                return FALSE;
+            *equal = bt1 == bt2 && size1 == size2;
+            return TRUE;
+        case SymTagPointerType:
+            /* compare sub types */
+            break;
+        case SymTagUDT:
+        case SymTagEnum:
+            if (!types_get_info(&type1, TI_GET_CHILDRENCOUNT, &count1) ||
+                !types_get_info(&type2, TI_GET_CHILDRENCOUNT, &count2)) return FALSE;
+            if (count1 != count2) return !(*equal = FALSE);
+            *equal = FALSE;
+            if (types_get_info(&type1, TI_GET_SYMNAME, &name1))
+            {
+                if (types_get_info(&type2, TI_GET_SYMNAME, &name2))
+                {
+                    if (!wcscmp(name1, name2))
+                        *equal = TRUE;
+                    HeapFree(GetProcessHeap(), 0, name2);
+                }
+                HeapFree(GetProcessHeap(), 0, name1);
+            }
+            /* we would need to compare each field or value, but that's too complicated for now */
+            if (tag1 == SymTagUDT) return TRUE;
+            /* compare underlying type for enums */
+            break;
+        case SymTagArrayType:
+            if (!types_get_info(&type1, TI_GET_LENGTH, &size1) ||
+                !types_get_info(&type2, TI_GET_LENGTH, &size2) ||
+                !types_get_info(&type1, TI_GET_COUNT,  &count1) ||
+                !types_get_info(&type2, TI_GET_COUNT,  &count2)) return FALSE;
+            if (size1 == size2 && count1 == count2)
+            {
+                struct dbg_type subtype1 = type1, subtype2 = type2;
+                if (!types_get_info(&type1, TI_GET_ARRAYINDEXTYPEID, &subtype1.id) ||
+                    !types_get_info(&type2, TI_GET_ARRAYINDEXTYPEID, &subtype2.id)) return FALSE;
+                if (!types_compare(subtype1, subtype2, equal)) return FALSE;
+                if (!*equal) return TRUE;
+            }
+            else return !(*equal = FALSE);
+            /* compare subtypes */
+            break;
+        case SymTagFunctionType:
+            if (!types_compare_children(type1, type2, equal)) return FALSE;
+            if (!*equal) return TRUE;
+            /* compare return:ed type */
+            break;
+        case SymTagFunctionArgType:
+            /* compare argument type */
+            break;
+        default:
+            dbg_printf("Unsupported yet tag %d\n", tag1);
+            return FALSE;
+        }
+    } while (types_get_info(&type1, TI_GET_TYPE, &type1.id) &&
+             types_get_info(&type2, TI_GET_TYPE, &type2.id));
+    return FALSE;
+}
+
+static BOOL is_basetype_char(DWORD bt)
+{
+    return bt == btChar || bt == btWChar || bt == btChar8 || bt == btChar16 || bt == btChar32;
+}
+
+static BOOL is_basetype_integer(DWORD bt)
+{
+    return is_basetype_char(bt) || bt == btInt || bt == btUInt || bt == btLong || bt == btULong;
+}
+
+BOOL types_is_integral_type(const struct dbg_lvalue* lv)
+{
+    struct dbg_type type = lv->type;
+    DWORD tag, bt;
+    if (lv->bitlen) return TRUE;
+    if (!types_get_real_type(&type, &tag) ||
+        !types_get_info(&type, TI_GET_BASETYPE, &bt)) return FALSE;
+    return is_basetype_integer(bt);
+}




More information about the wine-devel mailing list