This series: - add a couple of commands to winedbg to ease scripting (mainly reload a minidump from parser, run a debuggee with arguments...). - a couple of quick fixes (updating CPU info displayed on reload) and detecting reloading a minidump for a different machine.
WOW64 support in minidump (dbghelp & winedbg) will require quite some work.
From: Eric Pouech epouech@codeweavers.com
Either from command line option, or as a command. Mostly handy for scripting.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/dbg.y | 3 ++- programs/winedbg/debug.l | 1 + programs/winedbg/debugger.h | 1 + programs/winedbg/tgt_active.c | 7 +++++++ programs/winedbg/winedbg.c | 14 +++++++++----- programs/winedbg/winedbg.man.in | 2 ++ 6 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index fc9a2977041..6e71d310c22 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -58,7 +58,7 @@ static void parser(const char*); %token <string> tPATH tIDENTIFIER tSTRING tINTVAR %token <integer> tNUM tFORMAT %token <type> tTYPEDEF -%token tSYMBOLFILE tRUN tATTACH tDETACH tKILL tMAINTENANCE tTYPE tMINIDUMP +%token tSYMBOLFILE tEXECFILE tRUN tATTACH tDETACH tKILL tMAINTENANCE tTYPE tMINIDUMP %token tNOPROCESS tWOW
/* can be prefixed by module name */ @@ -146,6 +146,7 @@ command: | tKILL { dbg_curr_process->process_io->close_process(dbg_curr_process, TRUE); } | tMINIDUMP pathname { minidump_write($2, (dbg_curr_thread && dbg_curr_thread->in_exception) ? &dbg_curr_thread->excpt_record : NULL);} | tECHO tSTRING { dbg_printf("%s\n", $2); } + | tEXECFILE pathname { dbg_set_exec_file($2); } | run_command | list_command | disassemble_command diff --git a/programs/winedbg/debug.l b/programs/winedbg/debug.l index dd7fb0db76f..a05a27dfc79 100644 --- a/programs/winedbg/debug.l +++ b/programs/winedbg/debug.l @@ -224,6 +224,7 @@ STRING "(\[^\n]|[^\"\n])*" <INITIAL>rwatch|rwatc|rwat { BEGIN(NOCMD); return tRWATCH; } <INITIAL>whatis|whati|what { BEGIN(NOCMD); return tWHATIS; } <INITIAL,NOPROCESS>run|ru|r { BEGIN(AWORD_EXPECTED); return tRUN;} +<INITIAL,NOPROCESS>exec-file { BEGIN(PATH_EXPECTED); return tEXECFILE;} <INITIAL>detach|detac|deta|det { BEGIN(NOCMD); return tDETACH; } <INITIAL>kill|kil|ki|k { BEGIN(NOCMD); return tKILL; } <INITIAL,NOPROCESS>maintenance|maint { BEGIN(MAINT_CMD); return tMAINTENANCE; } diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index c65b9bfae67..49cab156df1 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -474,6 +474,7 @@ struct list_string char* string; struct list_string* next; }; +extern void dbg_set_exec_file(const char *path); extern void dbg_run_debuggee(struct list_string* ls); extern void dbg_wait_next_exception(DWORD cont, int count, int mode); extern enum dbg_start dbg_active_attach(int argc, char* argv[]); diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 9587ef450d2..209d82374c6 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -87,6 +87,7 @@ BOOL dbg_attach_debuggee(DWORD pid) SetEnvironmentVariableA("DBGHELP_NOLIVE", NULL);
dbg_curr_process->active_debuggee = TRUE; + dbg_printf("WineDbg attached to pid %04lx\n", dbg_curr_pid); return TRUE; }
@@ -670,6 +671,7 @@ static BOOL dbg_start_debuggee(LPSTR cmdLine) free(dbg_last_cmd_line); dbg_last_cmd_line = cmdLine; } + dbg_printf("WineDbg starting on pid %04lx\n", dbg_curr_pid);
return TRUE; } @@ -755,6 +757,11 @@ static char *dbg_build_command_line( char **argv ) return ret; }
+void dbg_set_exec_file(const char *path) +{ + free(dbg_executable); + dbg_executable = strdup(path); +}
void dbg_run_debuggee(struct list_string* ls) { diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 39ce6cbf8a9..b642284f73b 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -637,11 +637,8 @@ void dbg_start_interactive(const char* filename, HANDLE hFile) struct dbg_process* p; struct dbg_process* p2;
- if (dbg_curr_process) - { - dbg_printf("WineDbg starting on pid %04lx\n", dbg_curr_pid); - if (dbg_curr_process->active_debuggee) dbg_active_wait_for_first_exception(); - } + if (dbg_curr_process && dbg_curr_process->active_debuggee) + dbg_active_wait_for_first_exception();
dbg_interactiveP = TRUE; parser_handle(filename, hFile); @@ -759,6 +756,13 @@ int main(int argc, char** argv) argc--; argv++; continue; } + if (!strcmp(argv[0], "--exec") && argc > 1) + { + argc--; argv++; + dbg_set_exec_file(argv[0]); + argc--; argv++; + continue; + } if (!strcmp(argv[0], "--file") && argc > 1) { argc--; argv++; diff --git a/programs/winedbg/winedbg.man.in b/programs/winedbg/winedbg.man.in index c58696ba1c9..1380832537f 100644 --- a/programs/winedbg/winedbg.man.in +++ b/programs/winedbg/winedbg.man.in @@ -61,6 +61,8 @@ When in \fBdefault\fR mode, the following options are available: \fBwinedbg\fR will execute the command \fIstring\fR as if it was keyed on winedbg command line, and then will exit. This can be handy for getting the pid of running processes (winedbg --command "info proc"). +.IP \fB--exec\ \fIfilename\fR +Sets the executable name, without starting the executable. .IP \fB--file\ \fIfilename\fR \fBwinedbg\fR will execute the list of commands contained in file filename as if they were keyed on winedbg command line, and then
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/dbg.y | 3 ++- programs/winedbg/debugger.h | 3 ++- programs/winedbg/tgt_minidump.c | 28 +++++++++++++++++++--------- programs/winedbg/winedbg.c | 2 +- programs/winedbg/winedbg.man.in | 24 +++++++++++++----------- 5 files changed, 37 insertions(+), 23 deletions(-)
diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index 6e71d310c22..f3af249ee07 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -141,10 +141,11 @@ command: | 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 { dbg_attach_debuggee($2); 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); } | tKILL { dbg_curr_process->process_io->close_process(dbg_curr_process, TRUE); } - | tMINIDUMP pathname { minidump_write($2, (dbg_curr_thread && dbg_curr_thread->in_exception) ? &dbg_curr_thread->excpt_record : NULL);} + | tMINIDUMP pathname { minidump_write($2, (dbg_curr_thread && dbg_curr_thread->in_exception) ? &dbg_curr_thread->excpt_record : NULL); } | tECHO tSTRING { dbg_printf("%s\n", $2); } | tEXECFILE pathname { dbg_set_exec_file($2); } | run_command diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 49cab156df1..096fc1e84b0 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -488,7 +488,8 @@ extern void fetch_module_name(void* name_addr, void* mod_addr, WCHAR
/* tgt_minidump.c */ extern void minidump_write(const char*, const EXCEPTION_RECORD*); -extern enum dbg_start minidump_reload(int argc, char* argv[]); +extern enum dbg_start minidump_reload(const char *); +extern enum dbg_start minidump_start(int argc, char* argv[]);
/* tgt_module.c */ extern enum dbg_start tgt_module_load(const char* name, BOOL keep); diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index ac8d9be71b2..c2594251d67 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -307,7 +307,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) const char *str; char tmp[128];
- dbg_printf("WineDbg starting on minidump on pid %04lx\n", pid); + dbg_printf("WineDbg starting minidump on pid %04lx\n", pid); switch (msi->ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_UNKNOWN: @@ -564,23 +564,23 @@ static void cleanup(struct tgt_process_minidump_data* data)
static struct be_process_io be_process_minidump_io;
-enum dbg_start minidump_reload(int argc, char* argv[]) +enum dbg_start minidump_reload(const char* filename) { struct tgt_process_minidump_data* data; enum dbg_start ret = start_error_parse;
- /* try the form <myself> minidump-file */ - if (argc != 1) return start_error_parse; - - WINE_TRACE("Processing Minidump file %s\n", argv[0]); - + if (dbg_curr_process) + { + dbg_printf("Already attached to a process. Use 'detach' or 'kill' before loading a minidump file'\n"); + return start_error_init; + } data = malloc(sizeof(struct tgt_process_minidump_data)); if (!data) return start_error_init; data->mapping = NULL; data->hMap = NULL; data->hFile = INVALID_HANDLE_VALUE;
- if ((data->hFile = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ, NULL, + if ((data->hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE && ((data->hMap = CreateFileMappingA(data->hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) && ((data->mapping = MapViewOfFile(data->hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)) @@ -594,7 +594,7 @@ enum dbg_start minidump_reload(int argc, char* argv[]) } __EXCEPT_PAGE_FAULT { - dbg_printf("Unexpected fault while reading minidump %s\n", argv[0]); + dbg_printf("Unexpected fault while reading minidump %s\n", filename); dbg_curr_pid = 0; } __ENDTRY; @@ -603,6 +603,16 @@ enum dbg_start minidump_reload(int argc, char* argv[]) return ret; }
+enum dbg_start minidump_start(int argc, char* argv[]) +{ + /* try the form <myself> minidump-file */ + if (argc != 1) return start_error_parse; + + WINE_TRACE("Processing Minidump file %s\n", argv[0]); + + return minidump_reload(argv[0]); +} + static BOOL tgt_process_minidump_close_process(struct dbg_process* pcs, BOOL kill) { struct tgt_process_minidump_data* data = private_data(pcs); diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index b642284f73b..c7f14e8238f 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -786,7 +786,7 @@ int main(int argc, char** argv) } if (!argc) ds = start_ok; else if ((ds = dbg_active_attach(argc, argv)) == start_error_parse && - (ds = minidump_reload(argc, argv)) == start_error_parse) + (ds = minidump_start(argc, argv)) == start_error_parse) ds = dbg_active_launch(argc, argv); switch (ds) { diff --git a/programs/winedbg/winedbg.man.in b/programs/winedbg/winedbg.man.in index 1380832537f..ec9b1bb37ea 100644 --- a/programs/winedbg/winedbg.man.in +++ b/programs/winedbg/winedbg.man.in @@ -138,18 +138,26 @@ Exits the debugger. Attach to a Wine process (\fIN\fR is its Windows ID, numeric or hexadecimal). IDs can be obtained using the \fBinfo\ process\fR command. Note the \fBinfo\ process\fR command returns hexadecimal values -.IP +.IP \fBattach\ \fIfile.mdmp\fR +Reload the state of a debuggee from the minidump \fIfile.mdmp\fR. +See the \fBminidump\fR command to save such a file. .IP \fBdetach\fR -Detach from a Wine-process. -.IP \fBthread\ \fIN\fR -Change the current thread to \fIN\fR (its Windows TID, numeric or hexadecimal). -.IP +Detach the current Wine-process. The process is no longer debugged by WineDbg, +but is still running (for a live target). +.IP \fBkill\fR +Kills the current Wine-process. The process is no longer debugged by WineDbg, +and is also terminated (for a live target). +.IP \fBminidump\fR\ \fIfile.mdmp\fR +Saves the debugging context of the debuggee into a minidump file called +\fIfile.mdmp\fR. .IP \fBrun\fR Re-run the same process with the same arguments. Note: all breakpoints of precedent process are no longer available. .IP \fBrun\ \fIarg1\ arg2...\fR Re-run the same process with arguments \fIarg1\ arg2...\fR. Note: all breakpoints of precedent process are no longer available. +.IP \fBthread\ \fIN\fR +Change the current thread to \fIN\fR (its Windows TID, numeric or hexadecimal). .PP \fIHelp commands\fR .IP \fBhelp\fR @@ -355,12 +363,6 @@ When specifying an identifier, if several symbols with this name exist, the debugger will prompt for the symbol you want to use. Pick up the one you want from its number. .PP -\fIMisc.\fR -.PP -.BI "minidump " file.mdmp -saves the debugging context of the debuggee into a minidump file called -\fIfile.mdmp\fR. -.PP \fIInformation on Wine internals\fR .IP \fBinfo\ class\fR Lists all Windows classes registered in Wine
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/dbg.y | 1 + 1 file changed, 1 insertion(+)
diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index f3af249ee07..6f4bb10fed8 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -630,6 +630,7 @@ void parser_handle(const char* filename, HANDLE input) } __ENDTRY; lexeme_flush(); + expr_free_all(); } while (!ret_ok);
dbg_parser = prev;
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/tgt_minidump.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index c2594251d67..309d5c526ab 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -314,17 +314,20 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) str = "Unknown"; break; case PROCESSOR_ARCHITECTURE_INTEL: - strcpy(tmp, "Intel "); + strcpy(tmp, "x86 ["); switch (msi->ProcessorLevel) { case 3: str = "80386"; break; case 4: str = "80486"; break; case 5: str = "Pentium"; break; - case 6: str = "Pentium Pro/II or AMD Athlon"; break; + case 6: str = "Pentium Pro/II, III, Core, Atom or AMD Athlon"; break; case 15: str = "Pentium 4 or AMD Athlon64"; break; - default: str = "???"; break; + case 23: str = "AMD Zen 1 or 2"; break; + case 25: str = "AMD Zen 3 or 4"; break; + case 26: str = "AMD Zen 5"; break; + default: sprintf(tmp + strlen(tmp), "Proc-level #%x", msi->ProcessorLevel); str = NULL; break; } - strcat(tmp, str); + if (str) strcat(tmp, str); if (msi->ProcessorLevel == 3 || msi->ProcessorLevel == 4) { if (HIBYTE(msi->ProcessorRevision) == 0xFF) @@ -339,6 +342,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) else sprintf(tmp + strlen(tmp), " (%d.%d)", HIBYTE(msi->ProcessorRevision), LOBYTE(msi->ProcessorRevision)); + strcat(tmp, "]"); str = tmp; break; case PROCESSOR_ARCHITECTURE_MIPS:
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/winedbg/tgt_minidump.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index 309d5c526ab..87098491392 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -303,9 +303,10 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data)
if (MiniDumpReadDumpStream(data->mapping, SystemInfoStream, &dir, &stream, NULL)) { - MINIDUMP_SYSTEM_INFO* msi = stream; - const char *str; - char tmp[128]; + MINIDUMP_SYSTEM_INFO *msi = stream; + USHORT machine = IMAGE_FILE_MACHINE_UNKNOWN; + const char *str; + char tmp[128];
dbg_printf("WineDbg starting minidump on pid %04lx\n", pid); switch (msi->ProcessorArchitecture) @@ -314,6 +315,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) str = "Unknown"; break; case PROCESSOR_ARCHITECTURE_INTEL: + machine = IMAGE_FILE_MACHINE_I386; strcpy(tmp, "x86 ["); switch (msi->ProcessorLevel) { @@ -355,6 +357,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) str = "PowerPC"; break; case PROCESSOR_ARCHITECTURE_AMD64: + machine = IMAGE_FILE_MACHINE_AMD64; str = "X86_64"; break; case PROCESSOR_ARCHITECTURE_ARM: @@ -462,6 +465,15 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) code + wes[1], code + wes[2], code + wes[3]); } } + if (machine == IMAGE_FILE_MACHINE_UNKNOWN +#ifdef __x86_64__ + || machine == IMAGE_FILE_MACHINE_I386 +#endif + ) + { + dbg_printf("Cannot reload this minidump because of incompatible/unsupported machine %x\n", machine); + return FALSE; + } }
dbg_curr_process = dbg_add_process(&be_process_minidump_io, pid, hProc);