[PATCH 5/5] [DbgHelp]: added preliminary extended FPO information out of PDB files
Eric Pouech
eric.pouech at orange.fr
Sat Jan 8 07:04:20 CST 2011
A+
---
0 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/dlls/dbghelp/cpu_i386.c b/dlls/dbghelp/cpu_i386.c
index 7739d13..61ed427 100644
--- a/dlls/dbghelp/cpu_i386.c
+++ b/dlls/dbghelp/cpu_i386.c
@@ -214,7 +214,8 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
#ifdef __i386__
if (curr_mode == stm_32bit)
{
- DWORD_PTR xframe;
+ DWORD_PTR xframe;
+ struct pdb_cmd_pair cpair[4];
if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, &xframe))
{
@@ -224,6 +225,19 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
frame->AddrReturn.Offset = context->Eip;
goto done_pep;
}
+ cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
+ cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
+ cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
+ cpair[3].name = NULL; cpair[3].pvalue = NULL;
+
+ if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, cpair))
+ {
+ frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
+ frame->AddrStack.Offset = context->Esp;
+ frame->AddrFrame.Offset = context->Ebp;
+ frame->AddrReturn.Offset = context->Eip;
+ goto done_pep;
+ }
}
#endif
}
@@ -353,7 +367,8 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
else
{
#ifdef __i386__
- DWORD_PTR xframe;
+ DWORD_PTR xframe;
+ struct pdb_cmd_pair cpair[4];
if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, &xframe))
{
@@ -363,6 +378,19 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
frame->AddrReturn.Offset = context->Eip;
goto done_pep;
}
+ cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
+ cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
+ cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
+ cpair[3].name = NULL; cpair[3].pvalue = NULL;
+
+ if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, cpair))
+ {
+ frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
+ frame->AddrStack.Offset = context->Esp;
+ frame->AddrFrame.Offset = context->Ebp;
+ frame->AddrReturn.Offset = context->Eip;
+ goto done_pep;
+ }
#endif
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
/* "pop up" previous EBP value */
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h
index 88247ec..bb82ad3 100644
--- a/dlls/dbghelp/dbghelp_private.h
+++ b/dlls/dbghelp/dbghelp_private.h
@@ -559,6 +559,12 @@ extern BOOL pe_load_debug_directory(const struct process* pcs,
const IMAGE_SECTION_HEADER* sectp, DWORD nsect,
const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg);
extern BOOL pdb_fetch_file_info(const struct pdb_lookup* pdb_lookup, unsigned* matched);
+struct pdb_cmd_pair {
+ const char* name;
+ DWORD* pvalue;
+};
+extern BOOL pdb_virtual_unwind(struct cpu_stack_walk* csw, DWORD_PTR ip,
+ CONTEXT* context, struct pdb_cmd_pair* cpair);
/* path.c */
extern BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_path,
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c
index 4dcf65f..93eef21 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -2750,6 +2750,310 @@ BOOL pdb_fetch_file_info(const struct pdb_lookup* pdb_lookup, unsigned* matched)
}
/*========================================================================
+ * FPO unwinding code
+ */
+
+/* Stack unwinding is based on postfixed operations.
+ * Let's define our Postfix EValuator
+ */
+#define PEV_MAX_LEN 32
+struct pevaluator
+{
+ struct cpu_stack_walk* csw;
+ struct pool pool;
+ struct vector stack;
+ unsigned stk_index;
+ struct hash_table values;
+ char error[64];
+};
+
+struct zvalue
+{
+ DWORD_PTR value;
+ struct hash_table_elt elt;
+};
+
+#define PEV_ERROR(pev, msg) snprintf((pev)->error, sizeof((pev)->error), "%s", (msg)),FALSE
+#define PEV_ERROR1(pev, msg, pmt) snprintf((pev)->error, sizeof((pev)->error), (msg), (pmt)),FALSE
+
+#if 0
+static void pev_dump_stack(struct pevaluator* pev)
+{
+ unsigned i;
+ FIXME("stack #%d\n", pev->stk_index);
+ for (i = 0; i < pev->stk_index; i++)
+ {
+ FIXME("\t%d) %s\n", i, *(char**)vector_at(&pev->stack, i));
+ }
+}
+#endif
+
+/* get the value out of an operand (variable or literal) */
+static BOOL pev_get_val(struct pevaluator* pev, const char* str, DWORD_PTR* val)
+{
+ char* n;
+ struct hash_table_iter hti;
+ void* ptr;
+
+ switch (str[0])
+ {
+ case '$':
+ case '.':
+ hash_table_iter_init(&pev->values, &hti, str);
+ if (!(ptr = hash_table_iter_up(&hti)))
+ return PEV_ERROR1(pev, "get_zvalue: no value found (%s)", str);
+ *val = GET_ENTRY(ptr, struct zvalue, elt)->value;
+ return TRUE;
+ default:
+ *val = strtol(str, &n, 10);
+ if (n == str || *n != '\0')
+ return PEV_ERROR1(pev, "get_val: not a literal (%s)", str);
+ return TRUE;
+ }
+}
+
+/* push an operand onto the stack */
+static BOOL pev_push(struct pevaluator* pev, const char* elt)
+{
+ char** at;
+ if (pev->stk_index < vector_length(&pev->stack))
+ at = vector_at(&pev->stack, pev->stk_index);
+ else
+ at = vector_add(&pev->stack, &pev->pool);
+ if (!at) return PEV_ERROR(pev, "push: out of memory");
+ *at = pool_strdup(&pev->pool, elt);
+ pev->stk_index++;
+ return TRUE;
+}
+
+/* pop an operand from the stack */
+static BOOL pev_pop(struct pevaluator* pev, char* elt)
+{
+ char** at = vector_at(&pev->stack, --pev->stk_index);
+ if (!at) return PEV_ERROR(pev, "pop: stack empty");
+ strcpy(elt, *at);
+ return TRUE;
+}
+
+/* pop an operand from the stack, and gets its value */
+static BOOL pev_pop_val(struct pevaluator* pev, DWORD_PTR* val)
+{
+ char p[PEV_MAX_LEN];
+
+ return pev_pop(pev, p) && pev_get_val(pev, p, val);
+}
+
+/* set var 'name' a new value (creates the var if it doesn't exist) */
+static BOOL pev_set_value(struct pevaluator* pev, const char* name, DWORD_PTR val)
+{
+ struct hash_table_iter hti;
+ void* ptr;
+
+ hash_table_iter_init(&pev->values, &hti, name);
+ if (!(ptr = hash_table_iter_up(&hti)))
+ {
+ struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv));
+ if (!zv) return PEV_ERROR(pev, "set_value: out of memory");
+ zv->value = val;
+
+ zv->elt.name = pool_strdup(&pev->pool, name);
+ hash_table_add(&pev->values, &zv->elt);
+ }
+ else GET_ENTRY(ptr, struct zvalue, elt)->value = val;
+ return TRUE;
+}
+
+/* execute a binary operand from the two top most values on the stack.
+ * puts result on top of the stack */
+static BOOL pev_binop(struct pevaluator* pev, char op)
+{
+ char res[PEV_MAX_LEN];
+ DWORD_PTR v1, v2, c;
+
+ if (!pev_pop_val(pev, &v1) || !pev_pop_val(pev, &v2)) return FALSE;
+ switch (op)
+ {
+ case '+': c = v1 + v2; break;
+ case '-': c = v1 - v2; break;
+ case '*': c = v1 * v2; break;
+ case '/': c = v1 / v2; break;
+ case '%': c = v1 % v2; break;
+ default: return PEV_ERROR1(pev, "binop: unknown op (%c)", op);
+ }
+ snprintf(res, sizeof(res), "%ld", c);
+ pev_push(pev, res);
+ return TRUE;
+}
+
+/* pops top most operand, dereference it, on pushes the result on top of the stack */
+static BOOL pev_deref(struct pevaluator* pev)
+{
+ char res[PEV_MAX_LEN];
+ DWORD_PTR v1, v2;
+
+ if (!pev_pop_val(pev, &v1)) return FALSE;
+ if (!sw_read_mem(pev->csw, v1, &v2, sizeof(v2)))
+ return PEV_ERROR1(pev, "deref: cannot read mem at %lx\n", v1);
+ snprintf(res, sizeof(res), "%ld", v2);
+ pev_push(pev, res);
+ return TRUE;
+}
+
+/* assign value to variable (from two top most operands) */
+static BOOL pev_assign(struct pevaluator* pev)
+{
+ char p2[PEV_MAX_LEN];
+ DWORD_PTR v1;
+
+ if (!pev_pop_val(pev, &v1) || !pev_pop(pev, p2)) return FALSE;
+ if (p2[0] != '$') return PEV_ERROR1(pev, "assign: %s isn't a variable", p2);
+ pev_set_value(pev, p2, v1);
+
+ return TRUE;
+}
+
+/* initializes the postfix evaluator */
+static void pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw,
+ PDB_FPO_DATA* fpoext, struct pdb_cmd_pair* cpair)
+{
+ pev->csw = csw;
+ pool_init(&pev->pool, 512);
+ vector_init(&pev->stack, sizeof(char*), 8);
+ pev->stk_index = 0;
+ hash_table_init(&pev->pool, &pev->values, 8);
+ pev->error[0] = '\0';
+ for (; cpair->name; cpair++)
+ pev_set_value(pev, cpair->name, *cpair->pvalue);
+ pev_set_value(pev, ".raSearchStart", fpoext->start);
+ pev_set_value(pev, ".cbLocals", fpoext->locals_size);
+ pev_set_value(pev, ".cbParams", fpoext->params_size);
+ pev_set_value(pev, ".cbSavedRegs", fpoext->savedregs_size);
+}
+
+static BOOL pev_free(struct pevaluator* pev, struct pdb_cmd_pair* cpair)
+{
+ DWORD_PTR val;
+
+ if (cpair) for (; cpair->name; cpair++)
+ {
+ if (pev_get_val(pev, cpair->name, &val))
+ *cpair->pvalue = val;
+ }
+ pool_destroy(&pev->pool);
+ return TRUE;
+}
+
+static BOOL pdb_parse_cmd_string(struct cpu_stack_walk* csw, PDB_FPO_DATA* fpoext,
+ const char* cmd, struct pdb_cmd_pair* cpair)
+{
+ char token[PEV_MAX_LEN];
+ char* ptok = token;
+ const char* ptr;
+ BOOL over = FALSE;
+ struct pevaluator pev;
+
+ pev_init(&pev, csw, fpoext, cpair);
+ for (ptr = cmd; !over; ptr++)
+ {
+ if (*ptr == ' ' || (over = *ptr == '\0'))
+ {
+ *ptok = '\0';
+
+ if (!strcmp(token, "+") || !strcmp(token, "-") || !strcmp(token, "*") ||
+ !strcmp(token, "/") || !strcmp(token, "%"))
+ {
+ if (!pev_binop(&pev, token[0])) goto done;
+ }
+ else if (!strcmp(token, "^"))
+ {
+ if (!pev_deref(&pev)) goto done;
+ }
+ else if (!strcmp(token, "="))
+ {
+ if (!pev_assign(&pev)) goto done;
+ }
+ else
+ {
+ if (!pev_push(&pev, token)) goto done;
+ }
+ ptok = token;
+ }
+ else
+ {
+ if (ptok - token >= PEV_MAX_LEN - 1)
+ {
+ PEV_ERROR1(&pev, "parse: token too long (%s)", ptr - (ptok - token));
+ goto done;
+ }
+ *ptok++ = *ptr;
+ }
+ }
+ pev_free(&pev, cpair);
+ return TRUE;
+done:
+ FIXME("Couldn't evaluate %s => %s\n", wine_dbgstr_a(cmd), pev.error);
+ pev_free(&pev, NULL);
+ return FALSE;
+}
+
+BOOL pdb_virtual_unwind(struct cpu_stack_walk* csw, DWORD_PTR ip,
+ CONTEXT* context, struct pdb_cmd_pair* cpair)
+{
+ struct module_pair pair;
+ struct pdb_module_info* pdb_info;
+ PDB_FPO_DATA* fpoext;
+ unsigned i, size, strsize;
+ char* strbase;
+ BOOL ret = TRUE;
+
+ if (!(pair.pcs = process_find_by_handle(csw->hProcess)) ||
+ !(pair.requested = module_find_by_addr(pair.pcs, ip, DMT_UNKNOWN)) ||
+ !module_get_debug(&pair))
+ return FALSE;
+ if (!pair.effective->format_info[DFI_PDB]) return FALSE;
+ pdb_info = pair.effective->format_info[DFI_PDB]->u.pdb_info;
+ TRACE("searching %lx => %lx\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage);
+ ip -= (DWORD_PTR)pair.effective->module.BaseOfImage;
+
+ strbase = pdb_read_file(&pdb_info->pdb_files[0], 12); /* FIXME: really fixed index ??? */
+ if (!strbase) return FALSE;
+ if (*(const DWORD*)strbase != 0xeffeeffe)
+ {
+ pdb_free(strbase);
+ return FALSE;
+ }
+ strsize = *(const DWORD*)(strbase + 8);
+ fpoext = pdb_read_file(&pdb_info->pdb_files[0], 10);
+ size = pdb_get_file_size(&pdb_info->pdb_files[0], 10);
+ if (fpoext && (size % sizeof(*fpoext)) == 0)
+ {
+ size /= sizeof(*fpoext);
+ for (i = 0; i < size; i++)
+ {
+ if (fpoext[i].start <= ip && ip < fpoext[i].start + fpoext[i].func_size)
+ {
+ TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n",
+ fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size,
+ fpoext[i].params_size, fpoext[i].maxstack_size, fpoext[i].prolog_size,
+ fpoext[i].savedregs_size, fpoext[i].flags,
+ fpoext[i].str_offset < strsize ?
+ wine_dbgstr_a(strbase + 12 + fpoext[i].str_offset) : "<out of bounds>");
+ if (fpoext[i].str_offset < strsize)
+ ret = pdb_parse_cmd_string(csw, fpoext, strbase + 12 + fpoext[i].str_offset, cpair);
+ else
+ ret = FALSE;
+ break;
+ }
+ }
+ }
+ else ret = FALSE;
+ pdb_free(fpoext);
+ pdb_free(strbase);
+
+ return ret;
+}
+
+/*========================================================================
* Process CodeView debug information.
*/
More information about the wine-patches
mailing list