This serie (#5 in PDB rewrite) actually starts the implementation of the i "new" PDB reader.
Basically, during the phase of migration from the "old" to the "new" PDB reader, both readers will be used at the same time (for every loaded module with PDB information).
So: - be ready to expect an increase in memory usage (as both will handle their own information), - in the process of migration, when possible, parts of the "old" reader will be disabled not to consume too much memory nor time,
Default will be to use the "new" reader. If you really want to use the "old" reader, set the WINE_DBGHELP_OLD_PDB env variable.
The integration of the "new" PDB reader is done through a set of methods attached to each debug format (1).
This serie: - sets the foundations of the "new" PDB reader (in a new pdb.c file), - use it to support the access to PFO unwinding information in PDB files (and this allows to unmap the PDB file, used by the all reader, when all information have been read by "old" reader), - introduces the methods vtable for each debug format.
Note 1: - "new" PDB reader will not support as many PDB variations as the "old" reader, - actually, PDB files come into two forms. The second form became the CL.EXE default in MSVC version 8, something like 30 years ago, (first format was very limited in the potential size of the PDB file), - also, the CodeView records in the PDB files exist in 3 versions: + V1: 2^16 types per image, identifiers as pascal string, 255 char max, + V2: 2^32 types per image, identifiers as pascal string, 255 char max, + V3: 2^32 types per image, identifiers as C-strings ("unlimited"), - for now, only support for the V3 CodeView records is included - I don't plan to add all the other variations as they are very obsolete, - for the record, this is aligned with clang design decisions for their PDB implementation,
Note 2: - "old" reader maps the whole PDB file in memory, then allocate memory chunks for each internal stream and reconstructs the stream by copying from the filemap into the stream buffer), - "new" reader access the PDB file through ReadFile,
[1] dwarf4/5 is a candidate to be moved to this new interface for the same reasons as PDB (not to load every debug information at module loading in dbghelp),
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/msc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 0b28abf200d..2e6fd07d4e7 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -4163,7 +4163,7 @@ 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; + if (!pev_pop_val(pev, &v2) || !pev_pop_val(pev, &v1)) return FALSE; if ((op == '/' || op == '%') && v2 == 0) { pev_set_error(pev, "binop: division by zero");
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/Makefile.in | 1 + dlls/dbghelp/dbghelp_private.h | 8 + dlls/dbghelp/msc.c | 422 +++--------------- dlls/dbghelp/pdb.c | 789 +++++++++++++++++++++++++++++++++ dlls/dbghelp/storage.c | 4 - 5 files changed, 868 insertions(+), 356 deletions(-) create mode 100644 dlls/dbghelp/pdb.c
diff --git a/dlls/dbghelp/Makefile.in b/dlls/dbghelp/Makefile.in index 152ef80611a..dd27e159f18 100644 --- a/dlls/dbghelp/Makefile.in +++ b/dlls/dbghelp/Makefile.in @@ -19,6 +19,7 @@ SOURCES = \ module.c \ msc.c \ path.c \ + pdb.c \ pe_module.c \ source.c \ stabs.c \ diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 5979eb7955a..4bb56fee46d 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -985,3 +985,11 @@ extern struct symt_function* #define IFC_DEPTH_MASK 0x3FFFFFFF #define IFC_MODE(x) ((x) & ~IFC_DEPTH_MASK) #define IFC_DEPTH(x) ((x) & IFC_DEPTH_MASK) + +/* temporary helpers for PDB rewriting */ +struct _PDB_FPO_DATA; +extern BOOL pdb_fpo_unwind_parse_cmd_string(struct cpu_stack_walk* csw, struct _PDB_FPO_DATA* fpoext, + const char* cmd, struct pdb_cmd_pair* cpair); +extern BOOL pdb_old_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, + union ctx *context, struct pdb_cmd_pair *cpair); +extern BOOL pdb_hack_get_main_info(struct module_format *modfmt, HANDLE *file, unsigned *fpoext_stream); diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 2e6fd07d4e7..8acd4e70f3a 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -37,7 +37,6 @@ #include <stdlib.h> #include <string.h>
-#include <stdarg.h> #include "windef.h" #include "winbase.h" #include "winternl.h" @@ -62,6 +61,7 @@ enum pdb_kind {PDB_JG, PDB_DS}; struct pdb_file_info { enum pdb_kind kind; + HANDLE file_handle; HANDLE hMap; const char* image; struct pdb_stream_name* stream_dict; @@ -97,6 +97,18 @@ struct cv_module_snarf const PDB_STRING_TABLE* strimage; };
+BOOL pdb_hack_get_main_info(struct module_format *modfmt, HANDLE *file, unsigned *fpoext_stream) +{ + struct pdb_module_info* pdb_info; + + if (!modfmt) return FALSE; + pdb_info = modfmt->u.pdb_info; + *file = pdb_info->pdb_files[0].file_handle; + if (fpoext_stream) + *fpoext_stream = pdb_info->pdb_files[0].fpoext_stream; + return TRUE; +} + /*======================================================================== * Debug file access helper routines */ @@ -3260,6 +3272,8 @@ static void pdb_module_remove(struct process* pcsn, struct module_format* modfmt UnmapViewOfFile(modfmt->u.pdb_info->pdb_files[i].image); if (modfmt->u.pdb_info->pdb_files[i].hMap) CloseHandle(modfmt->u.pdb_info->pdb_files[i].hMap); + if (modfmt->u.pdb_info->pdb_files[i].file_handle) + CloseHandle(modfmt->u.pdb_info->pdb_files[i].file_handle); } HeapFree(GetProcessHeap(), 0, modfmt); } @@ -3785,13 +3799,21 @@ static BOOL pdb_process_internal(const struct process *pcs, CloseHandle(hFile); return FALSE; } - CloseHandle(hFile); + if (!pdb_init(pdb_file, image)) { + CloseHandle(hFile); CloseHandle(hMap); UnmapViewOfFile(image); return FALSE; } + if (getenv("WINE_DBGHELP_OLD_PDB")) /* keep using old pdb reader */ + { + pdb_file->file_handle = NULL; + CloseHandle(hFile); + } + else + pdb_file->file_handle = hFile;
pdb_file->hMap = hMap; pdb_file->image = image; @@ -4000,356 +4022,6 @@ static BOOL pdb_process_file(const struct process *pcs, return FALSE; }
-/*======================================================================== - * 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; -}; - -static void pev_set_error(struct pevaluator* pev, const char* msg, ...) __WINE_PRINTF_ATTR(2,3); -static void pev_set_error(struct pevaluator* pev, const char* msg, ...) -{ - va_list args; - - va_start(args, msg); - vsnprintf(pev->error, sizeof(pev->error), msg, args); - va_end(args); -} - -#if 0 -static void pev_dump_stack(struct pevaluator* pev) -{ - unsigned i; - struct hash_table_iter hti; - - 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)); - } - hash_table_iter_init(&pev->values, &hti, str); - FIXME("hash\n"); - while ((ptr = hash_table_iter_up(&hti))) - { - struct zvalue* zval = CONTAINING_RECORD(ptr, struct zvalue, elt); - FIXME("\t%s: Ix\n", zval->elt.name, zval->value); - } - -} -#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); - while ((ptr = hash_table_iter_up(&hti))) - { - if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, str)) - { - *val = CONTAINING_RECORD(ptr, struct zvalue, elt)->value; - return TRUE; - } - } - pev_set_error(pev, "get_zvalue: no value found (%s)", str); - return FALSE; - default: - *val = strtol(str, &n, 10); - if (n != str && *n == '\0') return TRUE; - pev_set_error(pev, "get_val: not a literal (%s)", str); - return FALSE; - } -} - -/* 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) - { - pev_set_error(pev, "push: out of memory"); - return FALSE; - } - *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) - { - pev_set_error(pev, "pop: stack empty"); - return FALSE; - } - 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); - while ((ptr = hash_table_iter_up(&hti))) - { - if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, name)) - { - CONTAINING_RECORD(ptr, struct zvalue, elt)->value = val; - break; - } - } - if (!ptr) - { - struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv)); - if (!zv) - { - pev_set_error(pev, "set_value: out of memory"); - return FALSE; - } - zv->value = val; - - zv->elt.name = pool_strdup(&pev->pool, name); - hash_table_add(&pev->values, &zv->elt); - } - 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, &v2) || !pev_pop_val(pev, &v1)) return FALSE; - if ((op == '/' || op == '%') && v2 == 0) - { - pev_set_error(pev, "binop: division by zero"); - 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: - pev_set_error(pev, "binop: unknown op (%c)", op); - return FALSE; - } - snprintf(res, sizeof(res), "%Id", 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 = 0; - - if (!pev_pop_val(pev, &v1)) return FALSE; - if (!sw_read_mem(pev->csw, v1, &v2, pev->csw->cpu->word_size)) - { - pev_set_error(pev, "deref: cannot read mem at %Ix", v1); - return FALSE; - } - snprintf(res, sizeof(res), "%Id", 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] != '$') - { - pev_set_error(pev, "assign: %s isn't a variable", p2); - return FALSE; - } - pev_set_value(pev, p2, v1); - - return TRUE; -} - -/* initializes the postfix evaluator */ -static void pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw, - const PDB_FPO_DATA* fpoext, struct pdb_cmd_pair* cpair) -{ - pev->csw = csw; - pool_init(&pev->pool, 512); - vector_init(&pev->stack, sizeof(char*), 0); - 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; - - if (!cmd) return FALSE; - 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_set_error(&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", debugstr_a(cmd), pev.error); - pev_free(&pev, NULL); - return FALSE; -} - -BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, - union ctx *context, struct pdb_cmd_pair *cpair) -{ - struct module_pair pair; - struct pdb_module_info* pdb_info; - PDB_FPO_DATA* fpoext; - unsigned i, size; - PDB_STRING_TABLE* strbase; - BOOL ret = TRUE; - - if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; - if (!pair.effective->format_info[DFI_PDB]) return FALSE; - pdb_info = pair.effective->format_info[DFI_PDB]->u.pdb_info; - TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); - ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; - - strbase = pdb_read_strings(&pdb_info->pdb_files[0]); - if (!strbase) return FALSE; - fpoext = pdb_read_stream(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); - size = pdb_get_stream_size(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); - 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, - debugstr_a(pdb_get_string_table_entry(strbase, fpoext[i].str_offset))); - ret = pdb_parse_cmd_string(csw, &fpoext[i], - pdb_get_string_table_entry(strbase, fpoext[i].str_offset), - cpair); - break; - } - } - } - else ret = FALSE; - pdb_free(fpoext); - pdb_free(strbase); - - return ret; -} - /*======================================================================== * Process CodeView debug information. */ @@ -4675,3 +4347,49 @@ DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info)
return msc_get_file_indexinfo(image, dbg, num_directories, info); } + +BOOL pdb_old_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, + union ctx *context, struct pdb_cmd_pair *cpair) +{ + struct module_pair pair; + struct pdb_module_info* pdb_info; + PDB_FPO_DATA* fpoext; + unsigned i, size; + PDB_STRING_TABLE* strbase; + BOOL ret = TRUE; + + if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; + if (!pair.effective->format_info[DFI_PDB]) return FALSE; + pdb_info = pair.effective->format_info[DFI_PDB]->u.pdb_info; + TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); + ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; + + strbase = pdb_read_strings(&pdb_info->pdb_files[0]); + if (!strbase) return FALSE; + fpoext = pdb_read_stream(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); + size = pdb_get_stream_size(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); + 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, + debugstr_a(pdb_get_string_table_entry(strbase, fpoext[i].str_offset))); + ret = pdb_fpo_unwind_parse_cmd_string(csw, &fpoext[i], + pdb_get_string_table_entry(strbase, fpoext[i].str_offset), + cpair); + break; + } + } + } + else ret = FALSE; + pdb_free(fpoext); + pdb_free(strbase); + + return ret; +} diff --git a/dlls/dbghelp/pdb.c b/dlls/dbghelp/pdb.c new file mode 100644 index 00000000000..d3813e16ee8 --- /dev/null +++ b/dlls/dbghelp/pdb.c @@ -0,0 +1,789 @@ +/* + * File pdb.c - read debug information out of PDB files. + * + * Copyright (C) 1996, Eric Youngdale. + * Copyright (C) 1999-2000, Ulrich Weigand. + * Copyright (C) 2004-2009, Eric Pouech. + * Copyright (C) 2004-2025, Eric Pouech for CodeWeavers. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <assert.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winternl.h" + +#include "wine/exception.h" +#include "wine/debug.h" +#include "dbghelp_private.h" +#include "wine/mscvpdb.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_pdb); + +/* Note: this file contains the new implementation for reading PDB files. + * msc.c contains the old implementation. + */ + +/*======================================================================== + * PDB reader. + * Design goal: + * - maximize on-the-fly operations (doesn't use dbghelp internal representation) + * - limit loaded and cached memory size + * Limitations: + * - doesn't support old JG format (could be added, but to be proven worthwile) + */ + +/* Note: + * - we use integer with known size to replicate serialized data inside the PDB file + * and plain integers for the rest of the code. + * - except for file offset and stream offsets + * - functions prefixed with pdb_reader_internal are for internal helpers and shouldn't be used + */ + +/* some internal types */ +typedef uint64_t pdboff_t; /* offset in whole PDB file (64bit) */ +typedef uint32_t pdbsize_t; /* size inside a stream (including offset from beg of stream) (2G max) */ + +struct pdb_reader; +typedef enum pdb_result (*pdb_reader_fetch_t)(struct pdb_reader *pdb, void *buffer, pdboff_t offset, pdbsize_t size); + +struct pdb_reader +{ + HANDLE file; + HANDLE heap; + + /* header */ + unsigned block_size; + struct PDB_DS_TOC *toc; + + /* stream information */ + struct + { + const uint32_t *blocks; /* points into toc */ + char *name; + } *streams; + char *stream_names; + + pdb_reader_fetch_t fetch; +}; + +enum pdb_result +{ + R_PDB_SUCCESS, + R_PDB_IOERROR, + R_PDB_OUT_OF_MEMORY, + R_PDB_INVALID_ARGUMENT, + R_PDB_INVALID_PDB_FILE, + R_PDB_BUFFER_TOO_SMALL, +}; + +static enum pdb_result pdb_reader_fetch_file(struct pdb_reader *pdb, void *buffer, pdboff_t offset, pdbsize_t size) +{ + OVERLAPPED ov = {.Offset = offset, .OffsetHigh = offset >> 32, .hEvent = (HANDLE)(DWORD_PTR)1}; + DWORD num_read; + + return ReadFile(pdb->file, buffer, size, &num_read, &ov) && num_read == size ? R_PDB_SUCCESS : R_PDB_IOERROR; +} + +static const char PDB_JG_IDENT[] = "Microsoft C/C++ program database 2.00\r\n\032JG\0"; +static const char PDB_DS_IDENT[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0"; + +static inline enum pdb_result pdb_reader_alloc(struct pdb_reader *pdb, size_t size, void **ptr) +{ + return (*ptr = HeapAlloc(pdb->heap, 0, size)) ? R_PDB_SUCCESS : R_PDB_OUT_OF_MEMORY; +} + +static inline enum pdb_result pdb_reader_realloc(struct pdb_reader *pdb, void **ptr, size_t size) +{ + void *new = HeapReAlloc(pdb->heap, 0, *ptr, size); + if (!new) return R_PDB_OUT_OF_MEMORY; + *ptr = new; + return R_PDB_SUCCESS; +} + +static inline void pdb_reader_free(struct pdb_reader *pdb, void *ptr) +{ + HeapFree(pdb->heap, 0, ptr); +} + +static inline unsigned pdb_reader_num_blocks(struct pdb_reader *pdb, pdbsize_t size) +{ + return (size + pdb->block_size - 1) / pdb->block_size; +} + +static enum pdb_result pdb_reader_get_stream_size(struct pdb_reader *pdb, unsigned stream_id, pdbsize_t *size) +{ + if (stream_id >= pdb->toc->num_streams) return R_PDB_INVALID_ARGUMENT; + *size = pdb->toc->stream_size[stream_id]; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_internal_read_from_blocks(struct pdb_reader *pdb, const uint32_t *blocks, pdbsize_t delta, + void *buffer, pdbsize_t size, pdbsize_t *num_read) +{ + enum pdb_result result; + pdbsize_t initial_size = size; + pdbsize_t toread; + + while (size) + { + toread = min(pdb->block_size - delta, size); + + if ((result = (*pdb->fetch)(pdb, buffer, (pdboff_t)*blocks * pdb->block_size + delta, toread))) + return result; + size -= toread; + blocks++; + buffer = (char*)buffer + toread; + delta = 0; + } + + if (num_read) *num_read = initial_size - size; + return size != initial_size ? R_PDB_SUCCESS : R_PDB_INVALID_ARGUMENT; +} + +struct pdb_reader_walker +{ + unsigned stream_id; + pdbsize_t offset; + pdbsize_t last; +}; + +static inline enum pdb_result pdb_reader_walker_init(struct pdb_reader *pdb, unsigned stream_id, struct pdb_reader_walker *walker) +{ + walker->stream_id = stream_id; + walker->offset = 0; + return pdb_reader_get_stream_size(pdb, stream_id, &walker->last); +} + +static enum pdb_result pdb_reader_read_from_stream(struct pdb_reader *pdb, const struct pdb_reader_walker *walker, + void *buffer, pdbsize_t size, pdbsize_t *num_read) +{ + enum pdb_result result; + const uint32_t *blocks; + pdbsize_t delta; + + if (walker->stream_id >= pdb->toc->num_streams) return R_PDB_INVALID_ARGUMENT; + if (walker->offset >= pdb->toc->stream_size[walker->stream_id]) return R_PDB_INVALID_ARGUMENT; + if (walker->offset >= walker->last) return R_PDB_INVALID_ARGUMENT; + blocks = pdb->streams[walker->stream_id].blocks + walker->offset / pdb->block_size; + + if (walker->offset + size > pdb->toc->stream_size[walker->stream_id]) + { + size = pdb->toc->stream_size[walker->stream_id] - walker->offset; + } + if (walker->offset + size > walker->last) + { + size = walker->last - walker->offset; + } + delta = walker->offset % pdb->block_size; + + if ((result = pdb_reader_internal_read_from_blocks(pdb, blocks, delta, buffer, size, num_read))) + return result; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_init(struct pdb_reader *pdb, HANDLE file, HANDLE heap) +{ + enum pdb_result result; + struct PDB_DS_HEADER hdr; + struct PDB_DS_TOC *toc = NULL; + unsigned i; + unsigned toc_blocks_size; + uint32_t *toc_blocks = NULL; + uint32_t *blocks; + + memset(pdb, 0, sizeof(*pdb)); + pdb->file = file; + pdb->heap = heap; + pdb->fetch = &pdb_reader_fetch_file; + + if ((result = (*pdb->fetch)(pdb, &hdr, 0, sizeof(hdr)))) return result; + if (!memcmp(hdr.signature, PDB_JG_IDENT, sizeof(PDB_JG_IDENT))) + { + FIXME("PDB reader doesn't support old PDB JG file format\n"); + return R_PDB_INVALID_PDB_FILE; + } + if (memcmp(hdr.signature, PDB_DS_IDENT, sizeof(PDB_DS_IDENT))) + { + ERR("PDB reader doesn't recognize format (%s)\n", wine_dbgstr_a((char*)&hdr)); + return R_PDB_INVALID_PDB_FILE; + } + pdb->block_size = hdr.block_size; + toc_blocks_size = pdb_reader_num_blocks(pdb, hdr.toc_size) * sizeof(uint32_t); + if ((result = pdb_reader_alloc(pdb, toc_blocks_size, (void**)&toc_blocks)) || + (result = (*pdb->fetch)(pdb, toc_blocks, (pdboff_t)hdr.toc_block * hdr.block_size, toc_blocks_size)) || + (result = pdb_reader_alloc(pdb, hdr.toc_size, (void**)&toc)) || + (result = pdb_reader_internal_read_from_blocks(pdb, toc_blocks, 0, toc, hdr.toc_size, NULL)) || + (result = pdb_reader_alloc(pdb, toc->num_streams * sizeof(pdb->streams[0]), (void**)&pdb->streams))) + goto failure; + pdb_reader_free(pdb, toc_blocks); + + pdb->toc = toc; + blocks = &toc->stream_size[toc->num_streams]; + for (i = 0; i < pdb->toc->num_streams; i++) + { + if (toc->stream_size[i] == 0 || toc->stream_size[i] == ~0u) + { + pdb->streams[i].blocks = NULL; + pdb->toc->stream_size[i] = 0; + } + else + { + pdb->streams[i].blocks = blocks; + blocks += pdb_reader_num_blocks(pdb, toc->stream_size[i]); + } + pdb->streams[i].name = NULL; + } + return R_PDB_SUCCESS; + +failure: + WARN("Failed to load PDB header\n"); + pdb_reader_free(pdb, toc); + pdb_reader_free(pdb, toc_blocks); + return result; +} + +static void pdb_reader_dispose(struct pdb_reader *pdb) +{ + unsigned i; + + for (i = 0; i < pdb->toc->num_streams; i++) + pdb_reader_free(pdb, pdb->streams[i].name); + pdb_reader_free(pdb, pdb->streams); + pdb_reader_free(pdb, pdb->toc); +} + +static enum pdb_result pdb_reader_internal_read_advance(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + void *buffer, pdbsize_t size) +{ + pdbsize_t num_read; + enum pdb_result result = pdb_reader_read_from_stream(pdb, walker, buffer, size, &num_read); + if (result) return result; + if (num_read != size) return R_PDB_INVALID_ARGUMENT; + walker->offset += size; + return R_PDB_SUCCESS; +} +/* Handy macro to deserialize: ensure that read length is the type length, and advance offset in case of success */ +#define pdb_reader_READ(pdb, walker, ptr) pdb_reader_internal_read_advance((pdb), (walker), (ptr), sizeof(*(ptr))) + +static enum pdb_result pdb_reader_alloc_and_read(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + pdbsize_t size, void **buffer) +{ + enum pdb_result result; + + if (walker->offset + size > walker->last) return R_PDB_INVALID_ARGUMENT; + if ((result = pdb_reader_alloc(pdb, size, buffer))) return result; + if ((result = pdb_reader_internal_read_advance(pdb, walker, *buffer, size))) + { + pdb_reader_free(pdb, *buffer); + *buffer = NULL; + return result; + } + return R_PDB_SUCCESS; +} + + +static enum pdb_result pdb_reader_fetch_string_from_stream(struct pdb_reader *pdb, struct pdb_reader_walker *walker, char *buffer, pdbsize_t length) +{ + enum pdb_result result; + pdbsize_t num_read; + char *zero; + + if ((result = pdb_reader_read_from_stream(pdb, walker, buffer, length, &num_read))) + return result; + if (!(zero = memchr(buffer, '\0', num_read))) + return num_read == length ? R_PDB_BUFFER_TOO_SMALL : R_PDB_INVALID_ARGUMENT; + walker->offset += zero - buffer + 1; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_load_stream_name_table(struct pdb_reader *pdb) +{ + struct pdb_reader_walker walker; + struct pdb_reader_walker ok_bits_walker; + struct PDB_DS_ROOT ds_root; + enum pdb_result result; + uint32_t count, numok, len, bitfield; + unsigned i; + + if ((result = pdb_reader_walker_init(pdb, 1, &walker)) || + (result = pdb_reader_READ(pdb, &walker, &ds_root))) + return result; + + if (ds_root.Version != 20000404) + { + ERR("-Unknown root block version %u\n", ds_root.Version); + return R_PDB_INVALID_ARGUMENT; + } + + if ((result = pdb_reader_alloc_and_read(pdb, &walker, ds_root.cbNames, (void**)&pdb->stream_names))) + goto failure; + + if ((result = pdb_reader_READ(pdb, &walker, &numok)) || + (result = pdb_reader_READ(pdb, &walker, &count))) + goto failure; + + /* account bitfield vector */ + if ((result = pdb_reader_READ(pdb, &walker, &len))) goto failure; + ok_bits_walker = walker; + walker.offset += len * sizeof(uint32_t); + + /* skip deleted vector */ + if ((result = pdb_reader_READ(pdb, &walker, &len))) goto failure; + walker.offset += len * sizeof(uint32_t); + + for (i = 0; i < count; i++) + { + if ((i & 31u) == 0) + { + if ((result = pdb_reader_READ(pdb, &ok_bits_walker, &bitfield))) + goto failure; + } + if (bitfield & (1u << (i & 31))) + { + uint32_t str_offset, stream_id; + if ((result = pdb_reader_READ(pdb, &walker, &str_offset)) || + (result = pdb_reader_READ(pdb, &walker, &stream_id))) + goto failure; + pdb->streams[stream_id].name = pdb->stream_names + str_offset; + } + } + return R_PDB_SUCCESS; +failure: + pdb_reader_free(pdb, pdb->stream_names); + pdb->stream_names = NULL; + return result; +} + +static enum pdb_result pdb_reader_get_stream_index_from_name(struct pdb_reader *pdb, const char *name, + unsigned *stream_id) +{ + unsigned i; + + if (!pdb->stream_names) + { + enum pdb_result result = pdb_reader_load_stream_name_table(pdb); + if (result) return result; + } + for (i = 0; i < pdb->toc->num_streams; i++) + if (pdb->streams[i].name && !strcmp(pdb->streams[i].name, name)) + { + *stream_id = i; + return R_PDB_SUCCESS; + } + return R_PDB_INVALID_ARGUMENT; +} + +static enum pdb_result pdb_reader_alloc_and_fetch_string(struct pdb_reader *pdb, struct pdb_reader_walker *walker, char **string) +{ + static const unsigned int alloc_step = 256; + enum pdb_result result; + unsigned len = alloc_step; + char *buffer; + + /* get string by chunks of alloc_step bytes... */ + /* Note: we never shrink the alloc buffer to its optimal size */ + for (buffer = NULL;; len += alloc_step) + { + if ((result = pdb_reader_realloc(pdb, (void**)&buffer, len))) + { + pdb_reader_free(pdb, buffer); + return result; + } + result = pdb_reader_fetch_string_from_stream(pdb, walker, buffer + len - alloc_step, alloc_step); + if (result != R_PDB_BUFFER_TOO_SMALL) + { + if (result == R_PDB_SUCCESS) + *string = buffer; + else + pdb_reader_free(pdb, buffer); + return result; + } + walker->offset += alloc_step; + } +} + +static enum pdb_result pdb_reader_alloc_and_fetch_global_string(struct pdb_reader *pdb, pdbsize_t str_offset, char **buffer) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + unsigned stream_id; + + if ((result = pdb_reader_get_stream_index_from_name(pdb, "/names", &stream_id))) + return result; + if ((result = pdb_reader_walker_init(pdb, stream_id, &walker))) return result; + walker.offset = sizeof(PDB_STRING_TABLE) + str_offset; + return pdb_reader_alloc_and_fetch_string(pdb, &walker, buffer); +} + +/*======================================================================== + * 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; +}; + +static void pev_set_error(struct pevaluator* pev, const char* msg, ...) __WINE_PRINTF_ATTR(2,3); +static void pev_set_error(struct pevaluator* pev, const char* msg, ...) +{ + va_list args; + + va_start(args, msg); + vsnprintf(pev->error, sizeof(pev->error), msg, args); + va_end(args); +} + +#if 0 +static void pev_dump_stack(struct pevaluator* pev) +{ + unsigned i; + struct hash_table_iter hti; + + 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)); + } + hash_table_iter_init(&pev->values, &hti, str); + FIXME("hash\n"); + while ((ptr = hash_table_iter_up(&hti))) + { + struct zvalue* zval = CONTAINING_RECORD(ptr, struct zvalue, elt); + FIXME("\t%s: Ix\n", zval->elt.name, zval->value); + } + +} +#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); + while ((ptr = hash_table_iter_up(&hti))) + { + if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, str)) + { + *val = CONTAINING_RECORD(ptr, struct zvalue, elt)->value; + return TRUE; + } + } + pev_set_error(pev, "get_zvalue: no value found (%s)", str); + return FALSE; + default: + *val = strtol(str, &n, 10); + if (n != str && *n == '\0') return TRUE; + pev_set_error(pev, "get_val: not a literal (%s)", str); + return FALSE; + } +} + +/* 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) + { + pev_set_error(pev, "push: out of memory"); + return FALSE; + } + *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) + { + pev_set_error(pev, "pop: stack empty"); + return FALSE; + } + 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); + while ((ptr = hash_table_iter_up(&hti))) + { + if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, name)) + { + CONTAINING_RECORD(ptr, struct zvalue, elt)->value = val; + break; + } + } + if (!ptr) + { + struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv)); + if (!zv) + { + pev_set_error(pev, "set_value: out of memory"); + return FALSE; + } + zv->value = val; + + zv->elt.name = pool_strdup(&pev->pool, name); + hash_table_add(&pev->values, &zv->elt); + } + 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, &v2) || !pev_pop_val(pev, &v1)) return FALSE; + if ((op == '/' || op == '%') && v2 == 0) + { + pev_set_error(pev, "binop: division by zero"); + 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: + pev_set_error(pev, "binop: unknown op (%c)", op); + return FALSE; + } + snprintf(res, sizeof(res), "%Id", 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 = 0; + + if (!pev_pop_val(pev, &v1)) return FALSE; + if (!sw_read_mem(pev->csw, v1, &v2, pev->csw->cpu->word_size)) + { + pev_set_error(pev, "deref: cannot read mem at %Ix", v1); + return FALSE; + } + snprintf(res, sizeof(res), "%Id", 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] != '$') + { + pev_set_error(pev, "assign: %s isn't a variable", p2); + return FALSE; + } + pev_set_value(pev, p2, v1); + + return TRUE; +} + +/* initializes the postfix evaluator */ +static void pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw, + const PDB_FPO_DATA* fpoext, struct pdb_cmd_pair* cpair) +{ + pev->csw = csw; + pool_init(&pev->pool, 512); + vector_init(&pev->stack, sizeof(char*), 0); + 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; +} + +BOOL pdb_fpo_unwind_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; + + if (!cmd) return FALSE; + 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_set_error(&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", debugstr_a(cmd), pev.error); + pev_free(&pev, NULL); + return FALSE; +} + +BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, + union ctx *context, struct pdb_cmd_pair *cpair) +{ + struct pdb_reader_walker walker; + struct pdb_reader pdb; + struct module_pair pair; + HANDLE file_handle; + unsigned fpoext_stream; + PDB_FPO_DATA fpoext; + BOOL ret = FALSE; + + if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; + if (!pdb_hack_get_main_info(pair.effective->format_info[DFI_PDB], &file_handle, &fpoext_stream)) return FALSE; + + if (!file_handle) + return pdb_old_virtual_unwind(csw, ip, context, cpair); + TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); + ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; + + if (pdb_reader_init(&pdb, file_handle, pair.effective->pool.heap)) + return FALSE; + + if (!pdb_reader_walker_init(&pdb, fpoext_stream, &walker) && + (walker.last % sizeof(fpoext)) == 0) + { + /* FIXME likely a binary search should be more appropriate here */ + while (pdb_reader_READ(&pdb, &walker, &fpoext) == R_PDB_SUCCESS) + { + if (fpoext.start <= ip && ip < fpoext.start + fpoext.func_size) + { + char *cmd; + + if (pdb_reader_alloc_and_fetch_global_string(&pdb, fpoext.str_offset, &cmd)) break; + TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n", + fpoext.start, fpoext.func_size, fpoext.locals_size, + fpoext.params_size, fpoext.maxstack_size, fpoext.prolog_size, + fpoext.savedregs_size, fpoext.flags, + debugstr_a(cmd)); + ret = pdb_fpo_unwind_parse_cmd_string(csw, &fpoext, cmd, cpair); + pdb_reader_free(&pdb, cmd); + break; + } + } + } + pdb_reader_dispose(&pdb); + + return ret; +} + diff --git a/dlls/dbghelp/storage.c b/dlls/dbghelp/storage.c index 0589ed699ee..d3fea475901 100644 --- a/dlls/dbghelp/storage.c +++ b/dlls/dbghelp/storage.c @@ -50,10 +50,6 @@ void* pool_realloc(struct pool* pool, void* ptr, size_t len)
void pool_free(struct pool* pool, void* ptr) { -#ifdef USE_STATS - if (ptr) - mem_stats_down(&pool->stats, HeapSize(pool->heap, 0, ptr)); -#endif HeapFree(pool->heap, 0, ptr); }
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 5 +++- dlls/dbghelp/msc.c | 39 ++++++++++++++---------- dlls/dbghelp/pdb.c | 54 ++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 42 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 4bb56fee46d..c669109a7f9 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -992,4 +992,7 @@ extern BOOL pdb_fpo_unwind_parse_cmd_string(struct cpu_stack_walk* csw, struct _ const char* cmd, struct pdb_cmd_pair* cpair); extern BOOL pdb_old_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context, struct pdb_cmd_pair *cpair); -extern BOOL pdb_hack_get_main_info(struct module_format *modfmt, HANDLE *file, unsigned *fpoext_stream); +struct pdb_reader; +extern BOOL pdb_hack_get_main_info(struct module_format *modfmt, struct pdb_reader **pdb, unsigned *fpoext_stream); +extern void pdb_reader_dispose(struct pdb_reader *pdb); +extern struct pdb_reader *pdb_hack_reader_init(struct module *module, HANDLE file); diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 8acd4e70f3a..b3e15e2eda3 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -61,8 +61,7 @@ enum pdb_kind {PDB_JG, PDB_DS}; struct pdb_file_info { enum pdb_kind kind; - HANDLE file_handle; - HANDLE hMap; + struct pdb_reader *pdb_reader; /* new pdb reader */ const char* image; struct pdb_stream_name* stream_dict; unsigned fpoext_stream; @@ -97,13 +96,13 @@ struct cv_module_snarf const PDB_STRING_TABLE* strimage; };
-BOOL pdb_hack_get_main_info(struct module_format *modfmt, HANDLE *file, unsigned *fpoext_stream) +BOOL pdb_hack_get_main_info(struct module_format *modfmt, struct pdb_reader **pdb, unsigned *fpoext_stream) { struct pdb_module_info* pdb_info;
if (!modfmt) return FALSE; pdb_info = modfmt->u.pdb_info; - *file = pdb_info->pdb_files[0].file_handle; + *pdb = pdb_info->pdb_files[0].pdb_reader; if (fpoext_stream) *fpoext_stream = pdb_info->pdb_files[0].fpoext_stream; return TRUE; @@ -3174,7 +3173,7 @@ static void pdb_free(void* buffer) HeapFree(GetProcessHeap(), 0, buffer); }
-static void pdb_free_file(struct pdb_file_info* pdb_file) +static void pdb_free_file(struct pdb_file_info* pdb_file, BOOL unmap) { switch (pdb_file->kind) { @@ -3188,6 +3187,12 @@ static void pdb_free_file(struct pdb_file_info* pdb_file) break; } HeapFree(GetProcessHeap(), 0, pdb_file->stream_dict); + pdb_file->stream_dict = NULL; + if (unmap) + { + UnmapViewOfFile(pdb_file->image); + pdb_file->image = NULL; + } }
static struct pdb_stream_name* pdb_load_stream_name_table(const char* str, unsigned cb) @@ -3267,13 +3272,11 @@ static void pdb_module_remove(struct process* pcsn, struct module_format* modfmt
for (i = 0; i < modfmt->u.pdb_info->used_subfiles; i++) { - pdb_free_file(&modfmt->u.pdb_info->pdb_files[i]); + pdb_free_file(&modfmt->u.pdb_info->pdb_files[i], TRUE); if (modfmt->u.pdb_info->pdb_files[i].image) UnmapViewOfFile(modfmt->u.pdb_info->pdb_files[i].image); - if (modfmt->u.pdb_info->pdb_files[i].hMap) - CloseHandle(modfmt->u.pdb_info->pdb_files[i].hMap); - if (modfmt->u.pdb_info->pdb_files[i].file_handle) - CloseHandle(modfmt->u.pdb_info->pdb_files[i].file_handle); + if (modfmt->u.pdb_info->pdb_files[i].pdb_reader) + pdb_reader_dispose(modfmt->u.pdb_info->pdb_files[i].pdb_reader); } HeapFree(GetProcessHeap(), 0, modfmt); } @@ -3800,22 +3803,26 @@ static BOOL pdb_process_internal(const struct process *pcs, return FALSE; }
+ CloseHandle(hMap); + /* old pdb reader */ if (!pdb_init(pdb_file, image)) { CloseHandle(hFile); - CloseHandle(hMap); UnmapViewOfFile(image); return FALSE; } if (getenv("WINE_DBGHELP_OLD_PDB")) /* keep using old pdb reader */ { - pdb_file->file_handle = NULL; + pdb_file->pdb_reader = NULL; CloseHandle(hFile); } - else - pdb_file->file_handle = hFile; + else if (!(pdb_file->pdb_reader = pdb_hack_reader_init(msc_dbg->module, hFile))) + { + CloseHandle(hFile); + UnmapViewOfFile(image); + return FALSE; + }
- pdb_file->hMap = hMap; pdb_file->image = image; symbols_image = pdb_read_stream(pdb_file, 3); if (symbols_image) @@ -3960,6 +3967,8 @@ static BOOL pdb_process_internal(const struct process *pcs, pdb_free(symbols_image); pdb_free(files_image);
+ pdb_free_file(pdb_file, pdb_file->pdb_reader != NULL); + return TRUE; }
diff --git a/dlls/dbghelp/pdb.c b/dlls/dbghelp/pdb.c index d3813e16ee8..7948dfd5f0b 100644 --- a/dlls/dbghelp/pdb.c +++ b/dlls/dbghelp/pdb.c @@ -67,8 +67,10 @@ typedef enum pdb_result (*pdb_reader_fetch_t)(struct pdb_reader *pdb, void *buff
struct pdb_reader { + struct module *module; HANDLE file; - HANDLE heap; + /* using ad hoc pool (not the module one), so that we can measure memory of each PDB reader during transition */ + struct pool pool;
/* header */ unsigned block_size; @@ -108,12 +110,12 @@ static const char PDB_DS_IDENT[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0";
static inline enum pdb_result pdb_reader_alloc(struct pdb_reader *pdb, size_t size, void **ptr) { - return (*ptr = HeapAlloc(pdb->heap, 0, size)) ? R_PDB_SUCCESS : R_PDB_OUT_OF_MEMORY; + return (*ptr = pool_alloc(&pdb->pool, size)) ? R_PDB_SUCCESS : R_PDB_OUT_OF_MEMORY; }
static inline enum pdb_result pdb_reader_realloc(struct pdb_reader *pdb, void **ptr, size_t size) { - void *new = HeapReAlloc(pdb->heap, 0, *ptr, size); + void *new = pool_realloc(&pdb->pool, *ptr, size); if (!new) return R_PDB_OUT_OF_MEMORY; *ptr = new; return R_PDB_SUCCESS; @@ -121,7 +123,7 @@ static inline enum pdb_result pdb_reader_realloc(struct pdb_reader *pdb, void **
static inline void pdb_reader_free(struct pdb_reader *pdb, void *ptr) { - HeapFree(pdb->heap, 0, ptr); + pool_free(&pdb->pool, ptr); }
static inline unsigned pdb_reader_num_blocks(struct pdb_reader *pdb, pdbsize_t size) @@ -200,7 +202,7 @@ static enum pdb_result pdb_reader_read_from_stream(struct pdb_reader *pdb, const return R_PDB_SUCCESS; }
-static enum pdb_result pdb_reader_init(struct pdb_reader *pdb, HANDLE file, HANDLE heap) +static enum pdb_result pdb_reader_init(struct pdb_reader *pdb, struct module *module, HANDLE file) { enum pdb_result result; struct PDB_DS_HEADER hdr; @@ -211,8 +213,9 @@ static enum pdb_result pdb_reader_init(struct pdb_reader *pdb, HANDLE file, HAND uint32_t *blocks;
memset(pdb, 0, sizeof(*pdb)); + pdb->module = module; pdb->file = file; - pdb->heap = heap; + pool_init(&pdb->pool, 65536); pdb->fetch = &pdb_reader_fetch_file;
if ((result = (*pdb->fetch)(pdb, &hdr, 0, sizeof(hdr)))) return result; @@ -261,14 +264,10 @@ failure: return result; }
-static void pdb_reader_dispose(struct pdb_reader *pdb) +void pdb_reader_dispose(struct pdb_reader *pdb) { - unsigned i; - - for (i = 0; i < pdb->toc->num_streams; i++) - pdb_reader_free(pdb, pdb->streams[i].name); - pdb_reader_free(pdb, pdb->streams); - pdb_reader_free(pdb, pdb->toc); + CloseHandle(pdb->file); + pool_destroy(&pdb->pool); }
static enum pdb_result pdb_reader_internal_read_advance(struct pdb_reader *pdb, struct pdb_reader_walker *walker, @@ -434,6 +433,14 @@ static enum pdb_result pdb_reader_alloc_and_fetch_global_string(struct pdb_reade return pdb_reader_alloc_and_fetch_string(pdb, &walker, buffer); }
+struct pdb_reader *pdb_hack_reader_init(struct module *module, HANDLE file) +{ + struct pdb_reader *pdb = pool_alloc(&module->pool, sizeof(*pdb)); + if (pdb && pdb_reader_init(pdb, module, file) == R_PDB_SUCCESS) return pdb; + pool_free(&module->pool, pdb); + return NULL; +} + /*======================================================================== * FPO unwinding code */ @@ -741,49 +748,44 @@ done: BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context, struct pdb_cmd_pair *cpair) { + struct pdb_reader *pdb; struct pdb_reader_walker walker; - struct pdb_reader pdb; struct module_pair pair; - HANDLE file_handle; unsigned fpoext_stream; PDB_FPO_DATA fpoext; BOOL ret = FALSE;
if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; - if (!pdb_hack_get_main_info(pair.effective->format_info[DFI_PDB], &file_handle, &fpoext_stream)) return FALSE; + if (!pdb_hack_get_main_info(pair.effective->format_info[DFI_PDB], &pdb, &fpoext_stream)) return FALSE;
- if (!file_handle) + if (!pdb) return pdb_old_virtual_unwind(csw, ip, context, cpair); TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); ip -= (DWORD_PTR)pair.effective->module.BaseOfImage;
- if (pdb_reader_init(&pdb, file_handle, pair.effective->pool.heap)) - return FALSE; - - if (!pdb_reader_walker_init(&pdb, fpoext_stream, &walker) && + if (!pdb_reader_walker_init(pdb, fpoext_stream, &walker) && (walker.last % sizeof(fpoext)) == 0) { /* FIXME likely a binary search should be more appropriate here */ - while (pdb_reader_READ(&pdb, &walker, &fpoext) == R_PDB_SUCCESS) + while (pdb_reader_READ(pdb, &walker, &fpoext) == R_PDB_SUCCESS) { if (fpoext.start <= ip && ip < fpoext.start + fpoext.func_size) { char *cmd;
- if (pdb_reader_alloc_and_fetch_global_string(&pdb, fpoext.str_offset, &cmd)) break; + if (pdb_reader_alloc_and_fetch_global_string(pdb, fpoext.str_offset, &cmd)) break; TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n", fpoext.start, fpoext.func_size, fpoext.locals_size, fpoext.params_size, fpoext.maxstack_size, fpoext.prolog_size, fpoext.savedregs_size, fpoext.flags, debugstr_a(cmd)); + ret = pdb_fpo_unwind_parse_cmd_string(csw, &fpoext, cmd, cpair); - pdb_reader_free(&pdb, cmd); + pdb_reader_free(pdb, cmd); break; } } } - pdb_reader_dispose(&pdb);
return ret; } -
From: Eric Pouech epouech@codeweavers.com
In following patches, we'll add a bunch of new interfaces here. Also, hide partially module_format walking with some helpers.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 41 +++++++++++++++++++++++++++++----- dlls/dbghelp/dwarf.c | 21 ++++++++++------- dlls/dbghelp/elf_module.c | 11 ++++++--- dlls/dbghelp/macho_module.c | 11 ++++++--- dlls/dbghelp/module.c | 11 ++++----- dlls/dbghelp/msc.c | 16 ++++++++----- dlls/dbghelp/pe_module.c | 11 ++++++--- dlls/dbghelp/symbol.c | 14 +++++------- dlls/dbghelp/type.c | 16 +++++-------- 9 files changed, 98 insertions(+), 54 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index c669109a7f9..fb55e4c89f7 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -414,14 +414,22 @@ enum format_info DFI_LAST };
-struct module_format +struct module_format; +struct module_format_vtable { - struct module* module; - void (*remove)(struct process* pcs, struct module_format* modfmt); - void (*loc_compute)(struct process* pcs, - const struct module_format* modfmt, + /* module handling */ + void (*remove)(struct module_format* modfmt); + /* stack walk */ + void (*loc_compute)(const struct module_format* modfmt, const struct symt_function* func, struct location* loc); +}; + +struct module_format +{ + struct module* module; + const struct module_format_vtable* vtable; + union { struct elf_module_info* elf_info; @@ -478,6 +486,29 @@ struct module struct wine_rb_tree sources_offsets_tree; };
+struct module_format_vtable_iterator +{ + int dfi; + struct module_format *modfmt; +}; + +#define MODULE_FORMAT_VTABLE_INDEX(f) (offsetof(struct module_format_vtable, f) / sizeof(void*)) + +static inline BOOL module_format_vtable_iterator_next(struct module *module, struct module_format_vtable_iterator *iter, size_t method_index) +{ + for ( ; iter->dfi < DFI_LAST; iter->dfi++) + { + iter->modfmt = module->format_info[iter->dfi]; + if (iter->modfmt && ((const void**)iter->modfmt->vtable)[method_index]) + { + iter->dfi++; + return TRUE; + } + } + iter->modfmt = NULL; + return FALSE; +} + typedef BOOL (*enum_modules_cb)(const WCHAR*, ULONG_PTR addr, void* user);
struct loader_ops diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 3971ff64988..86d41cd1970 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -3129,12 +3129,12 @@ static const dwarf2_cuhead_t* get_cuhead_from_func(const struct symt_function* f
static enum location_error compute_call_frame_cfa(struct module* module, ULONG_PTR ip, struct location* frame);
-static enum location_error loc_compute_frame(struct process* pcs, - const struct module_format* modfmt, +static enum location_error loc_compute_frame(const struct module_format* modfmt, const struct symt_function* func, DWORD_PTR ip, const dwarf2_cuhead_t* head, struct location* frame) { + struct process *pcs = modfmt->module->process; struct symt** psym = NULL; struct location* pframe; dwarf2_traverse_context_t lctx; @@ -4007,8 +4007,7 @@ static enum location_error compute_call_frame_cfa(struct module* module, ULONG_P return 0; }
-static void dwarf2_location_compute(struct process* pcs, - const struct module_format* modfmt, +static void dwarf2_location_compute(const struct module_format* modfmt, const struct symt_function* func, struct location* loc) { @@ -4026,10 +4025,11 @@ static void dwarf2_location_compute(struct process* pcs, } else { + struct process *pcs = modfmt->module->process; /* instruction pointer relative to compiland's start */ ip = pcs->localscope_pc - ((struct symt_compiland*)func->container)->address;
- if ((err = loc_compute_frame(pcs, modfmt, func, ip, head, &frame)) == 0) + if ((err = loc_compute_frame(modfmt, func, ip, head, &frame)) == 0) { switch (loc->kind) { @@ -4187,7 +4187,7 @@ static inline void dwarf2_fini_section(dwarf2_section_t* section) HeapFree(GetProcessHeap(), 0, (void*)section->address); }
-static void dwarf2_module_remove(struct process* pcs, struct module_format* modfmt) +static void dwarf2_module_remove(struct module_format* modfmt) { dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_loc); dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_frame); @@ -4293,6 +4293,12 @@ static BOOL dwarf2_unload_CU_module(dwarf2_parse_module_context_t* module_ctx) return TRUE; }
+static const struct module_format_vtable dwarf2_module_format_vtable = +{ + dwarf2_module_remove, + dwarf2_location_compute, +}; + BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, const struct elf_thunk_area* thunks, struct image_file_map* fmap) @@ -4340,8 +4346,7 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, goto leave; } dwarf2_modfmt->module = module; - dwarf2_modfmt->remove = dwarf2_module_remove; - dwarf2_modfmt->loc_compute = dwarf2_location_compute; + dwarf2_modfmt->vtable = &dwarf2_module_format_vtable; dwarf2_modfmt->u.dwarf2_info = (struct dwarf2_module_info_s*)(dwarf2_modfmt + 1); dwarf2_modfmt->u.dwarf2_info->word_size = fmap->addr_size / 8; /* set the word_size for eh_frame parsing */ dwarf2_modfmt->module->format_info[DFI_DWARF] = dwarf2_modfmt; diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index 8596d60483a..83c4ea898e8 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -602,7 +602,7 @@ BOOL elf_map_handle(HANDLE handle, struct image_file_map* fmap) return elf_map_file(&emfd, fmap); }
-static void elf_module_remove(struct process* pcs, struct module_format* modfmt) +static void elf_module_remove(struct module_format* modfmt) { image_unmap_file(&modfmt->u.elf_info->file_map); HeapFree(GetProcessHeap(), 0, modfmt); @@ -1142,6 +1142,12 @@ static BOOL elf_fetch_file_info(struct process* process, const WCHAR* name, ULON return TRUE; }
+static const struct module_format_vtable elf_module_format_vtable = +{ + elf_module_remove, + NULL, +}; + static BOOL elf_load_file_from_fmap(struct process* pcs, const WCHAR* filename, struct image_file_map* fmap, ULONG_PTR load_offset, ULONG_PTR dyn_addr, struct elf_info* elf_info) @@ -1253,8 +1259,7 @@ static BOOL elf_load_file_from_fmap(struct process* pcs, const WCHAR* filename, elf_module_info = (void*)(modfmt + 1); elf_info->module->format_info[DFI_ELF] = modfmt; modfmt->module = elf_info->module; - modfmt->remove = elf_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &elf_module_format_vtable; modfmt->u.elf_info = elf_module_info;
elf_module_info->elf_addr = load_offset; diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index 491e7188009..234136fa92d 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -1479,12 +1479,18 @@ static BOOL macho_fetch_file_info(struct process* process, const WCHAR* name, UL /****************************************************************** * macho_module_remove */ -static void macho_module_remove(struct process* pcs, struct module_format* modfmt) +static void macho_module_remove(struct module_format* modfmt) { macho_unmap_file(&modfmt->u.macho_info->file_map); HeapFree(GetProcessHeap(), 0, modfmt); }
+static const struct module_format_vtable macho_module_format_vtable = +{ + macho_module_remove, + NULL, +}; + /****************************************************************** * macho_load_file * @@ -1538,8 +1544,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, macho_info->module->format_info[DFI_MACHO] = modfmt;
modfmt->module = macho_info->module; - modfmt->remove = macho_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &macho_module_format_vtable; modfmt->u.macho_info = macho_module_info;
macho_module_info->load_addr = load_addr; diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index ce49ef2744a..3d0c5ba7549 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1023,9 +1023,8 @@ DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, */ BOOL module_remove(struct process* pcs, struct module* module) { - struct module_format*modfmt; + struct module_format_vtable_iterator iter = {}; struct module** p; - unsigned i;
TRACE("%s (%p)\n", debugstr_w(module->modulename), module);
@@ -1046,11 +1045,9 @@ BOOL module_remove(struct process* pcs, struct module* module) } } } - for (i = 0; i < DFI_LAST; i++) - { - if ((modfmt = module->format_info[i]) && modfmt->remove) - modfmt->remove(pcs, module->format_info[i]); - } + while (module_format_vtable_iterator_next(module, &iter, MODULE_FORMAT_VTABLE_INDEX(remove))) + iter.modfmt->vtable->remove(iter.modfmt); + hash_table_destroy(&module->ht_symbols); hash_table_destroy(&module->ht_types); HeapFree(GetProcessHeap(), 0, module->sources); diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index b3e15e2eda3..db06b186edb 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -2866,8 +2866,7 @@ static BOOL codeview_is_inside(const struct cv_local_info* locinfo, const struct return TRUE; }
-static void pdb_location_compute(struct process* pcs, - const struct module_format* modfmt, +static void pdb_location_compute(const struct module_format* modfmt, const struct symt_function* func, struct location* loc) { @@ -2880,7 +2879,7 @@ static void pdb_location_compute(struct process* pcs, locinfo->kind != 0; locinfo = (const struct cv_local_info*)((const char*)(locinfo + 1) + locinfo->ngaps * sizeof(locinfo->gaps[0]))) { - if (!codeview_is_inside(locinfo, func, pcs->localscope_pc)) continue; + if (!codeview_is_inside(locinfo, func, modfmt->module->process->localscope_pc)) continue; switch (locinfo->kind) { case S_DEFRANGE: @@ -3266,7 +3265,7 @@ static const char* pdb_get_string_table_entry(const PDB_STRING_TABLE* table, uns return (!table || offset >= table->length) ? NULL : (const char*)(table + 1) + offset; }
-static void pdb_module_remove(struct process* pcsn, struct module_format* modfmt) +static void pdb_module_remove(struct module_format* modfmt) { unsigned i;
@@ -3972,6 +3971,12 @@ static BOOL pdb_process_internal(const struct process *pcs, return TRUE; }
+static const struct module_format_vtable pdb_module_format_vtable = +{ + pdb_module_remove, + pdb_location_compute, +}; + static BOOL pdb_process_file(const struct process *pcs, const struct msc_debug_info *msc_dbg, const char *filename, const GUID *guid, DWORD timestamp, DWORD age) @@ -3991,8 +3996,7 @@ static BOOL pdb_process_file(const struct process *pcs, pdb_module_info = (void*)(modfmt + 1); msc_dbg->module->format_info[DFI_PDB] = modfmt; modfmt->module = msc_dbg->module; - modfmt->remove = pdb_module_remove; - modfmt->loc_compute = pdb_location_compute; + modfmt->vtable = &pdb_module_format_vtable; modfmt->u.pdb_info = pdb_module_info;
memset(cv_zmodules, 0, sizeof(cv_zmodules)); diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index bd3d6000535..1f2022fc1af 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -387,7 +387,7 @@ BOOL pe_unlock_region(struct module *module, const BYTE* region) return TRUE; }
-static void pe_module_remove(struct process* pcs, struct module_format* modfmt) +static void pe_module_remove(struct module_format* modfmt) { image_unmap_file(&modfmt->u.pe_info->fmap); HeapFree(GetProcessHeap(), 0, modfmt); @@ -802,6 +802,12 @@ static BOOL search_builtin_pe(void *param, HANDLE handle, const WCHAR *path) return TRUE; }
+static const struct module_format_vtable pe_module_format_vtable = +{ + pe_module_remove, + NULL, +}; + /****************************************************************** * pe_load_native_module * @@ -877,8 +883,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, { module->real_path = real_path ? pool_wcsdup(&module->pool, real_path) : NULL; modfmt->module = module; - modfmt->remove = pe_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &pe_module_format_vtable; module->format_info[DFI_PE] = modfmt; module->reloc_delta = base - PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, ImageBase); } diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 4fdd0a141be..7edf11a19b9 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -733,17 +733,13 @@ static void symt_fill_sym_info(struct module_pair* pair,
if (loc.kind >= loc_user) { - unsigned i; - struct module_format* modfmt; + struct module_format_vtable_iterator iter = {};
- for (i = 0; i < DFI_LAST; i++) + while ((module_format_vtable_iterator_next(pair->effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(loc_compute)))) { - modfmt = pair->effective->format_info[i]; - if (modfmt && modfmt->loc_compute) - { - modfmt->loc_compute(pair->pcs, modfmt, func, &loc); - break; - } + iter.modfmt->vtable->loc_compute(iter.modfmt, func, &loc); + break; } } switch (loc.kind) diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index a3ad80aacbb..b8bfd7ff369 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -1039,19 +1039,15 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case DataIsParam: { struct location loc = ((const struct symt_data*)type)->u.var; - unsigned i; - struct module_format* modfmt; + struct module_format_vtable_iterator iter = {};
if (loc.kind < loc_user) return FALSE; - for (i = 0; i < DFI_LAST; i++) + while ((module_format_vtable_iterator_next(module, &iter, + MODULE_FORMAT_VTABLE_INDEX(loc_compute)))) { - modfmt = module->format_info[i]; - if (modfmt && modfmt->loc_compute) - { - modfmt->loc_compute(module->process, modfmt, - (const struct symt_function*)((const struct symt_data*)type)->container, &loc); - break; - } + iter.modfmt->vtable->loc_compute(iter.modfmt, + (const struct symt_function*)((const struct symt_data*)type)->container, &loc); + break; } if (loc.kind != loc_absolute) return FALSE; V_VT(&X(VARIANT)) = VT_UI4; /* FIXME */