From 2ce5eca6a5b5c6522e396e3b3f566dc523b29856 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 6 Feb 2006 11:27:32 +0100 Subject: [PATCH] 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. --- dlls/dbghelp/stabs.c | 113 ++++++++++++++++++++---------------- dlls/dbghelp/symbol.c | 21 +++++-- programs/winedbg/debugger.h | 1 + programs/winedbg/memory.c | 24 +++++++- programs/winedbg/stack.c | 46 ++++++++++----- programs/winedbg/symbol.c | 52 ++++++----------- 6 files changed, 153 insertions(+), 104 deletions(-) diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 75517df615a..7f1714f7120 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -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; } diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index bd9598383e0..016e14faa5f 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -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; diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 385ab443cca..89ff56f86b5 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -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); diff --git a/programs/winedbg/memory.c b/programs/winedbg/memory.c index 8b042c93e3c..8d09e9c9e70 100644 --- a/programs/winedbg/memory.c +++ b/programs/winedbg/memory.c @@ -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, ""); + 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, "", regno); + return FALSE; +} diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c index abb943a2ed1..f506f5f36d3 100644 --- a/programs/winedbg/stack.c +++ b/programs/winedbg/stack.c @@ -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; } /****************************************************************** diff --git a/programs/winedbg/symbol.c b/programs/winedbg/symbol.c index f7dcfce539c..14172859979 100644 --- a/programs/winedbg/symbol.c +++ b/programs/winedbg/symbol.c @@ -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; }