|
15 | 15 |
|
16 | 16 | use binaryninjacore_sys::*;
|
17 | 17 |
|
| 18 | +use crate::architecture::Architecture; |
| 19 | +use crate::architecture::CoreArchitecture; |
| 20 | +use crate::basic_block::BasicBlock; |
| 21 | +use crate::function::NativeBlock; |
| 22 | +use crate::high_level_il as hlil; |
| 23 | +use crate::low_level_il as llil; |
| 24 | +use crate::medium_level_il as mlil; |
| 25 | +use crate::string::BnStrCompatible; |
18 | 26 | use crate::string::{raw_to_string, strings_to_string_list, BnString};
|
19 | 27 |
|
20 | 28 | use crate::rc::*;
|
21 | 29 |
|
22 | 30 | use crate::confidence::MAX_CONFIDENCE;
|
23 |
| -use crate::function::HighlightColor; |
| 31 | +use crate::function::{Function, HighlightColor}; |
24 | 32 | use crate::tags::Tag;
|
25 | 33 | use crate::types::Type;
|
| 34 | +use crate::variable::StackVariableReference; |
| 35 | + |
26 | 36 | use std::convert::From;
|
| 37 | +use std::ffi; |
27 | 38 | use std::fmt::{Display, Formatter};
|
| 39 | +use std::ptr; |
28 | 40 |
|
29 | 41 | pub type DisassemblyOption = BNDisassemblyOption;
|
30 | 42 | pub type InstructionTextTokenType = BNInstructionTextTokenType;
|
@@ -1005,3 +1017,298 @@ unsafe impl RefCountable for DisassemblySettings {
|
1005 | 1017 | BNFreeDisassemblySettings(handle.handle);
|
1006 | 1018 | }
|
1007 | 1019 | }
|
| 1020 | + |
| 1021 | +#[repr(transparent)] |
| 1022 | +pub struct DisassemblyTextRenderer { |
| 1023 | + handle: ptr::NonNull<BNDisassemblyTextRenderer>, |
| 1024 | +} |
| 1025 | + |
| 1026 | +impl DisassemblyTextRenderer { |
| 1027 | + pub unsafe fn from_raw(handle: ptr::NonNull<BNDisassemblyTextRenderer>) -> Self { |
| 1028 | + Self { handle } |
| 1029 | + } |
| 1030 | + |
| 1031 | + #[allow(clippy::mut_from_ref)] |
| 1032 | + pub unsafe fn as_raw(&self) -> &mut BNDisassemblyTextRenderer { |
| 1033 | + unsafe { &mut *self.handle.as_ptr() } |
| 1034 | + } |
| 1035 | + |
| 1036 | + pub fn from_function(func: &Function, settings: Option<&DisassemblySettings>) -> Self { |
| 1037 | + let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); |
| 1038 | + let result = unsafe { BNCreateDisassemblyTextRenderer(func.handle, settings_ptr) }; |
| 1039 | + unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) } |
| 1040 | + } |
| 1041 | + |
| 1042 | + pub fn from_llil_function< |
| 1043 | + A: Architecture, |
| 1044 | + M: llil::function::FunctionMutability, |
| 1045 | + F: llil::function::FunctionForm, |
| 1046 | + >( |
| 1047 | + func: &llil::function::LowLevelILFunction<A, M, F>, |
| 1048 | + settings: Option<&DisassemblySettings>, |
| 1049 | + ) -> Self { |
| 1050 | + let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); |
| 1051 | + let result = |
| 1052 | + unsafe { BNCreateLowLevelILDisassemblyTextRenderer(func.handle, settings_ptr) }; |
| 1053 | + unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) } |
| 1054 | + } |
| 1055 | + |
| 1056 | + pub fn from_mlil_function( |
| 1057 | + func: &mlil::MediumLevelILFunction, |
| 1058 | + settings: Option<&DisassemblySettings>, |
| 1059 | + ) -> Self { |
| 1060 | + let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); |
| 1061 | + let result = |
| 1062 | + unsafe { BNCreateMediumLevelILDisassemblyTextRenderer(func.handle, settings_ptr) }; |
| 1063 | + unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) } |
| 1064 | + } |
| 1065 | + |
| 1066 | + pub fn from_hlil_function( |
| 1067 | + func: &hlil::HighLevelILFunction, |
| 1068 | + settings: Option<&DisassemblySettings>, |
| 1069 | + ) -> Self { |
| 1070 | + let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); |
| 1071 | + let result = |
| 1072 | + unsafe { BNCreateHighLevelILDisassemblyTextRenderer(func.handle, settings_ptr) }; |
| 1073 | + unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) } |
| 1074 | + } |
| 1075 | + |
| 1076 | + pub fn function(&self) -> Ref<Function> { |
| 1077 | + let result = unsafe { BNGetDisassemblyTextRendererFunction(self.as_raw()) }; |
| 1078 | + assert!(!result.is_null()); |
| 1079 | + unsafe { Function::ref_from_raw(result) } |
| 1080 | + } |
| 1081 | + |
| 1082 | + pub fn llil_function<M: llil::function::FunctionMutability, F: llil::function::FunctionForm>( |
| 1083 | + &self, |
| 1084 | + ) -> Ref<llil::function::LowLevelILFunction<CoreArchitecture, M, F>> { |
| 1085 | + let arch = self.arch(); |
| 1086 | + let result = unsafe { BNGetDisassemblyTextRendererLowLevelILFunction(self.as_raw()) }; |
| 1087 | + assert!(!result.is_null()); |
| 1088 | + unsafe { llil::function::LowLevelILFunction::ref_from_raw(arch.handle(), result) } |
| 1089 | + } |
| 1090 | + |
| 1091 | + pub fn mlil_function(&self) -> Ref<mlil::MediumLevelILFunction> { |
| 1092 | + let result = unsafe { BNGetDisassemblyTextRendererMediumLevelILFunction(self.as_raw()) }; |
| 1093 | + assert!(!result.is_null()); |
| 1094 | + unsafe { mlil::MediumLevelILFunction::ref_from_raw(result) } |
| 1095 | + } |
| 1096 | + |
| 1097 | + pub fn hlil_function(&self) -> Ref<hlil::HighLevelILFunction> { |
| 1098 | + let result = unsafe { BNGetDisassemblyTextRendererHighLevelILFunction(self.as_raw()) }; |
| 1099 | + assert!(!result.is_null()); |
| 1100 | + unsafe { hlil::HighLevelILFunction::ref_from_raw(result, true) } |
| 1101 | + } |
| 1102 | + |
| 1103 | + pub fn basic_block(&self) -> Option<Ref<BasicBlock<NativeBlock>>> { |
| 1104 | + let result = unsafe { BNGetDisassemblyTextRendererBasicBlock(self.as_raw()) }; |
| 1105 | + if result.is_null() { |
| 1106 | + return None; |
| 1107 | + } |
| 1108 | + Some(unsafe { Ref::new(BasicBlock::from_raw(result, NativeBlock::new())) }) |
| 1109 | + } |
| 1110 | + |
| 1111 | + pub fn set_basic_block(&self, value: Option<&BasicBlock<NativeBlock>>) { |
| 1112 | + let block_ptr = value.map(|b| b.handle).unwrap_or(ptr::null_mut()); |
| 1113 | + unsafe { BNSetDisassemblyTextRendererBasicBlock(self.as_raw(), block_ptr) } |
| 1114 | + } |
| 1115 | + |
| 1116 | + pub fn arch(&self) -> CoreArchitecture { |
| 1117 | + let result = unsafe { BNGetDisassemblyTextRendererArchitecture(self.as_raw()) }; |
| 1118 | + assert!(!result.is_null()); |
| 1119 | + unsafe { CoreArchitecture::from_raw(result) } |
| 1120 | + } |
| 1121 | + |
| 1122 | + pub fn set_arch(&self, value: CoreArchitecture) { |
| 1123 | + unsafe { BNSetDisassemblyTextRendererArchitecture(self.as_raw(), value.handle) } |
| 1124 | + } |
| 1125 | + |
| 1126 | + pub fn settings(&self) -> DisassemblySettings { |
| 1127 | + DisassemblySettings { |
| 1128 | + handle: unsafe { BNGetDisassemblyTextRendererSettings(self.as_raw()) }, |
| 1129 | + } |
| 1130 | + } |
| 1131 | + |
| 1132 | + pub fn set_settings(&self, settings: Option<&DisassemblySettings>) { |
| 1133 | + let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); |
| 1134 | + unsafe { BNSetDisassemblyTextRendererSettings(self.as_raw(), settings_ptr) } |
| 1135 | + } |
| 1136 | + |
| 1137 | + pub fn is_il(&self) -> bool { |
| 1138 | + unsafe { BNIsILDisassemblyTextRenderer(self.as_raw()) } |
| 1139 | + } |
| 1140 | + |
| 1141 | + pub fn has_data_flow(&self) -> bool { |
| 1142 | + unsafe { BNDisassemblyTextRendererHasDataFlow(self.as_raw()) } |
| 1143 | + } |
| 1144 | + |
| 1145 | + pub fn instruction_annotations(&self, addr: u64) -> Array<InstructionTextToken> { |
| 1146 | + let mut count = 0; |
| 1147 | + let result = unsafe { |
| 1148 | + BNGetDisassemblyTextRendererInstructionAnnotations(self.as_raw(), addr, &mut count) |
| 1149 | + }; |
| 1150 | + assert!(!result.is_null()); |
| 1151 | + unsafe { Array::new(result, count, ()) } |
| 1152 | + } |
| 1153 | + |
| 1154 | + pub fn instruction_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> { |
| 1155 | + let mut count = 0; |
| 1156 | + let mut length = 0; |
| 1157 | + let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut(); |
| 1158 | + let result = unsafe { |
| 1159 | + BNGetDisassemblyTextRendererInstructionText( |
| 1160 | + self.as_raw(), |
| 1161 | + addr, |
| 1162 | + &mut length, |
| 1163 | + &mut lines, |
| 1164 | + &mut count, |
| 1165 | + ) |
| 1166 | + }; |
| 1167 | + result.then(|| (unsafe { Array::new(lines, count, ()) }, length)) |
| 1168 | + } |
| 1169 | + |
| 1170 | + pub fn disassembly_text(&self, addr: u64) -> Option<(Array<DisassemblyTextLine>, usize)> { |
| 1171 | + let mut count = 0; |
| 1172 | + let mut length = 0; |
| 1173 | + let mut lines: *mut BNDisassemblyTextLine = ptr::null_mut(); |
| 1174 | + let result = unsafe { |
| 1175 | + BNGetDisassemblyTextRendererLines( |
| 1176 | + self.as_raw(), |
| 1177 | + addr, |
| 1178 | + &mut length, |
| 1179 | + &mut lines, |
| 1180 | + &mut count, |
| 1181 | + ) |
| 1182 | + }; |
| 1183 | + result.then(|| (unsafe { Array::new(lines, count, ()) }, length)) |
| 1184 | + } |
| 1185 | + |
| 1186 | + // TODO post_process_lines BNPostProcessDisassemblyTextRendererLines |
| 1187 | + |
| 1188 | + pub fn is_integer_token(token_type: InstructionTextTokenType) -> bool { |
| 1189 | + unsafe { BNIsIntegerToken(token_type) } |
| 1190 | + } |
| 1191 | + |
| 1192 | + pub fn reset_deduplicated_comments(&self) { |
| 1193 | + unsafe { BNResetDisassemblyTextRendererDeduplicatedComments(self.as_raw()) } |
| 1194 | + } |
| 1195 | + |
| 1196 | + pub fn symbol_tokens( |
| 1197 | + &self, |
| 1198 | + addr: u64, |
| 1199 | + size: usize, |
| 1200 | + operand: Option<usize>, |
| 1201 | + ) -> Option<Array<InstructionTextToken>> { |
| 1202 | + let operand = operand.unwrap_or(0xffffffff); |
| 1203 | + let mut count = 0; |
| 1204 | + let mut tokens: *mut BNInstructionTextToken = ptr::null_mut(); |
| 1205 | + let result = unsafe { |
| 1206 | + BNGetDisassemblyTextRendererSymbolTokens( |
| 1207 | + self.as_raw(), |
| 1208 | + addr, |
| 1209 | + size, |
| 1210 | + operand, |
| 1211 | + &mut tokens, |
| 1212 | + &mut count, |
| 1213 | + ) |
| 1214 | + }; |
| 1215 | + result.then(|| unsafe { Array::new(tokens, count, ()) }) |
| 1216 | + } |
| 1217 | + |
| 1218 | + pub fn stack_var_reference_tokens( |
| 1219 | + &self, |
| 1220 | + ref_: &StackVariableReference, |
| 1221 | + ) -> Array<InstructionTextToken> { |
| 1222 | + let name = ref_.name.clone().into_bytes_with_nul(); |
| 1223 | + let mut stack_ref = StackVariableReference::into_raw(ref_.clone()); |
| 1224 | + let mut count = 0; |
| 1225 | + let tokens = unsafe { |
| 1226 | + BNGetDisassemblyTextRendererStackVariableReferenceTokens( |
| 1227 | + self.as_raw(), |
| 1228 | + &mut stack_ref, |
| 1229 | + &mut count, |
| 1230 | + ) |
| 1231 | + }; |
| 1232 | + assert!(!tokens.is_null()); |
| 1233 | + unsafe { Array::new(tokens, count, ()) } |
| 1234 | + } |
| 1235 | + |
| 1236 | + pub fn integer_token( |
| 1237 | + &self, |
| 1238 | + int_token: &InstructionTextToken, |
| 1239 | + addr: u64, |
| 1240 | + arch: Option<CoreArchitecture>, |
| 1241 | + ) -> Array<InstructionTextToken> { |
| 1242 | + let arch = arch.map(|a| a.handle).unwrap_or(ptr::null_mut()); |
| 1243 | + let mut count = 0; |
| 1244 | + let int_token_raw = InstructionTextToken::into_raw(int_token.clone()); |
| 1245 | + let tokens = unsafe { |
| 1246 | + BNGetDisassemblyTextRendererIntegerTokens( |
| 1247 | + self.as_raw(), |
| 1248 | + &int_token_raw as *const BNInstructionTextToken as *mut _, |
| 1249 | + arch, |
| 1250 | + addr, |
| 1251 | + &mut count, |
| 1252 | + ) |
| 1253 | + }; |
| 1254 | + assert!(!tokens.is_null()); |
| 1255 | + unsafe { Array::new(tokens, count, ()) } |
| 1256 | + } |
| 1257 | + |
| 1258 | + pub fn wrap_comment<S1: BnStrCompatible, S2: BnStrCompatible, S3: BnStrCompatible>( |
| 1259 | + &self, |
| 1260 | + cur_line: &DisassemblyTextLine, |
| 1261 | + comment: S1, |
| 1262 | + has_auto_annotations: bool, |
| 1263 | + leading_spaces: S2, |
| 1264 | + indent_spaces: S3, |
| 1265 | + ) -> Array<DisassemblyTextLine> { |
| 1266 | + //// //leading_spaces: str = " ", indent_spaces: str = "" |
| 1267 | + let mut tokens_raw: Vec<_> = cur_line |
| 1268 | + .tokens |
| 1269 | + .iter() |
| 1270 | + .map(|x| InstructionTextToken::into_raw(x.clone())) |
| 1271 | + .collect(); |
| 1272 | + let mut cur_line_obj = BNDisassemblyTextLine { |
| 1273 | + addr: cur_line.address, |
| 1274 | + instrIndex: cur_line.instruction_index, |
| 1275 | + tokens: tokens_raw.as_mut_ptr(), |
| 1276 | + count: cur_line.tokens.len(), |
| 1277 | + highlight: cur_line.highlight.into(), |
| 1278 | + ..Default::default() |
| 1279 | + }; |
| 1280 | + let mut count = 0; |
| 1281 | + let comment_raw = comment.into_bytes_with_nul(); |
| 1282 | + let leading_spaces_raw = leading_spaces.into_bytes_with_nul(); |
| 1283 | + let indent_spaces_raw = indent_spaces.into_bytes_with_nul(); |
| 1284 | + let lines = unsafe { |
| 1285 | + BNDisassemblyTextRendererWrapComment( |
| 1286 | + self.as_raw(), |
| 1287 | + &mut cur_line_obj, |
| 1288 | + &mut count, |
| 1289 | + comment_raw.as_ref().as_ptr() as *const ffi::c_char, |
| 1290 | + has_auto_annotations, |
| 1291 | + leading_spaces_raw.as_ref().as_ptr() as *const ffi::c_char, |
| 1292 | + indent_spaces_raw.as_ref().as_ptr() as *const ffi::c_char, |
| 1293 | + ) |
| 1294 | + }; |
| 1295 | + assert!(!lines.is_null()); |
| 1296 | + unsafe { Array::new(lines, count, ()) } |
| 1297 | + } |
| 1298 | +} |
| 1299 | + |
| 1300 | +impl Clone for DisassemblyTextRenderer { |
| 1301 | + fn clone(&self) -> Self { |
| 1302 | + unsafe { |
| 1303 | + Self::from_raw( |
| 1304 | + ptr::NonNull::new(BNNewDisassemblyTextRendererReference(self.as_raw())).unwrap(), |
| 1305 | + ) |
| 1306 | + } |
| 1307 | + } |
| 1308 | +} |
| 1309 | + |
| 1310 | +impl Drop for DisassemblyTextRenderer { |
| 1311 | + fn drop(&mut self) { |
| 1312 | + unsafe { BNFreeDisassemblyTextRenderer(self.as_raw()) } |
| 1313 | + } |
| 1314 | +} |
0 commit comments