aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sartain <mikesart@fastmail.com>2021-03-10 06:20:22 -0700
committerGitHub <noreply@github.com>2021-03-10 08:20:22 -0500
commit300e71de9c3a99c613f295a74efba4bcce906064 (patch)
treebc5b441e94bf0919984ef4961f0de1213b2403d2
parent7844ca2e0501e1427cd18ece99f0baf63497df72 (diff)
downloadrneovim-300e71de9c3a99c613f295a74efba4bcce906064.tar.gz
rneovim-300e71de9c3a99c613f295a74efba4bcce906064.tar.bz2
rneovim-300e71de9c3a99c613f295a74efba4bcce906064.zip
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.
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt8
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim168
2 files changed, 169 insertions, 7 deletions
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index bec2b362ea..5885b20ab7 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -312,6 +312,8 @@ Other commands ~
*:Program* jump to the window with the running program
*:Source* jump to the window with the source code, create it if there
isn't one
+ *:Asm* jump to the window with the disassembly, create it if there
+ isn't one
Prompt mode ~
@@ -330,6 +332,12 @@ This works slightly differently:
Prompt mode can be used even when the |+terminal| feature is present with: >
let g:termdebug_use_prompt = 1
+<
+ *termdebug_disasm_window*
+If you want the Asm window shown by default, set this to 1. Setting to
+any value greater than 1 will set the Asm window height to that value: >
+ let g:termdebug_disasm_window = 15
+<
Communication ~
*termdebug-communication*
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 6870bcec75..fa5d064048 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -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)
for msg in a:msgs
@@ -608,7 +691,10 @@ func s:CommOutput(job_id, msgs, event)
if msg[0] == "\n"
let msg = msg[1:]
endif
- if msg != ''
+
+ if s:parsing_disasm_msg
+ call s:HandleDisasmMsg(msg)
+ elseif msg != ''
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
call s:HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
@@ -621,6 +707,9 @@ func s:CommOutput(job_id, msgs, event)
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
endif
endfor
@@ -651,6 +740,7 @@ func s:InstallCommands()
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()
" TODO: can the K mapping be restored?
@@ -689,6 +779,7 @@ func s:DeleteCommands()
delcommand Gdb
delcommand Program
delcommand Source
+ delcommand Asm
delcommand Winbar
nunmap K
@@ -963,6 +1054,48 @@ func s:GotoSourcewinOrCreateIt()
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
+
" Handle stopping and running message from gdb.
" Will update the sign that shows the current position.
func s:HandleCursor(msg)
@@ -981,10 +1114,31 @@ func s:HandleCursor(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 a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
- call s:GotoSourcewinOrCreateIt()
+ call s:GotoSourcewinOrCreateIt()
if expand('%:p') != fnamemodify(fname, ':p')
if &modified
" TODO: find existing window