mirror of
https://github.com/mamedev/mame.git
synced 2024-11-16 07:48:32 +01:00
9e36b6a6d9
Made the sound manager mute controls readable, and got rid of system enable since it just controls system mute anyway. This was causing confusion: phantom2 was trying to use both independentlyt casuing the mute bit to be ignored. THe Lua interface changes are mostly changing methods to properties, some renames to make things clearer, and some additional properties for better control over snapshots.
289 lines
7.6 KiB
Lua
289 lines
7.6 KiB
Lua
-- license:BSD-3-Clause
|
|
-- copyright-holders: Carl
|
|
local exports = {}
|
|
exports.name = "gdbstub"
|
|
exports.version = "0.0.1"
|
|
exports.description = "GDB stub plugin"
|
|
exports.license = "The BSD 3-Clause License"
|
|
exports.author = { name = "Carl" }
|
|
|
|
local gdbstub = exports
|
|
|
|
-- percpu mapping of mame registers to gdb register order
|
|
local regmaps = {
|
|
i386 = {
|
|
togdb = {
|
|
EAX = 1, ECX = 2, EDX = 3, EBX = 4, ESP = 5, EBP = 6, ESI = 7, EDI = 8, EIP = 9, EFLAGS = 10, CS = 11, SS = 12,
|
|
DS = 13, ES = 14, FS = 15, GS = 16 },
|
|
fromgdb = {
|
|
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", "EIP", "EFLAGS", "CS", "SS", "DS", "ES", "FS", "GS" },
|
|
regsize = 4,
|
|
addrsize = 4,
|
|
pcreg = "EIP"
|
|
}
|
|
}
|
|
regmaps.i486 = regmaps.i386
|
|
regmaps.pentium = regmaps.i386
|
|
|
|
function gdbstub.startplugin()
|
|
local debugger
|
|
local debug
|
|
local cpu
|
|
local breaks
|
|
local watches
|
|
local consolelog
|
|
local consolelast
|
|
local running
|
|
|
|
emu.register_start(function ()
|
|
debugger = manager.machine.debugger
|
|
if not debugger then
|
|
print("gdbstub: debugger not enabled")
|
|
return
|
|
end
|
|
cpu = manager.machine.devices[":maincpu"]
|
|
if not cpu then
|
|
print("gdbstub: maincpu not found")
|
|
end
|
|
if not regmaps[cpu.shortname] then
|
|
print("gdbstub: no register map for cpu " .. cpu.shortname)
|
|
cpu = nil
|
|
end
|
|
consolelog = debugger.consolelog
|
|
consolelast = 0
|
|
breaks = {byaddr = {}, byidx = {}}
|
|
watches = {byaddr = {}, byidx = {}}
|
|
running = false
|
|
end)
|
|
|
|
emu.register_stop(function()
|
|
consolelog = nil
|
|
cpu = nil
|
|
debug = nil
|
|
end)
|
|
|
|
local socket = emu.file("", 7)
|
|
local connected = false
|
|
socket:open("socket.127.0.0.1:2159")
|
|
|
|
emu.register_periodic(function ()
|
|
if not cpu then
|
|
return
|
|
end
|
|
|
|
if running and debugger.execution_state == "stop" then
|
|
socket:write("$S05#B8")
|
|
running = false
|
|
return
|
|
elseif debugger.execution_state == "run" then
|
|
running = true
|
|
end
|
|
|
|
local function chksum(str)
|
|
local sum = 0
|
|
str:gsub(".", function(s) sum = sum + s:byte() end)
|
|
return string.format("%.2x", sum & 0xff)
|
|
end
|
|
|
|
local function makebestr(val, len)
|
|
local str = ""
|
|
for count = 0, len - 1 do
|
|
str = str .. string.format("%.2x", (val >> (count * 8)) & 0xff)
|
|
end
|
|
return str
|
|
end
|
|
|
|
local last = consolelast
|
|
local msg = consolelog[#consolelog]
|
|
consolelast = #consolelog
|
|
if #consolelog > last and msg:find("Stopped at", 1, true) then
|
|
local point = tonumber(msg:match("Stopped at breakpoint ([0-9]+)"))
|
|
local map = regmaps[cpu.shortname]
|
|
running = false
|
|
if not point then
|
|
point = tonumber(msg:match("Stopped at watchpoint ([0-9]+"))
|
|
if not point then
|
|
return -- ??
|
|
end
|
|
local wp = watches.byidx[point]
|
|
if wp then
|
|
local reply = "T05" .. wp.type .. ":" .. makebestr(wp.addr, map.addrsize)
|
|
socket:write("$" .. reply .. "#" .. chksum(reply))
|
|
else
|
|
socket:write("$S05#B8")
|
|
end
|
|
return
|
|
else
|
|
local bp = breaks.byidx[point]
|
|
if bp then
|
|
local reply = "T05hwbreak:" .. makebestr(cpu.state[map.pcreg].value, map.regsize)
|
|
socket:write("$" .. reply .. "#" .. chksum(reply))
|
|
else
|
|
socket:write("$S05#B8")
|
|
end
|
|
return
|
|
end
|
|
end
|
|
|
|
if running and debugger.execution_state == "stop" then
|
|
socket:write("$S05#B8")
|
|
running = false
|
|
return
|
|
elseif debugger.execution_state == "run" then
|
|
running = true
|
|
end
|
|
|
|
local data = ""
|
|
|
|
repeat
|
|
local read = socket:read(100)
|
|
data = data .. read
|
|
until #read == 0
|
|
if #data == 0 then
|
|
return
|
|
end
|
|
if data == "\x03" then
|
|
debugger.execution_state = "stop"
|
|
socket:write("$S05#B8")
|
|
running = false
|
|
return
|
|
end
|
|
local packet, checksum = data:match("%$([^#]+)#(%x%x)")
|
|
if packet then
|
|
packet:gsub("}(.)", function(s) return string.char(string.byte(s) ~ 0x20) end)
|
|
local cmd = packet:sub(1, 1)
|
|
local map = regmaps[cpu.shortname]
|
|
if cmd == "g" then
|
|
local regs = {}
|
|
for reg, idx in pairs(map.togdb) do
|
|
regs[idx] = makebestr(cpu.state[reg].value, map.regsize)
|
|
end
|
|
local data = table.concat(regs)
|
|
socket:write("+$" .. data .. "#" .. chksum(data))
|
|
elseif cmd == "G" then
|
|
local count = 0
|
|
packet:sub(2):gsub(string.rep("%x", map.regsize * 2), function(s)
|
|
count = count + 1
|
|
cpu.state[map.fromgdb[count]].value = tonumber(s,16)
|
|
end)
|
|
socket:write("+$OK#9a")
|
|
elseif cmd == "m" then
|
|
local addr, len = packet:match("m(%x+),(%x+)")
|
|
if addr and len then
|
|
addr = tonumber(addr, 16)
|
|
len = tonumber(len, 16)
|
|
local data = ""
|
|
local space = cpu.spaces["program"]
|
|
for count = 1, len do
|
|
data = data .. string.format("%.2x", space:readv_u8(addr))
|
|
addr = addr + 1
|
|
end
|
|
socket:write("+$" .. data .. "#" .. chksum(data))
|
|
else
|
|
socket:write("+$E00#a5") -- fix error
|
|
end
|
|
elseif cmd == "M" then
|
|
local count = 0
|
|
local addr, len, data = packet:match("M(%x+),(%x+),(%x+)")
|
|
if addr and len and data then
|
|
addr = tonumber(addr, 16)
|
|
local space = cpu.spaces["program"]
|
|
data:gsub("%x%x", function(s) space:writev_u8(addr + count, tonumber(s, 16)) count = count + 1 end)
|
|
socket:write("+$OK#9a")
|
|
else
|
|
socket:write("+$E00#a5")
|
|
end
|
|
elseif cmd == "s" then
|
|
if #packet == 1 then
|
|
cpu.debug:step()
|
|
socket:write("+$OK#9a")
|
|
socket:write("$S05#B8")
|
|
running = false
|
|
else
|
|
socket:write("+$E00#a5")
|
|
end
|
|
elseif cmd == "c" then
|
|
if #packet == 1 then
|
|
cpu.debug:go()
|
|
socket:write("+$OK#9a")
|
|
else
|
|
socket:write("+$E00#a5")
|
|
end
|
|
elseif cmd == "Z" then
|
|
local btype, addr, kind = packet:match("Z([0-4]),(%x+),(.*)")
|
|
addr = tonumber(addr, 16)
|
|
if btype == "0" then
|
|
socket:write("") -- is machine dependant
|
|
elseif btype == "1" then
|
|
if breaks.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = cpu.debug:bpset(addr)
|
|
breaks.byaddr[addr] = idx
|
|
breaks.byidx[idx] = addr
|
|
socket:write("+$OK#9a")
|
|
elseif btype == "2" then
|
|
if watches.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = cpu.debug:wpset(cpu.spaces["program"], "w", addr, 1)
|
|
watches.byaddr[addr] = idx
|
|
watches.byidx[idx] = {addr = addr, type = "watch"}
|
|
socket:write("+$OK#9a")
|
|
elseif btype == "3" then
|
|
if watches.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = cpu.debug:wpset(cpu.spaces["program"], "r", addr, 1)
|
|
watches.byaddr[addr] = idx
|
|
watches.byidx[idx] = {addr = addr, type = "rwatch"}
|
|
socket:write("+$OK#9a")
|
|
elseif btype == "4" then
|
|
if watches.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = cpu.debug:wpset(cpu.spaces["program"], "rw", addr, 1)
|
|
watches.byaddr[addr] = idx
|
|
watches.byidx[idx] = {addr = addr, type = "awatch"}
|
|
socket:write("+$OK#9a")
|
|
end
|
|
elseif cmd == "z" then
|
|
local btype, addr, kind = packet:match("z([0-4]),(%x+),(.*)")
|
|
addr = tonumber(addr, 16)
|
|
if btype == "0" then
|
|
socket:write("") -- is machine dependent
|
|
elseif btype == "1" then
|
|
if not breaks.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = breaks.byaddr[addr]
|
|
cpu.debug:bpclr(idx)
|
|
breaks.byaddr[addr] = nil
|
|
breaks.byidx[idx] = nil
|
|
socket:write("+$OK#9a")
|
|
elseif btype == "2" or btype == "3" or btype == "4" then
|
|
if not watches.byaddr[addr] then
|
|
socket:write("+$E00#a5")
|
|
return
|
|
end
|
|
local idx = watches.byaddr[addr]
|
|
cpu.debug:wpclr(idx)
|
|
watches.byaddr[addr] = nil
|
|
watches.byidx[idx] = nil
|
|
socket:write("+$OK#9a")
|
|
end
|
|
elseif cmd == "?" then
|
|
socket:write("+$S05#B8")
|
|
else
|
|
socket:write("+$#00")
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
return exports
|