Files
trade-iac/ansible/files/operator-dotfiles/nvim/lua/hazard3_dap.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