# HG changeset patch # User Bram Moolenaar # Date 1543755606 -3600 # Node ID 8690318105eeb29dc41ec023c5bc8bbe77341de3 # Parent 1aa58d876f4f15b2fde6f7920aa41baa721f8dee patch 8.1.0557: Termdebug: gdb may use X.Y for breakpoint number commit https://github.com/vim/vim/commit/5378e1cf0a05121bfa76df2279944ad3b0b5ce4f Author: Bram Moolenaar Date: Sun Dec 2 13:47:03 2018 +0100 patch 8.1.0557: Termdebug: gdb may use X.Y for breakpoint number Problem: Termdebug: gdb may use X.Y for breakpoint number. Solution: Handle X.Y breakpoint numbers. (Yasuhiro Matsumoto, close https://github.com/vim/vim/issues/3641) 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 @@ -73,6 +73,13 @@ let s:pc_id = 12 let s:break_id = 13 " breakpoint number is added to this let s:stopped = 1 +" Take a breakpoint number as used by GDB and turn it into an integer. +" The breakpoint may contain a dot: 123.4 +func s:Breakpoint2SignNumber(nr) + let t = split(a:nr, '\.') + return t[0] * 1000 + (len(t) == 2 ? t[1] : 0) +endfunction + func s:Highlight(init, old, new) let default = a:init ? 'default ' : '' if a:new ==# 'light' && a:old !=# 'light' @@ -138,9 +145,9 @@ endfunc func s:StartDebug_term(dict) " Open a terminal window without a job, to run the debugged program in. let s:ptybuf = term_start('NONE', { - \ 'term_name': 'debugged program', - \ 'vertical': s:vertical, - \ }) + \ 'term_name': 'debugged program', + \ 'vertical': s:vertical, + \ }) if s:ptybuf == 0 echoerr 'Failed to open the program terminal window' return @@ -155,10 +162,10 @@ func s:StartDebug_term(dict) " Create a hidden terminal window to communicate with gdb let s:commbuf = term_start('NONE', { - \ 'term_name': 'gdb communication', - \ 'out_cb': function('s:CommOutput'), - \ 'hidden': 1, - \ }) + \ 'term_name': 'gdb communication', + \ 'out_cb': function('s:CommOutput'), + \ 'hidden': 1, + \ }) if s:commbuf == 0 echoerr 'Failed to open the communication terminal window' exe 'bwipe! ' . s:ptybuf @@ -174,9 +181,9 @@ func s:StartDebug_term(dict) let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args call ch_log('executing "' . join(cmd) . '"') let s:gdbbuf = term_start(cmd, { - \ 'exit_cb': function('s:EndTermDebug'), - \ 'term_finish': 'close', - \ }) + \ 'exit_cb': function('s:EndTermDebug'), + \ 'term_finish': 'close', + \ }) if s:gdbbuf == 0 echoerr 'Failed to open the gdb terminal window' exe 'bwipe! ' . s:ptybuf @@ -200,18 +207,18 @@ func s:StartDebug_term(dict) let response = '' for lnum in range(1,200) if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' - " response can be in the same line or the next line - let response = term_getline(s:gdbbuf, lnum) . term_getline(s:gdbbuf, lnum + 1) - if response =~ 'Undefined command' - echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' - exe 'bwipe! ' . s:ptybuf - exe 'bwipe! ' . s:commbuf - return - endif - if response =~ 'New UI allocated' - " Success! - break - endif + " response can be in the same line or the next line + let response = term_getline(s:gdbbuf, lnum) . term_getline(s:gdbbuf, lnum + 1) + if response =~ 'Undefined command' + echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' + exe 'bwipe! ' . s:ptybuf + exe 'bwipe! ' . s:commbuf + return + endif + if response =~ 'New UI allocated' + " Success! + break + endif endif endfor if response =~ 'New UI allocated' @@ -268,9 +275,9 @@ func s:StartDebug_prompt(dict) call ch_log('executing "' . join(cmd) . '"') let s:gdbjob = job_start(cmd, { - \ 'exit_cb': function('s:EndPromptDebug'), - \ 'out_cb': function('s:GdbOutCallback'), - \ }) + \ 'exit_cb': function('s:EndPromptDebug'), + \ 'out_cb': function('s:GdbOutCallback'), + \ }) if job_status(s:gdbjob) != "run" echoerr 'Failed to start gdb' exe 'bwipe! ' . s:promptbuf @@ -295,8 +302,8 @@ func s:StartDebug_prompt(dict) " Unix: Run the debugged program in a terminal window. Open it below the " gdb window. belowright let s:ptybuf = term_start('NONE', { - \ 'term_name': 'debugged program', - \ }) + \ 'term_name': 'debugged program', + \ }) if s:ptybuf == 0 echoerr 'Failed to open the program terminal window' call job_stop(s:gdbjob) @@ -353,7 +360,8 @@ func s:StartDebugCommon(dict) endif endif - " Contains breakpoints that have been placed, key is the number. + " Contains breakpoints that have been placed, key is a string with the GDB + " breakpoint number. let s:breakpoints = {} augroup TermDebug @@ -466,9 +474,9 @@ func s:DecodeMessage(quotedText) if a:quotedText[i] == '\' let i += 1 if a:quotedText[i] == 'n' - " drop \n - let i += 1 - continue + " drop \n + let i += 1 + continue endif endif let result .= a:quotedText[i] @@ -479,6 +487,9 @@ endfunc " Extract the "name" value from a gdb message with fullname="name". func s:GetFullname(msg) + if a:msg !~ 'fullname' + return '' + endif let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', '')) if has('win32') && name =~ ':\\\\' " sometimes the name arrives double-escaped @@ -549,17 +560,17 @@ func s:CommOutput(chan, msg) endif if msg != '' if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' - call s:HandleCursor(msg) + call s:HandleCursor(msg) elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' - call s:HandleNewBreakpoint(msg) + call s:HandleNewBreakpoint(msg) elseif msg =~ '^=breakpoint-deleted,' - call s:HandleBreakpointDelete(msg) + call s:HandleBreakpointDelete(msg) elseif msg =~ '^=thread-group-started' - call s:HandleProgramRun(msg) + call s:HandleProgramRun(msg) elseif msg =~ '^\^done,value=' - call s:HandleEvaluate(msg) + call s:HandleEvaluate(msg) elseif msg =~ '^\^error,msg=' - call s:HandleError(msg) + call s:HandleError(msg) endif endif endfor @@ -650,12 +661,12 @@ func s:DeleteCommands() let curwinid = win_getid(winnr()) for winid in s:winbar_winids if win_gotoid(winid) - aunmenu WinBar.Step - aunmenu WinBar.Next - aunmenu WinBar.Finish - aunmenu WinBar.Cont - aunmenu WinBar.Stop - aunmenu WinBar.Eval + aunmenu WinBar.Step + aunmenu WinBar.Next + aunmenu WinBar.Finish + aunmenu WinBar.Cont + aunmenu WinBar.Stop + aunmenu WinBar.Eval endif endfor call win_gotoid(curwinid) @@ -673,7 +684,7 @@ func s:DeleteCommands() exe 'sign unplace ' . s:pc_id for key in keys(s:breakpoints) - exe 'sign unplace ' . (s:break_id + key) + exe 'sign unplace ' . (s:break_id + s:Breakpoint2SignNumber(key)) endfor unlet s:breakpoints @@ -700,7 +711,7 @@ func s:SetBreakpoint() endif " Use the fname:lnum format, older gdb can't handle --source. call s:SendCommand('-break-insert ' - \ . fnameescape(expand('%:p')) . ':' . line('.')) + \ . fnameescape(expand('%:p')) . ':' . line('.')) if do_continue call s:SendCommand('-exec-continue') endif @@ -714,7 +725,7 @@ func s:ClearBreakpoint() if val['fname'] == fname && val['lnum'] == lnum call s:SendCommand('-break-delete ' . key) " Assume this always wors, the reply is simply "^done". - exe 'sign unplace ' . (s:break_id + key) + exe 'sign unplace ' . (s:break_id + s:Breakpoint2SignNumber(key)) unlet s:breakpoints[key] break endif @@ -839,14 +850,14 @@ func s:HandleCursor(msg) if lnum =~ '^[0-9]*$' call s:GotoSourcewinOrCreateIt() if expand('%:p') != fnamemodify(fname, ':p') - if &modified - " TODO: find existing window - exe 'split ' . fnameescape(fname) - let s:sourcewin = win_getid(winnr()) - call s:InstallWinbar() - else - exe 'edit ' . fnameescape(fname) - endif + if &modified + " TODO: find existing window + exe 'split ' . fnameescape(fname) + let s:sourcewin = win_getid(winnr()) + call s:InstallWinbar() + else + exe 'edit ' . fnameescape(fname) + endif endif exe lnum exe 'sign unplace ' . s:pc_id @@ -865,10 +876,14 @@ let s:BreakpointSigns = [] func s:CreateBreakpoint(nr) if index(s:BreakpointSigns, a:nr) == -1 call add(s:BreakpointSigns, a:nr) - exe "sign define debugBreakpoint" . a:nr . " text=" . a:nr . " texthl=debugBreakpoint" + exe "sign define debugBreakpoint" . a:nr . " text=" . substitute(a:nr, '\..*', '', '') . " texthl=debugBreakpoint" endif endfunc +func s:SplitMsg(s) + return split(a:s, '{\%([a-z-]\+=[^,]\+,*\)\+}\zs') +endfunction + " Handle setting a breakpoint " Will update the sign that shows the breakpoint func s:HandleNewBreakpoint(msg) @@ -876,50 +891,57 @@ func s:HandleNewBreakpoint(msg) " a watch does not have a file name return endif - - let nr = substitute(a:msg, '.*number="\([0-9]*\)".*', '\1', '') + 0 - if nr == 0 - return - endif - call s:CreateBreakpoint(nr) + for msg in s:SplitMsg(a:msg) + let fname = s:GetFullname(msg) + if empty(fname) + continue + endif + let nr = substitute(msg, '.*number="\([0-9.]*\)\".*', '\1', '') + if empty(nr) + return + endif + call s:CreateBreakpoint(nr) - if has_key(s:breakpoints, nr) - let entry = s:breakpoints[nr] - else - let entry = {} - let s:breakpoints[nr] = entry - endif + if has_key(s:breakpoints, nr) + let entry = s:breakpoints[nr] + else + let entry = {} + let s:breakpoints[nr] = entry + endif - let fname = s:GetFullname(a:msg) - let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') - let entry['fname'] = fname - let entry['lnum'] = lnum + let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '') + let entry['fname'] = fname + let entry['lnum'] = lnum - if bufloaded(fname) - call s:PlaceSign(nr, entry) - endif + if bufloaded(fname) + call s:PlaceSign(nr, entry) + endif + endfor endfunc func s:PlaceSign(nr, entry) - exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint' . a:nr . ' file=' . a:entry['fname'] + exe 'sign place ' . (s:break_id + s:Breakpoint2SignNumber(a:nr)) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint' . a:nr . ' file=' . a:entry['fname'] let a:entry['placed'] = 1 endfunc " Handle deleting a breakpoint " Will remove the sign that shows the breakpoint func s:HandleBreakpointDelete(msg) - let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 - if nr == 0 + let key = substitute(a:msg, '.*id="\([0-9.]*\)\".*', '\1', '') + if empty(key) return endif - if has_key(s:breakpoints, nr) + for [nr, entry] in items(s:breakpoints) + if stridx(nr, key) != 0 + continue + endif let entry = s:breakpoints[nr] if has_key(entry, 'placed') - exe 'sign unplace ' . (s:break_id + nr) + exe 'sign unplace ' . (s:break_id + s:Breakpoint2SignNumber(nr)) unlet entry['placed'] endif unlet s:breakpoints[nr] - endif + endfor endfunc " Handle the debugged program starting to run. diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -793,6 +793,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 557, +/**/ 556, /**/ 555,