155 lines
3.9 KiB
Lua
155 lines
3.9 KiB
Lua
-- hazard3_dap.lua — Hazard3 helpers for nvim-dap (GDB DAP)
|
|
|
|
local M = {}
|
|
|
|
local disasm_buf ---@type integer|nil
|
|
|
|
local function ensure_disasm_buf()
|
|
if disasm_buf and vim.api.nvim_buf_is_valid(disasm_buf) then
|
|
return disasm_buf
|
|
end
|
|
|
|
disasm_buf = vim.api.nvim_create_buf(false, true)
|
|
pcall(vim.api.nvim_buf_set_name, disasm_buf, "[DAP Disassembly]")
|
|
|
|
vim.bo[disasm_buf].buftype = "nofile"
|
|
vim.bo[disasm_buf].bufhidden = "hide"
|
|
vim.bo[disasm_buf].swapfile = false
|
|
vim.bo[disasm_buf].filetype = "asm"
|
|
|
|
vim.bo[disasm_buf].modifiable = true
|
|
vim.api.nvim_buf_set_lines(disasm_buf, 0, -1, false, { "(DAP) Disassembly" })
|
|
vim.bo[disasm_buf].modifiable = false
|
|
|
|
return disasm_buf
|
|
end
|
|
|
|
local function show_buf(buf)
|
|
local wins = vim.fn.win_findbuf(buf)
|
|
if wins and #wins > 0 then
|
|
vim.api.nvim_set_current_win(wins[1])
|
|
vim.wo.cursorline = true
|
|
return
|
|
end
|
|
|
|
vim.cmd("vsplit")
|
|
vim.api.nvim_set_current_buf(buf)
|
|
vim.wo.cursorline = true
|
|
end
|
|
|
|
local function update_disassembly(buf, opts)
|
|
opts = opts or {}
|
|
local count = opts.count or 80
|
|
local before = opts.before or 20
|
|
|
|
local ok, dap = pcall(require, "dap")
|
|
if not ok then
|
|
return
|
|
end
|
|
|
|
local session = dap.session()
|
|
if not session then
|
|
return
|
|
end
|
|
|
|
session:request("stackTrace", { threadId = 1, startFrame = 0, levels = 1 }, function(err, resp)
|
|
if err then
|
|
vim.notify("DAP disasm: stackTrace failed: " .. tostring(err), vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
local frames = resp and resp.stackFrames or {}
|
|
if #frames == 0 then
|
|
vim.notify("DAP disasm: no stack frames", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
local frame = frames[1]
|
|
local memref = frame.instructionPointerReference
|
|
if memref == nil or memref == "" then
|
|
vim.notify("DAP disasm: no instructionPointerReference", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
session:request("disassemble", {
|
|
memoryReference = memref,
|
|
instructionOffset = -before,
|
|
instructionCount = count,
|
|
resolveSymbols = true,
|
|
}, function(err2, resp2)
|
|
if err2 then
|
|
vim.notify("DAP disasm: disassemble failed: " .. tostring(err2), vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
|
|
local insts = resp2 and resp2.instructions or {}
|
|
local lines = {}
|
|
lines[#lines + 1] = "memref: " .. memref
|
|
for _, i in ipairs(insts) do
|
|
local addr = i.address or "?"
|
|
local ins = i.instruction or ""
|
|
local mark = (addr == memref) and "=> " or " "
|
|
lines[#lines + 1] = mark .. addr .. " " .. ins
|
|
end
|
|
|
|
if not vim.api.nvim_buf_is_valid(buf) then
|
|
return
|
|
end
|
|
|
|
vim.bo[buf].modifiable = true
|
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
|
vim.bo[buf].modifiable = false
|
|
|
|
local pc_line
|
|
for idx, line in ipairs(lines) do
|
|
if line:sub(1, 3) == "=> " then
|
|
pc_line = idx
|
|
break
|
|
end
|
|
end
|
|
|
|
if pc_line then
|
|
local wins = vim.fn.win_findbuf(buf)
|
|
if wins and #wins > 0 then
|
|
for _, win in ipairs(wins) do
|
|
pcall(vim.api.nvim_win_set_cursor, win, { pc_line, 0 })
|
|
vim.wo[win].cursorline = true
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
function M.open_disassembly(opts)
|
|
local buf = ensure_disasm_buf()
|
|
local cur_win = vim.api.nvim_get_current_win()
|
|
show_buf(buf)
|
|
update_disassembly(buf, opts)
|
|
|
|
if opts and opts.keep_focus then
|
|
pcall(vim.api.nvim_set_current_win, cur_win)
|
|
end
|
|
end
|
|
|
|
function M.setup()
|
|
local ok, dap = pcall(require, "dap")
|
|
if not ok then
|
|
return
|
|
end
|
|
|
|
if vim.api.nvim_create_user_command then
|
|
pcall(vim.api.nvim_create_user_command, "DapDisassembly", function()
|
|
M.open_disassembly()
|
|
end, {})
|
|
end
|
|
|
|
dap.listeners.after.event_stopped["hazard3_disasm"] = function()
|
|
if disasm_buf and vim.api.nvim_buf_is_valid(disasm_buf) then
|
|
update_disassembly(disasm_buf, { keep_focus = true })
|
|
end
|
|
end
|
|
end
|
|
|
|
return M
|