1fe386641SBram Moolenaar" Debugger plugin using gdb. 2c572da5fSBram Moolenaar" 3b3307b5eSBram Moolenaar" Author: Bram Moolenaar 4b3307b5eSBram Moolenaar" Copyright: Vim license applies, see ":help license" 5*82be4849SBram Moolenaar" Last Change: 2021 Jan 03 6c572da5fSBram Moolenaar" 7b3307b5eSBram Moolenaar" WORK IN PROGRESS - Only the basics work 8b3307b5eSBram Moolenaar" Note: On MS-Windows you need a recent version of gdb. The one included with 9b3307b5eSBram Moolenaar" MingW is too old (7.6.1). 10b3307b5eSBram Moolenaar" I used version 7.12 from http://www.equation.com/servlet/equation.cmd?fa=gdb 11fe386641SBram Moolenaar" 12b3307b5eSBram Moolenaar" There are two ways to run gdb: 13b3307b5eSBram Moolenaar" - In a terminal window; used if possible, does not work on MS-Windows 14b3307b5eSBram Moolenaar" Not used when g:termdebug_use_prompt is set to 1. 15b3307b5eSBram Moolenaar" - Using a "prompt" buffer; may use a terminal window for the program 16b3307b5eSBram Moolenaar" 17b3307b5eSBram Moolenaar" For both the current window is used to view source code and shows the 18b3307b5eSBram Moolenaar" current statement from gdb. 19b3307b5eSBram Moolenaar" 20b3307b5eSBram Moolenaar" USING A TERMINAL WINDOW 21b3307b5eSBram Moolenaar" 22b3307b5eSBram Moolenaar" Opens two visible terminal windows: 23b3307b5eSBram Moolenaar" 1. runs a pty for the debugged program, as with ":term NONE" 24b3307b5eSBram Moolenaar" 2. runs gdb, passing the pty of the debugged program 25fe386641SBram Moolenaar" A third terminal window is hidden, it is used for communication with gdb. 26fe386641SBram Moolenaar" 27b3307b5eSBram Moolenaar" USING A PROMPT BUFFER 28b3307b5eSBram Moolenaar" 29b3307b5eSBram Moolenaar" Opens a window with a prompt buffer to communicate with gdb. 30b3307b5eSBram Moolenaar" Gdb is run as a job with callbacks for I/O. 31b3307b5eSBram Moolenaar" On Unix another terminal window is opened to run the debugged program 32b3307b5eSBram Moolenaar" On MS-Windows a separate console is opened to run the debugged program 33b3307b5eSBram Moolenaar" 34fe386641SBram Moolenaar" The communication with gdb uses GDB/MI. See: 35fe386641SBram Moolenaar" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html 36c572da5fSBram Moolenaar 37b3307b5eSBram Moolenaar" In case this gets sourced twice. 3837c64c78SBram Moolenaarif exists(':Termdebug') 3937c64c78SBram Moolenaar finish 4037c64c78SBram Moolenaarendif 4137c64c78SBram Moolenaar 42b3307b5eSBram Moolenaar" Need either the +terminal feature or +channel and the prompt buffer. 43b3307b5eSBram Moolenaar" The terminal feature does not work with gdb on win32. 44b3307b5eSBram Moolenaarif has('terminal') && !has('win32') 45b3307b5eSBram Moolenaar let s:way = 'terminal' 46b3307b5eSBram Moolenaarelseif has('channel') && exists('*prompt_setprompt') 47b3307b5eSBram Moolenaar let s:way = 'prompt' 48b3307b5eSBram Moolenaarelse 49b3307b5eSBram Moolenaar if has('terminal') 50b3307b5eSBram Moolenaar let s:err = 'Cannot debug, missing prompt buffer support' 51b3307b5eSBram Moolenaar else 52b3307b5eSBram Moolenaar let s:err = 'Cannot debug, +channel feature is not supported' 53b3307b5eSBram Moolenaar endif 54b3307b5eSBram Moolenaar command -nargs=* -complete=file -bang Termdebug echoerr s:err 55b3307b5eSBram Moolenaar command -nargs=+ -complete=file -bang TermdebugCommand echoerr s:err 56b3307b5eSBram Moolenaar finish 57b3307b5eSBram Moolenaarendif 5860e73f2aSBram Moolenaar 59ca4cc018SBram Moolenaarlet s:keepcpo = &cpo 60ca4cc018SBram Moolenaarset cpo&vim 61ca4cc018SBram Moolenaar 62fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim". 63fe386641SBram Moolenaar" To end type "quit" in the gdb window. 6432c67ba7SBram Moolenaarcommand -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>) 6532c67ba7SBram Moolenaarcommand -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>) 66c572da5fSBram Moolenaar 67fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb". 6818223a59SBram Moolenaarif !exists('g:termdebugger') 6918223a59SBram Moolenaar let g:termdebugger = 'gdb' 70c572da5fSBram Moolenaarendif 71c572da5fSBram Moolenaar 72fe386641SBram Moolenaarlet s:pc_id = 12 73*82be4849SBram Moolenaarlet s:asm_id = 13 74*82be4849SBram Moolenaarlet s:break_id = 14 " breakpoint number is added to this 7560e73f2aSBram Moolenaarlet s:stopped = 1 76e09ba7baSBram Moolenaar 77*82be4849SBram Moolenaarlet s:parsing_disasm_msg = 0 78*82be4849SBram Moolenaarlet s:asm_lines = [] 79*82be4849SBram Moolenaarlet s:asm_addr = '' 80*82be4849SBram Moolenaar 815378e1cfSBram Moolenaar" Take a breakpoint number as used by GDB and turn it into an integer. 8237402ed5SBram Moolenaar" The breakpoint may contain a dot: 123.4 -> 123004 8337402ed5SBram Moolenaar" The main breakpoint has a zero subid. 8437402ed5SBram Moolenaarfunc s:Breakpoint2SignNumber(id, subid) 8537402ed5SBram Moolenaar return s:break_id + a:id * 1000 + a:subid 865378e1cfSBram Moolenaarendfunction 875378e1cfSBram Moolenaar 88f07f9e73SBram Moolenaarfunc s:Highlight(init, old, new) 89f07f9e73SBram Moolenaar let default = a:init ? 'default ' : '' 90f07f9e73SBram Moolenaar if a:new ==# 'light' && a:old !=# 'light' 91f07f9e73SBram Moolenaar exe "hi " . default . "debugPC term=reverse ctermbg=lightblue guibg=lightblue" 92f07f9e73SBram Moolenaar elseif a:new ==# 'dark' && a:old !=# 'dark' 93f07f9e73SBram Moolenaar exe "hi " . default . "debugPC term=reverse ctermbg=darkblue guibg=darkblue" 94e09ba7baSBram Moolenaar endif 95f07f9e73SBram Moolenaarendfunc 96f07f9e73SBram Moolenaar 97f07f9e73SBram Moolenaarcall s:Highlight(1, '', &background) 98e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red 99fe386641SBram Moolenaar 10032c67ba7SBram Moolenaarfunc s:StartDebug(bang, ...) 10132c67ba7SBram Moolenaar " First argument is the command to debug, second core file or process ID. 10232c67ba7SBram Moolenaar call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) 10332c67ba7SBram Moolenaarendfunc 10432c67ba7SBram Moolenaar 10532c67ba7SBram Moolenaarfunc s:StartDebugCommand(bang, ...) 10632c67ba7SBram Moolenaar " First argument is the command to debug, rest are run arguments. 10732c67ba7SBram Moolenaar call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang}) 10832c67ba7SBram Moolenaarendfunc 10932c67ba7SBram Moolenaar 11032c67ba7SBram Moolenaarfunc s:StartDebug_internal(dict) 111b3623a38SBram Moolenaar if exists('s:gdbwin') 11218223a59SBram Moolenaar echoerr 'Terminal debugger already running, cannot run two' 113b3623a38SBram Moolenaar return 114b3623a38SBram Moolenaar endif 11518223a59SBram Moolenaar if !executable(g:termdebugger) 11618223a59SBram Moolenaar echoerr 'Cannot execute debugger program "' .. g:termdebugger .. '"' 11718223a59SBram Moolenaar return 11818223a59SBram Moolenaar endif 11918223a59SBram Moolenaar 120b3307b5eSBram Moolenaar let s:ptywin = 0 1214551c0a9SBram Moolenaar let s:pid = 0 122*82be4849SBram Moolenaar let s:asmwin = 0 123b3623a38SBram Moolenaar 124b3307b5eSBram Moolenaar " Uncomment this line to write logging in "debuglog". 125b3307b5eSBram Moolenaar " call ch_logfile('debuglog', 'w') 126b3307b5eSBram Moolenaar 127b3307b5eSBram Moolenaar let s:sourcewin = win_getid(winnr()) 128cb80aa2dSBram Moolenaar 129cb80aa2dSBram Moolenaar " Remember the old value of 'signcolumn' for each buffer that it's set in, so 130cb80aa2dSBram Moolenaar " that we can restore the value for all buffers. 131cb80aa2dSBram Moolenaar let b:save_signcolumn = &signcolumn 132cb80aa2dSBram Moolenaar let s:signcolumn_buflist = [bufnr()] 133fe386641SBram Moolenaar 13424a98a0eSBram Moolenaar let s:save_columns = 0 13568e6560bSBram Moolenaar let s:allleft = 0 13624a98a0eSBram Moolenaar if exists('g:termdebug_wide') 13724a98a0eSBram Moolenaar if &columns < g:termdebug_wide 13838baa3e6SBram Moolenaar let s:save_columns = &columns 13938baa3e6SBram Moolenaar let &columns = g:termdebug_wide 14068e6560bSBram Moolenaar " If we make the Vim window wider, use the whole left halve for the debug 14168e6560bSBram Moolenaar " windows. 14268e6560bSBram Moolenaar let s:allleft = 1 14324a98a0eSBram Moolenaar endif 144b3307b5eSBram Moolenaar let s:vertical = 1 14538baa3e6SBram Moolenaar else 146b3307b5eSBram Moolenaar let s:vertical = 0 14738baa3e6SBram Moolenaar endif 14838baa3e6SBram Moolenaar 149b3307b5eSBram Moolenaar " Override using a terminal window by setting g:termdebug_use_prompt to 1. 150b3307b5eSBram Moolenaar let use_prompt = exists('g:termdebug_use_prompt') && g:termdebug_use_prompt 151b3307b5eSBram Moolenaar if has('terminal') && !has('win32') && !use_prompt 152b3307b5eSBram Moolenaar let s:way = 'terminal' 153b3307b5eSBram Moolenaar else 154b3307b5eSBram Moolenaar let s:way = 'prompt' 155b3307b5eSBram Moolenaar endif 156b3307b5eSBram Moolenaar 157b3307b5eSBram Moolenaar if s:way == 'prompt' 158b3307b5eSBram Moolenaar call s:StartDebug_prompt(a:dict) 159b3307b5eSBram Moolenaar else 160b3307b5eSBram Moolenaar call s:StartDebug_term(a:dict) 161b3307b5eSBram Moolenaar endif 162*82be4849SBram Moolenaar 163*82be4849SBram Moolenaar if exists('g:termdebug_disasm_window') 164*82be4849SBram Moolenaar if g:termdebug_disasm_window 165*82be4849SBram Moolenaar let curwinid = win_getid(winnr()) 166*82be4849SBram Moolenaar call s:GotoAsmwinOrCreateIt() 167*82be4849SBram Moolenaar call win_gotoid(curwinid) 168*82be4849SBram Moolenaar endif 169*82be4849SBram Moolenaar endif 170b3307b5eSBram Moolenaarendfunc 171b3307b5eSBram Moolenaar 172ef3c6a5bSBram Moolenaar" Use when debugger didn't start or ended. 173ef3c6a5bSBram Moolenaarfunc s:CloseBuffers() 174ef3c6a5bSBram Moolenaar exe 'bwipe! ' . s:ptybuf 175ef3c6a5bSBram Moolenaar exe 'bwipe! ' . s:commbuf 176ef3c6a5bSBram Moolenaar unlet! s:gdbwin 177ef3c6a5bSBram Moolenaarendfunc 178ef3c6a5bSBram Moolenaar 179b3307b5eSBram Moolenaarfunc s:StartDebug_term(dict) 180b3307b5eSBram Moolenaar " Open a terminal window without a job, to run the debugged program in. 181fe386641SBram Moolenaar let s:ptybuf = term_start('NONE', { 182b3307b5eSBram Moolenaar \ 'term_name': 'debugged program', 183b3307b5eSBram Moolenaar \ 'vertical': s:vertical, 184fe386641SBram Moolenaar \ }) 185fe386641SBram Moolenaar if s:ptybuf == 0 186fe386641SBram Moolenaar echoerr 'Failed to open the program terminal window' 187fe386641SBram Moolenaar return 188fe386641SBram Moolenaar endif 189fe386641SBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 19045d5f26dSBram Moolenaar let s:ptywin = win_getid(winnr()) 191b3307b5eSBram Moolenaar if s:vertical 19251b0f370SBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 19351b0f370SBram Moolenaar " columns for that, thus one less for the terminal window. 19451b0f370SBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 19568e6560bSBram Moolenaar if s:allleft 19668e6560bSBram Moolenaar " use the whole left column 19768e6560bSBram Moolenaar wincmd H 19868e6560bSBram Moolenaar endif 19951b0f370SBram Moolenaar endif 200fe386641SBram Moolenaar 201fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 202fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 203fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 204fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 205fe386641SBram Moolenaar \ 'hidden': 1, 206fe386641SBram Moolenaar \ }) 207fe386641SBram Moolenaar if s:commbuf == 0 208fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 209fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 210fe386641SBram Moolenaar return 211fe386641SBram Moolenaar endif 212fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 213c572da5fSBram Moolenaar 214c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 215c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 21632c67ba7SBram Moolenaar let gdb_args = get(a:dict, 'gdb_args', []) 21732c67ba7SBram Moolenaar let proc_args = get(a:dict, 'proc_args', []) 21832c67ba7SBram Moolenaar 21932c67ba7SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args 220b3307b5eSBram Moolenaar call ch_log('executing "' . join(cmd) . '"') 22160e73f2aSBram Moolenaar let s:gdbbuf = term_start(cmd, { 222fe386641SBram Moolenaar \ 'term_finish': 'close', 223c572da5fSBram Moolenaar \ }) 22460e73f2aSBram Moolenaar if s:gdbbuf == 0 225fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 226ef3c6a5bSBram Moolenaar call s:CloseBuffers() 227fe386641SBram Moolenaar return 228fe386641SBram Moolenaar endif 22945d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 230fe386641SBram Moolenaar 23132c67ba7SBram Moolenaar " Set arguments to be run 23232c67ba7SBram Moolenaar if len(proc_args) 23332c67ba7SBram Moolenaar call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r") 23432c67ba7SBram Moolenaar endif 23532c67ba7SBram Moolenaar 236fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 23760e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 23860e73f2aSBram Moolenaar 2393e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 2403e4b84d0SBram Moolenaar " why the debugger doesn't work. 2413e4b84d0SBram Moolenaar let try_count = 0 2423e4b84d0SBram Moolenaar while 1 243ef3c6a5bSBram Moolenaar let gdbproc = term_getjob(s:gdbbuf) 244ef3c6a5bSBram Moolenaar if gdbproc == v:null || job_status(gdbproc) !=# 'run' 245ef3c6a5bSBram Moolenaar echoerr string(g:termdebugger) . ' exited unexpectedly' 246ef3c6a5bSBram Moolenaar call s:CloseBuffers() 247ef3c6a5bSBram Moolenaar return 248ef3c6a5bSBram Moolenaar endif 249ef3c6a5bSBram Moolenaar 2503e4b84d0SBram Moolenaar let response = '' 251b3623a38SBram Moolenaar for lnum in range(1, 200) 25219c8fe19SBram Moolenaar let line1 = term_getline(s:gdbbuf, lnum) 25319c8fe19SBram Moolenaar let line2 = term_getline(s:gdbbuf, lnum + 1) 25419c8fe19SBram Moolenaar if line1 =~ 'new-ui mi ' 255f63db65bSBram Moolenaar " response can be in the same line or the next line 25619c8fe19SBram Moolenaar let response = line1 . line2 2573e4b84d0SBram Moolenaar if response =~ 'Undefined command' 258f3ba14ffSBram Moolenaar echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' 259ef3c6a5bSBram Moolenaar call s:CloseBuffers() 2603e4b84d0SBram Moolenaar return 2613e4b84d0SBram Moolenaar endif 2623e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 2633e4b84d0SBram Moolenaar " Success! 2643e4b84d0SBram Moolenaar break 2653e4b84d0SBram Moolenaar endif 26619c8fe19SBram Moolenaar elseif line1 =~ 'Reading symbols from' && line2 !~ 'new-ui mi ' 26719c8fe19SBram Moolenaar " Reading symbols might take a while, try more times 26806fe74aeSBram Moolenaar let try_count -= 1 26906fe74aeSBram Moolenaar endif 2703e4b84d0SBram Moolenaar endfor 2713e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 2723e4b84d0SBram Moolenaar break 2733e4b84d0SBram Moolenaar endif 2743e4b84d0SBram Moolenaar let try_count += 1 2753e4b84d0SBram Moolenaar if try_count > 100 2763e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 2773e4b84d0SBram Moolenaar break 2783e4b84d0SBram Moolenaar endif 2793e4b84d0SBram Moolenaar sleep 10m 2803e4b84d0SBram Moolenaar endwhile 2813e4b84d0SBram Moolenaar 28291359014SBram Moolenaar " Interpret commands while the target is running. This should usually only be 28360e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 28460e73f2aSBram Moolenaar " running. 28560e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 286b3307b5eSBram Moolenaar " Older gdb uses a different command. 287b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set target-async on') 288e09ba7baSBram Moolenaar 289f3ba14ffSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 290f3ba14ffSBram Moolenaar " "Type <return> to continue" prompt. 291b3307b5eSBram Moolenaar call s:SendCommand('set pagination off') 292f3ba14ffSBram Moolenaar 293ef3c6a5bSBram Moolenaar call job_setoptions(gdbproc, {'exit_cb': function('s:EndTermDebug')}) 294b3307b5eSBram Moolenaar call s:StartDebugCommon(a:dict) 295b3307b5eSBram Moolenaarendfunc 296b3307b5eSBram Moolenaar 297b3307b5eSBram Moolenaarfunc s:StartDebug_prompt(dict) 298b3307b5eSBram Moolenaar " Open a window with a prompt buffer to run gdb in. 299b3307b5eSBram Moolenaar if s:vertical 300b3307b5eSBram Moolenaar vertical new 301b3307b5eSBram Moolenaar else 302b3307b5eSBram Moolenaar new 303b3307b5eSBram Moolenaar endif 304b3307b5eSBram Moolenaar let s:gdbwin = win_getid(winnr()) 305b3307b5eSBram Moolenaar let s:promptbuf = bufnr('') 306b3307b5eSBram Moolenaar call prompt_setprompt(s:promptbuf, 'gdb> ') 307b3307b5eSBram Moolenaar set buftype=prompt 308b3307b5eSBram Moolenaar file gdb 309b3307b5eSBram Moolenaar call prompt_setcallback(s:promptbuf, function('s:PromptCallback')) 310b3307b5eSBram Moolenaar call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt')) 311b3307b5eSBram Moolenaar 312b3307b5eSBram Moolenaar if s:vertical 313b3307b5eSBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 314b3307b5eSBram Moolenaar " columns for that, thus one less for the terminal window. 315b3307b5eSBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 316b3307b5eSBram Moolenaar endif 317b3307b5eSBram Moolenaar 318b3307b5eSBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 319b3307b5eSBram Moolenaar let gdb_args = get(a:dict, 'gdb_args', []) 320b3307b5eSBram Moolenaar let proc_args = get(a:dict, 'proc_args', []) 321b3307b5eSBram Moolenaar 322b3307b5eSBram Moolenaar let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args 323b3307b5eSBram Moolenaar call ch_log('executing "' . join(cmd) . '"') 324b3307b5eSBram Moolenaar 325b3307b5eSBram Moolenaar let s:gdbjob = job_start(cmd, { 326b3307b5eSBram Moolenaar \ 'exit_cb': function('s:EndPromptDebug'), 327b3307b5eSBram Moolenaar \ 'out_cb': function('s:GdbOutCallback'), 328b3307b5eSBram Moolenaar \ }) 329b3307b5eSBram Moolenaar if job_status(s:gdbjob) != "run" 330b3307b5eSBram Moolenaar echoerr 'Failed to start gdb' 331b3307b5eSBram Moolenaar exe 'bwipe! ' . s:promptbuf 332b3307b5eSBram Moolenaar return 333b3307b5eSBram Moolenaar endif 3344551c0a9SBram Moolenaar " Mark the buffer modified so that it's not easy to close. 3354551c0a9SBram Moolenaar set modified 336b3307b5eSBram Moolenaar let s:gdb_channel = job_getchannel(s:gdbjob) 337b3307b5eSBram Moolenaar 33891359014SBram Moolenaar " Interpret commands while the target is running. This should usually only 339b3307b5eSBram Moolenaar " be exec-interrupt, since many commands don't work properly while the 340b3307b5eSBram Moolenaar " target is running. 341b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 342b3307b5eSBram Moolenaar " Older gdb uses a different command. 343b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set target-async on') 344b3307b5eSBram Moolenaar 345b3307b5eSBram Moolenaar let s:ptybuf = 0 346b3307b5eSBram Moolenaar if has('win32') 347b3307b5eSBram Moolenaar " MS-Windows: run in a new console window for maximum compatibility 348b3307b5eSBram Moolenaar call s:SendCommand('set new-console on') 349b3307b5eSBram Moolenaar elseif has('terminal') 350b3307b5eSBram Moolenaar " Unix: Run the debugged program in a terminal window. Open it below the 351b3307b5eSBram Moolenaar " gdb window. 352b3307b5eSBram Moolenaar belowright let s:ptybuf = term_start('NONE', { 353b3307b5eSBram Moolenaar \ 'term_name': 'debugged program', 354b3307b5eSBram Moolenaar \ }) 355b3307b5eSBram Moolenaar if s:ptybuf == 0 356b3307b5eSBram Moolenaar echoerr 'Failed to open the program terminal window' 357b3307b5eSBram Moolenaar call job_stop(s:gdbjob) 358b3307b5eSBram Moolenaar return 359b3307b5eSBram Moolenaar endif 360b3307b5eSBram Moolenaar let s:ptywin = win_getid(winnr()) 361b3307b5eSBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 362b3307b5eSBram Moolenaar call s:SendCommand('tty ' . pty) 363b3307b5eSBram Moolenaar 364b3307b5eSBram Moolenaar " Since GDB runs in a prompt window, the environment has not been set to 365b3307b5eSBram Moolenaar " match a terminal window, need to do that now. 366b3307b5eSBram Moolenaar call s:SendCommand('set env TERM = xterm-color') 367b3307b5eSBram Moolenaar call s:SendCommand('set env ROWS = ' . winheight(s:ptywin)) 368b3307b5eSBram Moolenaar call s:SendCommand('set env LINES = ' . winheight(s:ptywin)) 369b3307b5eSBram Moolenaar call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin)) 370b3307b5eSBram Moolenaar call s:SendCommand('set env COLORS = ' . &t_Co) 371b3307b5eSBram Moolenaar call s:SendCommand('set env VIM_TERMINAL = ' . v:version) 372b3307b5eSBram Moolenaar else 373b3307b5eSBram Moolenaar " TODO: open a new terminal get get the tty name, pass on to gdb 374b3307b5eSBram Moolenaar call s:SendCommand('show inferior-tty') 375b3307b5eSBram Moolenaar endif 376b3307b5eSBram Moolenaar call s:SendCommand('set print pretty on') 377b3307b5eSBram Moolenaar call s:SendCommand('set breakpoint pending on') 378b3307b5eSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 379b3307b5eSBram Moolenaar call s:SendCommand('set pagination off') 380b3307b5eSBram Moolenaar 381b3307b5eSBram Moolenaar " Set arguments to be run 382b3307b5eSBram Moolenaar if len(proc_args) 383b3307b5eSBram Moolenaar call s:SendCommand('set args ' . join(proc_args)) 384b3307b5eSBram Moolenaar endif 385b3307b5eSBram Moolenaar 386b3307b5eSBram Moolenaar call s:StartDebugCommon(a:dict) 387b3307b5eSBram Moolenaar startinsert 388b3307b5eSBram Moolenaarendfunc 389b3307b5eSBram Moolenaar 390b3307b5eSBram Moolenaarfunc s:StartDebugCommon(dict) 39138baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 39238baa3e6SBram Moolenaar " There can be only one. 39338baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 39438baa3e6SBram Moolenaar 39545d5f26dSBram Moolenaar " Install debugger commands in the text window. 396b3307b5eSBram Moolenaar call win_gotoid(s:sourcewin) 397e09ba7baSBram Moolenaar call s:InstallCommands() 39845d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 399e09ba7baSBram Moolenaar 40051b0f370SBram Moolenaar " Enable showing a balloon with eval info 401246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 402246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 40351b0f370SBram Moolenaar if has("balloon_eval") 40451b0f370SBram Moolenaar set ballooneval 405246fe03dSBram Moolenaar endif 40651b0f370SBram Moolenaar if has("balloon_eval_term") 40751b0f370SBram Moolenaar set balloonevalterm 40851b0f370SBram Moolenaar endif 40951b0f370SBram Moolenaar endif 41051b0f370SBram Moolenaar 4115378e1cfSBram Moolenaar " Contains breakpoints that have been placed, key is a string with the GDB 4125378e1cfSBram Moolenaar " breakpoint number. 41337402ed5SBram Moolenaar " Each entry is a dict, containing the sub-breakpoints. Key is the subid. 41437402ed5SBram Moolenaar " For a breakpoint that is just a number the subid is zero. 41537402ed5SBram Moolenaar " For a breakpoint "123.4" the id is "123" and subid is "4". 41637402ed5SBram Moolenaar " Example, when breakpoint "44", "123", "123.1" and "123.2" exist: 41737402ed5SBram Moolenaar " {'44': {'0': entry}, '123': {'0': entry, '1': entry, '2': entry}} 418e09ba7baSBram Moolenaar let s:breakpoints = {} 4191b9645deSBram Moolenaar 42037402ed5SBram Moolenaar " Contains breakpoints by file/lnum. The key is "fname:lnum". 42137402ed5SBram Moolenaar " Each entry is a list of breakpoint IDs at that position. 42237402ed5SBram Moolenaar let s:breakpoint_locations = {} 42337402ed5SBram Moolenaar 4241b9645deSBram Moolenaar augroup TermDebug 4251b9645deSBram Moolenaar au BufRead * call s:BufRead() 4261b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 427f07f9e73SBram Moolenaar au OptionSet background call s:Highlight(0, v:option_old, v:option_new) 4281b9645deSBram Moolenaar augroup END 42932c67ba7SBram Moolenaar 430b3307b5eSBram Moolenaar " Run the command if the bang attribute was given and got to the debug 431b3307b5eSBram Moolenaar " window. 43232c67ba7SBram Moolenaar if get(a:dict, 'bang', 0) 43332c67ba7SBram Moolenaar call s:SendCommand('-exec-run') 43432c67ba7SBram Moolenaar call win_gotoid(s:ptywin) 43532c67ba7SBram Moolenaar endif 436c572da5fSBram Moolenaarendfunc 437c572da5fSBram Moolenaar 438b3307b5eSBram Moolenaar" Send a command to gdb. "cmd" is the string without line terminator. 439b3307b5eSBram Moolenaarfunc s:SendCommand(cmd) 440b3307b5eSBram Moolenaar call ch_log('sending to gdb: ' . a:cmd) 441b3307b5eSBram Moolenaar if s:way == 'prompt' 442b3307b5eSBram Moolenaar call ch_sendraw(s:gdb_channel, a:cmd . "\n") 443b3307b5eSBram Moolenaar else 444b3307b5eSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 445b3307b5eSBram Moolenaar endif 446b3307b5eSBram Moolenaarendfunc 447b3307b5eSBram Moolenaar 448b3307b5eSBram Moolenaar" This is global so that a user can create their mappings with this. 449b3307b5eSBram Moolenaarfunc TermDebugSendCommand(cmd) 450b3307b5eSBram Moolenaar if s:way == 'prompt' 451b3307b5eSBram Moolenaar call ch_sendraw(s:gdb_channel, a:cmd . "\n") 452b3307b5eSBram Moolenaar else 453b3307b5eSBram Moolenaar let do_continue = 0 454b3307b5eSBram Moolenaar if !s:stopped 455b3307b5eSBram Moolenaar let do_continue = 1 456b3307b5eSBram Moolenaar call s:SendCommand('-exec-interrupt') 457b3307b5eSBram Moolenaar sleep 10m 458b3307b5eSBram Moolenaar endif 459b3307b5eSBram Moolenaar call term_sendkeys(s:gdbbuf, a:cmd . "\r") 460b3307b5eSBram Moolenaar if do_continue 461b3307b5eSBram Moolenaar Continue 462b3307b5eSBram Moolenaar endif 463b3307b5eSBram Moolenaar endif 464b3307b5eSBram Moolenaarendfunc 465b3307b5eSBram Moolenaar 466b3307b5eSBram Moolenaar" Function called when entering a line in the prompt buffer. 467b3307b5eSBram Moolenaarfunc s:PromptCallback(text) 468b3307b5eSBram Moolenaar call s:SendCommand(a:text) 469b3307b5eSBram Moolenaarendfunc 470b3307b5eSBram Moolenaar 4714551c0a9SBram Moolenaar" Function called when pressing CTRL-C in the prompt buffer and when placing a 4724551c0a9SBram Moolenaar" breakpoint. 473b3307b5eSBram Moolenaarfunc s:PromptInterrupt() 4742ed890f1SBram Moolenaar call ch_log('Interrupting gdb') 4752ed890f1SBram Moolenaar if has('win32') 4762ed890f1SBram Moolenaar " Using job_stop() does not work on MS-Windows, need to send SIGTRAP to 4772ed890f1SBram Moolenaar " the debugger program so that gdb responds again. 4784551c0a9SBram Moolenaar if s:pid == 0 4794551c0a9SBram Moolenaar echoerr 'Cannot interrupt gdb, did not find a process ID' 4804551c0a9SBram Moolenaar else 4814551c0a9SBram Moolenaar call debugbreak(s:pid) 4824551c0a9SBram Moolenaar endif 4832ed890f1SBram Moolenaar else 4842ed890f1SBram Moolenaar call job_stop(s:gdbjob, 'int') 4852ed890f1SBram Moolenaar endif 486b3307b5eSBram Moolenaarendfunc 487b3307b5eSBram Moolenaar 488b3307b5eSBram Moolenaar" Function called when gdb outputs text. 489b3307b5eSBram Moolenaarfunc s:GdbOutCallback(channel, text) 490b3307b5eSBram Moolenaar call ch_log('received from gdb: ' . a:text) 491b3307b5eSBram Moolenaar 492b3307b5eSBram Moolenaar " Drop the gdb prompt, we have our own. 493b3307b5eSBram Moolenaar " Drop status and echo'd commands. 494a15b0a93SBram Moolenaar if a:text == '(gdb) ' || a:text == '^done' || a:text[0] == '&' 495b3307b5eSBram Moolenaar return 496b3307b5eSBram Moolenaar endif 497b3307b5eSBram Moolenaar if a:text =~ '^^error,msg=' 498b3307b5eSBram Moolenaar let text = s:DecodeMessage(a:text[11:]) 499b3307b5eSBram Moolenaar if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context' 500b3307b5eSBram Moolenaar " Silently drop evaluation errors. 501b3307b5eSBram Moolenaar unlet s:evalexpr 502b3307b5eSBram Moolenaar return 503b3307b5eSBram Moolenaar endif 504b3307b5eSBram Moolenaar elseif a:text[0] == '~' 505b3307b5eSBram Moolenaar let text = s:DecodeMessage(a:text[1:]) 506b3307b5eSBram Moolenaar else 507b3307b5eSBram Moolenaar call s:CommOutput(a:channel, a:text) 508b3307b5eSBram Moolenaar return 509b3307b5eSBram Moolenaar endif 510b3307b5eSBram Moolenaar 511b3307b5eSBram Moolenaar let curwinid = win_getid(winnr()) 512b3307b5eSBram Moolenaar call win_gotoid(s:gdbwin) 513b3307b5eSBram Moolenaar 514b3307b5eSBram Moolenaar " Add the output above the current prompt. 515b3307b5eSBram Moolenaar call append(line('$') - 1, text) 5164551c0a9SBram Moolenaar set modified 517b3307b5eSBram Moolenaar 518b3307b5eSBram Moolenaar call win_gotoid(curwinid) 519b3307b5eSBram Moolenaarendfunc 520b3307b5eSBram Moolenaar 521b3307b5eSBram Moolenaar" Decode a message from gdb. quotedText starts with a ", return the text up 522b3307b5eSBram Moolenaar" to the next ", unescaping characters. 523b3307b5eSBram Moolenaarfunc s:DecodeMessage(quotedText) 524b3307b5eSBram Moolenaar if a:quotedText[0] != '"' 525a15b0a93SBram Moolenaar echoerr 'DecodeMessage(): missing quote in ' . a:quotedText 526b3307b5eSBram Moolenaar return 527b3307b5eSBram Moolenaar endif 528b3307b5eSBram Moolenaar let result = '' 529b3307b5eSBram Moolenaar let i = 1 530b3307b5eSBram Moolenaar while a:quotedText[i] != '"' && i < len(a:quotedText) 531b3307b5eSBram Moolenaar if a:quotedText[i] == '\' 532b3307b5eSBram Moolenaar let i += 1 533b3307b5eSBram Moolenaar if a:quotedText[i] == 'n' 534b3307b5eSBram Moolenaar " drop \n 535b3307b5eSBram Moolenaar let i += 1 536b3307b5eSBram Moolenaar continue 537589edb34SBram Moolenaar elseif a:quotedText[i] == 't' 538589edb34SBram Moolenaar " append \t 539589edb34SBram Moolenaar let i += 1 540589edb34SBram Moolenaar let result .= "\t" 541589edb34SBram Moolenaar continue 542b3307b5eSBram Moolenaar endif 543b3307b5eSBram Moolenaar endif 544b3307b5eSBram Moolenaar let result .= a:quotedText[i] 545b3307b5eSBram Moolenaar let i += 1 546b3307b5eSBram Moolenaar endwhile 547b3307b5eSBram Moolenaar return result 548b3307b5eSBram Moolenaarendfunc 549b3307b5eSBram Moolenaar 550a15b0a93SBram Moolenaar" Extract the "name" value from a gdb message with fullname="name". 551a15b0a93SBram Moolenaarfunc s:GetFullname(msg) 5525378e1cfSBram Moolenaar if a:msg !~ 'fullname' 5535378e1cfSBram Moolenaar return '' 5545378e1cfSBram Moolenaar endif 555a15b0a93SBram Moolenaar let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', '')) 556a15b0a93SBram Moolenaar if has('win32') && name =~ ':\\\\' 557a15b0a93SBram Moolenaar " sometimes the name arrives double-escaped 558a15b0a93SBram Moolenaar let name = substitute(name, '\\\\', '\\', 'g') 559a15b0a93SBram Moolenaar endif 560a15b0a93SBram Moolenaar return name 561a15b0a93SBram Moolenaarendfunc 562a15b0a93SBram Moolenaar 563*82be4849SBram Moolenaar" Extract the "addr" value from a gdb message with addr="0x0001234". 564*82be4849SBram Moolenaarfunc s:GetAsmAddr(msg) 565*82be4849SBram Moolenaar if a:msg !~ 'addr=' 566*82be4849SBram Moolenaar return '' 567*82be4849SBram Moolenaar endif 568*82be4849SBram Moolenaar let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', '')) 569*82be4849SBram Moolenaar return addr 570*82be4849SBram Moolenaarendfunc 571b3307b5eSBram Moolenaarfunc s:EndTermDebug(job, status) 572fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 573b3623a38SBram Moolenaar unlet s:gdbwin 574e09ba7baSBram Moolenaar 575b3307b5eSBram Moolenaar call s:EndDebugCommon() 576b3307b5eSBram Moolenaarendfunc 577b3307b5eSBram Moolenaar 578b3307b5eSBram Moolenaarfunc s:EndDebugCommon() 579e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 580e09ba7baSBram Moolenaar 581b3307b5eSBram Moolenaar if exists('s:ptybuf') && s:ptybuf 582b3307b5eSBram Moolenaar exe 'bwipe! ' . s:ptybuf 583b3307b5eSBram Moolenaar endif 584b3307b5eSBram Moolenaar 585cb80aa2dSBram Moolenaar " Restore 'signcolumn' in all buffers for which it was set. 586b3307b5eSBram Moolenaar call win_gotoid(s:sourcewin) 587cb80aa2dSBram Moolenaar let was_buf = bufnr() 588cb80aa2dSBram Moolenaar for bufnr in s:signcolumn_buflist 589cb80aa2dSBram Moolenaar if bufexists(bufnr) 590cb80aa2dSBram Moolenaar exe bufnr .. "buf" 591cb80aa2dSBram Moolenaar if exists('b:save_signcolumn') 592cb80aa2dSBram Moolenaar let &signcolumn = b:save_signcolumn 593cb80aa2dSBram Moolenaar unlet b:save_signcolumn 594cb80aa2dSBram Moolenaar endif 595cb80aa2dSBram Moolenaar endif 596cb80aa2dSBram Moolenaar endfor 597cb80aa2dSBram Moolenaar exe was_buf .. "buf" 598cb80aa2dSBram Moolenaar 599e09ba7baSBram Moolenaar call s:DeleteCommands() 600e09ba7baSBram Moolenaar 601e09ba7baSBram Moolenaar call win_gotoid(curwinid) 602b3307b5eSBram Moolenaar 60338baa3e6SBram Moolenaar if s:save_columns > 0 60438baa3e6SBram Moolenaar let &columns = s:save_columns 60538baa3e6SBram Moolenaar endif 6061b9645deSBram Moolenaar 607246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 608246fe03dSBram Moolenaar set balloonexpr= 60951b0f370SBram Moolenaar if has("balloon_eval") 61051b0f370SBram Moolenaar set noballooneval 611246fe03dSBram Moolenaar endif 61251b0f370SBram Moolenaar if has("balloon_eval_term") 61351b0f370SBram Moolenaar set noballoonevalterm 61451b0f370SBram Moolenaar endif 61551b0f370SBram Moolenaar endif 61651b0f370SBram Moolenaar 6171b9645deSBram Moolenaar au! TermDebug 618fe386641SBram Moolenaarendfunc 619fe386641SBram Moolenaar 620b3307b5eSBram Moolenaarfunc s:EndPromptDebug(job, status) 621b3307b5eSBram Moolenaar let curwinid = win_getid(winnr()) 622b3307b5eSBram Moolenaar call win_gotoid(s:gdbwin) 6234551c0a9SBram Moolenaar set nomodified 624b3307b5eSBram Moolenaar close 625b3307b5eSBram Moolenaar if curwinid != s:gdbwin 626b3307b5eSBram Moolenaar call win_gotoid(curwinid) 627b3307b5eSBram Moolenaar endif 628b3307b5eSBram Moolenaar 629b3307b5eSBram Moolenaar call s:EndDebugCommon() 630b3307b5eSBram Moolenaar unlet s:gdbwin 631b3307b5eSBram Moolenaar call ch_log("Returning from EndPromptDebug()") 632b3307b5eSBram Moolenaarendfunc 633b3307b5eSBram Moolenaar 634*82be4849SBram Moolenaar" Disassembly window - added by Michael Sartain 635*82be4849SBram Moolenaar" 636*82be4849SBram Moolenaar" - CommOutput: disassemble $pc 637*82be4849SBram Moolenaar" - CommOutput: &"disassemble $pc\n" 638*82be4849SBram Moolenaar" - CommOutput: ~"Dump of assembler code for function main(int, char**):\n" 639*82be4849SBram Moolenaar" - CommOutput: ~" 0x0000555556466f69 <+0>:\tpush rbp\n" 640*82be4849SBram Moolenaar" ... 641*82be4849SBram Moolenaar" - CommOutput: ~" 0x0000555556467cd0:\tpop rbp\n" 642*82be4849SBram Moolenaar" - CommOutput: ~" 0x0000555556467cd1:\tret \n" 643*82be4849SBram Moolenaar" - CommOutput: ~"End of assembler dump.\n" 644*82be4849SBram Moolenaar" - CommOutput: ^done 645*82be4849SBram Moolenaar 646*82be4849SBram Moolenaar" - CommOutput: disassemble $pc 647*82be4849SBram Moolenaar" - CommOutput: &"disassemble $pc\n" 648*82be4849SBram Moolenaar" - CommOutput: &"No function contains specified address.\n" 649*82be4849SBram Moolenaar" - CommOutput: ^error,msg="No function contains specified address." 650*82be4849SBram Moolenaarfunc s:HandleDisasmMsg(msg) 651*82be4849SBram Moolenaar if a:msg =~ '^\^done' 652*82be4849SBram Moolenaar let curwinid = win_getid(winnr()) 653*82be4849SBram Moolenaar if win_gotoid(s:asmwin) 654*82be4849SBram Moolenaar silent normal! gg0"_dG 655*82be4849SBram Moolenaar call setline(1, s:asm_lines) 656*82be4849SBram Moolenaar set nomodified 657*82be4849SBram Moolenaar set filetype=asm 658*82be4849SBram Moolenaar 659*82be4849SBram Moolenaar let lnum = search('^' . s:asm_addr) 660*82be4849SBram Moolenaar if lnum != 0 661*82be4849SBram Moolenaar exe 'sign unplace ' . s:asm_id 662*82be4849SBram Moolenaar exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC' 663*82be4849SBram Moolenaar endif 664*82be4849SBram Moolenaar 665*82be4849SBram Moolenaar call win_gotoid(curwinid) 666*82be4849SBram Moolenaar endif 667*82be4849SBram Moolenaar 668*82be4849SBram Moolenaar let s:parsing_disasm_msg = 0 669*82be4849SBram Moolenaar let s:asm_lines = [] 670*82be4849SBram Moolenaar elseif a:msg =~ '^\^error,msg=' 671*82be4849SBram Moolenaar if s:parsing_disasm_msg == 1 672*82be4849SBram Moolenaar " Disassemble call ran into an error. This can happen when gdb can't 673*82be4849SBram Moolenaar " find the function frame address, so let's try to disassemble starting 674*82be4849SBram Moolenaar " at current PC 675*82be4849SBram Moolenaar call s:SendCommand('disassemble $pc,+100') 676*82be4849SBram Moolenaar endif 677*82be4849SBram Moolenaar let s:parsing_disasm_msg = 0 678*82be4849SBram Moolenaar elseif a:msg =~ '\&\"disassemble \$pc' 679*82be4849SBram Moolenaar if a:msg =~ '+100' 680*82be4849SBram Moolenaar " This is our second disasm attempt 681*82be4849SBram Moolenaar let s:parsing_disasm_msg = 2 682*82be4849SBram Moolenaar endif 683*82be4849SBram Moolenaar else 684*82be4849SBram Moolenaar let value = substitute(a:msg, '^\~\"[ ]*', '', '') 685*82be4849SBram Moolenaar let value = substitute(value, '^=>[ ]*', '', '') 686*82be4849SBram Moolenaar let value = substitute(value, '\\n\" 687*82be4849SBram Moolenaar$', '', '') 688*82be4849SBram Moolenaar let value = substitute(value, '\\n\"$', '', '') 689*82be4849SBram Moolenaar let value = substitute(value, ' 690*82be4849SBram Moolenaar', '', '') 691*82be4849SBram Moolenaar let value = substitute(value, '\\t', ' ', 'g') 692*82be4849SBram Moolenaar 693*82be4849SBram Moolenaar if value != '' || !empty(s:asm_lines) 694*82be4849SBram Moolenaar call add(s:asm_lines, value) 695*82be4849SBram Moolenaar endif 696*82be4849SBram Moolenaar endif 697fe386641SBram Moolenaarendfunc 698fe386641SBram Moolenaar 699fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 700fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 701fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 702fe386641SBram Moolenaar 703fe386641SBram Moolenaar for msg in msgs 704fe386641SBram Moolenaar " remove prefixed NL 705fe386641SBram Moolenaar if msg[0] == "\n" 706*82be4849SBram Moolenaar let msg = msg[1:] 707*82be4849SBram Moolenaar endif 708*82be4849SBram Moolenaar 709*82be4849SBram Moolenaar if s:parsing_disasm_msg 7101b9645deSBram Moolenaar call s:HandleDisasmMsg(msg) 711e09ba7baSBram Moolenaar elseif msg != '' 71245d5f26dSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 713e09ba7baSBram Moolenaar call s:HandleCursor(msg) 714e09ba7baSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 715e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 7164551c0a9SBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 7174551c0a9SBram Moolenaar call s:HandleBreakpointDelete(msg) 71845d5f26dSBram Moolenaar elseif msg =~ '^=thread-group-started' 71945d5f26dSBram Moolenaar call s:HandleProgramRun(msg) 72045d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 72145d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 722*82be4849SBram Moolenaar elseif msg =~ '^\^error,msg=' 723*82be4849SBram Moolenaar call s:HandleError(msg) 724*82be4849SBram Moolenaar elseif msg =~ '^disassemble' 725e09ba7baSBram Moolenaar let s:parsing_disasm_msg = 1 726e09ba7baSBram Moolenaar let s:asm_lines = [] 727e09ba7baSBram Moolenaar endif 728e09ba7baSBram Moolenaar endif 729e09ba7baSBram Moolenaar endfor 730589edb34SBram Moolenaarendfunc 731589edb34SBram Moolenaar 732589edb34SBram Moolenaarfunc s:GotoProgram() 733589edb34SBram Moolenaar if has('win32') 734589edb34SBram Moolenaar if executable('powershell') 735589edb34SBram Moolenaar call system(printf('powershell -Command "add-type -AssemblyName microsoft.VisualBasic;[Microsoft.VisualBasic.Interaction]::AppActivate(%d);"', s:pid)) 736469bdbdeSBram Moolenaar endif 737589edb34SBram Moolenaar else 738589edb34SBram Moolenaar call win_gotoid(s:ptywin) 739589edb34SBram Moolenaar endif 740e09ba7baSBram Moolenaarendfunc 741e09ba7baSBram Moolenaar 742963c1ad5SBram Moolenaar" Install commands in the current window to control the debugger. 743963c1ad5SBram Moolenaarfunc s:InstallCommands() 744963c1ad5SBram Moolenaar let save_cpo = &cpo 745589edb34SBram Moolenaar set cpo&vim 74671137fedSBram Moolenaar 747e09ba7baSBram Moolenaar command -nargs=? Break call s:SetBreakpoint(<q-args>) 74845d5f26dSBram Moolenaar command Clear call s:ClearBreakpoint() 749e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 75060e73f2aSBram Moolenaar command Over call s:SendCommand('-exec-next') 75160e73f2aSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 75260e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 753b3307b5eSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 754b3307b5eSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 755b3307b5eSBram Moolenaar 756b3307b5eSBram Moolenaar " using -exec-continue results in CTRL-C in gdb window not working 757b3307b5eSBram Moolenaar if s:way == 'prompt' 758b3307b5eSBram Moolenaar command Continue call s:SendCommand('continue') 759b3307b5eSBram Moolenaar else 760b3307b5eSBram Moolenaar command Continue call term_sendkeys(s:gdbbuf, "continue\r") 76145d5f26dSBram Moolenaar endif 76245d5f26dSBram Moolenaar 763589edb34SBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 764b3307b5eSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 765*82be4849SBram Moolenaar command Program call s:GotoProgram() 76671137fedSBram Moolenaar command Source call s:GotoSourcewinOrCreateIt() 76745d5f26dSBram Moolenaar command Asm call s:GotoAsmwinOrCreateIt() 768388a5d4fSBram Moolenaar command Winbar call s:InstallWinbar() 769388a5d4fSBram Moolenaar 77045d5f26dSBram Moolenaar if !exists('g:termdebug_map_K') || g:termdebug_map_K 771388a5d4fSBram Moolenaar let s:k_map_saved = maparg('K', 'n', 0, 1) 7721b9645deSBram Moolenaar nnoremap K :Evaluate<CR> 773f0b03c4eSBram Moolenaar endif 77471137fedSBram Moolenaar 77571137fedSBram Moolenaar if has('menu') && &mouse != '' 77671137fedSBram Moolenaar call s:InstallWinbar() 77771137fedSBram Moolenaar 77871137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 77971137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 78071137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 78171137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 78271137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 78371137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 78471137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 785963c1ad5SBram Moolenaar endif 786963c1ad5SBram Moolenaar endif 78771137fedSBram Moolenaar 78871137fedSBram Moolenaar let &cpo = save_cpo 78971137fedSBram Moolenaarendfunc 79071137fedSBram Moolenaar 79171137fedSBram Moolenaarlet s:winbar_winids = [] 79271137fedSBram Moolenaar 793c4b533e1SBram Moolenaar" Install the window toolbar in the current window. 79424a98a0eSBram Moolenaarfunc s:InstallWinbar() 79524a98a0eSBram Moolenaar if has('menu') && &mouse != '' 79624a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 79724a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 79860e73f2aSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 79924a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 80071137fedSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 801c4b533e1SBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 802e09ba7baSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 803e09ba7baSBram Moolenaar endif 804e09ba7baSBram Moolenaarendfunc 805e09ba7baSBram Moolenaar 806e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 80771137fedSBram Moolenaarfunc s:DeleteCommands() 808e09ba7baSBram Moolenaar delcommand Break 80945d5f26dSBram Moolenaar delcommand Clear 810e09ba7baSBram Moolenaar delcommand Step 81160e73f2aSBram Moolenaar delcommand Over 81260e73f2aSBram Moolenaar delcommand Finish 81360e73f2aSBram Moolenaar delcommand Run 814e09ba7baSBram Moolenaar delcommand Arguments 81545d5f26dSBram Moolenaar delcommand Stop 81645d5f26dSBram Moolenaar delcommand Continue 81745d5f26dSBram Moolenaar delcommand Evaluate 818b3623a38SBram Moolenaar delcommand Gdb 819*82be4849SBram Moolenaar delcommand Program 82071137fedSBram Moolenaar delcommand Source 82145d5f26dSBram Moolenaar delcommand Asm 8221b884a00SBram Moolenaar delcommand Winbar 8231b884a00SBram Moolenaar 8241b884a00SBram Moolenaar if exists('s:k_map_saved') 8251b884a00SBram Moolenaar if empty(s:k_map_saved) 826388a5d4fSBram Moolenaar nunmap K 8271b884a00SBram Moolenaar else 828388a5d4fSBram Moolenaar call mapset('n', 0, s:k_map_saved) 829388a5d4fSBram Moolenaar endif 8301b9645deSBram Moolenaar unlet s:k_map_saved 8311b9645deSBram Moolenaar endif 83271137fedSBram Moolenaar 83371137fedSBram Moolenaar if has('menu') 83471137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 83571137fedSBram Moolenaar let curwinid = win_getid(winnr()) 8361b9645deSBram Moolenaar for winid in s:winbar_winids 8371b9645deSBram Moolenaar if win_gotoid(winid) 8381b9645deSBram Moolenaar aunmenu WinBar.Step 8391b9645deSBram Moolenaar aunmenu WinBar.Next 84060e73f2aSBram Moolenaar aunmenu WinBar.Finish 8411b9645deSBram Moolenaar aunmenu WinBar.Cont 8421b9645deSBram Moolenaar aunmenu WinBar.Stop 84371137fedSBram Moolenaar aunmenu WinBar.Eval 84471137fedSBram Moolenaar endif 84571137fedSBram Moolenaar endfor 84671137fedSBram Moolenaar call win_gotoid(curwinid) 84771137fedSBram Moolenaar let s:winbar_winids = [] 84871137fedSBram Moolenaar 84971137fedSBram Moolenaar if exists('s:saved_mousemodel') 85071137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 85171137fedSBram Moolenaar unlet s:saved_mousemodel 85271137fedSBram Moolenaar aunmenu PopUp.-SEP3- 85371137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 85471137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 85571137fedSBram Moolenaar aunmenu PopUp.Evaluate 8561b9645deSBram Moolenaar endif 85745d5f26dSBram Moolenaar endif 85837402ed5SBram Moolenaar 85937402ed5SBram Moolenaar exe 'sign unplace ' . s:pc_id 86037402ed5SBram Moolenaar for [id, entries] in items(s:breakpoints) 86137402ed5SBram Moolenaar for subid in keys(entries) 86245d5f26dSBram Moolenaar exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) 86345d5f26dSBram Moolenaar endfor 86437402ed5SBram Moolenaar endfor 865a15b0a93SBram Moolenaar unlet s:breakpoints 866a15b0a93SBram Moolenaar unlet s:breakpoint_locations 867a15b0a93SBram Moolenaar 868a15b0a93SBram Moolenaar sign undefine debugPC 869a15b0a93SBram Moolenaar for val in s:BreakpointSigns 8704551c0a9SBram Moolenaar exe "sign undefine debugBreakpoint" . val 871e09ba7baSBram Moolenaar endfor 872e09ba7baSBram Moolenaar let s:BreakpointSigns = [] 873e09ba7baSBram Moolenaarendfunc 874589edb34SBram Moolenaar 87560e73f2aSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 87660e73f2aSBram Moolenaarfunc s:SetBreakpoint(at) 87760e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 87860e73f2aSBram Moolenaar " Interrupt to make it work. 87960e73f2aSBram Moolenaar let do_continue = 0 880b3307b5eSBram Moolenaar if !s:stopped 8814551c0a9SBram Moolenaar let do_continue = 1 882b3307b5eSBram Moolenaar if s:way == 'prompt' 88360e73f2aSBram Moolenaar call s:PromptInterrupt() 884b3307b5eSBram Moolenaar else 88560e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 88660e73f2aSBram Moolenaar endif 887589edb34SBram Moolenaar sleep 10m 888a15b0a93SBram Moolenaar endif 889589edb34SBram Moolenaar 890589edb34SBram Moolenaar " Use the fname:lnum format, older gdb can't handle --source. 891589edb34SBram Moolenaar let at = empty(a:at) ? 89260e73f2aSBram Moolenaar \ fnameescape(expand('%:p')) . ':' . line('.') : a:at 89360e73f2aSBram Moolenaar call s:SendCommand('-break-insert ' . at) 89460e73f2aSBram Moolenaar if do_continue 895e09ba7baSBram Moolenaar call s:SendCommand('-exec-continue') 896e09ba7baSBram Moolenaar endif 89771137fedSBram Moolenaarendfunc 89871137fedSBram Moolenaar 899e09ba7baSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 900e09ba7baSBram Moolenaarfunc s:ClearBreakpoint() 90137402ed5SBram Moolenaar let fname = fnameescape(expand('%:p')) 90237402ed5SBram Moolenaar let lnum = line('.') 90337402ed5SBram Moolenaar let bploc = printf('%s:%d', fname, lnum) 90437402ed5SBram Moolenaar if has_key(s:breakpoint_locations, bploc) 90537402ed5SBram Moolenaar let idx = 0 90637402ed5SBram Moolenaar for id in s:breakpoint_locations[bploc] 90737402ed5SBram Moolenaar if has_key(s:breakpoints, id) 90837402ed5SBram Moolenaar " Assume this always works, the reply is simply "^done". 90937402ed5SBram Moolenaar call s:SendCommand('-break-delete ' . id) 91037402ed5SBram Moolenaar for subid in keys(s:breakpoints[id]) 91137402ed5SBram Moolenaar exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) 91237402ed5SBram Moolenaar endfor 913e09ba7baSBram Moolenaar unlet s:breakpoints[id] 91437402ed5SBram Moolenaar unlet s:breakpoint_locations[bploc][idx] 91537402ed5SBram Moolenaar break 916e09ba7baSBram Moolenaar else 917e09ba7baSBram Moolenaar let idx += 1 91837402ed5SBram Moolenaar endif 91937402ed5SBram Moolenaar endfor 92037402ed5SBram Moolenaar if empty(s:breakpoint_locations[bploc]) 92137402ed5SBram Moolenaar unlet s:breakpoint_locations[bploc] 922e09ba7baSBram Moolenaar endif 923e09ba7baSBram Moolenaar endif 92460e73f2aSBram Moolenaarendfunc 92560e73f2aSBram Moolenaar 92660e73f2aSBram Moolenaarfunc s:Run(args) 92760e73f2aSBram Moolenaar if a:args != '' 92860e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 92960e73f2aSBram Moolenaar endif 93060e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 93151b0f370SBram Moolenaarendfunc 93251b0f370SBram Moolenaar 93351b0f370SBram Moolenaarfunc s:SendEval(expr) 93451b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 93551b0f370SBram Moolenaar let s:evalexpr = a:expr 93645d5f26dSBram Moolenaarendfunc 93745d5f26dSBram Moolenaar 93845d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 93945d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 94045d5f26dSBram Moolenaar if a:arg != '' 94145d5f26dSBram Moolenaar let expr = a:arg 94245d5f26dSBram Moolenaar elseif a:range == 2 94345d5f26dSBram Moolenaar let pos = getcurpos() 94445d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 94545d5f26dSBram Moolenaar let regt = getregtype('v') 94645d5f26dSBram Moolenaar normal! gv"vy 94745d5f26dSBram Moolenaar let expr = @v 94845d5f26dSBram Moolenaar call setpos('.', pos) 94945d5f26dSBram Moolenaar call setreg('v', reg, regt) 95045d5f26dSBram Moolenaar else 95122f1d0e3SBram Moolenaar let expr = expand('<cexpr>') 95251b0f370SBram Moolenaar endif 95345d5f26dSBram Moolenaar let s:ignoreEvalError = 0 95445d5f26dSBram Moolenaar call s:SendEval(expr) 95522f1d0e3SBram Moolenaarendfunc 95651b0f370SBram Moolenaar 95751b0f370SBram Moolenaarlet s:ignoreEvalError = 0 95845d5f26dSBram Moolenaarlet s:evalFromBalloonExpr = 0 95945d5f26dSBram Moolenaar 9601b9645deSBram Moolenaar" Handle the result of data-evaluate-expression 9611b9645deSBram Moolenaarfunc s:HandleEvaluate(msg) 96251b0f370SBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 96351b0f370SBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 96451b0f370SBram Moolenaar if s:evalFromBalloonExpr 96551b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 96651b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 96751b0f370SBram Moolenaar else 96851b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 96951b0f370SBram Moolenaar endif 9701b9645deSBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 97151b0f370SBram Moolenaar else 9721b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 9737f2e9d7cSBram Moolenaar endif 9741b9645deSBram Moolenaar 97522f1d0e3SBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 97651b0f370SBram Moolenaar " Looks like a pointer, also display what it points to. 97751b0f370SBram Moolenaar let s:ignoreEvalError = 1 97851b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 9791b9645deSBram Moolenaar else 98045d5f26dSBram Moolenaar let s:evalFromBalloonExpr = 0 98145d5f26dSBram Moolenaar endif 98251b0f370SBram Moolenaarendfunc 98351b0f370SBram Moolenaar 98451b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 985b3307b5eSBram Moolenaar" if there is any. 986396e829fSBram Moolenaarfunc TermDebugBalloonExpr() 987b3307b5eSBram Moolenaar if v:beval_winid != s:sourcewin 988b3307b5eSBram Moolenaar return '' 989b3307b5eSBram Moolenaar endif 990b3307b5eSBram Moolenaar if !s:stopped 991396e829fSBram Moolenaar " Only evaluate when stopped, otherwise setting a breakpoint using the 99251b0f370SBram Moolenaar " mouse triggers a balloon. 99351b0f370SBram Moolenaar return '' 99451b0f370SBram Moolenaar endif 99522f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 1 99622f1d0e3SBram Moolenaar let s:evalFromBalloonExprResult = '' 99751b0f370SBram Moolenaar let s:ignoreEvalError = 1 99851b0f370SBram Moolenaar call s:SendEval(v:beval_text) 99951b0f370SBram Moolenaar return '' 100045d5f26dSBram Moolenaarendfunc 100145d5f26dSBram Moolenaar 100222f1d0e3SBram Moolenaar" Handle an error. 100351b0f370SBram Moolenaarfunc s:HandleError(msg) 100422f1d0e3SBram Moolenaar if s:ignoreEvalError 100522f1d0e3SBram Moolenaar " Result of s:SendEval() failed, ignore. 100651b0f370SBram Moolenaar let s:ignoreEvalError = 0 100751b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 100845d5f26dSBram Moolenaar return 100945d5f26dSBram Moolenaar endif 101045d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 1011b3307b5eSBram Moolenaarendfunc 1012b3307b5eSBram Moolenaar 1013c4b533e1SBram Moolenaarfunc s:GotoSourcewinOrCreateIt() 1014b3307b5eSBram Moolenaar if !win_gotoid(s:sourcewin) 1015c4b533e1SBram Moolenaar new 1016c4b533e1SBram Moolenaar let s:sourcewin = win_getid(winnr()) 1017c4b533e1SBram Moolenaar call s:InstallWinbar() 1018c4b533e1SBram Moolenaar endif 1019*82be4849SBram Moolenaarendfunc 1020*82be4849SBram Moolenaar 1021*82be4849SBram Moolenaarfunc s:GotoAsmwinOrCreateIt() 1022*82be4849SBram Moolenaar if !win_gotoid(s:asmwin) 1023*82be4849SBram Moolenaar if win_gotoid(s:sourcewin) 1024*82be4849SBram Moolenaar exe 'rightbelow new' 1025*82be4849SBram Moolenaar else 1026*82be4849SBram Moolenaar exe 'new' 1027*82be4849SBram Moolenaar endif 1028*82be4849SBram Moolenaar 1029*82be4849SBram Moolenaar let s:asmwin = win_getid(winnr()) 1030*82be4849SBram Moolenaar 1031*82be4849SBram Moolenaar setlocal nowrap 1032*82be4849SBram Moolenaar setlocal number 1033*82be4849SBram Moolenaar setlocal noswapfile 1034*82be4849SBram Moolenaar setlocal buftype=nofile 1035*82be4849SBram Moolenaar 1036*82be4849SBram Moolenaar let asmbuf = bufnr('Termdebug-asm-listing') 1037*82be4849SBram Moolenaar if asmbuf > 0 1038*82be4849SBram Moolenaar exe 'buffer' . asmbuf 1039*82be4849SBram Moolenaar else 1040*82be4849SBram Moolenaar exe 'file Termdebug-asm-listing' 1041*82be4849SBram Moolenaar endif 1042*82be4849SBram Moolenaar 1043*82be4849SBram Moolenaar if exists('g:termdebug_disasm_window') 1044*82be4849SBram Moolenaar if g:termdebug_disasm_window > 1 1045*82be4849SBram Moolenaar exe 'resize ' . g:termdebug_disasm_window 1046*82be4849SBram Moolenaar endif 1047*82be4849SBram Moolenaar endif 1048*82be4849SBram Moolenaar endif 1049*82be4849SBram Moolenaar 1050*82be4849SBram Moolenaar if s:asm_addr != '' 1051*82be4849SBram Moolenaar let lnum = search('^' . s:asm_addr) 1052*82be4849SBram Moolenaar if lnum == 0 1053*82be4849SBram Moolenaar if s:stopped 1054*82be4849SBram Moolenaar call s:SendCommand('disassemble $pc') 1055*82be4849SBram Moolenaar endif 1056*82be4849SBram Moolenaar else 1057*82be4849SBram Moolenaar exe 'sign unplace ' . s:asm_id 1058*82be4849SBram Moolenaar exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC' 1059*82be4849SBram Moolenaar endif 1060*82be4849SBram Moolenaar endif 1061e09ba7baSBram Moolenaarendfunc 1062e09ba7baSBram Moolenaar 1063e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 1064fe386641SBram Moolenaar" Will update the sign that shows the current position. 1065fe386641SBram Moolenaarfunc s:HandleCursor(msg) 106660e73f2aSBram Moolenaar let wid = win_getid(winnr()) 10674551c0a9SBram Moolenaar 106860e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 106960e73f2aSBram Moolenaar call ch_log('program stopped') 10704551c0a9SBram Moolenaar let s:stopped = 1 107160e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 107260e73f2aSBram Moolenaar call ch_log('program running') 107360e73f2aSBram Moolenaar let s:stopped = 0 1074a15b0a93SBram Moolenaar endif 1075a15b0a93SBram Moolenaar 1076a15b0a93SBram Moolenaar if a:msg =~ 'fullname=' 1077a15b0a93SBram Moolenaar let fname = s:GetFullname(a:msg) 1078a15b0a93SBram Moolenaar else 1079*82be4849SBram Moolenaar let fname = '' 1080*82be4849SBram Moolenaar endif 1081*82be4849SBram Moolenaar 1082*82be4849SBram Moolenaar if a:msg =~ 'addr=' 1083*82be4849SBram Moolenaar let asm_addr = s:GetAsmAddr(a:msg) 1084*82be4849SBram Moolenaar if asm_addr != '' 1085*82be4849SBram Moolenaar let s:asm_addr = asm_addr 1086*82be4849SBram Moolenaar 1087*82be4849SBram Moolenaar let curwinid = win_getid(winnr()) 1088*82be4849SBram Moolenaar if win_gotoid(s:asmwin) 1089*82be4849SBram Moolenaar let lnum = search('^' . s:asm_addr) 1090*82be4849SBram Moolenaar if lnum == 0 1091*82be4849SBram Moolenaar call s:SendCommand('disassemble $pc') 1092*82be4849SBram Moolenaar else 1093*82be4849SBram Moolenaar exe 'sign unplace ' . s:asm_id 1094*82be4849SBram Moolenaar exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC' 1095*82be4849SBram Moolenaar endif 1096*82be4849SBram Moolenaar 1097*82be4849SBram Moolenaar call win_gotoid(curwinid) 1098*82be4849SBram Moolenaar endif 1099*82be4849SBram Moolenaar endif 11001b9645deSBram Moolenaar endif 1101e09ba7baSBram Moolenaar 1102fe386641SBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 11034551c0a9SBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 11041b9645deSBram Moolenaar if lnum =~ '^[0-9]*$' 1105fe386641SBram Moolenaar call s:GotoSourcewinOrCreateIt() 1106fe386641SBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 1107fe386641SBram Moolenaar if &modified 1108b3307b5eSBram Moolenaar " TODO: find existing window 1109c4b533e1SBram Moolenaar exe 'split ' . fnameescape(fname) 1110fe386641SBram Moolenaar let s:sourcewin = win_getid(winnr()) 1111fe386641SBram Moolenaar call s:InstallWinbar() 1112fe386641SBram Moolenaar else 1113fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 1114fe386641SBram Moolenaar endif 111501164a65SBram Moolenaar endif 111639f7aa3cSBram Moolenaar exe lnum 1117cb80aa2dSBram Moolenaar exe 'sign unplace ' . s:pc_id 1118cb80aa2dSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC priority=110 file=' . fname 1119cb80aa2dSBram Moolenaar if !exists('b:save_signcolumn') 1120cb80aa2dSBram Moolenaar let b:save_signcolumn = &signcolumn 1121fe386641SBram Moolenaar call add(s:signcolumn_buflist, bufnr()) 1122fe386641SBram Moolenaar endif 11234551c0a9SBram Moolenaar setlocal signcolumn=yes 1124fe386641SBram Moolenaar endif 1125fe386641SBram Moolenaar elseif !s:stopped || fname != '' 1126fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 1127fe386641SBram Moolenaar endif 1128e09ba7baSBram Moolenaar 1129e09ba7baSBram Moolenaar call win_gotoid(wid) 1130de1a8314SBram Moolenaarendfunc 1131a15b0a93SBram Moolenaar 113237402ed5SBram Moolenaarlet s:BreakpointSigns = [] 113337402ed5SBram Moolenaar 113437402ed5SBram Moolenaarfunc s:CreateBreakpoint(id, subid) 113537402ed5SBram Moolenaar let nr = printf('%d.%d', a:id, a:subid) 113637402ed5SBram Moolenaar if index(s:BreakpointSigns, nr) == -1 1137de1a8314SBram Moolenaar call add(s:BreakpointSigns, nr) 1138de1a8314SBram Moolenaar exe "sign define debugBreakpoint" . nr . " text=" . substitute(nr, '\..*', '', '') . " texthl=debugBreakpoint" 1139de1a8314SBram Moolenaar endif 114037402ed5SBram Moolenaarendfunc 114137402ed5SBram Moolenaar 11425378e1cfSBram Moolenaarfunc! s:SplitMsg(s) 11435378e1cfSBram Moolenaar return split(a:s, '{.\{-}}\zs') 1144e09ba7baSBram Moolenaarendfunction 1145e09ba7baSBram Moolenaar 1146e09ba7baSBram Moolenaar" Handle setting a breakpoint 11476dccc962SBram Moolenaar" Will update the sign that shows the breakpoint 11486dccc962SBram Moolenaarfunc s:HandleNewBreakpoint(msg) 11496dccc962SBram Moolenaar if a:msg !~ 'fullname=' 11506dccc962SBram Moolenaar " a watch does not have a file name 11515378e1cfSBram Moolenaar return 11525378e1cfSBram Moolenaar endif 11535378e1cfSBram Moolenaar for msg in s:SplitMsg(a:msg) 11545378e1cfSBram Moolenaar let fname = s:GetFullname(msg) 11555378e1cfSBram Moolenaar if empty(fname) 11565378e1cfSBram Moolenaar continue 11575378e1cfSBram Moolenaar endif 1158e09ba7baSBram Moolenaar let nr = substitute(msg, '.*number="\([0-9.]*\)\".*', '\1', '') 1159fe386641SBram Moolenaar if empty(nr) 1160e09ba7baSBram Moolenaar return 116137402ed5SBram Moolenaar endif 116237402ed5SBram Moolenaar 116337402ed5SBram Moolenaar " If "nr" is 123 it becomes "123.0" and subid is "0". 116437402ed5SBram Moolenaar " If "nr" is 123.4 it becomes "123.4.0" and subid is "4"; "0" is discarded. 116537402ed5SBram Moolenaar let [id, subid; _] = map(split(nr . '.0', '\.'), 'v:val + 0') 116637402ed5SBram Moolenaar call s:CreateBreakpoint(id, subid) 116737402ed5SBram Moolenaar 116837402ed5SBram Moolenaar if has_key(s:breakpoints, id) 116937402ed5SBram Moolenaar let entries = s:breakpoints[id] 117037402ed5SBram Moolenaar else 117137402ed5SBram Moolenaar let entries = {} 117237402ed5SBram Moolenaar let s:breakpoints[id] = entries 117337402ed5SBram Moolenaar endif 1174e09ba7baSBram Moolenaar if has_key(entries, subid) 1175e09ba7baSBram Moolenaar let entry = entries[subid] 117637402ed5SBram Moolenaar else 1177fe386641SBram Moolenaar let entry = {} 1178e09ba7baSBram Moolenaar let entries[subid] = entry 11795378e1cfSBram Moolenaar endif 1180e09ba7baSBram Moolenaar 1181e09ba7baSBram Moolenaar let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '') 11821b9645deSBram Moolenaar let entry['fname'] = fname 118337402ed5SBram Moolenaar let entry['lnum'] = lnum 118437402ed5SBram Moolenaar 118537402ed5SBram Moolenaar let bploc = printf('%s:%d', fname, lnum) 118637402ed5SBram Moolenaar if !has_key(s:breakpoint_locations, bploc) 118737402ed5SBram Moolenaar let s:breakpoint_locations[bploc] = [] 118837402ed5SBram Moolenaar endif 11891b9645deSBram Moolenaar let s:breakpoint_locations[bploc] += [id] 119037402ed5SBram Moolenaar 11911b9645deSBram Moolenaar if bufloaded(fname) 11925378e1cfSBram Moolenaar call s:PlaceSign(id, subid, entry) 11931b9645deSBram Moolenaar endif 11941b9645deSBram Moolenaar endfor 119537402ed5SBram Moolenaarendfunc 119637402ed5SBram Moolenaar 11973132cdddSBram Moolenaarfunc s:PlaceSign(id, subid, entry) 11981b9645deSBram Moolenaar let nr = printf('%d.%d', a:id, a:subid) 1199e09ba7baSBram Moolenaar exe 'sign place ' . s:Breakpoint2SignNumber(a:id, a:subid) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint' . nr . ' priority=110 file=' . a:entry['fname'] 1200e09ba7baSBram Moolenaar let a:entry['placed'] = 1 1201e09ba7baSBram Moolenaarendfunc 1202e09ba7baSBram Moolenaar 1203e09ba7baSBram Moolenaar" Handle deleting a breakpoint 120437402ed5SBram Moolenaar" Will remove the sign that shows the breakpoint 120537402ed5SBram Moolenaarfunc s:HandleBreakpointDelete(msg) 1206e09ba7baSBram Moolenaar let id = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 1207e09ba7baSBram Moolenaar if empty(id) 120837402ed5SBram Moolenaar return 120937402ed5SBram Moolenaar endif 12101b9645deSBram Moolenaar if has_key(s:breakpoints, id) 121137402ed5SBram Moolenaar for [subid, entry] in items(s:breakpoints[id]) 12121b9645deSBram Moolenaar if has_key(entry, 'placed') 12131b9645deSBram Moolenaar exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid) 12145378e1cfSBram Moolenaar unlet entry['placed'] 121537402ed5SBram Moolenaar endif 121637402ed5SBram Moolenaar endfor 1217c572da5fSBram Moolenaar unlet s:breakpoints[id] 12181b9645deSBram Moolenaar endif 12194551c0a9SBram Moolenaarendfunc 12204551c0a9SBram Moolenaar 12214551c0a9SBram Moolenaar" Handle the debugged program starting to run. 12224551c0a9SBram Moolenaar" Will store the process ID in s:pid 12234551c0a9SBram Moolenaarfunc s:HandleProgramRun(msg) 12244551c0a9SBram Moolenaar let nr = substitute(a:msg, '.*pid="\([0-9]*\)\".*', '\1', '') + 0 12254551c0a9SBram Moolenaar if nr == 0 12264551c0a9SBram Moolenaar return 12274551c0a9SBram Moolenaar endif 12284551c0a9SBram Moolenaar let s:pid = nr 12294551c0a9SBram Moolenaar call ch_log('Detected process ID: ' . s:pid) 12301b9645deSBram Moolenaarendfunc 12311b9645deSBram Moolenaar 12321b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 123337402ed5SBram Moolenaarfunc s:BufRead() 123437402ed5SBram Moolenaar let fname = expand('<afile>:p') 12351b9645deSBram Moolenaar for [id, entries] in items(s:breakpoints) 123637402ed5SBram Moolenaar for [subid, entry] in items(entries) 12371b9645deSBram Moolenaar if entry['fname'] == fname 12381b9645deSBram Moolenaar call s:PlaceSign(id, subid, entry) 123937402ed5SBram Moolenaar endif 12401b9645deSBram Moolenaar endfor 12411b9645deSBram Moolenaar endfor 12421b9645deSBram Moolenaarendfunc 12431b9645deSBram Moolenaar 12441b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 124537402ed5SBram Moolenaarfunc s:BufUnloaded() 124637402ed5SBram Moolenaar let fname = expand('<afile>:p') 12471b9645deSBram Moolenaar for [id, entries] in items(s:breakpoints) 12481b9645deSBram Moolenaar for [subid, entry] in items(entries) 12491b9645deSBram Moolenaar if entry['fname'] == fname 12501b9645deSBram Moolenaar let entry['placed'] = 0 125137402ed5SBram Moolenaar endif 12521b9645deSBram Moolenaar endfor 1253ca4cc018SBram Moolenaar endfor 1254ca4cc018SBram Moolenaarendfunc 1255ca4cc018SBram Moolenaar 1256let &cpo = s:keepcpo 1257unlet s:keepcpo 1258