1use binaryninjacore_sys::{
6 BNLlvmServicesAssemble, BNLlvmServicesAssembleFree, BNLlvmServicesDisasmInstruction,
7 BNLlvmServicesInit,
8};
9use std::ffi::{CStr, CString};
10use std::os::raw::{c_char, c_int};
11
12#[repr(i32)]
13pub enum LlvmServicesDialect {
14 Unspecified = 0,
15 Att = 1,
16 Intel = 2,
17}
18
19#[repr(i32)]
20pub enum LlvmServicesCodeModel {
21 Default = 0,
22 Small = 1,
23 Kernel = 2,
24 Medium = 3,
25 Large = 4,
26}
27
28#[repr(i32)]
29pub enum LlvmServicesRelocMode {
30 Static = 0,
31 PIC = 1,
32 DynamicNoPIC = 2,
33}
34
35pub fn llvm_assemble(
36 code: &str,
37 dialect: LlvmServicesDialect,
38 triplet: &str,
39 code_model: LlvmServicesCodeModel,
40 reloc_mode: LlvmServicesRelocMode,
41) -> Result<Vec<u8>, String> {
42 let code = CString::new(code).map_err(|_| "Invalid encoding in code string".to_string())?;
43 let arch_triple = CString::new(triplet)
44 .map_err(|_| "Invalid encoding in architecture triple string".to_string())?;
45 let mut out_bytes: *mut std::ffi::c_char = std::ptr::null_mut();
46 let mut out_bytes_len: std::ffi::c_int = 0;
47 let mut err_bytes: *mut std::ffi::c_char = std::ptr::null_mut();
48 let mut err_len: std::ffi::c_int = 0;
49
50 unsafe {
51 BNLlvmServicesInit();
52 }
53
54 let result = unsafe {
55 BNLlvmServicesAssemble(
56 code.as_ptr(),
57 dialect as i32,
58 arch_triple.as_ptr(),
59 code_model as i32,
60 reloc_mode as i32,
61 &mut out_bytes as *mut *mut std::ffi::c_char,
62 &mut out_bytes_len as *mut std::ffi::c_int,
63 &mut err_bytes as *mut *mut std::ffi::c_char,
64 &mut err_len as *mut std::ffi::c_int,
65 )
66 };
67
68 let out = if out_bytes_len == 0 {
69 Vec::new()
70 } else {
71 unsafe {
72 std::slice::from_raw_parts(
73 out_bytes as *const std::ffi::c_char as *const u8,
74 out_bytes_len as usize,
75 )
76 }
77 .to_vec()
78 };
79
80 let errors = if err_len == 0 {
81 "".into()
82 } else {
83 String::from_utf8_lossy(unsafe {
84 std::slice::from_raw_parts(
85 err_bytes as *const std::ffi::c_char as *const u8,
86 err_len as usize,
87 )
88 })
89 .into_owned()
90 };
91
92 unsafe {
93 BNLlvmServicesAssembleFree(out_bytes, err_bytes);
94 }
95
96 if result == 0 {
97 Ok(out)
98 } else {
99 Err(errors)
100 }
101}
102
103pub fn llvm_disassemble(triplet: &str, data: &[u8], address: u64) -> Option<(usize, String)> {
104 unsafe {
105 let triplet = CString::new(triplet).ok()?;
106 let mut src = data.to_vec();
107 let mut buf = vec![0u8; 256];
108 let instr_len = BNLlvmServicesDisasmInstruction(
109 triplet.as_ptr(),
110 src.as_mut_ptr(),
111 src.len() as c_int,
112 address,
113 buf.as_mut_ptr() as *mut c_char,
114 buf.len(),
115 );
116
117 if instr_len > 0 {
118 if let Some(z) = buf.iter().position(|&b| b == 0) {
120 let s = CStr::from_bytes_with_nul(&buf[..=z])
121 .unwrap()
122 .to_string_lossy()
123 .into_owned();
124 Some((instr_len as usize, s))
125 } else {
126 Some((instr_len as usize, String::new()))
128 }
129 } else {
130 None
131 }
132 }
133}