fix: refactor how `c` and `s` track breakpoints

We move state from Server.zig to Emulator.zig (the interface)
This commit is contained in:
Rekai Nyangadzayi Musuka 2023-01-26 23:54:33 -06:00
parent dbf00006e7
commit 82bad92fcf
3 changed files with 48 additions and 19 deletions

View File

@ -46,7 +46,7 @@ const String = union(enum) {
}
};
pub fn parse(self: *Self, allocator: Allocator, state: *State, emu: Emulator) !String {
pub fn parse(self: *Self, allocator: Allocator, emu: *Emulator) !String {
switch (self.contents[0]) {
// Required
'?' => {
@ -97,24 +97,25 @@ pub fn parse(self: *Self, allocator: Allocator, state: *State, emu: Emulator) !S
},
'M' => @panic("TODO: Memory Write"),
'c' => {
while (true) {
emu.step();
const r = emu.registers();
const is_thumb = emu.cpsr() >> 5 & 1 == 1;
const r15 = r[15] -| if (is_thumb) @as(u32, 4) else 8;
if (state.hw_bkpt.isHit(r15)) {
return .{ .static = "T05 hwbreak;" };
}
switch (emu.contd()) {
.SingleStep => unreachable,
.Trap => |r| switch (r) {
.HwBkpt => return .{ .static = "T05 hwbreak:;" },
.SwBkpt => return .{ .static = "T05 swbreak:;" },
},
}
},
's' => {
// var tokens = std.mem.tokenize(u8, self.contents[1..], " ");
// const addr = if (tokens.next()) |s| try std.fmt.parseInt(u32, s, 16) else null;
emu.step();
return .{ .static = "S05" }; // Signal.Trap
switch (emu.step()) {
.SingleStep => return .{ .static = "T05" },
.Trap => |r| switch (r) {
.HwBkpt => return .{ .static = "T05 hwbreak:;" },
.SwBkpt => return .{ .static = "T05 swbreak:;" },
},
}
},
// Breakpoints
@ -126,7 +127,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *State, emu: Emulator) !S
const addr_str = tokens.next() orelse return error.InvalidPacket;
const addr = try std.fmt.parseInt(u32, addr_str, 16);
state.hw_bkpt.remove(addr);
emu.state.hw_bkpt.remove(addr);
return .{ .static = "OK" };
},
'2' => return .{ .static = "" }, // TODO: Remove Write Watchpoint
@ -144,7 +145,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *State, emu: Emulator) !S
const addr = try std.fmt.parseInt(u32, addr_str, 16);
const kind = try std.fmt.parseInt(u32, kind_str, 16);
state.hw_bkpt.add(addr, kind) catch |e| {
emu.state.hw_bkpt.add(addr, kind) catch |e| {
switch (e) {
error.OutOfSpace => return .{ .static = "E22" }, // FIXME: Which errno?
else => return e,

View File

@ -1,7 +1,6 @@
const std = @import("std");
const network = @import("network");
const Packet = @import("Packet.zig");
const State = @import("State.zig");
const Socket = network.Socket;
const Allocator = std.mem.Allocator;
@ -60,7 +59,6 @@ pkt_cache: ?[]const u8 = null,
client: Socket,
_socket: Socket,
state: State = .{},
emu: Emulator,
pub fn init(emulator: Emulator) !Self {
@ -131,7 +129,7 @@ fn handlePacket(self: *Self, allocator: Allocator, input: []const u8) !Action {
var packet = Packet.from(allocator, input) catch return .nack;
defer packet.deinit(allocator);
var string = packet.parse(allocator, &self.state, self.emu) catch return .nack;
var string = packet.parse(allocator, &self.emu) catch return .nack;
defer string.deinit(allocator);
const reply = string.inner();

View File

@ -1,10 +1,20 @@
/// Re-export of the server interface
pub const Server = @import("Server.zig");
const State = @import("State.zig");
/// Interface for interacting between GDB and a GBA emu
pub const Emulator = struct {
const Self = @This();
const Signal = union(enum) {
const Kind = enum { HwBkpt, SwBkpt };
Trap: Kind,
SingleStep: void,
};
state: State = .{},
ptr: *anyopaque,
readFn: *const fn (*anyopaque, u32) u8,
@ -75,7 +85,27 @@ pub const Emulator = struct {
return self.cpsrFn(self.ptr);
}
pub inline fn step(self: Self) void {
pub inline fn contd(self: *Self) Signal {
while (true) {
const signal = self.step();
switch (signal) {
.SingleStep => {},
.Trap => return signal,
}
}
}
pub inline fn step(self: *Self) Signal {
self.stepFn(self.ptr);
const r = self.registersFn(self.ptr);
const is_thumb = self.cpsrFn(self.ptr) >> 5 & 1 == 1;
const r15 = r[15] -| if (is_thumb) @as(u32, 4) else 8;
if (self.state.hw_bkpt.isHit(r15)) return .{ .Trap = .HwBkpt };
return .SingleStep;
}
};