Skip to content
This repository was archived by the owner on Aug 4, 2024. It is now read-only.

Commit b3a7bed

Browse files
committed
properly handle errors when getting a CapstoneContext instance from Java
1 parent 4404f21 commit b3a7bed

File tree

4 files changed

+189
-99
lines changed

4 files changed

+189
-99
lines changed

lib/src/capstone/context.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ impl CapstoneContext {
3232
}
3333

3434
/// Clones an Arc out of the handle field of the given object.
35-
pub fn get(env: &mut JNIEnv, object: &JObject) -> Arc<CapstoneContext> {
35+
pub fn get(env: &mut JNIEnv, object: &JObject) -> JResult<Arc<CapstoneContext>> {
3636
let guard: MutexGuard<Arc<CapstoneContext>> =
37-
unsafe { env.get_rust_field(object, HANDLE_FIELD).unwrap() };
38-
guard.clone()
37+
unsafe { env.get_rust_field(object, HANDLE_FIELD)? };
38+
Ok(guard.clone())
3939
}
4040

4141
/// Surrenders ownership of the context instance to Java.

lib/src/capstone/mod.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,110 @@
33
*
44
* Use of this source code is governed by the MIT license found in the LICENSE file.
55
*/
6+
use crate::capstone::context::CapstoneContext;
7+
use crate::capstone::mode::CapstoneMode;
8+
use crate::capstone::output::CapstoneOutput;
9+
use capstone::arch::BuildsCapstone;
10+
use capstone::{arch, Capstone, InsnGroupId, InsnGroupIdInt, InsnId, InsnIdInt, RegId, RegIdInt};
11+
use jni::objects::{JByteArray, JObject, ReleaseMode};
12+
use jni::sys::{jint, jlong, jshort};
13+
use jni::JNIEnv;
14+
use std::ops::BitAnd;
15+
616
pub mod context;
717
pub mod mode;
818
pub mod output;
19+
20+
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
21+
22+
pub fn init<'local>(
23+
env: &mut JNIEnv<'local>,
24+
this: JObject<'local>,
25+
mode: JObject<'local>,
26+
) -> Result<()> {
27+
let mode = CapstoneMode::from(env, &mode);
28+
29+
let capstone = match mode {
30+
Some(CapstoneMode::ARM32) => Capstone::new()
31+
.arm()
32+
.mode(arch::arm::ArchMode::Arm)
33+
.detail(true)
34+
.build(),
35+
Some(CapstoneMode::ARM64) => Capstone::new()
36+
.arm64()
37+
.mode(arch::arm64::ArchMode::Arm)
38+
.detail(true)
39+
.build(),
40+
_ => return Err("invalid argument 'mode'".into()),
41+
}
42+
.map_err(|e| e.to_string())?;
43+
44+
let instance = CapstoneContext::new(capstone, mode.unwrap());
45+
46+
CapstoneContext::surrender_instance(instance, env, &this)?;
47+
Ok(())
48+
}
49+
50+
pub fn disassemble<'local>(
51+
env: &mut JNIEnv<'local>,
52+
this: JObject<'local>,
53+
result_object: JObject<'local>,
54+
data: JByteArray<'local>,
55+
count: jint,
56+
address: jlong,
57+
) -> Result<()> {
58+
let code: Vec<u8> = {
59+
let result = unsafe { env.get_array_elements(&data, ReleaseMode::NoCopyBack)? };
60+
result.iter().map(|b| (*b as u8).bitand(0xff)).collect()
61+
};
62+
63+
let ctx = CapstoneContext::get(env, &this)?;
64+
let capstone = ctx.capstone.lock().unwrap();
65+
66+
let instructions = {
67+
if count == 0 {
68+
capstone.disasm_all(&code, address as u64)
69+
} else {
70+
capstone.disasm_count(&code, address as u64, count as usize)
71+
}
72+
.map_err(|e| e.to_string())?
73+
};
74+
75+
let mut output = CapstoneOutput::new(env, &ctx.mode, &capstone, &result_object);
76+
output.copy_instructions(instructions)
77+
}
78+
79+
pub fn get_insn_name<'local>(
80+
env: &mut JNIEnv<'local>,
81+
this: JObject<'local>,
82+
insn_id: jint,
83+
) -> Result<Option<String>> {
84+
let ctx = CapstoneContext::get(env, &this)?;
85+
let capstone = ctx.capstone.lock().unwrap();
86+
Ok(capstone.insn_name(InsnId(insn_id as InsnIdInt)))
87+
}
88+
89+
pub fn get_reg_name<'local>(
90+
env: &mut JNIEnv<'local>,
91+
this: JObject<'local>,
92+
reg_id: jint,
93+
) -> Result<Option<String>> {
94+
let ctx = CapstoneContext::get(env, &this)?;
95+
let capstone = ctx.capstone.lock().unwrap();
96+
Ok(capstone.reg_name(RegId(reg_id as RegIdInt)))
97+
}
98+
99+
pub fn get_group_name<'local>(
100+
env: &mut JNIEnv<'local>,
101+
this: JObject<'local>,
102+
group_id: jshort,
103+
) -> Result<Option<String>> {
104+
let ctx = CapstoneContext::get(env, &this)?;
105+
let capstone = ctx.capstone.lock().unwrap();
106+
Ok(capstone.group_name(InsnGroupId(group_id as InsnGroupIdInt)))
107+
}
108+
109+
pub fn throw(env: &mut JNIEnv, message: &str) {
110+
env.throw_new("org/native4j/capstone/exception/CapstoneException", message)
111+
.unwrap();
112+
}

lib/src/lib.rs

Lines changed: 28 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,25 @@
33
*
44
* Use of this source code is governed by the MIT license found in the LICENSE file.
55
*/
6-
use std::ops::BitAnd;
7-
8-
use ::capstone::arch::BuildsCapstone;
9-
use ::capstone::{arch, Capstone, InsnGroupId, InsnGroupIdInt, InsnId, InsnIdInt, RegId, RegIdInt};
10-
use jni::objects::{JByteArray, JObject, ReleaseMode};
6+
use jni::objects::{JByteArray, JObject};
117
use jni::sys::{jint, jlong, jshort, jstring};
128
use jni::JNIEnv;
139

1410
use crate::capstone::context::CapstoneContext;
15-
use crate::capstone::mode::CapstoneMode;
16-
use crate::capstone::output::CapstoneOutput;
1711

1812
mod capstone;
1913
mod obj;
2014
mod util;
2115
mod writer;
16+
2217
#[no_mangle]
2318
pub extern "system" fn Java_org_native4j_capstone_Capstone_init<'local>(
2419
mut env: JNIEnv<'local>,
2520
this: JObject<'local>,
2621
mode: JObject<'local>,
2722
) -> jstring {
28-
let mode = CapstoneMode::from(&mut env, &mode);
29-
30-
let capstone = match mode {
31-
Some(CapstoneMode::ARM32) => Capstone::new()
32-
.arm()
33-
.mode(arch::arm::ArchMode::Arm)
34-
.detail(true)
35-
.build(),
36-
Some(CapstoneMode::ARM64) => Capstone::new()
37-
.arm64()
38-
.mode(arch::arm64::ArchMode::Arm)
39-
.detail(true)
40-
.build(),
41-
_ => return make_error!(env, "invalid argument 'mode'"),
42-
};
43-
check_result!(env, capstone);
44-
45-
let instance = CapstoneContext::new(capstone.unwrap(), mode.unwrap());
46-
47-
let result = CapstoneContext::surrender_instance(instance, &mut env, &this);
23+
let result = capstone::init(&mut env, this, mode);
4824
check_result!(env, result);
49-
5025
0 as jstring /* null */
5126
}
5227

@@ -57,7 +32,6 @@ pub extern "system" fn Java_org_native4j_capstone_Capstone_shutdown<'local>(
5732
) -> jstring {
5833
let result = CapstoneContext::drop_instance(&mut env, &this);
5934
check_result!(env, result);
60-
6135
0 as jstring /* null */
6236
}
6337

@@ -70,36 +44,8 @@ pub extern "system" fn Java_org_native4j_capstone_Capstone_disassemble<'local>(
7044
count: jint,
7145
address: jlong,
7246
) -> jstring {
73-
let code: Vec<u8> = {
74-
let result = unsafe { env.get_array_elements(&data, ReleaseMode::NoCopyBack) };
75-
check_result!(env, result);
76-
result
77-
.unwrap()
78-
.iter()
79-
.map(|b| (*b as u8).bitand(0xff))
80-
.collect()
81-
};
82-
83-
let ctx = CapstoneContext::get(&mut env, &this);
84-
let capstone = ctx.capstone.lock().unwrap();
85-
86-
let instructions = {
87-
let result = if count == 0 {
88-
capstone.disasm_all(&code, address as u64)
89-
} else {
90-
capstone.disasm_count(&code, address as u64, count as usize)
91-
};
92-
if let Err(e) = result {
93-
return make_error!(env, e.to_string());
94-
}
95-
result.unwrap()
96-
};
97-
98-
let mut output = CapstoneOutput::new(&mut env, &ctx.mode, &capstone, &result_object);
99-
100-
let result = output.copy_instructions(instructions);
47+
let result = capstone::disassemble(&mut env, this, result_object, data, count, address);
10148
check_result!(env, result);
102-
10349
0 as jstring /* null */
10450
}
10551

@@ -109,12 +55,15 @@ pub extern "system" fn Java_org_native4j_capstone_Capstone_getInsnName<'local>(
10955
this: JObject<'local>,
11056
insn_id: jint,
11157
) -> jstring {
112-
let ctx = CapstoneContext::get(&mut env, &this);
113-
let capstone = ctx.capstone.lock().unwrap();
114-
match capstone.insn_name(InsnId(insn_id as InsnIdInt)) {
115-
Some(str) => make_jstring!(env, str),
116-
None => 0 as jstring, /* null */
58+
let result = capstone::get_insn_name(&mut env, this, insn_id);
59+
if let Err(e) = result {
60+
capstone::throw(&mut env, &e.to_string());
61+
return 0 as jstring /* null */;
11762
}
63+
result
64+
.unwrap()
65+
.map(|str| make_jstring!(env, str))
66+
.unwrap_or(0 as jstring /* null */)
11867
}
11968

12069
#[no_mangle]
@@ -123,12 +72,15 @@ pub extern "system" fn Java_org_native4j_capstone_Capstone_getRegName<'local>(
12372
this: JObject<'local>,
12473
reg_id: jint,
12574
) -> jstring {
126-
let ctx = CapstoneContext::get(&mut env, &this);
127-
let capstone = ctx.capstone.lock().unwrap();
128-
match capstone.reg_name(RegId(reg_id as RegIdInt)) {
129-
Some(str) => make_jstring!(env, str),
130-
None => 0 as jstring, /* null */
75+
let result = capstone::get_reg_name(&mut env, this, reg_id);
76+
if let Err(e) = result {
77+
capstone::throw(&mut env, &e.to_string());
78+
return 0 as jstring /* null */;
13179
}
80+
result
81+
.unwrap()
82+
.map(|str| make_jstring!(env, str))
83+
.unwrap_or(0 as jstring /* null */)
13284
}
13385

13486
#[no_mangle]
@@ -137,10 +89,13 @@ pub extern "system" fn Java_org_native4j_capstone_Capstone_getGroupName<'local>(
13789
this: JObject<'local>,
13890
group_id: jshort,
13991
) -> jstring {
140-
let ctx = CapstoneContext::get(&mut env, &this);
141-
let capstone = ctx.capstone.lock().unwrap();
142-
match capstone.group_name(InsnGroupId(group_id as InsnGroupIdInt)) {
143-
Some(str) => make_jstring!(env, str),
144-
None => 0 as jstring, /* null */
92+
let result = capstone::get_group_name(&mut env, this, group_id);
93+
if let Err(e) = result {
94+
capstone::throw(&mut env, &e.to_string());
95+
return 0 as jstring /* null */;
14596
}
97+
result
98+
.unwrap()
99+
.map(|str| make_jstring!(env, str))
100+
.unwrap_or(0 as jstring /* null */)
146101
}

0 commit comments

Comments
 (0)