Second part: - test and rewrite of SymFunctionTableAccess for x86_64 (fixing PE map handling, chained entries) - a couple of fixes for thread info generation
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/tests/dbghelp.c | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index d1c2f219533..1ba4ecb6b30 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -1492,6 +1492,45 @@ static void test_live_modules(void) } }
+#define test_function_table_main_module(b) _test_function_table_entry(__LINE__, NULL, #b, (DWORD64)(DWORD_PTR)&(b)) +#define test_function_table_module(a, b) _test_function_table_entry(__LINE__, a, #b, (DWORD64)(DWORD_PTR)GetProcAddress(GetModuleHandleA(a), (b))) +static void *_test_function_table_entry(unsigned lineno, const char *modulename, const char *name, DWORD64 addr) +{ + DWORD64 base_module = (DWORD64)(DWORD_PTR)GetModuleHandleA(modulename); + + if (RtlImageNtHeader(GetModuleHandleW(NULL))->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) + { + IMAGE_AMD64_RUNTIME_FUNCTION_ENTRY *func; + + func = SymFunctionTableAccess64(GetCurrentProcess(), addr); + ok_(__FILE__, lineno)(func != NULL, "Couldn't find function table for %s\n", name); + if (func) + { + ok_(__FILE__, lineno)(func->BeginAddress == addr - base_module, "Unexpected start of function\n"); + ok_(__FILE__, lineno)(func->BeginAddress < func->EndAddress, "Unexpected end of function\n"); + ok_(__FILE__, lineno)((func->UnwindData & 1) == 0, "Unexpected chained runtime function\n"); + } + + return func; + } + return NULL; +} + +static void test_function_tables(void) +{ + void *ptr1, *ptr2; + + 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()); +} + START_TEST(dbghelp) { BOOL ret; @@ -1523,4 +1562,5 @@ START_TEST(dbghelp) test_loaded_modules(); test_live_modules(); } + test_function_tables(); }
From: Eric Pouech epouech@codeweavers.com
This mainly allows to release internal resources bound to image. Also follow chained RUNTIME_FUNCTION entries (if any).
Note: on Win10, native seems to rather use thread storage than the per-context buffer.
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()); }
From: Eric Pouech epouech@codeweavers.com
In case a minidump is written from current process, create a dedicated thread to write the minidump (and hide that thread from the minidump).
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/dbghelp_private.h | 4 +- dlls/dbghelp/minidump.c | 248 ++++++++++++++++++--------------- dlls/dbghelp/tests/minidump.c | 7 +- 3 files changed, 143 insertions(+), 116 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 791f5ad6e14..33714e73bc1 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -618,7 +618,9 @@ struct dump_context struct dump_module* modules; unsigned num_modules; unsigned alloc_modules; - /* exception information */ + /* outter information */ + MINIDUMP_EXCEPTION_INFORMATION *except_param; + MINIDUMP_USER_STREAM_INFORMATION *user_stream; /* output information */ MINIDUMP_TYPE type; HANDLE hFile; diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index 5adbe4fd02d..50a062b11e9 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -61,15 +61,19 @@ static BOOL fetch_process_info(struct dump_context* dc) { if (HandleToUlong(spi->UniqueProcessId) == dc->pid) { - dc->num_threads = spi->dwThreadCount; + dc->num_threads = 0; dc->threads = HeapAlloc(GetProcessHeap(), 0, - dc->num_threads * sizeof(dc->threads[0])); - if (!dc->threads) goto failed; - for (i = 0; i < dc->num_threads; i++) + spi->dwThreadCount * sizeof(dc->threads[0])); + if (!dc->threads) break; + for (i = 0; i < spi->dwThreadCount; i++) { - dc->threads[i].tid = HandleToULong(spi->ti[i].ClientId.UniqueThread); - dc->threads[i].prio_class = spi->ti[i].dwBasePriority; /* FIXME */ - dc->threads[i].curr_prio = spi->ti[i].dwCurrentPriority; + /* don't include current thread */ + if (HandleToULong(spi->ti[i].ClientId.UniqueThread) == GetCurrentThreadId()) + continue; + dc->threads[dc->num_threads].tid = HandleToULong(spi->ti[i].ClientId.UniqueThread); + dc->threads[dc->num_threads].prio_class = spi->ti[i].dwBasePriority; /* FIXME */ + dc->threads[dc->num_threads].curr_prio = spi->ti[i].dwCurrentPriority; + dc->num_threads++; } HeapFree(GetProcessHeap(), 0, pcs_buffer); return TRUE; @@ -78,7 +82,6 @@ static BOOL fetch_process_info(struct dump_context* dc) spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset); } } -failed: HeapFree(GetProcessHeap(), 0, pcs_buffer); return FALSE; } @@ -397,22 +400,21 @@ static void append(struct dump_context* dc, const void* data, unsigned size) * * Write in File the exception information from pcs */ -static unsigned dump_exception_info(struct dump_context* dc, - const MINIDUMP_EXCEPTION_INFORMATION* except) +static unsigned dump_exception_info(struct dump_context* dc) { MINIDUMP_EXCEPTION_STREAM mdExcpt; EXCEPTION_RECORD rec, *prec; CONTEXT ctx, *pctx; DWORD i;
- mdExcpt.ThreadId = except->ThreadId; + mdExcpt.ThreadId = dc->except_param->ThreadId; mdExcpt.__alignment = 0; - if (except->ClientPointers) + if (dc->except_param->ClientPointers) { EXCEPTION_POINTERS ep;
ReadProcessMemory(dc->process->handle, - except->ExceptionPointers, &ep, sizeof(ep), NULL); + dc->except_param->ExceptionPointers, &ep, sizeof(ep), NULL); ReadProcessMemory(dc->process->handle, ep.ExceptionRecord, &rec, sizeof(rec), NULL); ReadProcessMemory(dc->process->handle, @@ -422,8 +424,8 @@ static unsigned dump_exception_info(struct dump_context* dc, } else { - prec = except->ExceptionPointers->ExceptionRecord; - pctx = except->ExceptionPointers->ContextRecord; + prec = dc->except_param->ExceptionPointers->ExceptionRecord; + pctx = dc->except_param->ExceptionPointers->ContextRecord; } mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode; mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags; @@ -715,8 +717,7 @@ static unsigned dump_system_info(struct dump_context* dc) * * Dumps into File the information about running threads */ -static unsigned dump_threads(struct dump_context* dc, - const MINIDUMP_EXCEPTION_INFORMATION* except) +static unsigned dump_threads(struct dump_context* dc) { MINIDUMP_THREAD mdThd; MINIDUMP_THREAD_LIST mdThdList; @@ -732,7 +733,7 @@ static unsigned dump_threads(struct dump_context* dc,
for (i = 0; i < dc->num_threads; i++) { - fetch_thread_info(dc, i, except, &mdThd, &ctx); + fetch_thread_info(dc, i, dc->except_param, &mdThd, &ctx);
flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext | ThreadWriteInstructionWindow; @@ -906,69 +907,24 @@ static unsigned dump_misc_info(struct dump_context* dc) return sizeof(mmi); }
-/****************************************************************** - * MiniDumpWriteDump (DEBUGHLP.@) - * - */ -BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, - MINIDUMP_TYPE DumpType, - PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - PMINIDUMP_CALLBACK_INFORMATION CallbackParam) +static DWORD CALLBACK write_minidump(void *_args) { + struct dump_context *dc = _args; static const MINIDUMP_DIRECTORY emptyDir = {UnusedStream, {0, 0}}; MINIDUMP_HEADER mdHead; MINIDUMP_DIRECTORY mdDir; DWORD i, nStreams, idx_stream; - struct dump_context dc; - BOOL sym_initialized = FALSE; - - if (!(dc.process = process_find_by_handle(hProcess))) - { - if (!(sym_initialized = SymInitializeW(hProcess, NULL, TRUE))) - { - WARN("failed to initialize process\n"); - return FALSE; - } - dc.process = process_find_by_handle(hProcess); - } - - dc.hFile = hFile; - dc.pid = pid; - dc.modules = NULL; - dc.num_modules = 0; - dc.alloc_modules = 0; - dc.threads = NULL; - dc.num_threads = 0; - dc.cb = CallbackParam; - dc.type = DumpType; - dc.mem = NULL; - dc.num_mem = 0; - dc.alloc_mem = 0; - dc.mem64 = NULL; - dc.num_mem64 = 0; - dc.alloc_mem64 = 0; - dc.rva = 0;
- if (!fetch_process_info(&dc)) return FALSE; - fetch_modules_info(&dc); + if (!fetch_process_info(dc)) return FALSE; + fetch_modules_info(dc);
/* 1) init */ - nStreams = 6 + (ExceptionParam ? 1 : 0) + - (UserStreamParam ? UserStreamParam->UserStreamCount : 0); + nStreams = 6 + (dc->except_param ? 1 : 0) + + (dc->user_stream ? dc->user_stream->UserStreamCount : 0);
/* pad the directory size to a multiple of 4 for alignment purposes */ nStreams = (nStreams + 3) & ~3;
- if (DumpType & MiniDumpWithDataSegs) - FIXME("NIY MiniDumpWithDataSegs\n"); - if (DumpType & MiniDumpWithHandleData) - FIXME("NIY MiniDumpWithHandleData\n"); - if (DumpType & MiniDumpFilterMemory) - FIXME("NIY MiniDumpFilterMemory\n"); - if (DumpType & MiniDumpScanMemory) - FIXME("NIY MiniDumpScanMemory\n"); - /* 2) write header */ mdHead.Signature = MINIDUMP_SIGNATURE; mdHead.Version = MINIDUMP_VERSION; /* NOTE: native puts in an 'implementation specific' value in the high order word of this member */ @@ -976,97 +932,169 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, mdHead.CheckSum = 0; /* native sets a 0 checksum in its files */ mdHead.StreamDirectoryRva = sizeof(mdHead); mdHead.TimeDateStamp = time(NULL); - mdHead.Flags = DumpType; - append(&dc, &mdHead, sizeof(mdHead)); + mdHead.Flags = dc->type; + append(dc, &mdHead, sizeof(mdHead));
/* 3) write stream directories */ - dc.rva += nStreams * sizeof(mdDir); + dc->rva += nStreams * sizeof(mdDir); idx_stream = 0;
/* 3.1) write data stream directories */
/* must be first in minidump */ mdDir.StreamType = SystemInfoStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_system_info(&dc); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_system_info(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
mdDir.StreamType = ThreadListStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_threads(&dc, ExceptionParam); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_threads(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
mdDir.StreamType = ModuleListStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_modules(&dc, FALSE); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_modules(dc, FALSE); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */ - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_modules(&dc, TRUE); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_modules(dc, TRUE); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
- if (!(DumpType & MiniDumpWithFullMemory)) + if (!(dc->type & MiniDumpWithFullMemory)) { mdDir.StreamType = MemoryListStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_memory_info(&dc); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_memory_info(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); }
mdDir.StreamType = MiscInfoStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_misc_info(&dc); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_misc_info(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
/* 3.2) write exception information (if any) */ - if (ExceptionParam) + if (dc->except_param) { mdDir.StreamType = ExceptionStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_exception_info(&dc, ExceptionParam); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_exception_info(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); }
/* 3.3) write user defined streams (if any) */ - if (UserStreamParam) + if (dc->user_stream) { - for (i = 0; i < UserStreamParam->UserStreamCount; i++) + for (i = 0; i < dc->user_stream->UserStreamCount; i++) { - mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type; - mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize; - mdDir.Location.Rva = dc.rva; - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.StreamType = dc->user_stream->UserStreamArray[i].Type; + mdDir.Location.DataSize = dc->user_stream->UserStreamArray[i].BufferSize; + mdDir.Location.Rva = dc->rva; + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); - append(&dc, UserStreamParam->UserStreamArray[i].Buffer, - UserStreamParam->UserStreamArray[i].BufferSize); + append(dc, dc->user_stream->UserStreamArray[i].Buffer, + dc->user_stream->UserStreamArray[i].BufferSize); } }
/* 3.4) write full memory (if requested) */ - if (DumpType & MiniDumpWithFullMemory) + if (dc->type & MiniDumpWithFullMemory) { - fetch_memory64_info(&dc); + fetch_memory64_info(dc);
mdDir.StreamType = Memory64ListStream; - mdDir.Location.Rva = dc.rva; - mdDir.Location.DataSize = dump_memory64_info(&dc); - writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), + mdDir.Location.Rva = dc->rva; + mdDir.Location.DataSize = dump_memory64_info(dc); + writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir)); }
/* fill the remaining directory entries with 0's (unused stream types) */ /* NOTE: this should always come last in the dump! */ for (i = idx_stream; i < nStreams; i++) - writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir)); + writeat(dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir)); + + return TRUE; +} + +/****************************************************************** + * MiniDumpWriteDump (DEBUGHLP.@) + * + */ +BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, + MINIDUMP_TYPE DumpType, + PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + PMINIDUMP_CALLBACK_INFORMATION CallbackParam) +{ + struct dump_context dc; + BOOL sym_initialized = FALSE; + BOOL ret = FALSE; + + if (!(dc.process = process_find_by_handle(hProcess))) + { + if (!(sym_initialized = SymInitializeW(hProcess, NULL, TRUE))) + { + WARN("failed to initialize process\n"); + return FALSE; + } + dc.process = process_find_by_handle(hProcess); + } + + if (DumpType & MiniDumpWithDataSegs) + FIXME("NIY MiniDumpWithDataSegs\n"); + if (DumpType & MiniDumpWithHandleData) + FIXME("NIY MiniDumpWithHandleData\n"); + if (DumpType & MiniDumpFilterMemory) + FIXME("NIY MiniDumpFilterMemory\n"); + if (DumpType & MiniDumpScanMemory) + FIXME("NIY MiniDumpScanMemory\n"); + + dc.hFile = hFile; + dc.pid = pid; + dc.modules = NULL; + dc.num_modules = 0; + dc.alloc_modules = 0; + dc.threads = NULL; + dc.num_threads = 0; + dc.cb = CallbackParam; + dc.type = DumpType; + dc.mem = NULL; + dc.num_mem = 0; + dc.alloc_mem = 0; + dc.mem64 = NULL; + dc.num_mem64 = 0; + dc.alloc_mem64 = 0; + dc.rva = 0; + dc.except_param = ExceptionParam; + dc.user_stream = UserStreamParam; + + /* have a dedicated thread for fetching info on self */ + if (dc.pid != GetCurrentProcessId()) + ret = write_minidump(&dc); + else + { + DWORD exit_code; + HANDLE h = CreateThread(NULL, 0, write_minidump, &dc, 0, NULL); + if (h) + { + if (WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0 && GetExitCodeThread(h, &exit_code)) + ret = exit_code; + else + TerminateThread(h, 0); + CloseHandle(h); + } + }
if (sym_initialized) SymCleanup(hProcess); @@ -1076,7 +1104,7 @@ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, HeapFree(GetProcessHeap(), 0, dc.modules); HeapFree(GetProcessHeap(), 0, dc.threads);
- return TRUE; + return ret; }
/****************************************************************** diff --git a/dlls/dbghelp/tests/minidump.c b/dlls/dbghelp/tests/minidump.c index 4ae0e9d44e3..231309d764b 100644 --- a/dlls/dbghelp/tests/minidump.c +++ b/dlls/dbghelp/tests/minidump.c @@ -463,13 +463,11 @@ static void test_current_process(void) num_threads = minidump_get_number_of_threads(data); ok(num_threads > 0, "Unexpected number of threads\n");
- minidump_check_threads(data, 11); + minidump_check_threads(data, 2); md = minidump_get_memory_description(data, (DWORD_PTR)&i); - todo_wine ok(md.kind == MD_STACK, "Couldn't find automatic variable\n");
md2 = minidump_get_memory_description(data, (DWORD_PTR)NtCurrentTeb()->Tib.StackBase - sizeof(void*)); - todo_wine ok(md2.kind == MD_STACK, "Couldn't find stack bottom\n"); ok(md.id == md2.id, "Should be on same stack\n");
@@ -486,7 +484,6 @@ static void test_current_process(void) minidump_walk_memory(data, &walker);
ok(walker.num_unknown == 0, "unexpected unknown memory locations\n"); - todo_wine ok(walker.num_thread_stack == num_threads, "Unexpected number of stacks\n");
if (sizeof(void*) > 4 && (process_tests[i].dump_type & MiniDumpWithModuleHeaders)) @@ -810,7 +807,7 @@ static void test_exception(void) ok(except_info->ThreadContext.Rva, "Unexpected value\n"); mctx = RVA_TO_ADDR(data, except_info->ThreadContext.Rva); ok(!memcmp(mctx, &ctx, sizeof(ctx)), "Unexpected value\n"); - minidump_check_threads(data, exception_tests[i].with_child ? 2 : (sizeof(void*) == 4 ? 7 : 6)); + minidump_check_threads(data, 2); minidump_close_for_read(data); winetest_pop_context(); if (exception_tests[i].with_child)
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/minidump.c | 43 ++++++++--------------------------- dlls/dbghelp/tests/minidump.c | 11 +++------ 2 files changed, 13 insertions(+), 41 deletions(-)
diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index 50a062b11e9..5a2b27f7632 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -119,7 +119,6 @@ static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr, * fetches some information about thread of id 'tid' */ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, - const MINIDUMP_EXCEPTION_INFORMATION* except, MINIDUMP_THREAD* mdThd, CONTEXT* ctx) { DWORD tid = dc->threads[thd_idx].tid; @@ -144,44 +143,22 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, FIXME("Couldn't open thread %lu (%lu)\n", tid, GetLastError()); return FALSE; } - + if (NtQueryInformationThread(hThread, ThreadBasicInformation, &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS) { mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress; if (tbi.ExitStatus == STILL_ACTIVE) { - if (tid != GetCurrentThreadId() && - (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1) - { - ctx->ContextFlags = CONTEXT_FULL; - if (!GetThreadContext(hThread, ctx)) - memset(ctx, 0, sizeof(*ctx)); - - fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack); - ResumeThread(hThread); - } - else if (tid == GetCurrentThreadId() && except) - { - CONTEXT lctx, *pctx; - mdThd->SuspendCount = 1; - if (except->ClientPointers) - { - EXCEPTION_POINTERS ep; - - ReadProcessMemory(dc->process->handle, except->ExceptionPointers, - &ep, sizeof(ep), NULL); - ReadProcessMemory(dc->process->handle, ep.ContextRecord, - &lctx, sizeof(lctx), NULL); - pctx = &lctx; - } - else pctx = except->ExceptionPointers->ContextRecord; - - *ctx = *pctx; - fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack); - } - else mdThd->SuspendCount = 0; + mdThd->SuspendCount = SuspendThread(hThread); + ctx->ContextFlags = CONTEXT_ALL; + if (!GetThreadContext(hThread, ctx)) + memset(ctx, 0, sizeof(*ctx)); + fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack); + ResumeThread(hThread); } + else + mdThd->SuspendCount = (DWORD)-1; } CloseHandle(hThread); return TRUE; @@ -733,7 +710,7 @@ static unsigned dump_threads(struct dump_context* dc)
for (i = 0; i < dc->num_threads; i++) { - fetch_thread_info(dc, i, dc->except_param, &mdThd, &ctx); + fetch_thread_info(dc, i, &mdThd, &ctx);
flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext | ThreadWriteInstructionWindow; diff --git a/dlls/dbghelp/tests/minidump.c b/dlls/dbghelp/tests/minidump.c index 231309d764b..85dd3209cae 100644 --- a/dlls/dbghelp/tests/minidump.c +++ b/dlls/dbghelp/tests/minidump.c @@ -192,7 +192,7 @@ static unsigned minidump_get_number_of_threads(void *data) return thread_list->NumberOfThreads; }
-static void minidump_check_threads(void *data, unsigned todo_flags) +static void minidump_check_threads(void *data) { MINIDUMP_THREAD_LIST *thread_list; ULONG stream_size; @@ -208,17 +208,12 @@ static void minidump_check_threads(void *data, unsigned todo_flags) const MINIDUMP_THREAD *thread = &thread_list->Threads[i]; const CONTEXT *ctx;
- todo_wine_if(todo_flags & 4) ok(thread->SuspendCount == 0, "Unexpected value\n"); - todo_wine_if(todo_flags & 1) ok(thread->Stack.StartOfMemoryRange, "Unexpected value %I64x\n", thread->Stack.StartOfMemoryRange); - todo_wine_if(todo_flags & 1) ok(thread->Stack.Memory.DataSize, "Unexpected value %x\n", thread->Stack.Memory.DataSize); ok(thread->Teb, "Unexpected value\n"); - todo_wine_if(todo_flags & 8) ok(thread->ThreadContext.DataSize >= sizeof(CONTEXT), "Unexpected value\n"); ctx = RVA_TO_ADDR(data, thread->ThreadContext.Rva); - todo_wine_if(todo_flags & 2) ok((ctx->ContextFlags & CONTEXT_ALL) == CONTEXT_ALL, "Unexpected value\n"); } } @@ -463,7 +458,7 @@ static void test_current_process(void) num_threads = minidump_get_number_of_threads(data); ok(num_threads > 0, "Unexpected number of threads\n");
- minidump_check_threads(data, 2); + minidump_check_threads(data); md = minidump_get_memory_description(data, (DWORD_PTR)&i); ok(md.kind == MD_STACK, "Couldn't find automatic variable\n");
@@ -807,7 +802,7 @@ static void test_exception(void) ok(except_info->ThreadContext.Rva, "Unexpected value\n"); mctx = RVA_TO_ADDR(data, except_info->ThreadContext.Rva); ok(!memcmp(mctx, &ctx, sizeof(ctx)), "Unexpected value\n"); - minidump_check_threads(data, 2); + minidump_check_threads(data); minidump_close_for_read(data); winetest_pop_context(); if (exception_tests[i].with_child)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=144058
Your paranoid android.
=== debian11b (64 bit WoW report) ===
d3dx10_34: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011BB840. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011B6060. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011B23C0. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011BB840. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011BB560.
d3dx10_35: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011E3CB0. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011E38C0. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011E3C60. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011E3980. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011E3C60.
d3dx10_36: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011BBA70. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011B7270. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 0000000001239C00. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011B7440. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011BB9B0.
d3dx10_37: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 0000000001239E90. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011B2470. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 0000000001239B10. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 0000000001239E90. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011958C0.
d3dx10_38: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011C3730. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011C3900. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011C3730. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011C0E20. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011C3900.
d3dx10_39: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 0000000001195800. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011959E0. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 0000000001195BB0. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011D1890. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011D1A60.
d3dx10_40: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011BBA60. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011E3B70. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011B6010. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011E3B20. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011D53B0.
d3dx10_41: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011E4070. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011D1820. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011D19F0. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011E4070. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011E4380.
d3dx10_42: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 0000000001239D60. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 0000000001239F30. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 0000000001239F30. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 0000000001239F30. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011A4AD0.
d3dx10_43: d3dx10.c:4380: Test succeeded inside todo block: Got unexpected effect 00000000011E3990. d3dx10.c:4470: Test succeeded inside todo block: Got unexpected effect 00000000011E3990. d3dx10.c:4480: Test succeeded inside todo block: Got unexpected effect 00000000011E3B60. d3dx10.c:4589: Test succeeded inside todo block: Got unexpected effect 00000000011D3A20. d3dx10.c:4599: Test succeeded inside todo block: Got unexpected effect 00000000011D3A20.