From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/tests/minidump.c | 44 +++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/dbghelp/tests/minidump.c b/dlls/dbghelp/tests/minidump.c index c6f73ca2662..64fd3e4fb6c 100644 --- a/dlls/dbghelp/tests/minidump.c +++ b/dlls/dbghelp/tests/minidump.c @@ -26,6 +26,9 @@ #include "winnt.h" #include "wine/test.h"
+static HRESULT (WINAPI *pSetThreadDescription)(HANDLE,PCWSTR); +static const WCHAR *main_thread_name = L"I'm the running thread!"; + static unsigned popcount32(ULONG val) { val -= val >> 1 & 0x55555555; @@ -102,7 +105,7 @@ typedef DWORD64 stream_mask_t; STREAM2MASK(ProcessVmCountersStream)) /* streams added in Win8 & Win10... */ #define BASIC_STREAM_BROKEN_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream)) -#define BASIC_STREAM_TODO_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream)) +#define BASIC_STREAM_TODO_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream) | STREAM2MASK(ThreadNamesStream)) static void test_minidump_contents(void) { static const struct minidump_streams @@ -123,6 +126,7 @@ static void test_minidump_contents(void) {MiniDumpWithAvxXStateContext, BASIC_STREAM_MASK, BASIC_STREAM_TODO_MASK}, /* requires win10 at least */ {MiniDumpWithIptTrace, BASIC_STREAM_MASK, BASIC_STREAM_TODO_MASK}, }; + stream_mask_t expected_mask; MINIDUMP_HEADER *hdr; void *where; ULONG size; @@ -145,8 +149,10 @@ static void test_minidump_contents(void) for (j = 3; j < 25 /* last documented stream */; j++) { ret = MiniDumpReadDumpStream(hdr, j, NULL, &where, &size); + expected_mask = streams_table[i].streams_mask; + if (pSetThreadDescription) expected_mask |= STREAM2MASK(ThreadNamesStream); todo_wine_if(streams_table[i].todo_wine_mask & STREAM2MASK(j)) - if (streams_table[i].streams_mask & STREAM2MASK(j)) + if (expected_mask & STREAM2MASK(j)) ok((ret && where) || broken(BASIC_STREAM_BROKEN_MASK & STREAM2MASK(j)), "Expecting stream %d to be present\n", j); else ok(!ret, "Not expecting stream %d to be present\n", j); @@ -218,6 +224,36 @@ static void minidump_check_threads(void *data) } }
+static void minidump_check_threads_name(void *data, DWORD tid, const WCHAR* name) +{ + MINIDUMP_THREAD_NAME_LIST *thread_name_list; + ULONG stream_size; + int i; + BOOL ret; + + if (!pSetThreadDescription) return; + + ret = MiniDumpReadDumpStream(data, ThreadNamesStream, NULL, (void**)&thread_name_list, &stream_size); + todo_wine + ok(ret && thread_name_list, "Couldn't find thread-name-list stream\n"); + if (!ret) return; /* temp */ + ok(stream_size == sizeof(thread_name_list->NumberOfThreadNames) + thread_name_list->NumberOfThreadNames * sizeof(thread_name_list->ThreadNames[0]), + "Unexpected size\n"); + for (i = 0; i < thread_name_list->NumberOfThreadNames; i++) + { + const MINIDUMP_THREAD_NAME *thread_name = &thread_name_list->ThreadNames[i]; + const MINIDUMP_STRING *md_string; + + md_string = RVA_TO_ADDR(data, (ULONG_PTR)thread_name->RvaOfThreadName); + if (thread_name->RvaOfThreadName == (ULONG_PTR)thread_name->RvaOfThreadName && + thread_name->ThreadId == tid && + wcslen(name) == md_string->Length / sizeof(WCHAR) && + !memcmp(name, md_string->Buffer, md_string->Length)) + break; + } + ok(i < thread_name_list->NumberOfThreadNames, "Couldn't find thread %lx %ls\n", tid, name); +} + static void minidump_check_module(void *data, const WCHAR *name, DWORD64 base) { MINIDUMP_MODULE_LIST *module_list; @@ -499,6 +535,7 @@ static void test_current_process(void) ok(walker.num_unwind_info == 0, "unexpected unwind info %u\n", walker.num_unwind_info); minidump_check_nostream(data, ExceptionStream);
+ minidump_check_threads_name(data, GetCurrentThreadId(), main_thread_name); minidump_close_for_read(data);
ret = DeleteFileA("foo.mdmp"); @@ -857,6 +894,9 @@ START_TEST(minidump) return; }
+ if ((pSetThreadDescription = (void *)GetProcAddress(GetModuleHandleW(L"kernel32"), "SetThreadDescription"))) + pSetThreadDescription(GetCurrentThread(), main_thread_name); + test_minidump_contents(); test_current_process(); test_callback();
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/minidump.c | 62 ++++++++++++++++++++++++++++++++++- dlls/dbghelp/tests/minidump.c | 4 +-- 2 files changed, 62 insertions(+), 4 deletions(-)
diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index 5a2b27f7632..054aaee22a9 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -771,6 +771,60 @@ static unsigned dump_threads(struct dump_context* dc) return sz; }
+/****************************************************************** + * dump_threads_names + * + * Dumps into File the information about threads's name + */ +static unsigned dump_threads_names(struct dump_context* dc) +{ + MINIDUMP_THREAD_NAME md_thread_name; + MINIDUMP_THREAD_NAME_LIST md_thread_name_list; + unsigned i, sz; + RVA rva_base; + + /* FIXME this could be optimized + * (we use dc->num_threads disk space, could be optimized to the number of threads with name) + */ + + rva_base = dc->rva; + dc->rva += sz = offsetof(MINIDUMP_THREAD_NAME_LIST, ThreadNames[dc->num_threads]); + + md_thread_name_list.NumberOfThreadNames = 0; + + for (i = 0; i < dc->num_threads; i++) + { + HANDLE thread; + WCHAR *thread_name; + + if ((thread = OpenThread(THREAD_ALL_ACCESS, FALSE, dc->threads[i].tid)) != NULL) + { + if (GetThreadDescription(thread, &thread_name)) + { + MINIDUMP_STRING md_string; + + md_thread_name.ThreadId = dc->threads[i].tid; + md_thread_name.RvaOfThreadName = dc->rva; + + md_string.Length = wcslen(thread_name) * sizeof(WCHAR); + append(dc, &md_string.Length, sizeof(md_string.Length)); + append(dc, thread_name, md_string.Length); + + writeat(dc, + rva_base + offsetof(MINIDUMP_THREAD_NAME_LIST, ThreadNames[md_thread_name_list.NumberOfThreadNames]), + &md_thread_name, sizeof(md_thread_name)); + md_thread_name_list.NumberOfThreadNames++; + LocalFree(thread_name); + } + CloseHandle(thread); + } + } + if (!md_thread_name_list.NumberOfThreadNames) return 0; + + writeat(dc, rva_base, &md_thread_name_list.NumberOfThreadNames, sizeof(md_thread_name_list.NumberOfThreadNames)); + return sz; +} + /****************************************************************** * dump_memory_info * @@ -896,7 +950,7 @@ static DWORD CALLBACK write_minidump(void *_args) fetch_modules_info(dc);
/* 1) init */ - nStreams = 6 + (dc->except_param ? 1 : 0) + + nStreams = 7 + (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 */ @@ -931,6 +985,12 @@ static DWORD CALLBACK write_minidump(void *_args) writeat(dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), &mdDir, sizeof(mdDir));
+ mdDir.StreamType = ThreadNamesStream; + mdDir.Location.Rva = dc->rva; + if ((mdDir.Location.DataSize = dump_threads_names(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); diff --git a/dlls/dbghelp/tests/minidump.c b/dlls/dbghelp/tests/minidump.c index 64fd3e4fb6c..088e44e6d8b 100644 --- a/dlls/dbghelp/tests/minidump.c +++ b/dlls/dbghelp/tests/minidump.c @@ -105,7 +105,7 @@ typedef DWORD64 stream_mask_t; STREAM2MASK(ProcessVmCountersStream)) /* streams added in Win8 & Win10... */ #define BASIC_STREAM_BROKEN_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream)) -#define BASIC_STREAM_TODO_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream) | STREAM2MASK(ThreadNamesStream)) +#define BASIC_STREAM_TODO_MASK (STREAM2MASK(SystemMemoryInfoStream) | STREAM2MASK(ProcessVmCountersStream)) static void test_minidump_contents(void) { static const struct minidump_streams @@ -234,9 +234,7 @@ static void minidump_check_threads_name(void *data, DWORD tid, const WCHAR* name if (!pSetThreadDescription) return;
ret = MiniDumpReadDumpStream(data, ThreadNamesStream, NULL, (void**)&thread_name_list, &stream_size); - todo_wine ok(ret && thread_name_list, "Couldn't find thread-name-list stream\n"); - if (!ret) return; /* temp */ ok(stream_size == sizeof(thread_name_list->NumberOfThreadNames) + thread_name_list->NumberOfThreadNames * sizeof(thread_name_list->ThreadNames[0]), "Unexpected size\n"); for (i = 0; i < thread_name_list->NumberOfThreadNames; i++)