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:
Eric Pouech 2006-02-06 11:27:32 +01:00 committed by Alexandre Julliard
parent dccd41a88a
commit 2ce5eca6a5
6 changed files with 153 additions and 104 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
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
sprintf(se->tmp + strlen(se->tmp), "%s=<\?\?\?>", sym_info->Name);
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;
}
/******************************************************************

View File

@ -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;
}