Skip to content

Commit b70ba27

Browse files
committed
jvmti: start implementing JVMTI bindings
1 parent e9b1912 commit b70ba27

File tree

12 files changed

+1853
-0
lines changed

12 files changed

+1853
-0
lines changed

.cargo/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ artifact-dir = "./build/out"
55
[env]
66

77
# Constant VM properties
8+
JAVA_VERSION = "27"
89
SYSTEM_PROPS_VM_SPECIFICATION_NAME = "Java Virtual Machine Specification"
910
SYSTEM_PROPS_VM_NAME = "SJVM"
1011
SYSTEM_PROPS_VM_VENDOR = "Serial-ATA"

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ members = [
1414
"platform",
1515
"jni",
1616
"jni/sys",
17+
"jvmti",
18+
"jvmti/sys",
1719
# Native libraries
1820
"native/*"
1921
]
@@ -97,6 +99,8 @@ instructions = { path = "instructions" }
9799
jimage = { path = "jimage" }
98100
jni = { path = "jni" }
99101
jni_sys = { path = "jni/sys" }
102+
jvmti = { path = "jvmti" }
103+
jvmti_sys = { path = "jvmti/sys" }
100104
platform = { path = "platform" }
101105
vm_symbols = { path = "generators/vm_symbols" }
102106

jni/src/java_vm/attach_args.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl VmAttachArgs {
8484
/// } JavaVMAttachArgs
8585
/// ```
8686
#[expect(dead_code)]
87+
#[repr(C)]
8788
pub(super) struct FinalizedJavaVMAttachArgs {
8889
version: jint,
8990
name: *const c_char,

jvmti/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "jvmti"
3+
version = "0.1.0"
4+
authors.workspace = true
5+
repository.workspace = true
6+
edition.workspace = true
7+
license.workspace = true
8+
9+
[dependencies]
10+
jvmti_sys.workspace = true
11+
12+
[lints]
13+
workspace = true

jvmti/src/env/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// Safer wrapper around [`jvmti_sys::jvmtiEnv`]
2+
#[repr(transparent)]
3+
#[derive(Copy, Clone, PartialEq, Eq)]
4+
pub struct JvmtiEnv(*mut jvmti_sys::jvmtiEnv);
5+
6+
impl JvmtiEnv {
7+
/// Get the inner pointer to this JVMTI env
8+
pub fn raw(&self) -> *mut jvmti_sys::jvmtiEnv {
9+
self.0
10+
}
11+
12+
/// Create a [`JvmtiEnv`] from a raw pointer
13+
///
14+
/// # Safety
15+
///
16+
/// The caller *must* ensure that the pointer provided was obtained from the VM.
17+
pub unsafe fn from_raw(env: *mut jvmti_sys::jvmtiEnv) -> Self {
18+
Self(env)
19+
}
20+
}

jvmti/src/error.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use jvmti_sys::jvmtiError;
2+
3+
pub enum JvmtiError {
4+
InvalidThread,
5+
InvalidThreadGroup,
6+
InvalidPriority,
7+
ThreadNotSuspended,
8+
ThreadSuspended,
9+
ThreadNotAlive,
10+
InvalidObject,
11+
InvalidClass,
12+
ClassNotPrepared,
13+
InvalidMethodId,
14+
InvalidLocation,
15+
InvalidFieldId,
16+
InvalidModule,
17+
NoMoreFrames,
18+
OpaqueFrame,
19+
TypeMismatch,
20+
InvalidSlot,
21+
Duplicate,
22+
NotFound,
23+
InvalidMonitor,
24+
NotMonitorOwner,
25+
Interrupt,
26+
InvalidClassFormat,
27+
CircularClassDefinition,
28+
FailsVerification,
29+
UnsupportedRedefinitionMethodAdded,
30+
UnsupportedRedefinitionSchemaChanged,
31+
InvalidTypestate,
32+
UnsupportedRedefinitionHierarchyChanged,
33+
UnsupportedRedefinitionMethodDeleted,
34+
UnsupportedVersion,
35+
NamesDontMatch,
36+
UnsupportedRedefinitionClassModifiersChanged,
37+
UnsupportedRedefinitionMethodModifiersChanged,
38+
UnsupportedRedefinitionClassAttributeChanged,
39+
UnsupportedOperation,
40+
UnmodifiableClass,
41+
UnmodifiableModule,
42+
NotAvailable,
43+
MustPossessCapability,
44+
NullPointer,
45+
AbsentInformation,
46+
InvalidEventType,
47+
IllegalArgument,
48+
NativeMethod,
49+
ClassLoaderUnsupported,
50+
OutOfMemory,
51+
AccessDenied,
52+
WrongPhase,
53+
Internal,
54+
UnattachedThread,
55+
InvalidEnvironment,
56+
}
57+
58+
impl JvmtiError {
59+
pub fn from_raw(raw: jvmtiError) -> Option<Self> {
60+
match raw {
61+
crate::sys::JVMTI_ERROR_INVALID_THREAD => Some(JvmtiError::InvalidThread),
62+
crate::sys::JVMTI_ERROR_INVALID_THREAD_GROUP => Some(JvmtiError::InvalidThreadGroup),
63+
crate::sys::JVMTI_ERROR_INVALID_PRIORITY => Some(JvmtiError::InvalidPriority),
64+
crate::sys::JVMTI_ERROR_THREAD_NOT_SUSPENDED => Some(JvmtiError::ThreadNotSuspended),
65+
crate::sys::JVMTI_ERROR_THREAD_SUSPENDED => Some(JvmtiError::ThreadSuspended),
66+
crate::sys::JVMTI_ERROR_THREAD_NOT_ALIVE => Some(JvmtiError::ThreadNotAlive),
67+
crate::sys::JVMTI_ERROR_INVALID_OBJECT => Some(JvmtiError::InvalidObject),
68+
crate::sys::JVMTI_ERROR_INVALID_CLASS => Some(JvmtiError::InvalidClass),
69+
crate::sys::JVMTI_ERROR_CLASS_NOT_PREPARED => Some(JvmtiError::ClassNotPrepared),
70+
crate::sys::JVMTI_ERROR_INVALID_METHODID => Some(JvmtiError::InvalidMethodId),
71+
crate::sys::JVMTI_ERROR_INVALID_LOCATION => Some(JvmtiError::InvalidLocation),
72+
crate::sys::JVMTI_ERROR_INVALID_FIELDID => Some(JvmtiError::InvalidFieldId),
73+
crate::sys::JVMTI_ERROR_INVALID_MODULE => Some(JvmtiError::InvalidModule),
74+
crate::sys::JVMTI_ERROR_NO_MORE_FRAMES => Some(JvmtiError::NoMoreFrames),
75+
crate::sys::JVMTI_ERROR_OPAQUE_FRAME => Some(JvmtiError::OpaqueFrame),
76+
crate::sys::JVMTI_ERROR_TYPE_MISMATCH => Some(JvmtiError::TypeMismatch),
77+
crate::sys::JVMTI_ERROR_INVALID_SLOT => Some(JvmtiError::InvalidSlot),
78+
crate::sys::JVMTI_ERROR_DUPLICATE => Some(JvmtiError::Duplicate),
79+
crate::sys::JVMTI_ERROR_NOT_FOUND => Some(JvmtiError::NotFound),
80+
crate::sys::JVMTI_ERROR_INVALID_MONITOR => Some(JvmtiError::InvalidMonitor),
81+
crate::sys::JVMTI_ERROR_NOT_MONITOR_OWNER => Some(JvmtiError::NotMonitorOwner),
82+
crate::sys::JVMTI_ERROR_INTERRUPT => Some(JvmtiError::Interrupt),
83+
crate::sys::JVMTI_ERROR_INVALID_CLASS_FORMAT => Some(JvmtiError::InvalidClassFormat),
84+
crate::sys::JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION => {
85+
Some(JvmtiError::CircularClassDefinition)
86+
},
87+
crate::sys::JVMTI_ERROR_FAILS_VERIFICATION => Some(JvmtiError::FailsVerification),
88+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED => {
89+
Some(JvmtiError::UnsupportedRedefinitionMethodAdded)
90+
},
91+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED => {
92+
Some(JvmtiError::UnsupportedRedefinitionSchemaChanged)
93+
},
94+
crate::sys::JVMTI_ERROR_INVALID_TYPESTATE => Some(JvmtiError::InvalidTypestate),
95+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED => {
96+
Some(JvmtiError::UnsupportedRedefinitionHierarchyChanged)
97+
},
98+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED => {
99+
Some(JvmtiError::UnsupportedRedefinitionMethodDeleted)
100+
},
101+
crate::sys::JVMTI_ERROR_UNSUPPORTED_VERSION => Some(JvmtiError::UnsupportedVersion),
102+
crate::sys::JVMTI_ERROR_NAMES_DONT_MATCH => Some(JvmtiError::NamesDontMatch),
103+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED => {
104+
Some(JvmtiError::UnsupportedRedefinitionClassModifiersChanged)
105+
},
106+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED => {
107+
Some(JvmtiError::UnsupportedRedefinitionMethodModifiersChanged)
108+
},
109+
crate::sys::JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED => {
110+
Some(JvmtiError::UnsupportedRedefinitionClassAttributeChanged)
111+
},
112+
crate::sys::JVMTI_ERROR_UNSUPPORTED_OPERATION => Some(JvmtiError::UnsupportedOperation),
113+
crate::sys::JVMTI_ERROR_UNMODIFIABLE_CLASS => Some(JvmtiError::UnmodifiableClass),
114+
crate::sys::JVMTI_ERROR_UNMODIFIABLE_MODULE => Some(JvmtiError::UnmodifiableModule),
115+
crate::sys::JVMTI_ERROR_NOT_AVAILABLE => Some(JvmtiError::NotAvailable),
116+
crate::sys::JVMTI_ERROR_MUST_POSSESS_CAPABILITY => {
117+
Some(JvmtiError::MustPossessCapability)
118+
},
119+
crate::sys::JVMTI_ERROR_NULL_POINTER => Some(JvmtiError::NullPointer),
120+
crate::sys::JVMTI_ERROR_ABSENT_INFORMATION => Some(JvmtiError::AbsentInformation),
121+
crate::sys::JVMTI_ERROR_INVALID_EVENT_TYPE => Some(JvmtiError::InvalidEventType),
122+
crate::sys::JVMTI_ERROR_ILLEGAL_ARGUMENT => Some(JvmtiError::IllegalArgument),
123+
crate::sys::JVMTI_ERROR_NATIVE_METHOD => Some(JvmtiError::NativeMethod),
124+
crate::sys::JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED => {
125+
Some(JvmtiError::ClassLoaderUnsupported)
126+
},
127+
crate::sys::JVMTI_ERROR_OUT_OF_MEMORY => Some(JvmtiError::OutOfMemory),
128+
crate::sys::JVMTI_ERROR_ACCESS_DENIED => Some(JvmtiError::AccessDenied),
129+
crate::sys::JVMTI_ERROR_WRONG_PHASE => Some(JvmtiError::WrongPhase),
130+
crate::sys::JVMTI_ERROR_INTERNAL => Some(JvmtiError::Internal),
131+
crate::sys::JVMTI_ERROR_UNATTACHED_THREAD => Some(JvmtiError::UnattachedThread),
132+
crate::sys::JVMTI_ERROR_INVALID_ENVIRONMENT => Some(JvmtiError::InvalidEnvironment),
133+
_ => None,
134+
}
135+
}
136+
}

jvmti/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pub mod env;
2+
pub mod error;
3+
4+
/// `jvmti_sys` re-exports
5+
pub mod sys {
6+
pub use jvmti_sys::*;
7+
}

jvmti/sys/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "jvmti_sys"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
jni_sys.workspace = true

jvmti/sys/build.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::ffi::c_int;
2+
use std::path::Path;
3+
4+
const JVMTI_VERSION_BASE: c_int = 0x30000000;
5+
6+
fn main() {
7+
println!("cargo:rerun-if-env-changed=JAVA_VERSION");
8+
9+
let Ok(java_version) = std::env::var("JAVA_VERSION") else {
10+
panic!("`JAVA_VERSION` environment variable must be set")
11+
};
12+
13+
let version_path = Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap())
14+
.join("src")
15+
.join("version.rs");
16+
let version_fn = format!(
17+
"pub(crate) const fn jvmti_version() -> std::ffi::c_int {{ {JVMTI_VERSION_BASE:#X} + \
18+
({java_version} * 0x10000) }}\n"
19+
);
20+
21+
std::fs::write(version_path, version_fn).unwrap();
22+
}

0 commit comments

Comments
 (0)