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