1use {
2 serde::{Deserialize, Serialize},
3 serde_json::{Value, json},
4 std::io::{self, BufRead, Write},
5};
6
7pub trait DebuggerInterface {
8 fn step(&mut self) -> Value;
9 fn next(&mut self) -> Value;
10 fn finish(&mut self) -> Value;
11 fn r#continue(&mut self) -> Value;
12 fn set_breakpoint(&mut self, file: String, line: usize) -> Value;
13 fn remove_breakpoint(&mut self, file: String, line: usize) -> Value;
14 fn get_stack_frames(&self) -> Value;
15 fn get_registers(&self) -> Value;
16 fn get_memory(&self, address: u64, size: usize) -> Value;
17 fn set_register(&mut self, index: usize, value: u64) -> Value;
18 fn get_rodata(&self) -> Value;
19 fn clear_breakpoints(&mut self, file: String) -> Value;
20 fn quit(&mut self) -> Value;
21 fn get_compute_units(&self) -> Value;
22 fn run_to_json(&mut self) -> Value;
23}
24
25#[derive(Deserialize)]
26struct AdapterCommand {
27 command: String,
28 args: Option<Value>,
29 #[serde(rename = "requestId")]
30 request_id: Option<Value>,
31}
32
33#[derive(Serialize)]
34struct AdapterResponse {
35 success: bool,
36 data: Option<Value>,
37 error: Option<String>,
38 #[serde(rename = "requestId")]
39 request_id: Option<Value>,
40}
41
42pub fn run_adapter_loop<T: DebuggerInterface>(debugger: &mut T) {
43 let stdin = io::stdin();
44 let mut stdout = io::stdout();
45 for line in stdin.lock().lines() {
46 let line = match line {
47 Ok(l) => l,
48 Err(_) => break,
49 };
50 if line.trim().is_empty() {
51 continue;
52 }
53 let cmd: Result<AdapterCommand, _> = serde_json::from_str(&line);
54 let mut response = AdapterResponse {
55 success: true,
56 data: None,
57 error: None,
58 request_id: None,
59 };
60 match cmd {
61 Ok(cmd) => {
62 response.request_id = cmd.request_id.clone();
63 let result = match cmd.command.as_str() {
64 "step" => debugger.step(),
65 "next" => debugger.next(),
66 "finish" => debugger.finish(),
67 "continue" => debugger.r#continue(),
68 "setBreakpoint" => {
69 if let Some(args) = cmd.args {
70 let file = args
71 .get(0)
72 .and_then(Value::as_str)
73 .unwrap_or("")
74 .to_string();
75 let line = args.get(1).and_then(Value::as_u64).unwrap_or(0) as usize;
76 debugger.set_breakpoint(file, line)
77 } else {
78 json!({"type": "error", "message": "Missing args"})
79 }
80 }
81 "removeBreakpoint" => {
82 if let Some(args) = cmd.args {
83 let file = args
84 .get(0)
85 .and_then(Value::as_str)
86 .unwrap_or("")
87 .to_string();
88 let line = args.get(1).and_then(Value::as_u64).unwrap_or(0) as usize;
89 debugger.remove_breakpoint(file, line)
90 } else {
91 json!({"type": "error", "message": "Missing args"})
92 }
93 }
94 "getStackFrames" => debugger.get_stack_frames(),
95 "getRegisters" => debugger.get_registers(),
96 "getRodata" => debugger.get_rodata(),
97 "clearBreakpoints" => {
98 if let Some(args) = cmd.args {
99 let file = args
100 .get(0)
101 .and_then(Value::as_str)
102 .unwrap_or("")
103 .to_string();
104 debugger.clear_breakpoints(file)
105 } else {
106 json!({"type": "error", "message": "Missing args"})
107 }
108 }
109 "getMemory" => {
110 if let Some(args) = cmd.args {
111 let address = args.get(0).and_then(Value::as_u64).unwrap_or(0);
112 let size = args.get(1).and_then(Value::as_u64).unwrap_or(0) as usize;
113 debugger.get_memory(address, size)
114 } else {
115 json!({"type": "error", "message": "Missing args"})
116 }
117 }
118 "getComputeUnits" => debugger.get_compute_units(),
119 "setRegister" => {
120 if let Some(args) = cmd.args {
121 let index = args.get(0).and_then(Value::as_u64).unwrap_or(0) as usize;
122 let value = args.get(1).and_then(Value::as_u64).unwrap_or(0);
123 debugger.set_register(index, value)
124 } else {
125 json!({"type": "error", "message": "Missing args"})
126 }
127 }
128 "quit" => debugger.quit(),
129 _ => json!({"type": "error", "message": "Unknown command"}),
130 };
131 if let Some(result_obj) = result.as_object() {
133 if result_obj.contains_key("error") {
134 response.success = false;
135 response.error = result_obj
136 .get("error")
137 .and_then(|v| v.as_str())
138 .map(|s| s.to_string());
139 } else if result_obj.get("type").and_then(|v| v.as_str()) == Some("error") {
140 response.success = false;
141 response.error = result_obj
142 .get("message")
143 .and_then(|v| v.as_str())
144 .map(|s| s.to_string());
145 }
146 }
147 response.data = Some(result);
148 }
149 Err(e) => {
150 response.success = false;
151 response.error = Some(format!("Invalid command: {}", e));
152 }
153 }
154 let resp_str = serde_json::to_string(&response).unwrap();
155 writeln!(stdout, "{}", resp_str).unwrap();
156 stdout.flush().unwrap();
157 }
158}