winedbg: Added support for function parameters passed in registers.
Added correct stabs parsing for function parameters in registers. Added a couple of helper functions to make code smaller and more readable.
This commit is contained in:
parent
dccd41a88a
commit
2ce5eca6a5
|
@ -2,7 +2,7 @@
|
|||
* File stabs.c - read stabs information from the modules
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* 1999-2004, Eric Pouech
|
||||
* 1999-2005, Eric Pouech
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -1092,6 +1092,48 @@ struct pending_loc_var
|
|||
unsigned regno;
|
||||
};
|
||||
|
||||
struct pending_block
|
||||
{
|
||||
struct pending_loc_var* vars;
|
||||
unsigned num;
|
||||
unsigned allocated;
|
||||
};
|
||||
|
||||
static inline void pending_add(struct pending_block* pending, const char* name,
|
||||
int regno, int offset)
|
||||
{
|
||||
if (pending->num == pending->allocated)
|
||||
{
|
||||
pending->allocated += 8;
|
||||
if (!pending->vars)
|
||||
pending->vars = HeapAlloc(GetProcessHeap(), 0,
|
||||
pending->allocated * sizeof(pending->vars[0]));
|
||||
else
|
||||
pending->vars = HeapReAlloc(GetProcessHeap(), 0, pending->vars,
|
||||
pending->allocated * sizeof(pending->vars[0]));
|
||||
}
|
||||
stab_strcpy(pending->vars[pending->num].name,
|
||||
sizeof(pending->vars[pending->num].name), name);
|
||||
pending->vars[pending->num].type = stabs_parse_type(name);
|
||||
pending->vars[pending->num].offset = offset;
|
||||
pending->vars[pending->num].regno = regno;
|
||||
pending->num++;
|
||||
}
|
||||
|
||||
static void pending_flush(struct pending_block* pending, struct module* module,
|
||||
struct symt_function* func, struct symt_block* block)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pending->num; i++)
|
||||
{
|
||||
symt_add_func_local(module, func, pending->vars[i].regno,
|
||||
pending->vars[i].offset, block,
|
||||
pending->vars[i].type, pending->vars[i].name);
|
||||
}
|
||||
pending->num = 0;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* stabs_finalize_function
|
||||
*
|
||||
|
@ -1129,7 +1171,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
struct symt_compiland* compiland = NULL;
|
||||
char currpath[PATH_MAX]; /* path to current file */
|
||||
char srcpath[PATH_MAX]; /* path to directory source file is in */
|
||||
int i, j;
|
||||
int i;
|
||||
int nstab;
|
||||
const char* ptr;
|
||||
char* stabbuff;
|
||||
|
@ -1141,9 +1183,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
unsigned incl[32];
|
||||
int incl_stk = -1;
|
||||
int source_idx = -1;
|
||||
struct pending_loc_var* pending_vars = NULL;
|
||||
unsigned num_pending_vars = 0;
|
||||
unsigned num_allocated_pending_vars = 0;
|
||||
struct pending_block pending;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
nstab = stablen / sizeof(struct stab_nlist);
|
||||
|
@ -1151,6 +1191,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
|
||||
memset(srcpath, 0, sizeof(srcpath));
|
||||
memset(stabs_basic, 0, sizeof(stabs_basic));
|
||||
memset(&pending, 0, sizeof(pending));
|
||||
|
||||
/*
|
||||
* Allocate a buffer into which we can build stab strings for cases
|
||||
|
@ -1254,7 +1295,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
"rbrac","","","", /* e0 */
|
||||
};
|
||||
|
||||
FIXME("Got %s<%u> %u/%lu (%s)\n",
|
||||
FIXME("Got %s<%u> %u/%ld (%s)\n",
|
||||
defs[stab_ptr->n_type / 2], stab_ptr->n_type, stab_ptr->n_desc, stab_ptr->n_value, debugstr_a(ptr));
|
||||
#endif
|
||||
|
||||
|
@ -1285,13 +1326,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
case N_LBRAC:
|
||||
block = symt_open_func_block(module, curr_func, block,
|
||||
stab_ptr->n_value, 0);
|
||||
for (j = 0; j < num_pending_vars; j++)
|
||||
{
|
||||
symt_add_func_local(module, curr_func, pending_vars[j].regno,
|
||||
pending_vars[j].offset,
|
||||
block, pending_vars[j].type, pending_vars[j].name);
|
||||
}
|
||||
num_pending_vars = 0;
|
||||
pending_flush(&pending, module, curr_func, block);
|
||||
break;
|
||||
case N_RBRAC:
|
||||
block = symt_close_func_block(module, curr_func, block,
|
||||
|
@ -1316,16 +1351,6 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
{
|
||||
unsigned reg;
|
||||
|
||||
if (num_pending_vars == num_allocated_pending_vars)
|
||||
{
|
||||
num_allocated_pending_vars += 8;
|
||||
if (!pending_vars)
|
||||
pending_vars = HeapAlloc(GetProcessHeap(), 0,
|
||||
num_allocated_pending_vars * sizeof(pending_vars[0]));
|
||||
else
|
||||
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
|
||||
num_allocated_pending_vars * sizeof(pending_vars[0]));
|
||||
}
|
||||
switch (stab_ptr->n_value)
|
||||
{
|
||||
case 0: reg = CV_REG_EAX; break;
|
||||
|
@ -1350,36 +1375,24 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
reg = CV_REG_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
stab_strcpy(pending_vars[num_pending_vars].name,
|
||||
sizeof(pending_vars[num_pending_vars].name), ptr);
|
||||
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
|
||||
pending_vars[num_pending_vars].offset = 0;
|
||||
pending_vars[num_pending_vars].regno = reg;
|
||||
num_pending_vars++;
|
||||
stab_strcpy(symname, sizeof(symname), ptr);
|
||||
if (ptr[strlen(symname) + 1] == 'P')
|
||||
{
|
||||
struct symt* param_type = stabs_parse_type(ptr);
|
||||
stab_strcpy(symname, sizeof(symname), ptr);
|
||||
symt_add_func_local(module, curr_func, reg, 1,
|
||||
NULL, param_type, symname);
|
||||
symt_add_function_signature_parameter(module,
|
||||
(struct symt_function_signature*)curr_func->type,
|
||||
param_type);
|
||||
}
|
||||
else
|
||||
pending_add(&pending, ptr, reg, 0);
|
||||
}
|
||||
break;
|
||||
case N_LSYM:
|
||||
/* These are local variables */
|
||||
if (curr_func != NULL)
|
||||
{
|
||||
if (num_pending_vars == num_allocated_pending_vars)
|
||||
{
|
||||
num_allocated_pending_vars += 8;
|
||||
if (!pending_vars)
|
||||
pending_vars = HeapAlloc(GetProcessHeap(), 0,
|
||||
num_allocated_pending_vars * sizeof(pending_vars[0]));
|
||||
else
|
||||
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
|
||||
num_allocated_pending_vars * sizeof(pending_vars[0]));
|
||||
}
|
||||
stab_strcpy(pending_vars[num_pending_vars].name,
|
||||
sizeof(pending_vars[num_pending_vars].name), ptr);
|
||||
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
|
||||
pending_vars[num_pending_vars].offset = stab_ptr->n_value;
|
||||
pending_vars[num_pending_vars].regno = 0;
|
||||
num_pending_vars++;
|
||||
}
|
||||
if (curr_func != NULL) pending_add(&pending, ptr, 0, stab_ptr->n_value);
|
||||
break;
|
||||
case N_SLINE:
|
||||
/*
|
||||
|
@ -1534,7 +1547,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
done:
|
||||
HeapFree(GetProcessHeap(), 0, stabbuff);
|
||||
stabs_free_includes();
|
||||
HeapFree(GetProcessHeap(), 0, pending_vars);
|
||||
HeapFree(GetProcessHeap(), 0, pending.vars);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -285,6 +285,19 @@ void symt_add_func_line(struct module* module, struct symt_function* func,
|
|||
dli->u.pc_offset = func->address + offset;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* symt_add_func_local
|
||||
*
|
||||
* Adds a new local/parameter to a given function:
|
||||
* If regno it's not 0:
|
||||
* - then variable is stored in a register
|
||||
* - if offset is > 0, then it's a parameter to the function (in a register)
|
||||
* - if offset is = 0, then it's a local variable (in a register)
|
||||
* Otherwise, the variable is stored on the stack:
|
||||
* - if offset is > 0, then it's a parameter to the function
|
||||
* - otherwise, it's a local variable
|
||||
* FIXME: this is too i386 centric
|
||||
*/
|
||||
struct symt_data* symt_add_func_local(struct module* module,
|
||||
struct symt_function* func,
|
||||
int regno, int offset,
|
||||
|
@ -304,7 +317,7 @@ struct symt_data* symt_add_func_local(struct module* module,
|
|||
locsym->symt.tag = SymTagData;
|
||||
locsym->hash_elt.name = pool_strdup(&module->pool, name);
|
||||
locsym->hash_elt.next = NULL;
|
||||
locsym->kind = (offset < 0) ? DataIsParam : DataIsLocal;
|
||||
locsym->kind = (offset > 0) ? DataIsParam : DataIsLocal;
|
||||
locsym->container = &block->symt;
|
||||
locsym->type = type;
|
||||
if (regno)
|
||||
|
@ -465,8 +478,10 @@ static void symt_fill_sym_info(const struct module* module,
|
|||
const struct symt_data* data = (const struct symt_data*)sym;
|
||||
switch (data->kind)
|
||||
{
|
||||
case DataIsLocal:
|
||||
case DataIsParam:
|
||||
sym_info->Flags |= SYMFLAG_PARAMETER;
|
||||
/* fall through */
|
||||
case DataIsLocal:
|
||||
if (data->u.s.reg_id)
|
||||
{
|
||||
sym_info->Flags |= SYMFLAG_REGISTER;
|
||||
|
@ -476,8 +491,6 @@ static void symt_fill_sym_info(const struct module* module,
|
|||
else
|
||||
{
|
||||
sym_info->Flags |= SYMFLAG_LOCAL | SYMFLAG_REGREL;
|
||||
/* FIXME: this is i386 dependent */
|
||||
if (data->u.s.offset >= 0) sym_info->Flags |= SYMFLAG_PARAMETER;
|
||||
/* FIXME: needed ? moreover, it's i386 dependent !!! */
|
||||
sym_info->Register = CV_REG_EBP;
|
||||
sym_info->Address = data->u.s.offset / 8;
|
||||
|
|
|
@ -334,6 +334,7 @@ extern BOOL memory_get_current_stack(ADDRESS* address);
|
|||
extern BOOL memory_get_current_frame(ADDRESS* address);
|
||||
extern BOOL memory_get_string(struct dbg_process* pcs, void* addr, BOOL in_debuggee, BOOL unicode, char* buffer, int size);
|
||||
extern BOOL memory_get_string_indirect(struct dbg_process* pcs, void* addr, BOOL unicode, char* buffer, int size);
|
||||
extern BOOL memory_get_register(DWORD regno, DWORD** value, char* buffer, int len);
|
||||
extern void memory_disassemble(const struct dbg_lvalue*, const struct dbg_lvalue*, int instruction_count);
|
||||
extern BOOL memory_disasm_one_insn(ADDRESS* addr);
|
||||
extern void print_bare_address(const ADDRESS* addr);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 1993 Eric Youngdale
|
||||
* Copyright 1995 Alexandre Julliard
|
||||
* Copyright 2000-2004 Eric Pouech
|
||||
* Copyright 2000-2005 Eric Pouech
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -570,3 +570,25 @@ void memory_disassemble(const struct dbg_lvalue* xstart,
|
|||
(stop == 0 || last.Offset <= stop); i++)
|
||||
memory_disasm_one_insn(&last);
|
||||
}
|
||||
|
||||
BOOL memory_get_register(DWORD regno, DWORD** value, char* buffer, int len)
|
||||
{
|
||||
const struct dbg_internal_var* div;
|
||||
|
||||
if (dbg_curr_thread->curr_frame != 0)
|
||||
{
|
||||
if (buffer) snprintf(buffer, len, "<register not in topmost frame>");
|
||||
return FALSE;
|
||||
}
|
||||
for (div = dbg_context_vars; div->name; div++)
|
||||
{
|
||||
if (div->val == regno)
|
||||
{
|
||||
*value = div->pval;
|
||||
snprintf(buffer, len, div->name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if (buffer) snprintf(buffer, len, "<unknown register %lu>", regno);
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -174,17 +174,30 @@ struct sym_enum
|
|||
static BOOL WINAPI sym_enum_cb(SYMBOL_INFO* sym_info, ULONG size, void* user)
|
||||
{
|
||||
struct sym_enum* se = (struct sym_enum*)user;
|
||||
DWORD addr;
|
||||
unsigned val;
|
||||
char tmp[32];
|
||||
|
||||
if ((sym_info->Flags & (SYMFLAG_PARAMETER|SYMFLAG_REGREL)) == (SYMFLAG_PARAMETER|SYMFLAG_REGREL))
|
||||
if (sym_info->Flags & SYMFLAG_PARAMETER)
|
||||
{
|
||||
if (se->tmp[0]) strcat(se->tmp, ", ");
|
||||
addr = se->frame + sym_info->Address;
|
||||
if (dbg_read_memory((char*)addr, &val, sizeof(val)))
|
||||
sprintf(se->tmp + strlen(se->tmp), "%s=0x%x", sym_info->Name, val);
|
||||
else
|
||||
sprintf(se->tmp + strlen(se->tmp), "%s=<\?\?\?>", sym_info->Name);
|
||||
|
||||
if (sym_info->Flags & SYMFLAG_REGREL)
|
||||
{
|
||||
unsigned val;
|
||||
DWORD addr = se->frame + sym_info->Address;
|
||||
|
||||
if (!dbg_read_memory((char*)addr, &val, sizeof(val)))
|
||||
snprintf(tmp, sizeof(tmp), "<*** cannot read at 0x%lx ***>", addr);
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), "0x%x", val);
|
||||
}
|
||||
else if (sym_info->Flags & SYMFLAG_REGISTER)
|
||||
{
|
||||
DWORD* pval;
|
||||
|
||||
if (memory_get_register(sym_info->Register, &pval, tmp, sizeof(tmp)))
|
||||
snprintf(tmp, sizeof(tmp), "0x%lx", *pval);
|
||||
}
|
||||
sprintf(se->tmp + strlen(se->tmp), "%s=%s", sym_info->Name, tmp);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -240,25 +253,28 @@ static void stack_print_addr_and_args(int nf)
|
|||
*
|
||||
* Do a backtrace on the the current thread
|
||||
*/
|
||||
static unsigned backtrace(void)
|
||||
static void backtrace(void)
|
||||
{
|
||||
unsigned nf = 0;
|
||||
unsigned cf = dbg_curr_thread->curr_frame;
|
||||
IMAGEHLP_STACK_FRAME ihsf;
|
||||
|
||||
dbg_printf("Backtrace:\n");
|
||||
for (nf = 0; nf < dbg_curr_thread->num_frames; nf++)
|
||||
for (dbg_curr_thread->curr_frame = 0;
|
||||
dbg_curr_thread->curr_frame < dbg_curr_thread->num_frames;
|
||||
dbg_curr_thread->curr_frame++)
|
||||
{
|
||||
dbg_printf("%s%d ",
|
||||
(nf == dbg_curr_thread->curr_frame ? "=>" : " "), nf + 1);
|
||||
stack_print_addr_and_args(nf);
|
||||
(cf == dbg_curr_thread->curr_frame ? "=>" : " "),
|
||||
dbg_curr_thread->curr_frame + 1);
|
||||
stack_print_addr_and_args(dbg_curr_thread->curr_frame);
|
||||
dbg_printf(" (");
|
||||
print_bare_address(&dbg_curr_thread->frames[nf].addr_pc);
|
||||
print_bare_address(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_pc);
|
||||
dbg_printf(")\n");
|
||||
}
|
||||
/* reset context to current stack frame */
|
||||
dbg_curr_thread->curr_frame = cf;
|
||||
stack_get_frame(dbg_curr_thread->curr_frame, &ihsf);
|
||||
SymSetContext(dbg_curr_process->handle, &ihsf, NULL);
|
||||
return nf;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Generate hash tables for Wine debugger symbols
|
||||
*
|
||||
* Copyright (C) 1993, Eric Youngdale.
|
||||
* 2004, Eric Pouech.
|
||||
* 2004-2005, Eric Pouech.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -93,22 +93,14 @@ static BOOL CALLBACK sgv_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
|||
|
||||
if (sym->Flags & SYMFLAG_REGISTER)
|
||||
{
|
||||
const struct dbg_internal_var* div;
|
||||
|
||||
if (dbg_curr_thread->curr_frame != 0)
|
||||
char tmp[32];
|
||||
DWORD* val;
|
||||
if (!memory_get_register(sym->Register, &val, tmp, sizeof(tmp)))
|
||||
{
|
||||
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
|
||||
sym->Name);
|
||||
dbg_printf(" %s (register): %s\n", sym->Name, tmp);
|
||||
return TRUE;
|
||||
}
|
||||
for (div = dbg_context_vars; div->name && div->val != sym->Register; div++);
|
||||
if (!div->name)
|
||||
{
|
||||
dbg_printf(" %s (register): couldn't find register %lu\n",
|
||||
sym->Name, sym->Register);
|
||||
return TRUE;
|
||||
}
|
||||
addr = (ULONG64)(DWORD_PTR)div->pval;
|
||||
addr = (ULONG64)(DWORD_PTR)val;
|
||||
cookie = DLV_HOST;
|
||||
}
|
||||
else if (sym->Flags & SYMFLAG_LOCAL) /* covers both local & parameters */
|
||||
|
@ -537,7 +529,6 @@ BOOL symbol_get_line(const char* filename, const char* name, IMAGEHLP_LINE* line
|
|||
static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
||||
{
|
||||
ULONG v, val;
|
||||
const char* explain = NULL;
|
||||
char buf[128];
|
||||
struct dbg_type type;
|
||||
|
||||
|
@ -546,29 +537,19 @@ static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
|||
type.id = sym->TypeIndex;
|
||||
types_print_type(&type, FALSE);
|
||||
|
||||
if (sym->Flags & SYMFLAG_PARAMETER) explain = "parameter";
|
||||
else if (sym->Flags & SYMFLAG_LOCAL) explain = "local";
|
||||
else if (sym->Flags & SYMFLAG_REGISTER) explain = buf;
|
||||
buf[0] = '\0';
|
||||
|
||||
if (sym->Flags & SYMFLAG_REGISTER)
|
||||
{
|
||||
const struct dbg_internal_var* div;
|
||||
|
||||
if (dbg_curr_thread->curr_frame != 0)
|
||||
char tmp[32];
|
||||
DWORD* pval;
|
||||
if (!memory_get_register(sym->Register, &pval, tmp, sizeof(tmp)))
|
||||
{
|
||||
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
|
||||
sym->Name);
|
||||
dbg_printf(" %s (register): %s\n", sym->Name, tmp);
|
||||
return TRUE;
|
||||
}
|
||||
for (div = dbg_context_vars; div->name; div++)
|
||||
{
|
||||
if (div->val == sym->Register)
|
||||
{
|
||||
val = *div->pval;
|
||||
sprintf(buf, "local in register %s", div->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sprintf(buf, " in register %s", tmp);
|
||||
val = *pval;
|
||||
}
|
||||
else if (sym->Flags & SYMFLAG_LOCAL)
|
||||
{
|
||||
|
@ -577,11 +558,14 @@ static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
|||
|
||||
if (!dbg_read_memory((void*)v, &val, sizeof(val)))
|
||||
{
|
||||
dbg_printf(" %s (%s) *** cannot read value at 0x%08lx\n", sym->Name, explain, v);
|
||||
dbg_printf(" %s (%s) *** cannot read at 0x%08lx\n",
|
||||
sym->Name, (sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local",
|
||||
v);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
dbg_printf(" %s = 0x%8.8lx (%s)\n", sym->Name, val, explain);
|
||||
dbg_printf(" %s = 0x%8.8lx (%s%s)\n", sym->Name, val,
|
||||
(sym->Flags & SYMFLAG_PARAMETER) ? "parameter" : "local", buf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue