use jni::{JValue, jni_sig, jni_str, objects::JObject};
use crate::{Result, runtime::GhidraRuntime};
use super::{
lifecycle::attach_bridge,
support::{JavaHandle, find_bridge_class, java_optional_string, java_string, jni_error},
};
pub(crate) fn instructions_for_function(
runtime: &GhidraRuntime,
program: JavaHandle,
function_address: &str,
) -> Result<String> {
string_string_operation(
runtime,
program,
function_address,
jni_str!("instructionsForFunction"),
"failed to list Ghidra function instructions",
)
}
pub(crate) fn instructions_in_range(
runtime: &GhidraRuntime,
program: JavaHandle,
start: &str,
end: &str,
) -> Result<String> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<String> {
let start = env.new_string(start)?;
let end = env.new_string(end)?;
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
jni_str!("instructionsInRange"),
jni_sig!("(JLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
&[
JValue::Long(program),
JValue::Object(&JObject::from(start)),
JValue::Object(&JObject::from(end)),
],
) {
Ok(value) => value,
Err(error) => {
return Err(jni_error(
env,
"failed to list Ghidra instructions in range",
error,
));
}
};
java_string(env, value.l()?)
})
}
pub(crate) fn instruction_at(
runtime: &GhidraRuntime,
program: JavaHandle,
address: &str,
) -> Result<Option<String>> {
optional_string_string_operation(
runtime,
program,
address,
jni_str!("instructionAt"),
"failed to read Ghidra instruction at address",
)
}
pub(crate) fn data_at(
runtime: &GhidraRuntime,
program: JavaHandle,
address: &str,
) -> Result<Option<String>> {
optional_string_string_operation(
runtime,
program,
address,
jni_str!("dataAt"),
"failed to read Ghidra data at address",
)
}
pub(crate) fn data_containing(
runtime: &GhidraRuntime,
program: JavaHandle,
address: &str,
) -> Result<Option<String>> {
optional_string_string_operation(
runtime,
program,
address,
jni_str!("dataContaining"),
"failed to read Ghidra data containing address",
)
}
fn string_string_operation(
runtime: &GhidraRuntime,
program: JavaHandle,
argument: &str,
method: &'static jni::strings::JNIStr,
context: &'static str,
) -> Result<String> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<String> {
let argument = env.new_string(argument)?;
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
method,
jni_sig!("(JLjava/lang/String;)Ljava/lang/String;"),
&[
JValue::Long(program),
JValue::Object(&JObject::from(argument)),
],
) {
Ok(value) => value,
Err(error) => return Err(jni_error(env, context, error)),
};
java_string(env, value.l()?)
})
}
fn optional_string_string_operation(
runtime: &GhidraRuntime,
program: JavaHandle,
argument: &str,
method: &'static jni::strings::JNIStr,
context: &'static str,
) -> Result<Option<String>> {
attach_bridge(runtime)?;
runtime.with_attached(|env| -> Result<Option<String>> {
let argument = env.new_string(argument)?;
let class = find_bridge_class(env)?;
let value = match env.call_static_method(
class,
method,
jni_sig!("(JLjava/lang/String;)Ljava/lang/String;"),
&[
JValue::Long(program),
JValue::Object(&JObject::from(argument)),
],
) {
Ok(value) => value,
Err(error) => return Err(jni_error(env, context, error)),
};
java_optional_string(env, value.l()?)
})
}