fix: refactor how `c` and `s` track breakpoints
We move state from Server.zig to Emulator.zig (the interface)
This commit is contained in:
parent
dbf00006e7
commit
82bad92fcf
|
@ -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]) {
|
switch (self.contents[0]) {
|
||||||
// Required
|
// Required
|
||||||
'?' => {
|
'?' => {
|
||||||
|
@ -97,24 +97,25 @@ pub fn parse(self: *Self, allocator: Allocator, state: *State, emu: Emulator) !S
|
||||||
},
|
},
|
||||||
'M' => @panic("TODO: Memory Write"),
|
'M' => @panic("TODO: Memory Write"),
|
||||||
'c' => {
|
'c' => {
|
||||||
while (true) {
|
switch (emu.contd()) {
|
||||||
emu.step();
|
.SingleStep => unreachable,
|
||||||
|
.Trap => |r| switch (r) {
|
||||||
const r = emu.registers();
|
.HwBkpt => return .{ .static = "T05 hwbreak:;" },
|
||||||
const is_thumb = emu.cpsr() >> 5 & 1 == 1;
|
.SwBkpt => return .{ .static = "T05 swbreak:;" },
|
||||||
const r15 = r[15] -| if (is_thumb) @as(u32, 4) else 8;
|
},
|
||||||
|
|
||||||
if (state.hw_bkpt.isHit(r15)) {
|
|
||||||
return .{ .static = "T05 hwbreak;" };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
's' => {
|
's' => {
|
||||||
// var tokens = std.mem.tokenize(u8, self.contents[1..], " ");
|
// var tokens = std.mem.tokenize(u8, self.contents[1..], " ");
|
||||||
// const addr = if (tokens.next()) |s| try std.fmt.parseInt(u32, s, 16) else null;
|
// const addr = if (tokens.next()) |s| try std.fmt.parseInt(u32, s, 16) else null;
|
||||||
|
|
||||||
emu.step();
|
switch (emu.step()) {
|
||||||
return .{ .static = "S05" }; // Signal.Trap
|
.SingleStep => return .{ .static = "T05" },
|
||||||
|
.Trap => |r| switch (r) {
|
||||||
|
.HwBkpt => return .{ .static = "T05 hwbreak:;" },
|
||||||
|
.SwBkpt => return .{ .static = "T05 swbreak:;" },
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Breakpoints
|
// 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_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
const addr = try std.fmt.parseInt(u32, addr_str, 16);
|
const addr = try std.fmt.parseInt(u32, addr_str, 16);
|
||||||
|
|
||||||
state.hw_bkpt.remove(addr);
|
emu.state.hw_bkpt.remove(addr);
|
||||||
return .{ .static = "OK" };
|
return .{ .static = "OK" };
|
||||||
},
|
},
|
||||||
'2' => return .{ .static = "" }, // TODO: Remove Write Watchpoint
|
'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 addr = try std.fmt.parseInt(u32, addr_str, 16);
|
||||||
const kind = try std.fmt.parseInt(u32, kind_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) {
|
switch (e) {
|
||||||
error.OutOfSpace => return .{ .static = "E22" }, // FIXME: Which errno?
|
error.OutOfSpace => return .{ .static = "E22" }, // FIXME: Which errno?
|
||||||
else => return e,
|
else => return e,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const network = @import("network");
|
const network = @import("network");
|
||||||
const Packet = @import("Packet.zig");
|
const Packet = @import("Packet.zig");
|
||||||
const State = @import("State.zig");
|
|
||||||
|
|
||||||
const Socket = network.Socket;
|
const Socket = network.Socket;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
@ -60,7 +59,6 @@ pkt_cache: ?[]const u8 = null,
|
||||||
client: Socket,
|
client: Socket,
|
||||||
_socket: Socket,
|
_socket: Socket,
|
||||||
|
|
||||||
state: State = .{},
|
|
||||||
emu: Emulator,
|
emu: Emulator,
|
||||||
|
|
||||||
pub fn init(emulator: Emulator) !Self {
|
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;
|
var packet = Packet.from(allocator, input) catch return .nack;
|
||||||
defer packet.deinit(allocator);
|
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);
|
defer string.deinit(allocator);
|
||||||
|
|
||||||
const reply = string.inner();
|
const reply = string.inner();
|
||||||
|
|
32
src/lib.zig
32
src/lib.zig
|
@ -1,10 +1,20 @@
|
||||||
/// Re-export of the server interface
|
/// Re-export of the server interface
|
||||||
pub const Server = @import("Server.zig");
|
pub const Server = @import("Server.zig");
|
||||||
|
const State = @import("State.zig");
|
||||||
|
|
||||||
/// Interface for interacting between GDB and a GBA emu
|
/// Interface for interacting between GDB and a GBA emu
|
||||||
pub const Emulator = struct {
|
pub const Emulator = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
const Signal = union(enum) {
|
||||||
|
const Kind = enum { HwBkpt, SwBkpt };
|
||||||
|
|
||||||
|
Trap: Kind,
|
||||||
|
SingleStep: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
state: State = .{},
|
||||||
|
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
|
|
||||||
readFn: *const fn (*anyopaque, u32) u8,
|
readFn: *const fn (*anyopaque, u32) u8,
|
||||||
|
@ -75,7 +85,27 @@ pub const Emulator = struct {
|
||||||
return self.cpsrFn(self.ptr);
|
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);
|
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue