Module: wine Branch: master Commit: c4548c04eb8e1e7e94b10ad42b59831f6687f4f8 URL: https://source.winehq.org/git/wine.git/?a=commit;h=c4548c04eb8e1e7e94b10ad42...
Author: Eric Pouech eric.pouech@gmail.com Date: Wed Dec 8 14:44:21 2021 +0100
winedbg: Add helper to compare types and use it to detect wrong assigments.
Signed-off-by: Eric Pouech eric.pouech@gmail.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
programs/winedbg/debugger.h | 2 + programs/winedbg/types.c | 190 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 186 insertions(+), 6 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index cd7a723f176..1d08c0e1262 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..1fafaac8c80 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,164 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v #undef X return TRUE; } + +static BOOL types_compare_name(struct dbg_type type1, struct dbg_type type2, BOOL* equal) +{ + LPWSTR name1, name2; + BOOL ret; + + if (types_get_info(&type1, TI_GET_SYMNAME, &name1)) + { + if (types_get_info(&type2, TI_GET_SYMNAME, &name2)) + { + *equal = !wcscmp(name1, name2); + ret = TRUE; + HeapFree(GetProcessHeap(), 0, name2); + } + else ret = FALSE; + HeapFree(GetProcessHeap(), 0, name1); + } + else ret = FALSE; + return ret; +} + +static BOOL types_compare_children(struct dbg_type type1, struct dbg_type type2, BOOL* equal, DWORD tag) +{ + DWORD count1, count2, i; + DWORD* children; + BOOL ret; + + 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 (!count1) return *equal = 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]; + switch (tag) + { + case SymTagFunctionType: ret = types_compare(type1, type2, equal); break; + case SymTagUDT: + /* each child is a SymTagData that describes the member */ + ret = types_compare_name(type1, type2, equal); + if (ret && *equal) + { + /* compare type of member */ + ret = types_get_info(&type1, TI_GET_TYPE, &type1.id) && + types_get_info(&type2, TI_GET_TYPE, &type2.id); + if (ret) ret = types_compare(type1, type2, equal); + /* FIXME should compare bitfield info when present */ + } + break; + default: ret = FALSE; break; + } + if (!ret || !*equal) break; + } + if (i == count1) 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; + DWORD count1, count2; + BOOL ret; + + 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: + ret = types_compare_name(type1, type2, equal); + if (!ret || !*equal) return ret; + ret = types_compare_children(type1, type2, equal, tag1); + if (!ret || !*equal) return ret; + 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, tag1)) 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); +}