changeset 15093:8690318105ee v8.1.0557

patch 8.1.0557: Termdebug: gdb may use X.Y for breakpoint number commit https://github.com/vim/vim/commit/5378e1cf0a05121bfa76df2279944ad3b0b5ce4f Author: Bram Moolenaar <Bram@vim.org> 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)
author Bram Moolenaar <Bram@vim.org>
date Sun, 02 Dec 2018 14:00:06 +0100
parents 1aa58d876f4f
children 692073d2f61c
files runtime/pack/dist/opt/termdebug/plugin/termdebug.vim src/version.c
diffstat 2 files changed, 104 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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,