1fe386641SBram Moolenaar" Debugger plugin using gdb. 2c572da5fSBram Moolenaar" 3c572da5fSBram Moolenaar" WORK IN PROGRESS - much doesn't work yet 4c572da5fSBram Moolenaar" 5fe386641SBram Moolenaar" Open two visible terminal windows: 6c572da5fSBram Moolenaar" 1. run a pty, as with ":term NONE" 7c572da5fSBram Moolenaar" 2. run gdb, passing the pty 8fe386641SBram Moolenaar" The current window is used to view source code and follows gdb. 9fe386641SBram Moolenaar" 10fe386641SBram Moolenaar" A third terminal window is hidden, it is used for communication with gdb. 11fe386641SBram Moolenaar" 12fe386641SBram Moolenaar" The communication with gdb uses GDB/MI. See: 13fe386641SBram Moolenaar" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html 14c572da5fSBram Moolenaar" 15c572da5fSBram Moolenaar" Author: Bram Moolenaar 16fe386641SBram Moolenaar" Copyright: Vim license applies, see ":help license" 17c572da5fSBram Moolenaar 1837c64c78SBram Moolenaar" In case this gets loaded twice. 1937c64c78SBram Moolenaarif exists(':Termdebug') 2037c64c78SBram Moolenaar finish 2137c64c78SBram Moolenaarendif 2237c64c78SBram Moolenaar 2360e73f2aSBram Moolenaar" Uncomment this line to write logging in "debuglog". 2460e73f2aSBram Moolenaar" call ch_logfile('debuglog', 'w') 2560e73f2aSBram Moolenaar 26fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim". 27fe386641SBram Moolenaar" To end type "quit" in the gdb window. 28c572da5fSBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) 29c572da5fSBram Moolenaar 30fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb". 31e09ba7baSBram Moolenaarif !exists('termdebugger') 32e09ba7baSBram Moolenaar let termdebugger = 'gdb' 33c572da5fSBram Moolenaarendif 34c572da5fSBram Moolenaar 35fe386641SBram Moolenaarlet s:pc_id = 12 36e09ba7baSBram Moolenaarlet s:break_id = 13 3760e73f2aSBram Moolenaarlet s:stopped = 1 38e09ba7baSBram Moolenaar 39e09ba7baSBram Moolenaarif &background == 'light' 40e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue 41e09ba7baSBram Moolenaarelse 42e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue 43e09ba7baSBram Moolenaarendif 44e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red 45fe386641SBram Moolenaar 46c572da5fSBram Moolenaarfunc s:StartDebug(cmd) 47fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 48fe386641SBram Moolenaar let s:startsigncolumn = &signcolumn 49fe386641SBram Moolenaar 5024a98a0eSBram Moolenaar let s:save_columns = 0 5124a98a0eSBram Moolenaar if exists('g:termdebug_wide') 5224a98a0eSBram Moolenaar if &columns < g:termdebug_wide 5338baa3e6SBram Moolenaar let s:save_columns = &columns 5438baa3e6SBram Moolenaar let &columns = g:termdebug_wide 5524a98a0eSBram Moolenaar endif 5638baa3e6SBram Moolenaar let vertical = 1 5738baa3e6SBram Moolenaar else 5838baa3e6SBram Moolenaar let vertical = 0 5938baa3e6SBram Moolenaar endif 6038baa3e6SBram Moolenaar 61c572da5fSBram Moolenaar " Open a terminal window without a job, to run the debugged program 62fe386641SBram Moolenaar let s:ptybuf = term_start('NONE', { 63fe386641SBram Moolenaar \ 'term_name': 'gdb program', 6438baa3e6SBram Moolenaar \ 'vertical': vertical, 65fe386641SBram Moolenaar \ }) 66fe386641SBram Moolenaar if s:ptybuf == 0 67fe386641SBram Moolenaar echoerr 'Failed to open the program terminal window' 68fe386641SBram Moolenaar return 69fe386641SBram Moolenaar endif 70fe386641SBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 7145d5f26dSBram Moolenaar let s:ptywin = win_getid(winnr()) 7251b0f370SBram Moolenaar if vertical 7351b0f370SBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 7451b0f370SBram Moolenaar " columns for that, thus one less for the terminal window. 7551b0f370SBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 7651b0f370SBram Moolenaar endif 77fe386641SBram Moolenaar 78fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 79fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 80fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 81fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 82fe386641SBram Moolenaar \ 'hidden': 1, 83fe386641SBram Moolenaar \ }) 84fe386641SBram Moolenaar if s:commbuf == 0 85fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 86fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 87fe386641SBram Moolenaar return 88fe386641SBram Moolenaar endif 89fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 90c572da5fSBram Moolenaar 91c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 92c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 93c3632516SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty, a:cmd] 94c572da5fSBram Moolenaar echomsg 'executing "' . join(cmd) . '"' 9560e73f2aSBram Moolenaar let s:gdbbuf = term_start(cmd, { 96c572da5fSBram Moolenaar \ 'exit_cb': function('s:EndDebug'), 97fe386641SBram Moolenaar \ 'term_finish': 'close', 98c572da5fSBram Moolenaar \ }) 9960e73f2aSBram Moolenaar if s:gdbbuf == 0 100fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 101fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 102fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 103fe386641SBram Moolenaar return 104fe386641SBram Moolenaar endif 10545d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 106fe386641SBram Moolenaar 107fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 10860e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 10960e73f2aSBram Moolenaar 110*3e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 111*3e4b84d0SBram Moolenaar " why the debugger doesn't work. 112*3e4b84d0SBram Moolenaar let try_count = 0 113*3e4b84d0SBram Moolenaar while 1 114*3e4b84d0SBram Moolenaar let response = '' 115*3e4b84d0SBram Moolenaar for lnum in range(1,20) 116*3e4b84d0SBram Moolenaar if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' 117*3e4b84d0SBram Moolenaar let response = term_getline(s:gdbbuf, lnum + 1) 118*3e4b84d0SBram Moolenaar if response =~ 'Undefined command' 119*3e4b84d0SBram Moolenaar echoerr 'Your gdb does not support the Machine Interface feature' 120*3e4b84d0SBram Moolenaar exe 'bwipe! ' . s:ptybuf 121*3e4b84d0SBram Moolenaar exe 'bwipe! ' . s:commbuf 122*3e4b84d0SBram Moolenaar return 123*3e4b84d0SBram Moolenaar endif 124*3e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 125*3e4b84d0SBram Moolenaar " Success! 126*3e4b84d0SBram Moolenaar break 127*3e4b84d0SBram Moolenaar endif 128*3e4b84d0SBram Moolenaar endif 129*3e4b84d0SBram Moolenaar endfor 130*3e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 131*3e4b84d0SBram Moolenaar break 132*3e4b84d0SBram Moolenaar endif 133*3e4b84d0SBram Moolenaar let try_count += 1 134*3e4b84d0SBram Moolenaar if try_count > 100 135*3e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 136*3e4b84d0SBram Moolenaar break 137*3e4b84d0SBram Moolenaar endif 138*3e4b84d0SBram Moolenaar sleep 10m 139*3e4b84d0SBram Moolenaar endwhile 140*3e4b84d0SBram Moolenaar 14160e73f2aSBram Moolenaar " Interpret commands while the target is running. This should usualy only be 14260e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 14360e73f2aSBram Moolenaar " running. 14460e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 145e09ba7baSBram Moolenaar 14638baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 14738baa3e6SBram Moolenaar " There can be only one. 14838baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 14938baa3e6SBram Moolenaar 15038baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 15138baa3e6SBram Moolenaar " Can be used multiple times. 15238baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 15338baa3e6SBram Moolenaar 15445d5f26dSBram Moolenaar " Install debugger commands in the text window. 15545d5f26dSBram Moolenaar call win_gotoid(s:startwin) 156e09ba7baSBram Moolenaar call s:InstallCommands() 15745d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 158e09ba7baSBram Moolenaar 15951b0f370SBram Moolenaar " Enable showing a balloon with eval info 160246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 161246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 16251b0f370SBram Moolenaar if has("balloon_eval") 16351b0f370SBram Moolenaar set ballooneval 164246fe03dSBram Moolenaar endif 16551b0f370SBram Moolenaar if has("balloon_eval_term") 16651b0f370SBram Moolenaar set balloonevalterm 16751b0f370SBram Moolenaar endif 16851b0f370SBram Moolenaar endif 16951b0f370SBram Moolenaar 170e09ba7baSBram Moolenaar let s:breakpoints = {} 1711b9645deSBram Moolenaar 1721b9645deSBram Moolenaar augroup TermDebug 1731b9645deSBram Moolenaar au BufRead * call s:BufRead() 1741b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1751b9645deSBram Moolenaar augroup END 176c572da5fSBram Moolenaarendfunc 177c572da5fSBram Moolenaar 178c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 179c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 180fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 181e09ba7baSBram Moolenaar 182e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 183e09ba7baSBram Moolenaar 184e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 185e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 186e09ba7baSBram Moolenaar call s:DeleteCommands() 187e09ba7baSBram Moolenaar 188e09ba7baSBram Moolenaar call win_gotoid(curwinid) 18938baa3e6SBram Moolenaar if s:save_columns > 0 19038baa3e6SBram Moolenaar let &columns = s:save_columns 19138baa3e6SBram Moolenaar endif 1921b9645deSBram Moolenaar 193246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 194246fe03dSBram Moolenaar set balloonexpr= 19551b0f370SBram Moolenaar if has("balloon_eval") 19651b0f370SBram Moolenaar set noballooneval 197246fe03dSBram Moolenaar endif 19851b0f370SBram Moolenaar if has("balloon_eval_term") 19951b0f370SBram Moolenaar set noballoonevalterm 20051b0f370SBram Moolenaar endif 20151b0f370SBram Moolenaar endif 20251b0f370SBram Moolenaar 2031b9645deSBram Moolenaar au! TermDebug 204fe386641SBram Moolenaarendfunc 205fe386641SBram Moolenaar 206fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 207fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 208fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 209fe386641SBram Moolenaar 210fe386641SBram Moolenaar for msg in msgs 211fe386641SBram Moolenaar " remove prefixed NL 212fe386641SBram Moolenaar if msg[0] == "\n" 213fe386641SBram Moolenaar let msg = msg[1:] 214fe386641SBram Moolenaar endif 215fe386641SBram Moolenaar if msg != '' 2161b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 217e09ba7baSBram Moolenaar call s:HandleCursor(msg) 21845d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 219e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 220e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 221e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 22245d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 22345d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 22445d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 22545d5f26dSBram Moolenaar call s:HandleError(msg) 226e09ba7baSBram Moolenaar endif 227e09ba7baSBram Moolenaar endif 228e09ba7baSBram Moolenaar endfor 229e09ba7baSBram Moolenaarendfunc 230e09ba7baSBram Moolenaar 231e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 232e09ba7baSBram Moolenaarfunc s:InstallCommands() 233e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 23471137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 235e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 23645d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 237e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 23860e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 23960e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 24060e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 241e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 24245d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 24345d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 24445d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 24571137fedSBram Moolenaar command Winbar call s:InstallWinbar() 24645d5f26dSBram Moolenaar 24745d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 24845d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 2491b9645deSBram Moolenaar 250f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 25171137fedSBram Moolenaar call s:InstallWinbar() 25271137fedSBram Moolenaar 25371137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 25471137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 25571137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 25671137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 25771137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 25871137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 25971137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 26071137fedSBram Moolenaar endif 26171137fedSBram Moolenaar endif 26271137fedSBram Moolenaarendfunc 26371137fedSBram Moolenaar 26471137fedSBram Moolenaarlet s:winbar_winids = [] 26571137fedSBram Moolenaar 26671137fedSBram Moolenaar" Install the window toolbar in the current window. 26771137fedSBram Moolenaarfunc s:InstallWinbar() 26824a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 26924a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 27024a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 27124a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 27260e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 27324a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 27471137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 275e09ba7baSBram Moolenaarendfunc 276e09ba7baSBram Moolenaar 277e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 278e09ba7baSBram Moolenaarfunc s:DeleteCommands() 279e09ba7baSBram Moolenaar delcommand Break 28071137fedSBram Moolenaar delcommand Clear 281e09ba7baSBram Moolenaar delcommand Step 28245d5f26dSBram Moolenaar delcommand Over 283e09ba7baSBram Moolenaar delcommand Finish 28460e73f2aSBram Moolenaar delcommand Run 28560e73f2aSBram Moolenaar delcommand Arguments 28660e73f2aSBram Moolenaar delcommand Stop 287e09ba7baSBram Moolenaar delcommand Continue 28845d5f26dSBram Moolenaar delcommand Evaluate 28945d5f26dSBram Moolenaar delcommand Gdb 29045d5f26dSBram Moolenaar delcommand Program 29171137fedSBram Moolenaar delcommand Winbar 29245d5f26dSBram Moolenaar 29345d5f26dSBram Moolenaar nunmap K 2941b9645deSBram Moolenaar 2951b9645deSBram Moolenaar if has('menu') 29671137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 29771137fedSBram Moolenaar let curwinid = win_getid(winnr()) 29871137fedSBram Moolenaar for winid in s:winbar_winids 29971137fedSBram Moolenaar if win_gotoid(winid) 3001b9645deSBram Moolenaar aunmenu WinBar.Step 3011b9645deSBram Moolenaar aunmenu WinBar.Next 3021b9645deSBram Moolenaar aunmenu WinBar.Finish 3031b9645deSBram Moolenaar aunmenu WinBar.Cont 30460e73f2aSBram Moolenaar aunmenu WinBar.Stop 3051b9645deSBram Moolenaar aunmenu WinBar.Eval 3061b9645deSBram Moolenaar endif 30771137fedSBram Moolenaar endfor 30871137fedSBram Moolenaar call win_gotoid(curwinid) 30971137fedSBram Moolenaar let s:winbar_winids = [] 31071137fedSBram Moolenaar 31171137fedSBram Moolenaar if exists('s:saved_mousemodel') 31271137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 31371137fedSBram Moolenaar unlet s:saved_mousemodel 31471137fedSBram Moolenaar aunmenu PopUp.-SEP3- 31571137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 31671137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 31771137fedSBram Moolenaar aunmenu PopUp.Evaluate 31871137fedSBram Moolenaar endif 31971137fedSBram Moolenaar endif 3201b9645deSBram Moolenaar 32145d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 32245d5f26dSBram Moolenaar for key in keys(s:breakpoints) 32345d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 32445d5f26dSBram Moolenaar endfor 32538baa3e6SBram Moolenaar sign undefine debugPC 32638baa3e6SBram Moolenaar sign undefine debugBreakpoint 32745d5f26dSBram Moolenaar unlet s:breakpoints 328e09ba7baSBram Moolenaarendfunc 329e09ba7baSBram Moolenaar 330e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 331e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 33260e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 33360e73f2aSBram Moolenaar " Interrupt to make it work. 33460e73f2aSBram Moolenaar let do_continue = 0 33560e73f2aSBram Moolenaar if !s:stopped 33660e73f2aSBram Moolenaar let do_continue = 1 33760e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 33860e73f2aSBram Moolenaar sleep 10m 33960e73f2aSBram Moolenaar endif 34060e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 34160e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 34260e73f2aSBram Moolenaar if do_continue 34360e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 34460e73f2aSBram Moolenaar endif 345e09ba7baSBram Moolenaarendfunc 346e09ba7baSBram Moolenaar 34771137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 34871137fedSBram Moolenaarfunc s:ClearBreakpoint() 349e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 350e09ba7baSBram Moolenaar let lnum = line('.') 351e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 352e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 353e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 354e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 355e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 356e09ba7baSBram Moolenaar unlet s:breakpoints[key] 357e09ba7baSBram Moolenaar break 358e09ba7baSBram Moolenaar endif 359e09ba7baSBram Moolenaar endfor 360e09ba7baSBram Moolenaarendfunc 361e09ba7baSBram Moolenaar 362e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 363e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 364e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 365e09ba7baSBram Moolenaarendfunc 366e09ba7baSBram Moolenaar 36760e73f2aSBram Moolenaarfunc s:Run(args) 36860e73f2aSBram Moolenaar if a:args != '' 36960e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 37060e73f2aSBram Moolenaar endif 37160e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 37260e73f2aSBram Moolenaarendfunc 37360e73f2aSBram Moolenaar 37451b0f370SBram Moolenaarfunc s:SendEval(expr) 37551b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 37651b0f370SBram Moolenaar let s:evalexpr = a:expr 37751b0f370SBram Moolenaarendfunc 37851b0f370SBram Moolenaar 37945d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 38045d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 38145d5f26dSBram Moolenaar if a:arg != '' 38245d5f26dSBram Moolenaar let expr = a:arg 38345d5f26dSBram Moolenaar elseif a:range == 2 38445d5f26dSBram Moolenaar let pos = getcurpos() 38545d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 38645d5f26dSBram Moolenaar let regt = getregtype('v') 38745d5f26dSBram Moolenaar normal! gv"vy 38845d5f26dSBram Moolenaar let expr = @v 38945d5f26dSBram Moolenaar call setpos('.', pos) 39045d5f26dSBram Moolenaar call setreg('v', reg, regt) 39145d5f26dSBram Moolenaar else 39245d5f26dSBram Moolenaar let expr = expand('<cexpr>') 39345d5f26dSBram Moolenaar endif 39422f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 39551b0f370SBram Moolenaar call s:SendEval(expr) 39645d5f26dSBram Moolenaarendfunc 39745d5f26dSBram Moolenaar 39822f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 39951b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 40051b0f370SBram Moolenaar 40145d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 40245d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 4031b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 4041b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 40551b0f370SBram Moolenaar if s:evalFromBalloonExpr 40651b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 40751b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 40851b0f370SBram Moolenaar else 40951b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 41051b0f370SBram Moolenaar endif 41151b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 41251b0f370SBram Moolenaar else 4131b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 41451b0f370SBram Moolenaar endif 4151b9645deSBram Moolenaar 4167f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 4171b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 41822f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 41951b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 42051b0f370SBram Moolenaar else 42151b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 4221b9645deSBram Moolenaar endif 42345d5f26dSBram Moolenaarendfunc 42445d5f26dSBram Moolenaar 42551b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 42651b0f370SBram Moolenaar" if there is any. 42751b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 42851b0f370SBram Moolenaar if v:beval_winid != s:startwin 42951b0f370SBram Moolenaar return 43051b0f370SBram Moolenaar endif 43151b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 43251b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 43322f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 43422f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 43551b0f370SBram Moolenaar return '' 43651b0f370SBram Moolenaarendfunc 43751b0f370SBram Moolenaar 43845d5f26dSBram Moolenaar" Handle an error. 43945d5f26dSBram Moolenaarfunc s:HandleError(msg) 44022f1d0e3SBram Moolenaar if s:ignoreEvalError 44151b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 44222f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 44322f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 44451b0f370SBram Moolenaar return 44551b0f370SBram Moolenaar endif 44645d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 44745d5f26dSBram Moolenaarendfunc 44845d5f26dSBram Moolenaar 449e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 450e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 451e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 452fe386641SBram Moolenaar let wid = win_getid(winnr()) 453fe386641SBram Moolenaar 45460e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 45560e73f2aSBram Moolenaar let s:stopped = 1 45660e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 45760e73f2aSBram Moolenaar let s:stopped = 0 45860e73f2aSBram Moolenaar endif 45960e73f2aSBram Moolenaar 460fe386641SBram Moolenaar if win_gotoid(s:startwin) 461e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 4621b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 463e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 464fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 4651b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 466fe386641SBram Moolenaar if &modified 467fe386641SBram Moolenaar " TODO: find existing window 468fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 469fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 470fe386641SBram Moolenaar else 471fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 472fe386641SBram Moolenaar endif 473fe386641SBram Moolenaar endif 474fe386641SBram Moolenaar exe lnum 47501164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 4761b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 477fe386641SBram Moolenaar setlocal signcolumn=yes 478fe386641SBram Moolenaar endif 479fe386641SBram Moolenaar else 480fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 481fe386641SBram Moolenaar endif 482fe386641SBram Moolenaar 483fe386641SBram Moolenaar call win_gotoid(wid) 484fe386641SBram Moolenaar endif 485e09ba7baSBram Moolenaarendfunc 486e09ba7baSBram Moolenaar 487e09ba7baSBram Moolenaar" Handle setting a breakpoint 488e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 489e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 490e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 491e09ba7baSBram Moolenaar if nr == 0 492e09ba7baSBram Moolenaar return 493fe386641SBram Moolenaar endif 494e09ba7baSBram Moolenaar 495e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 496e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 497e09ba7baSBram Moolenaar else 498e09ba7baSBram Moolenaar let entry = {} 499e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 500fe386641SBram Moolenaar endif 501e09ba7baSBram Moolenaar 502e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 503e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 504e09ba7baSBram Moolenaar let entry['fname'] = fname 505e09ba7baSBram Moolenaar let entry['lnum'] = lnum 5061b9645deSBram Moolenaar 5071b9645deSBram Moolenaar if bufloaded(fname) 5081b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5091b9645deSBram Moolenaar endif 5101b9645deSBram Moolenaarendfunc 5111b9645deSBram Moolenaar 5121b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 5131b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 5141b9645deSBram Moolenaar let a:entry['placed'] = 1 515e09ba7baSBram Moolenaarendfunc 516e09ba7baSBram Moolenaar 517e09ba7baSBram Moolenaar" Handle deleting a breakpoint 518e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 519e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 520e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 521e09ba7baSBram Moolenaar if nr == 0 522e09ba7baSBram Moolenaar return 523e09ba7baSBram Moolenaar endif 5241b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 5251b9645deSBram Moolenaar let entry = s:breakpoints[nr] 5261b9645deSBram Moolenaar if has_key(entry, 'placed') 527e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 5281b9645deSBram Moolenaar unlet entry['placed'] 5291b9645deSBram Moolenaar endif 530e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 5311b9645deSBram Moolenaar endif 532c572da5fSBram Moolenaarendfunc 5331b9645deSBram Moolenaar 5341b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 5351b9645deSBram Moolenaarfunc s:BufRead() 5361b9645deSBram Moolenaar let fname = expand('<afile>:p') 5371b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5381b9645deSBram Moolenaar if entry['fname'] == fname 5391b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5401b9645deSBram Moolenaar endif 5411b9645deSBram Moolenaar endfor 5421b9645deSBram Moolenaarendfunc 5431b9645deSBram Moolenaar 5441b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 5451b9645deSBram Moolenaarfunc s:BufUnloaded() 5461b9645deSBram Moolenaar let fname = expand('<afile>:p') 5471b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5481b9645deSBram Moolenaar if entry['fname'] == fname 5491b9645deSBram Moolenaar let entry['placed'] = 0 5501b9645deSBram Moolenaar endif 5511b9645deSBram Moolenaar endfor 5521b9645deSBram Moolenaarendfunc 5531b9645deSBram Moolenaar 554