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. 28*b3623a38SBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<f-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 46*b3623a38SBram Moolenaarfunc s:StartDebug(...) 47*b3623a38SBram Moolenaar if exists('s:gdbwin') 48*b3623a38SBram Moolenaar echoerr 'Terminal debugger already running' 49*b3623a38SBram Moolenaar return 50*b3623a38SBram Moolenaar endif 51*b3623a38SBram Moolenaar 52fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 53fe386641SBram Moolenaar let s:startsigncolumn = &signcolumn 54fe386641SBram Moolenaar 5524a98a0eSBram Moolenaar let s:save_columns = 0 5624a98a0eSBram Moolenaar if exists('g:termdebug_wide') 5724a98a0eSBram Moolenaar if &columns < g:termdebug_wide 5838baa3e6SBram Moolenaar let s:save_columns = &columns 5938baa3e6SBram Moolenaar let &columns = g:termdebug_wide 6024a98a0eSBram Moolenaar endif 6138baa3e6SBram Moolenaar let vertical = 1 6238baa3e6SBram Moolenaar else 6338baa3e6SBram Moolenaar let vertical = 0 6438baa3e6SBram Moolenaar endif 6538baa3e6SBram Moolenaar 66c572da5fSBram Moolenaar " Open a terminal window without a job, to run the debugged program 67fe386641SBram Moolenaar let s:ptybuf = term_start('NONE', { 68fe386641SBram Moolenaar \ 'term_name': 'gdb program', 6938baa3e6SBram Moolenaar \ 'vertical': vertical, 70fe386641SBram Moolenaar \ }) 71fe386641SBram Moolenaar if s:ptybuf == 0 72fe386641SBram Moolenaar echoerr 'Failed to open the program terminal window' 73fe386641SBram Moolenaar return 74fe386641SBram Moolenaar endif 75fe386641SBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 7645d5f26dSBram Moolenaar let s:ptywin = win_getid(winnr()) 7751b0f370SBram Moolenaar if vertical 7851b0f370SBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 7951b0f370SBram Moolenaar " columns for that, thus one less for the terminal window. 8051b0f370SBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 8151b0f370SBram Moolenaar endif 82fe386641SBram Moolenaar 83fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 84fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 85fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 86fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 87fe386641SBram Moolenaar \ 'hidden': 1, 88fe386641SBram Moolenaar \ }) 89fe386641SBram Moolenaar if s:commbuf == 0 90fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 91fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 92fe386641SBram Moolenaar return 93fe386641SBram Moolenaar endif 94fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 95c572da5fSBram Moolenaar 96c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 97c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 98*b3623a38SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty] + a:000 99c572da5fSBram Moolenaar echomsg 'executing "' . join(cmd) . '"' 10060e73f2aSBram Moolenaar let s:gdbbuf = term_start(cmd, { 101c572da5fSBram Moolenaar \ 'exit_cb': function('s:EndDebug'), 102fe386641SBram Moolenaar \ 'term_finish': 'close', 103c572da5fSBram Moolenaar \ }) 10460e73f2aSBram Moolenaar if s:gdbbuf == 0 105fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 106fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 107fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 108fe386641SBram Moolenaar return 109fe386641SBram Moolenaar endif 11045d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 111fe386641SBram Moolenaar 112fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 11360e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 11460e73f2aSBram Moolenaar 1153e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 1163e4b84d0SBram Moolenaar " why the debugger doesn't work. 1173e4b84d0SBram Moolenaar let try_count = 0 1183e4b84d0SBram Moolenaar while 1 1193e4b84d0SBram Moolenaar let response = '' 120*b3623a38SBram Moolenaar for lnum in range(1,200) 1213e4b84d0SBram Moolenaar if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' 1223e4b84d0SBram Moolenaar let response = term_getline(s:gdbbuf, lnum + 1) 1233e4b84d0SBram Moolenaar if response =~ 'Undefined command' 124f3ba14ffSBram Moolenaar echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' 1253e4b84d0SBram Moolenaar exe 'bwipe! ' . s:ptybuf 1263e4b84d0SBram Moolenaar exe 'bwipe! ' . s:commbuf 1273e4b84d0SBram Moolenaar return 1283e4b84d0SBram Moolenaar endif 1293e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1303e4b84d0SBram Moolenaar " Success! 1313e4b84d0SBram Moolenaar break 1323e4b84d0SBram Moolenaar endif 1333e4b84d0SBram Moolenaar endif 1343e4b84d0SBram Moolenaar endfor 1353e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1363e4b84d0SBram Moolenaar break 1373e4b84d0SBram Moolenaar endif 1383e4b84d0SBram Moolenaar let try_count += 1 1393e4b84d0SBram Moolenaar if try_count > 100 1403e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 1413e4b84d0SBram Moolenaar break 1423e4b84d0SBram Moolenaar endif 1433e4b84d0SBram Moolenaar sleep 10m 1443e4b84d0SBram Moolenaar endwhile 1453e4b84d0SBram Moolenaar 14660e73f2aSBram Moolenaar " Interpret commands while the target is running. This should usualy only be 14760e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 14860e73f2aSBram Moolenaar " running. 14960e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 150e09ba7baSBram Moolenaar 151f3ba14ffSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 152f3ba14ffSBram Moolenaar " "Type <return> to continue" prompt. 153f3ba14ffSBram Moolenaar call s:SendCommand('-gdb-set pagination off') 154f3ba14ffSBram Moolenaar 15538baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 15638baa3e6SBram Moolenaar " There can be only one. 15738baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 15838baa3e6SBram Moolenaar 15938baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 16038baa3e6SBram Moolenaar " Can be used multiple times. 16138baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 16238baa3e6SBram Moolenaar 16345d5f26dSBram Moolenaar " Install debugger commands in the text window. 16445d5f26dSBram Moolenaar call win_gotoid(s:startwin) 165e09ba7baSBram Moolenaar call s:InstallCommands() 16645d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 167e09ba7baSBram Moolenaar 16851b0f370SBram Moolenaar " Enable showing a balloon with eval info 169246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 170246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 17151b0f370SBram Moolenaar if has("balloon_eval") 17251b0f370SBram Moolenaar set ballooneval 173246fe03dSBram Moolenaar endif 17451b0f370SBram Moolenaar if has("balloon_eval_term") 17551b0f370SBram Moolenaar set balloonevalterm 17651b0f370SBram Moolenaar endif 17751b0f370SBram Moolenaar endif 17851b0f370SBram Moolenaar 179e09ba7baSBram Moolenaar let s:breakpoints = {} 1801b9645deSBram Moolenaar 1811b9645deSBram Moolenaar augroup TermDebug 1821b9645deSBram Moolenaar au BufRead * call s:BufRead() 1831b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1841b9645deSBram Moolenaar augroup END 185c572da5fSBram Moolenaarendfunc 186c572da5fSBram Moolenaar 187c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 188c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 189fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 190*b3623a38SBram Moolenaar unlet s:gdbwin 191e09ba7baSBram Moolenaar 192e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 193e09ba7baSBram Moolenaar 194e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 195e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 196e09ba7baSBram Moolenaar call s:DeleteCommands() 197e09ba7baSBram Moolenaar 198e09ba7baSBram Moolenaar call win_gotoid(curwinid) 19938baa3e6SBram Moolenaar if s:save_columns > 0 20038baa3e6SBram Moolenaar let &columns = s:save_columns 20138baa3e6SBram Moolenaar endif 2021b9645deSBram Moolenaar 203246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 204246fe03dSBram Moolenaar set balloonexpr= 20551b0f370SBram Moolenaar if has("balloon_eval") 20651b0f370SBram Moolenaar set noballooneval 207246fe03dSBram Moolenaar endif 20851b0f370SBram Moolenaar if has("balloon_eval_term") 20951b0f370SBram Moolenaar set noballoonevalterm 21051b0f370SBram Moolenaar endif 21151b0f370SBram Moolenaar endif 21251b0f370SBram Moolenaar 2131b9645deSBram Moolenaar au! TermDebug 214fe386641SBram Moolenaarendfunc 215fe386641SBram Moolenaar 216fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 217fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 218fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 219fe386641SBram Moolenaar 220fe386641SBram Moolenaar for msg in msgs 221fe386641SBram Moolenaar " remove prefixed NL 222fe386641SBram Moolenaar if msg[0] == "\n" 223fe386641SBram Moolenaar let msg = msg[1:] 224fe386641SBram Moolenaar endif 225fe386641SBram Moolenaar if msg != '' 2261b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 227e09ba7baSBram Moolenaar call s:HandleCursor(msg) 22845d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 229e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 230e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 231e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 23245d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 23345d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 23445d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 23545d5f26dSBram Moolenaar call s:HandleError(msg) 236e09ba7baSBram Moolenaar endif 237e09ba7baSBram Moolenaar endif 238e09ba7baSBram Moolenaar endfor 239e09ba7baSBram Moolenaarendfunc 240e09ba7baSBram Moolenaar 241e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 242e09ba7baSBram Moolenaarfunc s:InstallCommands() 243e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 24471137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 245e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 24645d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 247e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 24860e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 24960e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 25060e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 251e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 25245d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 25345d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 25445d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 255c4b533e1SBram Moolenaar command Source call s:GotoStartwinOrCreateIt() 25671137fedSBram Moolenaar command Winbar call s:InstallWinbar() 25745d5f26dSBram Moolenaar 25845d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 25945d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 2601b9645deSBram Moolenaar 261f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 26271137fedSBram Moolenaar call s:InstallWinbar() 26371137fedSBram Moolenaar 26471137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 26571137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 26671137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 26771137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 26871137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 26971137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 27071137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 27171137fedSBram Moolenaar endif 27271137fedSBram Moolenaar endif 27371137fedSBram Moolenaarendfunc 27471137fedSBram Moolenaar 27571137fedSBram Moolenaarlet s:winbar_winids = [] 27671137fedSBram Moolenaar 27771137fedSBram Moolenaar" Install the window toolbar in the current window. 27871137fedSBram Moolenaarfunc s:InstallWinbar() 279c4b533e1SBram Moolenaar if has('menu') && &mouse != '' 28024a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 28124a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 28224a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 28324a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 28460e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 28524a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 28671137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 287c4b533e1SBram Moolenaar endif 288e09ba7baSBram Moolenaarendfunc 289e09ba7baSBram Moolenaar 290e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 291e09ba7baSBram Moolenaarfunc s:DeleteCommands() 292e09ba7baSBram Moolenaar delcommand Break 29371137fedSBram Moolenaar delcommand Clear 294e09ba7baSBram Moolenaar delcommand Step 29545d5f26dSBram Moolenaar delcommand Over 296e09ba7baSBram Moolenaar delcommand Finish 29760e73f2aSBram Moolenaar delcommand Run 29860e73f2aSBram Moolenaar delcommand Arguments 29960e73f2aSBram Moolenaar delcommand Stop 300e09ba7baSBram Moolenaar delcommand Continue 30145d5f26dSBram Moolenaar delcommand Evaluate 30245d5f26dSBram Moolenaar delcommand Gdb 30345d5f26dSBram Moolenaar delcommand Program 304*b3623a38SBram Moolenaar delcommand Source 30571137fedSBram Moolenaar delcommand Winbar 30645d5f26dSBram Moolenaar 30745d5f26dSBram Moolenaar nunmap K 3081b9645deSBram Moolenaar 3091b9645deSBram Moolenaar if has('menu') 31071137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 31171137fedSBram Moolenaar let curwinid = win_getid(winnr()) 31271137fedSBram Moolenaar for winid in s:winbar_winids 31371137fedSBram Moolenaar if win_gotoid(winid) 3141b9645deSBram Moolenaar aunmenu WinBar.Step 3151b9645deSBram Moolenaar aunmenu WinBar.Next 3161b9645deSBram Moolenaar aunmenu WinBar.Finish 3171b9645deSBram Moolenaar aunmenu WinBar.Cont 31860e73f2aSBram Moolenaar aunmenu WinBar.Stop 3191b9645deSBram Moolenaar aunmenu WinBar.Eval 3201b9645deSBram Moolenaar endif 32171137fedSBram Moolenaar endfor 32271137fedSBram Moolenaar call win_gotoid(curwinid) 32371137fedSBram Moolenaar let s:winbar_winids = [] 32471137fedSBram Moolenaar 32571137fedSBram Moolenaar if exists('s:saved_mousemodel') 32671137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 32771137fedSBram Moolenaar unlet s:saved_mousemodel 32871137fedSBram Moolenaar aunmenu PopUp.-SEP3- 32971137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 33071137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 33171137fedSBram Moolenaar aunmenu PopUp.Evaluate 33271137fedSBram Moolenaar endif 33371137fedSBram Moolenaar endif 3341b9645deSBram Moolenaar 33545d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 33645d5f26dSBram Moolenaar for key in keys(s:breakpoints) 33745d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 33845d5f26dSBram Moolenaar endfor 33938baa3e6SBram Moolenaar sign undefine debugPC 34038baa3e6SBram Moolenaar sign undefine debugBreakpoint 34145d5f26dSBram Moolenaar unlet s:breakpoints 342e09ba7baSBram Moolenaarendfunc 343e09ba7baSBram Moolenaar 344e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 345e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 34660e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 34760e73f2aSBram Moolenaar " Interrupt to make it work. 34860e73f2aSBram Moolenaar let do_continue = 0 34960e73f2aSBram Moolenaar if !s:stopped 35060e73f2aSBram Moolenaar let do_continue = 1 35160e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 35260e73f2aSBram Moolenaar sleep 10m 35360e73f2aSBram Moolenaar endif 35460e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 35560e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 35660e73f2aSBram Moolenaar if do_continue 35760e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 35860e73f2aSBram Moolenaar endif 359e09ba7baSBram Moolenaarendfunc 360e09ba7baSBram Moolenaar 36171137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 36271137fedSBram Moolenaarfunc s:ClearBreakpoint() 363e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 364e09ba7baSBram Moolenaar let lnum = line('.') 365e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 366e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 367e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 368e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 369e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 370e09ba7baSBram Moolenaar unlet s:breakpoints[key] 371e09ba7baSBram Moolenaar break 372e09ba7baSBram Moolenaar endif 373e09ba7baSBram Moolenaar endfor 374e09ba7baSBram Moolenaarendfunc 375e09ba7baSBram Moolenaar 376e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 377e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 378e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 379e09ba7baSBram Moolenaarendfunc 380e09ba7baSBram Moolenaar 38160e73f2aSBram Moolenaarfunc s:Run(args) 38260e73f2aSBram Moolenaar if a:args != '' 38360e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 38460e73f2aSBram Moolenaar endif 38560e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 38660e73f2aSBram Moolenaarendfunc 38760e73f2aSBram Moolenaar 38851b0f370SBram Moolenaarfunc s:SendEval(expr) 38951b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 39051b0f370SBram Moolenaar let s:evalexpr = a:expr 39151b0f370SBram Moolenaarendfunc 39251b0f370SBram Moolenaar 39345d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 39445d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 39545d5f26dSBram Moolenaar if a:arg != '' 39645d5f26dSBram Moolenaar let expr = a:arg 39745d5f26dSBram Moolenaar elseif a:range == 2 39845d5f26dSBram Moolenaar let pos = getcurpos() 39945d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 40045d5f26dSBram Moolenaar let regt = getregtype('v') 40145d5f26dSBram Moolenaar normal! gv"vy 40245d5f26dSBram Moolenaar let expr = @v 40345d5f26dSBram Moolenaar call setpos('.', pos) 40445d5f26dSBram Moolenaar call setreg('v', reg, regt) 40545d5f26dSBram Moolenaar else 40645d5f26dSBram Moolenaar let expr = expand('<cexpr>') 40745d5f26dSBram Moolenaar endif 40822f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 40951b0f370SBram Moolenaar call s:SendEval(expr) 41045d5f26dSBram Moolenaarendfunc 41145d5f26dSBram Moolenaar 41222f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 41351b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 41451b0f370SBram Moolenaar 41545d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 41645d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 4171b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 4181b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 41951b0f370SBram Moolenaar if s:evalFromBalloonExpr 42051b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 42151b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 42251b0f370SBram Moolenaar else 42351b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 42451b0f370SBram Moolenaar endif 42551b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 42651b0f370SBram Moolenaar else 4271b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 42851b0f370SBram Moolenaar endif 4291b9645deSBram Moolenaar 4307f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 4311b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 43222f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 43351b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 43451b0f370SBram Moolenaar else 43551b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 4361b9645deSBram Moolenaar endif 43745d5f26dSBram Moolenaarendfunc 43845d5f26dSBram Moolenaar 43951b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 44051b0f370SBram Moolenaar" if there is any. 44151b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 44251b0f370SBram Moolenaar if v:beval_winid != s:startwin 44351b0f370SBram Moolenaar return 44451b0f370SBram Moolenaar endif 44551b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 44651b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 44722f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 44822f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 44951b0f370SBram Moolenaar return '' 45051b0f370SBram Moolenaarendfunc 45151b0f370SBram Moolenaar 45245d5f26dSBram Moolenaar" Handle an error. 45345d5f26dSBram Moolenaarfunc s:HandleError(msg) 45422f1d0e3SBram Moolenaar if s:ignoreEvalError 45551b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 45622f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 45722f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 45851b0f370SBram Moolenaar return 45951b0f370SBram Moolenaar endif 46045d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 46145d5f26dSBram Moolenaarendfunc 46245d5f26dSBram Moolenaar 463c4b533e1SBram Moolenaarfunc s:GotoStartwinOrCreateIt() 464c4b533e1SBram Moolenaar if !win_gotoid(s:startwin) 465c4b533e1SBram Moolenaar new 466c4b533e1SBram Moolenaar let s:startwin = win_getid(winnr()) 467c4b533e1SBram Moolenaar call s:InstallWinbar() 468c4b533e1SBram Moolenaar endif 469c4b533e1SBram Moolenaarendfunc 470c4b533e1SBram Moolenaar 471e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 472e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 473e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 474fe386641SBram Moolenaar let wid = win_getid(winnr()) 475fe386641SBram Moolenaar 47660e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 47760e73f2aSBram Moolenaar let s:stopped = 1 47860e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 47960e73f2aSBram Moolenaar let s:stopped = 0 48060e73f2aSBram Moolenaar endif 48160e73f2aSBram Moolenaar 482c4b533e1SBram Moolenaar call s:GotoStartwinOrCreateIt() 483c4b533e1SBram Moolenaar 484e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 4851b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 486e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 487fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 4881b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 489fe386641SBram Moolenaar if &modified 490fe386641SBram Moolenaar " TODO: find existing window 491fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 492fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 493c4b533e1SBram Moolenaar call s:InstallWinbar() 494fe386641SBram Moolenaar else 495fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 496fe386641SBram Moolenaar endif 497fe386641SBram Moolenaar endif 498fe386641SBram Moolenaar exe lnum 49901164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 5001b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 501fe386641SBram Moolenaar setlocal signcolumn=yes 502fe386641SBram Moolenaar endif 503fe386641SBram Moolenaar else 504fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 505fe386641SBram Moolenaar endif 506fe386641SBram Moolenaar 507fe386641SBram Moolenaar call win_gotoid(wid) 508e09ba7baSBram Moolenaarendfunc 509e09ba7baSBram Moolenaar 510e09ba7baSBram Moolenaar" Handle setting a breakpoint 511e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 512e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 513e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 514e09ba7baSBram Moolenaar if nr == 0 515e09ba7baSBram Moolenaar return 516fe386641SBram Moolenaar endif 517e09ba7baSBram Moolenaar 518e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 519e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 520e09ba7baSBram Moolenaar else 521e09ba7baSBram Moolenaar let entry = {} 522e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 523fe386641SBram Moolenaar endif 524e09ba7baSBram Moolenaar 525e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 526e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 527e09ba7baSBram Moolenaar let entry['fname'] = fname 528e09ba7baSBram Moolenaar let entry['lnum'] = lnum 5291b9645deSBram Moolenaar 5301b9645deSBram Moolenaar if bufloaded(fname) 5311b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5321b9645deSBram Moolenaar endif 5331b9645deSBram Moolenaarendfunc 5341b9645deSBram Moolenaar 5351b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 5361b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 5371b9645deSBram Moolenaar let a:entry['placed'] = 1 538e09ba7baSBram Moolenaarendfunc 539e09ba7baSBram Moolenaar 540e09ba7baSBram Moolenaar" Handle deleting a breakpoint 541e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 542e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 543e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 544e09ba7baSBram Moolenaar if nr == 0 545e09ba7baSBram Moolenaar return 546e09ba7baSBram Moolenaar endif 5471b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 5481b9645deSBram Moolenaar let entry = s:breakpoints[nr] 5491b9645deSBram Moolenaar if has_key(entry, 'placed') 550e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 5511b9645deSBram Moolenaar unlet entry['placed'] 5521b9645deSBram Moolenaar endif 553e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 5541b9645deSBram Moolenaar endif 555c572da5fSBram Moolenaarendfunc 5561b9645deSBram Moolenaar 5571b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 5581b9645deSBram Moolenaarfunc s:BufRead() 5591b9645deSBram Moolenaar let fname = expand('<afile>:p') 5601b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5611b9645deSBram Moolenaar if entry['fname'] == fname 5621b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5631b9645deSBram Moolenaar endif 5641b9645deSBram Moolenaar endfor 5651b9645deSBram Moolenaarendfunc 5661b9645deSBram Moolenaar 5671b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 5681b9645deSBram Moolenaarfunc s:BufUnloaded() 5691b9645deSBram Moolenaar let fname = expand('<afile>:p') 5701b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5711b9645deSBram Moolenaar if entry['fname'] == fname 5721b9645deSBram Moolenaar let entry['placed'] = 0 5731b9645deSBram Moolenaar endif 5741b9645deSBram Moolenaar endfor 5751b9645deSBram Moolenaarendfunc 5761b9645deSBram Moolenaar 577