mirror of
https://github.com/vim/vim.git
synced 2025-09-29 04:34:16 -04:00
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 #3641)
This commit is contained in:
182
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
182
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
@@ -73,6 +73,13 @@ let s:pc_id = 12
|
|||||||
let s:break_id = 13 " breakpoint number is added to this
|
let s:break_id = 13 " breakpoint number is added to this
|
||||||
let s:stopped = 1
|
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)
|
func s:Highlight(init, old, new)
|
||||||
let default = a:init ? 'default ' : ''
|
let default = a:init ? 'default ' : ''
|
||||||
if a:new ==# 'light' && a:old !=# 'light'
|
if a:new ==# 'light' && a:old !=# 'light'
|
||||||
@@ -138,9 +145,9 @@ endfunc
|
|||||||
func s:StartDebug_term(dict)
|
func s:StartDebug_term(dict)
|
||||||
" Open a terminal window without a job, to run the debugged program in.
|
" Open a terminal window without a job, to run the debugged program in.
|
||||||
let s:ptybuf = term_start('NONE', {
|
let s:ptybuf = term_start('NONE', {
|
||||||
\ 'term_name': 'debugged program',
|
\ 'term_name': 'debugged program',
|
||||||
\ 'vertical': s:vertical,
|
\ 'vertical': s:vertical,
|
||||||
\ })
|
\ })
|
||||||
if s:ptybuf == 0
|
if s:ptybuf == 0
|
||||||
echoerr 'Failed to open the program terminal window'
|
echoerr 'Failed to open the program terminal window'
|
||||||
return
|
return
|
||||||
@@ -155,10 +162,10 @@ func s:StartDebug_term(dict)
|
|||||||
|
|
||||||
" Create a hidden terminal window to communicate with gdb
|
" Create a hidden terminal window to communicate with gdb
|
||||||
let s:commbuf = term_start('NONE', {
|
let s:commbuf = term_start('NONE', {
|
||||||
\ 'term_name': 'gdb communication',
|
\ 'term_name': 'gdb communication',
|
||||||
\ 'out_cb': function('s:CommOutput'),
|
\ 'out_cb': function('s:CommOutput'),
|
||||||
\ 'hidden': 1,
|
\ 'hidden': 1,
|
||||||
\ })
|
\ })
|
||||||
if s:commbuf == 0
|
if s:commbuf == 0
|
||||||
echoerr 'Failed to open the communication terminal window'
|
echoerr 'Failed to open the communication terminal window'
|
||||||
exe 'bwipe! ' . s:ptybuf
|
exe 'bwipe! ' . s:ptybuf
|
||||||
@@ -174,9 +181,9 @@ func s:StartDebug_term(dict)
|
|||||||
let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args
|
let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args
|
||||||
call ch_log('executing "' . join(cmd) . '"')
|
call ch_log('executing "' . join(cmd) . '"')
|
||||||
let s:gdbbuf = term_start(cmd, {
|
let s:gdbbuf = term_start(cmd, {
|
||||||
\ 'exit_cb': function('s:EndTermDebug'),
|
\ 'exit_cb': function('s:EndTermDebug'),
|
||||||
\ 'term_finish': 'close',
|
\ 'term_finish': 'close',
|
||||||
\ })
|
\ })
|
||||||
if s:gdbbuf == 0
|
if s:gdbbuf == 0
|
||||||
echoerr 'Failed to open the gdb terminal window'
|
echoerr 'Failed to open the gdb terminal window'
|
||||||
exe 'bwipe! ' . s:ptybuf
|
exe 'bwipe! ' . s:ptybuf
|
||||||
@@ -200,18 +207,18 @@ func s:StartDebug_term(dict)
|
|||||||
let response = ''
|
let response = ''
|
||||||
for lnum in range(1,200)
|
for lnum in range(1,200)
|
||||||
if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi '
|
if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi '
|
||||||
" response can be in the same line or the next line
|
" response can be in the same line or the next line
|
||||||
let response = term_getline(s:gdbbuf, lnum) . term_getline(s:gdbbuf, lnum + 1)
|
let response = term_getline(s:gdbbuf, lnum) . term_getline(s:gdbbuf, lnum + 1)
|
||||||
if response =~ 'Undefined command'
|
if response =~ 'Undefined command'
|
||||||
echoerr 'Sorry, your gdb is too old, gdb 7.12 is required'
|
echoerr 'Sorry, your gdb is too old, gdb 7.12 is required'
|
||||||
exe 'bwipe! ' . s:ptybuf
|
exe 'bwipe! ' . s:ptybuf
|
||||||
exe 'bwipe! ' . s:commbuf
|
exe 'bwipe! ' . s:commbuf
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
if response =~ 'New UI allocated'
|
if response =~ 'New UI allocated'
|
||||||
" Success!
|
" Success!
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
if response =~ 'New UI allocated'
|
if response =~ 'New UI allocated'
|
||||||
@@ -268,9 +275,9 @@ func s:StartDebug_prompt(dict)
|
|||||||
call ch_log('executing "' . join(cmd) . '"')
|
call ch_log('executing "' . join(cmd) . '"')
|
||||||
|
|
||||||
let s:gdbjob = job_start(cmd, {
|
let s:gdbjob = job_start(cmd, {
|
||||||
\ 'exit_cb': function('s:EndPromptDebug'),
|
\ 'exit_cb': function('s:EndPromptDebug'),
|
||||||
\ 'out_cb': function('s:GdbOutCallback'),
|
\ 'out_cb': function('s:GdbOutCallback'),
|
||||||
\ })
|
\ })
|
||||||
if job_status(s:gdbjob) != "run"
|
if job_status(s:gdbjob) != "run"
|
||||||
echoerr 'Failed to start gdb'
|
echoerr 'Failed to start gdb'
|
||||||
exe 'bwipe! ' . s:promptbuf
|
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
|
" Unix: Run the debugged program in a terminal window. Open it below the
|
||||||
" gdb window.
|
" gdb window.
|
||||||
belowright let s:ptybuf = term_start('NONE', {
|
belowright let s:ptybuf = term_start('NONE', {
|
||||||
\ 'term_name': 'debugged program',
|
\ 'term_name': 'debugged program',
|
||||||
\ })
|
\ })
|
||||||
if s:ptybuf == 0
|
if s:ptybuf == 0
|
||||||
echoerr 'Failed to open the program terminal window'
|
echoerr 'Failed to open the program terminal window'
|
||||||
call job_stop(s:gdbjob)
|
call job_stop(s:gdbjob)
|
||||||
@@ -353,7 +360,8 @@ func s:StartDebugCommon(dict)
|
|||||||
endif
|
endif
|
||||||
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 = {}
|
let s:breakpoints = {}
|
||||||
|
|
||||||
augroup TermDebug
|
augroup TermDebug
|
||||||
@@ -466,9 +474,9 @@ func s:DecodeMessage(quotedText)
|
|||||||
if a:quotedText[i] == '\'
|
if a:quotedText[i] == '\'
|
||||||
let i += 1
|
let i += 1
|
||||||
if a:quotedText[i] == 'n'
|
if a:quotedText[i] == 'n'
|
||||||
" drop \n
|
" drop \n
|
||||||
let i += 1
|
let i += 1
|
||||||
continue
|
continue
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
let result .= a:quotedText[i]
|
let result .= a:quotedText[i]
|
||||||
@@ -479,6 +487,9 @@ endfunc
|
|||||||
|
|
||||||
" Extract the "name" value from a gdb message with fullname="name".
|
" Extract the "name" value from a gdb message with fullname="name".
|
||||||
func s:GetFullname(msg)
|
func s:GetFullname(msg)
|
||||||
|
if a:msg !~ 'fullname'
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', ''))
|
let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', ''))
|
||||||
if has('win32') && name =~ ':\\\\'
|
if has('win32') && name =~ ':\\\\'
|
||||||
" sometimes the name arrives double-escaped
|
" sometimes the name arrives double-escaped
|
||||||
@@ -549,17 +560,17 @@ func s:CommOutput(chan, msg)
|
|||||||
endif
|
endif
|
||||||
if msg != ''
|
if msg != ''
|
||||||
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
|
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
|
||||||
call s:HandleCursor(msg)
|
call s:HandleCursor(msg)
|
||||||
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
|
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
|
||||||
call s:HandleNewBreakpoint(msg)
|
call s:HandleNewBreakpoint(msg)
|
||||||
elseif msg =~ '^=breakpoint-deleted,'
|
elseif msg =~ '^=breakpoint-deleted,'
|
||||||
call s:HandleBreakpointDelete(msg)
|
call s:HandleBreakpointDelete(msg)
|
||||||
elseif msg =~ '^=thread-group-started'
|
elseif msg =~ '^=thread-group-started'
|
||||||
call s:HandleProgramRun(msg)
|
call s:HandleProgramRun(msg)
|
||||||
elseif msg =~ '^\^done,value='
|
elseif msg =~ '^\^done,value='
|
||||||
call s:HandleEvaluate(msg)
|
call s:HandleEvaluate(msg)
|
||||||
elseif msg =~ '^\^error,msg='
|
elseif msg =~ '^\^error,msg='
|
||||||
call s:HandleError(msg)
|
call s:HandleError(msg)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
@@ -650,12 +661,12 @@ func s:DeleteCommands()
|
|||||||
let curwinid = win_getid(winnr())
|
let curwinid = win_getid(winnr())
|
||||||
for winid in s:winbar_winids
|
for winid in s:winbar_winids
|
||||||
if win_gotoid(winid)
|
if win_gotoid(winid)
|
||||||
aunmenu WinBar.Step
|
aunmenu WinBar.Step
|
||||||
aunmenu WinBar.Next
|
aunmenu WinBar.Next
|
||||||
aunmenu WinBar.Finish
|
aunmenu WinBar.Finish
|
||||||
aunmenu WinBar.Cont
|
aunmenu WinBar.Cont
|
||||||
aunmenu WinBar.Stop
|
aunmenu WinBar.Stop
|
||||||
aunmenu WinBar.Eval
|
aunmenu WinBar.Eval
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
call win_gotoid(curwinid)
|
call win_gotoid(curwinid)
|
||||||
@@ -673,7 +684,7 @@ func s:DeleteCommands()
|
|||||||
|
|
||||||
exe 'sign unplace ' . s:pc_id
|
exe 'sign unplace ' . s:pc_id
|
||||||
for key in keys(s:breakpoints)
|
for key in keys(s:breakpoints)
|
||||||
exe 'sign unplace ' . (s:break_id + key)
|
exe 'sign unplace ' . (s:break_id + s:Breakpoint2SignNumber(key))
|
||||||
endfor
|
endfor
|
||||||
unlet s:breakpoints
|
unlet s:breakpoints
|
||||||
|
|
||||||
@@ -700,7 +711,7 @@ func s:SetBreakpoint()
|
|||||||
endif
|
endif
|
||||||
" Use the fname:lnum format, older gdb can't handle --source.
|
" Use the fname:lnum format, older gdb can't handle --source.
|
||||||
call s:SendCommand('-break-insert '
|
call s:SendCommand('-break-insert '
|
||||||
\ . fnameescape(expand('%:p')) . ':' . line('.'))
|
\ . fnameescape(expand('%:p')) . ':' . line('.'))
|
||||||
if do_continue
|
if do_continue
|
||||||
call s:SendCommand('-exec-continue')
|
call s:SendCommand('-exec-continue')
|
||||||
endif
|
endif
|
||||||
@@ -714,7 +725,7 @@ func s:ClearBreakpoint()
|
|||||||
if val['fname'] == fname && val['lnum'] == lnum
|
if val['fname'] == fname && val['lnum'] == lnum
|
||||||
call s:SendCommand('-break-delete ' . key)
|
call s:SendCommand('-break-delete ' . key)
|
||||||
" Assume this always wors, the reply is simply "^done".
|
" 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]
|
unlet s:breakpoints[key]
|
||||||
break
|
break
|
||||||
endif
|
endif
|
||||||
@@ -839,14 +850,14 @@ func s:HandleCursor(msg)
|
|||||||
if lnum =~ '^[0-9]*$'
|
if lnum =~ '^[0-9]*$'
|
||||||
call s:GotoSourcewinOrCreateIt()
|
call s:GotoSourcewinOrCreateIt()
|
||||||
if expand('%:p') != fnamemodify(fname, ':p')
|
if expand('%:p') != fnamemodify(fname, ':p')
|
||||||
if &modified
|
if &modified
|
||||||
" TODO: find existing window
|
" TODO: find existing window
|
||||||
exe 'split ' . fnameescape(fname)
|
exe 'split ' . fnameescape(fname)
|
||||||
let s:sourcewin = win_getid(winnr())
|
let s:sourcewin = win_getid(winnr())
|
||||||
call s:InstallWinbar()
|
call s:InstallWinbar()
|
||||||
else
|
else
|
||||||
exe 'edit ' . fnameescape(fname)
|
exe 'edit ' . fnameescape(fname)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
exe lnum
|
exe lnum
|
||||||
exe 'sign unplace ' . s:pc_id
|
exe 'sign unplace ' . s:pc_id
|
||||||
@@ -865,10 +876,14 @@ let s:BreakpointSigns = []
|
|||||||
func s:CreateBreakpoint(nr)
|
func s:CreateBreakpoint(nr)
|
||||||
if index(s:BreakpointSigns, a:nr) == -1
|
if index(s:BreakpointSigns, a:nr) == -1
|
||||||
call add(s:BreakpointSigns, a:nr)
|
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
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func s:SplitMsg(s)
|
||||||
|
return split(a:s, '{\%([a-z-]\+=[^,]\+,*\)\+}\zs')
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Handle setting a breakpoint
|
" Handle setting a breakpoint
|
||||||
" Will update the sign that shows the breakpoint
|
" Will update the sign that shows the breakpoint
|
||||||
func s:HandleNewBreakpoint(msg)
|
func s:HandleNewBreakpoint(msg)
|
||||||
@@ -876,50 +891,57 @@ func s:HandleNewBreakpoint(msg)
|
|||||||
" a watch does not have a file name
|
" a watch does not have a file name
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
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)
|
||||||
|
|
||||||
let nr = substitute(a:msg, '.*number="\([0-9]*\)".*', '\1', '') + 0
|
if has_key(s:breakpoints, nr)
|
||||||
if nr == 0
|
let entry = s:breakpoints[nr]
|
||||||
return
|
else
|
||||||
endif
|
let entry = {}
|
||||||
call s:CreateBreakpoint(nr)
|
let s:breakpoints[nr] = entry
|
||||||
|
endif
|
||||||
|
|
||||||
if has_key(s:breakpoints, nr)
|
let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '')
|
||||||
let entry = s:breakpoints[nr]
|
let entry['fname'] = fname
|
||||||
else
|
let entry['lnum'] = lnum
|
||||||
let entry = {}
|
|
||||||
let s:breakpoints[nr] = entry
|
|
||||||
endif
|
|
||||||
|
|
||||||
let fname = s:GetFullname(a:msg)
|
if bufloaded(fname)
|
||||||
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
|
call s:PlaceSign(nr, entry)
|
||||||
let entry['fname'] = fname
|
endif
|
||||||
let entry['lnum'] = lnum
|
endfor
|
||||||
|
|
||||||
if bufloaded(fname)
|
|
||||||
call s:PlaceSign(nr, entry)
|
|
||||||
endif
|
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func s:PlaceSign(nr, entry)
|
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
|
let a:entry['placed'] = 1
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Handle deleting a breakpoint
|
" Handle deleting a breakpoint
|
||||||
" Will remove the sign that shows the breakpoint
|
" Will remove the sign that shows the breakpoint
|
||||||
func s:HandleBreakpointDelete(msg)
|
func s:HandleBreakpointDelete(msg)
|
||||||
let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
|
let key = substitute(a:msg, '.*id="\([0-9.]*\)\".*', '\1', '')
|
||||||
if nr == 0
|
if empty(key)
|
||||||
return
|
return
|
||||||
endif
|
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]
|
let entry = s:breakpoints[nr]
|
||||||
if has_key(entry, 'placed')
|
if has_key(entry, 'placed')
|
||||||
exe 'sign unplace ' . (s:break_id + nr)
|
exe 'sign unplace ' . (s:break_id + s:Breakpoint2SignNumber(nr))
|
||||||
unlet entry['placed']
|
unlet entry['placed']
|
||||||
endif
|
endif
|
||||||
unlet s:breakpoints[nr]
|
unlet s:breakpoints[nr]
|
||||||
endif
|
endfor
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Handle the debugged program starting to run.
|
" Handle the debugged program starting to run.
|
||||||
|
@@ -792,6 +792,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
557,
|
||||||
/**/
|
/**/
|
||||||
556,
|
556,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user