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@gmail.com
--- programs/winedbg/debugger.h | 2 programs/winedbg/types.c | 192 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 188 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..6b3fb0c9572 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,166 @@ 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_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); +}