mirror of
https://github.com/neovim/neovim.git
synced 2025-09-16 08:18:17 +00:00
runtime/termdebug 82be4849eed0b8fbee45bc8da99b685ec89af59a (#13660)
port termdebug dissasembly window only (termdebug.vim) This patch adds disassembly window to Termdebug :Asm should bring up disassembly window or setting: g:termdebug_disasm_window Values greater than 1 will set disasm window height. Code works by calling gdb disassemble command, demangling output and storing in Termdebug-asm-listing buffer + window. Current pc address is parsed from 'addr=' cursor msg and we search for that address in the disasm window. When the search fails, we execute a new "disassemble $pc" command. When in a location without a proper stack frame, "disassemble $pc" can fail and in this case we add a +length argument and try again. Tested with x86_64 gdb v10.1 and v8.2.1, and aarch64 gdb v7.12.
This commit is contained in:
168
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
168
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
@@ -43,7 +43,7 @@
|
||||
" balloon -> nvim floating window
|
||||
"
|
||||
" The code for opening the floating window was taken from the beautiful
|
||||
" implementation of LanguageClient-Neovim:
|
||||
" implementation of LanguageClient-Neovim:
|
||||
" https://github.com/autozimu/LanguageClient-neovim/blob/0ed9b69dca49c415390a8317b19149f97ae093fa/autoload/LanguageClient.vim#L304
|
||||
"
|
||||
" Neovim terminal also works seamlessly on windows, which is why the ability
|
||||
@@ -76,9 +76,14 @@ if !exists('g:termdebugger')
|
||||
endif
|
||||
|
||||
let s:pc_id = 12
|
||||
let s:break_id = 13 " breakpoint number is added to this
|
||||
let s:asm_id = 13
|
||||
let s:break_id = 14 " breakpoint number is added to this
|
||||
let s:stopped = 1
|
||||
|
||||
let s:parsing_disasm_msg = 0
|
||||
let s:asm_lines = []
|
||||
let s:asm_addr = ''
|
||||
|
||||
" Take a breakpoint number as used by GDB and turn it into an integer.
|
||||
" The breakpoint may contain a dot: 123.4 -> 123004
|
||||
" The main breakpoint has a zero subid.
|
||||
@@ -120,6 +125,7 @@ func s:StartDebug_internal(dict)
|
||||
|
||||
let s:ptywin = 0
|
||||
let s:pid = 0
|
||||
let s:asmwin = 0
|
||||
|
||||
" Uncomment this line to write logging in "debuglog".
|
||||
" call ch_logfile('debuglog', 'w')
|
||||
@@ -155,6 +161,14 @@ func s:StartDebug_internal(dict)
|
||||
else
|
||||
call s:StartDebug_term(a:dict)
|
||||
endif
|
||||
|
||||
if exists('g:termdebug_disasm_window')
|
||||
if g:termdebug_disasm_window
|
||||
let curwinid = win_getid(winnr())
|
||||
call s:GotoAsmwinOrCreateIt()
|
||||
call win_gotoid(curwinid)
|
||||
endif
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Use when debugger didn't start or ended.
|
||||
@@ -321,9 +335,9 @@ func s:StartDebug_prompt(dict)
|
||||
"call ch_log('executing "' . join(cmd) . '"')
|
||||
|
||||
let s:gdbjob = jobstart(cmd, {
|
||||
\ 'on_exit': function('s:EndPromptDebug'),
|
||||
\ 'on_stdout': function('s:GdbOutCallback'),
|
||||
\ })
|
||||
\ 'on_exit': function('s:EndPromptDebug'),
|
||||
\ 'on_stdout': function('s:GdbOutCallback'),
|
||||
\ })
|
||||
if s:gdbjob == 0
|
||||
echoerr 'invalid argument (or job table is full) while starting gdb job'
|
||||
exe 'bwipe! ' . s:ptybuf
|
||||
@@ -562,6 +576,15 @@ func s:GetFullname(msg)
|
||||
return name
|
||||
endfunc
|
||||
|
||||
" Extract the "addr" value from a gdb message with addr="0x0001234".
|
||||
func s:GetAsmAddr(msg)
|
||||
if a:msg !~ 'addr='
|
||||
return ''
|
||||
endif
|
||||
let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', ''))
|
||||
return addr
|
||||
endfunc
|
||||
|
||||
function s:EndTermDebug(job_id, exit_code, event)
|
||||
unlet s:gdbwin
|
||||
|
||||
@@ -601,6 +624,66 @@ func s:EndPromptDebug(job_id, exit_code, event)
|
||||
"call ch_log("Returning from EndPromptDebug()")
|
||||
endfunc
|
||||
|
||||
" - CommOutput: disassemble $pc
|
||||
" - CommOutput: &"disassemble $pc\n"
|
||||
" - CommOutput: ~"Dump of assembler code for function main(int, char**):\n"
|
||||
" - CommOutput: ~" 0x0000555556466f69 <+0>:\tpush rbp\n"
|
||||
" ...
|
||||
" - CommOutput: ~" 0x0000555556467cd0:\tpop rbp\n"
|
||||
" - CommOutput: ~" 0x0000555556467cd1:\tret \n"
|
||||
" - CommOutput: ~"End of assembler dump.\n"
|
||||
" - CommOutput: ^done
|
||||
|
||||
" - CommOutput: disassemble $pc
|
||||
" - CommOutput: &"disassemble $pc\n"
|
||||
" - CommOutput: &"No function contains specified address.\n"
|
||||
" - CommOutput: ^error,msg="No function contains specified address."
|
||||
func s:HandleDisasmMsg(msg)
|
||||
if a:msg =~ '^\^done'
|
||||
let curwinid = win_getid(winnr())
|
||||
if win_gotoid(s:asmwin)
|
||||
silent normal! gg0"_dG
|
||||
call setline(1, s:asm_lines)
|
||||
set nomodified
|
||||
set filetype=asm
|
||||
|
||||
let lnum = search('^' . s:asm_addr)
|
||||
if lnum != 0
|
||||
exe 'sign unplace ' . s:asm_id
|
||||
exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC'
|
||||
endif
|
||||
|
||||
call win_gotoid(curwinid)
|
||||
endif
|
||||
|
||||
let s:parsing_disasm_msg = 0
|
||||
let s:asm_lines = []
|
||||
elseif a:msg =~ '^\^error,msg='
|
||||
if s:parsing_disasm_msg == 1
|
||||
" Disassemble call ran into an error. This can happen when gdb can't
|
||||
" find the function frame address, so let's try to disassemble starting
|
||||
" at current PC
|
||||
call s:SendCommand('disassemble $pc,+100')
|
||||
endif
|
||||
let s:parsing_disasm_msg = 0
|
||||
elseif a:msg =~ '\&\"disassemble \$pc'
|
||||
if a:msg =~ '+100'
|
||||
" This is our second disasm attempt
|
||||
let s:parsing_disasm_msg = 2
|
||||
endif
|
||||
else
|
||||
let value = substitute(a:msg, '^\~\"[ ]*', '', '')
|
||||
let value = substitute(value, '^=>[ ]*', '', '')
|
||||
let value = substitute(value, '\\n\"
|
||||
$', '', '')
|
||||
let value = substitute(value, '
|
||||
', '', '')
|
||||
let value = substitute(value, '\\t', ' ', 'g')
|
||||
|
||||
if value != '' || !empty(s:asm_lines)
|
||||
call add(s:asm_lines, value)
|
||||
endif
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func s:CommOutput(job_id, msgs, event)
|
||||
@@ -608,7 +691,10 @@ func s:CommOutput(job_id, msgs, event)
|
||||
for msg in a:msgs
|
||||
" remove prefixed NL
|
||||
if msg[0] == "\n"
|
||||
if msg != ''
|
||||
let msg = msg[1:]
|
||||
endif
|
||||
|
||||
if s:parsing_disasm_msg
|
||||
call s:HandleDisasmMsg(msg)
|
||||
elseif msg != ''
|
||||
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
|
||||
@@ -621,6 +707,9 @@ func s:CommOutput(job_id, msgs, event)
|
||||
call s:HandleProgramRun(msg)
|
||||
elseif msg =~ '^\^done,value='
|
||||
call s:HandleEvaluate(msg)
|
||||
elseif msg =~ '^\^error,msg='
|
||||
call s:HandleError(msg)
|
||||
elseif msg =~ '^disassemble'
|
||||
let s:parsing_disasm_msg = 1
|
||||
let s:asm_lines = []
|
||||
endif
|
||||
@@ -651,6 +740,7 @@ func s:InstallCommands()
|
||||
|
||||
command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
|
||||
command Gdb call win_gotoid(s:gdbwin)
|
||||
command Program call win_gotoid(s:ptywin)
|
||||
command Source call s:GotoSourcewinOrCreateIt()
|
||||
command Asm call s:GotoAsmwinOrCreateIt()
|
||||
command Winbar call s:InstallWinbar()
|
||||
@@ -689,6 +779,7 @@ func s:DeleteCommands()
|
||||
delcommand Continue
|
||||
delcommand Evaluate
|
||||
delcommand Gdb
|
||||
delcommand Program
|
||||
delcommand Source
|
||||
delcommand Asm
|
||||
delcommand Winbar
|
||||
@@ -963,6 +1054,48 @@ func s:GotoSourcewinOrCreateIt()
|
||||
new
|
||||
let s:sourcewin = win_getid(winnr())
|
||||
call s:InstallWinbar()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func s:GotoAsmwinOrCreateIt()
|
||||
if !win_gotoid(s:asmwin)
|
||||
if win_gotoid(s:sourcewin)
|
||||
exe 'rightbelow new'
|
||||
else
|
||||
exe 'new'
|
||||
endif
|
||||
|
||||
let s:asmwin = win_getid(winnr())
|
||||
|
||||
setlocal nowrap
|
||||
setlocal number
|
||||
setlocal noswapfile
|
||||
setlocal buftype=nofile
|
||||
|
||||
let asmbuf = bufnr('Termdebug-asm-listing')
|
||||
if asmbuf > 0
|
||||
exe 'buffer' . asmbuf
|
||||
else
|
||||
exe 'file Termdebug-asm-listing'
|
||||
endif
|
||||
|
||||
if exists('g:termdebug_disasm_window')
|
||||
if g:termdebug_disasm_window > 1
|
||||
exe 'resize ' . g:termdebug_disasm_window
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if s:asm_addr != ''
|
||||
let lnum = search('^' . s:asm_addr)
|
||||
if lnum == 0
|
||||
if s:stopped
|
||||
call s:SendCommand('disassemble $pc')
|
||||
endif
|
||||
else
|
||||
exe 'sign unplace ' . s:asm_id
|
||||
exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC'
|
||||
endif
|
||||
endif
|
||||
endfunc
|
||||
|
||||
@@ -981,10 +1114,31 @@ func s:HandleCursor(msg)
|
||||
|
||||
if a:msg =~ 'fullname='
|
||||
let fname = s:GetFullname(a:msg)
|
||||
else
|
||||
let fname = ''
|
||||
endif
|
||||
|
||||
if a:msg =~ 'addr='
|
||||
let asm_addr = s:GetAsmAddr(a:msg)
|
||||
if asm_addr != ''
|
||||
let s:asm_addr = asm_addr
|
||||
|
||||
let curwinid = win_getid(winnr())
|
||||
if win_gotoid(s:asmwin)
|
||||
let lnum = search('^' . s:asm_addr)
|
||||
if lnum == 0
|
||||
call s:SendCommand('disassemble $pc')
|
||||
else
|
||||
exe 'sign unplace ' . s:asm_id
|
||||
exe 'sign place ' . s:asm_id . ' line=' . lnum . ' name=debugPC'
|
||||
endif
|
||||
|
||||
call win_gotoid(curwinid)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if lnum =~ '^[0-9]*$'
|
||||
if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
|
||||
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
|
||||
if lnum =~ '^[0-9]*$'
|
||||
call s:GotoSourcewinOrCreateIt()
|
||||
|
Reference in New Issue
Block a user