Module: wine Branch: master Commit: 56193155a01cbdace7bad303a472f07fe0e2d5c1 URL: https://gitlab.winehq.org/wine/wine/-/commit/56193155a01cbdace7bad303a472f07...
Author: Eric Pouech epouech@codeweavers.com Date: Tue Mar 5 17:52:26 2024 +0100
dbghelp: Use an intermediate buffer in SymFunctionTableAccess (x86_64).
This mainly allows to release internal resources bound to image. Also follow chained RUNTIME_FUNCTION entries (if any).
Signed-off-by: Eric Pouech epouech@codeweavers.com
---
dlls/dbghelp/cpu_x86_64.c | 49 +++++++++++++++++++++++++++--------------- dlls/dbghelp/dbghelp_private.h | 3 +++ dlls/dbghelp/pe_module.c | 46 +++++++++++++++++++++++++++++++++++++++ dlls/dbghelp/tests/dbghelp.c | 2 -- 4 files changed, 81 insertions(+), 19 deletions(-)
diff --git a/dlls/dbghelp/cpu_x86_64.c b/dlls/dbghelp/cpu_x86_64.c index eeae1f042b2..5193faee825 100644 --- a/dlls/dbghelp/cpu_x86_64.c +++ b/dlls/dbghelp/cpu_x86_64.c @@ -729,31 +729,46 @@ static BOOL x86_64_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame, static void* x86_64_find_runtime_function(struct module* module, DWORD64 addr) { #ifdef __x86_64__ - RUNTIME_FUNCTION* rtf; - ULONG size; - int min, max; + RUNTIME_FUNCTION *func = NULL; + const RUNTIME_FUNCTION *rtf; + ULONG size;
- rtf = (RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size); - if (rtf) for (min = 0, max = size / sizeof(*rtf); min <= max; ) + rtf = (const RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size); + if (rtf) { - int pos = (min + max) / 2; - if (addr < module->module.BaseOfImage + rtf[pos].BeginAddress) max = pos - 1; - else if (addr >= module->module.BaseOfImage + rtf[pos].EndAddress) min = pos + 1; - else + int lo, hi; + + for (lo = 0, hi = size / sizeof(*rtf); lo <= hi; ) { - rtf += pos; - while (rtf->UnwindData & 1) /* follow chained entry */ + int pos = (lo + hi) / 2; + if (addr < module->module.BaseOfImage + rtf[pos].BeginAddress) hi = pos - 1; + else if (addr >= module->module.BaseOfImage + rtf[pos].EndAddress) lo = pos + 1; + else if ((func = fetch_buffer(module->process, sizeof(*func)))) { - FIXME("RunTime_Function outside IMAGE_DIRECTORY_ENTRY_EXCEPTION unimplemented yet!\n"); - return NULL; - /* we need to read into the other process */ - /* rtf = (RUNTIME_FUNCTION*)(module->module.BaseOfImage + (rtf->UnwindData & ~1)); */ + *func = rtf[pos]; + while (func && (func->UnwindData & 1)) + { + const BYTE *next = pe_lock_region_from_rva(module, func->UnwindData & ~1, sizeof(*func), NULL); + if (next) + { + *func = *(const RUNTIME_FUNCTION *)next; + pe_unlock_region(module, next); + } + else + { + WARN("Couldn't find chained RUNTIME_FUNCTION\n"); + func = NULL; + } + } + break; } - return rtf; } + pe_unmap_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, (const char*)rtf); } -#endif + return func; +#else return NULL; +#endif }
static unsigned x86_64_map_dwarf_register(unsigned regno, const struct module* module, BOOL eh_frame) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 5677f6bfdb3..791f5ad6e14 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -781,7 +781,10 @@ extern struct module* extern BOOL pe_load_debug_info(const struct process* pcs, struct module* module); extern const char* pe_map_directory(struct module* module, int dirno, DWORD* size); +extern BOOL pe_unmap_directory(struct module* module, int dirno, const char*); extern DWORD pe_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info); +extern const BYTE* pe_lock_region_from_rva(struct module *module, DWORD rva, DWORD size, DWORD *length); +extern BOOL pe_unlock_region(struct module *module, const BYTE* region);
/* source.c */ extern unsigned source_new(struct module* module, const char* basedir, const char* source); diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 255c9f1832d..ebb4cf38db3 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -341,6 +341,52 @@ const char* pe_map_directory(struct module* module, int dirno, DWORD* size) nth->OptionalHeader.DataDirectory[dirno].VirtualAddress, NULL); }
+BOOL pe_unmap_directory(struct module* module, int dirno, const char *dir) +{ + if (module->type != DMT_PE || !module->format_info[DFI_PE]) return FALSE; + if (dirno >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return FALSE; + pe_unmap_full(&module->format_info[DFI_PE]->u.pe_info->fmap); + return TRUE; +} + +/* Locks a region from a mapped PE file, from its RVA, and for at least 'size' bytes. + * Region must fit entirely inside a PE section. + * 'length', upon success, gets the size from RVA until end of PE section. + */ +const BYTE* pe_lock_region_from_rva(struct module *module, DWORD rva, DWORD size, DWORD *length) +{ + IMAGE_NT_HEADERS* nth; + void* mapping; + IMAGE_SECTION_HEADER *section; + const BYTE *ret; + + if (module->type != DMT_PE || !module->format_info[DFI_PE]) return NULL; + if (!(mapping = pe_map_full(&module->format_info[DFI_PE]->u.pe_info->fmap, &nth))) + return NULL; + section = NULL; + ret = RtlImageRvaToVa(nth, mapping, rva, §ion); + if (ret) + { + if (rva + size <= section->VirtualAddress + section->SizeOfRawData) + { + if (length) + *length = section->VirtualAddress + section->SizeOfRawData - rva; + return ret; + } + if (rva + size <= section->VirtualAddress + section->Misc.VirtualSize) + FIXME("Not able to lock regions not present on file\n"); + } + pe_unmap_full(&module->format_info[DFI_PE]->u.pe_info->fmap); + return NULL; +} + +BOOL pe_unlock_region(struct module *module, const BYTE* region) +{ + if (module->type != DMT_PE || !module->format_info[DFI_PE] || !region) return FALSE; + pe_unmap_full(&module->format_info[DFI_PE]->u.pe_info->fmap); + return TRUE; +} + static void pe_module_remove(struct process* pcs, struct module_format* modfmt) { image_unmap_file(&modfmt->u.pe_info->fmap); diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 1ba4ecb6b30..ae757e1ae08 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -1523,10 +1523,8 @@ static void test_function_tables(void) SymInitialize(GetCurrentProcess(), NULL, TRUE); ptr1 = test_function_table_main_module(test_live_modules); ptr2 = test_function_table_main_module(test_function_tables); - todo_wine_if(ptr1) ok(ptr1 == ptr2, "Expecting unique storage area\n"); ptr2 = test_function_table_module("kernel32.dll", "CreateFileMappingA"); - todo_wine_if(ptr1) ok(ptr1 == ptr2, "Expecting unique storage area\n"); SymCleanup(GetCurrentProcess()); }