+
diff --git a/page/src/components/status-indicator.tsx b/page/src/components/status-indicator.tsx
index 4bd469b5..1b627bbd 100644
--- a/page/src/components/status-indicator.tsx
+++ b/page/src/components/status-indicator.tsx
@@ -1,28 +1,48 @@
import { Badge } from "@/components/ui/badge";
import { CircleFill } from "react-bootstrap-icons";
+import { EmulationState as State } from "@/emulator";
+
+function getStateName(state: State) {
+ switch (state) {
+ case State.Stopped:
+ return "Stopped";
+ case State.Paused:
+ return "Paused";
+ case State.Running:
+ return "Running";
+ default:
+ return "";
+ }
+}
+
+function getStateColor(state: State) {
+ switch (state) {
+ case State.Stopped:
+ return "bg-orange-600";
+ case State.Paused:
+ return "bg-amber-500";
+ case State.Running:
+ return "bg-lime-600";
+ default:
+ return "";
+ }
+}
export interface StatusIndicatorProps {
- running: boolean;
+ state: State;
}
export function StatusIndicator(props: StatusIndicatorProps) {
- const getText = () => {
- return props.running ? " Running" : " Stopped";
- };
-
- const getColor = () => {
- return props.running ? "bg-lime-600" : "bg-orange-600";
- };
-
return (
- {getText()}
+ {getStateName(props.state)}
);
}
diff --git a/page/src/components/ui/button.tsx b/page/src/components/ui/button.tsx
index 2adaf00d..d0f87271 100644
--- a/page/src/components/ui/button.tsx
+++ b/page/src/components/ui/button.tsx
@@ -10,13 +10,13 @@ const buttonVariants = cva(
variants: {
variant: {
default:
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 fancy-primary",
destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80 fancy-secondary",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
diff --git a/page/src/components/ui/dropdown-menu.tsx b/page/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 00000000..fe5ed99e
--- /dev/null
+++ b/page/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,255 @@
+import * as React from "react";
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
+import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
+
+import { cn } from "@/lib/utils";
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps
) {
+ return ;
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = "default",
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+ variant?: "default" | "destructive";
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"span">) {
+ return (
+
+ );
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+}) {
+ return (
+
+ {children}
+
+
+ );
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuPortal,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuLabel,
+ DropdownMenuItem,
+ DropdownMenuCheckboxItem,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubTrigger,
+ DropdownMenuSubContent,
+};
diff --git a/page/src/components/ui/resizable.tsx b/page/src/components/ui/resizable.tsx
new file mode 100644
index 00000000..c9556348
--- /dev/null
+++ b/page/src/components/ui/resizable.tsx
@@ -0,0 +1,54 @@
+import * as React from "react";
+import { GripVerticalIcon } from "lucide-react";
+import * as ResizablePrimitive from "react-resizable-panels";
+
+import { cn } from "@/lib/utils";
+
+function ResizablePanelGroup({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function ResizablePanel({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function ResizableHandle({
+ withHandle,
+ className,
+ ...props
+}: React.ComponentProps & {
+ withHandle?: boolean;
+}) {
+ return (
+ div]:rotate-90",
+ className,
+ )}
+ {...props}
+ >
+ {withHandle && (
+
+
+
+ )}
+
+ );
+}
+
+export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
diff --git a/page/src/emulator.ts b/page/src/emulator.ts
index ce38da34..123dc823 100644
--- a/page/src/emulator.ts
+++ b/page/src/emulator.ts
@@ -1,6 +1,10 @@
import { createDefaultSettings, Settings, translateSettings } from "./settings";
import { FileEntry } from "./zip-file";
+import * as flatbuffers from "flatbuffers";
+import * as fbDebugger from "@/fb/debugger";
+import * as fbDebuggerEvent from "@/fb/debugger/event";
+
type LogHandler = (lines: string[]) => void;
export interface UserFile {
@@ -8,17 +12,61 @@ export interface UserFile {
data: ArrayBuffer;
}
+export enum EmulationState {
+ Stopped,
+ Paused,
+ Running,
+}
+
+function base64Encode(uint8Array: Uint8Array): string {
+ let binaryString = "";
+ for (let i = 0; i < uint8Array.byteLength; i++) {
+ binaryString += String.fromCharCode(uint8Array[i]);
+ }
+
+ return btoa(binaryString);
+}
+
+function base64Decode(data: string) {
+ const binaryString = atob(data);
+
+ const len = binaryString.length;
+ const bytes = new Uint8Array(len);
+
+ for (let i = 0; i < len; i++) {
+ bytes[i] = binaryString.charCodeAt(i);
+ }
+
+ return bytes;
+}
+
+function decodeEvent(data: string) {
+ const array = base64Decode(data);
+ const buffer = new flatbuffers.ByteBuffer(array);
+ const event = fbDebugger.DebugEvent.getRootAsDebugEvent(buffer);
+ return event.unpack();
+}
+
+type StateChangeHandler = (state: EmulationState) => void;
+
export class Emulator {
filesystem: FileEntry[];
logHandler: LogHandler;
+ stateChangeHandler: StateChangeHandler;
terminatePromise: Promise;
terminateResolve: (value: number | null) => void;
terminateReject: (reason?: any) => void;
worker: Worker;
+ state: EmulationState = EmulationState.Stopped;
- constructor(filesystem: FileEntry[], logHandler: LogHandler) {
+ constructor(
+ filesystem: FileEntry[],
+ logHandler: LogHandler,
+ stateChangeHandler: StateChangeHandler,
+ ) {
this.filesystem = filesystem;
this.logHandler = logHandler;
+ this.stateChangeHandler = stateChangeHandler;
this.terminateResolve = () => {};
this.terminateReject = () => {};
this.terminatePromise = new Promise((resolve, reject) => {
@@ -30,13 +78,7 @@ export class Emulator {
/*new URL('./emulator-worker.js', import.meta.url)*/ "./emulator-worker.js",
);
- this.worker.onmessage = (event: MessageEvent) => {
- if (event.data.message == "log") {
- this.logHandler(event.data.data);
- } else if (event.data.message == "end") {
- this.terminateResolve(0);
- }
- };
+ this.worker.onmessage = this._onMessage.bind(this);
}
start(
@@ -54,6 +96,7 @@ export class Emulator {
});
}
+ this._setState(EmulationState.Running);
this.worker.postMessage({
message: "run",
data: {
@@ -64,6 +107,19 @@ export class Emulator {
});
}
+ updateState() {
+ this.sendEvent(
+ new fbDebugger.DebugEventT(
+ fbDebugger.Event.GetStateRequest,
+ new fbDebugger.GetStateRequestT(),
+ ),
+ );
+ }
+
+ getState() {
+ return this.state;
+ }
+
stop() {
this.worker.terminate();
this.terminateResolve(null);
@@ -72,4 +128,80 @@ export class Emulator {
onTerminate() {
return this.terminatePromise;
}
+
+ sendEvent(event: fbDebugger.DebugEventT) {
+ const builder = new flatbuffers.Builder(1024);
+ fbDebugger.DebugEvent.finishDebugEventBuffer(builder, event.pack(builder));
+
+ const message = base64Encode(builder.asUint8Array());
+
+ this.worker.postMessage({
+ message: "event",
+ data: message,
+ });
+ }
+
+ pause() {
+ this.sendEvent(
+ new fbDebugger.DebugEventT(
+ fbDebugger.Event.PauseRequest,
+ new fbDebugger.PauseRequestT(),
+ ),
+ );
+
+ this.updateState();
+ }
+
+ resume() {
+ this.sendEvent(
+ new fbDebugger.DebugEventT(
+ fbDebugger.Event.RunRequest,
+ new fbDebugger.RunRequestT(),
+ ),
+ );
+
+ this.updateState();
+ }
+
+ _onMessage(event: MessageEvent) {
+ if (event.data.message == "log") {
+ this.logHandler(event.data.data);
+ } else if (event.data.message == "event") {
+ this._onEvent(decodeEvent(event.data.data));
+ } else if (event.data.message == "end") {
+ this._setState(EmulationState.Stopped);
+ this.terminateResolve(0);
+ }
+ }
+
+ _onEvent(event: fbDebugger.DebugEventT) {
+ switch (event.eventType) {
+ case fbDebugger.Event.GetStateResponse:
+ this._handle_state_response(
+ event.event as fbDebugger.GetStateResponseT,
+ );
+ break;
+ }
+ }
+
+ _setState(state: EmulationState) {
+ this.state = state;
+ this.stateChangeHandler(this.state);
+ }
+
+ _handle_state_response(response: fbDebugger.GetStateResponseT) {
+ switch (response.state) {
+ case fbDebugger.State.None:
+ this._setState(EmulationState.Stopped);
+ break;
+
+ case fbDebugger.State.Paused:
+ this._setState(EmulationState.Paused);
+ break;
+
+ case fbDebugger.State.Running:
+ this._setState(EmulationState.Running);
+ break;
+ }
+ }
}
diff --git a/page/src/fb/debugger.ts b/page/src/fb/debugger.ts
new file mode 100644
index 00000000..c5f2befb
--- /dev/null
+++ b/page/src/fb/debugger.ts
@@ -0,0 +1,19 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+export { DebugEvent, DebugEventT } from './debugger/debug-event.js';
+export { Event } from './debugger/event.js';
+export { GetStateRequest, GetStateRequestT } from './debugger/get-state-request.js';
+export { GetStateResponse, GetStateResponseT } from './debugger/get-state-response.js';
+export { PauseRequest, PauseRequestT } from './debugger/pause-request.js';
+export { ReadMemoryRequest, ReadMemoryRequestT } from './debugger/read-memory-request.js';
+export { ReadMemoryResponse, ReadMemoryResponseT } from './debugger/read-memory-response.js';
+export { ReadRegisterRequest, ReadRegisterRequestT } from './debugger/read-register-request.js';
+export { ReadRegisterResponse, ReadRegisterResponseT } from './debugger/read-register-response.js';
+export { RunRequest, RunRequestT } from './debugger/run-request.js';
+export { State } from './debugger/state.js';
+export { WriteMemoryRequest, WriteMemoryRequestT } from './debugger/write-memory-request.js';
+export { WriteMemoryResponse, WriteMemoryResponseT } from './debugger/write-memory-response.js';
+export { WriteRegisterRequest, WriteRegisterRequestT } from './debugger/write-register-request.js';
+export { WriteRegisterResponse, WriteRegisterResponseT } from './debugger/write-register-response.js';
diff --git a/page/src/fb/debugger/debug-event.ts b/page/src/fb/debugger/debug-event.ts
new file mode 100644
index 00000000..9be99bfa
--- /dev/null
+++ b/page/src/fb/debugger/debug-event.ts
@@ -0,0 +1,119 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+import { Event, unionToEvent, unionListToEvent } from '../debugger/event.js';
+import { GetStateRequest, GetStateRequestT } from '../debugger/get-state-request.js';
+import { GetStateResponse, GetStateResponseT } from '../debugger/get-state-response.js';
+import { PauseRequest, PauseRequestT } from '../debugger/pause-request.js';
+import { ReadMemoryRequest, ReadMemoryRequestT } from '../debugger/read-memory-request.js';
+import { ReadMemoryResponse, ReadMemoryResponseT } from '../debugger/read-memory-response.js';
+import { ReadRegisterRequest, ReadRegisterRequestT } from '../debugger/read-register-request.js';
+import { ReadRegisterResponse, ReadRegisterResponseT } from '../debugger/read-register-response.js';
+import { RunRequest, RunRequestT } from '../debugger/run-request.js';
+import { WriteMemoryRequest, WriteMemoryRequestT } from '../debugger/write-memory-request.js';
+import { WriteMemoryResponse, WriteMemoryResponseT } from '../debugger/write-memory-response.js';
+import { WriteRegisterRequest, WriteRegisterRequestT } from '../debugger/write-register-request.js';
+import { WriteRegisterResponse, WriteRegisterResponseT } from '../debugger/write-register-response.js';
+
+
+export class DebugEvent implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):DebugEvent {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsDebugEvent(bb:flatbuffers.ByteBuffer, obj?:DebugEvent):DebugEvent {
+ return (obj || new DebugEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsDebugEvent(bb:flatbuffers.ByteBuffer, obj?:DebugEvent):DebugEvent {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new DebugEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+eventType():Event {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint8(this.bb_pos + offset) : Event.NONE;
+}
+
+event(obj:any):any|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
+}
+
+static startDebugEvent(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addEventType(builder:flatbuffers.Builder, eventType:Event) {
+ builder.addFieldInt8(0, eventType, Event.NONE);
+}
+
+static addEvent(builder:flatbuffers.Builder, eventOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, eventOffset, 0);
+}
+
+static endDebugEvent(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static finishDebugEventBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset);
+}
+
+static finishSizePrefixedDebugEventBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset, undefined, true);
+}
+
+static createDebugEvent(builder:flatbuffers.Builder, eventType:Event, eventOffset:flatbuffers.Offset):flatbuffers.Offset {
+ DebugEvent.startDebugEvent(builder);
+ DebugEvent.addEventType(builder, eventType);
+ DebugEvent.addEvent(builder, eventOffset);
+ return DebugEvent.endDebugEvent(builder);
+}
+
+unpack(): DebugEventT {
+ return new DebugEventT(
+ this.eventType(),
+ (() => {
+ const temp = unionToEvent(this.eventType(), this.event.bind(this));
+ if(temp === null) { return null; }
+ return temp.unpack()
+ })()
+ );
+}
+
+
+unpackTo(_o: DebugEventT): void {
+ _o.eventType = this.eventType();
+ _o.event = (() => {
+ const temp = unionToEvent(this.eventType(), this.event.bind(this));
+ if(temp === null) { return null; }
+ return temp.unpack()
+ })();
+}
+}
+
+export class DebugEventT implements flatbuffers.IGeneratedObject {
+constructor(
+ public eventType: Event = Event.NONE,
+ public event: GetStateRequestT|GetStateResponseT|PauseRequestT|ReadMemoryRequestT|ReadMemoryResponseT|ReadRegisterRequestT|ReadRegisterResponseT|RunRequestT|WriteMemoryRequestT|WriteMemoryResponseT|WriteRegisterRequestT|WriteRegisterResponseT|null = null
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ const event = builder.createObjectOffset(this.event);
+
+ return DebugEvent.createDebugEvent(builder,
+ this.eventType,
+ event
+ );
+}
+}
diff --git a/page/src/fb/debugger/event.ts b/page/src/fb/debugger/event.ts
new file mode 100644
index 00000000..fde2a752
--- /dev/null
+++ b/page/src/fb/debugger/event.ts
@@ -0,0 +1,78 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import { GetStateRequest, GetStateRequestT } from '../debugger/get-state-request.js';
+import { GetStateResponse, GetStateResponseT } from '../debugger/get-state-response.js';
+import { PauseRequest, PauseRequestT } from '../debugger/pause-request.js';
+import { ReadMemoryRequest, ReadMemoryRequestT } from '../debugger/read-memory-request.js';
+import { ReadMemoryResponse, ReadMemoryResponseT } from '../debugger/read-memory-response.js';
+import { ReadRegisterRequest, ReadRegisterRequestT } from '../debugger/read-register-request.js';
+import { ReadRegisterResponse, ReadRegisterResponseT } from '../debugger/read-register-response.js';
+import { RunRequest, RunRequestT } from '../debugger/run-request.js';
+import { WriteMemoryRequest, WriteMemoryRequestT } from '../debugger/write-memory-request.js';
+import { WriteMemoryResponse, WriteMemoryResponseT } from '../debugger/write-memory-response.js';
+import { WriteRegisterRequest, WriteRegisterRequestT } from '../debugger/write-register-request.js';
+import { WriteRegisterResponse, WriteRegisterResponseT } from '../debugger/write-register-response.js';
+
+
+export enum Event {
+ NONE = 0,
+ PauseRequest = 1,
+ RunRequest = 2,
+ GetStateRequest = 3,
+ GetStateResponse = 4,
+ WriteMemoryRequest = 5,
+ WriteMemoryResponse = 6,
+ ReadMemoryRequest = 7,
+ ReadMemoryResponse = 8,
+ WriteRegisterRequest = 9,
+ WriteRegisterResponse = 10,
+ ReadRegisterRequest = 11,
+ ReadRegisterResponse = 12
+}
+
+export function unionToEvent(
+ type: Event,
+ accessor: (obj:GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null
+): GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
+ switch(Event[type]) {
+ case 'NONE': return null;
+ case 'PauseRequest': return accessor(new PauseRequest())! as PauseRequest;
+ case 'RunRequest': return accessor(new RunRequest())! as RunRequest;
+ case 'GetStateRequest': return accessor(new GetStateRequest())! as GetStateRequest;
+ case 'GetStateResponse': return accessor(new GetStateResponse())! as GetStateResponse;
+ case 'WriteMemoryRequest': return accessor(new WriteMemoryRequest())! as WriteMemoryRequest;
+ case 'WriteMemoryResponse': return accessor(new WriteMemoryResponse())! as WriteMemoryResponse;
+ case 'ReadMemoryRequest': return accessor(new ReadMemoryRequest())! as ReadMemoryRequest;
+ case 'ReadMemoryResponse': return accessor(new ReadMemoryResponse())! as ReadMemoryResponse;
+ case 'WriteRegisterRequest': return accessor(new WriteRegisterRequest())! as WriteRegisterRequest;
+ case 'WriteRegisterResponse': return accessor(new WriteRegisterResponse())! as WriteRegisterResponse;
+ case 'ReadRegisterRequest': return accessor(new ReadRegisterRequest())! as ReadRegisterRequest;
+ case 'ReadRegisterResponse': return accessor(new ReadRegisterResponse())! as ReadRegisterResponse;
+ default: return null;
+ }
+}
+
+export function unionListToEvent(
+ type: Event,
+ accessor: (index: number, obj:GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse) => GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null,
+ index: number
+): GetStateRequest|GetStateResponse|PauseRequest|ReadMemoryRequest|ReadMemoryResponse|ReadRegisterRequest|ReadRegisterResponse|RunRequest|WriteMemoryRequest|WriteMemoryResponse|WriteRegisterRequest|WriteRegisterResponse|null {
+ switch(Event[type]) {
+ case 'NONE': return null;
+ case 'PauseRequest': return accessor(index, new PauseRequest())! as PauseRequest;
+ case 'RunRequest': return accessor(index, new RunRequest())! as RunRequest;
+ case 'GetStateRequest': return accessor(index, new GetStateRequest())! as GetStateRequest;
+ case 'GetStateResponse': return accessor(index, new GetStateResponse())! as GetStateResponse;
+ case 'WriteMemoryRequest': return accessor(index, new WriteMemoryRequest())! as WriteMemoryRequest;
+ case 'WriteMemoryResponse': return accessor(index, new WriteMemoryResponse())! as WriteMemoryResponse;
+ case 'ReadMemoryRequest': return accessor(index, new ReadMemoryRequest())! as ReadMemoryRequest;
+ case 'ReadMemoryResponse': return accessor(index, new ReadMemoryResponse())! as ReadMemoryResponse;
+ case 'WriteRegisterRequest': return accessor(index, new WriteRegisterRequest())! as WriteRegisterRequest;
+ case 'WriteRegisterResponse': return accessor(index, new WriteRegisterResponse())! as WriteRegisterResponse;
+ case 'ReadRegisterRequest': return accessor(index, new ReadRegisterRequest())! as ReadRegisterRequest;
+ case 'ReadRegisterResponse': return accessor(index, new ReadRegisterResponse())! as ReadRegisterResponse;
+ default: return null;
+ }
+}
diff --git a/page/src/fb/debugger/get-state-request.ts b/page/src/fb/debugger/get-state-request.ts
new file mode 100644
index 00000000..8ec9ff10
--- /dev/null
+++ b/page/src/fb/debugger/get-state-request.ts
@@ -0,0 +1,56 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class GetStateRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):GetStateRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsGetStateRequest(bb:flatbuffers.ByteBuffer, obj?:GetStateRequest):GetStateRequest {
+ return (obj || new GetStateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsGetStateRequest(bb:flatbuffers.ByteBuffer, obj?:GetStateRequest):GetStateRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new GetStateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static startGetStateRequest(builder:flatbuffers.Builder) {
+ builder.startObject(0);
+}
+
+static endGetStateRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createGetStateRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ GetStateRequest.startGetStateRequest(builder);
+ return GetStateRequest.endGetStateRequest(builder);
+}
+
+unpack(): GetStateRequestT {
+ return new GetStateRequestT();
+}
+
+
+unpackTo(_o: GetStateRequestT): void {}
+}
+
+export class GetStateRequestT implements flatbuffers.IGeneratedObject {
+constructor(){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return GetStateRequest.createGetStateRequest(builder);
+}
+}
diff --git a/page/src/fb/debugger/get-state-response.ts b/page/src/fb/debugger/get-state-response.ts
new file mode 100644
index 00000000..f429791b
--- /dev/null
+++ b/page/src/fb/debugger/get-state-response.ts
@@ -0,0 +1,86 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+import { State } from '../debugger/state.js';
+
+
+export class GetStateResponse implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):GetStateResponse {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsGetStateResponse(bb:flatbuffers.ByteBuffer, obj?:GetStateResponse):GetStateResponse {
+ return (obj || new GetStateResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsGetStateResponse(bb:flatbuffers.ByteBuffer, obj?:GetStateResponse):GetStateResponse {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new GetStateResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+state():State {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : State.None;
+}
+
+mutate_state(value:State):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+static startGetStateResponse(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+}
+
+static addState(builder:flatbuffers.Builder, state:State) {
+ builder.addFieldInt32(0, state, State.None);
+}
+
+static endGetStateResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createGetStateResponse(builder:flatbuffers.Builder, state:State):flatbuffers.Offset {
+ GetStateResponse.startGetStateResponse(builder);
+ GetStateResponse.addState(builder, state);
+ return GetStateResponse.endGetStateResponse(builder);
+}
+
+unpack(): GetStateResponseT {
+ return new GetStateResponseT(
+ this.state()
+ );
+}
+
+
+unpackTo(_o: GetStateResponseT): void {
+ _o.state = this.state();
+}
+}
+
+export class GetStateResponseT implements flatbuffers.IGeneratedObject {
+constructor(
+ public state: State = State.None
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return GetStateResponse.createGetStateResponse(builder,
+ this.state
+ );
+}
+}
diff --git a/page/src/fb/debugger/pause-request.ts b/page/src/fb/debugger/pause-request.ts
new file mode 100644
index 00000000..1aa4564c
--- /dev/null
+++ b/page/src/fb/debugger/pause-request.ts
@@ -0,0 +1,56 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class PauseRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):PauseRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsPauseRequest(bb:flatbuffers.ByteBuffer, obj?:PauseRequest):PauseRequest {
+ return (obj || new PauseRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsPauseRequest(bb:flatbuffers.ByteBuffer, obj?:PauseRequest):PauseRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new PauseRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static startPauseRequest(builder:flatbuffers.Builder) {
+ builder.startObject(0);
+}
+
+static endPauseRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createPauseRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ PauseRequest.startPauseRequest(builder);
+ return PauseRequest.endPauseRequest(builder);
+}
+
+unpack(): PauseRequestT {
+ return new PauseRequestT();
+}
+
+
+unpackTo(_o: PauseRequestT): void {}
+}
+
+export class PauseRequestT implements flatbuffers.IGeneratedObject {
+constructor(){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return PauseRequest.createPauseRequest(builder);
+}
+}
diff --git a/page/src/fb/debugger/read-memory-request.ts b/page/src/fb/debugger/read-memory-request.ts
new file mode 100644
index 00000000..5779ac60
--- /dev/null
+++ b/page/src/fb/debugger/read-memory-request.ts
@@ -0,0 +1,110 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class ReadMemoryRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):ReadMemoryRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsReadMemoryRequest(bb:flatbuffers.ByteBuffer, obj?:ReadMemoryRequest):ReadMemoryRequest {
+ return (obj || new ReadMemoryRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsReadMemoryRequest(bb:flatbuffers.ByteBuffer, obj?:ReadMemoryRequest):ReadMemoryRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new ReadMemoryRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+address():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_address(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+size():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_size(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+static startReadMemoryRequest(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addAddress(builder:flatbuffers.Builder, address:bigint) {
+ builder.addFieldInt64(0, address, BigInt('0'));
+}
+
+static addSize(builder:flatbuffers.Builder, size:number) {
+ builder.addFieldInt32(1, size, 0);
+}
+
+static endReadMemoryRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createReadMemoryRequest(builder:flatbuffers.Builder, address:bigint, size:number):flatbuffers.Offset {
+ ReadMemoryRequest.startReadMemoryRequest(builder);
+ ReadMemoryRequest.addAddress(builder, address);
+ ReadMemoryRequest.addSize(builder, size);
+ return ReadMemoryRequest.endReadMemoryRequest(builder);
+}
+
+unpack(): ReadMemoryRequestT {
+ return new ReadMemoryRequestT(
+ this.address(),
+ this.size()
+ );
+}
+
+
+unpackTo(_o: ReadMemoryRequestT): void {
+ _o.address = this.address();
+ _o.size = this.size();
+}
+}
+
+export class ReadMemoryRequestT implements flatbuffers.IGeneratedObject {
+constructor(
+ public address: bigint = BigInt('0'),
+ public size: number = 0
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return ReadMemoryRequest.createReadMemoryRequest(builder,
+ this.address,
+ this.size
+ );
+}
+}
diff --git a/page/src/fb/debugger/read-memory-response.ts b/page/src/fb/debugger/read-memory-response.ts
new file mode 100644
index 00000000..9e0b38c1
--- /dev/null
+++ b/page/src/fb/debugger/read-memory-response.ts
@@ -0,0 +1,123 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class ReadMemoryResponse implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):ReadMemoryResponse {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsReadMemoryResponse(bb:flatbuffers.ByteBuffer, obj?:ReadMemoryResponse):ReadMemoryResponse {
+ return (obj || new ReadMemoryResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsReadMemoryResponse(bb:flatbuffers.ByteBuffer, obj?:ReadMemoryResponse):ReadMemoryResponse {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new ReadMemoryResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+address():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_address(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+data(index: number):number|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+}
+
+dataLength():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+}
+
+dataArray():Uint8Array|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+}
+
+static startReadMemoryResponse(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addAddress(builder:flatbuffers.Builder, address:bigint) {
+ builder.addFieldInt64(0, address, BigInt('0'));
+}
+
+static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, dataOffset, 0);
+}
+
+static createDataVector(builder:flatbuffers.Builder, data:number[]|Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (let i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]!);
+ }
+ return builder.endVector();
+}
+
+static startDataVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+}
+
+static endReadMemoryResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createReadMemoryResponse(builder:flatbuffers.Builder, address:bigint, dataOffset:flatbuffers.Offset):flatbuffers.Offset {
+ ReadMemoryResponse.startReadMemoryResponse(builder);
+ ReadMemoryResponse.addAddress(builder, address);
+ ReadMemoryResponse.addData(builder, dataOffset);
+ return ReadMemoryResponse.endReadMemoryResponse(builder);
+}
+
+unpack(): ReadMemoryResponseT {
+ return new ReadMemoryResponseT(
+ this.address(),
+ this.bb!.createScalarList(this.data.bind(this), this.dataLength())
+ );
+}
+
+
+unpackTo(_o: ReadMemoryResponseT): void {
+ _o.address = this.address();
+ _o.data = this.bb!.createScalarList(this.data.bind(this), this.dataLength());
+}
+}
+
+export class ReadMemoryResponseT implements flatbuffers.IGeneratedObject {
+constructor(
+ public address: bigint = BigInt('0'),
+ public data: (number)[] = []
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ const data = ReadMemoryResponse.createDataVector(builder, this.data);
+
+ return ReadMemoryResponse.createReadMemoryResponse(builder,
+ this.address,
+ data
+ );
+}
+}
diff --git a/page/src/fb/debugger/read-register-request.ts b/page/src/fb/debugger/read-register-request.ts
new file mode 100644
index 00000000..71980ad8
--- /dev/null
+++ b/page/src/fb/debugger/read-register-request.ts
@@ -0,0 +1,85 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class ReadRegisterRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):ReadRegisterRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsReadRegisterRequest(bb:flatbuffers.ByteBuffer, obj?:ReadRegisterRequest):ReadRegisterRequest {
+ return (obj || new ReadRegisterRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsReadRegisterRequest(bb:flatbuffers.ByteBuffer, obj?:ReadRegisterRequest):ReadRegisterRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new ReadRegisterRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+register():number {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_register(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+static startReadRegisterRequest(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+}
+
+static addRegister(builder:flatbuffers.Builder, register:number) {
+ builder.addFieldInt32(0, register, 0);
+}
+
+static endReadRegisterRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createReadRegisterRequest(builder:flatbuffers.Builder, register:number):flatbuffers.Offset {
+ ReadRegisterRequest.startReadRegisterRequest(builder);
+ ReadRegisterRequest.addRegister(builder, register);
+ return ReadRegisterRequest.endReadRegisterRequest(builder);
+}
+
+unpack(): ReadRegisterRequestT {
+ return new ReadRegisterRequestT(
+ this.register()
+ );
+}
+
+
+unpackTo(_o: ReadRegisterRequestT): void {
+ _o.register = this.register();
+}
+}
+
+export class ReadRegisterRequestT implements flatbuffers.IGeneratedObject {
+constructor(
+ public register: number = 0
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return ReadRegisterRequest.createReadRegisterRequest(builder,
+ this.register
+ );
+}
+}
diff --git a/page/src/fb/debugger/read-register-response.ts b/page/src/fb/debugger/read-register-response.ts
new file mode 100644
index 00000000..9d2d6c86
--- /dev/null
+++ b/page/src/fb/debugger/read-register-response.ts
@@ -0,0 +1,123 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class ReadRegisterResponse implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):ReadRegisterResponse {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsReadRegisterResponse(bb:flatbuffers.ByteBuffer, obj?:ReadRegisterResponse):ReadRegisterResponse {
+ return (obj || new ReadRegisterResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsReadRegisterResponse(bb:flatbuffers.ByteBuffer, obj?:ReadRegisterResponse):ReadRegisterResponse {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new ReadRegisterResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+register():number {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_register(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+data(index: number):number|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+}
+
+dataLength():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+}
+
+dataArray():Uint8Array|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+}
+
+static startReadRegisterResponse(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addRegister(builder:flatbuffers.Builder, register:number) {
+ builder.addFieldInt32(0, register, 0);
+}
+
+static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, dataOffset, 0);
+}
+
+static createDataVector(builder:flatbuffers.Builder, data:number[]|Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (let i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]!);
+ }
+ return builder.endVector();
+}
+
+static startDataVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+}
+
+static endReadRegisterResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createReadRegisterResponse(builder:flatbuffers.Builder, register:number, dataOffset:flatbuffers.Offset):flatbuffers.Offset {
+ ReadRegisterResponse.startReadRegisterResponse(builder);
+ ReadRegisterResponse.addRegister(builder, register);
+ ReadRegisterResponse.addData(builder, dataOffset);
+ return ReadRegisterResponse.endReadRegisterResponse(builder);
+}
+
+unpack(): ReadRegisterResponseT {
+ return new ReadRegisterResponseT(
+ this.register(),
+ this.bb!.createScalarList(this.data.bind(this), this.dataLength())
+ );
+}
+
+
+unpackTo(_o: ReadRegisterResponseT): void {
+ _o.register = this.register();
+ _o.data = this.bb!.createScalarList(this.data.bind(this), this.dataLength());
+}
+}
+
+export class ReadRegisterResponseT implements flatbuffers.IGeneratedObject {
+constructor(
+ public register: number = 0,
+ public data: (number)[] = []
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ const data = ReadRegisterResponse.createDataVector(builder, this.data);
+
+ return ReadRegisterResponse.createReadRegisterResponse(builder,
+ this.register,
+ data
+ );
+}
+}
diff --git a/page/src/fb/debugger/run-request.ts b/page/src/fb/debugger/run-request.ts
new file mode 100644
index 00000000..d974c1ae
--- /dev/null
+++ b/page/src/fb/debugger/run-request.ts
@@ -0,0 +1,85 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class RunRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):RunRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsRunRequest(bb:flatbuffers.ByteBuffer, obj?:RunRequest):RunRequest {
+ return (obj || new RunRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsRunRequest(bb:flatbuffers.ByteBuffer, obj?:RunRequest):RunRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new RunRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+singleStep():boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
+}
+
+mutate_single_step(value:boolean):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, +value);
+ return true;
+}
+
+static startRunRequest(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+}
+
+static addSingleStep(builder:flatbuffers.Builder, singleStep:boolean) {
+ builder.addFieldInt8(0, +singleStep, +false);
+}
+
+static endRunRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createRunRequest(builder:flatbuffers.Builder, singleStep:boolean):flatbuffers.Offset {
+ RunRequest.startRunRequest(builder);
+ RunRequest.addSingleStep(builder, singleStep);
+ return RunRequest.endRunRequest(builder);
+}
+
+unpack(): RunRequestT {
+ return new RunRequestT(
+ this.singleStep()
+ );
+}
+
+
+unpackTo(_o: RunRequestT): void {
+ _o.singleStep = this.singleStep();
+}
+}
+
+export class RunRequestT implements flatbuffers.IGeneratedObject {
+constructor(
+ public singleStep: boolean = false
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return RunRequest.createRunRequest(builder,
+ this.singleStep
+ );
+}
+}
diff --git a/page/src/fb/debugger/state.ts b/page/src/fb/debugger/state.ts
new file mode 100644
index 00000000..01be2fac
--- /dev/null
+++ b/page/src/fb/debugger/state.ts
@@ -0,0 +1,9 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+export enum State {
+ None = 0,
+ Running = 1,
+ Paused = 2
+}
diff --git a/page/src/fb/debugger/write-memory-request.ts b/page/src/fb/debugger/write-memory-request.ts
new file mode 100644
index 00000000..3d669553
--- /dev/null
+++ b/page/src/fb/debugger/write-memory-request.ts
@@ -0,0 +1,123 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class WriteMemoryRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):WriteMemoryRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsWriteMemoryRequest(bb:flatbuffers.ByteBuffer, obj?:WriteMemoryRequest):WriteMemoryRequest {
+ return (obj || new WriteMemoryRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsWriteMemoryRequest(bb:flatbuffers.ByteBuffer, obj?:WriteMemoryRequest):WriteMemoryRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new WriteMemoryRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+address():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_address(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+data(index: number):number|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+}
+
+dataLength():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+}
+
+dataArray():Uint8Array|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+}
+
+static startWriteMemoryRequest(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addAddress(builder:flatbuffers.Builder, address:bigint) {
+ builder.addFieldInt64(0, address, BigInt('0'));
+}
+
+static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, dataOffset, 0);
+}
+
+static createDataVector(builder:flatbuffers.Builder, data:number[]|Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (let i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]!);
+ }
+ return builder.endVector();
+}
+
+static startDataVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+}
+
+static endWriteMemoryRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createWriteMemoryRequest(builder:flatbuffers.Builder, address:bigint, dataOffset:flatbuffers.Offset):flatbuffers.Offset {
+ WriteMemoryRequest.startWriteMemoryRequest(builder);
+ WriteMemoryRequest.addAddress(builder, address);
+ WriteMemoryRequest.addData(builder, dataOffset);
+ return WriteMemoryRequest.endWriteMemoryRequest(builder);
+}
+
+unpack(): WriteMemoryRequestT {
+ return new WriteMemoryRequestT(
+ this.address(),
+ this.bb!.createScalarList(this.data.bind(this), this.dataLength())
+ );
+}
+
+
+unpackTo(_o: WriteMemoryRequestT): void {
+ _o.address = this.address();
+ _o.data = this.bb!.createScalarList(this.data.bind(this), this.dataLength());
+}
+}
+
+export class WriteMemoryRequestT implements flatbuffers.IGeneratedObject {
+constructor(
+ public address: bigint = BigInt('0'),
+ public data: (number)[] = []
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ const data = WriteMemoryRequest.createDataVector(builder, this.data);
+
+ return WriteMemoryRequest.createWriteMemoryRequest(builder,
+ this.address,
+ data
+ );
+}
+}
diff --git a/page/src/fb/debugger/write-memory-response.ts b/page/src/fb/debugger/write-memory-response.ts
new file mode 100644
index 00000000..700f9444
--- /dev/null
+++ b/page/src/fb/debugger/write-memory-response.ts
@@ -0,0 +1,135 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class WriteMemoryResponse implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):WriteMemoryResponse {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsWriteMemoryResponse(bb:flatbuffers.ByteBuffer, obj?:WriteMemoryResponse):WriteMemoryResponse {
+ return (obj || new WriteMemoryResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsWriteMemoryResponse(bb:flatbuffers.ByteBuffer, obj?:WriteMemoryResponse):WriteMemoryResponse {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new WriteMemoryResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+address():bigint {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
+}
+
+mutate_address(value:bigint):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+}
+
+size():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_size(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+success():boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
+}
+
+mutate_success(value:boolean):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, +value);
+ return true;
+}
+
+static startWriteMemoryResponse(builder:flatbuffers.Builder) {
+ builder.startObject(3);
+}
+
+static addAddress(builder:flatbuffers.Builder, address:bigint) {
+ builder.addFieldInt64(0, address, BigInt('0'));
+}
+
+static addSize(builder:flatbuffers.Builder, size:number) {
+ builder.addFieldInt32(1, size, 0);
+}
+
+static addSuccess(builder:flatbuffers.Builder, success:boolean) {
+ builder.addFieldInt8(2, +success, +false);
+}
+
+static endWriteMemoryResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createWriteMemoryResponse(builder:flatbuffers.Builder, address:bigint, size:number, success:boolean):flatbuffers.Offset {
+ WriteMemoryResponse.startWriteMemoryResponse(builder);
+ WriteMemoryResponse.addAddress(builder, address);
+ WriteMemoryResponse.addSize(builder, size);
+ WriteMemoryResponse.addSuccess(builder, success);
+ return WriteMemoryResponse.endWriteMemoryResponse(builder);
+}
+
+unpack(): WriteMemoryResponseT {
+ return new WriteMemoryResponseT(
+ this.address(),
+ this.size(),
+ this.success()
+ );
+}
+
+
+unpackTo(_o: WriteMemoryResponseT): void {
+ _o.address = this.address();
+ _o.size = this.size();
+ _o.success = this.success();
+}
+}
+
+export class WriteMemoryResponseT implements flatbuffers.IGeneratedObject {
+constructor(
+ public address: bigint = BigInt('0'),
+ public size: number = 0,
+ public success: boolean = false
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return WriteMemoryResponse.createWriteMemoryResponse(builder,
+ this.address,
+ this.size,
+ this.success
+ );
+}
+}
diff --git a/page/src/fb/debugger/write-register-request.ts b/page/src/fb/debugger/write-register-request.ts
new file mode 100644
index 00000000..6e81a3f8
--- /dev/null
+++ b/page/src/fb/debugger/write-register-request.ts
@@ -0,0 +1,123 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class WriteRegisterRequest implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):WriteRegisterRequest {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsWriteRegisterRequest(bb:flatbuffers.ByteBuffer, obj?:WriteRegisterRequest):WriteRegisterRequest {
+ return (obj || new WriteRegisterRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsWriteRegisterRequest(bb:flatbuffers.ByteBuffer, obj?:WriteRegisterRequest):WriteRegisterRequest {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new WriteRegisterRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+register():number {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_register(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+data(index: number):number|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+}
+
+dataLength():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+}
+
+dataArray():Uint8Array|null {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+}
+
+static startWriteRegisterRequest(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+}
+
+static addRegister(builder:flatbuffers.Builder, register:number) {
+ builder.addFieldInt32(0, register, 0);
+}
+
+static addData(builder:flatbuffers.Builder, dataOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, dataOffset, 0);
+}
+
+static createDataVector(builder:flatbuffers.Builder, data:number[]|Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (let i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]!);
+ }
+ return builder.endVector();
+}
+
+static startDataVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+}
+
+static endWriteRegisterRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createWriteRegisterRequest(builder:flatbuffers.Builder, register:number, dataOffset:flatbuffers.Offset):flatbuffers.Offset {
+ WriteRegisterRequest.startWriteRegisterRequest(builder);
+ WriteRegisterRequest.addRegister(builder, register);
+ WriteRegisterRequest.addData(builder, dataOffset);
+ return WriteRegisterRequest.endWriteRegisterRequest(builder);
+}
+
+unpack(): WriteRegisterRequestT {
+ return new WriteRegisterRequestT(
+ this.register(),
+ this.bb!.createScalarList(this.data.bind(this), this.dataLength())
+ );
+}
+
+
+unpackTo(_o: WriteRegisterRequestT): void {
+ _o.register = this.register();
+ _o.data = this.bb!.createScalarList(this.data.bind(this), this.dataLength());
+}
+}
+
+export class WriteRegisterRequestT implements flatbuffers.IGeneratedObject {
+constructor(
+ public register: number = 0,
+ public data: (number)[] = []
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ const data = WriteRegisterRequest.createDataVector(builder, this.data);
+
+ return WriteRegisterRequest.createWriteRegisterRequest(builder,
+ this.register,
+ data
+ );
+}
+}
diff --git a/page/src/fb/debugger/write-register-response.ts b/page/src/fb/debugger/write-register-response.ts
new file mode 100644
index 00000000..839edc55
--- /dev/null
+++ b/page/src/fb/debugger/write-register-response.ts
@@ -0,0 +1,135 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+import * as flatbuffers from 'flatbuffers';
+
+
+
+export class WriteRegisterResponse implements flatbuffers.IUnpackableObject {
+ bb: flatbuffers.ByteBuffer|null = null;
+ bb_pos = 0;
+ __init(i:number, bb:flatbuffers.ByteBuffer):WriteRegisterResponse {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+}
+
+static getRootAsWriteRegisterResponse(bb:flatbuffers.ByteBuffer, obj?:WriteRegisterResponse):WriteRegisterResponse {
+ return (obj || new WriteRegisterResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+static getSizePrefixedRootAsWriteRegisterResponse(bb:flatbuffers.ByteBuffer, obj?:WriteRegisterResponse):WriteRegisterResponse {
+ bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
+ return (obj || new WriteRegisterResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+}
+
+register():number {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_register(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+size():number {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+}
+
+mutate_size(value:number):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+}
+
+success():boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
+}
+
+mutate_success(value:boolean):boolean {
+ const offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, +value);
+ return true;
+}
+
+static startWriteRegisterResponse(builder:flatbuffers.Builder) {
+ builder.startObject(3);
+}
+
+static addRegister(builder:flatbuffers.Builder, register:number) {
+ builder.addFieldInt32(0, register, 0);
+}
+
+static addSize(builder:flatbuffers.Builder, size:number) {
+ builder.addFieldInt32(1, size, 0);
+}
+
+static addSuccess(builder:flatbuffers.Builder, success:boolean) {
+ builder.addFieldInt8(2, +success, +false);
+}
+
+static endWriteRegisterResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
+ const offset = builder.endObject();
+ return offset;
+}
+
+static createWriteRegisterResponse(builder:flatbuffers.Builder, register:number, size:number, success:boolean):flatbuffers.Offset {
+ WriteRegisterResponse.startWriteRegisterResponse(builder);
+ WriteRegisterResponse.addRegister(builder, register);
+ WriteRegisterResponse.addSize(builder, size);
+ WriteRegisterResponse.addSuccess(builder, success);
+ return WriteRegisterResponse.endWriteRegisterResponse(builder);
+}
+
+unpack(): WriteRegisterResponseT {
+ return new WriteRegisterResponseT(
+ this.register(),
+ this.size(),
+ this.success()
+ );
+}
+
+
+unpackTo(_o: WriteRegisterResponseT): void {
+ _o.register = this.register();
+ _o.size = this.size();
+ _o.success = this.success();
+}
+}
+
+export class WriteRegisterResponseT implements flatbuffers.IGeneratedObject {
+constructor(
+ public register: number = 0,
+ public size: number = 0,
+ public success: boolean = false
+){}
+
+
+pack(builder:flatbuffers.Builder): flatbuffers.Offset {
+ return WriteRegisterResponse.createWriteRegisterResponse(builder,
+ this.register,
+ this.size,
+ this.success
+ );
+}
+}
diff --git a/page/src/fb/events.ts b/page/src/fb/events.ts
new file mode 100644
index 00000000..f21dacb2
--- /dev/null
+++ b/page/src/fb/events.ts
@@ -0,0 +1,5 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
+
+export * as Debugger from './debugger.js';
diff --git a/page/tsconfig.app.json b/page/tsconfig.app.json
index 9f0a5124..0f468d74 100644
--- a/page/tsconfig.app.json
+++ b/page/tsconfig.app.json
@@ -17,8 +17,8 @@
/* Linting */
"strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"baseUrl": ".",
diff --git a/src/.clang-format-ignore b/src/.clang-format-ignore
new file mode 100644
index 00000000..9d3995d3
--- /dev/null
+++ b/src/.clang-format-ignore
@@ -0,0 +1 @@
+**/*.hxx
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4492d05c..870f20e1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,6 +9,7 @@ momo_targets_set_folder("backends" ${BACKEND_TARGETS})
if (NOT MOMO_BUILD_AS_LIBRARY)
add_subdirectory(analyzer)
+ add_subdirectory(debugger)
add_subdirectory(fuzzing-engine)
add_subdirectory(fuzzer)
add_subdirectory(windows-emulator-test)
diff --git a/src/analyzer/CMakeLists.txt b/src/analyzer/CMakeLists.txt
index 0cfffb61..036e614e 100644
--- a/src/analyzer/CMakeLists.txt
+++ b/src/analyzer/CMakeLists.txt
@@ -16,6 +16,7 @@ endif()
target_link_libraries(analyzer PRIVATE
reflect
+ debugger
windows-emulator
windows-gdb-stub
)
diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp
index ec943fa0..b95bd429 100644
--- a/src/analyzer/main.cpp
+++ b/src/analyzer/main.cpp
@@ -6,6 +6,10 @@
#include "object_watching.hpp"
#include "snapshot.hpp"
+#ifdef OS_EMSCRIPTEN
+#include
+#endif
+
#include
#include
@@ -249,6 +253,14 @@ namespace
bool run(const analysis_options& options, const std::span args)
{
const auto win_emu = setup_emulator(options, args);
+
+#ifdef OS_EMSCRIPTEN
+ win_emu->callbacks.on_thread_switch = [&] {
+ debugger::event_context c{.win_emu = *win_emu};
+ debugger::handle_events(c); //
+ };
+#endif
+
win_emu->log.log("Using emulator: %s\n", win_emu->emu().get_name().c_str());
(void)&watch_system_objects;
diff --git a/src/debugger/CMakeLists.txt b/src/debugger/CMakeLists.txt
new file mode 100644
index 00000000..6fb70a5a
--- /dev/null
+++ b/src/debugger/CMakeLists.txt
@@ -0,0 +1,25 @@
+file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS
+ *.cpp
+ *.hpp
+ *.rc
+)
+
+list(SORT SRC_FILES)
+
+add_library(debugger ${SRC_FILES})
+
+momo_assign_source_group(${SRC_FILES})
+
+target_link_libraries(debugger PRIVATE
+ windows-emulator
+ flatbuffers
+ base64
+)
+
+target_include_directories(debugger INTERFACE "${CMAKE_CURRENT_LIST_DIR}")
+
+add_custom_target(generate-flatbuffer
+ DEPENDS flatc
+ COMMAND "$" --gen-mutable --gen-object-api --filename-ext hxx --cpp -o "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}/events.fbs"
+ COMMAND "$" --gen-mutable --gen-object-api --ts -o "${PROJECT_SOURCE_DIR}/page/src/fb" "${CMAKE_CURRENT_LIST_DIR}/events.fbs"
+)
diff --git a/src/debugger/event_handler.cpp b/src/debugger/event_handler.cpp
new file mode 100644
index 00000000..72d24bd2
--- /dev/null
+++ b/src/debugger/event_handler.cpp
@@ -0,0 +1,233 @@
+#include "event_handler.hpp"
+#include "message_transmitter.hpp"
+
+#include
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#endif
+
+#include "events_generated.hxx"
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace debugger
+{
+ namespace
+ {
+ std::optional receive_event()
+ {
+ const auto message = receive_message();
+ if (message.empty())
+ {
+ return std::nullopt;
+ }
+
+ const auto data = base64::from_base64(message);
+
+ flatbuffers::Verifier verifier(reinterpret_cast(data.data()), data.size());
+ if (!Debugger::VerifyDebugEventBuffer(verifier))
+ {
+ return std::nullopt;
+ }
+
+ Debugger::DebugEventT e{};
+ Debugger::GetDebugEvent(data.data())->UnPackTo(&e);
+
+ return {std::move(e)};
+ }
+
+ void send_event(const Debugger::DebugEventT& event)
+ {
+ flatbuffers::FlatBufferBuilder fbb{};
+ fbb.Finish(Debugger::DebugEvent::Pack(fbb, &event));
+
+ const std::string_view buffer(reinterpret_cast(fbb.GetBufferPointer()), fbb.GetSize());
+ const auto message = base64::to_base64(buffer);
+
+ send_message(message);
+ }
+
+ template
+ requires(!std::is_same_v, Debugger::DebugEventT>)
+ void send_event(T event)
+ {
+ Debugger::DebugEventT e{};
+ e.event.Set(std::move(event));
+ send_event(e);
+ }
+
+ Debugger::State translate_state(const emulation_state state)
+ {
+ switch (state)
+ {
+ case emulation_state::paused:
+ return Debugger::State_Paused;
+
+ case emulation_state::none:
+ case emulation_state::running:
+ return Debugger::State_Running;
+
+ default:
+ return Debugger::State_None;
+ }
+ }
+
+ void handle_get_state(const event_context& c)
+ {
+ Debugger::GetStateResponseT response{};
+ response.state = translate_state(c.state);
+
+ send_event(response);
+ }
+
+ void handle_read_memory(const event_context& c, const Debugger::ReadMemoryRequestT& request)
+ {
+ std::vector buffer{};
+ buffer.resize(request.size);
+ const auto res = c.win_emu.memory.try_read_memory(request.address, buffer.data(), buffer.size());
+
+ Debugger::ReadMemoryResponseT response{};
+ response.address = request.address;
+
+ if (res)
+ {
+ response.data = std::move(buffer);
+ }
+
+ send_event(std::move(response));
+ }
+
+ void handle_write_memory(const event_context& c, const Debugger::WriteMemoryRequestT& request)
+ {
+ bool success{};
+
+ try
+ {
+ c.win_emu.memory.write_memory(request.address, request.data.data(), request.data.size());
+ success = true;
+ }
+ catch (...)
+ {
+ success = false;
+ }
+
+ Debugger::WriteMemoryResponseT response{};
+ response.address = request.address;
+ response.size = static_cast(request.data.size());
+ response.success = success;
+
+ send_event(response);
+ }
+
+ void handle_read_register(const event_context& c, const Debugger::ReadRegisterRequestT& request)
+ {
+ std::array buffer{};
+ const auto res = c.win_emu.emu().read_register(static_cast(request.register_), buffer.data(),
+ buffer.size());
+
+ const auto size = std::min(buffer.size(), res);
+
+ Debugger::ReadRegisterResponseT response{};
+ response.register_ = request.register_;
+ response.data.assign(buffer.data(), buffer.data() + size);
+
+ send_event(std::move(response));
+ }
+
+ void handle_write_register(const event_context& c, const Debugger::WriteRegisterRequestT& request)
+ {
+ bool success{};
+ size_t size = request.data.size();
+
+ try
+ {
+ size = c.win_emu.emu().write_register(static_cast(request.register_), request.data.data(),
+ request.data.size());
+ success = true;
+ }
+ catch (...)
+ {
+ success = false;
+ }
+
+ Debugger::WriteRegisterResponseT response{};
+ response.register_ = request.register_;
+ response.size = static_cast(size);
+ response.success = success;
+
+ send_event(response);
+ }
+
+ void handle_event(event_context& c, const Debugger::DebugEventT& e)
+ {
+ switch (e.event.type)
+ {
+ case Debugger::Event_PauseRequest:
+ c.state = emulation_state::paused;
+ break;
+
+ case Debugger::Event_RunRequest:
+ c.state = emulation_state::running;
+ break;
+
+ case Debugger::Event_GetStateRequest:
+ handle_get_state(c);
+ break;
+
+ case Debugger::Event_ReadMemoryRequest:
+ handle_read_memory(c, *e.event.AsReadMemoryRequest());
+ break;
+
+ case Debugger::Event_WriteMemoryRequest:
+ handle_write_memory(c, *e.event.AsWriteMemoryRequest());
+ break;
+
+ case Debugger::Event_ReadRegisterRequest:
+ handle_read_register(c, *e.event.AsReadRegisterRequest());
+ break;
+
+ case Debugger::Event_WriteRegisterRequest:
+ handle_write_register(c, *e.event.AsWriteRegisterRequest());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ void handle_events_once(event_context& c)
+ {
+ while (true)
+ {
+ suspend_execution(0ms);
+
+ const auto e = receive_event();
+ if (!e.has_value())
+ {
+ break;
+ }
+
+ handle_event(c, *e);
+ }
+ }
+
+ void handle_events(event_context& c)
+ {
+ while (true)
+ {
+ handle_events_once(c);
+
+ if (c.state != emulation_state::paused)
+ {
+ break;
+ }
+
+ suspend_execution(2ms);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/debugger/event_handler.hpp b/src/debugger/event_handler.hpp
new file mode 100644
index 00000000..0e052fe6
--- /dev/null
+++ b/src/debugger/event_handler.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+
+namespace debugger
+{
+ enum class emulation_state
+ {
+ none,
+ running,
+ paused,
+ };
+
+ struct event_context
+ {
+ windows_emulator& win_emu;
+ emulation_state state{emulation_state::none};
+ };
+
+ void handle_events(event_context& c);
+}
diff --git a/src/debugger/events.fbs b/src/debugger/events.fbs
new file mode 100644
index 00000000..4c17f9a4
--- /dev/null
+++ b/src/debugger/events.fbs
@@ -0,0 +1,81 @@
+namespace Debugger;
+
+table GetStateRequest {}
+
+enum State : uint32 {
+ None = 0,
+ Running,
+ Paused,
+}
+
+table GetStateResponse {
+ state: State;
+}
+
+table PauseRequest {}
+
+table RunRequest {
+ single_step: bool;
+}
+
+table WriteMemoryRequest {
+ address: uint64;
+ data: [ubyte];
+}
+
+table WriteMemoryResponse {
+ address: uint64;
+ size: uint32;
+ success: bool;
+}
+
+table ReadMemoryRequest {
+ address: uint64;
+ size: uint32;
+}
+
+table ReadMemoryResponse {
+ address: uint64;
+ data: [ubyte];
+}
+
+table WriteRegisterRequest {
+ register: uint32;
+ data: [ubyte];
+}
+
+table WriteRegisterResponse {
+ register: uint32;
+ size: uint32;
+ success: bool;
+}
+
+table ReadRegisterRequest {
+ register: uint32;
+}
+
+table ReadRegisterResponse {
+ register: uint32;
+ data: [ubyte];
+}
+
+union Event {
+ PauseRequest,
+ RunRequest,
+ GetStateRequest,
+ GetStateResponse,
+ WriteMemoryRequest,
+ WriteMemoryResponse,
+ ReadMemoryRequest,
+ ReadMemoryResponse,
+ WriteRegisterRequest,
+ WriteRegisterResponse,
+ ReadRegisterRequest,
+ ReadRegisterResponse,
+}
+
+table DebugEvent {
+ event: Event;
+}
+
+root_type DebugEvent;
diff --git a/src/debugger/events_generated.hxx b/src/debugger/events_generated.hxx
new file mode 100644
index 00000000..5c56b8c5
--- /dev/null
+++ b/src/debugger/events_generated.hxx
@@ -0,0 +1,2070 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_EVENTS_DEBUGGER_H_
+#define FLATBUFFERS_GENERATED_EVENTS_DEBUGGER_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+// Ensure the included flatbuffers.h is the same version as when this file was
+// generated, otherwise it may not be compatible.
+static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
+ FLATBUFFERS_VERSION_MINOR == 2 &&
+ FLATBUFFERS_VERSION_REVISION == 10,
+ "Non-compatible flatbuffers version included");
+
+namespace Debugger {
+
+struct GetStateRequest;
+struct GetStateRequestBuilder;
+struct GetStateRequestT;
+
+struct GetStateResponse;
+struct GetStateResponseBuilder;
+struct GetStateResponseT;
+
+struct PauseRequest;
+struct PauseRequestBuilder;
+struct PauseRequestT;
+
+struct RunRequest;
+struct RunRequestBuilder;
+struct RunRequestT;
+
+struct WriteMemoryRequest;
+struct WriteMemoryRequestBuilder;
+struct WriteMemoryRequestT;
+
+struct WriteMemoryResponse;
+struct WriteMemoryResponseBuilder;
+struct WriteMemoryResponseT;
+
+struct ReadMemoryRequest;
+struct ReadMemoryRequestBuilder;
+struct ReadMemoryRequestT;
+
+struct ReadMemoryResponse;
+struct ReadMemoryResponseBuilder;
+struct ReadMemoryResponseT;
+
+struct WriteRegisterRequest;
+struct WriteRegisterRequestBuilder;
+struct WriteRegisterRequestT;
+
+struct WriteRegisterResponse;
+struct WriteRegisterResponseBuilder;
+struct WriteRegisterResponseT;
+
+struct ReadRegisterRequest;
+struct ReadRegisterRequestBuilder;
+struct ReadRegisterRequestT;
+
+struct ReadRegisterResponse;
+struct ReadRegisterResponseBuilder;
+struct ReadRegisterResponseT;
+
+struct DebugEvent;
+struct DebugEventBuilder;
+struct DebugEventT;
+
+enum State : uint32_t {
+ State_None = 0,
+ State_Running = 1,
+ State_Paused = 2,
+ State_MIN = State_None,
+ State_MAX = State_Paused
+};
+
+inline const State (&EnumValuesState())[3] {
+ static const State values[] = {
+ State_None,
+ State_Running,
+ State_Paused
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesState() {
+ static const char * const names[4] = {
+ "None",
+ "Running",
+ "Paused",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameState(State e) {
+ if (::flatbuffers::IsOutRange(e, State_None, State_Paused)) return "";
+ const size_t index = static_cast(e);
+ return EnumNamesState()[index];
+}
+
+enum Event : uint8_t {
+ Event_NONE = 0,
+ Event_PauseRequest = 1,
+ Event_RunRequest = 2,
+ Event_GetStateRequest = 3,
+ Event_GetStateResponse = 4,
+ Event_WriteMemoryRequest = 5,
+ Event_WriteMemoryResponse = 6,
+ Event_ReadMemoryRequest = 7,
+ Event_ReadMemoryResponse = 8,
+ Event_WriteRegisterRequest = 9,
+ Event_WriteRegisterResponse = 10,
+ Event_ReadRegisterRequest = 11,
+ Event_ReadRegisterResponse = 12,
+ Event_MIN = Event_NONE,
+ Event_MAX = Event_ReadRegisterResponse
+};
+
+inline const Event (&EnumValuesEvent())[13] {
+ static const Event values[] = {
+ Event_NONE,
+ Event_PauseRequest,
+ Event_RunRequest,
+ Event_GetStateRequest,
+ Event_GetStateResponse,
+ Event_WriteMemoryRequest,
+ Event_WriteMemoryResponse,
+ Event_ReadMemoryRequest,
+ Event_ReadMemoryResponse,
+ Event_WriteRegisterRequest,
+ Event_WriteRegisterResponse,
+ Event_ReadRegisterRequest,
+ Event_ReadRegisterResponse
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesEvent() {
+ static const char * const names[14] = {
+ "NONE",
+ "PauseRequest",
+ "RunRequest",
+ "GetStateRequest",
+ "GetStateResponse",
+ "WriteMemoryRequest",
+ "WriteMemoryResponse",
+ "ReadMemoryRequest",
+ "ReadMemoryResponse",
+ "WriteRegisterRequest",
+ "WriteRegisterResponse",
+ "ReadRegisterRequest",
+ "ReadRegisterResponse",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameEvent(Event e) {
+ if (::flatbuffers::IsOutRange(e, Event_NONE, Event_ReadRegisterResponse)) return "";
+ const size_t index = static_cast(e);
+ return EnumNamesEvent()[index];
+}
+
+template struct EventTraits {
+ static const Event enum_value = Event_NONE;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_PauseRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_RunRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_GetStateRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_GetStateResponse;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_WriteMemoryRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_WriteMemoryResponse;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_ReadMemoryRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_ReadMemoryResponse;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_WriteRegisterRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_WriteRegisterResponse;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_ReadRegisterRequest;
+};
+
+template<> struct EventTraits {
+ static const Event enum_value = Event_ReadRegisterResponse;
+};
+
+template struct EventUnionTraits {
+ static const Event enum_value = Event_NONE;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_PauseRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_RunRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_GetStateRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_GetStateResponse;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_WriteMemoryRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_WriteMemoryResponse;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_ReadMemoryRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_ReadMemoryResponse;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_WriteRegisterRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_WriteRegisterResponse;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_ReadRegisterRequest;
+};
+
+template<> struct EventUnionTraits {
+ static const Event enum_value = Event_ReadRegisterResponse;
+};
+
+struct EventUnion {
+ Event type;
+ void *value;
+
+ EventUnion() : type(Event_NONE), value(nullptr) {}
+ EventUnion(EventUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(Event_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ EventUnion(const EventUnion &);
+ EventUnion &operator=(const EventUnion &u)
+ { EventUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ EventUnion &operator=(EventUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~EventUnion() { Reset(); }
+
+ void Reset();
+
+ template
+ void Set(T&& val) {
+ typedef typename std::remove_reference::type RT;
+ Reset();
+ type = EventUnionTraits