use crate::commands::{command_sets, vm_commands};
use crate::connection::JdwpConnection;
use crate::protocol::{CommandPacket, JdwpResult};
use crate::reader::{read_i32, read_string, read_u8};
use crate::types::ReferenceTypeId;
use bytes::BufMut;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VmVersion {
pub description: String,
pub jdwp_major: i32,
pub jdwp_minor: i32,
pub vm_version: String,
pub vm_name: String,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
pub struct VmCapabilities {
pub can_watch_field_modification: bool,
pub can_watch_field_access: bool,
pub can_get_bytecodes: bool,
pub can_get_synthetic_attribute: bool,
pub can_get_owned_monitor_info: bool,
pub can_get_current_contended_monitor: bool,
pub can_get_monitor_info: bool,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
pub struct VmCapabilitiesNew {
pub can_redefine_classes: bool,
pub can_add_method: bool,
pub can_unrestrictedly_redefine_classes: bool,
pub can_pop_frames: bool,
pub can_use_instance_filters: bool,
pub can_get_instance_info: bool,
pub can_request_monitor_events: bool,
pub can_get_monitor_frame_info: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassInfo {
pub ref_type_tag: u8, pub type_id: ReferenceTypeId,
pub signature: String,
pub status: i32,
}
impl JdwpConnection {
pub async fn get_version(&mut self) -> JdwpResult<VmVersion> {
let id = self.next_id();
let packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::VERSION);
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let description = read_string(&mut data)?;
let jdwp_major = read_i32(&mut data)?;
let jdwp_minor = read_i32(&mut data)?;
let vm_version = read_string(&mut data)?;
let vm_name = read_string(&mut data)?;
Ok(VmVersion { description, jdwp_major, jdwp_minor, vm_version, vm_name })
}
pub async fn capabilities(&mut self) -> JdwpResult<VmCapabilities> {
let id = self.next_id();
let packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::CAPABILITIES);
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let mut flag = || -> JdwpResult<bool> { Ok(read_u8(&mut data)? != 0) };
Ok(VmCapabilities {
can_watch_field_modification: flag()?,
can_watch_field_access: flag()?,
can_get_bytecodes: flag()?,
can_get_synthetic_attribute: flag()?,
can_get_owned_monitor_info: flag()?,
can_get_current_contended_monitor: flag()?,
can_get_monitor_info: flag()?,
})
}
pub async fn capabilities_new(&mut self) -> JdwpResult<VmCapabilitiesNew> {
let id = self.next_id();
let packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::CAPABILITIES_NEW);
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let mut flag = || -> JdwpResult<bool> { Ok(read_u8(&mut data)? != 0) };
for _ in 0..7 {
flag()?;
}
let can_redefine_classes = flag()?;
let can_add_method = flag()?;
let can_unrestrictedly_redefine_classes = flag()?;
let can_pop_frames = flag()?;
let can_use_instance_filters = flag()?;
for _ in 0..3 {
flag()?;
}
Ok(VmCapabilitiesNew {
can_redefine_classes,
can_add_method,
can_unrestrictedly_redefine_classes,
can_pop_frames,
can_use_instance_filters,
can_get_instance_info: flag()?,
can_request_monitor_events: flag()?,
can_get_monitor_frame_info: flag()?,
})
}
pub async fn instance_counts(&mut self, ref_types: &[ReferenceTypeId]) -> JdwpResult<Vec<i64>> {
let id = self.next_id();
let mut packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::INSTANCE_COUNTS);
packet.data.put_i32(i32::try_from(ref_types.len()).unwrap_or(i32::MAX));
for t in ref_types {
packet.data.put_u64(*t);
}
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let n = read_i32(&mut data)?;
let mut counts = Vec::with_capacity(usize::try_from(n).unwrap_or(0));
for _ in 0..n {
counts.push(crate::reader::read_i64(&mut data)?);
}
Ok(counts)
}
pub async fn redefine_classes(&mut self, defs: &[(ReferenceTypeId, Vec<u8>)]) -> JdwpResult<()> {
self.guard_mutation("a class redefinition")?;
let id = self.next_id();
let mut packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::REDEFINE_CLASSES);
packet.data.put_i32(i32::try_from(defs.len()).unwrap_or(i32::MAX));
for (type_id, bytes) in defs {
packet.data.put_u64(*type_id);
packet.data.put_u32(u32::try_from(bytes.len()).unwrap_or(u32::MAX));
packet.data.extend_from_slice(bytes);
}
let reply = self.send_command(packet).await?;
reply.check_error()?;
for (type_id, _) in defs {
self.types().invalidate(*type_id);
}
Ok(())
}
pub async fn dispose(&mut self) -> JdwpResult<()> {
let id = self.next_id();
let packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::DISPOSE);
let reply = self.send_command(packet).await?;
reply.check_error()?;
Ok(())
}
pub async fn classes_by_signature(&mut self, signature: &str) -> JdwpResult<Vec<ClassInfo>> {
let id = self.next_id();
let mut packet =
CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::CLASSES_BY_SIGNATURE);
let sig_bytes = signature.as_bytes();
packet.data.put_u32(u32::try_from(sig_bytes.len()).unwrap_or(u32::MAX));
packet.data.extend_from_slice(sig_bytes);
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let classes_count = read_i32(&mut data)?;
let mut classes = Vec::with_capacity(usize::try_from(classes_count).unwrap_or(0));
for _ in 0..classes_count {
let ref_type_tag = read_u8(&mut data)?;
let type_id = crate::reader::read_u64(&mut data)?;
let status = read_i32(&mut data)?;
classes.push(ClassInfo { ref_type_tag, type_id, signature: signature.to_string(), status });
}
Ok(classes)
}
pub async fn all_classes(&mut self) -> JdwpResult<Vec<ClassInfo>> {
let id = self.next_id();
let packet = CommandPacket::new(id, command_sets::VIRTUAL_MACHINE, vm_commands::ALL_CLASSES);
let reply = self.send_command(packet).await?;
reply.check_error()?;
let mut data = reply.data();
let classes_count = read_i32(&mut data)?;
let mut classes = Vec::with_capacity(usize::try_from(classes_count).unwrap_or(0));
for _ in 0..classes_count {
let ref_type_tag = read_u8(&mut data)?;
let type_id = crate::reader::read_u64(&mut data)?;
let signature = read_string(&mut data)?;
let status = read_i32(&mut data)?;
classes.push(ClassInfo { ref_type_tag, type_id, signature, status });
}
Ok(classes)
}
}