1use crate::commands::{command_sets, event_commands, event_kinds, step_depths, step_sizes, vm_commands};
5use crate::connection::JdwpConnection;
6use crate::eval::{write_tagged_value, write_untagged_value};
7use crate::eventrequest::{EventFilters, SuspendPolicy};
8use crate::protocol::{CommandPacket, JdwpResult};
9use crate::reader::{read_i32, read_u64, read_u8, read_value_by_tag};
10use crate::types::{FrameId, MethodId, ObjectId, ReferenceTypeId, ThreadId, Value, ValueData};
11use bytes::BufMut;
12
13const MOD_COUNT: u8 = 1;
15const MOD_THREAD_ONLY: u8 = 3;
16const MOD_CLASS_ONLY: u8 = 4;
18const MOD_CLASS_EXCLUDE: u8 = 6;
21const MOD_LOCATION_ONLY: u8 = 7;
22const MOD_STEP: u8 = 10;
23const MOD_INSTANCE_ONLY: u8 = 11;
25const ARRAY_LENGTH: u8 = 1;
27const ARRAY_GET_VALUES: u8 = 2;
28const ARRAY_SET_VALUES: u8 = 3;
29
30fn write_jdwp_string(packet: &mut CommandPacket, s: &str) {
32 let b = s.as_bytes();
33 packet.data.put_u32(u32::try_from(b.len()).unwrap_or(u32::MAX));
34 packet.data.extend_from_slice(b);
35}
36
37#[derive(Debug, Clone, Copy)]
39pub enum StepDepth {
40 Into,
41 Over,
42 Out,
43}
44
45impl JdwpConnection {
46 pub async fn set_breakpoint_ex(
51 &mut self,
52 class_id: ReferenceTypeId,
53 method_id: MethodId,
54 bytecode_index: u64,
55 suspend_policy: SuspendPolicy,
56 filters: EventFilters,
57 ) -> JdwpResult<i32> {
58 let id = self.next_id();
59 let mut packet = CommandPacket::new(id, command_sets::EVENT_REQUEST, event_commands::SET);
60 packet.data.put_u8(event_kinds::BREAKPOINT);
61 packet.data.put_u8(suspend_policy as u8);
62
63 let n_mods = 1
64 + i32::from(filters.count.is_some())
65 + i32::from(filters.thread.is_some())
66 + i32::from(filters.instance.is_some());
67 packet.data.put_i32(n_mods);
68
69 packet.data.put_u8(MOD_LOCATION_ONLY);
71 packet.data.put_u8(1); packet.data.put_u64(class_id);
73 packet.data.put_u64(method_id);
74 packet.data.put_u64(bytecode_index);
75
76 if let Some(c) = filters.count {
77 packet.data.put_u8(MOD_COUNT);
78 packet.data.put_i32(c);
79 }
80 if let Some(t) = filters.thread {
81 packet.data.put_u8(MOD_THREAD_ONLY);
82 packet.data.put_u64(t);
83 }
84 if let Some(o) = filters.instance {
85 packet.data.put_u8(MOD_INSTANCE_ONLY);
86 packet.data.put_u64(o);
87 }
88
89 let reply = self.send_command(packet).await?;
90 reply.check_error()?;
91 let mut data = reply.data();
92 read_i32(&mut data)
93 }
94
95 pub async fn set_step(&mut self, thread: ThreadId, depth: StepDepth) -> JdwpResult<i32> {
101 self.set_step_ex(thread, depth, &[], &[]).await
102 }
103
104 pub async fn set_step_ex(
127 &mut self,
128 thread: ThreadId,
129 depth: StepDepth,
130 exclude: &[String],
131 only: &[String],
132 ) -> JdwpResult<i32> {
133 let id = self.next_id();
134 let mut packet = CommandPacket::new(id, command_sets::EVENT_REQUEST, event_commands::SET);
135 packet.data.put_u8(event_kinds::SINGLE_STEP);
136 packet.data.put_u8(SuspendPolicy::All as u8);
137 let n_mods = 1 + exclude.len() + only.len();
139 packet.data.put_i32(i32::try_from(n_mods).unwrap_or(i32::MAX));
140 packet.data.put_u8(MOD_STEP);
141 packet.data.put_u64(thread);
142 packet.data.put_i32(step_sizes::LINE);
143 packet.data.put_i32(match depth {
144 StepDepth::Into => step_depths::INTO,
145 StepDepth::Over => step_depths::OVER,
146 StepDepth::Out => step_depths::OUT,
147 });
148 for pat in only {
149 packet.data.put_u8(MOD_CLASS_ONLY);
150 write_jdwp_string(&mut packet, pat);
151 }
152 for pat in exclude {
153 packet.data.put_u8(MOD_CLASS_EXCLUDE);
154 write_jdwp_string(&mut packet, pat);
155 }
156 let reply = self.send_command(packet).await?;
157 reply.check_error()?;
158 let mut data = reply.data();
159 read_i32(&mut data)
160 }
161
162 pub async fn clear_step(&mut self, request_id: i32) -> JdwpResult<()> {
167 let id = self.next_id();
168 let mut packet = CommandPacket::new(id, command_sets::EVENT_REQUEST, event_commands::CLEAR);
169 packet.data.put_u8(event_kinds::SINGLE_STEP);
170 packet.data.put_i32(request_id);
171 let reply = self.send_command(packet).await?;
172 reply.check_error()?;
173 Ok(())
174 }
175
176 pub async fn clear_all_breakpoints(&mut self) -> JdwpResult<()> {
181 let id = self.next_id();
182 let packet =
183 CommandPacket::new(id, command_sets::EVENT_REQUEST, event_commands::CLEAR_ALL_BREAKPOINTS);
184 let reply = self.send_command(packet).await?;
185 reply.check_error()?;
186 Ok(())
187 }
188
189 pub async fn get_array_length(&mut self, array_id: ObjectId) -> JdwpResult<i32> {
194 let id = self.next_id();
195 let mut packet = CommandPacket::new(id, command_sets::ARRAY_REFERENCE, ARRAY_LENGTH);
196 packet.data.put_u64(array_id);
197 let reply = self.send_command(packet).await?;
198 reply.check_error()?;
199 let mut data = reply.data();
200 read_i32(&mut data)
201 }
202
203 pub async fn get_array_values(
208 &mut self,
209 array_id: ObjectId,
210 first: i32,
211 length: i32,
212 ) -> JdwpResult<Vec<Value>> {
213 let id = self.next_id();
214 let mut packet = CommandPacket::new(id, command_sets::ARRAY_REFERENCE, ARRAY_GET_VALUES);
215 packet.data.put_u64(array_id);
216 packet.data.put_i32(first);
217 packet.data.put_i32(length);
218 let reply = self.send_command(packet).await?;
219 reply.check_error()?;
220 let mut data = reply.data();
221
222 let region_tag = read_u8(&mut data)?;
225 let count = read_i32(&mut data)?;
226 let is_object = matches!(region_tag, 76 | 115 | 116 | 103 | 108 | 99 | 91);
227 let mut out = Vec::with_capacity(usize::try_from(count.max(0)).unwrap_or(0));
228 for _ in 0..count {
229 if is_object {
230 let t = read_u8(&mut data)?;
231 out.push(Value { tag: t, data: read_value_by_tag(t, &mut data)? });
232 } else {
233 out.push(Value { tag: region_tag, data: read_value_by_tag(region_tag, &mut data)? });
234 }
235 }
236 Ok(out)
237 }
238
239 pub async fn set_array_values(
249 &mut self,
250 array_id: ObjectId,
251 first: i32,
252 values: &[Value],
253 ) -> JdwpResult<()> {
254 self.guard_mutation("an array element write")?;
255 let id = self.next_id();
256 let mut packet = CommandPacket::new(id, command_sets::ARRAY_REFERENCE, ARRAY_SET_VALUES);
257 packet.data.put_u64(array_id);
258 packet.data.put_i32(first);
259 packet.data.put_i32(i32::try_from(values.len()).unwrap_or(i32::MAX));
260 for v in values {
261 write_untagged_value(&mut packet.data, v);
262 }
263 let reply = self.send_command(packet).await?;
264 reply.check_error()?;
265 Ok(())
266 }
267
268 pub async fn create_string(&mut self, s: &str) -> JdwpResult<ObjectId> {
273 let id = self.next_id();
274 let mut packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::CREATE_STRING);
275 let bytes = s.as_bytes();
276 packet.data.put_i32(i32::try_from(bytes.len()).unwrap_or(i32::MAX));
277 packet.data.put_slice(bytes);
278 let reply = self.send_command(packet).await?;
279 reply.check_error()?;
280 let mut data = reply.data();
281 read_u64(&mut data)
282 }
283
284 pub async fn set_frame_value(
289 &mut self,
290 thread_id: ThreadId,
291 frame_id: FrameId,
292 slot: i32,
293 value: &Value,
294 ) -> JdwpResult<()> {
295 self.guard_mutation("a local variable write")?;
296 let id = self.next_id();
297 let mut packet = CommandPacket::new(id, command_sets::STACK_FRAME, 2 );
298 packet.data.put_u64(thread_id);
299 packet.data.put_u64(frame_id);
300 packet.data.put_i32(1); packet.data.put_i32(slot);
302 write_tagged_value(&mut packet.data, value);
303 let reply = self.send_command(packet).await?;
304 reply.check_error()?;
305 Ok(())
306 }
307}
308
309#[must_use]
311pub const fn value_int(v: i32) -> Value {
312 Value { tag: 73, data: ValueData::Int(v) }
313}
314#[must_use]
315pub const fn value_long(v: i64) -> Value {
316 Value { tag: 74, data: ValueData::Long(v) }
317}
318#[must_use]
319pub const fn value_bool(v: bool) -> Value {
320 Value { tag: 90, data: ValueData::Boolean(v) }
321}
322#[must_use]
325pub const fn value_float(v: f32) -> Value {
326 Value { tag: 70, data: ValueData::Float(v) }
327}
328#[must_use]
329pub const fn value_double(v: f64) -> Value {
330 Value { tag: 68, data: ValueData::Double(v) }
331}
332#[must_use]
335pub const fn value_char(v: u16) -> Value {
336 Value { tag: 67, data: ValueData::Char(v) }
337}
338#[must_use]
339pub const fn value_null() -> Value {
340 Value { tag: 76, data: ValueData::Object(0) }
341}
342#[must_use]
343pub const fn value_object(id: ObjectId) -> Value {
344 Value { tag: 76, data: ValueData::Object(id) }
345}