[PATCH 0/4] MR10562: Improve winedbg when attached to a minidump.
This MR improves WineDbg when it's used with a minidump as debuggee: - commands 'bt <tid>' and 'bt all' now return content from the minidump, - 'bt' commands now prints the thread name/description when available (either for an active debuggee or a debuggee from a minidump), - 'info thread' now prints threads from the minidump, - a bunch of (other) 'info' commands are now inactive when attached to a minidump as they only reflect the active system. Note: as a pid or tid from a minidump can match the one of an active thread/process, we really have not to access the active system when attached to a minidump. There are still some other commands to be fixed accordingly. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10562
From: Eric Pouech <epouech@codeweavers.com> Signed-off-by: Eric Pouech <epouech@codeweavers.com> --- programs/winedbg/info.c | 67 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 727686c2fc5..b5e68763d7f 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -271,7 +271,7 @@ void info_win32_module(DWORD64 base, BOOL multi_machine) if (!dbg_curr_process) { - dbg_printf("Cannot get info on module while no process is loaded\n"); + dbg_printf("Cannot proceed with 'info module' while no process is being debugged\n"); return; } @@ -397,6 +397,12 @@ void info_win32_class(HWND hWnd, const char* name) WNDCLASSEXA wca; HINSTANCE hInst = hWnd ? (HINSTANCE)GetWindowLongPtrW(hWnd, GWLP_HINSTANCE) : 0; + if (dbg_curr_process && !dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot proceed with 'info class' while debugging a non active process\n"); + return; + } + if (!name) { struct class_walker cw; @@ -475,6 +481,12 @@ void info_win32_window(HWND hWnd, BOOL detailed) RECT windowRect; WORD w; + if (dbg_curr_process && !dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot proceed with 'info window' while debugging a non active process\n"); + return; + } + if (!IsWindow(hWnd)) hWnd = GetDesktopWindow(); if (!detailed) @@ -585,7 +597,7 @@ static void dump_proc_info(const struct dump_proc* dp, unsigned idx, unsigned de } } -void info_win32_processes(void) +static void info_win32_active_processes(void) { HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snap != INVALID_HANDLE_VALUE) @@ -639,6 +651,15 @@ void info_win32_processes(void) } } +void info_win32_processes(void) +{ + if (!dbg_curr_process || dbg_curr_process->active_debuggee) + info_win32_active_processes(); + else + /* FIXME we could do better */ + dbg_printf("Cannot proceed with 'info proc' while debugging a non active process\n"); +} + static BOOL get_process_name(DWORD pid, PROCESSENTRY32W* entry) { BOOL ret = FALSE; @@ -764,7 +785,12 @@ void info_win32_frame_exceptions(DWORD tid) if (!dbg_curr_process || !dbg_curr_thread) { - dbg_printf("Cannot get info on exceptions while no process is loaded\n"); + dbg_printf("Cannot proceed with 'info frame' while no process is being debugged\n"); + return; + } + if (!dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot proceed with 'info frame' while debugging a non active process\n"); return; } @@ -816,6 +842,11 @@ void info_win32_segments(DWORD start, int length) DWORD i; LDT_ENTRY le; + if (dbg_curr_process && !dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot proceed with 'info segments' while debugging a non active process\n"); + return; + } if (length == -1) length = (8192 - start); for (i = start; i < start + length; i++) @@ -855,11 +886,17 @@ void info_win32_virtual(DWORD pid) char prot[3+1]; HANDLE hProc; + if (dbg_curr_process && !dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot proceed with 'info maps' while debugging a non active process\n"); + return; + } + if (pid == dbg_curr_pid) { if (dbg_curr_process == NULL) { - dbg_printf("Cannot look at mapping of current process, while no process is loaded\n"); + dbg_printf("Cannot proceed with 'info maps' while no process is being debugged\n"); return; } hProc = dbg_curr_process->handle; @@ -929,7 +966,12 @@ void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name) if (!dbg_curr_process || !dbg_curr_thread) { - dbg_printf("Cannot set/get debug channels while no process is loaded\n"); + dbg_printf("Cannot set/get debug channels while no process is being debugged\n"); + return; + } + if (!dbg_curr_process->active_debuggee) + { + dbg_printf("Cannot set/get debug channels while debugging a non active process\n"); return; } if (NtQueryInformationProcess(dbg_curr_process->handle, ProcessBasicInformation, &info, sizeof(info), NULL )) @@ -982,11 +1024,17 @@ void info_win32_exception(void) ADDRESS64 addr; char hexbuf[MAX_OFFSET_TO_STR_LEN]; + if (!dbg_curr_thread) + { + dbg_printf("Cannot proceed with 'info exception' as there's no current thread\n"); + return; + } if (!dbg_curr_thread->in_exception) { - dbg_printf("Thread isn't in an exception\n"); + dbg_printf("Cannot proceed with 'info exception' while current thread isn't inside an exception\n"); return; } + rec = &dbg_curr_thread->excpt_record; memory_get_current_pc(&addr); @@ -1205,6 +1253,13 @@ void info_win32_system(void) IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_ARM, IMAGE_FILE_MACHINE_ARMNT, }; + if (dbg_curr_process && !dbg_curr_process->active_debuggee) + { + /* FIXME we could better for minidump */ + dbg_printf("Cannot proceed with 'info system' while debugging a non active process\n"); + return; + } + wine_get_build_id = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_build_id"); wine_get_host_version = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_host_version"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10562
From: Eric Pouech <epouech@codeweavers.com> Let these helpers work through various configurations, starting with getting thread name from a minidump. Signed-off-by: Eric Pouech <epouech@codeweavers.com> --- programs/winedbg/debugger.h | 4 ++- programs/winedbg/gdbproxy.c | 8 ++--- programs/winedbg/info.c | 53 ++++----------------------------- programs/winedbg/tgt_active.c | 38 ++++++++++++++++++++++- programs/winedbg/tgt_minidump.c | 29 ++++++++++++++++++ programs/winedbg/winedbg.c | 17 +++++++++++ 6 files changed, 94 insertions(+), 55 deletions(-) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index e778f7eeb95..ff27997c888 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -301,6 +301,7 @@ struct be_process_io BOOL (*read)(HANDLE, const void*, void*, SIZE_T, SIZE_T*); BOOL (*write)(HANDLE, void*, const void*, SIZE_T, SIZE_T*); BOOL (*get_selector)(HANDLE, DWORD, LDT_ENTRY*); + BOOL (*fetch_thread_name)(const struct dbg_thread*, WCHAR**); }; extern struct dbg_process* dbg_curr_process; @@ -395,7 +396,6 @@ extern void info_win32_segments(DWORD start, int length); extern void info_win32_exception(void); extern void info_win32_system(void); extern void info_wine_dbg_channel(BOOL add, const char* chnl, const char* name); -extern WCHAR* fetch_thread_description(DWORD tid); /* memory.c */ extern BOOL memory_read_value(const struct dbg_lvalue* lvalue, DWORD size, void* result); @@ -485,6 +485,7 @@ extern enum dbg_start dbg_active_minidump(int argc, char* argv[]); extern void dbg_active_wait_for_first_exception(void); extern BOOL dbg_attach_debuggee(DWORD pid); extern void fetch_module_name(void* name_addr, void* mod_addr, WCHAR* buffer, size_t bufsz); +extern BOOL dbg_fetch_active_thread_name(DWORD tid, WCHAR **description); /* tgt_minidump.c */ extern void minidump_write(const char*, const EXCEPTION_RECORD*); @@ -531,6 +532,7 @@ extern struct dbg_process* dbg_get_process_h(HANDLE handle); extern void dbg_del_process(struct dbg_process* p); struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid, HANDLE h, void* teb); extern struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid); +extern WCHAR* dbg_fetch_thread_name(const struct dbg_thread *thread); extern void dbg_del_thread(struct dbg_thread* t); extern BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade); extern BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size); diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index e937c4edf32..3dbc7f7c32a 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -1801,14 +1801,10 @@ static enum packet_return packet_query_threads(struct gdb_context* gdbctx) reply_buffer_append_str(reply, "id=\""); reply_buffer_append_uinthex(reply, thread->tid, 4); reply_buffer_append_str(reply, "\" name=\""); - if ((description = fetch_thread_description(thread->tid))) + if ((description = dbg_fetch_thread_name(thread))) { reply_buffer_append_wstr(reply, description); - LocalFree(description); - } - else if (strlen(thread->name)) - { - reply_buffer_append_str(reply, thread->name); + free(description); } else { diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index b5e68763d7f..e1bb33bad53 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -676,39 +676,6 @@ static BOOL get_process_name(DWORD pid, PROCESSENTRY32W* entry) return ret; } -WCHAR* fetch_thread_description(DWORD tid) -{ - static HRESULT (WINAPI *my_GetThreadDescription)(HANDLE, PWSTR*) = NULL; - static BOOL resolved = FALSE; - HANDLE h; - WCHAR* desc = NULL; - - if (!resolved) - { - HMODULE kernelbase = GetModuleHandleA("kernelbase.dll"); - if (kernelbase) - my_GetThreadDescription = (void *)GetProcAddress(kernelbase, "GetThreadDescription"); - resolved = TRUE; - } - - if (!my_GetThreadDescription) - return NULL; - - h = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tid); - if (!h) - return NULL; - - my_GetThreadDescription(h, &desc); - CloseHandle(h); - - if (desc && desc[0] == '\0') - { - LocalFree(desc); - return NULL; - } - return desc; -} - void info_win32_threads(void) { HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); @@ -718,7 +685,6 @@ void info_win32_threads(void) BOOL ok; DWORD lastProcessId = 0; struct dbg_process* p = NULL; - struct dbg_thread* t = NULL; WCHAR *description; entry.dwSize = sizeof(entry); @@ -751,20 +717,13 @@ void info_win32_threads(void) entry.th32OwnerProcessID, p ? " (D)" : "", exename); lastProcessId = entry.th32OwnerProcessID; } - dbg_printf("\t%08lx %4ld%s ", + if (!dbg_fetch_active_thread_name(entry.th32ThreadID, &description)) + description = NULL; + dbg_printf("\t%08lx %4ld%s %ls\n", entry.th32ThreadID, entry.tpBasePri, - (entry.th32ThreadID == dbg_curr_tid) ? " <==" : " "); - - if ((description = fetch_thread_description(entry.th32ThreadID))) - { - dbg_printf("%ls\n", description); - LocalFree(description); - } - else - { - t = dbg_get_thread(p, entry.th32ThreadID); - dbg_printf("%s\n", t ? t->name : ""); - } + (entry.th32ThreadID == dbg_curr_tid) ? " <==" : " ", + description ? description : L""); + free(description); } ok = Thread32Next(snap, &entry); } diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index dba595b5f30..52fae345b98 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -1092,10 +1092,46 @@ static BOOL tgt_process_active_get_selector(HANDLE hThread, DWORD sel, LDT_ENTRY #endif } +BOOL dbg_fetch_active_thread_name(DWORD tid, WCHAR **description) +{ + static HRESULT (WINAPI *my_GetThreadDescription)(HANDLE, PWSTR*) = NULL; + static BOOL resolved = FALSE; + HANDLE h; + WCHAR *result = NULL; + + if (!resolved) + { + HMODULE kernelbase = GetModuleHandleA("kernelbase.dll"); + if (kernelbase) + my_GetThreadDescription = (void *)GetProcAddress(kernelbase, "GetThreadDescription"); + resolved = TRUE; + } + + if (my_GetThreadDescription && (h = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tid))) + { + WCHAR *descr; + if (my_GetThreadDescription(h, &descr) == S_OK) + { + if (*descr) result = wcsdup(descr); + LocalFree(descr); + } + CloseHandle(h); + } + if (!result) return FALSE; + *description = result; + return TRUE; +} + +static BOOL tgt_process_active_fetch_thread_name(const struct dbg_thread *thread, WCHAR **description) +{ + return dbg_fetch_active_thread_name(thread->tid, description); +} + static struct be_process_io be_process_active_io = { tgt_process_active_close_process, tgt_process_active_read, tgt_process_active_write, - tgt_process_active_get_selector + tgt_process_active_get_selector, + tgt_process_active_fetch_thread_name, }; diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index 87098491392..bed25406e22 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -648,10 +648,39 @@ static BOOL tgt_process_minidump_get_selector(HANDLE hThread, DWORD sel, LDT_ENT return TRUE; } +static BOOL tgt_process_minidump_fetch_thread_name(const struct dbg_thread *thread, WCHAR **description) +{ + struct tgt_process_minidump_data *data = private_data(thread->process); + void *stream; + + if (MiniDumpReadDumpStream(data->mapping, ThreadNamesStream, NULL, &stream, NULL)) + { + MINIDUMP_THREAD_NAME_LIST* mtnl = stream; + ULONG i; + + for (i = 0; i < mtnl->NumberOfThreadNames; i++) + { + if (thread->tid == mtnl->ThreadNames[i].ThreadId) + { + MINIDUMP_STRING *mdmp_string = (MINIDUMP_STRING *)((char*)data->mapping + mtnl->ThreadNames[i].RvaOfThreadName); + WCHAR *ret; + if (!mdmp_string->Length) return FALSE; + if (!(ret = malloc(mdmp_string->Length + sizeof(WCHAR)))) return FALSE; + memcpy(ret, mdmp_string->Buffer, mdmp_string->Length); + ret[mdmp_string->Length / sizeof(WCHAR)] = L'\0'; + *description = ret; + return TRUE; + } + } + } + return FALSE; +} + static struct be_process_io be_process_minidump_io = { tgt_process_minidump_close_process, tgt_process_minidump_read, tgt_process_minidump_write, tgt_process_minidump_get_selector, + tgt_process_minidump_fetch_thread_name, }; diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index c7f14e8238f..6d9afba7a6d 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -513,6 +513,23 @@ void dbg_del_thread(struct dbg_thread* t) free(t); } +WCHAR* dbg_fetch_thread_name(const struct dbg_thread *thread) +{ + WCHAR *descr; + + if (thread->process->process_io->fetch_thread_name && + thread->process->process_io->fetch_thread_name(thread, &descr)) + return descr; + if (*thread->name) + { + DWORD len = MultiByteToWideChar(CP_ACP, 0, thread->name, -1, NULL, 0); + if ((descr = malloc(len * sizeof(WCHAR)))) + MultiByteToWideChar(CP_ACP, 0, thread->name, -1, descr, len); + return descr; + } + return NULL; +} + void dbg_set_option(const char* option, const char* val) { if (!strcasecmp(option, "module_load_mismatched")) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10562
From: Eric Pouech <epouech@codeweavers.com> - 'bt <tid>' will backtrace the relevant thread from the minidump. - 'bt all' will backtrace all threads from the minidump. Signed-off-by: Eric Pouech <epouech@codeweavers.com> --- programs/winedbg/dbg.y | 2 +- programs/winedbg/debugger.h | 4 +- programs/winedbg/stack.c | 75 +++++++++++++++++++++++---------- programs/winedbg/tgt_active.c | 13 +++--- programs/winedbg/tgt_minidump.c | 44 ++++++++++++++++++- programs/winedbg/winedbg.c | 3 +- 6 files changed, 105 insertions(+), 36 deletions(-) diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index a0d0ebb34f4..a142d67a6dc 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -140,7 +140,7 @@ command: | tSYMBOLFILE pathname { symbol_read_symtable($2, 0); } | tSYMBOLFILE pathname expr_rvalue { symbol_read_symtable($2, $3); } | tWHATIS expr_lvalue { dbg_printf("type = "); types_print_type(&$2.type, FALSE, NULL); dbg_printf("\n"); } - | tATTACH tNUM { if (dbg_attach_debuggee($2)) dbg_active_wait_for_first_exception(); } + | tATTACH tNUM { if (dbg_attach_debuggee($2, TRUE)) dbg_active_wait_for_first_exception(); } | tATTACH pathname { minidump_reload($2); } | tDETACH { dbg_curr_process->process_io->close_process(dbg_curr_process, FALSE); } | tTHREAD tNUM { dbg_set_curr_thread($2); } diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index ff27997c888..25b510f3902 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -302,6 +302,7 @@ struct be_process_io BOOL (*write)(HANDLE, void*, const void*, SIZE_T, SIZE_T*); BOOL (*get_selector)(HANDLE, DWORD, LDT_ENTRY*); BOOL (*fetch_thread_name)(const struct dbg_thread*, WCHAR**); + BOOL (*fetch_thread_context)(const struct dbg_thread*, dbg_ctx_t *); }; extern struct dbg_process* dbg_curr_process; @@ -311,6 +312,7 @@ extern DWORD dbg_curr_tid; extern dbg_ctx_t dbg_context; extern BOOL dbg_interactiveP; extern HANDLE dbg_houtput; +extern struct list dbg_process_list; struct dbg_internal_var { @@ -483,7 +485,7 @@ extern enum dbg_start dbg_active_launch(int argc, char* argv[]); extern enum dbg_start dbg_active_auto(int argc, char* argv[]); extern enum dbg_start dbg_active_minidump(int argc, char* argv[]); extern void dbg_active_wait_for_first_exception(void); -extern BOOL dbg_attach_debuggee(DWORD pid); +extern BOOL dbg_attach_debuggee(DWORD pid, BOOL verbose); extern void fetch_module_name(void* name_addr, void* mod_addr, WCHAR* buffer, size_t bufsz); extern BOOL dbg_fetch_active_thread_name(DWORD tid, WCHAR **description); diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c index 7860e73c088..059b6f37396 100644 --- a/programs/winedbg/stack.c +++ b/programs/winedbg/stack.c @@ -327,6 +327,20 @@ static void backtrace(void) stack_set_local_scope(); } +static const char *thread_display(const struct dbg_thread *thread) +{ + static char buffer[256]; + WCHAR *thread_descr = dbg_fetch_thread_name(thread); + if (thread_descr) + { + snprintf(buffer, sizeof(buffer), "%04lx (%ls)", thread->tid, thread_descr); + free(thread_descr); + } + else + snprintf(buffer, sizeof(buffer), "%04lx", thread->tid); + return buffer; +} + /****************************************************************** * backtrace_tid * @@ -336,23 +350,24 @@ static void backtrace(void) static void backtrace_tid(struct dbg_process* pcs, DWORD tid) { struct dbg_thread* thread = dbg_curr_thread; + dbg_ctx_t ctx = {{0}}; if (!(dbg_curr_thread = dbg_get_thread(pcs, tid))) dbg_printf("Unknown thread id (%04lx) in process (%04lx)\n", tid, pcs->pid); - else + else if (pcs->active_debuggee) { - dbg_ctx_t ctx = {{0}}; - dbg_curr_tid = dbg_curr_thread->tid; if (SuspendThread(dbg_curr_thread->handle) != -1) { if (!pcs->be_cpu->get_context(dbg_curr_thread->handle, &ctx)) { - dbg_printf("Can't get context for thread %04lx in current process\n", - tid); + dbg_printf("Can't get context for thread %s in current process\n", + thread_display(dbg_curr_thread)); } else { + dbg_printf("\nBacktracing for thread %s in process %04lx (%ls):\n", + thread_display(dbg_curr_thread), dbg_curr_pid, dbg_curr_process->imageName); stack_fetch_frames(&ctx); backtrace(); } @@ -360,17 +375,28 @@ static void backtrace_tid(struct dbg_process* pcs, DWORD tid) } else dbg_printf("Can't suspend thread %04lx in current process\n", tid); } + else if (pcs->process_io->fetch_thread_context && + pcs->process_io->fetch_thread_context(dbg_curr_thread, &ctx)) + { + dbg_curr_tid = dbg_curr_thread->tid; + dbg_printf("\nBacktracing for thread %s in process %04lx (%ls):\n", + thread_display(dbg_curr_thread), dbg_curr_pid, dbg_curr_process->imageName); + stack_fetch_frames(&ctx); + backtrace(); + } + else dbg_printf("Can't backtrace thread %04lx in current process\n", tid); + dbg_curr_thread = thread; dbg_curr_tid = thread ? thread->tid : 0; } /****************************************************************** - * backtrace_all + * backtrace_all_active * * Do a backtrace on every running thread in the system (except the debugger) * (preserves current process information) */ -static void backtrace_all(void) +static void backtrace_all_active(void) { struct dbg_process* process = dbg_curr_process; struct dbg_thread* thread = dbg_curr_thread; @@ -402,17 +428,11 @@ static void backtrace_all(void) } else if (entry.th32OwnerProcessID != dbg_curr_pid) { - if (!dbg_attach_debuggee(entry.th32OwnerProcessID)) - { - dbg_printf("\nwarning: could not attach to %04lx\n", - entry.th32OwnerProcessID); + dbg_curr_process = NULL; + if (!dbg_attach_debuggee(entry.th32OwnerProcessID, FALSE)) continue; - } dbg_active_wait_for_first_exception(); } - - dbg_printf("\nBacktracing for thread %04lx in process %04lx (%ls):\n", - entry.th32ThreadID, dbg_curr_pid, dbg_curr_process->imageName); backtrace_tid(dbg_curr_process, entry.th32ThreadID); } while (Thread32Next(snapshot, &entry)); @@ -428,6 +448,18 @@ static void backtrace_all(void) dbg_context = ctx; } +static void backtrace_all_attached(void) +{ + struct dbg_process *pcs; + struct dbg_thread *thread; + + LIST_FOR_EACH_ENTRY(pcs, &dbg_process_list, struct dbg_process, entry) + { + LIST_FOR_EACH_ENTRY(thread, &pcs->threads, struct dbg_thread, entry) + backtrace_tid(pcs, thread->tid); + } +} + void stack_backtrace(DWORD tid) { /* backtrace every thread in every process except the debugger itself, @@ -435,17 +467,16 @@ void stack_backtrace(DWORD tid) */ if (tid == -1) { - backtrace_all(); - return; + if (!dbg_curr_process || dbg_curr_process->active_debuggee) + backtrace_all_active(); + else + backtrace_all_attached(); } - - if (!dbg_curr_process) + else if (!dbg_curr_process) { dbg_printf("You must be attached to a process to run this command.\n"); - return; } - - if (tid == dbg_curr_tid) + else if (tid == dbg_curr_tid) { backtrace(); } diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 52fae345b98..02bc3bc481e 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -63,12 +63,8 @@ static unsigned dbg_handle_debug_event(DEBUG_EVENT* de); * dbg_attach_debuggee * * Sets the debuggee to <pid> - * cofe instructs winedbg what to do when first exception is received - * (break=FALSE, continue=TRUE) - * wfe is set to TRUE if dbg_attach_debuggee should also proceed with all debug events - * until the first exception is received (aka: attach to an already running process) */ -BOOL dbg_attach_debuggee(DWORD pid) +BOOL dbg_attach_debuggee(DWORD pid, BOOL verbose) { if (pid == GetCurrentProcessId()) { @@ -92,7 +88,8 @@ BOOL dbg_attach_debuggee(DWORD pid) SetEnvironmentVariableA("DBGHELP_NOLIVE", NULL); dbg_curr_process->active_debuggee = TRUE; - dbg_printf("WineDbg attached to pid %04lx\n", pid); + if (verbose) + dbg_printf("WineDbg attached to pid %04lx\n", pid); dbg_curr_pid = pid; dbg_curr_thread = NULL; dbg_curr_tid = 0; @@ -840,14 +837,14 @@ enum dbg_start dbg_active_attach(int argc, char* argv[]) /* try the form <myself> pid */ if (argc == 1 && str2int(argv[0], &pid) && pid != 0) { - if (!dbg_attach_debuggee(pid)) + if (!dbg_attach_debuggee(pid, TRUE)) return start_error_init; } /* try the form <myself> pid evt (Win32 JIT debugger) */ else if (argc == 2 && str2int(argv[0], &pid) && pid != 0 && str2int(argv[1], &evt) && evt != 0) { - if (!dbg_attach_debuggee(pid)) + if (!dbg_attach_debuggee(pid, TRUE)) { /* don't care about result */ SetEvent((HANDLE)evt); diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index bed25406e22..8a13a4639bf 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -253,6 +253,24 @@ static BOOL is_pe_module_embedded(struct tgt_process_minidump_data* data, return FALSE; } +static BOOL copy_context(dbg_ctx_t *ctx, struct tgt_process_minidump_data* data, + const MINIDUMP_LOCATION_DESCRIPTOR *loc_desc) +{ + BOOL ret = TRUE; + unsigned len = loc_desc->DataSize; + + if (len > sizeof(*ctx)) + { + ERR("Incoming context size is larger than internal structure\n"); + len = sizeof(*ctx); + ret = FALSE; + } + memcpy(ctx, (char*)data->mapping + loc_desc->Rva, len); + if (len < sizeof(*ctx)) + memset((char*)ctx + len, 0, sizeof(*ctx) - len); + return ret; +} + static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) { void* stream; @@ -556,8 +574,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) { dbg_curr_thread->excpt_record.ExceptionInformation[i] = mes->ExceptionRecord.ExceptionInformation[i]; } - memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva, - min(sizeof(dbg_context), mes->ThreadContext.DataSize)); + copy_context(&dbg_context, data, &mes->ThreadContext); memory_get_current_pc(&addr); stack_fetch_frames(&dbg_context); dbg_curr_process->be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0); @@ -676,6 +693,28 @@ static BOOL tgt_process_minidump_fetch_thread_name(const struct dbg_thread *thre return FALSE; } +static BOOL tgt_process_minidump_fetch_thread_context(const struct dbg_thread* thread, dbg_ctx_t *ctx) +{ + struct tgt_process_minidump_data *data = private_data(thread->process); + void *stream; + + if (MiniDumpReadDumpStream(data->mapping, ThreadListStream, NULL, &stream, NULL)) + { + MINIDUMP_THREAD_LIST* mtl = stream; + ULONG i; + + for (i = 0; i < mtl->NumberOfThreads; i++) + { + if (thread->tid == mtl->Threads[i].ThreadId) + { + copy_context(ctx, data, &mtl->Threads[i].ThreadContext); + return TRUE; + } + } + } + return FALSE; +} + static struct be_process_io be_process_minidump_io = { tgt_process_minidump_close_process, @@ -683,4 +722,5 @@ static struct be_process_io be_process_minidump_io = tgt_process_minidump_write, tgt_process_minidump_get_selector, tgt_process_minidump_fetch_thread_name, + tgt_process_minidump_fetch_thread_context, }; diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 6d9afba7a6d..9707120dfc7 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -82,8 +82,7 @@ DWORD dbg_curr_pid = 0; dbg_ctx_t dbg_context; BOOL dbg_interactiveP = FALSE; HANDLE dbg_houtput = 0; - -static struct list dbg_process_list = LIST_INIT(dbg_process_list); +struct list dbg_process_list = LIST_INIT(dbg_process_list); struct dbg_internal_var dbg_internal_vars[DBG_IV_LAST]; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10562
From: Eric Pouech <epouech@codeweavers.com> When attached to a minidump, only dump threads from the minidump. Signed-off-by: Eric Pouech <epouech@codeweavers.com> --- programs/winedbg/info.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index e1bb33bad53..feeaf42fdfb 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -676,7 +676,7 @@ static BOOL get_process_name(DWORD pid, PROCESSENTRY32W* entry) return ret; } -void info_win32_threads(void) +static void info_win32_active_threads(void) { HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (snap != INVALID_HANDLE_VALUE) @@ -732,6 +732,34 @@ void info_win32_threads(void) } } +void info_win32_threads(void) +{ + if (!dbg_curr_process || dbg_curr_process->active_debuggee) + info_win32_active_threads(); + else + { + struct dbg_process *pcs; + struct dbg_thread *thread; + WCHAR *description; + + dbg_printf("%-8.8s %-8.8s %s %s (all IDs are in hex)\n", + "process", "tid", "prio", "name"); + LIST_FOR_EACH_ENTRY(pcs, &dbg_process_list, struct dbg_process, entry) + { + dbg_printf("%08lx%s %ls\n", pcs->pid, " (D)", pcs->imageName); + LIST_FOR_EACH_ENTRY(thread, &pcs->threads, struct dbg_thread, entry) + { + description = dbg_fetch_thread_name(thread); + /* FIXME thread prio is available from a minidump */ + dbg_printf("\t%08lx %4s%s %ls\n", + thread->tid, "?", (thread->tid == dbg_curr_tid) ? " <==" : " ", + description ? description : L""); + free(description); + } + } + } +} + /*********************************************************************** * info_win32_frame_exceptions * -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10562
participants (2)
-
Eric Pouech -
eric pouech (@epo)