[PATCH 15/19] programs/winedbg: cache pointer type:s
Eric Pouech
eric.pouech at gmail.com
Wed Dec 8 07:45:08 CST 2021
this doesn't require searching debuggee's type when taking address of an
expression
not to mention, this search could also fail
Signed-off-by: Eric Pouech <eric.pouech at gmail.com>
---
programs/winedbg/debugger.h | 6 ++
programs/winedbg/expr.c | 17 ++---
programs/winedbg/types.c | 135 +++++++++++++++++++++++++++----------------
programs/winedbg/winedbg.c | 3 +
4 files changed, 99 insertions(+), 62 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index f74ddfc210f..a29b731017f 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -67,6 +67,7 @@ enum dbg_line_status
enum dbg_internal_types
{
+ dbg_itype_pointers = 0xf0000000,
dbg_itype_first = 0xffffff00,
dbg_itype_unsigned_int,
dbg_itype_signed_int,
@@ -265,6 +266,8 @@ struct dbg_process
char source_current_file[MAX_PATH];
int source_start_line;
int source_end_line;
+ struct dbg_type* pointers_type;
+ unsigned num_pointers_type;
};
/* describes the way the debugger interacts with a given process */
@@ -493,8 +496,9 @@ extern BOOL types_store_value(struct dbg_lvalue* lvalue_to, const st
extern BOOL types_udt_find_element(struct dbg_lvalue* value, const char* name);
extern BOOL types_array_index(const struct dbg_lvalue* value, int index, struct dbg_lvalue* result);
extern BOOL types_get_info(const struct dbg_type*, IMAGEHLP_SYMBOL_TYPE_INFO, void*);
+extern BOOL types_get_type(const struct dbg_type*, struct dbg_type* ret);
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 BOOL types_find_pointer(const struct dbg_type* type, struct dbg_type* pttype);
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*);
diff --git a/programs/winedbg/expr.c b/programs/winedbg/expr.c
index 5d9ef30ad13..bd48e3e868f 100644
--- a/programs/winedbg/expr.c
+++ b/programs/winedbg/expr.c
@@ -325,8 +325,7 @@ struct dbg_lvalue expr_eval(struct expr* exp)
}
for (i = 0; i < exp->un.cast.cast_to.deref_count; i++)
{
- rtn.type = types_find_pointer(&rtn.type);
- if (rtn.type.id == dbg_itype_none)
+ if (!types_find_pointer(&rtn.type, &rtn.type))
{
dbg_printf("Cannot find pointer type\n");
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
@@ -442,8 +441,7 @@ struct dbg_lvalue expr_eval(struct expr* exp)
#endif
init_lvalue_in_debugger(&rtn, dbg_itype_none, &exp->un.call.result);
/* get return type from function signature type */
- /* FIXME rtn.type.module should be set to function's module... */
- types_get_info(&rtn.type, TI_GET_TYPE, &rtn.type.id);
+ types_get_type(&rtn.type, &rtn.type);
break;
case EXPR_TYPE_INTVAR:
if (!(div = dbg_get_internal_var(exp->un.intvar.name)))
@@ -463,11 +461,11 @@ struct dbg_lvalue expr_eval(struct expr* exp)
case EXP_OP_ADD:
if (!types_get_info(&exp1.type, TI_GET_SYMTAG, &tag) ||
tag != SymTagPointerType ||
- !types_get_info(&exp1.type, TI_GET_TYPE, &type1.id))
+ !types_get_type(&exp1.type, &type1))
type1.id = dbg_itype_none;
if (!types_get_info(&exp2.type, TI_GET_SYMTAG, &tag) ||
tag != SymTagPointerType ||
- !types_get_info(&exp2.type, TI_GET_TYPE, &type2.id))
+ !types_get_type(&exp2.type, &type2))
type2.id = dbg_itype_none;
scale1 = 1;
scale2 = 1;
@@ -489,11 +487,11 @@ struct dbg_lvalue expr_eval(struct expr* exp)
case EXP_OP_SUB:
if (!types_get_info(&exp1.type, TI_GET_SYMTAG, &tag) ||
tag != SymTagPointerType ||
- !types_get_info(&exp1.type, TI_GET_TYPE, &type1.id))
+ !types_get_type(&exp1.type, &type1))
type1.id = dbg_itype_none;
if (!types_get_info(&exp2.type, TI_GET_SYMTAG, &tag) ||
tag != SymTagPointerType ||
- !types_get_info(&exp2.type, TI_GET_TYPE, &type2.id))
+ !types_get_type(&exp2.type, &type2))
type2.id = dbg_itype_none;
scale1 = 1;
scale2 = 1;
@@ -610,8 +608,7 @@ struct dbg_lvalue expr_eval(struct expr* exp)
if (exp1.addr.Mode != AddrModeFlat)
RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL);
exp->un.unop.result = (ULONG_PTR)memory_to_linear_addr(&exp1.addr);
- rtn.type = types_find_pointer(&exp1.type);
- if (rtn.type.id == dbg_itype_none)
+ if (!types_find_pointer(&exp1.type, &rtn.type))
RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL);
break;
default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c
index 3aefbe03058..5633201d2fe 100644
--- a/programs/winedbg/types.c
+++ b/programs/winedbg/types.c
@@ -42,7 +42,7 @@ BOOL types_get_real_type(struct dbg_type* type, DWORD* tag)
if (!types_get_info(type, TI_GET_SYMTAG, tag))
return FALSE;
if (*tag != SymTagTypedef) return TRUE;
- } while (types_get_info(type, TI_GET_TYPE, &type->id));
+ } while (types_get_type(type, type));
return FALSE;
}
@@ -195,9 +195,8 @@ static BOOL types_get_udt_element_lvalue(struct dbg_lvalue* lvalue, const struct
DWORD offset, bitoffset;
DWORD64 length;
- types_get_info(type, TI_GET_TYPE, &lvalue->type.id);
- lvalue->type.module = type->module;
- if (!types_get_info(type, TI_GET_OFFSET, &offset)) return FALSE;
+ if (!types_get_type(type, &lvalue->type) ||
+ !types_get_info(type, TI_GET_OFFSET, &offset)) return FALSE;
lvalue->addr.Offset += offset;
if (types_get_info(type, TI_GET_BITPOSITION, &bitoffset))
@@ -301,8 +300,7 @@ BOOL types_array_index(const struct dbg_lvalue* lvalue, int index, struct dbg_lv
/*
* Get the base type, so we know how much to index by.
*/
- if (!types_get_info(&type, TI_GET_TYPE, &result->type.id)) return FALSE;
- result->type.module = type.module;
+ if (!types_get_type(&type, &result->type)) return FALSE;
if (index)
{
DWORD64 length;
@@ -341,8 +339,6 @@ static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
{
struct type_find_t* user = _user;
BOOL ret = TRUE;
- struct dbg_type type;
- DWORD type_id;
if (sym->Tag == user->tag)
{
@@ -355,15 +351,6 @@ static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
ret = FALSE;
}
break;
- case SymTagPointerType:
- type.module = sym->ModBase;
- type.id = sym->TypeIndex;
- if (types_get_info(&type, TI_GET_TYPE, &type_id) && type_id == user->u.typeid)
- {
- user->result = sym->TypeIndex;
- ret = FALSE;
- }
- break;
default: break;
}
}
@@ -373,21 +360,40 @@ static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
/******************************************************************
* types_find_pointer
*
- * Should look up in module based at linear whether (typeid*) exists
- * Otherwise, we could create it locally
+ * There's no way in dbghelp for looking up the pointer type of a given type
+ * - SymEnumTypes would do, but it'll enumerate all types, which could be long
+ * - but more impacting, there's no guarantee such a type exists
+ * Hence, we create a cache of all needed pointer types.
+ * That's cumbersome as we end up with dbg_type in different modules (types_get_type()
+ * must be used for querying TI_GET_TYPE instead of types_get_info).
*/
-struct dbg_type types_find_pointer(const struct dbg_type* type)
+BOOL types_find_pointer(const struct dbg_type* type, struct dbg_type* ret)
{
- struct type_find_t f;
- struct dbg_type ret;
+ unsigned i;
+ struct dbg_type* new;
- f.result = dbg_itype_none;
- f.tag = SymTagPointerType;
- f.u.typeid = type->id;
- SymEnumTypes(dbg_curr_process->handle, type->module, types_cb, &f);
- ret.module = type->module;
- ret.id = f.result;
- return ret;
+ if (!dbg_curr_process) return FALSE;
+ for (i = 0; i < dbg_curr_process->num_pointers_type; i++)
+ if (!memcmp(type, &dbg_curr_process->pointers_type[i], sizeof(*type)))
+ {
+ ret->module = 0;
+ ret->id = dbg_itype_pointers + i;
+ return TRUE;
+ }
+ if (dbg_itype_pointers + dbg_curr_process->num_pointers_type >= dbg_itype_first)
+ {
+ FIXME("overflow in pointer types\n");
+ return FALSE;
+ }
+ new = dbg_heap_realloc(dbg_curr_process->pointers_type, (dbg_curr_process->num_pointers_type + 1) * sizeof(*new));
+ if (!new) return FALSE;
+ dbg_curr_process->pointers_type = new;
+ dbg_curr_process->pointers_type[dbg_curr_process->num_pointers_type] = *type;
+ ret->module = 0;
+ ret->id = dbg_itype_pointers + dbg_curr_process->num_pointers_type;
+ dbg_curr_process->num_pointers_type++;
+
+ return TRUE;
}
/******************************************************************
@@ -498,7 +504,7 @@ void print_value(const struct dbg_lvalue* lvalue, char format, int level)
types_get_info(&type, TI_GET_COUNT, &count);
types_get_info(&type, TI_GET_LENGTH, &size);
lvalue_field = *lvalue;
- types_get_info(&lvalue_field.type, TI_GET_TYPE, &lvalue_field.type.id);
+ types_get_type(&lvalue_field.type, &lvalue_field.type);
types_get_real_type(&lvalue_field.type, &tag);
if (size == count && tag == SymTagBaseType)
@@ -536,7 +542,7 @@ void print_value(const struct dbg_lvalue* lvalue, char format, int level)
break;
case SymTagTypedef:
lvalue_field = *lvalue;
- types_get_info(&lvalue->type, TI_GET_TYPE, &lvalue_field.type.id);
+ types_get_type(&lvalue->type, &lvalue_field.type);
print_value(&lvalue_field, format, level);
break;
default:
@@ -598,8 +604,7 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
if (details) dbg_printf("Basic<%ls>", name); else dbg_printf("%ls", name);
break;
case SymTagPointerType:
- types_get_info(type, TI_GET_TYPE, &subtype.id);
- subtype.module = type->module;
+ types_get_type(type, &subtype);
types_print_type(&subtype, FALSE);
dbg_printf("*");
break;
@@ -635,7 +640,7 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
if (!types_get_info(&type_elt, TI_GET_SYMNAME, &ptr) || !ptr) continue;
dbg_printf("%ls", ptr);
HeapFree(GetProcessHeap(), 0, ptr);
- if (types_get_info(&type_elt, TI_GET_TYPE, &type_elt.id))
+ if (types_get_type(&type_elt, &type_elt))
{
dbg_printf(":");
types_print_type(&type_elt, details);
@@ -650,8 +655,7 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
}
break;
case SymTagArrayType:
- types_get_info(type, TI_GET_TYPE, &subtype.id);
- subtype.module = type->module;
+ types_get_type(type, &subtype);
types_print_type(&subtype, details);
if (types_get_info(type, TI_GET_COUNT, &count))
dbg_printf(" %ls[%d]", name, count);
@@ -662,17 +666,12 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
dbg_printf("enum %ls", name);
break;
case SymTagFunctionType:
- types_get_info(type, TI_GET_TYPE, &subtype.id);
- /* is the returned type the same object as function sig itself ? */
- if (subtype.id != type->id)
+ if (types_get_type(type, &subtype))
{
- subtype.module = type->module;
- types_print_type(&subtype, FALSE);
- }
- else
- {
- subtype.module = 0;
- dbg_printf("<ret_type=self>");
+ if (memcmp(type, &subtype, sizeof(subtype)))
+ types_print_type(&subtype, FALSE);
+ else
+ dbg_printf("<ret_type=self>");
}
dbg_printf(" (*%ls)(", name);
if (types_get_info(type, TI_GET_CHILDRENCOUNT, &count))
@@ -691,7 +690,7 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
for (i = 0; i < min(fcp->Count, count); i++)
{
subtype.id = fcp->ChildId[i];
- types_get_info(&subtype, TI_GET_TYPE, &subtype.id);
+ types_get_type(&subtype, &subtype);
types_print_type(&subtype, FALSE);
if (i < min(fcp->Count, count) - 1 || count > 256) dbg_printf(", ");
}
@@ -717,6 +716,9 @@ BOOL types_print_type(const struct dbg_type* type, BOOL details)
/* helper to typecast pInfo to its expected type (_t) */
#define X(_t) (*((_t*)pInfo))
+/* wrapper to SymGetInfo, including also: support for internal types
+ * use types_get_type() rather than this function for TI_GET_TYPE request
+ */
BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, void* pInfo)
{
if (type->id == dbg_itype_none) return FALSE;
@@ -756,6 +758,20 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v
return ret;
}
+ if (type->id >= dbg_itype_pointers && type->id < dbg_itype_first)
+ {
+ unsigned i = type->id - dbg_itype_pointers;
+ if (i >= dbg_curr_process->num_pointers_type) return FALSE;
+ switch (ti)
+ {
+ case TI_GET_SYMTAG: X(DWORD) = SymTagPointerType; break;
+ case TI_GET_LENGTH: X(DWORD64) = ADDRSIZE; break;
+ case TI_GET_TYPE: WINE_FIXME("Should use types_get_type() instead\n"); break;
+ default: WINE_FIXME("unsupported %u for pointer type %d\n", ti, i); return FALSE;
+ }
+ return TRUE;
+ }
+
assert(type->id >= dbg_itype_first);
switch (type->id)
@@ -920,6 +936,24 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v
return TRUE;
}
+/* one shouldn't call TI_GET_TYPE in symt_get_info() as cached pointer info won't be properly supported
+ * this function should be used instead
+ * (type and ret could point to the same structure)
+ */
+BOOL types_get_type(const struct dbg_type* type, struct dbg_type* ret)
+{
+ if (type->module == 0 && type->id >= dbg_itype_pointers && type->id < dbg_itype_first)
+ {
+ unsigned i = type->id - dbg_itype_pointers;
+ if (i >= dbg_curr_process->num_pointers_type) return FALSE;
+ *ret = dbg_curr_process->pointers_type[i];
+ return TRUE;
+ }
+ if (!types_get_info(type, TI_GET_TYPE, &ret->id)) return FALSE;
+ ret->module = type->module;
+ 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)
@@ -969,8 +1003,7 @@ static BOOL types_compare_children(struct dbg_type type1, struct dbg_type type2,
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);
+ ret = types_get_type(&type1, &type1) && types_get_type(&type2, &type2);
if (ret) ret = types_compare(type1, type2, equal);
/* FIXME should compare bitfield info when present */
}
@@ -1058,8 +1091,8 @@ BOOL types_compare(struct dbg_type type1, struct dbg_type type2, BOOL* equal)
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));
+ } while (types_get_type(&type1, &type1) &&
+ types_get_type(&type2, &type2));
return FALSE;
}
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index dab5fbd85a3..a152ea8a2c8 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -313,6 +313,8 @@ struct dbg_process* dbg_add_process(const struct be_process_io* pio, DWORD pid,
p->source_current_file[0] = '\0';
p->source_start_line = -1;
p->source_end_line = -1;
+ p->pointers_type = NULL;
+ p->num_pointers_type = 0;
list_add_head(&dbg_process_list, &p->entry);
@@ -362,6 +364,7 @@ void dbg_del_process(struct dbg_process* p)
if (p == dbg_curr_process) dbg_curr_process = NULL;
if (p->event_on_first_exception) CloseHandle(p->event_on_first_exception);
HeapFree(GetProcessHeap(), 0, (char*)p->imageName);
+ HeapFree(GetProcessHeap(), 0, p->pointers_type);
HeapFree(GetProcessHeap(), 0, p);
}
More information about the wine-devel
mailing list