Commit 56193155 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

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: 's avatarEric Pouech <epouech@codeweavers.com>
parent da22ef6c
......@@ -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)
......
......@@ -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);
......
......@@ -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, &section);
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);
......
......@@ -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());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment