# HG changeset patch # User Christian Brabandt # Date 1529527505 -7200 # Node ID de75c249723d15640f078cf152da0949cdf5feb1 # Parent 63473cfe56b06f6e52532636cf9795e76093c75d patch 8.1.0091: MS-Windows: Cannot interrupt gdb when program is running commit https://github.com/vim/vim/commit/4551c0a9fcdbdef52836d4852686d54b5e47fdaf Author: Bram Moolenaar Date: Wed Jun 20 22:38:21 2018 +0200 patch 8.1.0091: MS-Windows: Cannot interrupt gdb when program is running Problem: MS-Windows: Cannot interrupt gdb when program is running. Solution: Add debugbreak() and use it in the terminal debugger. Respect 'modified' in a prompt buffer. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2108,6 +2108,7 @@ cscope_connection([{num}, {dbpath} [, {p cursor({lnum}, {col} [, {off}]) Number move cursor to {lnum}, {col}, {off} cursor({list}) Number move cursor to position in {list} +debugbreak({pid}) Number interrupt process being debugged deepcopy({expr} [, {noref}]) any make a full copy of {expr} delete({fname} [, {flags}]) Number delete the file or directory {fname} deletebufline({expr}, {first}[, {last}]) @@ -3480,6 +3481,11 @@ cursor({list}) position within a or after the last character. Returns 0 when the position could be set, -1 otherwise. +debugbreak({pid}) *debugbreak()* + Specifically used to interrupt a program being debugged. It + will cause process {pid} to get a SIGTRAP. Behavior for other + processes is undefined. See |terminal-debugger|. + {only available on MS-Windows} deepcopy({expr} [, {noref}]) *deepcopy()* *E698* Make a copy of {expr}. For Numbers and Strings this isn't diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -98,6 +98,7 @@ func s:StartDebug_internal(dict) return endif let s:ptywin = 0 + let s:pid = 0 " Uncomment this line to write logging in "debuglog". " call ch_logfile('debuglog', 'w') @@ -271,6 +272,8 @@ func s:StartDebug_prompt(dict) exe 'bwipe! ' . s:promptbuf return endif + " Mark the buffer modified so that it's not easy to close. + set modified let s:gdb_channel = job_getchannel(s:gdbjob) " Interpret commands while the target is running. This should usualy only @@ -396,10 +399,16 @@ func s:PromptCallback(text) call s:SendCommand(a:text) endfunc -" Function called when pressing CTRL-C in the prompt buffer. +" Function called when pressing CTRL-C in the prompt buffer and when placing a +" breakpoint. func s:PromptInterrupt() - call ch_log('Interrupting gdb') - call job_stop(s:gdbjob, 'int') + if s:pid == 0 + echoerr 'Cannot interrupt gdb, did not find a process ID' + else + call ch_log('Interrupting gdb') + " Using job_stop(s:gdbjob, 'int') does not work. + call debugbreak(s:pid) + endif endfunc " Function called when gdb outputs text. @@ -430,7 +439,7 @@ func s:GdbOutCallback(channel, text) " Add the output above the current prompt. call append(line('$') - 1, text) - set nomodified + set modified call win_gotoid(curwinid) endfunc @@ -509,6 +518,7 @@ endfunc func s:EndPromptDebug(job, status) let curwinid = win_getid(winnr()) call win_gotoid(s:gdbwin) + set nomodified close if curwinid != s:gdbwin call win_gotoid(curwinid) @@ -535,6 +545,8 @@ func s:CommOutput(chan, msg) call s:HandleNewBreakpoint(msg) elseif msg =~ '^=breakpoint-deleted,' call s:HandleBreakpointDelete(msg) + elseif msg =~ '^=thread-group-started' + call s:HandleProgramRun(msg) elseif msg =~ '^\^done,value=' call s:HandleEvaluate(msg) elseif msg =~ '^\^error,msg=' @@ -655,7 +667,7 @@ func s:DeleteCommands() for val in s:BreakpointSigns exe "sign undefine debugBreakpoint" . val endfor - unlet s:BreakpointSigns + let s:BreakpointSigns = [] endfunc " :Break - Set a breakpoint at the cursor position. @@ -666,9 +678,7 @@ func s:SetBreakpoint() if !s:stopped let do_continue = 1 if s:way == 'prompt' - " Need to send a signal to get the UI to listen. Strangely this is only - " needed once. - call job_stop(s:gdbjob, 'int') + call s:PromptInterrupt() else call s:SendCommand('-exec-interrupt') endif @@ -798,13 +808,13 @@ func s:HandleCursor(msg) let wid = win_getid(winnr()) if a:msg =~ '^\*stopped' + call ch_log('program stopped') let s:stopped = 1 elseif a:msg =~ '^\*running' + call ch_log('program running') let s:stopped = 0 endif - call s:GotoSourcewinOrCreateIt() - if a:msg =~ 'fullname=' let fname = s:GetFullname(a:msg) else @@ -813,6 +823,7 @@ func s:HandleCursor(msg) if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') if lnum =~ '^[0-9]*$' + call s:GotoSourcewinOrCreateIt() if expand('%:p') != fnamemodify(fname, ':p') if &modified " TODO: find existing window @@ -828,7 +839,7 @@ func s:HandleCursor(msg) exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname setlocal signcolumn=yes endif - else + elseif !s:stopped || fname != '' exe 'sign unplace ' . s:pc_id endif @@ -892,6 +903,17 @@ func s:HandleBreakpointDelete(msg) endif endfunc +" Handle the debugged program starting to run. +" Will store the process ID in s:pid +func s:HandleProgramRun(msg) + let nr = substitute(a:msg, '.*pid="\([0-9]*\)\".*', '\1', '') + 0 + if nr == 0 + return + endif + let s:pid = nr + call ch_log('Detected process ID: ' . s:pid) +endfunc + " Handle a BufRead autocommand event: place any signs. func s:BufRead() let fname = expand(':p') diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -123,6 +123,9 @@ static void f_cosh(typval_T *argvars, ty static void f_count(typval_T *argvars, typval_T *rettv); static void f_cscope_connection(typval_T *argvars, typval_T *rettv); static void f_cursor(typval_T *argsvars, typval_T *rettv); +#ifdef WIN3264 +static void f_debugbreak(typval_T *argvars, typval_T *rettv); +#endif static void f_deepcopy(typval_T *argvars, typval_T *rettv); static void f_delete(typval_T *argvars, typval_T *rettv); static void f_deletebufline(typval_T *argvars, typval_T *rettv); @@ -577,6 +580,9 @@ static struct fst {"count", 2, 4, f_count}, {"cscope_connection",0,3, f_cscope_connection}, {"cursor", 1, 3, f_cursor}, +#ifdef WIN3264 + {"debugbreak", 1, 1, f_debugbreak}, +#endif {"deepcopy", 1, 2, f_deepcopy}, {"delete", 1, 2, f_delete}, {"deletebufline", 2, 3, f_deletebufline}, @@ -2761,6 +2767,33 @@ f_cursor(typval_T *argvars, typval_T *re rettv->vval.v_number = 0; } +#ifdef WIN3264 +/* + * "debugbreak()" function + */ + static void +f_debugbreak(typval_T *argvars, typval_T *rettv) +{ + int pid; + + rettv->vval.v_number = FAIL; + pid = (int)get_tv_number(&argvars[0]); + if (pid == 0) + EMSG(_(e_invarg)); + else + { + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid); + + if (hProcess != NULL) + { + DebugBreakProcess(hProcess); + CloseHandle(hProcess); + rettv->vval.v_number = OK; + } + } +} +#endif + /* * "deepcopy()" function */ diff --git a/src/undo.c b/src/undo.c --- a/src/undo.c +++ b/src/undo.c @@ -3539,7 +3539,9 @@ bufIsChanged(buf_T *buf) int bufIsChangedNotTerm(buf_T *buf) { - return !bt_dontwrite(buf) + // In a "prompt" buffer we do respect 'modified', so that we can control + // closing the window by setting or resetting that option. + return (!bt_dontwrite(buf) || bt_prompt(buf)) && (buf->b_changed || file_ff_differs(buf, TRUE)); } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -762,6 +762,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 91, +/**/ 90, /**/ 89,