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 1103e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 1113e4b84d0SBram Moolenaar " why the debugger doesn't work. 1123e4b84d0SBram Moolenaar let try_count = 0 1133e4b84d0SBram Moolenaar while 1 1143e4b84d0SBram Moolenaar let response = '' 1153e4b84d0SBram Moolenaar for lnum in range(1,20) 1163e4b84d0SBram Moolenaar if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' 1173e4b84d0SBram Moolenaar let response = term_getline(s:gdbbuf, lnum + 1) 1183e4b84d0SBram Moolenaar if response =~ 'Undefined command' 119f3ba14ffSBram Moolenaar echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' 1203e4b84d0SBram Moolenaar exe 'bwipe! ' . s:ptybuf 1213e4b84d0SBram Moolenaar exe 'bwipe! ' . s:commbuf 1223e4b84d0SBram Moolenaar return 1233e4b84d0SBram Moolenaar endif 1243e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1253e4b84d0SBram Moolenaar " Success! 1263e4b84d0SBram Moolenaar break 1273e4b84d0SBram Moolenaar endif 1283e4b84d0SBram Moolenaar endif 1293e4b84d0SBram Moolenaar endfor 1303e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1313e4b84d0SBram Moolenaar break 1323e4b84d0SBram Moolenaar endif 1333e4b84d0SBram Moolenaar let try_count += 1 1343e4b84d0SBram Moolenaar if try_count > 100 1353e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 1363e4b84d0SBram Moolenaar break 1373e4b84d0SBram Moolenaar endif 1383e4b84d0SBram Moolenaar sleep 10m 1393e4b84d0SBram Moolenaar endwhile 1403e4b84d0SBram 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 146f3ba14ffSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 147f3ba14ffSBram Moolenaar " "Type <return> to continue" prompt. 148f3ba14ffSBram Moolenaar call s:SendCommand('-gdb-set pagination off') 149f3ba14ffSBram Moolenaar 15038baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 15138baa3e6SBram Moolenaar " There can be only one. 15238baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 15338baa3e6SBram Moolenaar 15438baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 15538baa3e6SBram Moolenaar " Can be used multiple times. 15638baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 15738baa3e6SBram Moolenaar 15845d5f26dSBram Moolenaar " Install debugger commands in the text window. 15945d5f26dSBram Moolenaar call win_gotoid(s:startwin) 160e09ba7baSBram Moolenaar call s:InstallCommands() 16145d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 162e09ba7baSBram Moolenaar 16351b0f370SBram Moolenaar " Enable showing a balloon with eval info 164246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 165246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 16651b0f370SBram Moolenaar if has("balloon_eval") 16751b0f370SBram Moolenaar set ballooneval 168246fe03dSBram Moolenaar endif 16951b0f370SBram Moolenaar if has("balloon_eval_term") 17051b0f370SBram Moolenaar set balloonevalterm 17151b0f370SBram Moolenaar endif 17251b0f370SBram Moolenaar endif 17351b0f370SBram Moolenaar 174e09ba7baSBram Moolenaar let s:breakpoints = {} 1751b9645deSBram Moolenaar 1761b9645deSBram Moolenaar augroup TermDebug 1771b9645deSBram Moolenaar au BufRead * call s:BufRead() 1781b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1791b9645deSBram Moolenaar augroup END 180c572da5fSBram Moolenaarendfunc 181c572da5fSBram Moolenaar 182c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 183c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 184fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 185e09ba7baSBram Moolenaar 186e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 187e09ba7baSBram Moolenaar 188e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 189e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 190e09ba7baSBram Moolenaar call s:DeleteCommands() 191e09ba7baSBram Moolenaar 192e09ba7baSBram Moolenaar call win_gotoid(curwinid) 19338baa3e6SBram Moolenaar if s:save_columns > 0 19438baa3e6SBram Moolenaar let &columns = s:save_columns 19538baa3e6SBram Moolenaar endif 1961b9645deSBram Moolenaar 197246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 198246fe03dSBram Moolenaar set balloonexpr= 19951b0f370SBram Moolenaar if has("balloon_eval") 20051b0f370SBram Moolenaar set noballooneval 201246fe03dSBram Moolenaar endif 20251b0f370SBram Moolenaar if has("balloon_eval_term") 20351b0f370SBram Moolenaar set noballoonevalterm 20451b0f370SBram Moolenaar endif 20551b0f370SBram Moolenaar endif 20651b0f370SBram Moolenaar 2071b9645deSBram Moolenaar au! TermDebug 208fe386641SBram Moolenaarendfunc 209fe386641SBram Moolenaar 210fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 211fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 212fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 213fe386641SBram Moolenaar 214fe386641SBram Moolenaar for msg in msgs 215fe386641SBram Moolenaar " remove prefixed NL 216fe386641SBram Moolenaar if msg[0] == "\n" 217fe386641SBram Moolenaar let msg = msg[1:] 218fe386641SBram Moolenaar endif 219fe386641SBram Moolenaar if msg != '' 2201b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 221e09ba7baSBram Moolenaar call s:HandleCursor(msg) 22245d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 223e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 224e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 225e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 22645d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 22745d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 22845d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 22945d5f26dSBram Moolenaar call s:HandleError(msg) 230e09ba7baSBram Moolenaar endif 231e09ba7baSBram Moolenaar endif 232e09ba7baSBram Moolenaar endfor 233e09ba7baSBram Moolenaarendfunc 234e09ba7baSBram Moolenaar 235e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 236e09ba7baSBram Moolenaarfunc s:InstallCommands() 237e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 23871137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 239e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 24045d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 241e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 24260e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 24360e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 24460e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 245e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 24645d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 24745d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 24845d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 249*c4b533e1SBram Moolenaar command Source call s:GotoStartwinOrCreateIt() 25071137fedSBram Moolenaar command Winbar call s:InstallWinbar() 25145d5f26dSBram Moolenaar 25245d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 25345d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 2541b9645deSBram Moolenaar 255f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 25671137fedSBram Moolenaar call s:InstallWinbar() 25771137fedSBram Moolenaar 25871137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 25971137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 26071137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 26171137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 26271137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 26371137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 26471137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 26571137fedSBram Moolenaar endif 26671137fedSBram Moolenaar endif 26771137fedSBram Moolenaarendfunc 26871137fedSBram Moolenaar 26971137fedSBram Moolenaarlet s:winbar_winids = [] 27071137fedSBram Moolenaar 27171137fedSBram Moolenaar" Install the window toolbar in the current window. 27271137fedSBram Moolenaarfunc s:InstallWinbar() 273*c4b533e1SBram Moolenaar if has('menu') && &mouse != '' 27424a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 27524a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 27624a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 27724a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 27860e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 27924a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 28071137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 281*c4b533e1SBram Moolenaar endif 282e09ba7baSBram Moolenaarendfunc 283e09ba7baSBram Moolenaar 284e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 285e09ba7baSBram Moolenaarfunc s:DeleteCommands() 286e09ba7baSBram Moolenaar delcommand Break 28771137fedSBram Moolenaar delcommand Clear 288e09ba7baSBram Moolenaar delcommand Step 28945d5f26dSBram Moolenaar delcommand Over 290e09ba7baSBram Moolenaar delcommand Finish 29160e73f2aSBram Moolenaar delcommand Run 29260e73f2aSBram Moolenaar delcommand Arguments 29360e73f2aSBram Moolenaar delcommand Stop 294e09ba7baSBram Moolenaar delcommand Continue 29545d5f26dSBram Moolenaar delcommand Evaluate 29645d5f26dSBram Moolenaar delcommand Gdb 29745d5f26dSBram Moolenaar delcommand Program 29871137fedSBram Moolenaar delcommand Winbar 29945d5f26dSBram Moolenaar 30045d5f26dSBram Moolenaar nunmap K 3011b9645deSBram Moolenaar 3021b9645deSBram Moolenaar if has('menu') 30371137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 30471137fedSBram Moolenaar let curwinid = win_getid(winnr()) 30571137fedSBram Moolenaar for winid in s:winbar_winids 30671137fedSBram Moolenaar if win_gotoid(winid) 3071b9645deSBram Moolenaar aunmenu WinBar.Step 3081b9645deSBram Moolenaar aunmenu WinBar.Next 3091b9645deSBram Moolenaar aunmenu WinBar.Finish 3101b9645deSBram Moolenaar aunmenu WinBar.Cont 31160e73f2aSBram Moolenaar aunmenu WinBar.Stop 3121b9645deSBram Moolenaar aunmenu WinBar.Eval 3131b9645deSBram Moolenaar endif 31471137fedSBram Moolenaar endfor 31571137fedSBram Moolenaar call win_gotoid(curwinid) 31671137fedSBram Moolenaar let s:winbar_winids = [] 31771137fedSBram Moolenaar 31871137fedSBram Moolenaar if exists('s:saved_mousemodel') 31971137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 32071137fedSBram Moolenaar unlet s:saved_mousemodel 32171137fedSBram Moolenaar aunmenu PopUp.-SEP3- 32271137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 32371137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 32471137fedSBram Moolenaar aunmenu PopUp.Evaluate 32571137fedSBram Moolenaar endif 32671137fedSBram Moolenaar endif 3271b9645deSBram Moolenaar 32845d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 32945d5f26dSBram Moolenaar for key in keys(s:breakpoints) 33045d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 33145d5f26dSBram Moolenaar endfor 33238baa3e6SBram Moolenaar sign undefine debugPC 33338baa3e6SBram Moolenaar sign undefine debugBreakpoint 33445d5f26dSBram Moolenaar unlet s:breakpoints 335e09ba7baSBram Moolenaarendfunc 336e09ba7baSBram Moolenaar 337e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 338e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 33960e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 34060e73f2aSBram Moolenaar " Interrupt to make it work. 34160e73f2aSBram Moolenaar let do_continue = 0 34260e73f2aSBram Moolenaar if !s:stopped 34360e73f2aSBram Moolenaar let do_continue = 1 34460e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 34560e73f2aSBram Moolenaar sleep 10m 34660e73f2aSBram Moolenaar endif 34760e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 34860e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 34960e73f2aSBram Moolenaar if do_continue 35060e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 35160e73f2aSBram Moolenaar endif 352e09ba7baSBram Moolenaarendfunc 353e09ba7baSBram Moolenaar 35471137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 35571137fedSBram Moolenaarfunc s:ClearBreakpoint() 356e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 357e09ba7baSBram Moolenaar let lnum = line('.') 358e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 359e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 360e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 361e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 362e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 363e09ba7baSBram Moolenaar unlet s:breakpoints[key] 364e09ba7baSBram Moolenaar break 365e09ba7baSBram Moolenaar endif 366e09ba7baSBram Moolenaar endfor 367e09ba7baSBram Moolenaarendfunc 368e09ba7baSBram Moolenaar 369e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 370e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 371e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 372e09ba7baSBram Moolenaarendfunc 373e09ba7baSBram Moolenaar 37460e73f2aSBram Moolenaarfunc s:Run(args) 37560e73f2aSBram Moolenaar if a:args != '' 37660e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 37760e73f2aSBram Moolenaar endif 37860e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 37960e73f2aSBram Moolenaarendfunc 38060e73f2aSBram Moolenaar 38151b0f370SBram Moolenaarfunc s:SendEval(expr) 38251b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 38351b0f370SBram Moolenaar let s:evalexpr = a:expr 38451b0f370SBram Moolenaarendfunc 38551b0f370SBram Moolenaar 38645d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 38745d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 38845d5f26dSBram Moolenaar if a:arg != '' 38945d5f26dSBram Moolenaar let expr = a:arg 39045d5f26dSBram Moolenaar elseif a:range == 2 39145d5f26dSBram Moolenaar let pos = getcurpos() 39245d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 39345d5f26dSBram Moolenaar let regt = getregtype('v') 39445d5f26dSBram Moolenaar normal! gv"vy 39545d5f26dSBram Moolenaar let expr = @v 39645d5f26dSBram Moolenaar call setpos('.', pos) 39745d5f26dSBram Moolenaar call setreg('v', reg, regt) 39845d5f26dSBram Moolenaar else 39945d5f26dSBram Moolenaar let expr = expand('<cexpr>') 40045d5f26dSBram Moolenaar endif 40122f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 40251b0f370SBram Moolenaar call s:SendEval(expr) 40345d5f26dSBram Moolenaarendfunc 40445d5f26dSBram Moolenaar 40522f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 40651b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 40751b0f370SBram Moolenaar 40845d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 40945d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 4101b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 4111b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 41251b0f370SBram Moolenaar if s:evalFromBalloonExpr 41351b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 41451b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 41551b0f370SBram Moolenaar else 41651b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 41751b0f370SBram Moolenaar endif 41851b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 41951b0f370SBram Moolenaar else 4201b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 42151b0f370SBram Moolenaar endif 4221b9645deSBram Moolenaar 4237f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 4241b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 42522f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 42651b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 42751b0f370SBram Moolenaar else 42851b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 4291b9645deSBram Moolenaar endif 43045d5f26dSBram Moolenaarendfunc 43145d5f26dSBram Moolenaar 43251b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 43351b0f370SBram Moolenaar" if there is any. 43451b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 43551b0f370SBram Moolenaar if v:beval_winid != s:startwin 43651b0f370SBram Moolenaar return 43751b0f370SBram Moolenaar endif 43851b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 43951b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 44022f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 44122f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 44251b0f370SBram Moolenaar return '' 44351b0f370SBram Moolenaarendfunc 44451b0f370SBram Moolenaar 44545d5f26dSBram Moolenaar" Handle an error. 44645d5f26dSBram Moolenaarfunc s:HandleError(msg) 44722f1d0e3SBram Moolenaar if s:ignoreEvalError 44851b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 44922f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 45022f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 45151b0f370SBram Moolenaar return 45251b0f370SBram Moolenaar endif 45345d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 45445d5f26dSBram Moolenaarendfunc 45545d5f26dSBram Moolenaar 456*c4b533e1SBram Moolenaarfunc s:GotoStartwinOrCreateIt() 457*c4b533e1SBram Moolenaar if !win_gotoid(s:startwin) 458*c4b533e1SBram Moolenaar new 459*c4b533e1SBram Moolenaar let s:startwin = win_getid(winnr()) 460*c4b533e1SBram Moolenaar call s:InstallWinbar() 461*c4b533e1SBram Moolenaar endif 462*c4b533e1SBram Moolenaarendfunc 463*c4b533e1SBram Moolenaar 464e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 465e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 466e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 467fe386641SBram Moolenaar let wid = win_getid(winnr()) 468fe386641SBram Moolenaar 46960e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 47060e73f2aSBram Moolenaar let s:stopped = 1 47160e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 47260e73f2aSBram Moolenaar let s:stopped = 0 47360e73f2aSBram Moolenaar endif 47460e73f2aSBram Moolenaar 475*c4b533e1SBram Moolenaar call s:GotoStartwinOrCreateIt() 476*c4b533e1SBram Moolenaar 477e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 4781b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 479e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 480fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 4811b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 482fe386641SBram Moolenaar if &modified 483fe386641SBram Moolenaar " TODO: find existing window 484fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 485fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 486*c4b533e1SBram Moolenaar call s:InstallWinbar() 487fe386641SBram Moolenaar else 488fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 489fe386641SBram Moolenaar endif 490fe386641SBram Moolenaar endif 491fe386641SBram Moolenaar exe lnum 49201164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 4931b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 494fe386641SBram Moolenaar setlocal signcolumn=yes 495fe386641SBram Moolenaar endif 496fe386641SBram Moolenaar else 497fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 498fe386641SBram Moolenaar endif 499fe386641SBram Moolenaar 500fe386641SBram Moolenaar call win_gotoid(wid) 501e09ba7baSBram Moolenaarendfunc 502e09ba7baSBram Moolenaar 503e09ba7baSBram Moolenaar" Handle setting a breakpoint 504e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 505e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 506e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 507e09ba7baSBram Moolenaar if nr == 0 508e09ba7baSBram Moolenaar return 509fe386641SBram Moolenaar endif 510e09ba7baSBram Moolenaar 511e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 512e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 513e09ba7baSBram Moolenaar else 514e09ba7baSBram Moolenaar let entry = {} 515e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 516fe386641SBram Moolenaar endif 517e09ba7baSBram Moolenaar 518e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 519e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 520e09ba7baSBram Moolenaar let entry['fname'] = fname 521e09ba7baSBram Moolenaar let entry['lnum'] = lnum 5221b9645deSBram Moolenaar 5231b9645deSBram Moolenaar if bufloaded(fname) 5241b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5251b9645deSBram Moolenaar endif 5261b9645deSBram Moolenaarendfunc 5271b9645deSBram Moolenaar 5281b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 5291b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 5301b9645deSBram Moolenaar let a:entry['placed'] = 1 531e09ba7baSBram Moolenaarendfunc 532e09ba7baSBram Moolenaar 533e09ba7baSBram Moolenaar" Handle deleting a breakpoint 534e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 535e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 536e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 537e09ba7baSBram Moolenaar if nr == 0 538e09ba7baSBram Moolenaar return 539e09ba7baSBram Moolenaar endif 5401b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 5411b9645deSBram Moolenaar let entry = s:breakpoints[nr] 5421b9645deSBram Moolenaar if has_key(entry, 'placed') 543e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 5441b9645deSBram Moolenaar unlet entry['placed'] 5451b9645deSBram Moolenaar endif 546e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 5471b9645deSBram Moolenaar endif 548c572da5fSBram Moolenaarendfunc 5491b9645deSBram Moolenaar 5501b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 5511b9645deSBram Moolenaarfunc s:BufRead() 5521b9645deSBram Moolenaar let fname = expand('<afile>:p') 5531b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5541b9645deSBram Moolenaar if entry['fname'] == fname 5551b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5561b9645deSBram Moolenaar endif 5571b9645deSBram Moolenaar endfor 5581b9645deSBram Moolenaarendfunc 5591b9645deSBram Moolenaar 5601b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 5611b9645deSBram Moolenaarfunc s:BufUnloaded() 5621b9645deSBram Moolenaar let fname = expand('<afile>:p') 5631b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5641b9645deSBram Moolenaar if entry['fname'] == fname 5651b9645deSBram Moolenaar let entry['placed'] = 0 5661b9645deSBram Moolenaar endif 5671b9645deSBram Moolenaar endfor 5681b9645deSBram Moolenaarendfunc 5691b9645deSBram Moolenaar 570