use jni::{JValue, jni_sig, jni_str, objects::JObject};
use crate::{DecompileOptions, Result, runtime::GhidraRuntime};
use super::{
lifecycle::attach_bridge,
support::{
JavaHandle, find_bridge_class, java_int, java_monitor_timeout_seconds, java_string,
jni_error,
},
};
pub(crate) fn open_decompiler(runtime: &GhidraRuntime, program: JavaHandle) -> Result<JavaHandle> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<JavaHandle> {
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
jni_str!("openDecompiler"),
jni_sig!("(J)J"),
&[JValue::Long(program)],
) {
Ok(value) => value,
Err(error) => return Err(jni_error(env, "failed to open Ghidra decompiler", error)),
};
Ok(value.j()?)
})
}
pub(crate) fn close_decompiler(runtime: &GhidraRuntime, decompiler: JavaHandle) -> Result<()> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<()> {
let class = find_bridge_class(env)?;
match env.call_static_method(
class,
jni_str!("closeDecompiler"),
jni_sig!("(J)V"),
&[JValue::Long(decompiler)],
) {
Ok(_) => Ok(()),
Err(error) => Err(jni_error(env, "failed to close Ghidra decompiler", error)),
}
})
}
pub(crate) fn decompile_function(
runtime: &GhidraRuntime,
decompiler: JavaHandle,
function_address: &str,
options: DecompileOptions,
) -> Result<String> {
attach_bridge(runtime)?;
let timeout = java_int(options.timeout_seconds, "decompile timeout")?;
let monitor_timeout_seconds = java_monitor_timeout_seconds(&options.monitor)?;
runtime.with_attached(|env| -> Result<String> {
let function_address = env.new_string(function_address)?;
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
jni_str!("decompileFunction"),
jni_sig!("(JLjava/lang/String;II)Ljava/lang/String;"),
&[
JValue::Long(decompiler),
JValue::Object(&JObject::from(function_address)),
JValue::Int(timeout),
JValue::Int(monitor_timeout_seconds),
],
) {
Ok(value) => value,
Err(error) => return Err(jni_error(env, "failed to decompile Ghidra function", error)),
};
java_string(env, value.l()?)
})
}
pub(crate) fn decompiler_metadata(
runtime: &GhidraRuntime,
decompiler: JavaHandle,
) -> Result<String> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<String> {
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
jni_str!("decompilerMetadata"),
jni_sig!("(J)Ljava/lang/String;"),
&[JValue::Long(decompiler)],
) {
Ok(value) => value,
Err(error) => {
return Err(jni_error(
env,
"failed to extract Ghidra decompiler metadata",
error,
));
}
};
java_string(env, value.l()?)
})
}