diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index cc4677551d6..e991508413e 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -47,7 +47,7 @@ int yyerror(const char*); struct type_expr_t type; } -%token tCONT tPASS tSTEP tLIST tNEXT tQUIT tHELP tBACKTRACE tINFO tUP tDOWN +%token tCONT tPASS tSTEP tLIST tNEXT tQUIT tHELP tBACKTRACE tALL tINFO tUP tDOWN %token tENABLE tDISABLE tBREAK tWATCH tDELETE tSET tMODE tPRINT tEXAM tABORT tVM86 %token tCLASS tMAPS tSTACK tSEGMENTS tSYMBOL tREGS tWND tQUEUE tLOCAL tEXCEPTION %token tPROCESS tTHREAD tMODREF tEOL tEOF @@ -119,6 +119,7 @@ command: | tABORT { abort(); } | tBACKTRACE { stack_backtrace(dbg_curr_tid, TRUE); } | tBACKTRACE tNUM { stack_backtrace($2, TRUE); } + | tBACKTRACE tALL { stack_backtrace(-1, TRUE); } | tUP { stack_set_frame(dbg_curr_frame + 1); } | tUP tNUM { stack_set_frame(dbg_curr_frame + $2); } | tDOWN { stack_set_frame(dbg_curr_frame - 1); } @@ -273,8 +274,9 @@ maintenance_command: ; noprocess_state: - tNOPROCESS {} /* shall not barf anything */ - | tNOPROCESS tSTRING { dbg_printf("No process loaded, cannot execute '%s'\n", $2); } + tNOPROCESS {} /* shall not barf anything */ + | tNOPROCESS tBACKTRACE tALL { stack_backtrace(-1, TRUE); } /* can backtrace all threads with no attached process */ + | tNOPROCESS tSTRING { dbg_printf("No process loaded, cannot execute '%s'\n", $2); } ; type_expr: @@ -449,11 +451,20 @@ static void stripwhite(char *string) static HANDLE dbg_parser_input; static HANDLE dbg_parser_output; +/* command passed in the command line arguments */ +char *arg_command = NULL; + int input_fetch_entire_line(const char* pfx, char** line, size_t* alloc, BOOL check_nl) { char buf_line[256]; DWORD nread; size_t len; + + if (arg_command) { + *line = arg_command; + arg_command = "quit\n"; /* we only run one command before exiting */ + return 1; + } /* as of today, console handles can be file handles... so better use file APIs rather than * console's @@ -501,7 +512,7 @@ int input_read_line(const char* pfx, char* buf, int size) assert(line); line[0] = '\n'; line[1] = '\0'; - + input_fetch_entire_line(pfx, &line, &len, FALSE); len = strlen(line); /* remove trailing \n */ diff --git a/programs/winedbg/debug.l b/programs/winedbg/debug.l index f28d50536db..61b3917dc03 100644 --- a/programs/winedbg/debug.l +++ b/programs/winedbg/debug.l @@ -143,8 +143,8 @@ STRING \"[^\n"]+\" x { BEGIN(FORMAT_EXPECTED); return tEXAM; } help|hel|he|"?" { BEGIN(HELP_CMD); return tHELP; } -backtrace|backtrac|backtra|backt|back|bac|ba|bt { BEGIN(NOCMD); return tBACKTRACE; } -where|wher|whe { BEGIN(NOCMD); return tBACKTRACE; } +backtrace|backtrac|backtra|backt|back|bac|ba|bt { BEGIN(NOCMD); return tBACKTRACE; } +where|wher|whe { BEGIN(NOCMD); return tBACKTRACE; } cont|con|co|c { BEGIN(NOCMD); return tCONT; } pass|pas|pa { BEGIN(NOCMD); return tPASS; } @@ -200,6 +200,7 @@ signed { return tSIGNED; } struct { return tSTRUCT; } union { return tUNION; } enum { return tENUM; } +all { return tALL; } {IDENTIFIER} { yylval.string = lexeme_alloc(yytext); return tIDENTIFIER; } "$"{IDENTIFIER} { yylval.string = lexeme_alloc(yytext+1); return tINTVAR; } diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index c36e9785f39..46d29607e78 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -109,6 +109,8 @@ enum dbg_exec_mode #endif }; +extern char *arg_command; + struct dbg_breakpoint { ADDRESS addr; diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c index 7ab5a9b13fb..43ab24cd248 100644 --- a/programs/winedbg/stack.c +++ b/programs/winedbg/stack.c @@ -28,6 +28,7 @@ #include "stackframe.h" #include "winbase.h" #include "wine/debug.h" +#include "tlhelp32.h" WINE_DEFAULT_DEBUG_CHANNEL(winedbg); @@ -103,6 +104,48 @@ void stack_backtrace(DWORD tid, BOOL noisy) struct dbg_thread* thread; unsigned nf; + if (tid == -1) /* backtrace every thread in every process except the debugger itself, invoking via "bt all" */ + { + THREADENTRY32 entry; + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + + if (snapshot == INVALID_HANDLE_VALUE) { + dbg_printf("unable to create toolhelp snapshot\n"); + return; + } + + entry.dwSize = sizeof(entry); + + if (!Thread32First(snapshot, &entry)) { + CloseHandle(snapshot); + return; + } + + do { + if (entry.th32OwnerProcessID == GetCurrentProcessId()) continue; + if (dbg_curr_process) dbg_detach_debuggee(); + + dbg_printf("\n"); + if (!dbg_attach_debuggee(entry.th32OwnerProcessID, FALSE, TRUE)) { + dbg_printf("\nwarning: could not attach to 0x%lx\n", entry.th32OwnerProcessID); + continue; + } + + dbg_printf("Backtracing for thread 0x%lx in process 0x%lx (%s):\n", entry.th32ThreadID, dbg_curr_pid, dbg_curr_process->imageName); + + stack_backtrace(entry.th32ThreadID, TRUE); + } while (Thread32Next(snapshot, &entry)); + + if (dbg_curr_process) dbg_detach_debuggee(); + CloseHandle(snapshot); + return; + } + + if (!dbg_curr_process) { + dbg_printf("You must be attached to a process to run this command.\n"); + return; + } + if (tid == dbg_curr_tid) { ctx = dbg_context; /* as StackWalk may modify it... */ diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 733f68fd282..1c4adf86983 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -1102,6 +1102,15 @@ int main(int argc, char** argv) /* parse options */ while (argc > 1 && argv[1][0] == '-') { + if (!strcmp(argv[1], "--command")) + { + argc--; argv++; + arg_command = HeapAlloc(GetProcessHeap(), 0, strlen(argv[1])+2); + strcpy(arg_command, argv[1]); + strcat(arg_command, "\n"); + argc--; argv++; + continue; + } if (!strcmp(argv[1], "--auto")) { if (dbg_action_mode != none_mode) return dbg_winedbg_usage();