From befef3d0b74aa893af30b07e30c21af42f3fef46 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Tue, 29 Apr 2025 16:05:54 -0400 Subject: [PATCH 01/54] [Rust] Pretty print LLIL sub expressions --- arch/msp430/src/architecture.rs | 1 + arch/riscv/disasm/src/lib.rs | 5 ++-- arch/riscv/src/lib.rs | 41 +++++++++++++++-------------- rust/src/architecture.rs | 3 ++- rust/src/low_level_il/expression.rs | 10 +++---- rust/src/low_level_il/function.rs | 6 ++--- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index 938e9ec580..ccc5ce80b9 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -25,6 +25,7 @@ use log::error; const MIN_MNEMONIC: usize = 9; +#[derive(Debug)] pub struct Msp430 { handle: CoreArchitecture, custom_handle: CustomArchitectureHandle, diff --git a/arch/riscv/disasm/src/lib.rs b/arch/riscv/disasm/src/lib.rs index a25516a627..959952eed8 100644 --- a/arch/riscv/disasm/src/lib.rs +++ b/arch/riscv/disasm/src/lib.rs @@ -291,7 +291,7 @@ impl FloatRegType for () {} impl FloatRegType for f32 {} impl FloatRegType for f64 {} -pub trait RegFile: Debug + Sized + Copy + Clone { +pub trait RegFile: Debug + Sized + Copy + Clone + Send + Sync + 'static { type Int: IntRegType; type Float: FloatRegType; @@ -2331,7 +2331,7 @@ impl StandardExtension for ExtensionSupported { } } -pub trait RiscVDisassembler: Debug + Sized + Copy + Clone { +pub trait RiscVDisassembler: 'static + Debug + Sized + Copy + Clone + Send + Sync { type RegFile: RegFile; type MulDivExtension: StandardExtension; type AtomicExtension: StandardExtension; @@ -3175,6 +3175,7 @@ pub trait RiscVDisassembler: Debug + Sized + Copy + Clone { #[derive(Copy, Clone, Debug)] pub struct RiscVIMACDisassembler(PhantomData); + impl RiscVDisassembler for RiscVIMACDisassembler { type RegFile = RF; type MulDivExtension = ExtensionSupported; diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 1abce973a4..6df34fd7cc 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -88,18 +88,18 @@ enum Intrinsic { } #[derive(Copy, Clone)] -struct Register { +struct Register { id: RegisterId, _dis: PhantomData, } #[derive(Debug, Copy, Clone)] -struct RiscVIntrinsic { +struct RiscVIntrinsic { id: Intrinsic, _dis: PhantomData, } -impl Register { +impl Register { fn new(id: RegisterId) -> Self { Self { id, @@ -118,7 +118,7 @@ impl Register { } } -impl From> for Register { +impl From> for Register { fn from(reg: riscv_dis::IntReg) -> Self { Self { id: RegisterId(reg.id()), @@ -127,7 +127,7 @@ impl From> for Register } } -impl From> for Register { +impl From> for Register { fn from(reg: FloatReg) -> Self { let int_reg_count = ::int_reg_count(); @@ -138,13 +138,13 @@ impl From> for Register { } } -impl From> for LowLevelILRegister> { +impl From> for LowLevelILRegister> { fn from(reg: Register) -> Self { LowLevelILRegister::ArchReg(reg) } } -impl RegisterInfo for Register { +impl RegisterInfo for Register { type RegType = Self; fn parent(&self) -> Option { @@ -166,7 +166,7 @@ impl RegisterInfo for Register { } } -impl architecture::Register for Register { +impl architecture::Register for Register { type InfoType = Self; fn name(&self) -> Cow { @@ -204,7 +204,7 @@ impl architecture::Register for Register { } } -impl<'a, D: 'static + RiscVDisassembler + Send + Sync> LiftableLowLevelIL<'a, RiscVArch> +impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a, RiscVArch> for Register { type Result = ValueExpr; @@ -221,7 +221,7 @@ impl<'a, D: 'static + RiscVDisassembler + Send + Sync> LiftableLowLevelIL<'a, Ri } } -impl<'a, D: 'static + RiscVDisassembler + Send + Sync> LiftableLowLevelILWithSize<'a, RiscVArch> +impl<'a, D: RiscVDisassembler> LiftableLowLevelILWithSize<'a, RiscVArch> for Register { fn lift_with_size( @@ -257,21 +257,21 @@ impl<'a, D: 'static + RiscVDisassembler + Send + Sync> LiftableLowLevelILWithSiz } } -impl Hash for Register { +impl Hash for Register { fn hash(&self, state: &mut H) { self.id.hash(state); } } -impl PartialEq for Register { +impl PartialEq for Register { fn eq(&self, other: &Self) -> bool { self.id == other.id } } -impl Eq for Register {} +impl Eq for Register {} -impl fmt::Debug for Register { +impl fmt::Debug for Register { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.name().as_ref()) } @@ -636,13 +636,14 @@ impl architecture::Intrinsic for RiscVIntrinsic { } } -struct RiscVArch { +#[derive(Debug)] +struct RiscVArch { handle: CoreArchitecture, custom_handle: CustomArchitectureHandle>, _dis: PhantomData, } -impl architecture::Architecture for RiscVArch { +impl Architecture for RiscVArch { type Handle = CustomArchitectureHandle; type RegisterInfo = Register; @@ -2652,7 +2653,7 @@ impl RelocationHandler } } -impl AsRef +impl AsRef for RiscVELFRelocationHandler { fn as_ref(&self) -> &CoreRelocationHandler { @@ -2660,17 +2661,17 @@ impl AsRef } } -struct RiscVCC { +struct RiscVCC { _dis: PhantomData, } -impl RiscVCC { +impl RiscVCC { fn new() -> Self { RiscVCC { _dis: PhantomData } } } -impl CallingConvention for RiscVCC { +impl CallingConvention for RiscVCC { fn caller_saved_registers(&self) -> Vec { let mut regs = Vec::with_capacity(36); let int_reg_count = ::int_reg_count(); diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 3573f1fb23..7ad10dfbdb 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -418,7 +418,7 @@ pub trait Intrinsic: Debug + Sized + Clone + Copy { fn outputs(&self) -> Vec>>; } -pub trait Architecture: 'static + Sized + AsRef { +pub trait Architecture: 'static + Sized + AsRef + Debug { type Handle: Borrow + Clone; type RegisterInfo: RegisterInfo; @@ -3234,6 +3234,7 @@ where } } +#[derive(Debug)] pub struct CustomArchitectureHandle where A: 'static + Architecture> + Send + Sync, diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index fd403c767e..f8fcf9f7f4 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -21,7 +21,7 @@ use super::VisitorAction; use super::*; use crate::architecture::Architecture; use std::fmt; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; /// Used as a marker for an [`LowLevelILExpression`] that **can** produce a value. @@ -32,7 +32,7 @@ pub struct ValueExpr; #[derive(Copy, Clone, Debug)] pub struct VoidExpr; -pub trait ExpressionResultType: 'static {} +pub trait ExpressionResultType: 'static + Debug {} impl ExpressionResultType for ValueExpr {} impl ExpressionResultType for VoidExpr {} @@ -102,9 +102,9 @@ where R: ExpressionResultType, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.debug_struct("Expression") - .field("index", &self.index) - .finish() + let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; + let t = unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }; + t.fmt(f) } } diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 85037632b3..301c3f0968 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -35,7 +35,7 @@ pub struct Mutable; #[derive(Copy, Clone, Debug)] pub struct Finalized; -pub trait FunctionMutability: 'static {} +pub trait FunctionMutability: 'static + Debug {} impl FunctionMutability for Mutable {} impl FunctionMutability for Finalized {} @@ -44,7 +44,7 @@ pub struct LiftedNonSSA; #[derive(Copy, Clone, Debug)] pub struct RegularNonSSA; -pub trait NonSSAVariant: 'static {} +pub trait NonSSAVariant: 'static + Debug {} impl NonSSAVariant for LiftedNonSSA {} impl NonSSAVariant for RegularNonSSA {} @@ -53,7 +53,7 @@ pub struct SSA; #[derive(Copy, Clone, Debug)] pub struct NonSSA(V); -pub trait FunctionForm: 'static {} +pub trait FunctionForm: 'static + Debug {} impl FunctionForm for SSA {} impl FunctionForm for NonSSA {} From 22844ce57d821795b6ae8678fbc6c5471c9963dc Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 30 Apr 2025 17:38:40 -0400 Subject: [PATCH 02/54] [Rust] Remove Architecture trait bound on LLIL related structures --- arch/msp430/src/architecture.rs | 6 +- arch/msp430/src/lift.rs | 11 +- arch/msp430/src/register.rs | 6 +- arch/riscv/disasm/src/lib.rs | 2 +- arch/riscv/src/lib.rs | 209 +++++++++----- plugins/warp/src/cache.rs | 20 +- plugins/warp/src/lib.rs | 24 +- rust/src/architecture.rs | 65 ++--- rust/src/disassembly.rs | 11 +- rust/src/flowgraph.rs | 11 +- rust/src/function.rs | 23 +- rust/src/function_recognizer.rs | 4 +- rust/src/low_level_il.rs | 129 +++++++-- rust/src/low_level_il/block.rs | 33 +-- rust/src/low_level_il/expression.rs | 275 +++++++++--------- rust/src/low_level_il/function.rs | 86 +++--- rust/src/low_level_il/instruction.rs | 103 +++---- rust/src/low_level_il/lifting.rs | 309 +++++++++----------- rust/src/low_level_il/operation.rs | 415 ++++++++------------------- rust/src/relocation.rs | 8 +- rust/src/workflow.rs | 19 +- rust/tests/low_level_il.rs | 14 +- 22 files changed, 807 insertions(+), 976 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index ccc5ce80b9..e5815c9198 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -194,7 +194,7 @@ impl Architecture for Msp430 { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &mut MutableLiftedILFunction, ) -> Option<(usize, bool)> { match msp430_asm::decode(data) { Ok(inst) => { @@ -226,8 +226,8 @@ impl Architecture for Msp430 { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, - ) -> Option> { + _il: &'a mut MutableLiftedILFunction, + ) -> Option> { None } diff --git a/arch/msp430/src/lift.rs b/arch/msp430/src/lift.rs index 6ad7b67bd5..124911f006 100644 --- a/arch/msp430/src/lift.rs +++ b/arch/msp430/src/lift.rs @@ -1,7 +1,6 @@ use crate::architecture::offset_to_absolute; use crate::flag::{Flag, FlagWrite}; use crate::register::Register; -use crate::Msp430; use binaryninja::{architecture::FlagCondition, low_level_il::lifting::LowLevelILLabel}; @@ -164,11 +163,7 @@ macro_rules! conditional_jump { }; } -pub(crate) fn lift_instruction( - inst: &Instruction, - addr: u64, - il: &MutableLiftedILFunction, -) { +pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &MutableLiftedILFunction) { match inst { Instruction::Rrc(inst) => { let size = match inst.operand_width() { @@ -628,8 +623,8 @@ pub(crate) fn lift_instruction( fn lift_source_operand<'a>( operand: &Operand, size: usize, - il: &'a MutableLiftedILFunction, -) -> MutableLiftedILExpr<'a, Msp430, ValueExpr> { + il: &'a MutableLiftedILFunction, +) -> MutableLiftedILExpr<'a, ValueExpr> { match operand { Operand::RegisterDirect(r) => il.reg(size, Register::try_from(*r as u32).unwrap()), Operand::Indexed((r, offset)) => il diff --git a/arch/msp430/src/register.rs b/arch/msp430/src/register.rs index 0886e537be..31339ea077 100644 --- a/arch/msp430/src/register.rs +++ b/arch/msp430/src/register.rs @@ -1,7 +1,7 @@ use binaryninja::architecture; use binaryninja::architecture::{ImplicitRegisterExtend, RegisterId}; -use binaryninja::low_level_il::LowLevelILRegister; +use binaryninja::low_level_il::LowLevelILRegisterKind; use std::borrow::Cow; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -134,8 +134,8 @@ impl architecture::RegisterInfo for Register { } } -impl From for LowLevelILRegister { +impl From for LowLevelILRegisterKind { fn from(register: Register) -> Self { - LowLevelILRegister::ArchReg(register) + LowLevelILRegisterKind::Arch(register) } } diff --git a/arch/riscv/disasm/src/lib.rs b/arch/riscv/disasm/src/lib.rs index 959952eed8..152817c606 100644 --- a/arch/riscv/disasm/src/lib.rs +++ b/arch/riscv/disasm/src/lib.rs @@ -2331,7 +2331,7 @@ impl StandardExtension for ExtensionSupported { } } -pub trait RiscVDisassembler: 'static + Debug + Sized + Copy + Clone + Send + Sync { +pub trait RiscVDisassembler: 'static + Debug + Sized + Copy + Clone + Send + Sync { type RegFile: RegFile; type MulDivExtension: StandardExtension; type AtomicExtension: StandardExtension; diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 6df34fd7cc..da4c31153f 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -43,7 +43,7 @@ use binaryninja::low_level_il::lifting::{ LiftableLowLevelIL, LiftableLowLevelILWithSize, LowLevelILLabel, }; use binaryninja::low_level_il::{ - expression::ExpressionHandler, instruction::InstructionHandler, LowLevelILRegister, + expression::ExpressionHandler, instruction::InstructionHandler, LowLevelILRegisterKind, MutableLiftedILExpr, MutableLiftedILFunction, RegularLowLevelILFunction, }; use riscv_dis::{ @@ -138,9 +138,9 @@ impl From> for Register { } } -impl From> for LowLevelILRegister> { +impl From> for LowLevelILRegisterKind> { fn from(reg: Register) -> Self { - LowLevelILRegister::ArchReg(reg) + LowLevelILRegisterKind::Arch(reg) } } @@ -204,15 +204,10 @@ impl architecture::Register for Register { } } -impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a, RiscVArch> - for Register -{ +impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a> for Register { type Result = ValueExpr; - fn lift( - il: &'a MutableLiftedILFunction>, - reg: Self, - ) -> MutableLiftedILExpr<'a, RiscVArch, Self::Result> { + fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { match reg.reg_type() { RegType::Integer(0) => il.const_int(reg.size(), 0), RegType::Integer(_) => il.reg(reg.size(), reg), @@ -221,14 +216,12 @@ impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a, RiscVArch> } } -impl<'a, D: RiscVDisassembler> LiftableLowLevelILWithSize<'a, RiscVArch> - for Register -{ +impl<'a, D: RiscVDisassembler> LiftableLowLevelILWithSize<'a> for Register { fn lift_with_size( - il: &'a MutableLiftedILFunction>, + il: &'a MutableLiftedILFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, RiscVArch, ValueExpr> { + ) -> MutableLiftedILExpr<'a, ValueExpr> { #[cfg(debug_assertions)] { if reg.size() < size { @@ -1069,7 +1062,7 @@ impl Architecture for RiscVArch { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &mut MutableLiftedILFunction, ) -> Option<(usize, bool)> { let max_width = self.default_integer_size(); @@ -1242,7 +1235,8 @@ impl Architecture for RiscVArch { (0, _, _) => il.jump(target).append(), // indirect jump (rd_id, rs1_id, _) if rd_id == rs1_id => { // store the target in a temporary register so we don't clobber it when rd == rs1 - let tmp_reg: LowLevelILRegister> = LowLevelILRegister::Temp(0); + let tmp_reg: LowLevelILRegisterKind> = + LowLevelILRegisterKind::from_temp(0); il.set_reg(max_width, tmp_reg, target).append(); // indirect jump with storage of next address to non-`ra` register il.set_reg( @@ -1312,42 +1306,42 @@ impl Architecture for RiscVArch { Op::Ebreak => il.bp().append(), Op::Uret => { il.intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Uret, - MutableLiftedILFunction::::NO_INPUTS, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Uret), + MutableLiftedILFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Sret => { il.intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Sret, - MutableLiftedILFunction::::NO_INPUTS, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Sret), + MutableLiftedILFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Mret => { il.intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Mret, - MutableLiftedILFunction::::NO_INPUTS, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Mret), + MutableLiftedILFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Wfi => il .intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Wfi, - MutableLiftedILFunction::::NO_INPUTS, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Wfi), + MutableLiftedILFunction::NO_INPUTS, ) .append(), Op::Fence(i) => il .intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Fence, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Fence), [il.const_int(4, i.imm() as u32 as u64)], ) .append(), @@ -1359,13 +1353,14 @@ impl Architecture for RiscVArch { if i.rd().id() == 0 { il.intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Csrwr, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Csrwr), [csr, rs1], ) .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrw, [rs1]).append(); + il.intrinsic([rd], RiscVIntrinsic::::from(Intrinsic::Csrrw), [rs1]) + .append(); } } Op::Csrrs(i) => { @@ -1374,9 +1369,15 @@ impl Architecture for RiscVArch { let csr = il.const_int(4, i.csr() as u64); if i.rs1().id() == 0 { - il.intrinsic([rd], Intrinsic::Csrrd, [csr]).append(); + il.intrinsic([rd], RiscVIntrinsic::::from(Intrinsic::Csrrd), [csr]) + .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrs, [csr, rs1]).append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Csrrs), + [csr, rs1], + ) + .append(); } } Op::Csrrc(i) => { @@ -1385,9 +1386,15 @@ impl Architecture for RiscVArch { let csr = il.const_int(4, i.csr() as u64); if i.rs1().id() == 0 { - il.intrinsic([rd], Intrinsic::Csrrd, [csr]).append(); + il.intrinsic([rd], RiscVIntrinsic::::from(Intrinsic::Csrrd), [csr]) + .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrc, [csr, rs1]).append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Csrrc), + [csr, rs1], + ) + .append(); } } Op::CsrrwI(i) => { @@ -1397,13 +1404,18 @@ impl Architecture for RiscVArch { if i.rd().id() == 0 { il.intrinsic( - MutableLiftedILFunction::::NO_OUTPUTS, - Intrinsic::Csrwr, + MutableLiftedILFunction::NO_OUTPUTS, + RiscVIntrinsic::::from(Intrinsic::Csrwr), [csr, imm], ) .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrw, [csr, imm]).append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Csrrw), + [csr, imm], + ) + .append(); } } Op::CsrrsI(i) => { @@ -1412,9 +1424,15 @@ impl Architecture for RiscVArch { let imm = il.const_int(max_width, i.imm() as u64); if i.imm() == 0 { - il.intrinsic([rd], Intrinsic::Csrrd, [csr]).append(); + il.intrinsic([rd], RiscVIntrinsic::::from(Intrinsic::Csrrd), [csr]) + .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrs, [csr, imm]).append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Csrrs), + [csr, imm], + ) + .append(); } } Op::CsrrcI(i) => { @@ -1423,9 +1441,15 @@ impl Architecture for RiscVArch { let imm = il.const_int(max_width, i.imm() as u64); if i.imm() == 0 { - il.intrinsic([rd], Intrinsic::Csrrd, [csr]).append(); + il.intrinsic([rd], RiscVIntrinsic::::from(Intrinsic::Csrrd), [csr]) + .append(); } else { - il.intrinsic([rd], Intrinsic::Csrrc, [csr, imm]).append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Csrrc), + [csr, imm], + ) + .append(); } } @@ -1444,7 +1468,7 @@ impl Architecture for RiscVArch { let rd = a.rd(); let dest_reg = match rd.id() { - 0 => LowLevelILRegister::Temp(0), + 0 => LowLevelILRegisterKind::from_temp(0), _ => Register::from(rd).into(), }; @@ -1492,14 +1516,14 @@ impl Architecture for RiscVArch { let rs2 = a.rs2(); let dest_reg = match rd.id() { - 0 => LowLevelILRegister::Temp(0), + 0 => LowLevelILRegisterKind::from_temp(0), _ => Register::from(rd).into(), }; let mut next_temp_reg = 1; let mut alloc_reg = |rs: riscv_dis::IntReg| match (rs.id(), rd.id()) { (id, r) if id != 0 && id == r => { - let reg = LowLevelILRegister::Temp(next_temp_reg); + let reg = LowLevelILRegisterKind::from_temp(next_temp_reg); next_temp_reg += 1; il.set_reg(max_width, reg, Register::from(rs)).append(); @@ -1579,10 +1603,11 @@ impl Architecture for RiscVArch { }; il.set_reg(width, rd, result).append(); } else { - let product = LowLevelILRegister::Temp(0); + let product: LowLevelILRegisterKind = + LowLevelILRegisterKind::from_temp(0); il.intrinsic( [product], - Intrinsic::Fmul(f.width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::Fmul(f.width(), f.rm())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); @@ -1590,21 +1615,21 @@ impl Architecture for RiscVArch { Op::Fmadd(..) => il .intrinsic( [rd], - Intrinsic::Fmul(f.width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::Fmul(f.width(), f.rm())), [il.reg(width, product), il.reg(width, rs3)], ) .append(), Op::Fmsub(..) => il .intrinsic( [rd], - Intrinsic::Fsub(f.width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::Fsub(f.width(), f.rm())), [il.reg(width, product), il.reg(width, rs3)], ) .append(), Op::Fnmadd(..) => il .intrinsic( [rd], - Intrinsic::Fsub(f.width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::Fsub(f.width(), f.rm())), [ il.fneg(width, il.reg(width, product)).build(), il.reg(width, rs3), @@ -1614,7 +1639,7 @@ impl Architecture for RiscVArch { Op::Fnmsub(..) => il .intrinsic( [rd], - Intrinsic::Fadd(f.width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::Fadd(f.width(), f.rm())), [ il.fneg(width, il.reg(width, product)).build(), il.reg(width, rs3), @@ -1641,10 +1666,18 @@ impl Architecture for RiscVArch { il.set_reg(width, rd, result).append(); } else { let intrinsic = match op { - Op::Fadd(..) => Intrinsic::Fadd(f.width(), f.rm()), - Op::Fsub(..) => Intrinsic::Fsub(f.width(), f.rm()), - Op::Fmul(..) => Intrinsic::Fmul(f.width(), f.rm()), - Op::Fdiv(..) => Intrinsic::Fdiv(f.width(), f.rm()), + Op::Fadd(..) => { + RiscVIntrinsic::::from(Intrinsic::Fadd(f.width(), f.rm())) + } + Op::Fsub(..) => { + RiscVIntrinsic::::from(Intrinsic::Fsub(f.width(), f.rm())) + } + Op::Fmul(..) => { + RiscVIntrinsic::::from(Intrinsic::Fmul(f.width(), f.rm())) + } + Op::Fdiv(..) => { + RiscVIntrinsic::::from(Intrinsic::Fdiv(f.width(), f.rm())) + } _ => unreachable!(), }; il.intrinsic([rd], intrinsic, [il.reg(width, rs1), il.reg(width, rs2)]) @@ -1661,7 +1694,7 @@ impl Architecture for RiscVArch { } else { il.intrinsic( [rd], - Intrinsic::Fsgnj(f.width()), + RiscVIntrinsic::::from(Intrinsic::Fsgnj(f.width())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); @@ -1678,7 +1711,7 @@ impl Architecture for RiscVArch { } else { il.intrinsic( [rd], - Intrinsic::Fsgnjn(f.width()), + RiscVIntrinsic::::from(Intrinsic::Fsgnjn(f.width())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); @@ -1695,7 +1728,7 @@ impl Architecture for RiscVArch { } else { il.intrinsic( [rd], - Intrinsic::Fsgnjx(f.width()), + RiscVIntrinsic::::from(Intrinsic::Fsgnjx(f.width())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); @@ -1715,7 +1748,7 @@ impl Architecture for RiscVArch { let width = f.width() as usize; il.intrinsic( [rd], - Intrinsic::Fmin(f.width()), + RiscVIntrinsic::::from(Intrinsic::Fmin(f.width())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); @@ -1727,14 +1760,14 @@ impl Architecture for RiscVArch { let width = f.width() as usize; il.intrinsic( [rd], - Intrinsic::Fmax(f.width()), + RiscVIntrinsic::::from(Intrinsic::Fmax(f.width())), [il.reg(width, rs1), il.reg(width, rs2)], ) .append(); } Op::Fle(f) | Op::Flt(f) | Op::Feq(f) => { let rd = match f.rd().id() { - 0 => LowLevelILRegister::Temp(0), + 0 => LowLevelILRegisterKind::from_temp(0), _ => Register::from(f.rd()).into(), }; let left = Register::from(f.rs1()); @@ -1760,7 +1793,11 @@ impl Architecture for RiscVArch { } else { il.intrinsic( [rd], - Intrinsic::FcvtFToF(f.rs1_width(), f.rd_width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::FcvtFToF( + f.rs1_width(), + f.rd_width(), + f.rm(), + )), [il.reg(rs1_width, rs1)], ) .append(); @@ -1768,7 +1805,7 @@ impl Architecture for RiscVArch { } Op::FcvtToInt(f) => { let rd = match f.rd().id() { - 0 => LowLevelILRegister::Temp(0), + 0 => LowLevelILRegisterKind::from_temp(0), _ => Register::from(f.rd()).into(), }; let rs1 = Register::from(f.rs1()); @@ -1777,14 +1814,22 @@ impl Architecture for RiscVArch { if f.zx() { il.intrinsic( [rd], - Intrinsic::FcvtFToU(f.rs1_width(), f.rd_width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::FcvtFToU( + f.rs1_width(), + f.rd_width(), + f.rm(), + )), [il.reg(rs1_width, rs1)], ) .append(); } else if f.rm() != RoundMode::Dynamic { il.intrinsic( [rd], - Intrinsic::FcvtFToI(f.rs1_width(), f.rd_width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::FcvtFToI( + f.rs1_width(), + f.rd_width(), + f.rm(), + )), [il.reg(rs1_width, rs1)], ) .append(); @@ -1807,14 +1852,22 @@ impl Architecture for RiscVArch { if f.zx() { il.intrinsic( [rd], - Intrinsic::FcvtUToF(f.rs1_width(), f.rd_width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::FcvtUToF( + f.rs1_width(), + f.rd_width(), + f.rm(), + )), [rs1], ) .append(); } else if f.rm() != RoundMode::Dynamic { il.intrinsic( [rd], - Intrinsic::FcvtIToF(f.rs1_width(), f.rd_width(), f.rm()), + RiscVIntrinsic::::from(Intrinsic::FcvtIToF( + f.rs1_width(), + f.rd_width(), + f.rm(), + )), [rs1], ) .append(); @@ -1825,7 +1878,7 @@ impl Architecture for RiscVArch { } Op::FmvToInt(f) => { let rd = match f.rd().id() { - 0 => LowLevelILRegister::Temp(0), + 0 => LowLevelILRegisterKind::from_temp(0), _ => Register::from(f.rd()).into(), }; let rs1 = Register::from(f.rs1()); @@ -1848,8 +1901,12 @@ impl Architecture for RiscVArch { let rd = Register::from(f.rd()); let rs1 = Register::from(f.rs1()); let width = f.width() as usize; - il.intrinsic([rd], Intrinsic::Fclass(f.width()), [il.reg(width, rs1)]) - .append(); + il.intrinsic( + [rd], + RiscVIntrinsic::::from(Intrinsic::Fclass(f.width())), + [il.reg(width, rs1)], + ) + .append(); } _ => il.unimplemented().append(), @@ -2653,9 +2710,7 @@ impl RelocationHandler } } -impl AsRef - for RiscVELFRelocationHandler -{ +impl AsRef for RiscVELFRelocationHandler { fn as_ref(&self) -> &CoreRelocationHandler { &self.handle } @@ -2793,7 +2848,7 @@ impl FunctionRecognizer for RiscVELFPLTRecognizer { &self, bv: &BinaryView, func: &Function, - llil: &RegularLowLevelILFunction, + llil: &RegularLowLevelILFunction, ) -> bool { // Look for the following code pattern: // t3 = plt diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index 4b1df5af7e..7219b54712 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -1,6 +1,5 @@ use crate::convert::{from_bn_symbol, from_bn_type_internal}; use crate::{build_function, function_guid}; -use binaryninja::architecture::Architecture; use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::confidence::MAX_CONFIDENCE; use binaryninja::function::Function as BNFunction; @@ -68,10 +67,7 @@ pub fn try_cached_function_match(function: &BNFunction) -> Option { .to_owned() } -pub fn cached_function( - function: &BNFunction, - llil: &RegularLowLevelILFunction, -) -> Function { +pub fn cached_function(function: &BNFunction, llil: &RegularLowLevelILFunction) -> Function { let view = function.view(); let view_id = ViewID::from(view.as_ref()); let function_cache = FUNCTION_CACHE.get_or_init(Default::default); @@ -122,9 +118,9 @@ where } } -pub fn cached_function_guid( +pub fn cached_function_guid( function: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction>, ) -> FunctionGUID { let view = function.view(); let view_id = ViewID::from(view); @@ -202,11 +198,7 @@ pub struct FunctionCache { } impl FunctionCache { - pub fn function( - &self, - function: &BNFunction, - llil: &RegularLowLevelILFunction, - ) -> Function { + pub fn function(&self, function: &BNFunction, llil: &RegularLowLevelILFunction) -> Function { let function_id = FunctionID::from(function); match self.cache.get(&function_id) { Some(function) => function.value().to_owned(), @@ -330,10 +322,10 @@ impl GUIDCache { } } - pub fn function_guid( + pub fn function_guid( &self, function: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction>, ) -> FunctionGUID { let function_id = FunctionID::from(function); match self.cache.get(&function_id) { diff --git a/plugins/warp/src/lib.rs b/plugins/warp/src/lib.rs index 3f2fc27624..3d68b4022e 100644 --- a/plugins/warp/src/lib.rs +++ b/plugins/warp/src/lib.rs @@ -16,7 +16,7 @@ use binaryninja::low_level_il::function::{ use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstruction, LowLevelILInstructionKind, }; -use binaryninja::low_level_il::{LowLevelILRegister, VisitorAction}; +use binaryninja::low_level_il::{LowLevelILRegisterKind, VisitorAction}; use binaryninja::rc::Ref as BNRef; use std::path::PathBuf; use warp::signature::basic_block::BasicBlockGUID; @@ -44,9 +44,9 @@ pub fn user_signature_dir() -> PathBuf { binaryninja::user_directory().join("signatures/") } -pub fn build_function( +pub fn build_function( func: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction>, ) -> Function { let bn_fn_ty = func.function_type(); Function { @@ -76,9 +76,9 @@ pub fn sorted_basic_blocks(func: &BNFunction) -> Vec( +pub fn function_guid( func: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction>, ) -> FunctionGUID { let basic_blocks = sorted_basic_blocks(func); let basic_block_guids = basic_blocks @@ -88,9 +88,9 @@ pub fn function_guid( FunctionGUID::from_basic_blocks(&basic_block_guids) } -pub fn basic_block_guid( +pub fn basic_block_guid( basic_block: &BNBasicBlock, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction>, ) -> BasicBlockGUID { let func = basic_block.function(); let view = func.view(); @@ -98,7 +98,7 @@ pub fn basic_block_guid( let max_instr_len = arch.max_instr_len(); // NOPs and useless moves are blacklisted to allow for hot-patchable functions. - let is_blacklisted_instr = |instr: &LowLevelILInstruction>| { + let is_blacklisted_instr = |instr: &LowLevelILInstruction>| { match instr.kind() { LowLevelILInstructionKind::Nop(_) => true, LowLevelILInstructionKind::SetReg(op) => { @@ -107,7 +107,7 @@ pub fn basic_block_guid( if op.dest_reg() == source_op.source_reg() => { match op.dest_reg() { - LowLevelILRegister::ArchReg(r) => { + LowLevelILRegisterKind::Arch(r) => { // If this register has no implicit extend then we can safely assume it's a NOP. // Ex. on x86_64 we don't want to remove `mov edi, edi` as it will zero the upper 32 bits. // Ex. on x86 we do want to remove `mov edi, edi` as it will not have a side effect like above. @@ -116,7 +116,7 @@ pub fn basic_block_guid( ImplicitRegisterExtend::NoExtend ) } - LowLevelILRegister::Temp(_) => false, + LowLevelILRegisterKind::Temp(_) => false, } } _ => false, @@ -126,8 +126,8 @@ pub fn basic_block_guid( } }; - let is_variant_instr = |instr: &LowLevelILInstruction>| { - let is_variant_expr = |expr: &LowLevelILExpressionKind>| { + let is_variant_instr = |instr: &LowLevelILInstruction>| { + let is_variant_expr = |expr: &LowLevelILExpressionKind>| { // TODO: Checking the section here is slow, we should gather all section ranges outside of this. match expr { LowLevelILExpressionKind::ConstPtr(op) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 7ad10dfbdb..c0fe138ed3 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -80,6 +80,13 @@ macro_rules! newtype { } newtype!(RegisterId, u32); + +impl RegisterId { + pub fn is_temporary(&self) -> bool { + self.0 & 0x8000_0000 != 0 + } +} + newtype!(RegisterStackId, u32); newtype!(FlagId, u32); // TODO: Make this NonZero? @@ -418,7 +425,7 @@ pub trait Intrinsic: Debug + Sized + Clone + Copy { fn outputs(&self) -> Vec>>; } -pub trait Architecture: 'static + Sized + AsRef + Debug { +pub trait Architecture: 'static + Sized + AsRef { type Handle: Borrow + Clone; type RegisterInfo: RegisterInfo; @@ -460,7 +467,7 @@ pub trait Architecture: 'static + Sized + AsRef + Debug { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &mut MutableLiftedILFunction, ) -> Option<(usize, bool)>; /// Fallback flag value calculation path. This method is invoked when the core is unable to @@ -477,8 +484,8 @@ pub trait Architecture: 'static + Sized + AsRef + Debug { flag: Self::Flag, flag_write_type: Self::FlagWrite, op: LowLevelILFlagWriteOp, - il: &'a mut MutableLiftedILFunction, - ) -> Option> { + il: &'a mut MutableLiftedILFunction, + ) -> Option> { let role = flag.role(flag_write_type.class()); Some(get_default_flag_write_llil(self, role, op, il)) } @@ -506,8 +513,8 @@ pub trait Architecture: 'static + Sized + AsRef + Debug { &self, cond: FlagCondition, class: Option, - il: &'a mut MutableLiftedILFunction, - ) -> Option> { + il: &'a mut MutableLiftedILFunction, + ) -> Option> { Some(get_default_flag_cond_llil(self, cond, class, il)) } @@ -528,8 +535,8 @@ pub trait Architecture: 'static + Sized + AsRef + Debug { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, - ) -> Option> { + _il: &'a mut MutableLiftedILFunction, + ) -> Option> { None } @@ -1505,7 +1512,7 @@ impl Architecture for CoreArchitecture { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &mut MutableLiftedILFunction, ) -> Option<(usize, bool)> { let mut size = data.len(); let success = unsafe { @@ -1530,8 +1537,8 @@ impl Architecture for CoreArchitecture { _flag: Self::Flag, _flag_write: Self::FlagWrite, _op: LowLevelILFlagWriteOp, - _il: &'a mut MutableLiftedILFunction, - ) -> Option> { + _il: &'a mut MutableLiftedILFunction, + ) -> Option> { None } @@ -1567,16 +1574,16 @@ impl Architecture for CoreArchitecture { &self, _cond: FlagCondition, _class: Option, - _il: &'a mut MutableLiftedILFunction, - ) -> Option> { + _il: &'a mut MutableLiftedILFunction, + ) -> Option> { None } fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, - ) -> Option> { + _il: &'a mut MutableLiftedILFunction, + ) -> Option> { None } @@ -2218,12 +2225,9 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A, - }; - let data = unsafe { std::slice::from_raw_parts(data, *len) }; - let mut lifter = unsafe { MutableLiftedILFunction::from_raw(custom_arch_handle, il) }; + let mut lifter = + unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; match custom_arch.instruction_llil(data, addr, &mut lifter) { Some((res_len, res_value)) => { @@ -2606,14 +2610,11 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A, - }; - let flag_write = custom_arch.flag_write_from_id(FlagWriteId(flag_write)); let flag = custom_arch.flag_from_id(FlagId(flag)); let operands = unsafe { std::slice::from_raw_parts(operands_raw, operand_count) }; - let mut lifter = unsafe { MutableLiftedILFunction::from_raw(custom_arch_handle, il) }; + let mut lifter = + unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; if let (Some(flag_write), Some(flag)) = (flag_write, flag) { if let Some(op) = LowLevelILFlagWriteOp::from_op(custom_arch, size, op, operands) { @@ -2659,13 +2660,10 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A, - }; - let class = custom_arch.flag_class_from_id(FlagClassId(class)); - let mut lifter = unsafe { MutableLiftedILFunction::from_raw(custom_arch_handle, il) }; + let mut lifter = + unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &mut lifter) { // TODO verify that returned expr is a bool value return expr.index.0; @@ -2683,11 +2681,8 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let custom_arch_handle = CustomArchitectureHandle { - handle: ctxt as *mut A, - }; - - let mut lifter = unsafe { MutableLiftedILFunction::from_raw(custom_arch_handle, il) }; + let mut lifter = + unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) { if let Some(expr) = custom_arch.flag_group_llil(group, &mut lifter) { diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 9dfd160f4b..99a6b22efc 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -1022,8 +1022,8 @@ impl DisassemblyTextRenderer { unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } } - pub fn from_llil( - func: &LowLevelILFunction, + pub fn from_llil( + func: &LowLevelILFunction, settings: Option<&DisassemblySettings>, ) -> Ref { let settings_ptr = settings.map(|s| s.handle).unwrap_or(ptr::null_mut()); @@ -1058,14 +1058,11 @@ impl DisassemblyTextRenderer { unsafe { Function::ref_from_raw(result) } } - pub fn llil( - &self, - ) -> Ref> { - let arch = self.arch(); + pub fn llil(&self) -> Ref> { let result = unsafe { BNGetDisassemblyTextRendererLowLevelILFunction(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { LowLevelILFunction::ref_from_raw(arch.handle(), result) } + unsafe { LowLevelILFunction::ref_from_raw(result) } } pub fn mlil(&self) -> Ref { diff --git a/rust/src/flowgraph.rs b/rust/src/flowgraph.rs index c8a9e4a74d..976764eb19 100644 --- a/rust/src/flowgraph.rs +++ b/rust/src/flowgraph.rs @@ -14,7 +14,6 @@ //! Interfaces for creating and displaying pretty CFGs in Binary Ninja. -use crate::architecture::CoreArchitecture; use crate::disassembly::DisassemblyTextLine; use crate::rc::*; use binaryninjacore_sys::*; @@ -55,17 +54,11 @@ impl FlowGraph { unsafe { Array::new(nodes_ptr, count, ()) } } - pub fn low_level_il(&self) -> Result>, ()> { + pub fn low_level_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle); match llil_ptr.is_null() { - false => { - let func_ptr = BNGetLowLevelILOwnerFunction(llil_ptr); - let arch_ptr = BNGetFunctionArchitecture(func_ptr); - let arch = CoreArchitecture::from_raw(arch_ptr); - BNFreeFunction(func_ptr); - Ok(RegularLowLevelILFunction::ref_from_raw(arch, llil_ptr)) - } + false => Ok(RegularLowLevelILFunction::ref_from_raw(llil_ptr)), true => Err(()), } } diff --git a/rust/src/function.rs b/rust/src/function.rs index 7990f109a9..c882ab08c9 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -529,45 +529,38 @@ impl Function { } } - pub fn low_level_il(&self) -> Result>, ()> { + pub fn low_level_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFunctionLowLevelIL(self.handle); match llil_ptr.is_null() { - false => Ok(RegularLowLevelILFunction::ref_from_raw( - self.arch(), - llil_ptr, - )), + false => Ok(RegularLowLevelILFunction::ref_from_raw(llil_ptr)), true => Err(()), } } } - pub fn low_level_il_if_available( - &self, - ) -> Option>> { + pub fn low_level_il_if_available(&self) -> Option> { let llil_ptr = unsafe { BNGetFunctionLowLevelILIfAvailable(self.handle) }; match llil_ptr.is_null() { - false => { - Some(unsafe { RegularLowLevelILFunction::ref_from_raw(self.arch(), llil_ptr) }) - } + false => Some(unsafe { RegularLowLevelILFunction::ref_from_raw(llil_ptr) }), true => None, } } - pub fn lifted_il(&self) -> Result>, ()> { + pub fn lifted_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFunctionLiftedIL(self.handle); match llil_ptr.is_null() { - false => Ok(LiftedILFunction::ref_from_raw(self.arch(), llil_ptr)), + false => Ok(LiftedILFunction::ref_from_raw(llil_ptr)), true => Err(()), } } } - pub fn lifted_il_if_available(&self) -> Option>> { + pub fn lifted_il_if_available(&self) -> Option> { let llil_ptr = unsafe { BNGetFunctionLiftedILIfAvailable(self.handle) }; match llil_ptr.is_null() { - false => Some(unsafe { LiftedILFunction::ref_from_raw(self.arch(), llil_ptr) }), + false => Some(unsafe { LiftedILFunction::ref_from_raw(llil_ptr) }), true => None, } } diff --git a/rust/src/function_recognizer.rs b/rust/src/function_recognizer.rs index 64e33806ba..cd5592ee75 100644 --- a/rust/src/function_recognizer.rs +++ b/rust/src/function_recognizer.rs @@ -10,7 +10,7 @@ pub trait FunctionRecognizer { &self, _bv: &BinaryView, _func: &Function, - _llil: &RegularLowLevelILFunction, + _llil: &RegularLowLevelILFunction, ) -> bool { false } @@ -49,7 +49,7 @@ where let context = unsafe { &*(ctxt as *mut FunctionRecognizerHandlerContext) }; let bv = unsafe { BinaryView::from_raw(bv).to_owned() }; let func = unsafe { Function::from_raw(func).to_owned() }; - let llil = unsafe { LowLevelILFunction::from_raw(func.arch(), llil).to_owned() }; + let llil = unsafe { LowLevelILFunction::from_raw(llil).to_owned() }; context.recognizer.recognize_low_level_il(&bv, &func, &llil) } diff --git a/rust/src/low_level_il.rs b/rust/src/low_level_il.rs index d6303c1342..453e05469b 100644 --- a/rust/src/low_level_il.rs +++ b/rust/src/low_level_il.rs @@ -20,8 +20,8 @@ use std::fmt; // requirements on load/store memory address sizes? // can reg/set_reg be used with sizes that differ from what is in BNRegisterInfo? -use crate::architecture::Register as ArchReg; use crate::architecture::{Architecture, RegisterId}; +use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::function::Location; pub mod block; @@ -35,52 +35,123 @@ use self::expression::*; use self::function::*; use self::instruction::*; -pub type MutableLiftedILFunction = LowLevelILFunction>; -pub type LiftedILFunction = LowLevelILFunction>; -pub type MutableLiftedILExpr<'a, Arch, ReturnType> = - LowLevelILExpression<'a, Arch, Mutable, NonSSA, ReturnType>; -pub type RegularLowLevelILFunction = - LowLevelILFunction>; -pub type RegularLowLevelILInstruction<'a, Arch> = - LowLevelILInstruction<'a, Arch, Finalized, NonSSA>; -pub type RegularLowLevelILInstructionKind<'a, Arch> = - LowLevelILInstructionKind<'a, Arch, Finalized, NonSSA>; -pub type RegularLowLevelILExpression<'a, Arch, ReturnType> = - LowLevelILExpression<'a, Arch, Finalized, NonSSA, ReturnType>; -pub type RegularLowLevelILExpressionKind<'a, Arch> = - LowLevelILExpressionKind<'a, Arch, Finalized, NonSSA>; -pub type LowLevelILSSAFunction = LowLevelILFunction; +pub type MutableLiftedILFunction = LowLevelILFunction>; +pub type LiftedILFunction = LowLevelILFunction>; +pub type MutableLiftedILExpr<'a, ReturnType> = + LowLevelILExpression<'a, Mutable, NonSSA, ReturnType>; +pub type RegularLowLevelILFunction = LowLevelILFunction>; +pub type RegularLowLevelILInstruction<'a> = + LowLevelILInstruction<'a, Finalized, NonSSA>; +pub type RegularLowLevelILInstructionKind<'a> = + LowLevelILInstructionKind<'a, Finalized, NonSSA>; +pub type RegularLowLevelILExpression<'a, ReturnType> = + LowLevelILExpression<'a, Finalized, NonSSA, ReturnType>; +pub type RegularLowLevelILExpressionKind<'a> = + LowLevelILExpressionKind<'a, Finalized, NonSSA>; +pub type LowLevelILSSAFunction = LowLevelILFunction; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct LowLevelILTempRegister { + /// The temporary id for the register, this will **NOT** be the referenced id in the core. + /// + /// Do not attempt to pass this to the core. Use [`LowLevelILTempRegister::id`] instead. + temp_id: RegisterId, +} + +impl LowLevelILTempRegister { + pub fn new(temp_id: u32) -> Self { + Self { + temp_id: RegisterId(temp_id), + } + } + + pub fn from_id(id: RegisterId) -> Option { + match id.is_temporary() { + true => { + let temp_id = RegisterId(id.0 & 0x7fff_ffff); + Some(Self { temp_id }) + } + false => None, + } + } + + /// The temporary registers core id, with the temporary bit set. + pub fn id(&self) -> RegisterId { + RegisterId(self.temp_id.0 | 0x8000_0000) + } +} + +impl fmt::Debug for LowLevelILTempRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "temp{}", self.temp_id) + } +} + +impl TryFrom for LowLevelILTempRegister { + type Error = (); + + fn try_from(value: RegisterId) -> Result { + Self::from_id(value).ok_or(()) + } +} + +impl From for LowLevelILTempRegister { + fn from(value: u32) -> Self { + Self::new(value) + } +} #[derive(Copy, Clone, PartialEq, Eq)] -pub enum LowLevelILRegister { - ArchReg(R), - // TODO: Might want to be changed to TempRegisterId. - // TODO: If we do that then we would need to get rid of `Register::id()` - Temp(u32), +pub enum LowLevelILRegisterKind { + Arch(R), + Temp(LowLevelILTempRegister), } -impl LowLevelILRegister { +impl LowLevelILRegisterKind { + pub fn from_raw(arch: &impl Architecture, val: RegisterId) -> Option { + match val.is_temporary() { + true => { + let temp_reg = LowLevelILTempRegister::from_id(val)?; + Some(LowLevelILRegisterKind::Temp(temp_reg)) + } + false => { + let arch_reg = arch.register_from_id(val)?; + Some(LowLevelILRegisterKind::Arch(arch_reg)) + } + } + } + + pub fn from_temp(temp: impl Into) -> Self { + LowLevelILRegisterKind::Temp(temp.into()) + } + fn id(&self) -> RegisterId { match *self { - LowLevelILRegister::ArchReg(ref r) => r.id(), - LowLevelILRegister::Temp(id) => RegisterId(0x8000_0000 | id), + LowLevelILRegisterKind::Arch(ref r) => r.id(), + LowLevelILRegisterKind::Temp(temp) => temp.id(), } } } -impl fmt::Debug for LowLevelILRegister { +impl fmt::Debug for LowLevelILRegisterKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - LowLevelILRegister::ArchReg(ref r) => write!(f, "{}", r.name().as_ref()), - LowLevelILRegister::Temp(id) => write!(f, "temp{}", id), + LowLevelILRegisterKind::Arch(ref r) => r.fmt(f), + LowLevelILRegisterKind::Temp(id) => id.fmt(f), } } } +impl From for LowLevelILRegisterKind { + fn from(reg: LowLevelILTempRegister) -> Self { + LowLevelILRegisterKind::Temp(reg) + } +} + #[derive(Copy, Clone, Debug)] pub enum LowLevelILSSARegister { - Full(LowLevelILRegister, u32), // no such thing as partial access to a temp register, I think - Partial(R, u32, R), // partial accesses only possible for arch registers, I think + Full(LowLevelILRegisterKind, u32), // no such thing as partial access to a temp register, I think + Partial(R, u32, R), // partial accesses only possible for arch registers, I think } impl LowLevelILSSARegister { diff --git a/rust/src/low_level_il/block.rs b/rust/src/low_level_il/block.rs index ac0be449f5..519c707e7b 100644 --- a/rust/src/low_level_il/block.rs +++ b/rust/src/low_level_il/block.rs @@ -15,38 +15,35 @@ use std::fmt::Debug; use std::ops::Range; -use crate::architecture::Architecture; use crate::basic_block::{BasicBlock, BlockContext}; use super::*; #[derive(Copy)] -pub struct LowLevelILBlock<'func, A, M, F> +pub struct LowLevelILBlock<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - pub(crate) function: &'func LowLevelILFunction, + pub(crate) function: &'func LowLevelILFunction, } -impl<'func, A, M, F> BlockContext for LowLevelILBlock<'func, A, M, F> +impl<'func, M, F> BlockContext for LowLevelILBlock<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - type Instruction = LowLevelILInstruction<'func, A, M, F>; + type Instruction = LowLevelILInstruction<'func, M, F>; type InstructionIndex = LowLevelInstructionIndex; - type Iter = LowLevelILBlockIter<'func, A, M, F>; + type Iter = LowLevelILBlockIter<'func, M, F>; - fn start(&self, block: &BasicBlock) -> LowLevelILInstruction<'func, A, M, F> { + fn start(&self, block: &BasicBlock) -> LowLevelILInstruction<'func, M, F> { self.function .instruction_from_index(block.start_index()) .unwrap() } - fn iter(&self, block: &BasicBlock) -> LowLevelILBlockIter<'func, A, M, F> { + fn iter(&self, block: &BasicBlock) -> LowLevelILBlockIter<'func, M, F> { LowLevelILBlockIter { function: self.function, range: (block.start_index().0)..(block.end_index().0), @@ -54,9 +51,8 @@ where } } -impl<'func, A, M, F> Debug for LowLevelILBlock<'func, A, M, F> +impl<'func, M, F> Debug for LowLevelILBlock<'func, M, F> where - A: 'func + Architecture + Debug, M: FunctionMutability, F: FunctionForm, { @@ -67,9 +63,8 @@ where } } -impl<'func, A, M, F> Clone for LowLevelILBlock<'func, A, M, F> +impl<'func, M, F> Clone for LowLevelILBlock<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { @@ -80,24 +75,22 @@ where } } -pub struct LowLevelILBlockIter<'func, A, M, F> +pub struct LowLevelILBlockIter<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, // TODO: Once step_trait is stable we can do Range range: Range, } -impl<'func, A, M, F> Iterator for LowLevelILBlockIter<'func, A, M, F> +impl<'func, M, F> Iterator for LowLevelILBlockIter<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - type Item = LowLevelILInstruction<'func, A, M, F>; + type Item = LowLevelILInstruction<'func, M, F>; fn next(&mut self) -> Option { self.range diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index f8fcf9f7f4..331ab980ad 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -19,7 +19,7 @@ use super::operation; use super::operation::Operation; use super::VisitorAction; use super::*; -use crate::architecture::Architecture; +use crate::architecture::CoreFlagWrite; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::marker::PhantomData; @@ -47,42 +47,39 @@ impl Display for LowLevelExpressionIndex { } // TODO: Probably want to rename this with a LowLevelIL prefix to avoid collisions when we add handlers for other ILs -pub trait ExpressionHandler<'func, A, M, F> +pub trait ExpressionHandler<'func, M, F> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, F>; + fn kind(&self) -> LowLevelILExpressionKind<'func, M, F>; fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction; + T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction; } -pub struct LowLevelILExpression<'func, A, M, F, R> +pub struct LowLevelILExpression<'func, M, F, R> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, R: ExpressionResultType, { - pub(crate) function: &'func LowLevelILFunction, + pub(crate) function: &'func LowLevelILFunction, pub index: LowLevelExpressionIndex, // tag the 'return' type of this expression pub(crate) _ty: PhantomData, } -impl<'func, A, M, F, R> LowLevelILExpression<'func, A, M, F, R> +impl<'func, M, F, R> LowLevelILExpression<'func, M, F, R> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, R: ExpressionResultType, { pub(crate) fn new( - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, index: LowLevelExpressionIndex, ) -> Self { // TODO: Validate expression here? @@ -94,27 +91,25 @@ where } } -impl<'func, A, M, F, R> fmt::Debug for LowLevelILExpression<'func, A, M, F, R> +impl<'func, M, F, R> fmt::Debug for LowLevelILExpression<'func, M, F, R> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, R: ExpressionResultType, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; - let t = unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }; - t.fmt(f) + // SAFETY: This is safe we are not exposing the expression kind to the caller. + let kind = unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }; + kind.fmt(f) } } -impl<'func, A, M> ExpressionHandler<'func, A, M, SSA> - for LowLevelILExpression<'func, A, M, SSA, ValueExpr> +impl<'func, M> ExpressionHandler<'func, M, SSA> for LowLevelILExpression<'func, M, SSA, ValueExpr> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, SSA> { + fn kind(&self) -> LowLevelILExpressionKind<'func, M, SSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; @@ -128,7 +123,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, A, M, SSA, ValueExpr>) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, SSA, ValueExpr>) -> VisitorAction, { // Visit the current expression. match f(self) { @@ -141,13 +136,12 @@ where } } -impl<'func, A, M> ExpressionHandler<'func, A, M, NonSSA> - for LowLevelILExpression<'func, A, M, NonSSA, ValueExpr> +impl<'func, M> ExpressionHandler<'func, M, NonSSA> + for LowLevelILExpression<'func, M, NonSSA, ValueExpr> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, NonSSA> { + fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; @@ -161,9 +155,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut( - &LowLevelILExpression<'func, A, M, NonSSA, ValueExpr>, - ) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, { // Visit the current expression. match f(self) { @@ -176,13 +168,12 @@ where } } -impl<'func, A, M> ExpressionHandler<'func, A, M, NonSSA> - for LowLevelILExpression<'func, A, M, NonSSA, ValueExpr> +impl<'func, M> ExpressionHandler<'func, M, NonSSA> + for LowLevelILExpression<'func, M, NonSSA, ValueExpr> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILExpressionKind<'func, A, M, NonSSA> { + fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> { use binaryninjacore_sys::BNLowLevelILOperation::*; let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; match op.operation { @@ -197,7 +188,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where T: FnMut( - &LowLevelILExpression<'func, A, M, NonSSA, ValueExpr>, + &LowLevelILExpression<'func, M, NonSSA, ValueExpr>, ) -> VisitorAction, { // Visit the current expression. @@ -211,129 +202,126 @@ where } } -impl<'func, A, F> LowLevelILExpression<'func, A, Finalized, F, ValueExpr> +impl<'func, F> LowLevelILExpression<'func, Finalized, F, ValueExpr> where - A: 'func + Architecture, F: FunctionForm, { // TODO possible values } #[derive(Debug)] -pub enum LowLevelILExpressionKind<'func, A, M, F> +pub enum LowLevelILExpressionKind<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - Load(Operation<'func, A, M, F, operation::Load>), - Pop(Operation<'func, A, M, F, operation::Pop>), - Reg(Operation<'func, A, M, F, operation::Reg>), - RegSplit(Operation<'func, A, M, F, operation::RegSplit>), - Const(Operation<'func, A, M, F, operation::Const>), - ConstPtr(Operation<'func, A, M, F, operation::Const>), - Flag(Operation<'func, A, M, F, operation::Flag>), - FlagBit(Operation<'func, A, M, F, operation::FlagBit>), - ExternPtr(Operation<'func, A, M, F, operation::Extern>), - - RegStackPop(Operation<'func, A, M, F, operation::RegStackPop>), - - Add(Operation<'func, A, M, F, operation::BinaryOp>), - Adc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Sub(Operation<'func, A, M, F, operation::BinaryOp>), - Sbb(Operation<'func, A, M, F, operation::BinaryOpCarry>), - And(Operation<'func, A, M, F, operation::BinaryOp>), - Or(Operation<'func, A, M, F, operation::BinaryOp>), - Xor(Operation<'func, A, M, F, operation::BinaryOp>), - Lsl(Operation<'func, A, M, F, operation::BinaryOp>), - Lsr(Operation<'func, A, M, F, operation::BinaryOp>), - Asr(Operation<'func, A, M, F, operation::BinaryOp>), - Rol(Operation<'func, A, M, F, operation::BinaryOp>), - Rlc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Ror(Operation<'func, A, M, F, operation::BinaryOp>), - Rrc(Operation<'func, A, M, F, operation::BinaryOpCarry>), - Mul(Operation<'func, A, M, F, operation::BinaryOp>), - - MulsDp(Operation<'func, A, M, F, operation::BinaryOp>), - MuluDp(Operation<'func, A, M, F, operation::BinaryOp>), - - Divu(Operation<'func, A, M, F, operation::BinaryOp>), - Divs(Operation<'func, A, M, F, operation::BinaryOp>), - - DivuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - DivsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - - Modu(Operation<'func, A, M, F, operation::BinaryOp>), - Mods(Operation<'func, A, M, F, operation::BinaryOp>), - - ModuDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - ModsDp(Operation<'func, A, M, F, operation::DoublePrecDivOp>), - - Neg(Operation<'func, A, M, F, operation::UnaryOp>), - Not(Operation<'func, A, M, F, operation::UnaryOp>), - Sx(Operation<'func, A, M, F, operation::UnaryOp>), - Zx(Operation<'func, A, M, F, operation::UnaryOp>), - LowPart(Operation<'func, A, M, F, operation::UnaryOp>), + Load(Operation<'func, M, F, operation::Load>), + Pop(Operation<'func, M, F, operation::Pop>), + Reg(Operation<'func, M, F, operation::Reg>), + RegSplit(Operation<'func, M, F, operation::RegSplit>), + Const(Operation<'func, M, F, operation::Const>), + ConstPtr(Operation<'func, M, F, operation::Const>), + Flag(Operation<'func, M, F, operation::Flag>), + FlagBit(Operation<'func, M, F, operation::FlagBit>), + ExternPtr(Operation<'func, M, F, operation::Extern>), + + RegStackPop(Operation<'func, M, F, operation::RegStackPop>), + + Add(Operation<'func, M, F, operation::BinaryOp>), + Adc(Operation<'func, M, F, operation::BinaryOpCarry>), + Sub(Operation<'func, M, F, operation::BinaryOp>), + Sbb(Operation<'func, M, F, operation::BinaryOpCarry>), + And(Operation<'func, M, F, operation::BinaryOp>), + Or(Operation<'func, M, F, operation::BinaryOp>), + Xor(Operation<'func, M, F, operation::BinaryOp>), + Lsl(Operation<'func, M, F, operation::BinaryOp>), + Lsr(Operation<'func, M, F, operation::BinaryOp>), + Asr(Operation<'func, M, F, operation::BinaryOp>), + Rol(Operation<'func, M, F, operation::BinaryOp>), + Rlc(Operation<'func, M, F, operation::BinaryOpCarry>), + Ror(Operation<'func, M, F, operation::BinaryOp>), + Rrc(Operation<'func, M, F, operation::BinaryOpCarry>), + Mul(Operation<'func, M, F, operation::BinaryOp>), + + MulsDp(Operation<'func, M, F, operation::BinaryOp>), + MuluDp(Operation<'func, M, F, operation::BinaryOp>), + + Divu(Operation<'func, M, F, operation::BinaryOp>), + Divs(Operation<'func, M, F, operation::BinaryOp>), + + DivuDp(Operation<'func, M, F, operation::DoublePrecDivOp>), + DivsDp(Operation<'func, M, F, operation::DoublePrecDivOp>), + + Modu(Operation<'func, M, F, operation::BinaryOp>), + Mods(Operation<'func, M, F, operation::BinaryOp>), + + ModuDp(Operation<'func, M, F, operation::DoublePrecDivOp>), + ModsDp(Operation<'func, M, F, operation::DoublePrecDivOp>), + + Neg(Operation<'func, M, F, operation::UnaryOp>), + Not(Operation<'func, M, F, operation::UnaryOp>), + Sx(Operation<'func, M, F, operation::UnaryOp>), + Zx(Operation<'func, M, F, operation::UnaryOp>), + LowPart(Operation<'func, M, F, operation::UnaryOp>), // Valid only in Lifted IL - FlagCond(Operation<'func, A, M, NonSSA, operation::FlagCond>), + FlagCond(Operation<'func, M, NonSSA, operation::FlagCond>), // Valid only in Lifted IL - FlagGroup(Operation<'func, A, M, NonSSA, operation::FlagGroup>), - - CmpE(Operation<'func, A, M, F, operation::Condition>), - CmpNe(Operation<'func, A, M, F, operation::Condition>), - CmpSlt(Operation<'func, A, M, F, operation::Condition>), - CmpUlt(Operation<'func, A, M, F, operation::Condition>), - CmpSle(Operation<'func, A, M, F, operation::Condition>), - CmpUle(Operation<'func, A, M, F, operation::Condition>), - CmpSge(Operation<'func, A, M, F, operation::Condition>), - CmpUge(Operation<'func, A, M, F, operation::Condition>), - CmpSgt(Operation<'func, A, M, F, operation::Condition>), - CmpUgt(Operation<'func, A, M, F, operation::Condition>), - - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO - BoolToInt(Operation<'func, A, M, F, operation::UnaryOp>), - - Fadd(Operation<'func, A, M, F, operation::BinaryOp>), - Fsub(Operation<'func, A, M, F, operation::BinaryOp>), - Fmul(Operation<'func, A, M, F, operation::BinaryOp>), - Fdiv(Operation<'func, A, M, F, operation::BinaryOp>), - Fsqrt(Operation<'func, A, M, F, operation::UnaryOp>), - Fneg(Operation<'func, A, M, F, operation::UnaryOp>), - Fabs(Operation<'func, A, M, F, operation::UnaryOp>), - FloatToInt(Operation<'func, A, M, F, operation::UnaryOp>), - IntToFloat(Operation<'func, A, M, F, operation::UnaryOp>), - FloatConv(Operation<'func, A, M, F, operation::UnaryOp>), - RoundToInt(Operation<'func, A, M, F, operation::UnaryOp>), - Floor(Operation<'func, A, M, F, operation::UnaryOp>), - Ceil(Operation<'func, A, M, F, operation::UnaryOp>), - Ftrunc(Operation<'func, A, M, F, operation::UnaryOp>), - - FcmpE(Operation<'func, A, M, F, operation::Condition>), - FcmpNE(Operation<'func, A, M, F, operation::Condition>), - FcmpLT(Operation<'func, A, M, F, operation::Condition>), - FcmpLE(Operation<'func, A, M, F, operation::Condition>), - FcmpGE(Operation<'func, A, M, F, operation::Condition>), - FcmpGT(Operation<'func, A, M, F, operation::Condition>), - FcmpO(Operation<'func, A, M, F, operation::Condition>), - FcmpUO(Operation<'func, A, M, F, operation::Condition>), + FlagGroup(Operation<'func, M, NonSSA, operation::FlagGroup>), + + CmpE(Operation<'func, M, F, operation::Condition>), + CmpNe(Operation<'func, M, F, operation::Condition>), + CmpSlt(Operation<'func, M, F, operation::Condition>), + CmpUlt(Operation<'func, M, F, operation::Condition>), + CmpSle(Operation<'func, M, F, operation::Condition>), + CmpUle(Operation<'func, M, F, operation::Condition>), + CmpSge(Operation<'func, M, F, operation::Condition>), + CmpUge(Operation<'func, M, F, operation::Condition>), + CmpSgt(Operation<'func, M, F, operation::Condition>), + CmpUgt(Operation<'func, M, F, operation::Condition>), + + //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO + BoolToInt(Operation<'func, M, F, operation::UnaryOp>), + + Fadd(Operation<'func, M, F, operation::BinaryOp>), + Fsub(Operation<'func, M, F, operation::BinaryOp>), + Fmul(Operation<'func, M, F, operation::BinaryOp>), + Fdiv(Operation<'func, M, F, operation::BinaryOp>), + Fsqrt(Operation<'func, M, F, operation::UnaryOp>), + Fneg(Operation<'func, M, F, operation::UnaryOp>), + Fabs(Operation<'func, M, F, operation::UnaryOp>), + FloatToInt(Operation<'func, M, F, operation::UnaryOp>), + IntToFloat(Operation<'func, M, F, operation::UnaryOp>), + FloatConv(Operation<'func, M, F, operation::UnaryOp>), + RoundToInt(Operation<'func, M, F, operation::UnaryOp>), + Floor(Operation<'func, M, F, operation::UnaryOp>), + Ceil(Operation<'func, M, F, operation::UnaryOp>), + Ftrunc(Operation<'func, M, F, operation::UnaryOp>), + + FcmpE(Operation<'func, M, F, operation::Condition>), + FcmpNE(Operation<'func, M, F, operation::Condition>), + FcmpLT(Operation<'func, M, F, operation::Condition>), + FcmpLE(Operation<'func, M, F, operation::Condition>), + FcmpGE(Operation<'func, M, F, operation::Condition>), + FcmpGT(Operation<'func, M, F, operation::Condition>), + FcmpO(Operation<'func, M, F, operation::Condition>), + FcmpUO(Operation<'func, M, F, operation::Condition>), // TODO ADD_OVERFLOW - Unimpl(Operation<'func, A, M, F, operation::NoArgs>), - UnimplMem(Operation<'func, A, M, F, operation::UnimplMem>), + Unimpl(Operation<'func, M, F, operation::NoArgs>), + UnimplMem(Operation<'func, M, F, operation::UnimplMem>), - Undef(Operation<'func, A, M, F, operation::NoArgs>), + Undef(Operation<'func, M, F, operation::NoArgs>), } -impl<'func, A, M, F> LowLevelILExpressionKind<'func, A, M, F> +impl<'func, M, F> LowLevelILExpressionKind<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { // TODO: Document what "unchecked" means and how to consume this safely. pub(crate) unsafe fn from_raw( - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, op: BNLowLevelILInstruction, ) -> Self { use binaryninjacore_sys::BNLowLevelILOperation::*; @@ -472,7 +460,7 @@ where } _ => Some(self.raw_struct().size), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO } } @@ -492,7 +480,7 @@ where } } - pub fn as_cmp_op(&self) -> Option<&Operation<'func, A, M, F, operation::Condition>> { + pub fn as_cmp_op(&self) -> Option<&Operation<'func, M, F, operation::Condition>> { use self::LowLevelILExpressionKind::*; match *self { @@ -504,7 +492,7 @@ where } } - pub fn as_binary_op(&self) -> Option<&Operation<'func, A, M, F, operation::BinaryOp>> { + pub fn as_binary_op(&self) -> Option<&Operation<'func, M, F, operation::BinaryOp>> { use self::LowLevelILExpressionKind::*; match *self { @@ -516,9 +504,7 @@ where } } - pub fn as_binary_op_carry( - &self, - ) -> Option<&Operation<'func, A, M, F, operation::BinaryOpCarry>> { + pub fn as_binary_op_carry(&self) -> Option<&Operation<'func, M, F, operation::BinaryOpCarry>> { use self::LowLevelILExpressionKind::*; match *self { @@ -529,7 +515,7 @@ where pub fn as_double_prec_div_op( &self, - ) -> Option<&Operation<'func, A, M, F, operation::DoublePrecDivOp>> { + ) -> Option<&Operation<'func, M, F, operation::DoublePrecDivOp>> { use self::LowLevelILExpressionKind::*; match *self { @@ -538,7 +524,7 @@ where } } - pub fn as_unary_op(&self) -> Option<&Operation<'func, A, M, F, operation::UnaryOp>> { + pub fn as_unary_op(&self) -> Option<&Operation<'func, M, F, operation::UnaryOp>> { use self::LowLevelILExpressionKind::*; match *self { @@ -552,7 +538,7 @@ where pub fn visit_sub_expressions(&self, mut visitor: T) -> VisitorAction where - T: FnMut(LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction, + T: FnMut(LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction, { use LowLevelILExpressionKind::*; @@ -659,16 +645,13 @@ where | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op, UnimplMem(ref op) => &op.op, - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO } } } -impl<'func, A> LowLevelILExpressionKind<'func, A, Mutable, NonSSA> -where - A: 'func + Architecture, -{ - pub fn flag_write(&self) -> Option { +impl<'func> LowLevelILExpressionKind<'func, Mutable, NonSSA> { + pub fn flag_write(&self) -> Option { use self::LowLevelILExpressionKind::*; match *self { @@ -720,7 +703,7 @@ where | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(), UnimplMem(ref op) => op.flag_write(), - //TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO + //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO } } } diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 301c3f0968..21eebc3cc7 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -17,7 +17,6 @@ use binaryninjacore_sys::BNGetLowLevelILOwnerFunction; use binaryninjacore_sys::BNLowLevelILFunction; use binaryninjacore_sys::BNNewLowLevelILFunctionReference; -use std::borrow::Borrow; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; @@ -57,51 +56,56 @@ pub trait FunctionForm: 'static + Debug {} impl FunctionForm for SSA {} impl FunctionForm for NonSSA {} -pub struct LowLevelILFunction { - pub(crate) arch_handle: A::Handle, +pub struct LowLevelILFunction { pub(crate) handle: *mut BNLowLevelILFunction, - _arch: PhantomData<*mut A>, + arch: Option, _mutability: PhantomData, _form: PhantomData, } -impl LowLevelILFunction +impl LowLevelILFunction where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub(crate) unsafe fn from_raw( - arch_handle: A::Handle, + pub(crate) unsafe fn from_raw_with_arch( handle: *mut BNLowLevelILFunction, + arch: Option, ) -> Self { debug_assert!(!handle.is_null()); Self { - arch_handle, handle, - _arch: PhantomData, + arch, _mutability: PhantomData, _form: PhantomData, } } - pub(crate) unsafe fn ref_from_raw( - arch_handle: A::Handle, + pub(crate) unsafe fn from_raw(handle: *mut BNLowLevelILFunction) -> Self { + Self::from_raw_with_arch(handle, None) + } + + pub(crate) unsafe fn ref_from_raw_with_arch( handle: *mut BNLowLevelILFunction, + arch: Option, ) -> Ref { debug_assert!(!handle.is_null()); - Ref::new(Self::from_raw(arch_handle, handle)) + Ref::new(Self::from_raw_with_arch(handle, arch)) } - pub(crate) fn arch(&self) -> &A { - self.arch_handle.borrow() + pub(crate) unsafe fn ref_from_raw(handle: *mut BNLowLevelILFunction) -> Ref { + Self::ref_from_raw_with_arch(handle, None) } - pub fn instruction_at>( - &self, - loc: L, - ) -> Option> { + pub(crate) fn arch(&self) -> CoreArchitecture { + match self.arch { + None => self.function().arch(), + Some(arch) => arch, + } + } + + pub fn instruction_at>(&self, loc: L) -> Option> { Some(LowLevelILInstruction::new( self, self.instruction_index_at(loc)?, @@ -128,7 +132,7 @@ where pub fn instruction_from_index( &self, index: LowLevelInstructionIndex, - ) -> Option> { + ) -> Option> { if index.0 >= self.instruction_count() { None } else { @@ -161,12 +165,8 @@ where // LLIL basic blocks are not available until the function object // is finalized, so ensure we can't try requesting basic blocks // during lifting -impl LowLevelILFunction -where - A: Architecture, - F: FunctionForm, -{ - pub fn basic_blocks(&self) -> Array>> { +impl LowLevelILFunction { + pub fn basic_blocks(&self) -> Array>> { use binaryninjacore_sys::BNGetLowLevelILBasicBlockList; unsafe { @@ -179,7 +179,7 @@ where } // Allow instantiating Lifted IL functions for querying Lifted IL from Architectures -impl LowLevelILFunction> { +impl LowLevelILFunction> { // TODO: Document what happens when you pass None for `source_func`. // TODO: Doing so would construct a LowLevelILFunction with no basic blocks // TODO: Document why you would want to do that. @@ -196,7 +196,7 @@ impl LowLevelILFunction> { // BNCreateLowLevelILFunction should always return a valid object. assert!(!handle.is_null()); - unsafe { Self::ref_from_raw(arch, handle) } + unsafe { Self::ref_from_raw_with_arch(handle, Some(arch)) } } pub fn generate_ssa_form(&self) { @@ -206,9 +206,8 @@ impl LowLevelILFunction> { } } -impl ToOwned for LowLevelILFunction +impl ToOwned for LowLevelILFunction where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -219,17 +218,15 @@ where } } -unsafe impl RefCountable for LowLevelILFunction +unsafe impl RefCountable for LowLevelILFunction where - A: Architecture, M: FunctionMutability, F: FunctionForm, { unsafe fn inc_ref(handle: &Self) -> Ref { Ref::new(Self { - arch_handle: handle.arch_handle.clone(), handle: BNNewLowLevelILFunctionReference(handle.handle), - _arch: PhantomData, + arch: handle.arch, _mutability: PhantomData, _form: PhantomData, }) @@ -240,9 +237,8 @@ where } } -impl Debug for LowLevelILFunction +impl Debug for LowLevelILFunction where - A: Architecture + Debug, M: FunctionMutability, F: FunctionForm, { @@ -255,26 +251,18 @@ where } } -unsafe impl Send - for LowLevelILFunction -{ -} -unsafe impl Sync - for LowLevelILFunction -{ -} +unsafe impl Send for LowLevelILFunction {} +unsafe impl Sync for LowLevelILFunction {} -impl Eq for LowLevelILFunction {} +impl Eq for LowLevelILFunction {} -impl PartialEq - for LowLevelILFunction -{ +impl PartialEq for LowLevelILFunction { fn eq(&self, rhs: &Self) -> bool { self.function().eq(&rhs.function()) } } -impl Hash for LowLevelILFunction { +impl Hash for LowLevelILFunction { fn hash(&self, state: &mut H) { self.function().hash(state) } diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index 977dcff4f4..a1253df5b3 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -16,7 +16,6 @@ use super::operation; use super::operation::Operation; use super::VisitorAction; use super::*; -use crate::architecture::Architecture; use binaryninjacore_sys::BNGetLowLevelILByIndex; use binaryninjacore_sys::BNGetLowLevelILIndexForInstruction; use binaryninjacore_sys::BNLowLevelILInstruction; @@ -51,44 +50,38 @@ impl Display for LowLevelInstructionIndex { } // TODO: Probably want to rename this with a LowLevelIL prefix to avoid collisions when we add handlers for other ILs -pub trait InstructionHandler<'func, A, M, F> +pub trait InstructionHandler<'func, M, F> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - fn kind(&self) -> LowLevelILInstructionKind<'func, A, M, F>; + fn kind(&self) -> LowLevelILInstructionKind<'func, M, F>; /// Visit the sub expressions of this instruction. /// /// NOTE: This does not visit the root expression, i.e. the instruction. fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction; + T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction; } -pub struct LowLevelILInstruction<'func, A, M, F> +pub struct LowLevelILInstruction<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - pub(crate) function: &'func LowLevelILFunction, + pub(crate) function: &'func LowLevelILFunction, pub index: LowLevelInstructionIndex, } -impl<'func, A, M, F> LowLevelILInstruction<'func, A, M, F> +impl<'func, M, F> LowLevelILInstruction<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { // TODO: Should we check the instruction count here with BNGetLowLevelILInstructionCount? // TODO: If we _can_ then this should become an Option methinks - pub fn new( - function: &'func LowLevelILFunction, - index: LowLevelInstructionIndex, - ) -> Self { + pub fn new(function: &'func LowLevelILFunction, index: LowLevelInstructionIndex) -> Self { Self { function, index } } @@ -107,9 +100,8 @@ where } } -impl<'func, A, M, F> Debug for LowLevelILInstruction<'func, A, M, F> +impl<'func, M, F> Debug for LowLevelILInstruction<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { @@ -122,12 +114,11 @@ where } } -impl<'func, A, M> InstructionHandler<'func, A, M, SSA> for LowLevelILInstruction<'func, A, M, SSA> +impl<'func, M> InstructionHandler<'func, M, SSA> for LowLevelILInstruction<'func, M, SSA> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILInstructionKind<'func, A, M, SSA> { + fn kind(&self) -> LowLevelILInstructionKind<'func, M, SSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let raw_op = self.into_raw(); @@ -143,20 +134,19 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, A, M, SSA, ValueExpr>) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, SSA, ValueExpr>) -> VisitorAction, { // Recursively visit sub expressions. self.kind().visit_sub_expressions(|e| e.visit_tree(f)) } } -impl<'func, A, M> InstructionHandler<'func, A, M, NonSSA> - for LowLevelILInstruction<'func, A, M, NonSSA> +impl<'func, M> InstructionHandler<'func, M, NonSSA> + for LowLevelILInstruction<'func, M, NonSSA> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILInstructionKind<'func, A, M, NonSSA> { + fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let raw_op = self.into_raw(); @@ -172,22 +162,19 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut( - &LowLevelILExpression<'func, A, M, NonSSA, ValueExpr>, - ) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, { // Recursively visit sub expressions. self.kind().visit_sub_expressions(|e| e.visit_tree(f)) } } -impl<'func, A, M> InstructionHandler<'func, A, M, NonSSA> - for LowLevelILInstruction<'func, A, M, NonSSA> +impl<'func, M> InstructionHandler<'func, M, NonSSA> + for LowLevelILInstruction<'func, M, NonSSA> where - A: 'func + Architecture, M: FunctionMutability, { - fn kind(&self) -> LowLevelILInstructionKind<'func, A, M, NonSSA> { + fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let raw_op = self.into_raw(); @@ -204,7 +191,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where T: FnMut( - &LowLevelILExpression<'func, A, M, NonSSA, ValueExpr>, + &LowLevelILExpression<'func, M, NonSSA, ValueExpr>, ) -> VisitorAction, { // Recursively visit sub expressions. @@ -213,52 +200,50 @@ where } #[derive(Debug)] -pub enum LowLevelILInstructionKind<'func, A, M, F> +pub enum LowLevelILInstructionKind<'func, M, F> where - A: 'func + Architecture, M: FunctionMutability, F: FunctionForm, { - Nop(Operation<'func, A, M, F, operation::NoArgs>), - SetReg(Operation<'func, A, M, F, operation::SetReg>), - SetRegSplit(Operation<'func, A, M, F, operation::SetRegSplit>), - SetFlag(Operation<'func, A, M, F, operation::SetFlag>), - Store(Operation<'func, A, M, F, operation::Store>), + Nop(Operation<'func, M, F, operation::NoArgs>), + SetReg(Operation<'func, M, F, operation::SetReg>), + SetRegSplit(Operation<'func, M, F, operation::SetRegSplit>), + SetFlag(Operation<'func, M, F, operation::SetFlag>), + Store(Operation<'func, M, F, operation::Store>), // TODO needs a real op - Push(Operation<'func, A, M, F, operation::UnaryOp>), + Push(Operation<'func, M, F, operation::UnaryOp>), - RegStackPush(Operation<'func, A, M, F, operation::RegStackPush>), + RegStackPush(Operation<'func, M, F, operation::RegStackPush>), - Jump(Operation<'func, A, M, F, operation::Jump>), - JumpTo(Operation<'func, A, M, F, operation::JumpTo>), + Jump(Operation<'func, M, F, operation::Jump>), + JumpTo(Operation<'func, M, F, operation::JumpTo>), - Call(Operation<'func, A, M, F, operation::Call>), - TailCall(Operation<'func, A, M, F, operation::Call>), + Call(Operation<'func, M, F, operation::Call>), + TailCall(Operation<'func, M, F, operation::Call>), - Ret(Operation<'func, A, M, F, operation::Ret>), - NoRet(Operation<'func, A, M, F, operation::NoArgs>), + Ret(Operation<'func, M, F, operation::Ret>), + NoRet(Operation<'func, M, F, operation::NoArgs>), - If(Operation<'func, A, M, F, operation::If>), - Goto(Operation<'func, A, M, F, operation::Goto>), + If(Operation<'func, M, F, operation::If>), + Goto(Operation<'func, M, F, operation::Goto>), - Syscall(Operation<'func, A, M, F, operation::Syscall>), - Intrinsic(Operation<'func, A, M, F, operation::Intrinsic>), - Bp(Operation<'func, A, M, F, operation::NoArgs>), - Trap(Operation<'func, A, M, F, operation::Trap>), - Undef(Operation<'func, A, M, F, operation::NoArgs>), + Syscall(Operation<'func, M, F, operation::Syscall>), + Intrinsic(Operation<'func, M, F, operation::Intrinsic>), + Bp(Operation<'func, M, F, operation::NoArgs>), + Trap(Operation<'func, M, F, operation::Trap>), + Undef(Operation<'func, M, F, operation::NoArgs>), /// The instruction is an expression. - Value(LowLevelILExpression<'func, A, M, F, ValueExpr>), + Value(LowLevelILExpression<'func, M, F, ValueExpr>), } -impl<'func, A, M, F> LowLevelILInstructionKind<'func, A, M, F> +impl<'func, M, F> LowLevelILInstructionKind<'func, M, F> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { pub(crate) unsafe fn from_raw( - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, expr_index: LowLevelExpressionIndex, op: BNLowLevelILInstruction, ) -> Self { @@ -315,7 +300,7 @@ where fn visit_sub_expressions(&self, mut visitor: T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, A, M, F, ValueExpr>) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction, { use LowLevelILInstructionKind::*; diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index 7401c99b57..c40f68f2e9 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -18,35 +18,33 @@ use binaryninjacore_sys::{BNAddLowLevelILLabelForAddress, BNLowLevelILOperation} use binaryninjacore_sys::{BNLowLevelILLabel, BNRegisterOrConstant}; use super::*; -use crate::architecture::Register as ArchReg; use crate::architecture::{Architecture, FlagWriteId, RegisterId}; +use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::architecture::{ Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic, }; use crate::function::Location; -pub trait LiftableLowLevelIL<'func, A: 'func + Architecture> { +pub trait LiftableLowLevelIL<'func> { type Result: ExpressionResultType; fn lift( - il: &'func MutableLiftedILFunction, + il: &'func MutableLiftedILFunction, expr: Self, - ) -> MutableLiftedILExpr<'func, A, Self::Result>; + ) -> MutableLiftedILExpr<'func, Self::Result>; } -pub trait LiftableLowLevelILWithSize<'func, A: 'func + Architecture>: - LiftableLowLevelIL<'func, A, Result = ValueExpr> -{ +pub trait LiftableLowLevelILWithSize<'func>: LiftableLowLevelIL<'func, Result = ValueExpr> { fn lift_with_size( - il: &'func MutableLiftedILFunction, + il: &'func MutableLiftedILFunction, expr: Self, size: usize, - ) -> MutableLiftedILExpr<'func, A, ValueExpr>; + ) -> MutableLiftedILExpr<'func, ValueExpr>; } #[derive(Copy, Clone)] pub enum LowLevelILRegisterOrConstant { - Register(usize, LowLevelILRegister), + Register(usize, LowLevelILRegisterKind), Constant(usize, u64), } @@ -267,14 +265,9 @@ impl LowLevelILFlagWriteOp { if operand.constant { LowLevelILRegisterOrConstant::Constant(size, operand.value) } else { - let il_reg = if 0x8000_0000 & operand.reg == 0 { - LowLevelILRegister::ArchReg( - arch.register_from_id(RegisterId(operand.reg)).unwrap(), - ) - } else { - LowLevelILRegister::Temp(operand.reg) - }; - + let raw_id = RegisterId(operand.reg); + let il_reg = + LowLevelILRegisterKind::from_raw(arch, raw_id).expect("Bad register ID"); LowLevelILRegisterOrConstant::Register(size, il_reg) } } @@ -466,8 +459,8 @@ pub fn get_default_flag_write_llil<'func, A>( arch: &A, role: FlagRole, op: LowLevelILFlagWriteOp, - il: &'func MutableLiftedILFunction, -) -> MutableLiftedILExpr<'func, A, ValueExpr> + il: &'func MutableLiftedILFunction, +) -> MutableLiftedILExpr<'func, ValueExpr> where A: 'func + Architecture, { @@ -494,8 +487,8 @@ pub fn get_default_flag_cond_llil<'func, A>( arch: &A, cond: FlagCondition, class: Option, - il: &'func MutableLiftedILFunction, -) -> MutableLiftedILExpr<'func, A, ValueExpr> + il: &'func MutableLiftedILFunction, +) -> MutableLiftedILExpr<'func, ValueExpr> where A: 'func + Architecture, { @@ -516,19 +509,19 @@ where macro_rules! prim_int_lifter { ($x:ty) => { - impl<'a, A: 'a + Architecture> LiftableLowLevelIL<'a, A> for $x { + impl<'a> LiftableLowLevelIL<'a> for $x { type Result = ValueExpr; - fn lift(il: &'a MutableLiftedILFunction, val: Self) - -> MutableLiftedILExpr<'a, A, Self::Result> + fn lift(il: &'a MutableLiftedILFunction, val: Self) + -> MutableLiftedILExpr<'a, Self::Result> { il.const_int(std::mem::size_of::(), val as i64 as u64) } } - impl<'a, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> for $x { - fn lift_with_size(il: &'a MutableLiftedILFunction, val: Self, size: usize) - -> MutableLiftedILExpr<'a, A, ValueExpr> + impl<'a> LiftableLowLevelILWithSize<'a> for $x { + fn lift_with_size(il: &'a MutableLiftedILFunction, val: Self, size: usize) + -> MutableLiftedILExpr<'a, ValueExpr> { let raw = val as i64; @@ -561,57 +554,51 @@ prim_int_lifter!(u16); prim_int_lifter!(u32); prim_int_lifter!(u64); -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableLowLevelIL<'a, A> for LowLevelILRegister +impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILRegisterKind where - R: LiftableLowLevelIL<'a, A, Result = ValueExpr> + Into>, + R: LiftableLowLevelIL<'a, Result = ValueExpr> + Into> + ArchReg, { type Result = ValueExpr; - fn lift( - il: &'a MutableLiftedILFunction, - reg: Self, - ) -> MutableLiftedILExpr<'a, A, Self::Result> { + fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { match reg { - LowLevelILRegister::ArchReg(r) => R::lift(il, r), - LowLevelILRegister::Temp(t) => il.reg( + LowLevelILRegisterKind::Arch(r) => R::lift(il, r), + LowLevelILRegisterKind::Temp(t) => il.reg( il.arch().default_integer_size(), - LowLevelILRegister::Temp(t), + LowLevelILRegisterKind::Temp::(t), ), } } } -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> - for LowLevelILRegister +impl<'a, R> LiftableLowLevelILWithSize<'a> for LowLevelILRegisterKind where - R: LiftableLowLevelILWithSize<'a, A> + Into>, + R: LiftableLowLevelILWithSize<'a> + Into> + ArchReg, { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, A, ValueExpr> { + ) -> MutableLiftedILExpr<'a, ValueExpr> { match reg { - LowLevelILRegister::ArchReg(r) => R::lift_with_size(il, r, size), - LowLevelILRegister::Temp(t) => il.reg(size, LowLevelILRegister::Temp(t)), + LowLevelILRegisterKind::Arch(r) => R::lift_with_size(il, r, size), + LowLevelILRegisterKind::Temp(t) => il.reg(size, LowLevelILRegisterKind::::Temp(t)), } } } -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableLowLevelIL<'a, A> - for LowLevelILRegisterOrConstant +impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILRegisterOrConstant where - R: LiftableLowLevelILWithSize<'a, A, Result = ValueExpr> + Into>, + R: LiftableLowLevelILWithSize<'a, Result = ValueExpr> + + Into> + + ArchReg, { type Result = ValueExpr; - fn lift( - il: &'a MutableLiftedILFunction, - reg: Self, - ) -> MutableLiftedILExpr<'a, A, Self::Result> { + fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { match reg { LowLevelILRegisterOrConstant::Register(size, r) => { - LowLevelILRegister::::lift_with_size(il, r, size) + LowLevelILRegisterKind::::lift_with_size(il, r, size) } LowLevelILRegisterOrConstant::Constant(size, value) => { u64::lift_with_size(il, value, size) @@ -620,20 +607,19 @@ where } } -impl<'a, R: ArchReg, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> - for LowLevelILRegisterOrConstant +impl<'a, R> LiftableLowLevelILWithSize<'a> for LowLevelILRegisterOrConstant where - R: LiftableLowLevelILWithSize<'a, A> + Into>, + R: LiftableLowLevelILWithSize<'a> + Into> + ArchReg, { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, A, ValueExpr> { + ) -> MutableLiftedILExpr<'a, ValueExpr> { // TODO ensure requested size is compatible with size of this constant match reg { LowLevelILRegisterOrConstant::Register(_, r) => { - LowLevelILRegister::::lift_with_size(il, r, size) + LowLevelILRegisterKind::::lift_with_size(il, r, size) } LowLevelILRegisterOrConstant::Constant(_, value) => { u64::lift_with_size(il, value, size) @@ -642,31 +628,26 @@ where } } -impl<'a, A, R> LiftableLowLevelIL<'a, A> - for LowLevelILExpression<'a, A, Mutable, NonSSA, R> +impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILExpression<'a, Mutable, NonSSA, R> where - A: 'a + Architecture, R: ExpressionResultType, { type Result = R; - fn lift( - il: &'a MutableLiftedILFunction, - expr: Self, - ) -> MutableLiftedILExpr<'a, A, Self::Result> { + fn lift(il: &'a MutableLiftedILFunction, expr: Self) -> MutableLiftedILExpr<'a, Self::Result> { debug_assert!(expr.function.handle == il.handle); expr } } -impl<'a, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> - for LowLevelILExpression<'a, A, Mutable, NonSSA, ValueExpr> +impl<'a> LiftableLowLevelILWithSize<'a> + for LowLevelILExpression<'a, Mutable, NonSSA, ValueExpr> { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, expr: Self, _size: usize, - ) -> MutableLiftedILExpr<'a, A, Self::Result> { + ) -> MutableLiftedILExpr<'a, Self::Result> { #[cfg(debug_assertions)] { use crate::low_level_il::ExpressionHandler; @@ -686,9 +667,8 @@ impl<'a, A: 'a + Architecture> LiftableLowLevelILWithSize<'a, A> } } -impl<'func, A, R> LowLevelILExpression<'func, A, Mutable, NonSSA, R> +impl<'func, R> LowLevelILExpression<'func, Mutable, NonSSA, R> where - A: 'func + Architecture, R: ExpressionResultType, { pub fn with_source_operand(self, op: u32) -> Self { @@ -702,12 +682,11 @@ where } } -pub struct ExpressionBuilder<'func, A, R> +pub struct ExpressionBuilder<'func, R> where - A: 'func + Architecture, R: ExpressionResultType, { - function: &'func LowLevelILFunction>, + function: &'func LowLevelILFunction>, op: BNLowLevelILOperation, size: usize, flag_write: FlagWriteId, @@ -718,12 +697,11 @@ where _ty: PhantomData, } -impl<'a, A, R> ExpressionBuilder<'a, A, R> +impl<'a, R> ExpressionBuilder<'a, R> where - A: 'a + Architecture, R: ExpressionResultType, { - pub fn from_expr(expr: LowLevelILExpression<'a, A, Mutable, NonSSA, R>) -> Self { + pub fn from_expr(expr: LowLevelILExpression<'a, Mutable, NonSSA, R>) -> Self { use binaryninjacore_sys::BNGetLowLevelILByIndex; let instr = unsafe { BNGetLowLevelILByIndex(expr.function.handle, expr.index.0) }; @@ -741,13 +719,13 @@ where } } - pub fn with_flag_write(mut self, flag_write: A::FlagWrite) -> Self { + pub fn with_flag_write(mut self, flag_write: impl FlagWrite) -> Self { // TODO verify valid id self.flag_write = flag_write.id(); self } - pub fn build(self) -> LowLevelILExpression<'a, A, Mutable, NonSSA, R> { + pub fn build(self) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { use binaryninjacore_sys::BNLowLevelILAddExpr; let expr_idx = unsafe { @@ -769,7 +747,7 @@ where pub fn with_source_operand( self, op: u32, - ) -> LowLevelILExpression<'a, A, Mutable, NonSSA, R> { + ) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { self.build().with_source_operand(op) } @@ -779,32 +757,25 @@ where } } -impl<'a, A, R> LiftableLowLevelIL<'a, A> for ExpressionBuilder<'a, A, R> +impl<'a, R> LiftableLowLevelIL<'a> for ExpressionBuilder<'a, R> where - A: 'a + Architecture, R: ExpressionResultType, { type Result = R; - fn lift( - il: &'a MutableLiftedILFunction, - expr: Self, - ) -> MutableLiftedILExpr<'a, A, Self::Result> { + fn lift(il: &'a MutableLiftedILFunction, expr: Self) -> MutableLiftedILExpr<'a, Self::Result> { debug_assert!(expr.function.handle == il.handle); expr.build() } } -impl<'a, A> LiftableLowLevelILWithSize<'a, A> for ExpressionBuilder<'a, A, ValueExpr> -where - A: 'a + Architecture, -{ +impl<'a> LiftableLowLevelILWithSize<'a> for ExpressionBuilder<'a, ValueExpr> { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, expr: Self, _size: usize, - ) -> MutableLiftedILExpr<'a, A, ValueExpr> { + ) -> MutableLiftedILExpr<'a, ValueExpr> { #[cfg(debug_assertions)] { use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_UNIMPL, LLIL_UNIMPL_MEM}; @@ -825,7 +796,7 @@ where macro_rules! no_arg_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self) -> LowLevelILExpression, $result> { + pub fn $name(&self) -> LowLevelILExpression, $result> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -838,7 +809,7 @@ macro_rules! no_arg_lifter { macro_rules! sized_no_arg_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self, size: usize) -> ExpressionBuilder { + pub fn $name(&self, size: usize) -> ExpressionBuilder<$result> { use binaryninjacore_sys::BNLowLevelILOperation::$op; ExpressionBuilder { @@ -861,9 +832,9 @@ macro_rules! unsized_unary_op_lifter { pub fn $name<'a, E>( &'a self, expr: E, - ) -> LowLevelILExpression<'a, A, Mutable, NonSSA, $result> + ) -> LowLevelILExpression<'a, Mutable, NonSSA, $result> where - E: LiftableLowLevelIL<'a, A, Result = ValueExpr>, + E: LiftableLowLevelIL<'a, Result = ValueExpr>, { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -881,9 +852,9 @@ macro_rules! unsized_unary_op_lifter { macro_rules! sized_unary_op_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> + pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, $result> where - E: LiftableLowLevelILWithSize<'a, A>, + E: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -906,9 +877,9 @@ macro_rules! sized_unary_op_lifter { macro_rules! size_changing_unary_op_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, A, $result> + pub fn $name<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, $result> where - E: LiftableLowLevelILWithSize<'a, A>, + E: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -936,10 +907,10 @@ macro_rules! binary_op_lifter { size: usize, left: L, right: R, - ) -> ExpressionBuilder<'a, A, ValueExpr> + ) -> ExpressionBuilder<'a, ValueExpr> where - L: LiftableLowLevelILWithSize<'a, A>, - R: LiftableLowLevelILWithSize<'a, A>, + L: LiftableLowLevelILWithSize<'a>, + R: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -969,11 +940,11 @@ macro_rules! binary_op_carry_lifter { left: L, right: R, carry: C, - ) -> ExpressionBuilder<'a, A, ValueExpr> + ) -> ExpressionBuilder<'a, ValueExpr> where - L: LiftableLowLevelILWithSize<'a, A>, - R: LiftableLowLevelILWithSize<'a, A>, - C: LiftableLowLevelILWithSize<'a, A>, + L: LiftableLowLevelILWithSize<'a>, + R: LiftableLowLevelILWithSize<'a>, + C: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -996,21 +967,18 @@ macro_rules! binary_op_carry_lifter { }; } -impl LowLevelILFunction> -where - A: Architecture, -{ - pub const NO_INPUTS: [ExpressionBuilder<'static, A, ValueExpr>; 0] = []; - pub const NO_OUTPUTS: [LowLevelILRegister; 0] = []; +impl LowLevelILFunction> { + pub const NO_INPUTS: [ExpressionBuilder<'static, ValueExpr>; 0] = []; + pub const NO_OUTPUTS: [LowLevelILRegisterKind; 0] = []; - pub fn expression<'a, E: LiftableLowLevelIL<'a, A>>( + pub fn expression<'a, E: LiftableLowLevelIL<'a>>( &'a self, expr: E, - ) -> LowLevelILExpression<'a, A, Mutable, NonSSA, E::Result> { + ) -> LowLevelILExpression<'a, Mutable, NonSSA, E::Result> { E::lift(self, expr) } - pub fn add_instruction<'a, E: LiftableLowLevelIL<'a, A>>(&'a self, expr: E) { + pub fn add_instruction<'a, E: LiftableLowLevelIL<'a>>(&'a self, expr: E) { let expr = self.expression(expr); unsafe { @@ -1019,7 +987,7 @@ where } } - pub unsafe fn replace_expression<'a, E: LiftableLowLevelIL<'a, A>>( + pub unsafe fn replace_expression<'a, E: LiftableLowLevelIL<'a>>( &'a self, replaced_expr_index: LowLevelExpressionIndex, replacement: E, @@ -1038,7 +1006,7 @@ where &self, size: usize, val: u64, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST; @@ -1052,7 +1020,7 @@ where &self, size: usize, val: u64, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST_PTR; @@ -1065,14 +1033,11 @@ where pub fn const_ptr( &self, val: u64, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILExpression, ValueExpr> { self.const_ptr_sized(self.arch().address_size(), val) } - pub fn trap( - &self, - val: u64, - ) -> LowLevelILExpression, VoidExpr> { + pub fn trap(&self, val: u64) -> LowLevelILExpression, VoidExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_TRAP; @@ -1099,9 +1064,9 @@ where cond: C, true_label: &'b mut LowLevelILLabel, false_label: &'b mut LowLevelILLabel, - ) -> LowLevelILExpression<'a, A, Mutable, NonSSA, VoidExpr> + ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> where - C: LiftableLowLevelIL<'b, A, Result = ValueExpr>, + C: LiftableLowLevelIL<'b, Result = ValueExpr>, { use binaryninjacore_sys::BNLowLevelILIf; @@ -1139,7 +1104,7 @@ where pub fn goto<'a: 'b, 'b>( &'a self, label: &'b mut LowLevelILLabel, - ) -> LowLevelILExpression<'a, A, Mutable, NonSSA, VoidExpr> { + ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> { use binaryninjacore_sys::BNLowLevelILGoto; let mut raw_label = BNLowLevelILLabel::from(*label); @@ -1156,11 +1121,11 @@ where LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn reg>>( + pub fn reg>>( &self, size: usize, - reg: R, - ) -> LowLevelILExpression, ValueExpr> { + reg: LR, + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG; @@ -1173,15 +1138,12 @@ where LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn reg_split< - H: Into>, - L: Into>, - >( + pub fn reg_split>>( &self, size: usize, - hi_reg: H, - lo_reg: L, - ) -> LowLevelILExpression, ValueExpr> { + hi_reg: LR, + lo_reg: LR, + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG_SPLIT; @@ -1205,15 +1167,16 @@ where LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn set_reg<'a, R, E>( + pub fn set_reg<'a, R, LR, E>( &'a self, size: usize, - dest_reg: R, + dest_reg: LR, expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> + ) -> ExpressionBuilder<'a, VoidExpr> where - R: Into>, - E: LiftableLowLevelILWithSize<'a, A>, + R: ArchReg, + LR: Into>, + E: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG; @@ -1236,17 +1199,17 @@ where } } - pub fn set_reg_split<'a, H, L, E>( + pub fn set_reg_split<'a, R, LR, E>( &'a self, size: usize, - hi_reg: H, - lo_reg: L, + hi_reg: LR, + lo_reg: LR, expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> + ) -> ExpressionBuilder<'a, VoidExpr> where - H: Into>, - L: Into>, - E: LiftableLowLevelILWithSize<'a, A>, + R: ArchReg, + LR: Into>, + E: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_REG_SPLIT; @@ -1260,7 +1223,6 @@ where function: self, op: LLIL_SET_REG_SPLIT, size, - // TODO: Make these optional? flag_write: FlagWriteId(0), op1: hi_reg.0 as u64, op2: lo_reg.0 as u64, @@ -1272,8 +1234,8 @@ where pub fn flag( &self, - flag: A::Flag, - ) -> LowLevelILExpression, ValueExpr> { + flag: impl Flag, + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG; @@ -1288,7 +1250,7 @@ where pub fn flag_cond( &self, cond: FlagCondition, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND; @@ -1301,8 +1263,8 @@ where pub fn flag_group( &self, - group: A::FlagGroup, - ) -> LowLevelILExpression, ValueExpr> { + group: impl FlagGroup, + ) -> LowLevelILExpression, ValueExpr> { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP; @@ -1325,11 +1287,11 @@ where pub fn set_flag<'a, E>( &'a self, - dest_flag: A::Flag, + dest_flag: impl Flag, expr: E, - ) -> ExpressionBuilder<'a, A, VoidExpr> + ) -> ExpressionBuilder<'a, VoidExpr> where - E: LiftableLowLevelILWithSize<'a, A>, + E: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_SET_FLAG; @@ -1355,9 +1317,9 @@ where FlagBit(usize, Flag, u64), */ - pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, A, ValueExpr> + pub fn load<'a, E>(&'a self, size: usize, source_mem: E) -> ExpressionBuilder<'a, ValueExpr> where - E: LiftableLowLevelIL<'a, A, Result = ValueExpr>, + E: LiftableLowLevelIL<'a, Result = ValueExpr>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_LOAD; @@ -1381,10 +1343,10 @@ where size: usize, dest_mem: D, value: V, - ) -> ExpressionBuilder<'a, A, VoidExpr> + ) -> ExpressionBuilder<'a, VoidExpr> where - D: LiftableLowLevelIL<'a, A, Result = ValueExpr>, - V: LiftableLowLevelILWithSize<'a, A>, + D: LiftableLowLevelIL<'a, Result = ValueExpr>, + V: LiftableLowLevelILWithSize<'a>, { use binaryninjacore_sys::BNLowLevelILOperation::LLIL_STORE; @@ -1404,18 +1366,17 @@ where } } - pub fn intrinsic<'a, O, OL, I, P, PL>( + // TODO: Reposition arguments. + pub fn intrinsic<'a, R, O, P>( &'a self, - outputs: OL, - intrinsic: I, - inputs: PL, - ) -> ExpressionBuilder<'a, A, VoidExpr> + outputs: impl IntoIterator, + intrinsic: impl Intrinsic, + inputs: impl IntoIterator, + ) -> ExpressionBuilder<'a, VoidExpr> where - O: Into>, - OL: IntoIterator, - I: Into, - P: LiftableLowLevelIL<'a, A, Result = ValueExpr>, - PL: IntoIterator, + R: ArchReg, + O: Into>, + P: LiftableLowLevelIL<'a, Result = ValueExpr>, { use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_CALL_PARAM, LLIL_INTRINSIC}; use binaryninjacore_sys::{BNLowLevelILAddExpr, BNLowLevelILAddOperandList}; @@ -1427,8 +1388,6 @@ where let output_expr_idx = unsafe { BNLowLevelILAddOperandList(self.handle, outputs.as_mut_ptr(), outputs.len()) }; - let intrinsic: A::Intrinsic = intrinsic.into(); - let mut inputs: Vec = inputs .into_iter() .map(|input| { diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index b1bc8ef43b..bd68bbb14d 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -15,33 +15,34 @@ use binaryninjacore_sys::{BNGetLowLevelILByIndex, BNLowLevelILInstruction}; use super::*; -use crate::architecture::{FlagGroupId, FlagId, FlagWriteId, IntrinsicId, RegisterStackId}; +use crate::architecture::{ + CoreFlag, CoreFlagGroup, CoreFlagWrite, CoreIntrinsic, CoreRegister, CoreRegisterStack, + FlagGroupId, FlagId, FlagWriteId, IntrinsicId, RegisterStackId, +}; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; use std::mem; -pub struct Operation<'func, A, M, F, O> +pub struct Operation<'func, M, F, O> where - A: Architecture, M: FunctionMutability, F: FunctionForm, O: OperationArguments, { - pub(crate) function: &'func LowLevelILFunction, + pub(crate) function: &'func LowLevelILFunction, pub(crate) op: BNLowLevelILInstruction, _args: PhantomData, } -impl<'func, A, M, F, O> Operation<'func, A, M, F, O> +impl<'func, M, F, O> Operation<'func, M, F, O> where - A: Architecture, M: FunctionMutability, F: FunctionForm, O: OperationArguments, { pub(crate) fn new( - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, op: BNLowLevelILInstruction, ) -> Self { Self { @@ -56,13 +57,12 @@ where } } -impl Operation<'_, A, M, NonSSA, O> +impl Operation<'_, M, NonSSA, O> where - A: Architecture, M: FunctionMutability, O: OperationArguments, { - pub fn flag_write(&self) -> Option { + pub fn flag_write(&self) -> Option { match self.op.flags { 0 => None, id => self.function.arch().flag_write_from_id(FlagWriteId(id)), @@ -73,9 +73,8 @@ where // LLIL_NOP, LLIL_NORET, LLIL_BP, LLIL_UNDEF, LLIL_UNIMPL pub struct NoArgs; -impl Debug for Operation<'_, A, M, F, NoArgs> +impl Debug for Operation<'_, M, F, NoArgs> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -87,9 +86,8 @@ where // LLIL_POP pub struct Pop; -impl Operation<'_, A, M, F, Pop> +impl Operation<'_, M, F, Pop> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -98,9 +96,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Pop> +impl Debug for Operation<'_, M, F, Pop> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -115,9 +112,8 @@ where // LLIL_SYSCALL, LLIL_SYSCALL_SSA pub struct Syscall; -impl Debug for Operation<'_, A, M, F, Syscall> +impl Debug for Operation<'_, M, F, Syscall> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -129,22 +125,20 @@ where // LLIL_INTRINSIC, LLIL_INTRINSIC_SSA pub struct Intrinsic; -impl Operation<'_, A, M, F, Intrinsic> +impl Operation<'_, M, F, Intrinsic> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { // TODO: Support register and expression lists - pub fn intrinsic(&self) -> Option { + pub fn intrinsic(&self) -> Option { let raw_id = self.op.operands[2] as u32; self.function.arch().intrinsic_from_id(IntrinsicId(raw_id)) } } -impl Debug for Operation<'_, A, M, F, Intrinsic> +impl Debug for Operation<'_, M, F, Intrinsic> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -159,9 +153,8 @@ where // LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA pub struct SetReg; -impl<'func, A, M, F> Operation<'func, A, M, F, SetReg> +impl<'func, M, F> Operation<'func, M, F, SetReg> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -169,28 +162,12 @@ where self.op.size } - pub fn dest_reg(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_SET_REG @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn dest_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } - pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -198,9 +175,8 @@ where } } -impl Debug for Operation<'_, A, M, F, SetReg> +impl Debug for Operation<'_, M, F, SetReg> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -217,9 +193,8 @@ where // LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA pub struct SetRegSplit; -impl<'func, A, M, F> Operation<'func, A, M, F, SetRegSplit> +impl<'func, M, F> Operation<'func, M, F, SetRegSplit> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -227,49 +202,17 @@ where self.op.size } - pub fn dest_reg_high(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn dest_reg_high(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } - pub fn dest_reg_low(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[1] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_SET_REG_SPLIT @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn dest_reg_low(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[1] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } - pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[2] as usize), @@ -277,9 +220,8 @@ where } } -impl Debug for Operation<'_, A, M, F, SetRegSplit> +impl Debug for Operation<'_, M, F, SetRegSplit> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -297,13 +239,12 @@ where // LLIL_SET_FLAG, LLIL_SET_FLAG_SSA pub struct SetFlag; -impl<'func, A, M, F> Operation<'func, A, M, F, SetFlag> +impl<'func, M, F> Operation<'func, M, F, SetFlag> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn dest_flag(&self) -> A::Flag { + pub fn dest_flag(&self) -> CoreFlag { // TODO: Error handling? // TODO: Test this. self.function @@ -312,7 +253,7 @@ where .unwrap() } - pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -320,9 +261,8 @@ where } } -impl Debug for Operation<'_, A, M, F, SetFlag> +impl Debug for Operation<'_, M, F, SetFlag> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -338,9 +278,8 @@ where // LLIL_LOAD, LLIL_LOAD_SSA pub struct Load; -impl<'func, A, M, F> Operation<'func, A, M, F, Load> +impl<'func, M, F> Operation<'func, M, F, Load> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -348,7 +287,7 @@ where self.op.size } - pub fn source_mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -356,9 +295,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Load> +impl Debug for Operation<'_, M, F, Load> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -374,9 +312,8 @@ where // LLIL_STORE, LLIL_STORE_SSA pub struct Store; -impl<'func, A, M, F> Operation<'func, A, M, F, Store> +impl<'func, M, F> Operation<'func, M, F, Store> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -384,14 +321,14 @@ where self.op.size } - pub fn dest_mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn dest_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -399,9 +336,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Store> +impl Debug for Operation<'_, M, F, Store> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -415,12 +351,11 @@ where } } -// LLIL_REG, LLIL_REG_SSA, LLIL_REG_SSA_PARTIAL +// LLIL_REG, LLIL_REG_SSLLIL_REG_SSA_PARTIAL pub struct Reg; -impl Operation<'_, A, M, F, Reg> +impl Operation<'_, M, F, Reg> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -428,31 +363,14 @@ where self.op.size } - pub fn source_reg(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn source_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } } -impl Debug for Operation<'_, A, M, F, Reg> +impl Debug for Operation<'_, M, F, Reg> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -468,9 +386,8 @@ where // LLIL_REG_SPLIT, LLIL_REG_SPLIT_SSA pub struct RegSplit; -impl Operation<'_, A, M, F, RegSplit> +impl Operation<'_, M, F, RegSplit> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -478,52 +395,19 @@ where self.op.size } - pub fn low_reg(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[0] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn low_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } - pub fn high_reg(&self) -> LowLevelILRegister { - let raw_id = self.op.operands[1] as u32; - - if raw_id >= 0x8000_0000 { - LowLevelILRegister::Temp(raw_id & 0x7fff_ffff) - } else { - self.function - .arch() - .register_from_id(RegisterId(raw_id)) - .map(LowLevelILRegister::ArchReg) - .unwrap_or_else(|| { - log::error!( - "got garbage register from LLIL_REG @ 0x{:x}", - self.op.address - ); - - LowLevelILRegister::Temp(0) - }) - } + pub fn high_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[1] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") } } -impl Debug for Operation<'_, A, M, F, RegSplit> +impl Debug for Operation<'_, M, F, RegSplit> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -540,9 +424,8 @@ where // LLIL_REG_STACK_PUSH pub struct RegStackPush; -impl<'func, A, M, F> Operation<'func, A, M, F, RegStackPush> +impl<'func, M, F> Operation<'func, M, F, RegStackPush> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -550,7 +433,7 @@ where self.op.size } - pub fn dest_reg_stack(&self) -> A::RegisterStack { + pub fn dest_reg_stack(&self) -> CoreRegisterStack { let raw_id = self.op.operands[0] as u32; self.function .arch() @@ -558,7 +441,7 @@ where .expect("Bad register stack ID") } - pub fn source_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -566,9 +449,8 @@ where } } -impl Debug for Operation<'_, A, M, F, RegStackPush> +impl Debug for Operation<'_, M, F, RegStackPush> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -585,9 +467,8 @@ where // LLIL_REG_STACK_POP pub struct RegStackPop; -impl Operation<'_, A, M, F, RegStackPop> +impl Operation<'_, M, F, RegStackPop> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -595,7 +476,7 @@ where self.op.size } - pub fn source_reg_stack(&self) -> A::RegisterStack { + pub fn source_reg_stack(&self) -> CoreRegisterStack { let raw_id = self.op.operands[0] as u32; self.function .arch() @@ -604,9 +485,8 @@ where } } -impl Debug for Operation<'_, A, M, F, RegStackPop> +impl Debug for Operation<'_, M, F, RegStackPop> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -622,9 +502,8 @@ where // LLIL_FLAG, LLIL_FLAG_SSA pub struct Flag; -impl Debug for Operation<'_, A, M, F, Flag> +impl Debug for Operation<'_, M, F, Flag> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -636,9 +515,8 @@ where // LLIL_FLAG_BIT, LLIL_FLAG_BIT_SSA pub struct FlagBit; -impl Debug for Operation<'_, A, M, F, FlagBit> +impl Debug for Operation<'_, M, F, FlagBit> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -650,13 +528,12 @@ where // LLIL_JUMP pub struct Jump; -impl<'func, A, M, F> Operation<'func, A, M, F, Jump> +impl<'func, M, F> Operation<'func, M, F, Jump> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -664,9 +541,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Jump> +impl Debug for Operation<'_, M, F, Jump> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -680,20 +556,18 @@ where // LLIL_JUMP_TO pub struct JumpTo; -struct TargetListIter<'func, A, M, F> +struct TargetListIter<'func, M, F> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - function: &'func LowLevelILFunction, + function: &'func LowLevelILFunction, cursor: BNLowLevelILInstruction, cursor_operand: usize, } -impl TargetListIter<'_, A, M, F> +impl TargetListIter<'_, M, F> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -710,13 +584,12 @@ where } } -impl<'func, A, M, F> Operation<'func, A, M, F, JumpTo> +impl<'func, M, F> Operation<'func, M, F, JumpTo> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -744,9 +617,8 @@ where } } -impl Debug for Operation<'_, A, M, F, JumpTo> +impl Debug for Operation<'_, M, F, JumpTo> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -761,13 +633,12 @@ where // LLIL_CALL, LLIL_CALL_SSA pub struct Call; -impl<'func, A, M, F> Operation<'func, A, M, F, Call> +impl<'func, M, F> Operation<'func, M, F, Call> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -785,9 +656,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Call> +impl Debug for Operation<'_, M, F, Call> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -802,13 +672,12 @@ where // LLIL_RET pub struct Ret; -impl<'func, A, M, F> Operation<'func, A, M, F, Ret> +impl<'func, M, F> Operation<'func, M, F, Ret> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn target(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -816,9 +685,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Ret> +impl Debug for Operation<'_, M, F, Ret> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -832,27 +700,26 @@ where // LLIL_IF pub struct If; -impl<'func, A, M, F> Operation<'func, A, M, F, If> +impl<'func, M, F> Operation<'func, M, F, If> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn condition(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn condition(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn true_target(&self) -> LowLevelILInstruction<'func, A, M, F> { + pub fn true_target(&self) -> LowLevelILInstruction<'func, M, F> { LowLevelILInstruction::new( self.function, LowLevelInstructionIndex(self.op.operands[1] as usize), ) } - pub fn false_target(&self) -> LowLevelILInstruction<'func, A, M, F> { + pub fn false_target(&self) -> LowLevelILInstruction<'func, M, F> { LowLevelILInstruction::new( self.function, LowLevelInstructionIndex(self.op.operands[2] as usize), @@ -860,9 +727,8 @@ where } } -impl Debug for Operation<'_, A, M, F, If> +impl Debug for Operation<'_, M, F, If> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -878,13 +744,12 @@ where // LLIL_GOTO pub struct Goto; -impl<'func, A, M, F> Operation<'func, A, M, F, Goto> +impl<'func, M, F> Operation<'func, M, F, Goto> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { - pub fn target(&self) -> LowLevelILInstruction<'func, A, M, F> { + pub fn target(&self) -> LowLevelILInstruction<'func, M, F> { LowLevelILInstruction::new( self.function, LowLevelInstructionIndex(self.op.operands[0] as usize), @@ -892,9 +757,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Goto> +impl Debug for Operation<'_, M, F, Goto> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -909,9 +773,8 @@ where // Valid only in Lifted IL pub struct FlagCond; -impl Debug for Operation<'_, A, M, F, FlagCond> +impl Debug for Operation<'_, M, F, FlagCond> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -924,12 +787,11 @@ where // Valid only in Lifted IL pub struct FlagGroup; -impl Operation<'_, A, M, NonSSA, FlagGroup> +impl Operation<'_, M, NonSSA, FlagGroup> where - A: Architecture, M: FunctionMutability, { - pub fn flag_group(&self) -> A::FlagGroup { + pub fn flag_group(&self) -> CoreFlagGroup { let id = self.op.operands[0] as u32; self.function .arch() @@ -938,9 +800,8 @@ where } } -impl Debug for Operation<'_, A, M, NonSSA, FlagGroup> +impl Debug for Operation<'_, M, NonSSA, FlagGroup> where - A: Architecture, M: FunctionMutability, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -950,9 +811,8 @@ where } } -impl Debug for Operation<'_, A, M, SSA, FlagGroup> +impl Debug for Operation<'_, M, SSA, FlagGroup> where - A: Architecture, M: FunctionMutability, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -963,9 +823,8 @@ where // LLIL_TRAP pub struct Trap; -impl Operation<'_, A, M, F, Trap> +impl Operation<'_, M, F, Trap> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -974,9 +833,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Trap> +impl Debug for Operation<'_, M, F, Trap> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -990,9 +848,8 @@ where // LLIL_REG_PHI pub struct RegPhi; -impl Debug for Operation<'_, A, M, F, RegPhi> +impl Debug for Operation<'_, M, F, RegPhi> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1004,9 +861,8 @@ where // LLIL_FLAG_PHI pub struct FlagPhi; -impl Debug for Operation<'_, A, M, F, FlagPhi> +impl Debug for Operation<'_, M, F, FlagPhi> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1018,9 +874,8 @@ where // LLIL_MEM_PHI pub struct MemPhi; -impl Debug for Operation<'_, A, M, F, MemPhi> +impl Debug for Operation<'_, M, F, MemPhi> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1032,9 +887,8 @@ where // LLIL_CONST, LLIL_CONST_PTR pub struct Const; -impl Operation<'_, A, M, F, Const> +impl Operation<'_, M, F, Const> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1073,9 +927,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Const> +impl Debug for Operation<'_, M, F, Const> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1090,9 +943,8 @@ where // LLIL_EXTERN_PTR pub struct Extern; -impl Operation<'_, A, M, F, Extern> +impl Operation<'_, M, F, Extern> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1131,9 +983,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Extern> +impl Debug for Operation<'_, M, F, Extern> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1152,9 +1003,8 @@ where // LLIL_MODS pub struct BinaryOp; -impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOp> +impl<'func, M, F> Operation<'func, M, F, BinaryOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1162,14 +1012,14 @@ where self.op.size } - pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -1177,9 +1027,8 @@ where } } -impl Debug for Operation<'_, A, M, F, BinaryOp> +impl Debug for Operation<'_, M, F, BinaryOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1195,9 +1044,8 @@ where // LLIL_ADC, LLIL_SBB, LLIL_RLC, LLIL_RRC pub struct BinaryOpCarry; -impl<'func, A, M, F> Operation<'func, A, M, F, BinaryOpCarry> +impl<'func, M, F> Operation<'func, M, F, BinaryOpCarry> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1205,21 +1053,21 @@ where self.op.size } - pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), ) } - pub fn carry(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn carry(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[2] as usize), @@ -1227,9 +1075,8 @@ where } } -impl Debug for Operation<'_, A, M, F, BinaryOpCarry> +impl Debug for Operation<'_, M, F, BinaryOpCarry> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1246,9 +1093,8 @@ where // LLIL_DIVS_DP, LLIL_DIVU_DP, LLIL_MODU_DP, LLIL_MODS_DP pub struct DoublePrecDivOp; -impl<'func, A, M, F> Operation<'func, A, M, F, DoublePrecDivOp> +impl<'func, M, F> Operation<'func, M, F, DoublePrecDivOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1256,14 +1102,14 @@ where self.op.size } - pub fn high(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn high(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn low(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn low(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -1271,7 +1117,7 @@ where } // TODO: I don't think this actually exists? - pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[2] as usize), @@ -1279,9 +1125,8 @@ where } } -impl Debug for Operation<'_, A, M, F, DoublePrecDivOp> +impl Debug for Operation<'_, M, F, DoublePrecDivOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1300,9 +1145,8 @@ where // LLIL_ZX, LLIL_LOW_PART, LLIL_BOOL_TO_INT, LLIL_UNIMPL_MEM pub struct UnaryOp; -impl<'func, A, M, F> Operation<'func, A, M, F, UnaryOp> +impl<'func, M, F> Operation<'func, M, F, UnaryOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1310,7 +1154,7 @@ where self.op.size } - pub fn operand(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn operand(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -1318,9 +1162,8 @@ where } } -impl Debug for Operation<'_, A, M, F, UnaryOp> +impl Debug for Operation<'_, M, F, UnaryOp> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1335,9 +1178,8 @@ where // LLIL_CMP_X pub struct Condition; -impl<'func, A, M, F> Operation<'func, A, M, F, Condition> +impl<'func, M, F> Operation<'func, M, F, Condition> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1345,14 +1187,14 @@ where self.op.size } - pub fn left(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn left(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), ) } - pub fn right(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn right(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[1] as usize), @@ -1360,9 +1202,8 @@ where } } -impl Debug for Operation<'_, A, M, F, Condition> +impl Debug for Operation<'_, M, F, Condition> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1378,9 +1219,8 @@ where // LLIL_UNIMPL_MEM pub struct UnimplMem; -impl<'func, A, M, F> Operation<'func, A, M, F, UnimplMem> +impl<'func, M, F> Operation<'func, M, F, UnimplMem> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { @@ -1388,7 +1228,7 @@ where self.op.size } - pub fn mem_expr(&self) -> LowLevelILExpression<'func, A, M, F, ValueExpr> { + pub fn mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -1396,9 +1236,8 @@ where } } -impl Debug for Operation<'_, A, M, F, UnimplMem> +impl Debug for Operation<'_, M, F, UnimplMem> where - A: Architecture, M: FunctionMutability, F: FunctionForm, { diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index 8fa9a86b08..f10115c8b5 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -83,7 +83,7 @@ impl From for usize { } // TODO: How to handle related relocation linked lists? -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct RelocationInfo { pub type_: RelocationType, pub pc_relative: bool, @@ -265,7 +265,7 @@ pub trait RelocationHandler: 'static + Sized + AsRef { _data: &[u8], _addr: u64, // TODO: Are we sure this is not a liftedilfunction? - _il: &RegularLowLevelILFunction, + _il: &RegularLowLevelILFunction, _reloc: &Relocation, ) -> RelocationOperand { RelocationOperand::AutocoerceExternPtr @@ -363,7 +363,7 @@ impl RelocationHandler for CoreRelocationHandler { &self, data: &[u8], addr: u64, - il: &RegularLowLevelILFunction, + il: &RegularLowLevelILFunction, reloc: &Relocation, ) -> RelocationOperand { unsafe { @@ -496,7 +496,7 @@ where return RelocationOperand::Invalid.into(); } let arch = unsafe { CoreArchitecture::from_raw(arch) }; - let il = unsafe { RegularLowLevelILFunction::from_raw(arch, il) }; + let il = unsafe { RegularLowLevelILFunction::from_raw_with_arch(il, Some(arch)) }; custom_handler .get_operand_for_external_relocation(data, addr, &il, &reloc) diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index b9c67a5df9..ca42ff686f 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -1,8 +1,5 @@ use binaryninjacore_sys::*; -use std::ffi::{c_char, c_void}; -use std::ptr::NonNull; -use crate::architecture::CoreArchitecture; use crate::basic_block::BasicBlock; use crate::binary_view::BinaryView; use crate::flowgraph::FlowGraph; @@ -13,6 +10,8 @@ use crate::low_level_il::MutableLiftedILFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnStrCompatible, BnString}; +use std::ffi::{c_char, c_void}; +use std::ptr::NonNull; #[repr(transparent)] /// The AnalysisContext struct is used to represent the current state of @@ -47,21 +46,17 @@ impl AnalysisContext { } /// [`LowLevelILFunction`] used to represent Low Level IL - pub unsafe fn lifted_il_function( - &self, - ) -> Option>> { + pub unsafe fn lifted_il_function(&self) -> Option> { let func = self.function(); let result = unsafe { BNGetFunctionLiftedIL(func.handle) }; - let arch = self.function().arch(); unsafe { Some(LowLevelILFunction::ref_from_raw( - arch, NonNull::new(result)?.as_ptr(), )) } } - pub fn set_lifted_il_function(&self, value: &MutableLiftedILFunction) { + pub fn set_lifted_il_function(&self, value: &MutableLiftedILFunction) { unsafe { BNSetLiftedILFunction(self.handle.as_ptr(), value.handle) } } @@ -70,12 +65,10 @@ impl AnalysisContext { /// [`LowLevelILFunction`] used to represent Low Level IL pub unsafe fn llil_function( &self, - ) -> Option>>> { + ) -> Option>>> { let result = unsafe { BNAnalysisContextGetLowLevelILFunction(self.handle.as_ptr()) }; - let arch = self.function().arch(); unsafe { Some(LowLevelILFunction::ref_from_raw( - arch, NonNull::new(result)?.as_ptr(), )) } @@ -85,7 +78,7 @@ impl AnalysisContext { // TODO: At some point we need to take the lifting code and make it available to regular IL. pub fn set_llil_function( &self, - value: &LowLevelILFunction>, + value: &LowLevelILFunction>, ) { unsafe { BNSetLowLevelILFunction(self.handle.as_ptr(), value.handle) } } diff --git a/rust/tests/low_level_il.rs b/rust/tests/low_level_il.rs index b9d7d203a5..88d915dc48 100644 --- a/rust/tests/low_level_il.rs +++ b/rust/tests/low_level_il.rs @@ -7,7 +7,7 @@ use binaryninja::low_level_il::expression::{ use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstructionKind, LowLevelInstructionIndex, }; -use binaryninja::low_level_il::{LowLevelILRegister, VisitorAction}; +use binaryninja::low_level_il::{LowLevelILRegisterKind, VisitorAction}; use std::path::PathBuf; #[test] @@ -34,7 +34,7 @@ fn test_llil_info() { LowLevelILInstructionKind::SetReg(op) => { assert_eq!(op.size(), 4); match op.dest_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "edi"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "edi"), _ => panic!("Expected Register::ArchReg"), } assert_eq!(op.source_expr().index, LowLevelExpressionIndex(0)); @@ -55,7 +55,7 @@ fn test_llil_info() { LowLevelILExpressionKind::Reg(op) => { assert_eq!(op.size(), 4); match op.source_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "ebp"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "ebp"), _ => panic!("Expected Register::ArchReg"), } } @@ -73,7 +73,7 @@ fn test_llil_info() { LowLevelILInstructionKind::SetReg(op) => { assert_eq!(op.size(), 4); match op.dest_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "ebp"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "ebp"), _ => panic!("Expected Register::ArchReg"), } assert_eq!(op.source_expr().index, LowLevelExpressionIndex(4)); @@ -89,7 +89,7 @@ fn test_llil_info() { LowLevelILInstructionKind::SetReg(op) => { assert_eq!(op.size(), 4); match op.dest_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "eax"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "eax"), _ => panic!("Expected Register::ArchReg"), } assert_eq!(op.source_expr().index, LowLevelExpressionIndex(9)); @@ -128,7 +128,7 @@ fn test_llil_info() { LowLevelILInstructionKind::SetReg(op) => { assert_eq!(op.size(), 4); match op.dest_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "esp"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "esp"), _ => panic!("Expected Register::ArchReg"), } assert_eq!(op.source_expr().index, LowLevelExpressionIndex(17)); @@ -144,7 +144,7 @@ fn test_llil_info() { LowLevelILInstructionKind::SetReg(op) => { assert_eq!(op.size(), 4); match op.dest_reg() { - LowLevelILRegister::ArchReg(reg) => assert_eq!(reg.name(), "ebp"), + LowLevelILRegisterKind::Arch(reg) => assert_eq!(reg.name(), "ebp"), _ => panic!("Expected Register::ArchReg"), } assert_eq!(op.source_expr().index, LowLevelExpressionIndex(19)); From 8193f13fe7019e052c06f75ad571b6aa01480899 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 3 May 2025 23:15:17 -0400 Subject: [PATCH 03/54] [Rust] Return `String` instead of `BnString` for cases where lossy conversion can be tolerated Still need to go and audit all usage, but realistically the most important places to give the user control are with symbols, where the data can come from non utf8 sources This is still incomplete, I just looked for usage of -> BnString so any other variant was omitted. --- plugins/dwarf/dwarf_export/src/lib.rs | 7 ++-- plugins/dwarf/shared/src/lib.rs | 2 +- plugins/warp/src/bin/sigem.rs | 2 +- plugins/warp/src/cache.rs | 2 +- plugins/warp/src/matcher.rs | 2 +- plugins/warp/src/plugin/create.rs | 2 +- rust/src/architecture.rs | 4 +- rust/src/background_task.rs | 4 +- rust/src/base_detection.rs | 4 +- rust/src/binary_view.rs | 21 ++++++---- rust/src/binary_view/memory_map.rs | 4 +- rust/src/calling_convention.rs | 4 +- rust/src/collaboration/changeset.rs | 4 +- rust/src/collaboration/file.rs | 56 ++++++++++++------------- rust/src/collaboration/folder.rs | 16 +++---- rust/src/collaboration/group.rs | 8 ++-- rust/src/collaboration/merge.rs | 8 ++-- rust/src/collaboration/permission.rs | 8 ++-- rust/src/collaboration/project.rs | 20 ++++----- rust/src/collaboration/remote.rs | 16 +++---- rust/src/collaboration/snapshot.rs | 36 ++++++++-------- rust/src/collaboration/sync.rs | 9 ++-- rust/src/collaboration/undo.rs | 4 +- rust/src/collaboration/user.rs | 20 ++++----- rust/src/component.rs | 29 +++---------- rust/src/custom_binary_view.rs | 15 +++---- rust/src/data_buffer.rs | 8 ++-- rust/src/database/snapshot.rs | 4 +- rust/src/database/undo.rs | 8 ++-- rust/src/debuginfo.rs | 4 +- rust/src/demangle.rs | 4 +- rust/src/disassembly.rs | 4 +- rust/src/download_provider.rs | 8 ++-- rust/src/enterprise.rs | 28 ++++++------- rust/src/external_library.rs | 4 +- rust/src/file_metadata.rs | 12 +++--- rust/src/function.rs | 44 +++++++------------- rust/src/headless.rs | 2 +- rust/src/high_level_il/operation.rs | 6 +-- rust/src/interaction.rs | 12 +++--- rust/src/lib.rs | 20 ++++----- rust/src/logger.rs | 6 +-- rust/src/platform.rs | 6 +-- rust/src/project.rs | 16 +++---- rust/src/project/file.rs | 16 +++---- rust/src/project/folder.rs | 12 +++--- rust/src/repository.rs | 12 +++--- rust/src/repository/plugin.rs | 60 +++++++++++++-------------- rust/src/secrets_provider.rs | 8 ++-- rust/src/section.rs | 16 +++---- rust/src/settings.rs | 20 ++++----- rust/src/string.rs | 60 ++++++++++++++++----------- rust/src/tags.rs | 20 ++++----- rust/src/type_archive.rs | 8 ++-- rust/src/type_container.rs | 8 ++-- rust/src/type_parser.rs | 4 +- rust/src/type_printer.rs | 4 +- rust/src/types.rs | 6 +-- rust/src/update.rs | 4 +- rust/src/websocket/provider.rs | 4 +- rust/src/workflow.rs | 14 +++---- 61 files changed, 381 insertions(+), 398 deletions(-) diff --git a/plugins/dwarf/dwarf_export/src/lib.rs b/plugins/dwarf/dwarf_export/src/lib.rs index bc159825f8..d1754d2950 100644 --- a/plugins/dwarf/dwarf_export/src/lib.rs +++ b/plugins/dwarf/dwarf_export/src/lib.rs @@ -18,7 +18,6 @@ use binaryninja::{ interaction, interaction::{FormResponses, FormResponses::Index}, rc::Ref, - string::BnString, symbol::SymbolType, types::{MemberAccess, StructureType, Type, TypeClass}, }; @@ -422,7 +421,7 @@ fn export_functions( // Set subprogram DIE attributes dwarf.unit.get_mut(function_die_uid).set( gimli::DW_AT_name, - AttributeValue::String(function.symbol().short_name().as_bytes().to_vec()), + AttributeValue::String(function.symbol().short_name().to_bytes().to_vec()), ); // TODO : (DW_AT_main_subprogram VS DW_TAG_entry_point) @@ -557,7 +556,7 @@ fn export_data_vars( if let Some(symbol) = data_var_sym { dwarf.unit.get_mut(var_die_uid).set( gimli::DW_AT_name, - AttributeValue::String(symbol.full_name().as_bytes().to_vec()), + AttributeValue::String(symbol.full_name().to_bytes().to_vec()), ); if symbol.external() { @@ -756,7 +755,7 @@ fn export_dwarf(bv: &BinaryView) { let arch_name = if let Some(arch) = bv.default_arch() { arch.name() } else { - BnString::new("Unknown") + String::from("Unknown") }; let responses = present_form(arch_name.as_str()); diff --git a/plugins/dwarf/shared/src/lib.rs b/plugins/dwarf/shared/src/lib.rs index b12aeab1c8..c4ed7937e0 100644 --- a/plugins/dwarf/shared/src/lib.rs +++ b/plugins/dwarf/shared/src/lib.rs @@ -106,7 +106,7 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>( if let Some(symbol) = view .symbols() .iter() - .find(|symbol| symbol.full_name().as_str() == "__elf_section_headers") + .find(|symbol| symbol.full_name().to_string_lossy() == "__elf_section_headers") { if let Some(data_var) = view .data_variables() diff --git a/plugins/warp/src/bin/sigem.rs b/plugins/warp/src/bin/sigem.rs index a455f1e8e0..a50b4ae2f3 100644 --- a/plugins/warp/src/bin/sigem.rs +++ b/plugins/warp/src/bin/sigem.rs @@ -131,7 +131,7 @@ fn main() { fn data_from_view(view: &BinaryView) -> Data { let mut data = Data::default(); let is_function_named = |f: &BNGuard| { - !f.symbol().short_name().as_str().contains("sub_") || f.has_user_annotations() + !f.symbol().short_name().to_string_lossy().contains("sub_") || f.has_user_annotations() }; data.functions = view diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index 7219b54712..8c82c68747 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -439,7 +439,7 @@ pub struct TypeRefID(u64); impl From<&BNNamedTypeReference> for TypeRefID { fn from(value: &BNNamedTypeReference) -> Self { let mut hasher = DefaultHasher::new(); - hasher.write(value.id().as_bytes()); + hasher.write(value.id().to_bytes()); Self(hasher.finish()) } } diff --git a/plugins/warp/src/matcher.rs b/plugins/warp/src/matcher.rs index 81458f8da9..6352cd7ae8 100644 --- a/plugins/warp/src/matcher.rs +++ b/plugins/warp/src/matcher.rs @@ -506,7 +506,7 @@ pub struct PlatformID(u64); impl From<&Platform> for PlatformID { fn from(value: &Platform) -> Self { let mut hasher = DefaultHasher::new(); - hasher.write(value.name().to_bytes()); + hasher.write(value.name().as_bytes()); Self(hasher.finish()) } } diff --git a/plugins/warp/src/plugin/create.rs b/plugins/warp/src/plugin/create.rs index 4beba1952a..e84e42ad3e 100644 --- a/plugins/warp/src/plugin/create.rs +++ b/plugins/warp/src/plugin/create.rs @@ -18,7 +18,7 @@ pub struct CreateSignatureFile; impl Command for CreateSignatureFile { fn action(&self, view: &BinaryView) { let is_function_named = |f: &Guard| { - !f.symbol().short_name().as_str().contains("sub_") || f.has_user_annotations() + !f.symbol().short_name().to_string_lossy().contains("sub_") || f.has_user_annotations() }; let mut signature_dir = user_signature_dir(); if let Some(default_plat) = view.default_platform() { diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index c0fe138ed3..d2e5e0fc21 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1412,8 +1412,8 @@ impl CoreArchitecture { } } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetArchitectureName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetArchitectureName(self.handle)) } } } diff --git a/rust/src/background_task.rs b/rust/src/background_task.rs index c818d5b950..5d30f27d1d 100644 --- a/rust/src/background_task.rs +++ b/rust/src/background_task.rs @@ -71,8 +71,8 @@ impl BackgroundTask { unsafe { BNFinishBackgroundTask(self.handle) } } - pub fn progress_text(&self) -> BnString { - unsafe { BnString::from_raw(BNGetBackgroundTaskProgressText(self.handle)) } + pub fn progress_text(&self) -> String { + unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) } } pub fn set_progress_text(&self, text: S) { diff --git a/rust/src/base_detection.rs b/rust/src/base_detection.rs index 1fd45ef633..c74f3f3a82 100644 --- a/rust/src/base_detection.rs +++ b/rust/src/base_detection.rs @@ -174,9 +174,9 @@ impl BaseAddressDetectionSettings { let arch_name = value .arch .map(|a| a.name().as_ptr()) - .unwrap_or(BASE_ADDRESS_AUTO_DETECTION_ARCH.as_ptr() as *const c_char); + .unwrap_or(BASE_ADDRESS_AUTO_DETECTION_ARCH.as_ptr() as *const u8); BNBaseAddressDetectionSettings { - Architecture: arch_name, + Architecture: arch_name as *const c_char, Analysis: value.analysis.as_raw().as_ptr(), MinStrlen: value.min_string_len, Alignment: value.alignment.get(), diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index db4c92d749..d8f35caf73 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -27,7 +27,7 @@ use crate::architecture::{Architecture, CoreArchitecture}; use crate::base_detection::BaseAddressDetection; use crate::basic_block::BasicBlock; use crate::binary_view::memory_map::MemoryMap; -use crate::component::{Component, IntoComponentGuid}; +use crate::component::Component; use crate::confidence::Conf; use crate::data_buffer::DataBuffer; use crate::debuginfo::DebugInfo; @@ -187,9 +187,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_name(&self) -> BnString { + fn type_name(&self) -> String { let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) }; - unsafe { BnString::from_raw(ptr) } + unsafe { BnString::into_string(ptr) } } fn parent_view(&self) -> Option> { @@ -204,9 +204,9 @@ pub trait BinaryViewExt: BinaryViewBase { self.file().view_of_type("Raw") } - fn view_type(&self) -> BnString { + fn view_type(&self) -> String { let ptr: *mut c_char = unsafe { BNGetViewType(self.as_ref().handle) }; - unsafe { BnString::from_raw(ptr) } + unsafe { BnString::into_string(ptr) } } /// Reads up to `len` bytes from address `offset` @@ -1493,9 +1493,14 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) } } - fn remove_component_by_guid(&self, guid: P) -> bool { - let path = guid.component_guid(); - unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } + fn remove_component_by_guid(&self, guid: P) -> bool { + let path = guid.into_bytes_with_nul(); + unsafe { + BNRemoveComponentByGuid( + self.as_ref().handle, + path.as_ref().as_ptr() as *const c_char, + ) + } } fn data_variable_parent_components(&self, data_variable: &DataVariable) -> Array { diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index 3e248c545b..182cb16a13 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -108,10 +108,10 @@ impl MemoryMap { } } - pub fn active_memory_region_at(&self, addr: u64) -> BnString { + pub fn active_memory_region_at(&self, addr: u64) -> String { unsafe { let name_raw = BNGetActiveMemoryRegionAt(self.view.handle, addr); - BnString::from_raw(name_raw) + BnString::into_string(name_raw) } } diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs index 2fb282e0ff..6f2e9a1c35 100644 --- a/rust/src/calling_convention.rs +++ b/rust/src/calling_convention.rs @@ -455,8 +455,8 @@ impl CoreCallingConvention { }) } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetCallingConventionName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetCallingConventionName(self.handle)) } } pub fn variables_for_parameters( diff --git a/rust/src/collaboration/changeset.rs b/rust/src/collaboration/changeset.rs index 9d7cdb7c3b..fd862df667 100644 --- a/rust/src/collaboration/changeset.rs +++ b/rust/src/collaboration/changeset.rs @@ -59,10 +59,10 @@ impl Changeset { } /// Changeset name - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNCollaborationChangesetGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the name of the changeset, e.g. in a name changeset function. diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index 2651d3c773..678c0c15b7 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -106,30 +106,30 @@ impl RemoteFile { } /// Web API endpoint URL - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let result = unsafe { BNRemoteFileGetUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Chat log API endpoint URL - pub fn chat_log_url(&self) -> BnString { + pub fn chat_log_url(&self) -> String { let result = unsafe { BNRemoteFileGetChatLogUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } - pub fn user_positions_url(&self) -> BnString { + pub fn user_positions_url(&self) -> String { let result = unsafe { BNRemoteFileGetUserPositionsUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Unique ID - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let result = unsafe { BNRemoteFileGetId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// All files share the same properties, but files with different types may make different @@ -144,10 +144,10 @@ impl RemoteFile { crate::ffi::time_from_bn(result.try_into().unwrap()) } - pub fn created_by(&self) -> BnString { + pub fn created_by(&self) -> String { let result = unsafe { BNRemoteFileGetCreatedBy(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Last modified of the file @@ -163,30 +163,30 @@ impl RemoteFile { } /// Username of user who pushed the last snapshot in the file - pub fn last_snapshot_by(&self) -> BnString { + pub fn last_snapshot_by(&self) -> String { let result = unsafe { BNRemoteFileGetLastSnapshotBy(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } - pub fn last_snapshot_name(&self) -> BnString { + pub fn last_snapshot_name(&self) -> String { let result = unsafe { BNRemoteFileGetLastSnapshotName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Hash of file contents (no algorithm guaranteed) - pub fn hash(&self) -> BnString { + pub fn hash(&self) -> String { let result = unsafe { BNRemoteFileGetHash(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Displayed name of file - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNRemoteFileGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the description of the file. You will need to push the file to update the remote version. @@ -202,10 +202,10 @@ impl RemoteFile { } /// Desciprtion of the file - pub fn description(&self) -> BnString { + pub fn description(&self) -> String { let result = unsafe { BNRemoteFileGetDescription(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the description of the file. You will need to push the file to update the remote version. @@ -220,10 +220,10 @@ impl RemoteFile { success.then_some(()).ok_or(()) } - pub fn metadata(&self) -> BnString { + pub fn metadata(&self) -> String { let result = unsafe { BNRemoteFileGetMetadata(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Size of raw content of file, in bytes @@ -234,10 +234,10 @@ impl RemoteFile { /// Get the default filepath for a remote File. This is based off the Setting for /// collaboration.directory, the file's id, the file's project's id, and the file's /// remote's id. - pub fn default_path(&self) -> BnString { + pub fn default_path(&self) -> String { let result = unsafe { BNCollaborationDefaultFilePath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// If the file has pulled the snapshots yet @@ -410,16 +410,16 @@ impl RemoteFile { // todo!() //} - pub fn request_user_positions(&self) -> BnString { + pub fn request_user_positions(&self) -> String { let result = unsafe { BNRemoteFileRequestUserPositions(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } - pub fn request_chat_log(&self) -> BnString { + pub fn request_chat_log(&self) -> String { let result = unsafe { BNRemoteFileRequestChatLog(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } // TODO: AsRef diff --git a/rust/src/collaboration/folder.rs b/rust/src/collaboration/folder.rs index 90a85f1cf6..eb4fd9f8ba 100644 --- a/rust/src/collaboration/folder.rs +++ b/rust/src/collaboration/folder.rs @@ -76,17 +76,17 @@ impl RemoteFolder { } /// Get web API endpoint URL. - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let result = unsafe { BNRemoteFolderGetUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Get unique ID. - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let result = unsafe { BNRemoteFolderGetId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Unique id of parent folder, if there is a parent. None, otherwise @@ -97,10 +97,10 @@ impl RemoteFolder { } /// Displayed name of folder - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNRemoteFolderGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the display name of the folder. You will need to push the folder to update the remote version. @@ -116,10 +116,10 @@ impl RemoteFolder { } /// Description of the folder - pub fn description(&self) -> BnString { + pub fn description(&self) -> String { let result = unsafe { BNRemoteFolderGetDescription(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the description of the folder. You will need to push the folder to update the remote version. diff --git a/rust/src/collaboration/group.rs b/rust/src/collaboration/group.rs index bad09d6cb7..9fb287a789 100644 --- a/rust/src/collaboration/group.rs +++ b/rust/src/collaboration/group.rs @@ -30,10 +30,10 @@ impl RemoteGroup { } /// Web api endpoint url - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let value = unsafe { BNCollaborationGroupGetUrl(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Unique id @@ -42,10 +42,10 @@ impl RemoteGroup { } /// Group name - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let value = unsafe { BNCollaborationGroupGetName(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Set group name diff --git a/rust/src/collaboration/merge.rs b/rust/src/collaboration/merge.rs index 2d28725c2b..68bfdc029e 100644 --- a/rust/src/collaboration/merge.rs +++ b/rust/src/collaboration/merge.rs @@ -108,18 +108,18 @@ impl MergeConflict { /// String representing the type name of the data, not the same as data_type. /// This is like "typeName" or "tag" depending on what object the conflict represents. - pub fn conflict_type(&self) -> BnString { + pub fn conflict_type(&self) -> String { let result = unsafe { BNAnalysisMergeConflictGetType(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Lookup key for the merge conflict, ideally a tree path that contains the name of the conflict /// and all the recursive children leading up to this conflict. - pub fn key(&self) -> BnString { + pub fn key(&self) -> String { let result = unsafe { BNAnalysisMergeConflictGetKey(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Call this when you've resolved the conflict to save the result diff --git a/rust/src/collaboration/permission.rs b/rust/src/collaboration/permission.rs index 99a7a4f28b..76b1eba3ca 100644 --- a/rust/src/collaboration/permission.rs +++ b/rust/src/collaboration/permission.rs @@ -37,17 +37,17 @@ impl Permission { } /// Web api endpoint url - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let value = unsafe { BNCollaborationPermissionGetUrl(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// unique id - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let value = unsafe { BNCollaborationPermissionGetId(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Level of permission diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index 1455f6c31c..b3c6513d86 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -103,17 +103,17 @@ impl RemoteProject { } /// Get the URL of the project - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let result = unsafe { BNRemoteProjectGetUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Get the unique ID of the project - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let result = unsafe { BNRemoteProjectGetId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Created date of the project @@ -129,10 +129,10 @@ impl RemoteProject { } /// Displayed name of file - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNRemoteProjectGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the description of the file. You will need to push the file to update the remote version. @@ -148,10 +148,10 @@ impl RemoteProject { } /// Desciprtion of the file - pub fn description(&self) -> BnString { + pub fn description(&self) -> String { let result = unsafe { BNRemoteProjectGetDescription(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Set the description of the file. You will need to push the file to update the remote version. @@ -879,9 +879,9 @@ impl RemoteProject { /// Get the default directory path for a remote Project. This is based off /// the Setting for collaboration.directory, the project's id, and the /// project's remote's id. - pub fn default_project_path(&self) -> BnString { + pub fn default_project_path(&self) -> String { let result = unsafe { BNCollaborationDefaultProjectPath(self.handle.as_ptr()) }; - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Upload a file, with database, to the remote under the given project diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index c12504033b..98784ddbbd 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -65,17 +65,17 @@ impl Remote { } /// Gets the name of the remote. - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNRemoteGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Gets the address of the remote. - pub fn address(&self) -> BnString { + pub fn address(&self) -> String { let result = unsafe { BNRemoteGetAddress(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Checks if the remote is connected. @@ -84,17 +84,17 @@ impl Remote { } /// Gets the username used to connect to the remote. - pub fn username(&self) -> BnString { + pub fn username(&self) -> String { let result = unsafe { BNRemoteGetUsername(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Gets the token used to connect to the remote. - pub fn token(&self) -> BnString { + pub fn token(&self) -> String { let result = unsafe { BNRemoteGetToken(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Gets the server version. If metadata has not been pulled, it will be pulled upon calling this. diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index 9f8f36934b..935b1c2fe2 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -54,52 +54,52 @@ impl RemoteSnapshot { } /// Web api endpoint url - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetUrl(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Unique id - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetId(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Name of snapshot - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetName(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Get the title of a snapshot: the first line of its name - pub fn title(&self) -> BnString { + pub fn title(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetTitle(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Get the description of a snapshot: the lines of its name after the first line - pub fn description(&self) -> BnString { + pub fn description(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetDescription(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Get the user id of the author of a snapshot - pub fn author(&self) -> BnString { + pub fn author(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetAuthor(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Get the username of the author of a snapshot, if possible (vs author which is user id) - pub fn author_username(&self) -> BnString { + pub fn author_username(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetAuthorUsername(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Created date of Snapshot @@ -116,18 +116,18 @@ impl RemoteSnapshot { /// Hash of snapshot data (analysis and markup, etc) /// No specific hash algorithm is guaranteed - pub fn hash(&self) -> BnString { + pub fn hash(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetHash(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Hash of file contents in snapshot /// No specific hash algorithm is guaranteed - pub fn snapshot_file_hash(&self) -> BnString { + pub fn snapshot_file_hash(&self) -> String { let value = unsafe { BNCollaborationSnapshotGetSnapshotFileHash(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// If the snapshot has pulled undo entries yet diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index 1c11b8f060..6fc85d31c7 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -3,7 +3,6 @@ use super::{ }; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void}; -use std::mem::ManuallyDrop; use std::ptr::NonNull; use crate::binary_view::{BinaryView, BinaryViewExt}; @@ -12,7 +11,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::rc::Ref; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{raw_to_string, BnStrCompatible, BnString}; use crate::type_archive::{TypeArchive, TypeArchiveMergeConflict}; // TODO: PathBuf @@ -859,13 +858,11 @@ pub trait DatabaseConflictHandler: Sized { let keys = core::slice::from_raw_parts(keys, conflict_count); let conflicts = core::slice::from_raw_parts(conflicts, conflict_count); keys.iter().zip(conflicts.iter()).all(|(key, conflict)| { - // NOTE this is a reference, not owned, so ManuallyDrop is required, or just implement `ref_from_raw` - // TODO: Replace with raw_to_string - let key = ManuallyDrop::new(BnString::from_raw(*key as *mut _)); + let key = raw_to_string(*key).unwrap(); // TODO I guess dont drop here? let raw_ptr = NonNull::new(*conflict).unwrap(); let conflict = MergeConflict::from_raw(raw_ptr); - ctxt.handle_conflict(key.as_str(), &conflict) + ctxt.handle_conflict(&key, &conflict) }) } } diff --git a/rust/src/collaboration/undo.rs b/rust/src/collaboration/undo.rs index 9f1cc5f086..0dde860fde 100644 --- a/rust/src/collaboration/undo.rs +++ b/rust/src/collaboration/undo.rs @@ -57,10 +57,10 @@ impl RemoteUndoEntry { } /// Web api endpoint url - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let value = unsafe { BNCollaborationUndoEntryGetUrl(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Unique id diff --git a/rust/src/collaboration/user.rs b/rust/src/collaboration/user.rs index 0e3433d319..b08e9da408 100644 --- a/rust/src/collaboration/user.rs +++ b/rust/src/collaboration/user.rs @@ -28,24 +28,24 @@ impl RemoteUser { } /// Web api endpoint url - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let value = unsafe { BNCollaborationUserGetUrl(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Unique id - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let value = unsafe { BNCollaborationUserGetId(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// User's login username - pub fn username(&self) -> BnString { + pub fn username(&self) -> String { let value = unsafe { BNCollaborationUserGetUsername(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Set user's username. You will need to push the user to update the Remote @@ -65,10 +65,10 @@ impl RemoteUser { } /// User's email address - pub fn email(&self) -> BnString { + pub fn email(&self) -> String { let value = unsafe { BNCollaborationUserGetEmail(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// Set user's email. You will need to push the user to update the Remote @@ -88,10 +88,10 @@ impl RemoteUser { } /// String representing the last date the user logged in - pub fn last_login(&self) -> BnString { + pub fn last_login(&self) -> String { let value = unsafe { BNCollaborationUserGetLastLogin(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } /// If the user account is active and can log in diff --git a/rust/src/component.rs b/rust/src/component.rs index 497c1f5723..72441c528d 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -86,10 +86,10 @@ impl Component { Ref::new(Self { handle }) } - pub fn guid(&self) -> BnString { + pub fn guid(&self) -> String { let result = unsafe { BNComponentGetGuid(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Add function to this component. @@ -145,10 +145,10 @@ impl Component { } /// Original name of the component - pub fn display_name(&self) -> BnString { + pub fn display_name(&self) -> String { let result = unsafe { BNComponentGetDisplayName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Original name set for this component @@ -158,10 +158,10 @@ impl Component { /// remain what was originally set (e.g. "MyComponentName") /// If this component has a duplicate name and is moved to a component where none of its siblings share its name, /// .name will return the original "MyComponentName" - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNComponentGetOriginalName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } pub fn set_name(&self, name: S) { @@ -309,20 +309,3 @@ unsafe impl CoreArrayProviderInner for Component { Guard::new(Self::from_raw(raw_ptr), context) } } - -// TODO: Should we keep this? -pub trait IntoComponentGuid { - fn component_guid(self) -> BnString; -} - -impl IntoComponentGuid for &Component { - fn component_guid(self) -> BnString { - self.guid() - } -} - -impl IntoComponentGuid for S { - fn component_guid(self) -> BnString { - BnString::new(self) - } -} diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index a43bbd4b57..de841a2631 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -15,6 +15,7 @@ //! An interface for providing your own [BinaryView]s to Binary Ninja. use binaryninjacore_sys::*; +use std::ffi::c_char; pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; @@ -211,12 +212,12 @@ pub trait BinaryViewTypeBase: AsRef { } pub trait BinaryViewTypeExt: BinaryViewTypeBase { - fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetBinaryViewTypeName(self.as_ref().handle)) } + fn name(&self) -> String { + unsafe { BnString::into_string(BNGetBinaryViewTypeName(self.as_ref().handle)) } } - fn long_name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetBinaryViewTypeLongName(self.as_ref().handle)) } + fn long_name(&self) -> String { + unsafe { BnString::into_string(BNGetBinaryViewTypeLongName(self.as_ref().handle)) } } fn register_arch(&self, id: u32, endianness: Endianness, arch: &A) { @@ -502,7 +503,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { let view_name = view_type.name(); - if let Some(bv) = file.view_of_type(view_name.as_str()) { + if let Some(bv) = file.view_of_type(&view_name) { // while it seems to work most of the time, you can get really unlucky // if the a free of the existing view of the same type kicks off while // BNCreateBinaryViewOfType is still running. the freeObject callback @@ -514,7 +515,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { // going to try and stop this from happening in the first place. log::error!( "attempt to create duplicate view of type '{}' (existing: {:?})", - view_name.as_str(), + view_name, bv.handle ); @@ -879,7 +880,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { unsafe { let res = BNCreateCustomBinaryView( - view_name.as_ptr(), + view_name.as_ptr() as *const c_char, file.handle, parent.handle, &mut bn_obj, diff --git a/rust/src/data_buffer.rs b/rust/src/data_buffer.rs index 5b7d1ae61a..460bb94d8c 100644 --- a/rust/src/data_buffer.rs +++ b/rust/src/data_buffer.rs @@ -110,9 +110,9 @@ impl DataBuffer { } } - pub fn to_escaped_string(&self, null_terminates: bool, escape_printable: bool) -> BnString { + pub fn to_escaped_string(&self, null_terminates: bool, escape_printable: bool) -> String { unsafe { - BnString::from_raw(BNDataBufferToEscapedString( + BnString::into_string(BNDataBufferToEscapedString( self.0, null_terminates, escape_printable, @@ -124,8 +124,8 @@ impl DataBuffer { Self(unsafe { BNDecodeEscapedString(value.as_ptr()) }) } - pub fn to_base64(&self) -> BnString { - unsafe { BnString::from_raw(BNDataBufferToBase64(self.0)) } + pub fn to_base64(&self) -> String { + unsafe { BnString::into_string(BNDataBufferToBase64(self.0)) } } pub fn from_base64(value: &BnString) -> Self { diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs index 35b0dc46d8..3768138c11 100644 --- a/rust/src/database/snapshot.rs +++ b/rust/src/database/snapshot.rs @@ -45,8 +45,8 @@ impl Snapshot { } /// Get the displayed snapshot name - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetSnapshotName(self.handle.as_ptr())) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetSnapshotName(self.handle.as_ptr())) } } /// Set the displayed snapshot name diff --git a/rust/src/database/undo.rs b/rust/src/database/undo.rs index 727a777ba5..a2001b7218 100644 --- a/rust/src/database/undo.rs +++ b/rust/src/database/undo.rs @@ -26,10 +26,10 @@ impl UndoEntry { Ref::new(Self { handle }) } - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let result = unsafe { BNUndoEntryGetId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } pub fn actions(&self) -> Array { @@ -115,10 +115,10 @@ impl UndoAction { } /// Gets the [`UndoAction`] summary as text rather than [`InstructionTextToken`]'s. - pub fn summary_as_string(&self) -> BnString { + pub fn summary_as_string(&self) -> String { let result = unsafe { BNUndoActionGetSummaryText(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 1353f8b177..bafa9cc490 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -141,8 +141,8 @@ impl DebugInfoParser { } /// Returns the name of the current parser - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetDebugInfoParserName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetDebugInfoParserName(self.handle)) } } /// Returns whether this debug-info parser is valid for the provided binary view diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index e4d0be1d94..bfe65f9af3 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -232,8 +232,8 @@ impl Demangler { } } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetDemanglerName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) } } pub fn from_name(name: S) -> Option { diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 99a6b22efc..6125f62383 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -302,9 +302,7 @@ impl InstructionTextToken { } pub(crate) fn free_raw(value: BNInstructionTextToken) { - if !value.text.is_null() { - unsafe { BNFreeString(value.text) }; - } + unsafe { BnString::free_raw(value.text) }; if !value.typeNames.is_null() { unsafe { BNFreeStringList(value.typeNames, value.namesCount) }; } diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index 39136c7d2d..4b7b3c0ce9 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -105,9 +105,9 @@ impl DownloadInstance { Ref::new(Self::from_raw(handle)) } - fn get_error(&self) -> BnString { + fn get_error(&self) -> String { let err: *mut c_char = unsafe { BNGetErrorForDownloadInstance(self.handle) }; - unsafe { BnString::from_raw(err) } + unsafe { BnString::into_string(err) } } unsafe extern "C" fn o_write_callback(data: *mut u8, len: u64, ctxt: *mut c_void) -> u64 { @@ -138,7 +138,7 @@ impl DownloadInstance { &mut self, url: S, callbacks: DownloadInstanceOutputCallbacks, - ) -> Result<(), BnString> { + ) -> Result<(), String> { let callbacks = Box::into_raw(Box::new(callbacks)); let mut cbs = BNDownloadInstanceOutputCallbacks { writeCallback: Some(Self::o_write_callback), @@ -215,7 +215,7 @@ impl DownloadInstance { url: U, headers: I, callbacks: DownloadInstanceInputOutputCallbacks, - ) -> Result { + ) -> Result { let mut header_keys = vec![]; let mut header_values = vec![]; for (key, value) in headers { diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index 7030b194aa..9b97a387c4 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -98,13 +98,13 @@ pub fn release_license() { } // TODO: If "" string return None -pub fn server_username() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUsername()) } +pub fn server_username() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerUsername()) } } // TODO: If "" string return None -pub fn server_url() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } +pub fn server_url() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } } pub fn set_server_url(url: S) -> Result<(), ()> { @@ -121,24 +121,24 @@ pub fn set_server_url(url: S) -> Result<(), ()> { } } -pub fn server_name() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerName()) } +pub fn server_name() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerName()) } } -pub fn server_id() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerId()) } +pub fn server_id() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerId()) } } pub fn server_version() -> u64 { unsafe { binaryninjacore_sys::BNGetEnterpriseServerVersion() } } -pub fn server_build_id() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerBuildId()) } +pub fn server_build_id() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerBuildId()) } } -pub fn server_token() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerToken()) } +pub fn server_token() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerToken()) } } pub fn license_duration() -> Duration { @@ -226,8 +226,8 @@ pub fn initialize_server() -> bool { unsafe { binaryninjacore_sys::BNInitializeEnterpriseServer() } } -pub fn server_last_error() -> BnString { - unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerLastError()) } +pub fn server_last_error() -> String { + unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerLastError()) } } pub fn server_authentication_methods() -> (Array, Array) { diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs index 2b3594b643..5360f29d0e 100644 --- a/rust/src/external_library.rs +++ b/rust/src/external_library.rs @@ -24,10 +24,10 @@ impl ExternalLibrary { } /// Get the name of this external library - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNExternalLibraryGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Get the file backing this external library diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index f1923b407c..c14aaf2999 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -68,10 +68,10 @@ impl FileMetadata { unsafe { BNFileMetadataGetSessionId(self.handle) } } - pub fn filename(&self) -> BnString { + pub fn filename(&self) -> String { unsafe { let raw = BNGetFilename(self.handle); - BnString::from_raw(raw) + BnString::into_string(raw) } } @@ -131,8 +131,8 @@ impl FileMetadata { } } - pub fn begin_undo_actions(&self, anonymous_allowed: bool) -> BnString { - unsafe { BnString::from_raw(BNBeginUndoActions(self.handle, anonymous_allowed)) } + pub fn begin_undo_actions(&self, anonymous_allowed: bool) -> String { + unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } pub fn commit_undo_actions(&self, id: S) { @@ -161,8 +161,8 @@ impl FileMetadata { } } - pub fn current_view(&self) -> BnString { - unsafe { BnString::from_raw(BNGetCurrentView(self.handle)) } + pub fn current_view(&self) -> String { + unsafe { BnString::into_string(BNGetCurrentView(self.handle)) } } pub fn current_offset(&self) -> u64 { diff --git a/rust/src/function.rs b/rust/src/function.rs index c882ab08c9..53fec505ef 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -368,8 +368,8 @@ impl Function { } } - pub fn comment(&self) -> BnString { - unsafe { BnString::from_raw(BNGetFunctionComment(self.handle)) } + pub fn comment(&self) -> String { + unsafe { BnString::into_string(BNGetFunctionComment(self.handle)) } } pub fn set_comment(&self, comment: S) { @@ -390,8 +390,8 @@ impl Function { unsafe { BNSetUserFunctionCanReturn(self.handle, &mut bool_with_confidence) } } - pub fn comment_at(&self, addr: u64) -> BnString { - unsafe { BnString::from_raw(BNGetCommentForAddress(self.handle, addr)) } + pub fn comment_at(&self, addr: u64) -> String { + unsafe { BnString::into_string(BNGetCommentForAddress(self.handle, addr)) } } pub fn set_comment_at(&self, addr: u64, comment: S) { @@ -459,11 +459,11 @@ impl Function { unsafe { Array::new(lines, count, ()) } } - pub fn variable_name(&self, var: &Variable) -> BnString { + pub fn variable_name(&self, var: &Variable) -> String { unsafe { let raw_var = BNVariable::from(var); let raw_name = BNGetVariableName(self.handle, &raw_var); - BnString::from_raw(raw_name) + BnString::into_string(raw_name) } } @@ -1741,10 +1741,10 @@ impl Function { value: u64, operand: usize, arch: Option, - ) -> BnString { + ) -> String { let arch = arch.unwrap_or_else(|| self.arch()); unsafe { - BnString::from_raw(BNGetIntegerConstantDisplayTypeEnumerationType( + BnString::into_string(BNGetIntegerConstantDisplayTypeEnumerationType( self.handle, arch.handle, instr_addr, @@ -1766,7 +1766,7 @@ impl Function { value: u64, operand: usize, arch: Option, - ) -> (IntegerDisplayType, BnString) { + ) -> (IntegerDisplayType, String) { let arch = arch.unwrap_or_else(|| self.arch()); let name = self.int_enum_display_typeid(instr_addr, value, operand, Some(arch)); let display = self.int_display_type(instr_addr, value, operand, Some(arch)); @@ -1922,7 +1922,7 @@ impl Function { addr: u64, offset: i64, arch: Option, - ) -> Option<(Variable, BnString, Conf>)> { + ) -> Option { let arch = arch.unwrap_or_else(|| self.arch()); let mut found_value = BNVariableNameAndType::default(); let found = unsafe { @@ -1937,13 +1937,7 @@ impl Function { if !found { return None; } - let var = Variable::from(found_value.var); - let name = unsafe { BnString::from_raw(found_value.name) }; - let var_type = Conf::new( - unsafe { Type::ref_from_raw(found_value.type_) }, - found_value.typeConfidence, - ); - Some((var, name, var_type)) + Some(NamedVariableWithType::from_owned_raw(found_value)) } pub fn stack_var_at_frame_offset_after_instruction( @@ -1951,7 +1945,7 @@ impl Function { addr: u64, offset: i64, arch: Option, - ) -> Option<(Variable, BnString, Conf>)> { + ) -> Option { let arch = arch.unwrap_or_else(|| self.arch()); let mut found_value = BNVariableNameAndType::default(); let found = unsafe { @@ -1966,13 +1960,7 @@ impl Function { if !found { return None; } - let var = Variable::from(found_value.var); - let name = unsafe { BnString::from_raw(found_value.name) }; - let var_type = Conf::new( - unsafe { Type::ref_from_raw(found_value.type_) }, - found_value.typeConfidence, - ); - Some((var, name, var_type)) + Some(NamedVariableWithType::from_owned_raw(found_value)) } pub fn stack_variables_referenced_by( @@ -2348,8 +2336,8 @@ impl Function { /// Returns a string representing the provenance. This portion of the API /// is under development. Currently the provenance information is /// undocumented, not persistent, and not saved to a database. - pub fn provenance(&self) -> BnString { - unsafe { BnString::from_raw(BNGetProvenanceString(self.handle)) } + pub fn provenance(&self) -> String { + unsafe { BnString::into_string(BNGetProvenanceString(self.handle)) } } /// Get registers that are used for the return value @@ -2780,7 +2768,7 @@ impl Default for HighlightColor { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct Comment { pub addr: u64, - pub comment: BnString, + pub comment: String, } impl CoreArrayProvider for Comment { diff --git a/rust/src/headless.rs b/rust/src/headless.rs index 3ea969473f..3228633196 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -71,7 +71,7 @@ pub fn init() -> Result<(), InitializationError> { /// /// ⚠️ Important! Must be called at the end of scripts. ⚠️ pub fn shutdown() { - match crate::product().as_str() { + match crate::product().to_string().as_str() { "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => { if NEED_LICENSE_RELEASE.load(SeqCst) { enterprise::release_license() diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs index 340b85a75d..c5733a4336 100644 --- a/rust/src/high_level_il/operation.rs +++ b/rust/src/high_level_il/operation.rs @@ -16,8 +16,8 @@ pub struct GotoLabel { } impl GotoLabel { - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNGetGotoLabelName(self.function.handle, self.target)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNGetGotoLabelName(self.function.handle, self.target)) } } fn set_name(&self, name: S) { @@ -323,7 +323,7 @@ pub struct LiftedLabel { } impl LiftedLabel { - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { self.target.name() } diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 1546bc5ae2..4a74127bf4 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -92,8 +92,8 @@ pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option return None; } - let string = unsafe { BnString::from_raw(value) }; - Some(PathBuf::from(string.as_str())) + let path = unsafe { BnString::into_string(value) }; + Some(PathBuf::from(path)) } pub fn get_save_filename_input( @@ -115,8 +115,8 @@ pub fn get_save_filename_input( return None; } - let string = unsafe { BnString::from_raw(value) }; - Some(PathBuf::from(string.as_str())) + let path = unsafe { BnString::into_string(value) }; + Some(PathBuf::from(path)) } pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option { @@ -133,8 +133,8 @@ pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option BnString { - unsafe { BnString::from_raw(BNGetVersionString()) } +pub fn version() -> String { + unsafe { BnString::into_string(BNGetVersionString()) } } pub fn build_id() -> u32 { @@ -512,16 +512,16 @@ pub fn version_info() -> VersionInfo { VersionInfo::from_owned_raw(info_raw) } -pub fn serial_number() -> BnString { - unsafe { BnString::from_raw(BNGetSerialNumber()) } +pub fn serial_number() -> String { + unsafe { BnString::into_string(BNGetSerialNumber()) } } pub fn is_license_validated() -> bool { unsafe { BNIsLicenseValidated() } } -pub fn licensed_user_email() -> BnString { - unsafe { BnString::from_raw(BNGetLicensedUserEmail()) } +pub fn licensed_user_email() -> String { + unsafe { BnString::into_string(BNGetLicensedUserEmail()) } } pub fn license_path() -> PathBuf { @@ -547,12 +547,12 @@ pub fn set_license(license: Option) { #[cfg(feature = "demo")] pub fn set_license(_license: Option) {} -pub fn product() -> BnString { - unsafe { BnString::from_raw(BNGetProduct()) } +pub fn product() -> String { + unsafe { BnString::into_string(BNGetProduct()) } } -pub fn product_type() -> BnString { - unsafe { BnString::from_raw(BNGetProductType()) } +pub fn product_type() -> String { + unsafe { BnString::into_string(BNGetProductType()) } } pub fn license_expiration_time() -> std::time::SystemTime { diff --git a/rust/src/logger.rs b/rust/src/logger.rs index c928287ff2..c06f4dfcd8 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -66,8 +66,8 @@ impl Logger { } } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNLoggerGetName(self.handle.as_ptr())) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNLoggerGetName(self.handle.as_ptr())) } } pub fn session_id(&self) -> usize { @@ -144,7 +144,7 @@ impl log::Log for Ref { BNLog( self.session_id(), level, - logger_name.as_ptr(), + logger_name.as_ptr() as *const c_char, 0, percent_s.as_ptr(), msg.as_ptr(), diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 72f6143041..6d2b30f001 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -160,10 +160,10 @@ impl Platform { } } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { unsafe { let raw_name = BNGetPlatformName(self.handle); - BnString::from_raw(raw_name) + BnString::into_string(raw_name) } } @@ -301,7 +301,7 @@ impl Platform { assert!(!error_string.is_null()); Err(TypeParserError::new( TypeParserErrorSeverity::FatalSeverity, - unsafe { BnString::from_raw(error_string) }.to_string(), + unsafe { BnString::into_string(error_string) }, file_name.to_string(), 0, 0, diff --git a/rust/src/project.rs b/rust/src/project.rs index fad1e5ef2f..ebb6949eb2 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -84,18 +84,18 @@ impl Project { } /// Get the unique id of this project - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetId(self.handle.as_ptr())) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNProjectGetId(self.handle.as_ptr())) } } /// Get the path of the project - pub fn path(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetPath(self.handle.as_ptr())) } + pub fn path(&self) -> String { + unsafe { BnString::into_string(BNProjectGetPath(self.handle.as_ptr())) } } /// Get the name of the project - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetName(self.handle.as_ptr())) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNProjectGetName(self.handle.as_ptr())) } } /// Set the name of the project @@ -110,8 +110,8 @@ impl Project { } /// Get the description of the project - pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectGetDescription(self.handle.as_ptr())) } + pub fn description(&self) -> String { + unsafe { BnString::into_string(BNProjectGetDescription(self.handle.as_ptr())) } } /// Set the description of the project diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs index 5071dd50b8..35f25937a7 100644 --- a/rust/src/project/file.rs +++ b/rust/src/project/file.rs @@ -37,8 +37,8 @@ impl ProjectFile { } /// Get the path on disk to this file's contents - pub fn path_on_disk(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetPathOnDisk(self.handle.as_ptr())) } + pub fn path_on_disk(&self) -> String { + unsafe { BnString::into_string(BNProjectFileGetPathOnDisk(self.handle.as_ptr())) } } /// Check if this file's contents exist on disk @@ -47,13 +47,13 @@ impl ProjectFile { } /// Get the unique id of this file - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetId(self.handle.as_ptr())) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNProjectFileGetId(self.handle.as_ptr())) } } /// Get the name of this file - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetName(self.handle.as_ptr())) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNProjectFileGetName(self.handle.as_ptr())) } } /// Set the name of this file @@ -68,8 +68,8 @@ impl ProjectFile { } /// Get the description of this file - pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFileGetDescription(self.handle.as_ptr())) } + pub fn description(&self) -> String { + unsafe { BnString::into_string(BNProjectFileGetDescription(self.handle.as_ptr())) } } /// Set the description of this file diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index 90b40051b6..316abeafd0 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -36,13 +36,13 @@ impl ProjectFolder { } /// Get the unique id of this folder - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetId(self.handle.as_ptr())) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNProjectFolderGetId(self.handle.as_ptr())) } } /// Get the name of this folder - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetName(self.handle.as_ptr())) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNProjectFolderGetName(self.handle.as_ptr())) } } /// Set the name of this folder @@ -57,8 +57,8 @@ impl ProjectFolder { } /// Get the description of this folder - pub fn description(&self) -> BnString { - unsafe { BnString::from_raw(BNProjectFolderGetDescription(self.handle.as_ptr())) } + pub fn description(&self) -> String { + unsafe { BnString::into_string(BNProjectFolderGetDescription(self.handle.as_ptr())) } } /// Set the description of this folder diff --git a/rust/src/repository.rs b/rust/src/repository.rs index 135b236783..90e414d5f9 100644 --- a/rust/src/repository.rs +++ b/rust/src/repository.rs @@ -31,17 +31,17 @@ impl Repository { } /// String URL of the git repository where the plugin repository's are stored - pub fn url(&self) -> BnString { + pub fn url(&self) -> String { let result = unsafe { BNRepositoryGetUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String local path to store the given plugin repository - pub fn path(&self) -> BnString { + pub fn path(&self) -> String { let result = unsafe { BNRepositoryGetRepoPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// List of RepoPlugin objects contained within this repository @@ -65,10 +65,10 @@ impl Repository { // TODO: Make this a PathBuf? /// String full path the repository - pub fn full_path(&self) -> BnString { + pub fn full_path(&self) -> String { let result = unsafe { BNRepositoryGetPluginsPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } } diff --git a/rust/src/repository/plugin.rs b/rust/src/repository/plugin.rs index af3886f2e9..82309e7935 100644 --- a/rust/src/repository/plugin.rs +++ b/rust/src/repository/plugin.rs @@ -31,31 +31,31 @@ impl RepositoryPlugin { } /// String of the plugin author - pub fn author(&self) -> BnString { + pub fn author(&self) -> String { let result = unsafe { BNPluginGetAuthor(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String short description of the plugin - pub fn description(&self) -> BnString { + pub fn description(&self) -> String { let result = unsafe { BNPluginGetDescription(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String complete license text for the given plugin - pub fn license_text(&self) -> BnString { + pub fn license_text(&self) -> String { let result = unsafe { BNPluginGetLicenseText(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String long description of the plugin - pub fn long_description(&self) -> BnString { + pub fn long_description(&self) -> String { let result = unsafe { BNPluginGetLongdescription(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// Minimum version info the plugin was tested on @@ -71,65 +71,65 @@ impl RepositoryPlugin { } /// String plugin name - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNPluginGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String URL of the plugin's git repository - pub fn project_url(&self) -> BnString { + pub fn project_url(&self) -> String { let result = unsafe { BNPluginGetProjectUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String URL of the plugin's git repository - pub fn package_url(&self) -> BnString { + pub fn package_url(&self) -> String { let result = unsafe { BNPluginGetPackageUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String URL of the plugin author's url - pub fn author_url(&self) -> BnString { + pub fn author_url(&self) -> String { let result = unsafe { BNPluginGetAuthorUrl(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String version of the plugin - pub fn version(&self) -> BnString { + pub fn version(&self) -> String { let result = unsafe { BNPluginGetVersion(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// String of the commit of this plugin git repository - pub fn commit(&self) -> BnString { + pub fn commit(&self) -> String { let result = unsafe { BNPluginGetCommit(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// Relative path from the base of the repository to the actual plugin - pub fn path(&self) -> BnString { + pub fn path(&self) -> String { let result = unsafe { BNPluginGetPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// Optional sub-directory the plugin code lives in as a relative path from the plugin root - pub fn subdir(&self) -> BnString { + pub fn subdir(&self) -> String { let result = unsafe { BNPluginGetSubdir(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// Dependencies required for installing this plugin - pub fn dependencies(&self) -> BnString { + pub fn dependencies(&self) -> String { let result = unsafe { BNPluginGetDependencies(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// true if the plugin is installed, false otherwise @@ -190,10 +190,10 @@ impl RepositoryPlugin { unsafe { Array::new(result, count, ()) } } - pub fn repository(&self) -> BnString { + pub fn repository(&self) -> String { let result = unsafe { BNPluginGetRepository(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result as *mut c_char) } + unsafe { BnString::into_string(result as *mut c_char) } } /// Boolean status indicating that the plugin is being deleted @@ -237,10 +237,10 @@ impl RepositoryPlugin { } /// Gets a json object of the project data field - pub fn project_data(&self) -> BnString { + pub fn project_data(&self) -> String { let result = unsafe { BNPluginGetProjectData(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Returns a datetime object representing the plugins last update diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index e61cd46652..5f42dbea62 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -56,10 +56,10 @@ impl CoreSecretsProvider { NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNGetSecretsProviderName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Check if data for a specific key exists, but do not retrieve it @@ -71,12 +71,12 @@ impl CoreSecretsProvider { } /// Retrieve data for the given key, if it exists - pub fn get_data(&self, key: S) -> BnString { + pub fn get_data(&self, key: S) -> String { let key = key.into_bytes_with_nul(); let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Store data with the given key diff --git a/rust/src/section.rs b/rust/src/section.rs index c88ef9b0e6..46a201d4f0 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -90,12 +90,12 @@ impl Section { SectionBuilder::new(name, range) } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNSectionGetName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNSectionGetName(self.handle)) } } - pub fn section_type(&self) -> BnString { - unsafe { BnString::from_raw(BNSectionGetType(self.handle)) } + pub fn section_type(&self) -> String { + unsafe { BnString::into_string(BNSectionGetType(self.handle)) } } pub fn start(&self) -> u64 { @@ -122,12 +122,12 @@ impl Section { unsafe { BNSectionGetSemantics(self.handle).into() } } - pub fn linked_section(&self) -> BnString { - unsafe { BnString::from_raw(BNSectionGetLinkedSection(self.handle)) } + pub fn linked_section(&self) -> String { + unsafe { BnString::into_string(BNSectionGetLinkedSection(self.handle)) } } - pub fn info_section(&self) -> BnString { - unsafe { BnString::from_raw(BNSectionGetInfoSection(self.handle)) } + pub fn info_section(&self) -> String { + unsafe { BnString::into_string(BNSectionGetInfoSection(self.handle)) } } pub fn info_data(&self) -> u64 { diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 8c64f314e8..4b4d418fdd 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -58,8 +58,8 @@ impl Settings { unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ref().as_ptr() as *mut _) }; } - pub fn serialize_schema(&self) -> BnString { - unsafe { BnString::from_raw(BNSettingsSerializeSchema(self.handle)) } + pub fn serialize_schema(&self) -> String { + unsafe { BnString::into_string(BNSettingsSerializeSchema(self.handle)) } } pub fn deserialize_schema(&self, schema: S) -> bool { @@ -184,7 +184,7 @@ impl Settings { } } - pub fn get_string(&self, key: S) -> BnString { + pub fn get_string(&self, key: S) -> String { self.get_string_with_opts(key, &mut QueryOptions::default()) } @@ -192,7 +192,7 @@ impl Settings { &self, key: S, options: &mut QueryOptions, - ) -> BnString { + ) -> String { let key = key.into_bytes_with_nul(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -203,7 +203,7 @@ impl Settings { _ => std::ptr::null_mut(), }; unsafe { - BnString::from_raw(BNSettingsGetString( + BnString::into_string(BNSettingsGetString( self.handle, key.as_ref().as_ptr() as *mut _, view_ptr, @@ -248,7 +248,7 @@ impl Settings { } } - pub fn get_json(&self, key: S) -> BnString { + pub fn get_json(&self, key: S) -> String { self.get_json_with_opts(key, &mut QueryOptions::default()) } @@ -256,7 +256,7 @@ impl Settings { &self, key: S, options: &mut QueryOptions, - ) -> BnString { + ) -> String { let key = key.into_bytes_with_nul(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -267,7 +267,7 @@ impl Settings { _ => std::ptr::null_mut(), }; unsafe { - BnString::from_raw(BNSettingsGetJson( + BnString::into_string(BNSettingsGetJson( self.handle, key.as_ref().as_ptr() as *mut _, view_ptr, @@ -479,11 +479,11 @@ impl Settings { } } - pub fn get_property_string(&self, key: S, property: S) -> BnString { + pub fn get_property_string(&self, key: S, property: S) -> String { let key = key.into_bytes_with_nul(); let property = property.into_bytes_with_nul(); unsafe { - BnString::from_raw(BNSettingsQueryPropertyString( + BnString::into_string(BNSettingsQueryPropertyString( self.handle, key.as_ref().as_ptr() as *mut _, property.as_ref().as_ptr() as *mut _, diff --git a/rust/src/string.rs b/rust/src/string.rs index f92248516a..3cdbf3840d 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -69,10 +69,25 @@ impl BnString { } } + /// Take an owned core string and convert it to [`String`]. + /// + /// This expects the passed raw string to be owned, as in, freed by us. + pub unsafe fn into_string(raw: *mut c_char) -> String { + Self::from_raw(raw).to_string() + } + /// Construct a BnString from an owned const char* allocated by BNAllocString pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self { Self { raw } } + + /// Free a raw string allocated by BNAllocString. + pub(crate) unsafe fn free_raw(raw: *mut c_char) { + use binaryninjacore_sys::BNFreeString; + if !raw.is_null() { + BNFreeString(raw); + } + } /// Consumes the `BnString`, returning a raw pointer to the string. /// @@ -87,34 +102,11 @@ impl BnString { mem::forget(value); res } - - pub fn as_str(&self) -> &str { - unsafe { CStr::from_ptr(self.raw).to_str().unwrap() } - } - - pub fn as_bytes(&self) -> &[u8] { - self.as_str().as_bytes() - } - - pub fn as_bytes_with_null(&self) -> &[u8] { - self.deref().to_bytes() - } - - pub fn len(&self) -> usize { - self.as_str().len() - } - - pub fn is_empty(&self) -> bool { - self.as_str().is_empty() - } } impl Drop for BnString { fn drop(&mut self) { - use binaryninjacore_sys::BNFreeString; - unsafe { - BNFreeString(self.raw); - } + unsafe { BnString::free_raw(self.raw) }; } } @@ -137,6 +129,18 @@ impl Deref for BnString { } } +impl From for BnString { + fn from(s: String) -> Self { + Self::new(s) + } +} + +impl From<&str> for BnString { + fn from(s: &str) -> Self { + Self::new(s) + } +} + impl AsRef<[u8]> for BnString { fn as_ref(&self) -> &[u8] { self.to_bytes_with_nul() @@ -208,6 +212,14 @@ unsafe impl BnStrCompatible for BnString { } } +unsafe impl BnStrCompatible for &BnString { + type Result = Self; + + fn into_bytes_with_nul(self) -> Self::Result { + self + } +} + unsafe impl BnStrCompatible for CString { type Result = Vec; diff --git a/rust/src/tags.rs b/rust/src/tags.rs index 2db3a58cbc..63c3634a75 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -47,12 +47,12 @@ impl Tag { unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ref().as_ptr() as *mut _)) } } - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNTagGetId(self.handle)) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNTagGetId(self.handle)) } } - pub fn data(&self) -> BnString { - unsafe { BnString::from_raw(BNTagGetData(self.handle)) } + pub fn data(&self) -> String { + unsafe { BnString::into_string(BNTagGetData(self.handle)) } } pub fn ty(&self) -> Ref { @@ -145,12 +145,12 @@ impl TagType { tag_type } - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNTagTypeGetId(self.handle)) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNTagTypeGetId(self.handle)) } } - pub fn icon(&self) -> BnString { - unsafe { BnString::from_raw(BNTagTypeGetIcon(self.handle)) } + pub fn icon(&self) -> String { + unsafe { BnString::into_string(BNTagTypeGetIcon(self.handle)) } } pub fn set_icon(&self, icon: S) { @@ -160,8 +160,8 @@ impl TagType { } } - pub fn name(&self) -> BnString { - unsafe { BnString::from_raw(BNTagTypeGetName(self.handle)) } + pub fn name(&self) -> String { + unsafe { BnString::into_string(BNTagTypeGetName(self.handle)) } } pub fn set_name(&self, name: S) { diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index f10cda504b..2c8caa3968 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -757,8 +757,8 @@ impl TypeArchive { ) }; assert!(!result.is_null()); - let id_str = unsafe { BnString::from_raw(result) }; - TypeArchiveSnapshotId(id_str.to_string()) + let id_str = unsafe { BnString::into_string(result) }; + TypeArchiveSnapshotId(id_str) } /// Merge two snapshots in the archive to produce a new snapshot @@ -1140,10 +1140,10 @@ impl TypeArchiveMergeConflict { NonNull::new(value).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } - pub fn type_id(&self) -> BnString { + pub fn type_id(&self) -> String { let value = unsafe { BNTypeArchiveMergeConflictGetTypeId(self.handle.as_ptr()) }; assert!(!value.is_null()); - unsafe { BnString::from_raw(value) } + unsafe { BnString::into_string(value) } } pub fn base_snapshot_id(&self) -> TypeArchiveSnapshotId { diff --git a/rust/src/type_container.rs b/rust/src/type_container.rs index 947c6912a0..1535732d40 100644 --- a/rust/src/type_container.rs +++ b/rust/src/type_container.rs @@ -44,17 +44,17 @@ impl TypeContainer { /// Get an id string for the Type Container. This will be unique within a given /// analysis session, but may not be globally unique. - pub fn id(&self) -> BnString { + pub fn id(&self) -> String { let result = unsafe { BNTypeContainerGetId(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Get a user-friendly name for the Type Container. - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNTypeContainerGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Get the type of underlying model the Type Container is accessing. diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index 656f0c9d46..22c4ba7692 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -61,10 +61,10 @@ impl CoreTypeParser { NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNGetTypeParserName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } } diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 12c7164580..124079ecb1 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -67,10 +67,10 @@ impl CoreTypePrinter { NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNGetTypePrinterName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } pub fn get_type_tokens>( diff --git a/rust/src/types.rs b/rust/src/types.rs index 9d1353bd96..8dbeeb48fd 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -932,9 +932,9 @@ impl Type { } } - pub fn generate_auto_demangled_type_id>(name: T) -> BnString { + pub fn generate_auto_demangled_type_id>(name: T) -> String { let mut raw_name = QualifiedName::into_raw(name.into()); - let type_id = unsafe { BnString::from_raw(BNGenerateAutoDemangledTypeId(&mut raw_name)) }; + let type_id = unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) }; QualifiedName::free_raw(raw_name); type_id } @@ -2334,7 +2334,7 @@ impl NameAndType { } pub(crate) fn free_raw(value: BNNameAndType) { - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; let _ = unsafe { Type::ref_from_raw(value.type_) }; } diff --git a/rust/src/update.rs b/rust/src/update.rs index 2a22c9c9f5..9afb1218d6 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -242,8 +242,8 @@ impl UpdateVersion { } pub(crate) fn free_raw(value: BNUpdateVersion) { - let _ = unsafe { BnString::from_raw(value.version) }; - let _ = unsafe { BnString::from_raw(value.notes) }; + unsafe { BnString::free_raw(value.version) }; + unsafe { BnString::free_raw(value.notes) }; } } diff --git a/rust/src/websocket/provider.rs b/rust/src/websocket/provider.rs index 0e28afe45c..2d01fbc363 100644 --- a/rust/src/websocket/provider.rs +++ b/rust/src/websocket/provider.rs @@ -87,10 +87,10 @@ impl CoreWebsocketProvider { NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNGetWebsocketProviderName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } } diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index ca42ff686f..71a60824a7 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -204,10 +204,10 @@ impl Activity { unsafe { Activity::ref_from_raw(NonNull::new(result).unwrap()) } } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNActivityGetName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } } @@ -303,10 +303,10 @@ impl Workflow { unsafe { Array::new(result, count, ()) } } - pub fn name(&self) -> BnString { + pub fn name(&self) -> String { let result = unsafe { BNGetWorkflowName(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Register this [Workflow], making it immutable and available for use. @@ -382,7 +382,7 @@ impl Workflow { } /// Retrieve the configuration as an adjacency list in JSON for the [Workflow]. - pub fn configuration(&self) -> BnString { + pub fn configuration(&self) -> String { self.configuration_with_activity("") } @@ -390,7 +390,7 @@ impl Workflow { /// [Workflow], just for the given `activity`. /// /// `activity` - return the configuration for the `activity` - pub fn configuration_with_activity(&self, activity: A) -> BnString { + pub fn configuration_with_activity(&self, activity: A) -> String { let result = unsafe { BNWorkflowGetConfiguration( self.handle.as_ptr(), @@ -398,7 +398,7 @@ impl Workflow { ) }; assert!(!result.is_null()); - unsafe { BnString::from_raw(result) } + unsafe { BnString::into_string(result) } } /// Whether this [Workflow] is registered or not. A [Workflow] becomes immutable once registered. From 16771533a9e012e0a21edb63c966b33d5076ede0 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 14:45:50 -0400 Subject: [PATCH 04/54] [Rust] Remove unused file --- rust/src/relocs.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 rust/src/relocs.rs diff --git a/rust/src/relocs.rs b/rust/src/relocs.rs deleted file mode 100644 index e69de29bb2..0000000000 From 4e81b6ce2db507a28aed55d9692d7d559f419b3a Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 15:38:54 -0400 Subject: [PATCH 05/54] [Rust] More cleanup --- rust/src/architecture.rs | 1 + rust/src/debuginfo.rs | 15 ++++----------- rust/src/function.rs | 40 +++++++++++++++++++++++++++------------- rust/src/interaction.rs | 2 +- rust/src/lib.rs | 30 ++++++++++++++++-------------- rust/src/linear_view.rs | 2 +- rust/src/platform.rs | 2 +- rust/src/string.rs | 2 +- rust/src/type_archive.rs | 16 +++++++++------- rust/src/type_parser.rs | 6 +++--- rust/src/type_printer.rs | 2 +- rust/src/types.rs | 11 ++++++----- rust/src/update.rs | 6 +++--- rust/src/variable.rs | 4 ++-- rust/src/websocket.rs | 2 +- 15 files changed, 77 insertions(+), 64 deletions(-) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index d2e5e0fc21..ee8033a225 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1810,6 +1810,7 @@ impl Architecture for CoreArchitecture { Ok(result) => result, Err(_) => return Err("Result buffer allocation failed".to_string()), }; + // TODO: This is actually a list of errors. let mut error_raw: *mut c_char = std::ptr::null_mut(); let res = unsafe { BNAssemble( diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index bafa9cc490..c4bc7addf3 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -807,15 +807,8 @@ impl DebugInfo { } for local_variable in &new_func.local_variables { - local_variables_array.push(BNVariableNameAndType { - var: local_variable.variable.into(), - autoDefined: local_variable.auto_defined, - typeConfidence: local_variable.ty.confidence, - name: BNAllocString( - local_variable.name.clone().into_bytes_with_nul().as_ptr() as _ - ), - type_: local_variable.ty.contents.handle, - }); + // NOTE: must be manually freed after call to BNAddDebugFunction is over. + local_variables_array.push(NamedVariableWithType::into_raw(local_variable.clone())); } let result = BNAddDebugFunction( @@ -841,11 +834,11 @@ impl DebugInfo { ); for i in components_array { - BNFreeString(i); + BnString::free_raw(i); } for i in &local_variables_array { - BNFreeString(i.name); + NamedVariableWithType::free_raw(*i); } result } diff --git a/rust/src/function.rs b/rust/src/function.rs index 53fec505ef..3eea3a3ffa 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -49,7 +49,7 @@ use crate::variable::{ use crate::workflow::Workflow; use std::fmt::{Debug, Formatter}; use std::ptr::NonNull; -use std::time::Duration; +use std::time::{Duration, UNIX_EPOCH}; use std::{ffi::c_char, hash::Hash, ops::Range}; /// Used to describe a location within a [`Function`]. @@ -259,7 +259,7 @@ impl FunctionViewType { } pub(crate) fn free_raw(value: BNFunctionViewType) { - let _ = unsafe { BnString::from_raw(value.name as *mut _) }; + unsafe { BnString::free_raw(value.name as *mut _) }; } } @@ -2520,23 +2520,38 @@ pub struct PerformanceInfo { pub seconds: Duration, } -impl From for PerformanceInfo { - fn from(value: BNPerformanceInfo) -> Self { +impl PerformanceInfo { + pub fn new(name: String, seconds: Duration) -> Self { Self { - name: unsafe { BnString::from_raw(value.name) }.to_string(), - seconds: Duration::from_secs_f64(value.seconds), + name: name.to_string(), + seconds, } } -} -impl From<&BNPerformanceInfo> for PerformanceInfo { - fn from(value: &BNPerformanceInfo) -> Self { + pub(crate) fn from_raw(value: &BNPerformanceInfo) -> Self { Self { - // TODO: Name will be freed by this. FIX! - name: unsafe { BnString::from_raw(value.name) }.to_string(), + name: raw_to_string(value.name as *mut _).unwrap(), seconds: Duration::from_secs_f64(value.seconds), } } + + pub(crate) fn from_owned_raw(value: BNPerformanceInfo) -> Self { + let owned = Self::from_raw(&value); + Self::free_raw(value); + owned + } + + pub(crate) fn into_raw(value: Self) -> BNPerformanceInfo { + let bn_name = BnString::new(value.name); + BNPerformanceInfo { + name: BnString::into_raw(bn_name), + seconds: value.seconds.as_secs_f64(), + } + } + + pub(crate) fn free_raw(value: BNPerformanceInfo) { + unsafe { BnString::free_raw(value.name) }; + } } impl CoreArrayProvider for PerformanceInfo { @@ -2551,8 +2566,7 @@ unsafe impl CoreArrayProviderInner for PerformanceInfo { } unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - // TODO: Swap this to the ref version. - Self::from(*raw) + Self::from_raw(raw) } } diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 4a74127bf4..23dcaf85c3 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -37,7 +37,7 @@ pub fn get_text_line_input(prompt: &str, title: &str) -> Option { return None; } - Some(unsafe { BnString::from_raw(value).to_string() }) + Some(unsafe { BnString::into_string(value) }) } pub fn get_integer_input(prompt: &str, title: &str) -> Option { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 0446fe60b4..4d6b97b4a8 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -279,8 +279,8 @@ where pub fn install_directory() -> PathBuf { let install_dir_ptr: *mut c_char = unsafe { BNGetInstallDirectory() }; assert!(!install_dir_ptr.is_null()); - let bn_install_dir = unsafe { BnString::from_raw(install_dir_ptr) }; - PathBuf::from(bn_install_dir.to_string()) + let install_dir_str = unsafe { BnString::into_string(install_dir_ptr) }; + PathBuf::from(install_dir_str) } pub fn bundled_plugin_directory() -> Result { @@ -288,7 +288,7 @@ pub fn bundled_plugin_directory() -> Result { if s.is_null() { return Err(()); } - Ok(PathBuf::from(unsafe { BnString::from_raw(s) }.to_string())) + Ok(PathBuf::from(unsafe { BnString::into_string(s) })) } pub fn set_bundled_plugin_directory(new_dir: impl AsRef) { @@ -299,8 +299,8 @@ pub fn set_bundled_plugin_directory(new_dir: impl AsRef) { pub fn user_directory() -> PathBuf { let user_dir_ptr: *mut c_char = unsafe { BNGetUserDirectory() }; assert!(!user_dir_ptr.is_null()); - let bn_user_dir = unsafe { BnString::from_raw(user_dir_ptr) }; - PathBuf::from(bn_user_dir.to_string()) + let user_dir_str = unsafe { BnString::into_string(user_dir_ptr) }; + PathBuf::from(user_dir_str) } pub fn user_plugin_directory() -> Result { @@ -308,7 +308,8 @@ pub fn user_plugin_directory() -> Result { if s.is_null() { return Err(()); } - Ok(PathBuf::from(unsafe { BnString::from_raw(s) }.to_string())) + let user_plugin_dir_str = unsafe { BnString::into_string(s) }; + Ok(PathBuf::from(user_plugin_dir_str)) } pub fn repositories_directory() -> Result { @@ -316,14 +317,15 @@ pub fn repositories_directory() -> Result { if s.is_null() { return Err(()); } - Ok(PathBuf::from(unsafe { BnString::from_raw(s) }.to_string())) + let repo_dir_str = unsafe { BnString::into_string(s) }; + Ok(PathBuf::from(repo_dir_str)) } -pub fn settings_file_name() -> PathBuf { +pub fn settings_file_path() -> PathBuf { let settings_file_name_ptr: *mut c_char = unsafe { BNGetSettingsFileName() }; assert!(!settings_file_name_ptr.is_null()); - let bn_settings_file_name = unsafe { BnString::from_raw(settings_file_name_ptr) }; - PathBuf::from(bn_settings_file_name.to_string()) + let settings_file_path_str = unsafe { BnString::into_string(settings_file_name_ptr) }; + PathBuf::from(settings_file_path_str) } /// Write the installation directory of the currently running core instance to disk. @@ -340,7 +342,7 @@ pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Resu if s.is_null() { return Err(()); } - Ok(PathBuf::from(unsafe { BnString::from_raw(s) }.to_string())) + Ok(PathBuf::from(unsafe { BnString::into_string(s) })) } pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result { @@ -350,7 +352,7 @@ pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result< if s.is_null() { return Err(()); } - Ok(PathBuf::from(unsafe { BnString::from_raw(s) }.to_string())) + Ok(PathBuf::from(unsafe { BnString::into_string(s) })) } pub fn path_relative_to_user_directory(path: impl AsRef) -> Result { @@ -360,7 +362,7 @@ pub fn path_relative_to_user_directory(path: impl AsRef) -> Result(string: S) -> Self { diff --git a/rust/src/linear_view.rs b/rust/src/linear_view.rs index ca35d525e7..db164278a6 100644 --- a/rust/src/linear_view.rs +++ b/rust/src/linear_view.rs @@ -267,7 +267,7 @@ impl LinearViewObjectIdentifier { } pub fn free_raw(value: BNLinearViewObjectIdentifier) { - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; } } diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 6d2b30f001..65138c19e4 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -386,7 +386,7 @@ impl Platform { assert!(!error_string.is_null()); Err(TypeParserError::new( TypeParserErrorSeverity::FatalSeverity, - unsafe { BnString::from_raw(error_string) }.to_string(), + unsafe { BnString::into_string(error_string) }, filename.to_string(), 0, 0, diff --git a/rust/src/string.rs b/rust/src/string.rs index 3cdbf3840d..5bd871f995 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -80,7 +80,7 @@ impl BnString { pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self { Self { raw } } - + /// Free a raw string allocated by BNAllocString. pub(crate) unsafe fn free_raw(raw: *mut c_char) { use binaryninjacore_sys::BNFreeString; diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 2c8caa3968..ee4bc276b5 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -112,8 +112,8 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchivePath(self.handle.as_ptr()) }; match result.is_null() { false => { - let bn_res = unsafe { BnString::from_raw(result) }; - Some(PathBuf::from(bn_res.to_string())) + let path_str = unsafe { BnString::into_string(result) }; + Some(PathBuf::from(path_str)) } true => None, } @@ -136,7 +136,8 @@ impl TypeArchive { pub fn current_snapshot_id(&self) -> TypeArchiveSnapshotId { let result = unsafe { BNGetTypeArchiveCurrentSnapshotId(self.handle.as_ptr()) }; assert!(!result.is_null()); - TypeArchiveSnapshotId(unsafe { BnString::from_raw(result) }.to_string()) + let id = unsafe { BnString::into_string(result) }; + TypeArchiveSnapshotId(id) } /// Revert the type archive's current snapshot to the given snapshot @@ -651,7 +652,8 @@ impl TypeArchive { let result = unsafe { BNTypeArchiveDeserializeSnapshot(self.handle.as_ptr(), data.as_raw()) }; assert!(!result.is_null()); - TypeArchiveSnapshotId(unsafe { BnString::from_raw(result) }.to_string()) + let id = unsafe { BnString::into_string(result) }; + TypeArchiveSnapshotId(id) } /// Register a notification listener @@ -1149,21 +1151,21 @@ impl TypeArchiveMergeConflict { pub fn base_snapshot_id(&self) -> TypeArchiveSnapshotId { let value = unsafe { BNTypeArchiveMergeConflictGetBaseSnapshotId(self.handle.as_ptr()) }; assert!(!value.is_null()); - let id = unsafe { BnString::from_raw(value) }.to_string(); + let id = unsafe { BnString::into_string(value) }; TypeArchiveSnapshotId(id) } pub fn first_snapshot_id(&self) -> TypeArchiveSnapshotId { let value = unsafe { BNTypeArchiveMergeConflictGetFirstSnapshotId(self.handle.as_ptr()) }; assert!(!value.is_null()); - let id = unsafe { BnString::from_raw(value) }.to_string(); + let id = unsafe { BnString::into_string(value) }; TypeArchiveSnapshotId(id) } pub fn second_snapshot_id(&self) -> TypeArchiveSnapshotId { let value = unsafe { BNTypeArchiveMergeConflictGetSecondSnapshotId(self.handle.as_ptr()) }; assert!(!value.is_null()); - let id = unsafe { BnString::from_raw(value) }.to_string(); + let id = unsafe { BnString::into_string(value) }; TypeArchiveSnapshotId(id) } diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index 22c4ba7692..dbf5a709ad 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -323,8 +323,8 @@ impl TypeParserError { } pub(crate) fn free_raw(value: BNTypeParserError) { - let _ = unsafe { BnString::from_raw(value.message) }; - let _ = unsafe { BnString::from_raw(value.fileName) }; + unsafe { BnString::free_raw(value.message) }; + unsafe { BnString::free_raw(value.fileName) }; } pub fn new( @@ -677,7 +677,7 @@ unsafe extern "C" fn cb_parse_type_string( unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) { // SAFETY: The returned string is just BnString - let _ = BnString::from_raw(string); + BnString::free_raw(string); } unsafe extern "C" fn cb_free_result(_ctxt: *mut c_void, result: *mut BNTypeParserResult) { diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 124079ecb1..67d3657035 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -951,7 +951,7 @@ unsafe extern "C" fn cb_print_all_types( unsafe extern "C" fn cb_free_string(_ctxt: *mut c_void, string: *mut c_char) { // SAFETY: The returned string is just BnString - let _ = BnString::from_raw(string); + BnString::free_raw(string); } unsafe extern "C" fn cb_free_tokens( diff --git a/rust/src/types.rs b/rust/src/types.rs index 8dbeeb48fd..a46dce2ebe 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -934,7 +934,8 @@ impl Type { pub fn generate_auto_demangled_type_id>(name: T) -> String { let mut raw_name = QualifiedName::into_raw(name.into()); - let type_id = unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) }; + let type_id = + unsafe { BnString::into_string(BNGenerateAutoDemangledTypeId(&mut raw_name)) }; QualifiedName::free_raw(raw_name); type_id } @@ -1109,7 +1110,7 @@ impl FunctionParameter { } pub(crate) fn free_raw(value: BNFunctionParameter) { - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; let _ = unsafe { Type::ref_from_raw(value.type_) }; } @@ -1184,7 +1185,7 @@ impl EnumerationMember { } pub(crate) fn free_raw(value: BNEnumerationMember) { - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; } pub fn new(name: String, value: u64, default: bool) -> Self { @@ -1723,7 +1724,7 @@ impl StructureMember { pub(crate) fn free_raw(value: BNStructureMember) { let _ = unsafe { Type::ref_from_raw(value.type_) }; - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; } pub fn new( @@ -1987,7 +1988,7 @@ impl QualifiedName { } pub(crate) fn free_raw(value: BNQualifiedName) { - unsafe { BNFreeString(value.join) }; + unsafe { BnString::free_raw(value.join) }; unsafe { BNFreeStringList(value.name, value.nameCount) }; } diff --git a/rust/src/update.rs b/rust/src/update.rs index 9afb1218d6..aa8c7daf38 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -75,9 +75,9 @@ impl UpdateChannel { } pub(crate) fn free_raw(value: BNUpdateChannel) { - let _ = unsafe { BnString::from_raw(value.name) }; - let _ = unsafe { BnString::from_raw(value.description) }; - let _ = unsafe { BnString::from_raw(value.latestVersion) }; + unsafe { BnString::free_raw(value.name) }; + unsafe { BnString::free_raw(value.description) }; + unsafe { BnString::free_raw(value.latestVersion) }; } pub fn all() -> Result, BnString> { diff --git a/rust/src/variable.rs b/rust/src/variable.rs index f6b0f52241..c0cab7d51f 100644 --- a/rust/src/variable.rs +++ b/rust/src/variable.rs @@ -186,7 +186,7 @@ impl NamedVariableWithType { pub(crate) fn free_raw(value: BNVariableNameAndType) { let _ = unsafe { Type::ref_from_raw(value.type_) }; - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; } pub fn new(variable: Variable, ty: Conf>, name: String, auto_defined: bool) -> Self { @@ -307,7 +307,7 @@ impl StackVariableReference { pub(crate) fn free_raw(value: BNStackVariableReference) { let _ = unsafe { Type::ref_from_raw(value.type_) }; - let _ = unsafe { BnString::from_raw(value.name) }; + unsafe { BnString::free_raw(value.name) }; } } diff --git a/rust/src/websocket.rs b/rust/src/websocket.rs index cc1b5f7740..4acf10a6b5 100644 --- a/rust/src/websocket.rs +++ b/rust/src/websocket.rs @@ -1,7 +1,7 @@ //! Interface for registering new websocket providers //! //! WARNING: Do _not_ use this for anything other than provider registration. If you need to open a -//! websocket connection use a real websocket library. +//! websocket connection, use a real websocket library. mod client; mod provider; From 0629024c7eafc70bcb7d2c64fed4dfe9a3320e59 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 15:49:30 -0400 Subject: [PATCH 06/54] [Rust] Misc clippy lints --- plugins/pdb-ng/src/lib.rs | 2 +- plugins/pdb-ng/src/type_parser.rs | 16 +++++++++++----- rust/src/function.rs | 3 ++- rust/src/low_level_il/block.rs | 4 ++-- rust/src/low_level_il/expression.rs | 6 +++--- rust/src/low_level_il/instruction.rs | 2 +- rust/src/low_level_il/lifting.rs | 2 +- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/plugins/pdb-ng/src/lib.rs b/plugins/pdb-ng/src/lib.rs index 2c1049b01f..188b2ed505 100644 --- a/plugins/pdb-ng/src/lib.rs +++ b/plugins/pdb-ng/src/lib.rs @@ -540,7 +540,7 @@ impl PDBParser { impl CustomDebugInfoParser for PDBParser { fn is_valid(&self, view: &BinaryView) -> bool { - view.type_name().to_string() == "PE" || is_pdb(view) + view.type_name() == "PE" || is_pdb(view) } fn parse_info( diff --git a/plugins/pdb-ng/src/type_parser.rs b/plugins/pdb-ng/src/type_parser.rs index 7910e13a86..61c6421835 100644 --- a/plugins/pdb-ng/src/type_parser.rs +++ b/plugins/pdb-ng/src/type_parser.rs @@ -1759,9 +1759,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { structure.width(data.size); self.namespace_stack.push(union_name.to_string()); - let success = self.parse_union_fields(&mut structure, data.fields, finder); + let _success = self.parse_union_fields(&mut structure, data.fields, finder); self.namespace_stack.pop(); - let _ = success?; let new_type = Type::structure(structure.finalize().as_ref()); Ok(Some(Box::new(ParsedType::Named(union_name, new_type)))) @@ -2015,7 +2014,11 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { // for some reason if let Some(raw_name) = Self::type_data_to_raw_name(&parsed) { if let Some(&full_index) = self.full_type_indices.get(&raw_name) { - if let None = self.type_stack.iter().find(|&&idx| idx == full_index) + if self + .type_stack + .iter() + .find(|&&idx| idx == full_index) + .is_none() { if full_index != index { return self.try_type_index_to_bare( @@ -2050,8 +2053,11 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { // for some reason if let Some(raw_name) = Self::type_data_to_raw_name(&parsed) { if let Some(&full_index) = self.full_type_indices.get(&raw_name) { - if let None = - self.type_stack.iter().find(|&&idx| idx == full_index) + if self + .type_stack + .iter() + .find(|&&idx| idx == full_index) + .is_none() { if full_index != index { return self.try_type_index_to_bare( diff --git a/rust/src/function.rs b/rust/src/function.rs index 3eea3a3ffa..50753d7476 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -49,7 +49,7 @@ use crate::variable::{ use crate::workflow::Workflow; use std::fmt::{Debug, Formatter}; use std::ptr::NonNull; -use std::time::{Duration, UNIX_EPOCH}; +use std::time::Duration; use std::{ffi::c_char, hash::Hash, ops::Range}; /// Used to describe a location within a [`Function`]. @@ -2520,6 +2520,7 @@ pub struct PerformanceInfo { pub seconds: Duration, } +#[allow(unused)] impl PerformanceInfo { pub fn new(name: String, seconds: Duration) -> Self { Self { diff --git a/rust/src/low_level_il/block.rs b/rust/src/low_level_il/block.rs index 519c707e7b..fd3e7c81b3 100644 --- a/rust/src/low_level_il/block.rs +++ b/rust/src/low_level_il/block.rs @@ -51,7 +51,7 @@ where } } -impl<'func, M, F> Debug for LowLevelILBlock<'func, M, F> +impl Debug for LowLevelILBlock<'_, M, F> where M: FunctionMutability, F: FunctionForm, @@ -63,7 +63,7 @@ where } } -impl<'func, M, F> Clone for LowLevelILBlock<'func, M, F> +impl Clone for LowLevelILBlock<'_, M, F> where M: FunctionMutability, F: FunctionForm, diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 331ab980ad..6addb7e10f 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -91,7 +91,7 @@ where } } -impl<'func, M, F, R> fmt::Debug for LowLevelILExpression<'func, M, F, R> +impl Debug for LowLevelILExpression<'_, M, F, R> where M: FunctionMutability, F: FunctionForm, @@ -202,7 +202,7 @@ where } } -impl<'func, F> LowLevelILExpression<'func, Finalized, F, ValueExpr> +impl LowLevelILExpression<'_, Finalized, F, ValueExpr> where F: FunctionForm, { @@ -650,7 +650,7 @@ where } } -impl<'func> LowLevelILExpressionKind<'func, Mutable, NonSSA> { +impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { pub fn flag_write(&self) -> Option { use self::LowLevelILExpressionKind::*; diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index a1253df5b3..ded9c6f3e0 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -100,7 +100,7 @@ where } } -impl<'func, M, F> Debug for LowLevelILInstruction<'func, M, F> +impl Debug for LowLevelILInstruction<'_, M, F> where M: FunctionMutability, F: FunctionForm, diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index c40f68f2e9..b0f85f11e5 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -667,7 +667,7 @@ impl<'a> LiftableLowLevelILWithSize<'a> } } -impl<'func, R> LowLevelILExpression<'func, Mutable, NonSSA, R> +impl LowLevelILExpression<'_, Mutable, NonSSA, R> where R: ExpressionResultType, { From de7a21002bc02274b06e8db052d8a0e1b6c6dfe6 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 19:06:10 -0400 Subject: [PATCH 07/54] [Rust] Simplify enterprise initialization We don't need to introduce extra global state when the goal is to not release floating licenses in shutdown. --- rust/src/enterprise.rs | 37 ++++++--- rust/src/headless.rs | 147 ++++++++++++++--------------------- rust/tests/initialization.rs | 4 +- 3 files changed, 90 insertions(+), 98 deletions(-) diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index 9b97a387c4..d09ac3333d 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -19,13 +19,23 @@ pub enum EnterpriseCheckoutError { RefreshExpiredLicenseFailed(String), } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum EnterpriseCheckoutStatus { + /// The UI is managing the enterprise checkout. + AlreadyManaged, + /// Checkout was successful, attached duration is the duration of the license, if any. + Success(Option), +} + /// Initialize the enterprise server connection to check out a floating license. /// Result value is if we actually checked out a license (i.e. Ok(false) means we already have a /// license checked out and will not need to release it later) -pub fn checkout_license(duration: Duration) -> Result { +pub fn checkout_license( + duration: Duration, +) -> Result { if crate::is_ui_enabled() { // We only need to check out a license if running headlessly. - return Ok(false); + return Ok(EnterpriseCheckoutStatus::AlreadyManaged); } // The disparate core functions we call here might already have mutexes to guard. @@ -67,20 +77,19 @@ pub fn checkout_license(duration: Duration) -> Result String { unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerToken()) } } -pub fn license_duration() -> Duration { - Duration::from_secs(unsafe { binaryninjacore_sys::BNGetEnterpriseServerLicenseDuration() }) +pub fn license_duration() -> Option { + let duration = + Duration::from_secs(unsafe { binaryninjacore_sys::BNGetEnterpriseServerLicenseDuration() }); + match duration { + // If the core returns 0 there is no license duration. + Duration::ZERO => None, + _ => Some(duration), + } } pub fn license_expiration_time() -> SystemTime { diff --git a/rust/src/headless.rs b/rust/src/headless.rs index 3228633196..7279a45980 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -14,14 +14,15 @@ use crate::{ binary_view, bundled_plugin_directory, enterprise, is_license_validated, is_main_thread, - license_path, set_bundled_plugin_directory, set_license, string::IntoJson, + is_ui_enabled, license_path, set_bundled_plugin_directory, set_license, string::IntoJson, }; use std::io; use std::path::{Path, PathBuf}; +use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; -use std::sync::atomic::{AtomicBool, AtomicUsize}; use thiserror::Error; +use crate::enterprise::EnterpriseCheckoutStatus; use crate::main_thread::{MainThreadAction, MainThreadHandler}; use crate::progress::ProgressCallback; use crate::rc::Ref; @@ -32,12 +33,9 @@ use std::thread::JoinHandle; use std::time::Duration; static MAIN_THREAD_HANDLE: Mutex>> = Mutex::new(None); -/// Prevent two threads from calling init() at the same time -static INIT_LOCK: Mutex<()> = Mutex::new(()); -/// Used to prevent shutting down Binary Ninja if there are other [`Session`]'s. + +/// Used to prevent shutting down Binary Ninja if there is another active [`Session`]. static SESSION_COUNT: AtomicUsize = AtomicUsize::new(0); -/// If we checked out a floating license and should release it on shutdown -static NEED_LICENSE_RELEASE: AtomicBool = AtomicBool::new(false); #[derive(Error, Debug)] pub enum InitializationError { @@ -49,15 +47,15 @@ pub enum InitializationError { InvalidLicense, #[error("no license could located, please see `binaryninja::set_license` for details")] NoLicenseFound, - #[error("could not acquire initialization mutex")] - InitMutex, + #[error("initialization already managed by ui")] + AlreadyManaged, } /// Loads plugins, core architecture, platform, etc. /// /// ⚠️ Important! Must be called at the beginning of scripts. Plugins do not need to call this. ⚠️ /// -/// You can instead call this through [`Session`]. +/// The preferred method for core initialization is [`Session`], use that instead of this where possible. /// /// If you need to customize initialization, use [`init_with_opts`] instead. pub fn init() -> Result<(), InitializationError> { @@ -67,15 +65,12 @@ pub fn init() -> Result<(), InitializationError> { /// Unloads plugins, stops all worker threads, and closes open logs. /// -/// If the core was initialized using an enterprise license, that will also be freed. -/// -/// ⚠️ Important! Must be called at the end of scripts. ⚠️ +/// This function does _NOT_ release floating licenses; it is expected that you call [`enterprise::release_license`]. pub fn shutdown() { - match crate::product().to_string().as_str() { + match crate::product().as_str() { "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => { - if NEED_LICENSE_RELEASE.load(SeqCst) { - enterprise::release_license() - } + // By default, we do not release floating licenses. + enterprise::release_license(false) } _ => {} } @@ -91,9 +86,9 @@ pub fn is_shutdown_requested() -> bool { pub struct InitializationOptions { /// A license to override with, you can use this to make sure you initialize with a specific license. pub license: Option, - /// If you need to make sure that you do not check out a license set this to false. + /// If you need to make sure that you do not check out a license, set this to false. /// - /// This is really only useful if you have a headless license but are using an enterprise enabled core. + /// This is really only useful if you have a headless license but are using an enterprise-enabled core. pub checkout_license: bool, /// Whether to register the default main thread handler. /// @@ -105,11 +100,11 @@ pub struct InitializationOptions { pub bundled_plugin_directory: PathBuf, /// Whether to initialize user plugins. /// - /// Set this to false if your use might be impacted by a user installed plugin. + /// Set this to false if your use might be impacted by a user-installed plugin. pub user_plugins: bool, /// Whether to initialize repo plugins. /// - /// Set this to false if your use might be impacted by a repo installed plugin. + /// Set this to false if your use might be impacted by a repo-installed plugin. pub repo_plugins: bool, } @@ -129,9 +124,9 @@ impl InitializationOptions { self } - /// If you need to make sure that you do not check out a license set this to false. + /// If you need to make sure that you do not check out a license, set this to false. /// - /// This is really only useful if you have a headless license but are using an enterprise enabled core. + /// This is really only useful if you have a headless license but are using an enterprise-enabled core. pub fn with_license_checkout(mut self, should_checkout: bool) -> Self { self.checkout_license = should_checkout; self @@ -151,13 +146,13 @@ impl InitializationOptions { self } - /// Set this to false if your use might be impacted by a user installed plugin. + /// Set this to false if your use might be impacted by a user-installed plugin. pub fn with_user_plugins(mut self, should_initialize: bool) -> Self { self.user_plugins = should_initialize; self } - /// Set this to false if your use might be impacted by a repo installed plugin. + /// Set this to false if your use might be impacted by a repo-installed plugin. pub fn with_repo_plugins(mut self, should_initialize: bool) -> Self { self.repo_plugins = should_initialize; self @@ -181,7 +176,11 @@ impl Default for InitializationOptions { /// This initializes the core with the given [`InitializationOptions`]. pub fn init_with_opts(options: InitializationOptions) -> Result<(), InitializationError> { - // If we are the main thread that means there is no main thread, we should register a main thread handler. + if is_ui_enabled() { + return Err(InitializationError::AlreadyManaged); + } + + // If we are the main thread, that means there is no main thread, we should register a main thread handler. if options.register_main_thread_handler && is_main_thread() { let mut main_thread_handle = MAIN_THREAD_HANDLE.lock().unwrap(); if main_thread_handle.is_none() { @@ -192,7 +191,7 @@ pub fn init_with_opts(options: InitializationOptions) -> Result<(), Initializati let join_handle = std::thread::Builder::new() .name("HeadlessMainThread".to_string()) .spawn(move || { - // We must register the main thread within said thread. + // We must register the main thread within the thread. main_thread.register(); while let Ok(action) = receiver.recv() { action.execute(); @@ -204,16 +203,13 @@ pub fn init_with_opts(options: InitializationOptions) -> Result<(), Initializati } } - match crate::product().as_str() { - "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => { - if options.checkout_license { - // We are allowed to check out a license, so do it! - if enterprise::checkout_license(options.floating_license_duration)? { - NEED_LICENSE_RELEASE.store(true, SeqCst); - } - } + if is_enterprise_product() && options.checkout_license { + // We are allowed to check out a license, so do it! + let checkout_status = enterprise::checkout_license(options.floating_license_duration)?; + if checkout_status == EnterpriseCheckoutStatus::AlreadyManaged { + // Should be impossible, but just in case. + return Err(InitializationError::AlreadyManaged); } - _ => {} } if let Some(license) = options.license { @@ -232,7 +228,7 @@ pub fn init_with_opts(options: InitializationOptions) -> Result<(), Initializati } if !is_license_validated() { - // Unfortunately you must have a valid license to use Binary Ninja. + // Unfortunately, you must have a valid license to use Binary Ninja. Err(InitializationError::InvalidLicense) } else { Ok(()) @@ -258,20 +254,27 @@ impl MainThreadHandler for HeadlessMainThreadSender { } } +fn is_enterprise_product() -> bool { + match crate::product().as_str() { + "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => true, + _ => false, + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum LicenseLocation { /// The license used when initializing will be the environment variable `BN_LICENSE`. EnvironmentVariable, /// The license used when initializing will be the file in the Binary Ninja user directory. File, - /// The license is retrieved using keychain credentials for `BN_ENTERPRISE_USERNAME`. + /// The license is retrieved using keychain credentials, this is only available for floating enterprise licenses. Keychain, } /// Attempts to identify the license location type, this follows the same order as core initialization. /// /// This is useful if you want to know whether the core will use your license. If this returns `None` -/// you should look setting the `BN_LICENSE` environment variable, or calling [`set_license`]. +/// you should look into setting the `BN_LICENSE` environment variable or calling [`set_license`]. pub fn license_location() -> Option { match std::env::var("BN_LICENSE") { Ok(_) => Some(LicenseLocation::EnvironmentVariable), @@ -279,33 +282,26 @@ pub fn license_location() -> Option { // Check the license_path to see if a file is there. if license_path().exists() { Some(LicenseLocation::File) - } else { - // Check to see if we might be authorizing with enterprise - if crate::product().as_str() == "Binary Ninja Enterprise Client" - || crate::product().as_str() == "Binary Ninja Ultimate" - { - // If we can't initialize enterprise, we probably are missing enterprise.server.url - // and our license surely is not valid. - if !enterprise::is_server_initialized() && !enterprise::initialize_server() { - return None; - } - // If Enterprise thinks we are using a floating license, then report it will be in the keychain - if enterprise::is_server_floating_license() { - Some(LicenseLocation::Keychain) - } else { - None - } - } else { - None + } else if is_enterprise_product() { + // If we can't initialize enterprise, we probably are missing enterprise.server.url + // and our license surely is not valid. + if !enterprise::is_server_initialized() && !enterprise::initialize_server() { + return None; } + // If Enterprise thinks we are using a floating license, then report it will be in the keychain + enterprise::is_server_floating_license().then_some(LicenseLocation::Keychain) + } else { + // If we are not using an enterprise license, we can't check the keychain, nowhere else to check. + None } } } } /// Wrapper for [`init`] and [`shutdown`]. Instantiating this at the top of your script will initialize everything correctly and then clean itself up at exit as well. +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] pub struct Session { - index: usize, + license_duration: Option, } impl Session { @@ -313,10 +309,8 @@ impl Session { /// /// This is required so that we can keep track of the [`SESSION_COUNT`]. fn registered_session() -> Self { - let previous_count = SESSION_COUNT.fetch_add(1, SeqCst); - Self { - index: previous_count, - } + let _previous_count = SESSION_COUNT.fetch_add(1, SeqCst); + Self::default() } /// Before calling new you must make sure that the license is retrievable, otherwise the core won't be able to initialize. @@ -326,19 +320,7 @@ impl Session { pub fn new() -> Result { if license_location().is_some() { // We were able to locate a license, continue with initialization. - - // Grab the lock before initialization to prevent another thread from initializing - // and racing the call to BNInitPlugins. - let _lock = INIT_LOCK - .lock() - .map_err(|_| InitializationError::InitMutex)?; - let session = Self::registered_session(); - // Since this whole section is locked, we're guaranteed to be index 0 if we're first. - // Only the first thread hitting this should be allowed to call BNInitPlugins - if session.index == 0 { - init()?; - } - Ok(session) + Self::new_with_opts(InitializationOptions::default()) } else { // There was no license that could be automatically retrieved, you must call [Self::new_with_license]. Err(InitializationError::NoLicenseFound) @@ -348,19 +330,10 @@ impl Session { /// Initialize with options, the same rules apply as [`Session::new`], see [`InitializationOptions::default`] for the regular options passed. /// /// This differs from [`Session::new`] in that it does not check to see if there is a license that the core - /// can discover by itself, therefor it is expected that you know where your license is when calling this directly. + /// can discover by itself, therefore, it is expected that you know where your license is when calling this directly. pub fn new_with_opts(options: InitializationOptions) -> Result { - // Grab the lock before initialization to prevent another thread from initializing - // and racing the call to BNInitPlugins. - let _lock = INIT_LOCK - .lock() - .map_err(|_| InitializationError::InitMutex)?; let session = Self::registered_session(); - // Since this whole section is locked, we're guaranteed to be index 0 if we're first. - // Only the first thread hitting this should be allowed to call BNInitPlugins - if session.index == 0 { - init_with_opts(options)?; - } + init_with_opts(options)?; Ok(session) } @@ -457,7 +430,7 @@ impl Drop for Session { fn drop(&mut self) { let previous_count = SESSION_COUNT.fetch_sub(1, SeqCst); if previous_count == 1 { - // We were the last session, therefor we can safely shut down. + // We were the last session, therefore, we can safely shut down. shutdown(); } } diff --git a/rust/tests/initialization.rs b/rust/tests/initialization.rs index 9847a73402..7ec52598ab 100644 --- a/rust/tests/initialization.rs +++ b/rust/tests/initialization.rs @@ -11,8 +11,8 @@ use binaryninja::set_license; #[test] fn test_license_validation() { - // Release floating license if we already have one, otherwise the failure will succeed. - release_license(); + // Release the floating license if we already have one, otherwise the failure will succeed. + release_license(true); // Make sure we properly report invalid license. let options = InitializationOptions::default() .with_license_checkout(false) From f82832fbbb451cac0c94edece9be24c78ead6d7a Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 19:10:56 -0400 Subject: [PATCH 08/54] [Rust] Simplify `BnStrCompatible` trait Followup to https://github.com/Vector35/binaryninja-api/pull/5897/ This simplifies usage of the trait in user code, should just be able to `to_cstr` to get the cstr repr and then call `as_ptr`. Co-authored-by: Michael Krasnitski --- rust/src/architecture.rs | 15 +- rust/src/background_task.rs | 8 +- rust/src/binary_view.rs | 130 ++++++++--------- rust/src/binary_view/memory_map.rs | 58 ++++---- rust/src/calling_convention.rs | 4 +- rust/src/collaboration.rs | 38 +++-- rust/src/collaboration/changeset.rs | 6 +- rust/src/collaboration/file.rs | 44 +++--- rust/src/collaboration/folder.rs | 10 +- rust/src/collaboration/group.rs | 17 +-- rust/src/collaboration/merge.rs | 18 +-- rust/src/collaboration/project.rs | 101 ++++++------- rust/src/collaboration/remote.rs | 95 ++++++------ rust/src/collaboration/snapshot.rs | 6 +- rust/src/collaboration/sync.rs | 35 +++-- rust/src/collaboration/user.rs | 10 +- rust/src/command.rs | 26 ++-- rust/src/component.rs | 14 +- rust/src/custom_binary_view.rs | 10 +- rust/src/data_buffer.rs | 7 +- rust/src/database.rs | 30 ++-- rust/src/database/kvs.rs | 14 +- rust/src/database/snapshot.rs | 6 +- rust/src/debuginfo.rs | 119 ++++++--------- rust/src/demangle.rs | 34 ++--- rust/src/disassembly.rs | 10 +- rust/src/download_provider.rs | 28 ++-- rust/src/enterprise.rs | 18 +-- rust/src/external_library.rs | 6 +- rust/src/file_metadata.rs | 44 +++--- rust/src/function.rs | 14 +- rust/src/high_level_il/operation.rs | 8 +- rust/src/interaction.rs | 36 ++--- rust/src/lib.rs | 52 +++---- rust/src/medium_level_il/function.rs | 18 +-- rust/src/metadata.rs | 40 +++--- rust/src/platform.rs | 27 ++-- rust/src/project.rs | 148 +++++++++---------- rust/src/project/file.rs | 14 +- rust/src/project/folder.rs | 16 +-- rust/src/relocation.rs | 6 +- rust/src/render_layer.rs | 10 +- rust/src/repository.rs | 6 +- rust/src/repository/manager.rs | 20 ++- rust/src/secrets_provider.rs | 26 ++-- rust/src/section.rs | 8 +- rust/src/settings.rs | 207 ++++++++++----------------- rust/src/string.rs | 136 +++++++++--------- rust/src/symbol.rs | 6 +- rust/src/tags.rs | 26 ++-- rust/src/template_simplifier.rs | 10 +- rust/src/type_archive.rs | 119 ++++++++------- rust/src/type_container.rs | 49 +++---- rust/src/type_library.rs | 60 ++++---- rust/src/type_parser.rs | 13 +- rust/src/type_printer.rs | 10 +- rust/src/types.rs | 46 +++--- rust/src/websocket/client.rs | 16 +-- rust/src/websocket/provider.rs | 8 +- rust/src/worker_thread.rs | 14 +- rust/src/workflow.rs | 119 +++++++-------- rust/tests/binary_view.rs | 9 +- rust/tests/websocket.rs | 6 +- 63 files changed, 1039 insertions(+), 1225 deletions(-) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index ee8033a225..74a8dfa409 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -27,7 +27,7 @@ use crate::{ platform::Platform, rc::*, relocation::CoreRelocationHandler, - string::BnStrCompatible, + string::AsCStr, string::*, types::{NameAndType, Type}, Endianness, @@ -1404,8 +1404,7 @@ impl CoreArchitecture { } pub fn by_name(name: &str) -> Option { - let handle = - unsafe { BNGetArchitectureByName(name.into_bytes_with_nul().as_ptr() as *mut _) }; + let handle = unsafe { BNGetArchitectureByName(name.to_cstr().as_ptr() as *mut _) }; match handle.is_null() { false => Some(CoreArchitecture { handle }), true => None, @@ -1953,8 +1952,8 @@ macro_rules! cc_func { /// Contains helper methods for all types implementing 'Architecture' pub trait ArchitectureExt: Architecture { - fn register_by_name(&self, name: S) -> Option { - let name = name.into_bytes_with_nul(); + fn register_by_name(&self, name: S) -> Option { + let name = name.to_cstr(); match unsafe { BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ref().as_ptr() as *mut _) @@ -2033,7 +2032,7 @@ pub trait ArchitectureExt: Architecture { fn register_relocation_handler(&self, name: S, func: F) where - S: BnStrCompatible, + S: AsCStr, R: 'static + RelocationHandler> + Send @@ -2056,7 +2055,7 @@ impl ArchitectureExt for T {} pub fn register_architecture(name: S, func: F) -> &'static A where - S: BnStrCompatible, + S: AsCStr, A: 'static + Architecture> + Send + Sync + Sized, F: FnOnce(CustomArchitectureHandle, CoreArchitecture) -> A, { @@ -3130,7 +3129,7 @@ where custom_arch.skip_and_return_value(data, addr, val) } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let uninit_arch = ArchitectureBuilder { arch: MaybeUninit::zeroed(), diff --git a/rust/src/background_task.rs b/rust/src/background_task.rs index 5d30f27d1d..c9059aca89 100644 --- a/rust/src/background_task.rs +++ b/rust/src/background_task.rs @@ -43,8 +43,8 @@ impl BackgroundTask { Self { handle } } - pub fn new(initial_text: S, can_cancel: bool) -> Ref { - let text = initial_text.into_bytes_with_nul(); + pub fn new(initial_text: S, can_cancel: bool) -> Ref { + let text = initial_text.to_cstr(); let handle = unsafe { BNBeginBackgroundTask(text.as_ref().as_ptr() as *mut _, can_cancel) }; // We should always be returned a valid task. assert!(!handle.is_null()); @@ -75,8 +75,8 @@ impl BackgroundTask { unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) } } - pub fn set_progress_text(&self, text: S) { - let progress_text = text.into_bytes_with_nul(); + pub fn set_progress_text(&self, text: S) { + let progress_text = text.to_cstr(); unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ref().as_ptr() as *mut _) } diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index d8f35caf73..854f58f4db 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -266,11 +266,11 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNGetEndOffset(self.as_ref().handle) } } - fn add_analysis_option(&self, name: impl BnStrCompatible) { + fn add_analysis_option(&self, name: impl AsCStr) { unsafe { BNAddAnalysisOption( self.as_ref().handle, - name.into_bytes_with_nul().as_ref().as_ptr() as *mut _, + name.to_cstr().as_ref().as_ptr() as *mut _, ) } } @@ -403,8 +403,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_raw_name(&self, raw_name: S) -> Option> { - let raw_name = raw_name.into_bytes_with_nul(); + fn symbol_by_raw_name(&self, raw_name: S) -> Option> { + let raw_name = raw_name.to_cstr(); unsafe { let raw_sym_ptr = BNGetSymbolByRawName( @@ -428,8 +428,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_by_name(&self, name: S) -> Array { - let raw_name = name.into_bytes_with_nul(); + fn symbols_by_name(&self, name: S) -> Array { + let raw_name = name.to_cstr(); unsafe { let mut count = 0; @@ -589,14 +589,14 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_type, S: BnStrCompatible>( + fn define_auto_type, S: AsCStr>( &self, name: T, source: S, type_obj: &Type, ) -> QualifiedName { let mut raw_name = QualifiedName::into_raw(name.into()); - let source_str = source.into_bytes_with_nul(); + let source_str = source.to_cstr(); let name_handle = unsafe { let id_str = BNGenerateAutoTypeId(source_str.as_ref().as_ptr() as *const _, &mut raw_name); @@ -606,14 +606,14 @@ pub trait BinaryViewExt: BinaryViewBase { QualifiedName::from_owned_raw(name_handle) } - fn define_auto_type_with_id, S: BnStrCompatible>( + fn define_auto_type_with_id, S: AsCStr>( &self, name: T, id: S, type_obj: &Type, ) -> QualifiedName { let mut raw_name = QualifiedName::into_raw(name.into()); - let id_str = id.into_bytes_with_nul(); + let id_str = id.to_cstr(); let result_raw_name = unsafe { BNDefineAnalysisType( self.as_ref().handle, @@ -716,8 +716,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn undefine_auto_type(&self, id: S) { - let id_str = id.into_bytes_with_nul(); + fn undefine_auto_type(&self, id: S) { + let id_str = id.to_cstr(); unsafe { BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _); } @@ -767,9 +767,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_by_id(&self, id: S) -> Option> { + fn type_by_id(&self, id: S) -> Option> { unsafe { - let id_str = id.into_bytes_with_nul(); + let id_str = id.to_cstr(); let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); if type_handle.is_null() { @@ -779,9 +779,9 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_name_by_id(&self, id: S) -> Option { + fn type_name_by_id(&self, id: S) -> Option { unsafe { - let id_str = id.into_bytes_with_nul(); + let id_str = id.to_cstr(); let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); let name = QualifiedName::from_owned_raw(name_handle); @@ -877,25 +877,25 @@ pub trait BinaryViewExt: BinaryViewBase { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: S) { - let raw_name = name.into_bytes_with_nul(); + fn remove_auto_section(&self, name: S) { + let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ref().as_ptr() as *mut _; unsafe { BNRemoveAutoSection(self.as_ref().handle, raw_name_ptr); } } - fn remove_user_section(&self, name: S) { - let raw_name = name.into_bytes_with_nul(); + fn remove_user_section(&self, name: S) { + let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ref().as_ptr() as *mut _; unsafe { BNRemoveUserSection(self.as_ref().handle, raw_name_ptr); } } - fn section_by_name(&self, name: S) -> Option> { + fn section_by_name(&self, name: S) -> Option> { unsafe { - let raw_name = name.into_bytes_with_nul(); + let raw_name = name.to_cstr(); let name_ptr = raw_name.as_ref().as_ptr() as *mut _; let raw_section_ptr = BNGetSectionByName(self.as_ref().handle, name_ptr); match raw_section_ptr.is_null() { @@ -1109,8 +1109,8 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } } - fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { - let raw_name = raw_name.into_bytes_with_nul(); + fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { + let raw_name = raw_name.to_cstr(); unsafe { BNShowGraphReport( self.as_ref().handle, @@ -1120,8 +1120,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn load_settings(&self, view_type_name: S) -> Result> { - let view_type_name = view_type_name.into_bytes_with_nul(); + fn load_settings(&self, view_type_name: S) -> Result> { + let view_type_name = view_type_name.to_cstr(); let settings_handle = unsafe { BNBinaryViewGetLoadSettings( self.as_ref().handle, @@ -1136,8 +1136,8 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_load_settings(&self, view_type_name: S, settings: &Settings) { - let view_type_name = view_type_name.into_bytes_with_nul(); + fn set_load_settings(&self, view_type_name: S, settings: &Settings) { + let view_type_name = view_type_name.to_cstr(); unsafe { BNBinaryViewSetLoadSettings( @@ -1153,11 +1153,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Arguments /// * `name` - the name for the tag /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag - fn create_tag_type( - &self, - name: N, - icon: I, - ) -> Ref { + fn create_tag_type(&self, name: N, icon: I) -> Ref { let tag_type = TagType::create(self.as_ref(), name, icon); unsafe { BNAddTagType(self.as_ref().handle, tag_type.handle); @@ -1171,8 +1167,8 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Get a tag type by its name. - fn tag_type_by_name(&self, name: S) -> Option> { - let name = name.into_bytes_with_nul(); + fn tag_type_by_name(&self, name: S) -> Option> { + let name = name.to_cstr(); unsafe { let handle = BNGetTagType(self.as_ref().handle, name.as_ref().as_ptr() as *mut _); if handle.is_null() { @@ -1185,8 +1181,8 @@ pub trait BinaryViewExt: BinaryViewBase { /// Get a tag by its id. /// /// Note this does not tell you anything about where it is used. - fn tag_by_id(&self, id: S) -> Option> { - let id = id.into_bytes_with_nul(); + fn tag_by_id(&self, id: S) -> Option> { + let id = id.to_cstr(); unsafe { let handle = BNGetTag(self.as_ref().handle, id.as_ref().as_ptr() as *mut _); if handle.is_null() { @@ -1199,7 +1195,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Creates and adds a tag to an address /// /// User tag creations will be added to the undo buffer - fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { + fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { let tag = Tag::new(t, data); unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) } @@ -1236,8 +1232,8 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// NOTE: This is different from setting a comment at the function-level. To set a comment in a /// function use [`Function::set_comment_at`] - fn set_comment_at(&self, addr: u64, comment: impl BnStrCompatible) { - let comment_raw = comment.into_bytes_with_nul(); + fn set_comment_at(&self, addr: u64, comment: impl AsCStr) { + let comment_raw = comment.to_cstr(); unsafe { BNSetGlobalCommentForAddress( self.as_ref().handle, @@ -1295,11 +1291,11 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn query_metadata(&self, key: S) -> Option> { + fn query_metadata(&self, key: S) -> Option> { let value: *mut BNMetadata = unsafe { BNBinaryViewQueryMetadata( self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, ) }; if value.is_null() { @@ -1309,7 +1305,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_metadata(&self, key: S) -> Option> + fn get_metadata(&self, key: S) -> Option> where T: for<'a> TryFrom<&'a Metadata>, { @@ -1317,7 +1313,7 @@ pub trait BinaryViewExt: BinaryViewBase { .map(|md| T::try_from(md.as_ref()).map_err(|_| ())) } - fn store_metadata(&self, key: S, value: V, is_auto: bool) + fn store_metadata(&self, key: S, value: V, is_auto: bool) where V: Into>, { @@ -1325,18 +1321,18 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNBinaryViewStoreMetadata( self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, md.as_ref().handle, is_auto, ) }; } - fn remove_metadata(&self, key: S) { + fn remove_metadata(&self, key: S) { unsafe { BNBinaryViewRemoveMetadata( self.as_ref().handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, ) }; } @@ -1462,8 +1458,8 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn component_by_guid(&self, guid: S) -> Option> { - let name = guid.into_bytes_with_nul(); + fn component_by_guid(&self, guid: S) -> Option> { + let name = guid.to_cstr(); let result = unsafe { BNGetComponentByGuid( self.as_ref().handle, @@ -1478,8 +1474,8 @@ pub trait BinaryViewExt: BinaryViewBase { NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn component_by_path(&self, path: P) -> Option> { - let path = path.into_bytes_with_nul(); + fn component_by_path(&self, path: P) -> Option> { + let path = path.to_cstr(); let result = unsafe { BNGetComponentByPath( self.as_ref().handle, @@ -1493,8 +1489,8 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) } } - fn remove_component_by_guid(&self, guid: P) -> bool { - let path = guid.into_bytes_with_nul(); + fn remove_component_by_guid(&self, guid: P) -> bool { + let path = guid.to_cstr(); unsafe { BNRemoveComponentByGuid( self.as_ref().handle, @@ -1521,8 +1517,8 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { Array::new(result, count, ()) } } - fn external_library(&self, name: S) -> Option> { - let name_ptr = name.into_bytes_with_nul(); + fn external_library(&self, name: S) -> Option> { + let name_ptr = name.to_cstr(); let result = unsafe { BNBinaryViewGetExternalLibrary( self.as_ref().handle, @@ -1533,8 +1529,8 @@ pub trait BinaryViewExt: BinaryViewBase { Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) } - fn remove_external_library(&self, name: S) { - let name_ptr = name.into_bytes_with_nul(); + fn remove_external_library(&self, name: S) { + let name_ptr = name.to_cstr(); unsafe { BNBinaryViewRemoveExternalLibrary( self.as_ref().handle, @@ -1543,13 +1539,13 @@ pub trait BinaryViewExt: BinaryViewBase { }; } - fn add_external_library( + fn add_external_library( &self, name: S, backing_file: Option<&ProjectFile>, auto: bool, ) -> Option> { - let name_ptr = name.into_bytes_with_nul(); + let name_ptr = name.to_cstr(); let result = unsafe { BNBinaryViewAddExternalLibrary( self.as_ref().handle, @@ -1585,7 +1581,7 @@ pub trait BinaryViewExt: BinaryViewBase { } // TODO: This is awful, rewrite this. - fn add_external_location( + fn add_external_location( &self, symbol: &Symbol, library: &ExternalLibrary, @@ -1593,7 +1589,7 @@ pub trait BinaryViewExt: BinaryViewBase { target_address: Option, target_is_auto: bool, ) -> Option> { - let target_symbol_name = target_symbol_name.into_bytes_with_nul(); + let target_symbol_name = target_symbol_name.to_cstr(); let target_address_ptr = target_address .map(|a| a as *mut u64) .unwrap_or(std::ptr::null_mut()); @@ -1643,8 +1639,8 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } } - fn type_library_by_name(&self, name: S) -> Option { - let name = name.into_bytes_with_nul(); + fn type_library_by_name(&self, name: S) -> Option { + let name = name.to_cstr(); let result = unsafe { BNGetBinaryViewTypeLibrary( self.as_ref().handle, @@ -1741,8 +1737,8 @@ pub trait BinaryViewExt: BinaryViewBase { /// contain a metadata key called "type_guids" which is a map /// Dict[string_guid, string_type_name] or /// Dict[string_guid, Tuple[string_type_name, type_library_name]] - fn import_type_by_guid(&self, guid: S) -> Option> { - let guid = guid.into_bytes_with_nul(); + fn import_type_by_guid(&self, guid: S) -> Option> { + let guid = guid.to_cstr(); let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid( self.as_ref().handle, @@ -1889,7 +1885,7 @@ impl BinaryView { } pub fn from_path(meta: &mut FileMetadata, file_path: impl AsRef) -> Result> { - let file = file_path.as_ref().into_bytes_with_nul(); + let file = file_path.as_ref().to_cstr(); let handle = unsafe { BNCreateBinaryDataViewFromFilename(meta.handle, file.as_ptr() as *mut _) }; @@ -1931,7 +1927,7 @@ impl BinaryView { /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there /// are no queued up main thread actions. pub fn save_to_path(&self, file_path: impl AsRef) -> bool { - let file = file_path.as_ref().into_bytes_with_nul(); + let file = file_path.as_ref().to_cstr(); unsafe { BNSaveToFilename(self.handle, file.as_ptr() as *mut _) } } diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index 182cb16a13..b173744066 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -3,7 +3,7 @@ use crate::data_buffer::DataBuffer; use crate::file_accessor::FileAccessor; use crate::rc::Ref; use crate::segment::SegmentFlags; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; use std::ffi::c_char; @@ -43,12 +43,12 @@ impl MemoryMap { pub fn add_binary_memory_region( &mut self, - name: impl BnStrCompatible, + name: impl AsCStr, start: u64, view: &BinaryView, segment_flags: Option, ) -> bool { - let name_raw = name.into_bytes_with_nul(); + let name_raw = name.to_cstr(); unsafe { BNAddBinaryMemoryRegion( self.view.handle, @@ -62,12 +62,12 @@ impl MemoryMap { pub fn add_data_memory_region( &mut self, - name: impl BnStrCompatible, + name: impl AsCStr, start: u64, data: &DataBuffer, segment_flags: Option, ) -> bool { - let name_raw = name.into_bytes_with_nul(); + let name_raw = name.to_cstr(); unsafe { BNAddDataMemoryRegion( self.view.handle, @@ -81,12 +81,12 @@ impl MemoryMap { pub fn add_remote_memory_region( &mut self, - name: impl BnStrCompatible, + name: impl AsCStr, start: u64, accessor: &mut FileAccessor, segment_flags: Option, ) -> bool { - let name_raw = name.into_bytes_with_nul(); + let name_raw = name.to_cstr(); unsafe { BNAddRemoteMemoryRegion( self.view.handle, @@ -98,8 +98,8 @@ impl MemoryMap { } } - pub fn remove_memory_region(&mut self, name: impl BnStrCompatible) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn remove_memory_region(&mut self, name: impl AsCStr) -> bool { + let name_raw = name.to_cstr(); unsafe { BNRemoveMemoryRegion( self.view.handle, @@ -115,8 +115,8 @@ impl MemoryMap { } } - pub fn memory_region_flags(&self, name: impl BnStrCompatible) -> SegmentFlags { - let name_raw = name.into_bytes_with_nul(); + pub fn memory_region_flags(&self, name: impl AsCStr) -> SegmentFlags { + let name_raw = name.to_cstr(); let flags_raw = unsafe { BNGetMemoryRegionFlags( self.view.handle, @@ -126,12 +126,8 @@ impl MemoryMap { SegmentFlags::from_raw(flags_raw) } - pub fn set_memory_region_flags( - &mut self, - name: impl BnStrCompatible, - flags: SegmentFlags, - ) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn set_memory_region_flags(&mut self, name: impl AsCStr, flags: SegmentFlags) -> bool { + let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFlags( self.view.handle, @@ -141,8 +137,8 @@ impl MemoryMap { } } - pub fn is_memory_region_enabled(&self, name: impl BnStrCompatible) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn is_memory_region_enabled(&self, name: impl AsCStr) -> bool { + let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionEnabled( self.view.handle, @@ -151,8 +147,8 @@ impl MemoryMap { } } - pub fn set_memory_region_enabled(&mut self, name: impl BnStrCompatible, enabled: bool) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn set_memory_region_enabled(&mut self, name: impl AsCStr, enabled: bool) -> bool { + let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionEnabled( self.view.handle, @@ -163,8 +159,8 @@ impl MemoryMap { } // TODO: Should we just call this is_memory_region_relocatable? - pub fn is_memory_region_rebaseable(&self, name: impl BnStrCompatible) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn is_memory_region_rebaseable(&self, name: impl AsCStr) -> bool { + let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionRebaseable( self.view.handle, @@ -173,12 +169,8 @@ impl MemoryMap { } } - pub fn set_memory_region_rebaseable( - &mut self, - name: impl BnStrCompatible, - enabled: bool, - ) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn set_memory_region_rebaseable(&mut self, name: impl AsCStr, enabled: bool) -> bool { + let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionRebaseable( self.view.handle, @@ -188,8 +180,8 @@ impl MemoryMap { } } - pub fn memory_region_fill(&self, name: impl BnStrCompatible) -> u8 { - let name_raw = name.into_bytes_with_nul(); + pub fn memory_region_fill(&self, name: impl AsCStr) -> u8 { + let name_raw = name.to_cstr(); unsafe { BNGetMemoryRegionFill( self.view.handle, @@ -198,8 +190,8 @@ impl MemoryMap { } } - pub fn set_memory_region_fill(&mut self, name: impl BnStrCompatible, fill: u8) -> bool { - let name_raw = name.into_bytes_with_nul(); + pub fn set_memory_region_fill(&mut self, name: impl AsCStr, fill: u8) -> bool { + let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFill( self.view.handle, diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs index 6f2e9a1c35..f0f0ba4cf7 100644 --- a/rust/src/calling_convention.rs +++ b/rust/src/calling_convention.rs @@ -58,7 +58,7 @@ pub trait CallingConvention: Sync { pub fn register_calling_convention(arch: &A, name: N, cc: C) -> Ref where A: Architecture, - N: BnStrCompatible, + N: AsCStr, C: 'static + CallingConvention, { struct CustomCallingConventionContext @@ -377,7 +377,7 @@ where ) } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let raw = Box::into_raw(Box::new(CustomCallingConventionContext { raw_handle: std::ptr::null_mut(), cc, diff --git a/rust/src/collaboration.rs b/rust/src/collaboration.rs index c90677622b..1f76dc9acf 100644 --- a/rust/src/collaboration.rs +++ b/rust/src/collaboration.rs @@ -30,7 +30,7 @@ pub use user::*; use binaryninjacore_sys::*; use crate::rc::{Array, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; // TODO: Should we pull metadata and information required to call a function? Or should we add documentation // TODO: on what functions need to have been called prior? I feel like we should make the user have to pull @@ -73,23 +73,23 @@ pub fn known_remotes() -> Array { } /// Get Remote by unique `id` -pub fn get_remote_by_id(id: S) -> Option> { - let id = id.into_bytes_with_nul(); +pub fn get_remote_by_id(id: S) -> Option> { + let id = id.to_cstr(); let value = unsafe { BNCollaborationGetRemoteById(id.as_ref().as_ptr() as *const c_char) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `address` -pub fn get_remote_by_address(address: S) -> Option> { - let address = address.into_bytes_with_nul(); +pub fn get_remote_by_address(address: S) -> Option> { + let address = address.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByAddress(address.as_ref().as_ptr() as *const c_char) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `name` -pub fn get_remote_by_name(name: S) -> Option> { - let name = name.into_bytes_with_nul(); +pub fn get_remote_by_name(name: S) -> Option> { + let name = name.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByName(name.as_ref().as_ptr() as *const c_char) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } @@ -106,15 +106,15 @@ pub fn save_remotes() { pub fn store_data_in_keychain(key: K, data: I) -> bool where - K: BnStrCompatible, + K: AsCStr, I: IntoIterator, - DK: BnStrCompatible, - DV: BnStrCompatible, + DK: AsCStr, + DV: AsCStr, { - let key = key.into_bytes_with_nul(); + let key = key.to_cstr(); let (data_keys, data_values): (Vec, Vec) = data .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let data_keys_ptr: Box<[*const c_char]> = data_keys .iter() @@ -134,15 +134,13 @@ where } } -pub fn has_data_in_keychain(key: K) -> bool { - let key = key.into_bytes_with_nul(); +pub fn has_data_in_keychain(key: K) -> bool { + let key = key.to_cstr(); unsafe { BNCollaborationHasDataInKeychain(key.as_ref().as_ptr() as *const c_char) } } -pub fn get_data_from_keychain( - key: K, -) -> Option<(Array, Array)> { - let key = key.into_bytes_with_nul(); +pub fn get_data_from_keychain(key: K) -> Option<(Array, Array)> { + let key = key.to_cstr(); let mut keys = std::ptr::null_mut(); let mut values = std::ptr::null_mut(); let count = unsafe { @@ -157,7 +155,7 @@ pub fn get_data_from_keychain( keys.zip(values) } -pub fn delete_data_from_keychain(key: K) -> bool { - let key = key.into_bytes_with_nul(); +pub fn delete_data_from_keychain(key: K) -> bool { + let key = key.to_cstr(); unsafe { BNCollaborationDeleteDataFromKeychain(key.as_ref().as_ptr() as *const c_char) } } diff --git a/rust/src/collaboration/changeset.rs b/rust/src/collaboration/changeset.rs index fd862df667..1cc30d765e 100644 --- a/rust/src/collaboration/changeset.rs +++ b/rust/src/collaboration/changeset.rs @@ -7,7 +7,7 @@ use super::{RemoteFile, RemoteUser}; use crate::database::snapshot::SnapshotId; use crate::database::Database; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; /// A collection of snapshots in a local database #[repr(transparent)] @@ -66,8 +66,8 @@ impl Changeset { } /// Set the name of the changeset, e.g. in a name changeset function. - pub fn set_name(&self, value: S) -> bool { - let value = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) -> bool { + let value = value.to_cstr(); unsafe { BNCollaborationChangesetSetName( self.handle.as_ptr(), diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index 678c0c15b7..2089fbb7e4 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -16,7 +16,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback, SplitProgressBuilder}; use crate::project::file::ProjectFile; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub type RemoteFileType = BNRemoteFileType; @@ -94,8 +94,8 @@ impl RemoteFile { success.then_some(()).ok_or(()) } - pub fn set_metadata(&self, folder: S) -> Result<(), ()> { - let folder_raw = folder.into_bytes_with_nul(); + pub fn set_metadata(&self, folder: S) -> Result<(), ()> { + let folder_raw = folder.to_cstr(); let success = unsafe { BNRemoteFileSetMetadata( self.handle.as_ptr(), @@ -190,8 +190,8 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: S) -> Result<(), ()> { + let name = name.to_cstr(); let success = unsafe { BNRemoteFileSetName( self.handle.as_ptr(), @@ -209,8 +209,8 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { - let description = description.into_bytes_with_nul(); + pub fn set_description(&self, description: S) -> Result<(), ()> { + let description = description.to_cstr(); let success = unsafe { BNRemoteFileSetDescription( self.handle.as_ptr(), @@ -263,15 +263,12 @@ impl RemoteFile { /// Get a specific Snapshot in the File by its id /// /// NOTE: If snapshots have not been pulled, they will be pulled upon calling this. - pub fn snapshot_by_id( - &self, - id: S, - ) -> Result>, ()> { + pub fn snapshot_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_snapshots() { self.pull_snapshots()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let result = unsafe { BNRemoteFileGetSnapshotById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; @@ -314,9 +311,9 @@ impl RemoteFile { parent_ids: I, ) -> Result, ()> where - S: BnStrCompatible, + S: AsCStr, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { self.create_snapshot_with_progress( name, @@ -346,16 +343,13 @@ impl RemoteFile { mut progress: P, ) -> Result, ()> where - S: BnStrCompatible, + S: AsCStr, P: ProgressCallback, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let name = name.into_bytes_with_nul(); - let parent_ids: Vec<_> = parent_ids - .into_iter() - .map(|id| id.into_bytes_with_nul()) - .collect(); + let name = name.to_cstr(); + let parent_ids: Vec<_> = parent_ids.into_iter().map(|id| id.to_cstr()).collect(); let mut parent_ids_raw: Vec<_> = parent_ids .iter() .map(|x| x.as_ref().as_ptr() as *const c_char) @@ -430,7 +424,7 @@ impl RemoteFile { /// * `progress_function` - Function to call for progress updates pub fn download(&self, db_path: S) -> Result, ()> where - S: BnStrCompatible, + S: AsCStr, { sync::download_file(self, db_path) } @@ -447,14 +441,14 @@ impl RemoteFile { progress_function: F, ) -> Result, ()> where - S: BnStrCompatible, + S: AsCStr, F: ProgressCallback, { sync::download_file_with_progress(self, db_path, progress_function) } /// Download a remote file and save it to a BNDB at the given `path`, returning the associated [`FileMetadata`]. - pub fn download_database(&self, path: S) -> Result, ()> { + pub fn download_database(&self, path: S) -> Result, ()> { let file = self.download(path)?; let database = file.database().ok_or(())?; self.sync(&database, DatabaseConflictHandlerFail, NoNameChangeset)?; @@ -464,7 +458,7 @@ impl RemoteFile { // TODO: This might be a bad helper... maybe remove... // TODO: AsRef /// Download a remote file and save it to a BNDB at the given `path`. - pub fn download_database_with_progress( + pub fn download_database_with_progress( &self, path: S, progress: impl ProgressCallback, diff --git a/rust/src/collaboration/folder.rs b/rust/src/collaboration/folder.rs index eb4fd9f8ba..0fd2bf874f 100644 --- a/rust/src/collaboration/folder.rs +++ b/rust/src/collaboration/folder.rs @@ -5,7 +5,7 @@ use std::ptr::NonNull; use crate::project::folder::ProjectFolder; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct RemoteFolder { @@ -104,8 +104,8 @@ impl RemoteFolder { } /// Set the display name of the folder. You will need to push the folder to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: S) -> Result<(), ()> { + let name = name.to_cstr(); let success = unsafe { BNRemoteFolderSetName( self.handle.as_ptr(), @@ -123,8 +123,8 @@ impl RemoteFolder { } /// Set the description of the folder. You will need to push the folder to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { - let description = description.into_bytes_with_nul(); + pub fn set_description(&self, description: S) -> Result<(), ()> { + let description = description.to_cstr(); let success = unsafe { BNRemoteFolderSetDescription( self.handle.as_ptr(), diff --git a/rust/src/collaboration/group.rs b/rust/src/collaboration/group.rs index 9fb287a789..942535199b 100644 --- a/rust/src/collaboration/group.rs +++ b/rust/src/collaboration/group.rs @@ -1,6 +1,6 @@ use super::Remote; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; use std::ffi::c_char; use std::fmt; @@ -50,8 +50,8 @@ impl RemoteGroup { /// Set group name /// You will need to push the group to update the Remote. - pub fn set_name(&self, name: U) { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: U) { + let name = name.to_cstr(); unsafe { BNCollaborationGroupSetName( self.handle.as_ptr(), @@ -90,12 +90,9 @@ impl RemoteGroup { pub fn set_users(&self, usernames: I) -> Result<(), ()> where I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let usernames: Vec<_> = usernames - .into_iter() - .map(|u| u.into_bytes_with_nul()) - .collect(); + let usernames: Vec<_> = usernames.into_iter().map(|u| u.to_cstr()).collect(); let mut usernames_raw: Vec<_> = usernames .iter() .map(|s| s.as_ref().as_ptr() as *const c_char) @@ -114,8 +111,8 @@ impl RemoteGroup { } /// Test if a group has a user with the given username - pub fn contains_user(&self, username: U) -> bool { - let username = username.into_bytes_with_nul(); + pub fn contains_user(&self, username: U) -> bool { + let username = username.to_cstr(); unsafe { BNCollaborationGroupContainsUser( self.handle.as_ptr(), diff --git a/rust/src/collaboration/merge.rs b/rust/src/collaboration/merge.rs index 68bfdc029e..84aa619276 100644 --- a/rust/src/collaboration/merge.rs +++ b/rust/src/collaboration/merge.rs @@ -5,7 +5,7 @@ use std::ptr::NonNull; use crate::database::{snapshot::Snapshot, Database}; use crate::file_metadata::FileMetadata; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub type MergeConflictDataType = BNMergeConflictDataType; @@ -49,8 +49,8 @@ impl MergeConflict { NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) } - pub fn path_item_string(&self, path: S) -> Result { - let path = path.into_bytes_with_nul(); + pub fn path_item_string(&self, path: S) -> Result { + let path = path.to_cstr(); let result = unsafe { BNAnalysisMergeConflictGetPathItemString( self.handle.as_ptr(), @@ -123,8 +123,8 @@ impl MergeConflict { } /// Call this when you've resolved the conflict to save the result - pub fn success(&self, value: S) -> Result<(), ()> { - let value = value.into_bytes_with_nul(); + pub fn success(&self, value: S) -> Result<(), ()> { + let value = value.to_cstr(); let success = unsafe { BNAnalysisMergeConflictSuccess( self.handle.as_ptr(), @@ -135,8 +135,8 @@ impl MergeConflict { } // TODO: Make a safe version of this that checks the path and if it holds a number - pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { - let path_key = path_key.into_bytes_with_nul(); + pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { + let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItem( self.handle.as_ptr(), @@ -150,8 +150,8 @@ impl MergeConflict { } } - pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { - let path_key = path_key.into_bytes_with_nul(); + pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { + let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItemString( self.handle.as_ptr(), diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index b3c6513d86..8c04080b23 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -15,7 +15,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct RemoteProject { @@ -136,8 +136,8 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: S) -> Result<(), ()> { + let name = name.to_cstr(); let success = unsafe { BNRemoteProjectSetName( self.handle.as_ptr(), @@ -155,8 +155,8 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { - let description = description.into_bytes_with_nul(); + pub fn set_description(&self, description: S) -> Result<(), ()> { + let description = description.to_cstr(); let success = unsafe { BNRemoteProjectSetDescription( self.handle.as_ptr(), @@ -230,12 +230,12 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_id(&self, id: S) -> Result>, ()> { + pub fn get_file_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let result = unsafe { BNRemoteProjectGetFileById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; @@ -246,15 +246,12 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_name( - &self, - name: S, - ) -> Result>, ()> { + pub fn get_file_by_name(&self, name: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; } - let id = name.into_bytes_with_nul(); + let id = name.to_cstr(); let result = unsafe { BNRemoteProjectGetFileByName( self.handle.as_ptr(), @@ -311,9 +308,9 @@ impl RemoteProject { file_type: RemoteFileType, ) -> Result, ()> where - F: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, + F: AsCStr, + N: AsCStr, + D: AsCStr, { self.create_file_with_progress( filename, @@ -348,17 +345,17 @@ impl RemoteProject { mut progress: P, ) -> Result, ()> where - F: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, + F: AsCStr, + N: AsCStr, + D: AsCStr, P: ProgressCallback, { // TODO: This sync should be removed? self.open()?; - let filename = filename.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); - let description = description.into_bytes_with_nul(); + let filename = filename.to_cstr(); + let name = name.to_cstr(); + let description = description.to_cstr(); let folder_handle = parent_folder.map_or(std::ptr::null_mut(), |f| f.handle.as_ptr()); let file_ptr = unsafe { BNRemoteProjectCreateFile( @@ -386,15 +383,15 @@ impl RemoteProject { pub fn push_file(&self, file: &RemoteFile, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { // TODO: This sync should be removed? self.open()?; let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw = keys .iter() @@ -446,15 +443,12 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If folders have not been pulled, they will be pulled upon calling this. - pub fn get_folder_by_id( - &self, - id: S, - ) -> Result>, ()> { + pub fn get_folder_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_folders() { self.pull_folders()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let result = unsafe { BNRemoteProjectGetFolderById( self.handle.as_ptr(), @@ -505,8 +499,8 @@ impl RemoteProject { parent_folder: Option<&RemoteFolder>, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, + N: AsCStr, + D: AsCStr, { self.create_folder_with_progress(name, description, parent_folder, NoProgressCallback) } @@ -527,15 +521,15 @@ impl RemoteProject { mut progress: P, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, + N: AsCStr, + D: AsCStr, P: ProgressCallback, { // TODO: This sync should be removed? self.open()?; - let name = name.into_bytes_with_nul(); - let description = description.into_bytes_with_nul(); + let name = name.to_cstr(); + let description = description.to_cstr(); let folder_handle = parent_folder.map_or(std::ptr::null_mut(), |f| f.handle.as_ptr()); let file_ptr = unsafe { BNRemoteProjectCreateFolder( @@ -562,15 +556,15 @@ impl RemoteProject { pub fn push_folder(&self, folder: &RemoteFolder, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { // TODO: This sync should be removed? self.open()?; let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw = keys .iter() @@ -637,10 +631,7 @@ impl RemoteProject { /// Get a specific permission in the Project by its id. /// /// NOTE: If group or user permissions have not been pulled, they will be pulled upon calling this. - pub fn get_permission_by_id( - &self, - id: S, - ) -> Result>, ()> { + pub fn get_permission_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_user_permissions() { self.pull_user_permissions()?; @@ -650,7 +641,7 @@ impl RemoteProject { self.pull_group_permissions()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let value = unsafe { BNRemoteProjectGetPermissionById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const _) }; @@ -745,7 +736,7 @@ impl RemoteProject { /// /// * `user_id` - User id /// * `level` - Permission level - pub fn create_user_permission( + pub fn create_user_permission( &self, user_id: S, level: CollaborationPermissionLevel, @@ -760,13 +751,13 @@ impl RemoteProject { /// * `user_id` - User id /// * `level` - Permission level /// * `progress` - The progress callback to call - pub fn create_user_permission_with_progress( + pub fn create_user_permission_with_progress( &self, user_id: S, level: CollaborationPermissionLevel, mut progress: F, ) -> Result, ()> { - let user_id = user_id.into_bytes_with_nul(); + let user_id = user_id.to_cstr(); let value = unsafe { BNRemoteProjectCreateUserPermission( self.handle.as_ptr(), @@ -795,12 +786,12 @@ impl RemoteProject { ) -> Result<(), ()> where I: Iterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw = keys .iter() @@ -836,8 +827,8 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_view(&self, username: S) -> bool { - let username = username.into_bytes_with_nul(); + pub fn can_user_view(&self, username: S) -> bool { + let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserView( self.handle.as_ptr(), @@ -851,8 +842,8 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_edit(&self, username: S) -> bool { - let username = username.into_bytes_with_nul(); + pub fn can_user_edit(&self, username: S) -> bool { + let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserEdit( self.handle.as_ptr(), @@ -866,8 +857,8 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_admin(&self, username: S) -> bool { - let username = username.into_bytes_with_nul(); + pub fn can_user_admin(&self, username: S) -> bool { + let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserAdmin( self.handle.as_ptr(), diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index 98784ddbbd..3a1f021cfb 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -10,7 +10,7 @@ use crate::enterprise; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct Remote { @@ -27,9 +27,9 @@ impl Remote { } /// Create a Remote and add it to the list of known remotes (saved to Settings) - pub fn new(name: N, address: A) -> Ref { - let name = name.into_bytes_with_nul(); - let address = address.into_bytes_with_nul(); + pub fn new(name: N, address: A) -> Ref { + let name = name.to_cstr(); + let address = address.to_cstr(); let result = unsafe { BNCollaborationCreateRemote( name.as_ref().as_ptr() as *const c_char, @@ -168,13 +168,13 @@ impl Remote { } /// Requests an authentication token using a username and password. - pub fn request_authentication_token( + pub fn request_authentication_token( &self, username: U, password: P, ) -> Option { - let username = username.into_bytes_with_nul(); - let password = password.into_bytes_with_nul(); + let username = username.to_cstr(); + let password = password.to_cstr(); let token = unsafe { BNRemoteRequestAuthenticationToken( self.handle.as_ptr(), @@ -229,9 +229,9 @@ impl Remote { token.unwrap().to_string() } }; - let username = options.username.into_bytes_with_nul(); + let username = options.username.to_cstr(); let username_ptr = username.as_ptr() as *const c_char; - let token = token.into_bytes_with_nul(); + let token = token.to_cstr(); let token_ptr = token.as_ptr() as *const c_char; let success = unsafe { BNRemoteConnect(self.handle.as_ptr(), username_ptr, token_ptr) }; success.then_some(()).ok_or(()) @@ -281,15 +281,12 @@ impl Remote { /// Gets a specific project in the Remote by its id. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_id( - &self, - id: S, - ) -> Result>, ()> { + pub fn get_project_by_id(&self, id: S) -> Result>, ()> { if !self.has_pulled_projects() { self.pull_projects()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let value = unsafe { BNRemoteGetProjectById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; @@ -299,7 +296,7 @@ impl Remote { /// Gets a specific project in the Remote by its name. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_name( + pub fn get_project_by_name( &self, name: S, ) -> Result>, ()> { @@ -307,7 +304,7 @@ impl Remote { self.pull_projects()?; } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let value = unsafe { BNRemoteGetProjectByName( self.handle.as_ptr(), @@ -347,7 +344,7 @@ impl Remote { /// /// * `name` - Project name /// * `description` - Project description - pub fn create_project( + pub fn create_project( &self, name: N, description: D, @@ -358,8 +355,8 @@ impl Remote { if !self.has_pulled_projects() { self.pull_projects()?; } - let name = name.into_bytes_with_nul(); - let description = description.into_bytes_with_nul(); + let name = name.to_cstr(); + let description = description.to_cstr(); let value = unsafe { BNRemoteCreateProject( self.handle.as_ptr(), @@ -403,12 +400,12 @@ impl Remote { pub fn push_project(&self, project: &RemoteProject, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw = keys .iter() @@ -472,15 +469,12 @@ impl Remote { /// /// If groups have not been pulled, they will be pulled upon calling this. /// This function is only available to accounts with admin status on the Remote. - pub fn get_group_by_name( - &self, - name: S, - ) -> Result>, ()> { + pub fn get_group_by_name(&self, name: S) -> Result>, ()> { if !self.has_pulled_groups() { self.pull_groups()?; } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let value = unsafe { BNRemoteGetGroupByName( self.handle.as_ptr(), @@ -496,11 +490,11 @@ impl Remote { /// # Arguments /// /// * `prefix` - Prefix of name for groups - pub fn search_groups( + pub fn search_groups( &self, prefix: S, ) -> Result<(Array, Array), ()> { - let prefix = prefix.into_bytes_with_nul(); + let prefix = prefix.to_cstr(); let mut count = 0; let mut group_ids = std::ptr::null_mut(); let mut group_names = std::ptr::null_mut(); @@ -560,15 +554,12 @@ impl Remote { /// * `usernames` - List of usernames of users in the group pub fn create_group(&self, name: N, usernames: I) -> Result, ()> where - N: BnStrCompatible, + N: AsCStr, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let name = name.into_bytes_with_nul(); - let usernames: Vec<_> = usernames - .into_iter() - .map(|s| s.into_bytes_with_nul()) - .collect(); + let name = name.to_cstr(); + let usernames: Vec<_> = usernames.into_iter().map(|s| s.to_cstr()).collect(); let mut username_ptrs: Vec<_> = usernames .iter() .map(|s| s.as_ref().as_ptr() as *const c_char) @@ -597,12 +588,12 @@ impl Remote { pub fn push_group(&self, group: &RemoteGroup, extra_fields: I) -> Result<(), ()> where I: IntoIterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw: Vec<_> = keys .iter() @@ -663,11 +654,11 @@ impl Remote { /// # Arguments /// /// * `id` - The identifier of the user to retrieve. - pub fn get_user_by_id(&self, id: S) -> Result>, ()> { + pub fn get_user_by_id(&self, id: S) -> Result>, ()> { if !self.has_pulled_users() { self.pull_users()?; } - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let value = unsafe { BNRemoteGetUserById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; @@ -683,14 +674,14 @@ impl Remote { /// # Arguments /// /// * `username` - The username of the user to retrieve. - pub fn get_user_by_username( + pub fn get_user_by_username( &self, username: S, ) -> Result>, ()> { if !self.has_pulled_users() { self.pull_users()?; } - let username = username.into_bytes_with_nul(); + let username = username.to_cstr(); let value = unsafe { BNRemoteGetUserByUsername( self.handle.as_ptr(), @@ -718,11 +709,11 @@ impl Remote { /// # Arguments /// /// * `prefix` - The prefix to search for in usernames. - pub fn search_users( + pub fn search_users( &self, prefix: S, ) -> Result<(Array, Array), ()> { - let prefix = prefix.into_bytes_with_nul(); + let prefix = prefix.to_cstr(); let mut count = 0; let mut user_ids = std::ptr::null_mut(); let mut usernames = std::ptr::null_mut(); @@ -783,7 +774,7 @@ impl Remote { /// # Arguments /// /// * Various details about the new user to be created. - pub fn create_user( + pub fn create_user( &self, username: U, email: E, @@ -792,9 +783,9 @@ impl Remote { group_ids: &[u64], user_permission_ids: &[u64], ) -> Result, ()> { - let username = username.into_bytes_with_nul(); - let email = email.into_bytes_with_nul(); - let password = password.into_bytes_with_nul(); + let username = username.to_cstr(); + let email = email.to_cstr(); + let password = password.to_cstr(); let value = unsafe { BNRemoteCreateUser( @@ -825,12 +816,12 @@ impl Remote { pub fn push_user(&self, user: &RemoteUser, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let mut keys_raw: Vec<_> = keys .iter() diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index 935b1c2fe2..465ae46a57 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -8,7 +8,7 @@ use crate::collaboration::undo::{RemoteUndoEntry, RemoteUndoEntryId}; use crate::database::snapshot::Snapshot; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; // TODO: RemoteSnapshotId ? @@ -226,12 +226,12 @@ impl RemoteSnapshot { } /// Create a new Undo Entry in this snapshot. - pub fn create_undo_entry( + pub fn create_undo_entry( &self, parent: Option, data: S, ) -> Result, ()> { - let data = data.into_bytes_with_nul(); + let data = data.to_cstr(); let value = unsafe { BNCollaborationSnapshotCreateUndoEntry( self.handle.as_ptr(), diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index 6fc85d31c7..4c1123362e 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -11,7 +11,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::rc::Ref; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::type_archive::{TypeArchive, TypeArchiveMergeConflict}; // TODO: PathBuf @@ -43,10 +43,7 @@ pub fn default_file_path(file: &RemoteFile) -> Result { /// /// * `file` - Remote File to download and open /// * `db_path` - File path for saved database -pub fn download_file( - file: &RemoteFile, - db_path: S, -) -> Result, ()> { +pub fn download_file(file: &RemoteFile, db_path: S) -> Result, ()> { download_file_with_progress(file, db_path, NoProgressCallback) } @@ -57,12 +54,12 @@ pub fn download_file( /// * `file` - Remote File to download and open /// * `db_path` - File path for saved database /// * `progress` - Function to call for progress updates -pub fn download_file_with_progress( +pub fn download_file_with_progress( file: &RemoteFile, db_path: S, mut progress: F, ) -> Result, ()> { - let db_path = db_path.into_bytes_with_nul(); + let db_path = db_path.to_cstr(); let result = unsafe { BNCollaborationDownloadFile( file.handle.as_ptr(), @@ -223,7 +220,7 @@ pub fn get_local_snapshot_for_remote( pub fn download_database(file: &RemoteFile, location: S, force: bool) -> Result<(), ()> where - S: BnStrCompatible, + S: AsCStr, { download_database_with_progress(file, location, force, NoProgressCallback) } @@ -235,10 +232,10 @@ pub fn download_database_with_progress( mut progress: F, ) -> Result<(), ()> where - S: BnStrCompatible, + S: AsCStr, F: ProgressCallback, { - let db_path = location.into_bytes_with_nul(); + let db_path = location.to_cstr(); let success = unsafe { BNCollaborationDownloadDatabaseForFile( file.handle.as_ptr(), @@ -478,12 +475,12 @@ pub fn get_snapshot_author( /// * `database` - Parent database /// * `snapshot` - Snapshot to edit /// * `author` - Target author -pub fn set_snapshot_author( +pub fn set_snapshot_author( database: &Database, snapshot: &Snapshot, author: S, ) -> Result<(), ()> { - let author = author.into_bytes_with_nul(); + let author = author.to_cstr(); let success = unsafe { BNCollaborationSetSnapshotAuthor( database.handle.as_ptr(), @@ -653,11 +650,11 @@ pub fn get_remote_file_for_local_type_archive(database: &TypeArchive) -> Option< } /// Get the remote snapshot associated with a local snapshot (if it exists) in a Type Archive -pub fn get_remote_snapshot_from_local_type_archive( +pub fn get_remote_snapshot_from_local_type_archive( type_archive: &TypeArchive, snapshot_id: S, ) -> Option> { - let snapshot_id = snapshot_id.into_bytes_with_nul(); + let snapshot_id = snapshot_id.to_cstr(); let value = unsafe { BNCollaborationGetRemoteSnapshotFromLocalTypeArchive( type_archive.handle.as_ptr(), @@ -682,11 +679,11 @@ pub fn get_local_snapshot_from_remote_type_archive( } /// Test if a snapshot is ignored from the archive -pub fn is_type_archive_snapshot_ignored( +pub fn is_type_archive_snapshot_ignored( type_archive: &TypeArchive, snapshot_id: S, ) -> bool { - let snapshot_id = snapshot_id.into_bytes_with_nul(); + let snapshot_id = snapshot_id.to_cstr(); unsafe { BNCollaborationIsTypeArchiveSnapshotIgnored( type_archive.handle.as_ptr(), @@ -697,7 +694,7 @@ pub fn is_type_archive_snapshot_ignored( /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive( +pub fn download_type_archive( file: &RemoteFile, location: S, ) -> Result>, ()> { @@ -706,13 +703,13 @@ pub fn download_type_archive( /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive_with_progress( +pub fn download_type_archive_with_progress( file: &RemoteFile, location: S, mut progress: F, ) -> Result>, ()> { let mut value = std::ptr::null_mut(); - let db_path = location.into_bytes_with_nul(); + let db_path = location.to_cstr(); let success = unsafe { BNCollaborationDownloadTypeArchive( file.handle.as_ptr(), diff --git a/rust/src/collaboration/user.rs b/rust/src/collaboration/user.rs index b08e9da408..43b4e854ec 100644 --- a/rust/src/collaboration/user.rs +++ b/rust/src/collaboration/user.rs @@ -4,7 +4,7 @@ use std::ffi::c_char; use std::ptr::NonNull; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; #[repr(transparent)] pub struct RemoteUser { @@ -49,8 +49,8 @@ impl RemoteUser { } /// Set user's username. You will need to push the user to update the Remote - pub fn set_username(&self, username: U) -> Result<(), ()> { - let username = username.into_bytes_with_nul(); + pub fn set_username(&self, username: U) -> Result<(), ()> { + let username = username.to_cstr(); let result = unsafe { BNCollaborationUserSetUsername( self.handle.as_ptr(), @@ -72,8 +72,8 @@ impl RemoteUser { } /// Set user's email. You will need to push the user to update the Remote - pub fn set_email(&self, email: U) -> Result<(), ()> { - let username = email.into_bytes_with_nul(); + pub fn set_email(&self, email: U) -> Result<(), ()> { + let username = email.to_cstr(); let result = unsafe { BNCollaborationUserSetEmail( self.handle.as_ptr(), diff --git a/rust/src/command.rs b/rust/src/command.rs index 48a911645b..0297d6cfa4 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -42,7 +42,7 @@ use std::os::raw::c_void; use crate::binary_view::BinaryView; use crate::function::Function; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; /// The trait required for generic commands. See [register_command] for example usage. pub trait Command: 'static + Sync { @@ -95,7 +95,7 @@ where /// ``` pub fn register_command(name: S, desc: S, command: C) where - S: BnStrCompatible, + S: AsCStr, C: Command, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView) @@ -126,8 +126,8 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); + let name = name.to_cstr(); + let desc = desc.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let desc_ptr = desc.as_ref().as_ptr() as *mut _; @@ -196,7 +196,7 @@ where /// ``` pub fn register_command_for_address(name: S, desc: S, command: C) where - S: BnStrCompatible, + S: AsCStr, C: AddressCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) @@ -227,8 +227,8 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); + let name = name.to_cstr(); + let desc = desc.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let desc_ptr = desc.as_ref().as_ptr() as *mut _; @@ -298,7 +298,7 @@ where /// ``` pub fn register_command_for_range(name: S, desc: S, command: C) where - S: BnStrCompatible, + S: AsCStr, C: RangeCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64) @@ -334,8 +334,8 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); + let name = name.to_cstr(); + let desc = desc.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let desc_ptr = desc.as_ref().as_ptr() as *mut _; @@ -405,7 +405,7 @@ where /// ``` pub fn register_command_for_function(name: S, desc: S, command: C) where - S: BnStrCompatible, + S: AsCStr, C: FunctionCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction) @@ -446,8 +446,8 @@ where }) } - let name = name.into_bytes_with_nul(); - let desc = desc.into_bytes_with_nul(); + let name = name.to_cstr(); + let desc = desc.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let desc_ptr = desc.as_ref().as_ptr() as *mut _; diff --git a/rust/src/component.rs b/rust/src/component.rs index 72441c528d..5fe44b64b9 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -1,7 +1,7 @@ use crate::binary_view::{BinaryView, BinaryViewExt}; use crate::function::Function; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::types::ComponentReferencedType; use std::ffi::c_char; use std::fmt::Debug; @@ -39,20 +39,20 @@ impl ComponentBuilder { let result = match (&self.parent, &self.name) { (None, None) => unsafe { BNCreateComponent(self.view.handle) }, (None, Some(name)) => { - let name_raw = name.into_bytes_with_nul(); + let name_raw = name.to_cstr(); unsafe { BNCreateComponentWithName(self.view.handle, name_raw.as_ptr() as *mut c_char) } } (Some(guid), None) => { - let guid_raw = guid.into_bytes_with_nul(); + let guid_raw = guid.to_cstr(); unsafe { BNCreateComponentWithParent(self.view.handle, guid_raw.as_ptr() as *mut c_char) } } (Some(guid), Some(name)) => { - let guid_raw = guid.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); + let guid_raw = guid.to_cstr(); + let name_raw = name.to_cstr(); unsafe { BNCreateComponentWithParentAndName( self.view.handle, @@ -164,8 +164,8 @@ impl Component { unsafe { BnString::into_string(result) } } - pub fn set_name(&self, name: S) { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: S) { + let name = name.to_cstr(); unsafe { BNComponentSetName( self.handle.as_ptr(), diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index de841a2631..adcde09d62 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -42,7 +42,7 @@ use crate::Endianness; /// implementation of the `CustomBinaryViewType` must return. pub fn register_view_type(name: S, long_name: S, constructor: F) -> &'static T where - S: BnStrCompatible, + S: AsCStr, T: CustomBinaryViewType, F: FnOnce(BinaryViewType) -> T, { @@ -149,10 +149,10 @@ where }) } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; - let long_name = long_name.into_bytes_with_nul(); + let long_name = long_name.to_cstr(); let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; let ctxt = Box::leak(Box::new(MaybeUninit::zeroed())); @@ -360,8 +360,8 @@ impl BinaryViewType { } /// Looks up a BinaryViewType by its short name - pub fn by_name(name: N) -> Result { - let bytes = name.into_bytes_with_nul(); + pub fn by_name(name: N) -> Result { + let bytes = name.to_cstr(); let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; match handle.is_null() { false => Ok(unsafe { BinaryViewType::from_raw(handle) }), diff --git a/rust/src/data_buffer.rs b/rust/src/data_buffer.rs index 460bb94d8c..a163d3464d 100644 --- a/rust/src/data_buffer.rs +++ b/rust/src/data_buffer.rs @@ -19,7 +19,7 @@ use binaryninjacore_sys::*; use std::ffi::c_void; use std::slice; -use crate::string::BnString; +use crate::string::{AsCStr, BnString}; pub struct DataBuffer(*mut BNDataBuffer); @@ -128,8 +128,9 @@ impl DataBuffer { unsafe { BnString::into_string(BNDataBufferToBase64(self.0)) } } - pub fn from_base64(value: &BnString) -> Self { - Self(unsafe { BNDecodeBase64(value.as_ptr()) }) + pub fn from_base64(value: &str) -> Self { + let t = value.to_cstr(); + Self(unsafe { BNDecodeBase64(t.as_ptr()) }) } pub fn zlib_compress(&self) -> Self { diff --git a/rust/src/database.rs b/rust/src/database.rs index 7174ebe8ff..fd20d1730e 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -15,7 +15,7 @@ use crate::database::snapshot::{Snapshot, SnapshotId}; use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub struct Database { pub(crate) handle: NonNull, @@ -62,7 +62,7 @@ impl Database { unsafe { BNSetDatabaseCurrentSnapshot(self.handle.as_ptr(), id.0) } } - pub fn write_snapshot_data( + pub fn write_snapshot_data( &self, parents: &[SnapshotId], file: &BinaryView, @@ -90,10 +90,10 @@ impl Database { mut progress: P, ) -> SnapshotId where - N: BnStrCompatible, + N: AsCStr, P: ProgressCallback, { - let name_raw = name.into_bytes_with_nul(); + let name_raw = name.to_cstr(); let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; let new_id = unsafe { @@ -133,8 +133,8 @@ impl Database { Err(()) } } - pub fn has_global(&self, key: S) -> bool { - let key_raw = key.into_bytes_with_nul(); + pub fn has_global(&self, key: S) -> bool { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_ptr) != 0 } } @@ -156,33 +156,33 @@ impl Database { } /// Get a specific global by key - pub fn read_global(&self, key: S) -> Option { - let key_raw = key.into_bytes_with_nul(); + pub fn read_global(&self, key: S) -> Option { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_ptr) }; unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database - pub fn write_global(&self, key: K, value: V) -> bool { - let key_raw = key.into_bytes_with_nul(); + pub fn write_global(&self, key: K, value: V) -> bool { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; - let value_raw = value.into_bytes_with_nul(); + let value_raw = value.to_cstr(); let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_ptr, value_ptr) } } /// Get a specific global by key, as a binary buffer - pub fn read_global_data(&self, key: S) -> Option { - let key_raw = key.into_bytes_with_nul(); + pub fn read_global_data(&self, key: S) -> Option { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_ptr) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database - pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { - let key_raw = key.into_bytes_with_nul(); + pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_ptr, value.as_raw()) } } diff --git a/rust/src/database/kvs.rs b/rust/src/database/kvs.rs index 4b77bbdbf8..43cf17ebda 100644 --- a/rust/src/database/kvs.rs +++ b/rust/src/database/kvs.rs @@ -1,6 +1,6 @@ use crate::data_buffer::DataBuffer; use crate::rc::{Array, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::{ BNBeginKeyValueStoreNamespace, BNEndKeyValueStoreNamespace, BNFreeKeyValueStore, BNGetKeyValueStoreBuffer, BNGetKeyValueStoreDataSize, BNGetKeyValueStoreKeys, @@ -42,16 +42,16 @@ impl KeyValueStore { } /// Get the value for a single key - pub fn value(&self, key: S) -> Option { - let key_raw = key.into_bytes_with_nul(); + pub fn value(&self, key: S) -> Option { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNGetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Set the value for a single key - pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { - let key_raw = key.into_bytes_with_nul(); + pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { + let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; unsafe { BNSetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr, value.as_raw()) } } @@ -64,8 +64,8 @@ impl KeyValueStore { } /// Begin storing new keys into a namespace - pub fn begin_namespace(&self, name: S) { - let name_raw = name.into_bytes_with_nul(); + pub fn begin_namespace(&self, name: S) { + let name_raw = name.to_cstr(); let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; unsafe { BNBeginKeyValueStoreNamespace(self.handle.as_ptr(), name_ptr) } } diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs index 3768138c11..7d7e39d198 100644 --- a/rust/src/database/snapshot.rs +++ b/rust/src/database/snapshot.rs @@ -4,7 +4,7 @@ use crate::database::undo::UndoEntry; use crate::database::Database; use crate::progress::ProgressCallback; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::{ BNCollaborationFreeSnapshotIdList, BNFreeSnapshot, BNFreeSnapshotList, BNGetSnapshotChildren, BNGetSnapshotDatabase, BNGetSnapshotFileContents, BNGetSnapshotFileContentsHash, @@ -50,8 +50,8 @@ impl Snapshot { } /// Set the displayed snapshot name - pub fn set_name(&self, value: S) { - let value_raw = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) { + let value_raw = value.to_cstr(); let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; unsafe { BNSetSnapshotName(self.handle.as_ptr(), value_ptr) } } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index c4bc7addf3..0afe4c77e5 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -83,7 +83,7 @@ use crate::{ binary_view::BinaryView, platform::Platform, rc::*, - string::{raw_to_string, BnStrCompatible, BnString}, + string::{raw_to_string, AsCStr, BnString}, types::{NameAndType, Type}, }; @@ -115,8 +115,8 @@ impl DebugInfoParser { } /// Returns debug info parser of the given name, if it exists - pub fn from_name(name: S) -> Result, ()> { - let name = name.into_bytes_with_nul(); + pub fn from_name(name: S) -> Result, ()> { + let name = name.to_cstr(); let parser = unsafe { BNGetDebugInfoParserByName(name.as_ref().as_ptr() as *mut _) }; if parser.is_null() { @@ -209,7 +209,7 @@ impl DebugInfoParser { // Registers a DebugInfoParser. See `binaryninja::debuginfo::DebugInfoParser` for more details. pub fn register(name: S, parser_callbacks: C) -> Ref where - S: BnStrCompatible, + S: AsCStr, C: CustomDebugInfoParser, { extern "C" fn cb_is_valid(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool @@ -259,7 +259,7 @@ impl DebugInfoParser { }) } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let ctxt = Box::into_raw(Box::new(parser_callbacks)); @@ -417,8 +417,8 @@ impl DebugInfo { } /// Returns all types within the parser - pub fn types_by_name(&self, parser_name: S) -> Vec { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn types_by_name(&self, parser_name: S) -> Vec { + let parser_name = parser_name.to_cstr(); let mut count: usize = 0; let debug_types_ptr = unsafe { @@ -455,8 +455,8 @@ impl DebugInfo { } /// Returns all functions within the parser - pub fn functions_by_name(&self, parser_name: S) -> Vec { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn functions_by_name(&self, parser_name: S) -> Vec { + let parser_name = parser_name.to_cstr(); let mut count: usize = 0; let functions_ptr = unsafe { @@ -495,11 +495,11 @@ impl DebugInfo { } /// Returns all data variables within the parser - pub fn data_variables_by_name( + pub fn data_variables_by_name( &self, parser_name: S, ) -> Vec { - let parser_name = parser_name.into_bytes_with_nul(); + let parser_name = parser_name.to_cstr(); let mut count: usize = 0; let data_variables_ptr = unsafe { @@ -537,9 +537,9 @@ impl DebugInfo { result } - pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); + pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { + let parser_name = parser_name.to_cstr(); + let name = name.to_cstr(); let result = unsafe { BNGetDebugTypeByName( @@ -555,13 +555,13 @@ impl DebugInfo { } } - pub fn get_data_variable_by_name( + pub fn get_data_variable_by_name( &self, parser_name: S, name: S, ) -> Option { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); + let parser_name = parser_name.to_cstr(); + let name = name.to_cstr(); let mut dv = BNDataVariableAndName::default(); unsafe { if BNGetDebugDataVariableByName( @@ -577,12 +577,12 @@ impl DebugInfo { } } - pub fn get_data_variable_by_address( + pub fn get_data_variable_by_address( &self, parser_name: S, address: u64, ) -> Option { - let parser_name = parser_name.into_bytes_with_nul(); + let parser_name = parser_name.to_cstr(); let mut dv = BNDataVariableAndName::default(); unsafe { if BNGetDebugDataVariableByAddress( @@ -599,9 +599,9 @@ impl DebugInfo { } /// Returns a list of [`NameAndType`] where the `name` is the parser the type originates from. - pub fn get_types_by_name(&self, name: S) -> Vec { + pub fn get_types_by_name(&self, name: S) -> Vec { let mut count: usize = 0; - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let raw_names_and_types_ptr = unsafe { BNGetDebugTypesByName(self.handle, name.as_ref().as_ptr() as *mut _, &mut count) }; @@ -619,11 +619,8 @@ impl DebugInfo { } // The tuple is (DebugInfoParserName, address, type) - pub fn get_data_variables_by_name( - &self, - name: S, - ) -> Vec<(String, u64, Ref)> { - let name = name.into_bytes_with_nul(); + pub fn get_data_variables_by_name(&self, name: S) -> Vec<(String, u64, Ref)> { + let name = name.to_cstr(); let mut count: usize = 0; let raw_variables_and_names = unsafe { @@ -674,37 +671,37 @@ impl DebugInfo { result } - pub fn remove_parser_info(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_parser_info(&self, parser_name: S) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ref().as_ptr() as *mut _) } } - pub fn remove_parser_types(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_parser_types(&self, parser_name: S) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ref().as_ptr() as *mut _) } } - pub fn remove_parser_functions(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_parser_functions(&self, parser_name: S) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ref().as_ptr() as *mut _) } } - pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ref().as_ptr() as *mut _) } } - pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); - let name = name.into_bytes_with_nul(); + pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { + let parser_name = parser_name.to_cstr(); + let name = name.to_cstr(); unsafe { BNRemoveDebugTypeByName( @@ -715,12 +712,8 @@ impl DebugInfo { } } - pub fn remove_function_by_index( - &self, - parser_name: S, - index: usize, - ) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_function_by_index(&self, parser_name: S, index: usize) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugFunctionByIndex( @@ -731,12 +724,8 @@ impl DebugInfo { } } - pub fn remove_data_variable_by_address( - &self, - parser_name: S, - address: u64, - ) -> bool { - let parser_name = parser_name.into_bytes_with_nul(); + pub fn remove_data_variable_by_address(&self, parser_name: S, address: u64) -> bool { + let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugDataVariableByAddress( @@ -748,16 +737,11 @@ impl DebugInfo { } /// Adds a type scoped under the current parser's name to the debug info - pub fn add_type( - &self, - name: S, - new_type: &Type, - components: &[&str], - ) -> bool { + pub fn add_type(&self, name: S, new_type: &Type, components: &[&str]) -> bool { // SAFETY: Lifetime of `components` will live long enough, so passing as_ptr is safe. let raw_components: Vec<_> = components.iter().map(|&c| c.as_ptr()).collect(); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNAddDebugType( self.handle, @@ -771,24 +755,15 @@ impl DebugInfo { /// Adds a function scoped under the current parser's name to the debug info pub fn add_function(&self, new_func: &DebugFunctionInfo) -> bool { - let short_name_bytes = new_func - .short_name - .as_ref() - .map(|name| name.into_bytes_with_nul()); + let short_name_bytes = new_func.short_name.as_ref().map(|name| name.to_cstr()); let short_name = short_name_bytes .as_ref() .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _); - let full_name_bytes = new_func - .full_name - .as_ref() - .map(|name| name.into_bytes_with_nul()); + let full_name_bytes = new_func.full_name.as_ref().map(|name| name.to_cstr()); let full_name = full_name_bytes .as_ref() .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _); - let raw_name_bytes = new_func - .raw_name - .as_ref() - .map(|name| name.into_bytes_with_nul()); + let raw_name_bytes = new_func.raw_name.as_ref().map(|name| name.to_cstr()); let raw_name = raw_name_bytes .as_ref() .map_or(std::ptr::null_mut() as *mut _, |name| name.as_ptr() as _); @@ -801,9 +776,7 @@ impl DebugInfo { unsafe { for component in &new_func.components { - components_array.push(BNAllocString( - component.clone().into_bytes_with_nul().as_ptr() as _, - )); + components_array.push(BNAllocString(component.clone().to_cstr().as_ptr() as _)); } for local_variable in &new_func.local_variables { @@ -845,7 +818,7 @@ impl DebugInfo { } /// Adds a data variable scoped under the current parser's name to the debug info - pub fn add_data_variable( + pub fn add_data_variable( &self, address: u64, t: &Type, @@ -860,7 +833,7 @@ impl DebugInfo { match name { Some(name) => { - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNAddDebugDataVariable( self.handle, diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index bfe65f9af3..9cec0c9329 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -19,20 +19,20 @@ use std::ffi::{c_char, c_void}; use crate::architecture::CoreArchitecture; use crate::binary_view::BinaryView; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::types::{QualifiedName, Type}; use crate::rc::*; pub type Result = std::result::Result; -pub fn demangle_generic( +pub fn demangle_generic( arch: &CoreArchitecture, mangled_name: S, view: Option<&BinaryView>, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); + let mangled_name_bwn = mangled_name.to_cstr(); let mangled_name_ptr = mangled_name_bwn.as_ref(); let mut out_type: *mut BNType = std::ptr::null_mut(); let mut out_name = BNQualifiedName::default(); @@ -58,8 +58,8 @@ pub fn demangle_generic( } } -pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); +pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { + let mangled_name_bwn = mangled_name.to_cstr(); let mangled_name_ptr = mangled_name_bwn.as_ref(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; @@ -87,12 +87,12 @@ pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Opt } } -pub fn demangle_gnu3( +pub fn demangle_gnu3( arch: &CoreArchitecture, mangled_name: S, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); + let mangled_name_bwn = mangled_name.to_cstr(); let mangled_name_ptr = mangled_name_bwn.as_ref(); let mut out_type: *mut BNType = std::ptr::null_mut(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); @@ -128,12 +128,12 @@ pub fn demangle_gnu3( } } -pub fn demangle_ms( +pub fn demangle_ms( arch: &CoreArchitecture, mangled_name: S, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.into_bytes_with_nul(); + let mangled_name_bwn = mangled_name.to_cstr(); let mangled_name_ptr = mangled_name_bwn.as_ref(); let mut out_type: *mut BNType = std::ptr::null_mut(); @@ -187,18 +187,18 @@ impl Demangler { unsafe { Array::::new(demanglers, count, ()) } } - pub fn is_mangled_string(&self, name: S) -> bool { - let bytes = name.into_bytes_with_nul(); + pub fn is_mangled_string(&self, name: S) -> bool { + let bytes = name.to_cstr(); unsafe { BNIsDemanglerMangledName(self.handle, bytes.as_ref().as_ptr() as *const _) } } - pub fn demangle( + pub fn demangle( &self, arch: &CoreArchitecture, name: S, view: Option<&BinaryView>, ) -> Option<(QualifiedName, Option>)> { - let name_bytes = name.into_bytes_with_nul(); + let name_bytes = name.to_cstr(); let mut out_type = std::ptr::null_mut(); let mut out_var_name = BNQualifiedName::default(); @@ -236,8 +236,8 @@ impl Demangler { unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) } } - pub fn from_name(name: S) -> Option { - let name_bytes = name.into_bytes_with_nul(); + pub fn from_name(name: S) -> Option { + let name_bytes = name.to_cstr(); let demangler = unsafe { BNGetDemanglerByName(name_bytes.as_ref().as_ptr() as *const _) }; if demangler.is_null() { None @@ -248,7 +248,7 @@ impl Demangler { pub fn register(name: S, demangler: C) -> Self where - S: BnStrCompatible, + S: AsCStr, C: CustomDemangler, { extern "C" fn cb_is_mangled_string(ctxt: *mut c_void, name: *const c_char) -> bool @@ -308,7 +308,7 @@ impl Demangler { }) } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let name_ptr = name.as_ref().as_ptr() as *mut _; let ctxt = Box::into_raw(Box::new(demangler)); diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 6125f62383..5964324d82 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -22,7 +22,7 @@ use crate::function::{Location, NativeBlock}; use crate::high_level_il as hlil; use crate::low_level_il as llil; use crate::medium_level_il as mlil; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use crate::string::{raw_to_string, strings_to_string_list, BnString}; use crate::rc::*; @@ -1242,7 +1242,7 @@ impl DisassemblyTextRenderer { unsafe { Array::new(tokens, count, ()) } } - pub fn wrap_comment( + pub fn wrap_comment( &self, cur_line: DisassemblyTextLine, comment: S1, @@ -1251,9 +1251,9 @@ impl DisassemblyTextRenderer { indent_spaces: S3, ) -> Array { let cur_line_raw = DisassemblyTextLine::into_raw(cur_line); - let comment_raw = comment.into_bytes_with_nul(); - let leading_spaces_raw = leading_spaces.into_bytes_with_nul(); - let indent_spaces_raw = indent_spaces.into_bytes_with_nul(); + let comment_raw = comment.to_cstr(); + let leading_spaces_raw = leading_spaces.to_cstr(); + let indent_spaces_raw = indent_spaces.to_cstr(); let mut count = 0; let lines = unsafe { BNDisassemblyTextRendererWrapComment( diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index 4b7b3c0ce9..f9e21e64e3 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -1,6 +1,6 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::settings::Settings; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::ffi::{c_void, CStr}; @@ -13,11 +13,9 @@ pub struct DownloadProvider { } impl DownloadProvider { - pub fn get(name: S) -> Option { + pub fn get(name: S) -> Option { let result = unsafe { - BNGetDownloadProviderByName( - name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char - ) + BNGetDownloadProviderByName(name.to_cstr().as_ref().as_ptr() as *const c_char) }; if result.is_null() { return None; @@ -134,7 +132,7 @@ impl DownloadInstance { } } - pub fn perform_request( + pub fn perform_request( &mut self, url: S, callbacks: DownloadInstanceOutputCallbacks, @@ -150,7 +148,7 @@ impl DownloadInstance { let result = unsafe { BNPerformDownloadRequest( self.handle, - url.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + url.to_cstr().as_ref().as_ptr() as *const c_char, &mut cbs as *mut BNDownloadInstanceOutputCallbacks, ) }; @@ -204,10 +202,10 @@ impl DownloadInstance { } pub fn perform_custom_request< - M: BnStrCompatible, - U: BnStrCompatible, - HK: BnStrCompatible, - HV: BnStrCompatible, + M: AsCStr, + U: AsCStr, + HK: AsCStr, + HV: AsCStr, I: IntoIterator, >( &mut self, @@ -219,8 +217,8 @@ impl DownloadInstance { let mut header_keys = vec![]; let mut header_values = vec![]; for (key, value) in headers { - header_keys.push(key.into_bytes_with_nul()); - header_values.push(value.into_bytes_with_nul()); + header_keys.push(key.to_cstr()); + header_values.push(value.to_cstr()); } let mut header_key_ptrs = vec![]; @@ -246,8 +244,8 @@ impl DownloadInstance { let result = unsafe { BNPerformCustomRequest( self.handle, - method.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - url.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + method.to_cstr().as_ref().as_ptr() as *const c_char, + url.to_cstr().as_ref().as_ptr() as *const c_char, header_key_ptrs.len() as u64, header_key_ptrs.as_ptr(), header_value_ptrs.as_ptr(), diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index d09ac3333d..74389d4563 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -1,5 +1,5 @@ use crate::rc::Array; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use std::ffi::c_void; use std::marker::PhantomData; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -120,8 +120,8 @@ pub fn server_url() -> String { unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } } -pub fn set_server_url(url: S) -> Result<(), ()> { - let url = url.into_bytes_with_nul(); +pub fn set_server_url(url: S) -> Result<(), ()> { + let url = url.to_cstr(); let result = unsafe { binaryninjacore_sys::BNSetEnterpriseServerUrl( url.as_ref().as_ptr() as *const std::os::raw::c_char @@ -185,11 +185,11 @@ pub fn is_server_license_still_activated() -> bool { pub fn authenticate_server_with_credentials(username: U, password: P, remember: bool) -> bool where - U: BnStrCompatible, - P: BnStrCompatible, + U: AsCStr, + P: AsCStr, { - let username = username.into_bytes_with_nul(); - let password = password.into_bytes_with_nul(); + let username = username.to_cstr(); + let password = password.to_cstr(); unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithCredentials( username.as_ref().as_ptr() as *const std::os::raw::c_char, @@ -199,8 +199,8 @@ where } } -pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { - let method = method.into_bytes_with_nul(); +pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { + let method = method.to_cstr(); unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithMethod( method.as_ref().as_ptr() as *const std::os::raw::c_char, diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs index 5360f29d0e..26425ccd74 100644 --- a/rust/src/external_library.rs +++ b/rust/src/external_library.rs @@ -1,6 +1,6 @@ use crate::project::file::ProjectFile; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::symbol::Symbol; use binaryninjacore_sys::*; use std::ffi::c_char; @@ -167,9 +167,9 @@ impl ExternalLocation { /// Set the symbol pointed to by this ExternalLocation. /// ExternalLocations must have a valid target address and/or symbol set. - pub fn set_target_symbol(&self, symbol: Option) -> bool { + pub fn set_target_symbol(&self, symbol: Option) -> bool { let symbol = symbol - .map(|x| x.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) + .map(|x| x.to_cstr().as_ref().as_ptr() as *const c_char) .unwrap_or(std::ptr::null_mut()); unsafe { BNExternalLocationSetTargetSymbol(self.handle.as_ptr(), symbol) } } diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index c14aaf2999..6b6a79a8b8 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -52,7 +52,7 @@ impl FileMetadata { Self::ref_from_raw(unsafe { BNCreateFileMetadata() }) } - pub fn with_filename(name: S) -> Ref { + pub fn with_filename(name: S) -> Ref { let ret = FileMetadata::new(); ret.set_filename(name); ret @@ -75,8 +75,8 @@ impl FileMetadata { } } - pub fn set_filename(&self, name: S) { - let name = name.into_bytes_with_nul(); + pub fn set_filename(&self, name: S) { + let name = name.to_cstr(); unsafe { BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _); @@ -107,8 +107,8 @@ impl FileMetadata { self.is_database_backed_for_view_type("") } - pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { - let view_type = view_type.into_bytes_with_nul(); + pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { + let view_type = view_type.to_cstr(); unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } } @@ -135,15 +135,15 @@ impl FileMetadata { unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } - pub fn commit_undo_actions(&self, id: S) { - let id = id.into_bytes_with_nul(); + pub fn commit_undo_actions(&self, id: S) { + let id = id.to_cstr(); unsafe { BNCommitUndoActions(self.handle, id.as_ref().as_ptr() as *const _); } } - pub fn revert_undo_actions(&self, id: S) { - let id = id.into_bytes_with_nul(); + pub fn revert_undo_actions(&self, id: S) { + let id = id.to_cstr(); unsafe { BNRevertUndoActions(self.handle, id.as_ref().as_ptr() as *const _); } @@ -169,8 +169,8 @@ impl FileMetadata { unsafe { BNGetCurrentOffset(self.handle) } } - pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { - let view = view.into_bytes_with_nul(); + pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { + let view = view.to_cstr(); unsafe { if BNNavigate(self.handle, view.as_ref().as_ptr() as *const _, offset) { @@ -181,8 +181,8 @@ impl FileMetadata { } } - pub fn view_of_type(&self, view: S) -> Option> { - let view = view.into_bytes_with_nul(); + pub fn view_of_type(&self, view: S) -> Option> { + let view = view.to_cstr(); unsafe { let raw_view_ptr = BNGetFileViewOfType(self.handle, view.as_ref().as_ptr() as *const _); @@ -215,7 +215,7 @@ impl FileMetadata { return false; }; - let file_path = file_path.as_ref().into_bytes_with_nul(); + let file_path = file_path.as_ref().to_cstr(); unsafe { BNCreateDatabase( raw_view.handle, @@ -226,7 +226,7 @@ impl FileMetadata { } // TODO: Pass settings? - pub fn create_database_with_progress( + pub fn create_database_with_progress( &self, file_path: impl AsRef, mut progress: P, @@ -235,7 +235,7 @@ impl FileMetadata { let Some(raw_view) = self.view_of_type("Raw") else { return false; }; - let file_path = file_path.as_ref().into_bytes_with_nul(); + let file_path = file_path.as_ref().to_cstr(); unsafe { BNCreateDatabaseWithProgress( raw_view.handle, @@ -256,11 +256,11 @@ impl FileMetadata { unsafe { BNSaveAutoSnapshot(raw_view.handle, ptr::null_mut() as *mut _) } } - pub fn open_database_for_configuration( + pub fn open_database_for_configuration( &self, filename: S, ) -> Result, ()> { - let filename = filename.into_bytes_with_nul(); + let filename = filename.to_cstr(); unsafe { let bv = BNOpenDatabaseForConfiguration(self.handle, filename.as_ref().as_ptr() as *const _); @@ -273,8 +273,8 @@ impl FileMetadata { } } - pub fn open_database(&self, filename: S) -> Result, ()> { - let filename = filename.into_bytes_with_nul(); + pub fn open_database(&self, filename: S) -> Result, ()> { + let filename = filename.to_cstr(); let filename_ptr = filename.as_ref().as_ptr() as *mut _; let view = unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }; @@ -286,12 +286,12 @@ impl FileMetadata { } } - pub fn open_database_with_progress( + pub fn open_database_with_progress( &self, filename: S, mut progress: P, ) -> Result, ()> { - let filename = filename.into_bytes_with_nul(); + let filename = filename.to_cstr(); let filename_ptr = filename.as_ref().as_ptr() as *mut _; let view = unsafe { diff --git a/rust/src/function.rs b/rust/src/function.rs index 50753d7476..dcefaa3513 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -372,8 +372,8 @@ impl Function { unsafe { BnString::into_string(BNGetFunctionComment(self.handle)) } } - pub fn set_comment(&self, comment: S) { - let raw = comment.into_bytes_with_nul(); + pub fn set_comment(&self, comment: S) { + let raw = comment.to_cstr(); unsafe { BNSetFunctionComment(self.handle, raw.as_ref().as_ptr() as *mut _); @@ -394,8 +394,8 @@ impl Function { unsafe { BnString::into_string(BNGetCommentForAddress(self.handle, addr)) } } - pub fn set_comment_at(&self, addr: u64, comment: S) { - let raw = comment.into_bytes_with_nul(); + pub fn set_comment_at(&self, addr: u64, comment: S) { + let raw = comment.to_cstr(); unsafe { BNSetCommentForAddress(self.handle, addr, raw.as_ref().as_ptr() as *mut _); @@ -1103,7 +1103,7 @@ impl Function { /// let crash = bv.create_tag_type("Crashes", "🎯"); /// fun.add_tag(&crash, "Nullpointer dereference", Some(0x1337), false, None); /// ``` - pub fn add_tag( + pub fn add_tag( &self, tag_type: &TagType, data: S, @@ -1707,10 +1707,10 @@ impl Function { operand: usize, display_type: IntegerDisplayType, arch: Option, - enum_display_typeid: Option, + enum_display_typeid: Option, ) { let arch = arch.unwrap_or_else(|| self.arch()); - let enum_display_typeid = enum_display_typeid.map(BnStrCompatible::into_bytes_with_nul); + let enum_display_typeid = enum_display_typeid.map(AsCStr::to_cstr); let enum_display_typeid_ptr = enum_display_typeid .map(|x| x.as_ref().as_ptr() as *const c_char) .unwrap_or(std::ptr::null()); diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs index c5733a4336..302a6d737e 100644 --- a/rust/src/high_level_il/operation.rs +++ b/rust/src/high_level_il/operation.rs @@ -6,7 +6,7 @@ use super::HighLevelILLiftedInstruction; use crate::architecture::CoreIntrinsic; use crate::function::Function; use crate::rc::Ref; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::variable::{ConstantData, SSAVariable, Variable}; #[derive(Clone, PartialEq, Eq)] @@ -20,8 +20,8 @@ impl GotoLabel { unsafe { BnString::into_string(BNGetGotoLabelName(self.function.handle, self.target)) } } - fn set_name(&self, name: S) { - let raw = name.into_bytes_with_nul(); + fn set_name(&self, name: S) { + let raw = name.to_cstr(); unsafe { BNSetUserGotoLabelName( self.function.handle, @@ -327,7 +327,7 @@ impl LiftedLabel { self.target.name() } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: S) { self.target.set_name(name) } } diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 23dcaf85c3..7e007eb983 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use crate::binary_view::BinaryView; use crate::rc::Ref; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub fn get_text_line_input(prompt: &str, title: &str) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); @@ -29,8 +29,8 @@ pub fn get_text_line_input(prompt: &str, title: &str) -> Option { let result = unsafe { BNGetTextLineInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, + prompt.to_cstr().as_ptr() as *mut _, + title.to_cstr().as_ptr() as *mut _, ) }; if !result { @@ -46,8 +46,8 @@ pub fn get_integer_input(prompt: &str, title: &str) -> Option { let result = unsafe { BNGetIntegerInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, + prompt.to_cstr().as_ptr() as *mut _, + title.to_cstr().as_ptr() as *mut _, ) }; @@ -64,8 +64,8 @@ pub fn get_address_input(prompt: &str, title: &str) -> Option { let result = unsafe { BNGetAddressInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - title.into_bytes_with_nul().as_ptr() as *mut _, + prompt.to_cstr().as_ptr() as *mut _, + title.to_cstr().as_ptr() as *mut _, std::ptr::null_mut(), 0, ) @@ -84,8 +84,8 @@ pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option let result = unsafe { BNGetOpenFileNameInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - extension.into_bytes_with_nul().as_ptr() as *mut _, + prompt.to_cstr().as_ptr() as *mut _, + extension.to_cstr().as_ptr() as *mut _, ) }; if !result { @@ -106,9 +106,9 @@ pub fn get_save_filename_input( let result = unsafe { BNGetSaveFileNameInput( &mut value, - prompt.into_bytes_with_nul().as_ptr() as *mut _, - extension.into_bytes_with_nul().as_ptr() as *mut _, - default_name.into_bytes_with_nul().as_ptr() as *mut _, + prompt.to_cstr().as_ptr() as *mut _, + extension.to_cstr().as_ptr() as *mut _, + default_name.to_cstr().as_ptr() as *mut _, ) }; if !result { @@ -125,8 +125,8 @@ pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option MessageBoxButtonResult { unsafe { BNShowMessageBox( - title.into_bytes_with_nul().as_ptr() as *mut _, - text.into_bytes_with_nul().as_ptr() as *mut _, + title.to_cstr().as_ptr() as *mut _, + text.to_cstr().as_ptr() as *mut _, buttons, icon, ) @@ -495,7 +495,7 @@ impl FormInputBuilder { BNGetFormInput( self.fields.as_mut_ptr(), self.fields.len(), - title.into_bytes_with_nul().as_ptr() as *const _, + title.to_cstr().as_ptr() as *const _, ) } { let result = self @@ -577,7 +577,7 @@ pub fn run_progress_dialog Result<(), ()>>)>( if unsafe { BNRunProgressDialog( - title.into_bytes_with_nul().as_ptr() as *mut _, + title.to_cstr().as_ptr() as *mut _, can_cancel, Some(cb_task::), &mut ctxt as *mut _ as *mut c_void, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 4d6b97b4a8..63872be3e1 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -102,7 +102,7 @@ use std::cmp; use std::collections::HashMap; use std::ffi::{c_char, c_void, CStr}; use std::path::{Path, PathBuf}; -use string::BnStrCompatible; +use string::AsCStr; use string::BnString; use string::IntoJson; @@ -128,7 +128,7 @@ pub fn load_with_progress( file_path: impl AsRef, mut progress: P, ) -> Option> { - let file_path = file_path.as_ref().into_bytes_with_nul(); + let file_path = file_path.as_ref().to_cstr(); let options = c""; let handle = unsafe { BNLoadFilename( @@ -193,13 +193,9 @@ where O: IntoJson, P: ProgressCallback, { - let file_path = file_path.as_ref().into_bytes_with_nul(); + let file_path = file_path.as_ref().to_cstr(); let options_or_default = if let Some(opt) = options { - opt.get_json_string() - .ok()? - .into_bytes_with_nul() - .as_ref() - .to_vec() + opt.get_json_string().ok()?.to_cstr().to_bytes().to_vec() } else { Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() @@ -247,11 +243,7 @@ where P: ProgressCallback, { let options_or_default = if let Some(opt) = options { - opt.get_json_string() - .ok()? - .into_bytes_with_nul() - .as_ref() - .to_vec() + opt.get_json_string().ok()?.to_cstr().to_bytes().to_vec() } else { Metadata::new_of_type(MetadataType::KeyValueDataType) .get_json_string() @@ -292,7 +284,7 @@ pub fn bundled_plugin_directory() -> Result { } pub fn set_bundled_plugin_directory(new_dir: impl AsRef) { - let new_dir = new_dir.as_ref().into_bytes_with_nul(); + let new_dir = new_dir.as_ref().to_cstr(); unsafe { BNSetBundledPluginDirectory(new_dir.as_ptr() as *const c_char) }; } @@ -336,7 +328,7 @@ pub fn save_last_run() { } pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Result { - let path_raw = path.as_ref().into_bytes_with_nul(); + let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr() as *const c_char) }; if s.is_null() { @@ -346,7 +338,7 @@ pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Resu } pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result { - let path_raw = path.as_ref().into_bytes_with_nul(); + let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr() as *const c_char) }; if s.is_null() { @@ -356,7 +348,7 @@ pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result< } pub fn path_relative_to_user_directory(path: impl AsRef) -> Result { - let path_raw = path.as_ref().into_bytes_with_nul(); + let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr() as *const c_char) }; if s.is_null() { @@ -481,8 +473,8 @@ impl VersionInfo { unsafe { BnString::free_raw(value.channel) }; } - pub fn from_string(string: S) -> Self { - let string = string.into_bytes_with_nul(); + pub fn from_string(string: S) -> Self { + let string = string.to_cstr(); let result = unsafe { BNParseVersionString(string.as_ref().as_ptr() as *const c_char) }; Self::from_owned_raw(result) } @@ -540,14 +532,14 @@ pub fn license_count() -> i32 { /// 1. Check the BN_LICENSE environment variable /// 2. Check the Binary Ninja user directory for license.dat #[cfg(not(feature = "demo"))] -pub fn set_license(license: Option) { - let license = license.unwrap_or_default().into_bytes_with_nul(); +pub fn set_license(license: Option) { + let license = license.unwrap_or_default().to_cstr(); let license_slice = license.as_ref(); unsafe { BNSetLicense(license_slice.as_ptr() as *const c_char) } } #[cfg(feature = "demo")] -pub fn set_license(_license: Option) {} +pub fn set_license(_license: Option) {} pub fn product() -> String { unsafe { BnString::into_string(BNGetProduct()) } @@ -566,8 +558,8 @@ pub fn is_ui_enabled() -> bool { unsafe { BNIsUIEnabled() } } -pub fn is_database(filename: S) -> bool { - let filename = filename.into_bytes_with_nul(); +pub fn is_database(filename: S) -> bool { + let filename = filename.to_cstr(); let filename_slice = filename.as_ref(); unsafe { BNIsDatabase(filename_slice.as_ptr() as *const c_char) } } @@ -596,16 +588,12 @@ pub fn plugin_ui_abi_minimum_version() -> u32 { BN_MINIMUM_UI_ABI_VERSION } -pub fn add_required_plugin_dependency(name: S) { - unsafe { - BNAddRequiredPluginDependency(name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) - }; +pub fn add_required_plugin_dependency(name: S) { + unsafe { BNAddRequiredPluginDependency(name.to_cstr().as_ref().as_ptr() as *const c_char) }; } -pub fn add_optional_plugin_dependency(name: S) { - unsafe { - BNAddOptionalPluginDependency(name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) - }; +pub fn add_optional_plugin_dependency(name: S) { + unsafe { BNAddOptionalPluginDependency(name.to_cstr().as_ref().as_ptr() as *const c_char) }; } // Provide ABI version automatically so that the core can verify binary compatibility diff --git a/rust/src/medium_level_il/function.rs b/rust/src/medium_level_il/function.rs index 0ac82ff182..de3ece02a2 100644 --- a/rust/src/medium_level_il/function.rs +++ b/rust/src/medium_level_il/function.rs @@ -11,7 +11,7 @@ use crate::disassembly::DisassemblySettings; use crate::flowgraph::FlowGraph; use crate::function::{Function, Location}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use crate::types::Type; use crate::variable::{PossibleValueSet, RegisterValue, SSAVariable, UserVariableValue, Variable}; @@ -122,14 +122,14 @@ impl MediumLevelILFunction { unsafe { Array::new(raw_instr_idxs, count, self.to_owned()) } } - pub fn create_user_stack_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_user_stack_var<'a, S: AsCStr, C: Into>>( self, offset: i64, var_type: C, name: S, ) { let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNCreateUserStackVariable( self.function().handle, @@ -144,7 +144,7 @@ impl MediumLevelILFunction { unsafe { BNDeleteUserStackVariable(self.function().handle, offset) } } - pub fn create_user_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_user_var<'a, S: AsCStr, C: Into>>( &self, var: &Variable, var_type: C, @@ -153,7 +153,7 @@ impl MediumLevelILFunction { ) { let raw_var = BNVariable::from(var); let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNCreateUserVariable( self.function().handle, @@ -274,14 +274,14 @@ impl MediumLevelILFunction { Ok(()) } - pub fn create_auto_stack_var<'a, T: Into>, S: BnStrCompatible>( + pub fn create_auto_stack_var<'a, T: Into>, S: AsCStr>( &self, offset: i64, var_type: T, name: S, ) { let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let name_c_str = name.as_ref(); unsafe { BNCreateAutoStackVariable( @@ -297,7 +297,7 @@ impl MediumLevelILFunction { unsafe { BNDeleteAutoStackVariable(self.function().handle, offset) } } - pub fn create_auto_var<'a, S: BnStrCompatible, C: Into>>( + pub fn create_auto_var<'a, S: AsCStr, C: Into>>( &self, var: &Variable, var_type: C, @@ -306,7 +306,7 @@ impl MediumLevelILFunction { ) { let raw_var = BNVariable::from(var); let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let name_c_str = name.as_ref(); unsafe { BNCreateAutoVariable( diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index fc935cd506..c31e806b52 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString, IntoJson}; +use crate::string::{AsCStr, BnString, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::os::raw::c_char; @@ -267,14 +267,14 @@ impl Metadata { Ok(Some(unsafe { Self::ref_from_raw(ptr) })) } - pub fn get(&self, key: S) -> Result>, ()> { + pub fn get(&self, key: S) -> Result>, ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } let ptr: *mut BNMetadata = unsafe { BNMetadataGetForKey( self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, ) }; if ptr.is_null() { @@ -291,7 +291,7 @@ impl Metadata { Ok(()) } - pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { + pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -299,7 +299,7 @@ impl Metadata { unsafe { BNMetadataSetValueForKey( self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, value.handle, ) }; @@ -315,7 +315,7 @@ impl Metadata { Ok(()) } - pub fn remove_key(&self, key: S) -> Result<(), ()> { + pub fn remove_key(&self, key: S) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -323,7 +323,7 @@ impl Metadata { unsafe { BNMetadataRemoveKey( self.handle, - key.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + key.to_cstr().as_ref().as_ptr() as *const c_char, ) }; Ok(()) @@ -398,7 +398,7 @@ impl From for Ref { fn from(value: String) -> Self { unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData( - value.into_bytes_with_nul().as_ptr() as *const c_char, + value.to_cstr().as_ptr() as *const c_char )) } } @@ -408,7 +408,7 @@ impl From<&str> for Ref { fn from(value: &str) -> Self { unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData( - value.into_bytes_with_nul().as_ptr() as *const c_char, + value.to_cstr().as_ptr() as *const c_char )) } } @@ -444,12 +444,10 @@ impl From<&Array> for Ref { } } -impl From>> for Ref { +impl From>> for Ref { fn from(value: HashMap>) -> Self { - let data: Vec<(S::Result, Ref)> = value - .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v)) - .collect(); + let data: Vec<(S::Result, Ref)> = + value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); let mut keys: Vec<*const c_char> = data .iter() .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) @@ -468,14 +466,12 @@ impl From>> for Ref { impl From<&[(S, T)]> for Ref where - S: BnStrCompatible + Copy, + S: AsCStr + Copy, for<'a> &'a T: Into>, { fn from(value: &[(S, T)]) -> Self { - let data: Vec<(S::Result, Ref)> = value - .iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into())) - .collect(); + let data: Vec<(S::Result, Ref)> = + value.iter().map(|(k, v)| (k.to_cstr(), v.into())).collect(); let mut keys: Vec<*const c_char> = data .iter() .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) @@ -494,7 +490,7 @@ where impl From<[(S, T); N]> for Ref where - S: BnStrCompatible + Copy, + S: AsCStr + Copy, for<'a> &'a T: Into>, { fn from(value: [(S, T); N]) -> Self { @@ -548,11 +544,11 @@ impl From<&Vec> for Ref { } } -impl From> for Ref { +impl From> for Ref { fn from(value: Vec) -> Self { let mut refs = vec![]; for v in value { - refs.push(v.into_bytes_with_nul()); + refs.push(v.to_cstr()); } let mut pointers = vec![]; for r in &refs { diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 65138c19e4..1918674059 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -82,8 +82,8 @@ impl Platform { Ref::new(Self { handle }) } - pub fn by_name(name: S) -> Option> { - let raw_name = name.into_bytes_with_nul(); + pub fn by_name(name: S) -> Option> { + let raw_name = name.to_cstr(); unsafe { let res = BNGetPlatformByName(raw_name.as_ref().as_ptr() as *mut _); @@ -113,8 +113,8 @@ impl Platform { } } - pub fn list_by_os(name: S) -> Array { - let raw_name = name.into_bytes_with_nul(); + pub fn list_by_os(name: S) -> Array { + let raw_name = name.to_cstr(); unsafe { let mut count = 0; @@ -124,11 +124,8 @@ impl Platform { } } - pub fn list_by_os_and_arch( - name: S, - arch: &CoreArchitecture, - ) -> Array { - let raw_name = name.into_bytes_with_nul(); + pub fn list_by_os_and_arch(name: S, arch: &CoreArchitecture) -> Array { + let raw_name = name.to_cstr(); unsafe { let mut count = 0; @@ -151,8 +148,8 @@ impl Platform { } } - pub fn new(arch: &A, name: S) -> Ref { - let name = name.into_bytes_with_nul(); + pub fn new(arch: &A, name: S) -> Ref { + let name = name.to_cstr(); unsafe { let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ref().as_ptr() as *mut _); assert!(!handle.is_null()); @@ -179,9 +176,9 @@ impl Platform { unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } - pub fn get_type_libraries_by_name(&self, name: T) -> Array { + pub fn get_type_libraries_by_name(&self, name: T) -> Array { let mut count = 0; - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let result = unsafe { BNGetPlatformTypeLibrariesByName( self.handle, @@ -193,8 +190,8 @@ impl Platform { unsafe { Array::new(result, count, ()) } } - pub fn register_os(&self, os: S) { - let os = os.into_bytes_with_nul(); + pub fn register_os(&self, os: S) { + let os = os.to_cstr(); unsafe { BNRegisterPlatform(os.as_ref().as_ptr() as *mut _, self.handle); diff --git a/rust/src/project.rs b/rust/src/project.rs index ebb6949eb2..453f1c5658 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -13,7 +13,7 @@ use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::project::folder::ProjectFolder; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub struct Project { pub(crate) handle: NonNull, @@ -39,9 +39,9 @@ impl Project { /// /// * `path` - Path to the project directory (.bnpr) /// * `name` - Name of the new project - pub fn create(path: P, name: S) -> Option> { - let path_raw = path.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); + pub fn create(path: P, name: S) -> Option> { + let path_raw = path.to_cstr(); + let name_raw = name.to_cstr(); let handle = unsafe { BNCreateProject( path_raw.as_ref().as_ptr() as *const c_char, @@ -54,8 +54,8 @@ impl Project { /// Open an existing project /// /// * `path` - Path to the project directory (.bnpr) or project metadata file (.bnpm) - pub fn open_project(path: P) -> Option> { - let path_raw = path.into_bytes_with_nul(); + pub fn open_project(path: P) -> Option> { + let path_raw = path.to_cstr(); let handle = unsafe { BNOpenProject(path_raw.as_ref().as_ptr() as *const c_char) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) } @@ -99,8 +99,8 @@ impl Project { } /// Set the name of the project - pub fn set_name(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) { + let value = value.to_cstr(); unsafe { BNProjectSetName( self.handle.as_ptr(), @@ -115,8 +115,8 @@ impl Project { } /// Set the description of the project - pub fn set_description(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn set_description(&self, value: S) { + let value = value.to_cstr(); unsafe { BNProjectSetDescription( self.handle.as_ptr(), @@ -126,8 +126,8 @@ impl Project { } /// Retrieves metadata stored under a key from the project - pub fn query_metadata(&self, key: S) -> Ref { - let key = key.into_bytes_with_nul(); + pub fn query_metadata(&self, key: S) -> Ref { + let key = key.to_cstr(); let result = unsafe { BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; @@ -138,8 +138,8 @@ impl Project { /// /// * `key` - Key under which to store the Metadata object /// * `value` - Object to store - pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { - let key_raw = key.into_bytes_with_nul(); + pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { + let key_raw = key.to_cstr(); unsafe { BNProjectStoreMetadata( self.handle.as_ptr(), @@ -150,8 +150,8 @@ impl Project { } /// Removes the metadata associated with this `key` from the project - pub fn remove_metadata(&self, key: S) { - let key_raw = key.into_bytes_with_nul(); + pub fn remove_metadata(&self, key: S) { + let key_raw = key.to_cstr(); unsafe { BNProjectRemoveMetadata( self.handle.as_ptr(), @@ -176,8 +176,8 @@ impl Project { description: D, ) -> Result, ()> where - P: BnStrCompatible, - D: BnStrCompatible, + P: AsCStr, + D: AsCStr, { self.create_folder_from_path_with_progress(path, parent, description, NoProgressCallback) } @@ -196,12 +196,12 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: BnStrCompatible, - D: BnStrCompatible, + P: AsCStr, + D: AsCStr, PC: ProgressCallback, { - let path_raw = path.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + let path_raw = path.to_cstr(); + let description_raw = description.to_cstr(); let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { @@ -229,11 +229,11 @@ impl Project { description: D, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, + N: AsCStr, + D: AsCStr, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { let result = BNProjectCreateFolder( @@ -260,14 +260,14 @@ impl Project { id: I, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, + N: AsCStr, + D: AsCStr, + I: AsCStr, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); - let id_raw = id.into_bytes_with_nul(); + let id_raw = id.to_cstr(); unsafe { let result = BNProjectCreateFolderUnsafe( self.handle.as_ptr(), @@ -292,8 +292,8 @@ impl Project { } /// Retrieve a folder in the project by unique folder `id` - pub fn folder_by_id(&self, id: S) -> Option> { - let id_raw = id.into_bytes_with_nul(); + pub fn folder_by_id(&self, id: S) -> Option> { + let id_raw = id.to_cstr(); let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), id_ptr) }; let handle = NonNull::new(result)?; @@ -350,9 +350,9 @@ impl Project { description: D, ) -> Result, ()> where - P: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, + P: AsCStr, + N: AsCStr, + D: AsCStr, { self.create_file_from_path_with_progress( path, @@ -379,14 +379,14 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, + P: AsCStr, + N: AsCStr, + D: AsCStr, PC: ProgressCallback, { - let path_raw = path.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + let path_raw = path.to_cstr(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { @@ -421,10 +421,10 @@ impl Project { creation_time: SystemTime, ) -> Result, ()> where - P: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, + P: AsCStr, + N: AsCStr, + D: AsCStr, + I: AsCStr, { self.create_file_from_path_unsafe_with_progress( path, @@ -458,16 +458,16 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: BnStrCompatible, - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, + P: AsCStr, + N: AsCStr, + D: AsCStr, + I: AsCStr, PC: ProgressCallback, { - let path_raw = path.into_bytes_with_nul(); - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - let id_raw = id.into_bytes_with_nul(); + let path_raw = path.to_cstr(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); + let id_raw = id.to_cstr(); let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { @@ -500,8 +500,8 @@ impl Project { description: D, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, + N: AsCStr, + D: AsCStr, { self.create_file_with_progress(contents, folder, name, description, NoProgressCallback) } @@ -522,12 +522,12 @@ impl Project { mut progress: P, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, + N: AsCStr, + D: AsCStr, P: ProgressCallback, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { @@ -563,9 +563,9 @@ impl Project { creation_time: SystemTime, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, + N: AsCStr, + D: AsCStr, + I: AsCStr, { self.create_file_unsafe_with_progress( contents, @@ -599,14 +599,14 @@ impl Project { mut progress: P, ) -> Result, ()> where - N: BnStrCompatible, - D: BnStrCompatible, - I: BnStrCompatible, + N: AsCStr, + D: AsCStr, + I: AsCStr, P: ProgressCallback, { - let name_raw = name.into_bytes_with_nul(); - let description_raw = description.into_bytes_with_nul(); - let id_raw = id.into_bytes_with_nul(); + let name_raw = name.to_cstr(); + let description_raw = description.to_cstr(); + let id_raw = id.to_cstr(); let folder_ptr = folder.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); unsafe { @@ -635,8 +635,8 @@ impl Project { } /// Retrieve a file in the project by unique `id` - pub fn file_by_id(&self, id: S) -> Option> { - let id_raw = id.into_bytes_with_nul(); + pub fn file_by_id(&self, id: S) -> Option> { + let id_raw = id.to_cstr(); let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), id_ptr) }; @@ -645,8 +645,8 @@ impl Project { } /// Retrieve a file in the project by the `path` on disk - pub fn file_by_path(&self, path: S) -> Option> { - let path_raw = path.into_bytes_with_nul(); + pub fn file_by_path(&self, path: S) -> Option> { + let path_raw = path.to_cstr(); let path_ptr = path_raw.as_ref().as_ptr() as *const c_char; let result = unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_ptr) }; diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs index 35f25937a7..d1724ab0f0 100644 --- a/rust/src/project/file.rs +++ b/rust/src/project/file.rs @@ -1,6 +1,6 @@ use crate::project::{systime_from_bntime, Project, ProjectFolder}; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::{ BNFreeProjectFile, BNFreeProjectFileList, BNNewProjectFileReference, BNProjectFile, BNProjectFileExistsOnDisk, BNProjectFileExport, BNProjectFileGetCreationTimestamp, @@ -57,8 +57,8 @@ impl ProjectFile { } /// Set the name of this file - pub fn set_name(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) -> bool { + let value_raw = value.to_cstr(); unsafe { BNProjectFileSetName( self.handle.as_ptr(), @@ -73,8 +73,8 @@ impl ProjectFile { } /// Set the description of this file - pub fn set_description(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); + pub fn set_description(&self, value: S) -> bool { + let value_raw = value.to_cstr(); unsafe { BNProjectFileSetDescription( self.handle.as_ptr(), @@ -104,8 +104,8 @@ impl ProjectFile { /// Export this file to disk, `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { - let dest_raw = dest.into_bytes_with_nul(); + pub fn export(&self, dest: S) -> bool { + let dest_raw = dest.to_cstr(); unsafe { BNProjectFileExport( self.handle.as_ptr(), diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index 316abeafd0..b8881ddcc1 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -1,7 +1,7 @@ use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::{ BNFreeProjectFolder, BNFreeProjectFolderList, BNNewProjectFolderReference, BNProjectFolder, BNProjectFolderExport, BNProjectFolderGetDescription, BNProjectFolderGetId, @@ -46,8 +46,8 @@ impl ProjectFolder { } /// Set the name of this folder - pub fn set_name(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) -> bool { + let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetName( self.handle.as_ptr(), @@ -62,8 +62,8 @@ impl ProjectFolder { } /// Set the description of this folder - pub fn set_description(&self, value: S) -> bool { - let value_raw = value.into_bytes_with_nul(); + pub fn set_description(&self, value: S) -> bool { + let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetDescription( self.handle.as_ptr(), @@ -88,7 +88,7 @@ impl ProjectFolder { /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { + pub fn export(&self, dest: S) -> bool { self.export_with_progress(dest, NoProgressCallback) } @@ -99,10 +99,10 @@ impl ProjectFolder { /// * `progress` - [`ProgressCallback`] that will be called as contents are exporting pub fn export_with_progress(&self, dest: S, mut progress: P) -> bool where - S: BnStrCompatible, + S: AsCStr, P: ProgressCallback, { - let dest_raw = dest.into_bytes_with_nul(); + let dest_raw = dest.to_cstr(); let success = unsafe { BNProjectFolderExport( diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index f10115c8b5..b794f698f7 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -1,6 +1,6 @@ use crate::low_level_il::RegularLowLevelILFunction; use crate::rc::Guard; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use crate::{ architecture::CoreArchitecture, binary_view::BinaryView, @@ -404,7 +404,7 @@ unsafe impl RefCountable for CoreRelocationHandler { pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: S, func: F) where - S: BnStrCompatible, + S: AsCStr, R: 'static + RelocationHandler> + Send + Sync + Sized, F: FnOnce(CustomRelocationHandlerHandle, CoreRelocationHandler) -> R, { @@ -503,7 +503,7 @@ where .into() } - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let raw = Box::leak(Box::new( MaybeUninit::>::zeroed(), diff --git a/rust/src/render_layer.rs b/rust/src/render_layer.rs index 80ecc63949..175ee16770 100644 --- a/rust/src/render_layer.rs +++ b/rust/src/render_layer.rs @@ -6,7 +6,7 @@ use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; use crate::linear_view::{LinearDisassemblyLine, LinearDisassemblyLineType, LinearViewObject}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void}; use std::ptr::NonNull; @@ -61,7 +61,7 @@ impl Default for RenderLayerDefaultState { } /// Register a [`RenderLayer`] with the API. -pub fn register_render_layer( +pub fn register_render_layer( name: S, render_layer: T, default_state: RenderLayerDefaultState, @@ -75,7 +75,7 @@ pub fn register_render_layer( }; let result = unsafe { BNRegisterRenderLayer( - name.into_bytes_with_nul().as_ref().as_ptr() as *const _, + name.to_cstr().as_ref().as_ptr() as *const _, &mut callback, default_state.into(), ) @@ -303,8 +303,8 @@ impl CoreRenderLayer { unsafe { Array::new(result, count, ()) } } - pub fn render_layer_by_name(name: S) -> Option { - let name_raw = name.into_bytes_with_nul(); + pub fn render_layer_by_name(name: S) -> Option { + let name_raw = name.to_cstr(); let result = unsafe { BNGetRenderLayerByName(name_raw.as_ref().as_ptr() as *const c_char) }; NonNull::new(result).map(Self::from_raw) } diff --git a/rust/src/repository.rs b/rust/src/repository.rs index 90e414d5f9..8d2fbafe91 100644 --- a/rust/src/repository.rs +++ b/rust/src/repository.rs @@ -9,7 +9,7 @@ use binaryninjacore_sys::*; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::repository::plugin::RepositoryPlugin; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub use manager::RepositoryManager; @@ -52,8 +52,8 @@ impl Repository { unsafe { Array::new(result, count, ()) } } - pub fn plugin_by_path(&self, path: S) -> Option> { - let path = path.into_bytes_with_nul(); + pub fn plugin_by_path(&self, path: S) -> Option> { + let path = path.to_cstr(); let result = unsafe { BNRepositoryGetPluginByPath( self.handle.as_ptr(), diff --git a/rust/src/repository/manager.rs b/rust/src/repository/manager.rs index 598891625d..e591180281 100644 --- a/rust/src/repository/manager.rs +++ b/rust/src/repository/manager.rs @@ -1,6 +1,6 @@ use crate::rc::{Array, Ref, RefCountable}; use crate::repository::Repository; -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use binaryninjacore_sys::{ BNCreateRepositoryManager, BNFreeRepositoryManager, BNGetRepositoryManager, BNNewRepositoryManagerReference, BNRepositoryGetRepositoryByPath, BNRepositoryManager, @@ -29,8 +29,8 @@ impl RepositoryManager { Ref::new(Self { handle }) } - pub fn new(plugins_path: S) -> Ref { - let plugins_path = plugins_path.into_bytes_with_nul(); + pub fn new(plugins_path: S) -> Ref { + let plugins_path = plugins_path.to_cstr(); let result = unsafe { BNCreateRepositoryManager(plugins_path.as_ref().as_ptr() as *const c_char) }; unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } @@ -61,13 +61,9 @@ impl RepositoryManager { /// * `repository_path` - path to where the repository will be stored on disk locally /// /// Returns true if the repository was successfully added, false otherwise. - pub fn add_repository( - &self, - url: U, - repository_path: P, - ) -> bool { - let url = url.into_bytes_with_nul(); - let repo_path = repository_path.into_bytes_with_nul(); + pub fn add_repository(&self, url: U, repository_path: P) -> bool { + let url = url.to_cstr(); + let repo_path = repository_path.to_cstr(); unsafe { BNRepositoryManagerAddRepository( self.handle.as_ptr(), @@ -77,8 +73,8 @@ impl RepositoryManager { } } - pub fn repository_by_path(&self, path: P) -> Option { - let path = path.into_bytes_with_nul(); + pub fn repository_by_path(&self, path: P) -> Option { + let path = path.to_cstr(); let result = unsafe { BNRepositoryGetRepositoryByPath( self.handle.as_ptr(), diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index 5f42dbea62..7acf6d4bbc 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use std::ptr::NonNull; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; pub trait SecretsProvider { fn has_data(&mut self, key: &str) -> bool; @@ -27,7 +27,7 @@ impl CoreSecretsProvider { /// Register a new provider pub fn new(name: &str, callback: C) -> Self { // SAFETY: once create SecretsProvider is never dropped - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let callback = Box::leak(Box::new(callback)); let mut callbacks = BNSecretsProviderCallbacks { context: callback as *mut C as *mut c_void, @@ -50,8 +50,8 @@ impl CoreSecretsProvider { } /// Retrieve a provider by name - pub fn by_name(name: S) -> Option { - let name = name.into_bytes_with_nul(); + pub fn by_name(name: S) -> Option { + let name = name.to_cstr(); let result = unsafe { BNGetSecretsProviderByName(name.as_ref().as_ptr() as *const c_char) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) } @@ -63,16 +63,16 @@ impl CoreSecretsProvider { } /// Check if data for a specific key exists, but do not retrieve it - pub fn has_data(&self, key: S) -> bool { - let key = key.into_bytes_with_nul(); + pub fn has_data(&self, key: S) -> bool { + let key = key.to_cstr(); unsafe { BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) } } /// Retrieve data for the given key, if it exists - pub fn get_data(&self, key: S) -> String { - let key = key.into_bytes_with_nul(); + pub fn get_data(&self, key: S) -> String { + let key = key.to_cstr(); let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; @@ -80,9 +80,9 @@ impl CoreSecretsProvider { } /// Store data with the given key - pub fn store_data(&self, key: K, value: V) -> bool { - let key = key.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); + pub fn store_data(&self, key: K, value: V) -> bool { + let key = key.to_cstr(); + let value = value.to_cstr(); unsafe { BNStoreSecretsProviderData( self.handle.as_ptr(), @@ -93,8 +93,8 @@ impl CoreSecretsProvider { } /// Delete stored data with the given key - pub fn delete_data(&self, key: S) -> bool { - let key = key.into_bytes_with_nul(); + pub fn delete_data(&self, key: S) -> bool { + let key = key.to_cstr(); unsafe { BNDeleteSecretsProviderData( self.handle.as_ptr(), diff --git a/rust/src/section.rs b/rust/src/section.rs index 46a201d4f0..d1098e6776 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -270,10 +270,10 @@ impl SectionBuilder { } pub(crate) fn create(self, view: &BinaryView) { - let name = self.name.into_bytes_with_nul(); - let ty = self.ty.into_bytes_with_nul(); - let linked_section = self.linked_section.into_bytes_with_nul(); - let info_section = self.info_section.into_bytes_with_nul(); + let name = self.name.to_cstr(); + let ty = self.ty.to_cstr(); + let linked_section = self.linked_section.to_cstr(); + let info_section = self.info_section.to_cstr(); let start = self.range.start; let len = self.range.end.wrapping_sub(start); diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 4b4d418fdd..b49dbdea8b 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -20,7 +20,7 @@ use std::fmt::Debug; use crate::binary_view::BinaryView; use crate::rc::*; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::function::Function; @@ -44,8 +44,8 @@ impl Settings { Self::new_with_id(GLOBAL_INSTANCE_ID) } - pub fn new_with_id(instance_id: S) -> Ref { - let instance_id = instance_id.into_bytes_with_nul(); + pub fn new_with_id(instance_id: S) -> Ref { + let instance_id = instance_id.to_cstr(); unsafe { let handle = BNCreateSettings(instance_id.as_ref().as_ptr() as *mut _); debug_assert!(!handle.is_null()); @@ -53,8 +53,8 @@ impl Settings { } } - pub fn set_resource_id(&self, resource_id: S) { - let resource_id = resource_id.into_bytes_with_nul(); + pub fn set_resource_id(&self, resource_id: S) { + let resource_id = resource_id.to_cstr(); unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ref().as_ptr() as *mut _) }; } @@ -62,16 +62,16 @@ impl Settings { unsafe { BnString::into_string(BNSettingsSerializeSchema(self.handle)) } } - pub fn deserialize_schema(&self, schema: S) -> bool { + pub fn deserialize_schema(&self, schema: S) -> bool { self.deserialize_schema_with_scope(schema, SettingsScope::SettingsAutoScope) } - pub fn deserialize_schema_with_scope( + pub fn deserialize_schema_with_scope( &self, schema: S, scope: SettingsScope, ) -> bool { - let schema = schema.into_bytes_with_nul(); + let schema = schema.to_cstr(); unsafe { BNSettingsDeserializeSchema( self.handle, @@ -82,8 +82,8 @@ impl Settings { } } - pub fn contains(&self, key: S) -> bool { - let key = key.into_bytes_with_nul(); + pub fn contains(&self, key: S) -> bool { + let key = key.to_cstr(); unsafe { BNSettingsContains(self.handle, key.as_ref().as_ptr() as *mut _) } } @@ -97,16 +97,12 @@ impl Settings { // TODO Update the settings API to take an optional BinaryView or Function. Separate functions or...? - pub fn get_bool(&self, key: S) -> bool { + pub fn get_bool(&self, key: S) -> bool { self.get_bool_with_opts(key, &mut QueryOptions::default()) } - pub fn get_bool_with_opts( - &self, - key: S, - options: &mut QueryOptions, - ) -> bool { - let key = key.into_bytes_with_nul(); + pub fn get_bool_with_opts(&self, key: S, options: &mut QueryOptions) -> bool { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -126,16 +122,12 @@ impl Settings { } } - pub fn get_double(&self, key: S) -> f64 { + pub fn get_double(&self, key: S) -> f64 { self.get_double_with_opts(key, &mut QueryOptions::default()) } - pub fn get_double_with_opts( - &self, - key: S, - options: &mut QueryOptions, - ) -> f64 { - let key = key.into_bytes_with_nul(); + pub fn get_double_with_opts(&self, key: S, options: &mut QueryOptions) -> f64 { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -155,16 +147,12 @@ impl Settings { } } - pub fn get_integer(&self, key: S) -> u64 { + pub fn get_integer(&self, key: S) -> u64 { self.get_integer_with_opts(key, &mut QueryOptions::default()) } - pub fn get_integer_with_opts( - &self, - key: S, - options: &mut QueryOptions, - ) -> u64 { - let key = key.into_bytes_with_nul(); + pub fn get_integer_with_opts(&self, key: S, options: &mut QueryOptions) -> u64 { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -184,16 +172,12 @@ impl Settings { } } - pub fn get_string(&self, key: S) -> String { + pub fn get_string(&self, key: S) -> String { self.get_string_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_with_opts( - &self, - key: S, - options: &mut QueryOptions, - ) -> String { - let key = key.into_bytes_with_nul(); + pub fn get_string_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -213,16 +197,16 @@ impl Settings { } } - pub fn get_string_list(&self, key: S) -> Array { + pub fn get_string_list(&self, key: S) -> Array { self.get_string_list_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_list_with_opts( + pub fn get_string_list_with_opts( &self, key: S, options: &mut QueryOptions, ) -> Array { - let key = key.into_bytes_with_nul(); + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -248,16 +232,12 @@ impl Settings { } } - pub fn get_json(&self, key: S) -> String { + pub fn get_json(&self, key: S) -> String { self.get_json_with_opts(key, &mut QueryOptions::default()) } - pub fn get_json_with_opts( - &self, - key: S, - options: &mut QueryOptions, - ) -> String { - let key = key.into_bytes_with_nul(); + pub fn get_json_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -277,17 +257,12 @@ impl Settings { } } - pub fn set_bool(&self, key: S, value: bool) { + pub fn set_bool(&self, key: S, value: bool) { self.set_bool_with_opts(key, value, &QueryOptions::default()) } - pub fn set_bool_with_opts( - &self, - key: S, - value: bool, - options: &QueryOptions, - ) { - let key = key.into_bytes_with_nul(); + pub fn set_bool_with_opts(&self, key: S, value: bool, options: &QueryOptions) { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -308,16 +283,11 @@ impl Settings { } } - pub fn set_double(&self, key: S, value: f64) { + pub fn set_double(&self, key: S, value: f64) { self.set_double_with_opts(key, value, &QueryOptions::default()) } - pub fn set_double_with_opts( - &self, - key: S, - value: f64, - options: &QueryOptions, - ) { - let key = key.into_bytes_with_nul(); + pub fn set_double_with_opts(&self, key: S, value: f64, options: &QueryOptions) { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -338,17 +308,12 @@ impl Settings { } } - pub fn set_integer(&self, key: S, value: u64) { + pub fn set_integer(&self, key: S, value: u64) { self.set_integer_with_opts(key, value, &QueryOptions::default()) } - pub fn set_integer_with_opts( - &self, - key: S, - value: u64, - options: &QueryOptions, - ) { - let key = key.into_bytes_with_nul(); + pub fn set_integer_with_opts(&self, key: S, value: u64, options: &QueryOptions) { + let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -369,18 +334,18 @@ impl Settings { } } - pub fn set_string(&self, key: S1, value: S2) { + pub fn set_string(&self, key: S1, value: S2) { self.set_string_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_with_opts( + pub fn set_string_with_opts( &self, key: S1, value: S2, options: &QueryOptions, ) { - let key = key.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); + let key = key.to_cstr(); + let value = value.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -401,7 +366,7 @@ impl Settings { } } - pub fn set_string_list>( + pub fn set_string_list>( &self, key: S1, value: I, @@ -409,18 +374,14 @@ impl Settings { self.set_string_list_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_list_with_opts< - S1: BnStrCompatible, - S2: BnStrCompatible, - I: Iterator, - >( + pub fn set_string_list_with_opts>( &self, key: S1, value: I, options: &QueryOptions, ) -> bool { - let key = key.into_bytes_with_nul(); - let raw_list: Vec<_> = value.map(|s| s.into_bytes_with_nul()).collect(); + let key = key.to_cstr(); + let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); let mut raw_list_ptr: Vec<_> = raw_list .iter() .map(|s| s.as_ref().as_ptr() as *const c_char) @@ -447,18 +408,18 @@ impl Settings { } } - pub fn set_json(&self, key: S1, value: S2) -> bool { + pub fn set_json(&self, key: S1, value: S2) -> bool { self.set_json_with_opts(key, value, &QueryOptions::default()) } - pub fn set_json_with_opts( + pub fn set_json_with_opts( &self, key: S1, value: S2, options: &QueryOptions, ) -> bool { - let key = key.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); + let key = key.to_cstr(); + let value = value.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, _ => std::ptr::null_mut(), @@ -479,9 +440,9 @@ impl Settings { } } - pub fn get_property_string(&self, key: S, property: S) -> String { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn get_property_string(&self, key: S, property: S) -> String { + let key = key.to_cstr(); + let property = property.to_cstr(); unsafe { BnString::into_string(BNSettingsQueryPropertyString( self.handle, @@ -491,13 +452,9 @@ impl Settings { } } - pub fn get_property_string_list( - &self, - key: S, - property: S, - ) -> Array { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn get_property_string_list(&self, key: S, property: S) -> Array { + let key = key.to_cstr(); + let property = property.to_cstr(); let mut size: usize = 0; unsafe { Array::new( @@ -513,9 +470,9 @@ impl Settings { } } - pub fn update_bool_property(&self, key: S, property: S, value: bool) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn update_bool_property(&self, key: S, property: S, value: bool) { + let key = key.to_cstr(); + let property = property.to_cstr(); unsafe { BNSettingsUpdateBoolProperty( self.handle, @@ -526,9 +483,9 @@ impl Settings { } } - pub fn update_integer_property(&self, key: S, property: S, value: u64) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn update_integer_property(&self, key: S, property: S, value: u64) { + let key = key.to_cstr(); + let property = property.to_cstr(); unsafe { BNSettingsUpdateUInt64Property( self.handle, @@ -539,9 +496,9 @@ impl Settings { } } - pub fn update_double_property(&self, key: S, property: S, value: f64) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); + pub fn update_double_property(&self, key: S, property: S, value: f64) { + let key = key.to_cstr(); + let property = property.to_cstr(); unsafe { BNSettingsUpdateDoubleProperty( self.handle, @@ -552,10 +509,10 @@ impl Settings { } } - pub fn update_string_property(&self, key: S, property: S, value: S) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); - let value = value.into_bytes_with_nul(); + pub fn update_string_property(&self, key: S, property: S, value: S) { + let key = key.to_cstr(); + let property = property.to_cstr(); + let value = value.to_cstr(); unsafe { BNSettingsUpdateStringProperty( self.handle, @@ -566,15 +523,15 @@ impl Settings { } } - pub fn update_string_list_property>( + pub fn update_string_list_property>( &self, key: S, property: S, value: I, ) { - let key = key.into_bytes_with_nul(); - let property = property.into_bytes_with_nul(); - let raw_list: Vec<_> = value.map(|s| s.into_bytes_with_nul()).collect(); + let key = key.to_cstr(); + let property = property.to_cstr(); + let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); let mut raw_list_ptr: Vec<_> = raw_list .iter() .map(|s| s.as_ref().as_ptr() as *const c_char) @@ -591,13 +548,9 @@ impl Settings { } } - pub fn register_group( - &self, - group: S1, - title: S2, - ) -> bool { - let group = group.into_bytes_with_nul(); - let title = title.into_bytes_with_nul(); + pub fn register_group(&self, group: S1, title: S2) -> bool { + let group = group.to_cstr(); + let title = title.to_cstr(); unsafe { BNSettingsRegisterGroup( @@ -608,13 +561,9 @@ impl Settings { } } - pub fn register_setting_json( - &self, - group: S1, - properties: S2, - ) -> bool { - let group = group.into_bytes_with_nul(); - let properties = properties.into_bytes_with_nul(); + pub fn register_setting_json(&self, group: S1, properties: S2) -> bool { + let group = group.to_cstr(); + let properties = properties.to_cstr(); unsafe { BNSettingsRegisterSetting( diff --git a/rust/src/string.rs b/rust/src/string.rs index 5bd871f995..17fcf911cf 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -44,29 +44,27 @@ pub(crate) fn strings_to_string_list(strings: &[String]) -> *mut *mut c_char { unsafe { BNAllocStringList(raw_str_list.as_mut_ptr(), raw_str_list.len()) } } -/// Is the equivalent of `core::ffi::CString` but using the alloc and free from `binaryninjacore-sys`. +/// A nul-terminated C string allocated by the core. +/// +/// Received from a variety of core function calls, and must be used when giving strings to the +/// core from many core-invoked callbacks, or otherwise passing ownership of the string to the core. +/// +/// These are strings we're responsible for freeing, such as strings allocated by the core and +/// given to us through the API and then forgotten about by the core. +/// +/// When passing to the core, make sure to use [`BnString::to_cstr`] and [`CStr::as_ptr`]. +/// +/// When giving ownership to the core, make sure to prevent dropping by calling [`BnString::into_raw`]. #[repr(transparent)] pub struct BnString { raw: *mut c_char, } -/// A nul-terminated C string allocated by the core. -/// -/// Received from a variety of core function calls, and -/// must be used when giving strings to the core from many -/// core-invoked callbacks. -/// -/// These are strings we're responsible for freeing, such as -/// strings allocated by the core and given to us through the API -/// and then forgotten about by the core. impl BnString { - pub fn new(s: S) -> Self { + pub fn new(s: S) -> Self { use binaryninjacore_sys::BNAllocString; - let raw = s.into_bytes_with_nul(); - unsafe { - let ptr = raw.as_ref().as_ptr() as *mut _; - Self::from_raw(BNAllocString(ptr)) - } + let raw = s.to_cstr(); + unsafe { Self::from_raw(BNAllocString(raw.as_ptr())) } } /// Take an owned core string and convert it to [`String`]. @@ -190,118 +188,116 @@ unsafe impl CoreArrayProviderInner for BnString { } } -pub unsafe trait BnStrCompatible { - type Result: AsRef<[u8]>; +pub unsafe trait AsCStr { + type Result: Deref; - fn into_bytes_with_nul(self) -> Self::Result; + fn to_cstr(self) -> Self::Result; } -unsafe impl<'a> BnStrCompatible for &'a CStr { - type Result = &'a [u8]; +unsafe impl<'a> AsCStr for &'a CStr { + type Result = Self; - fn into_bytes_with_nul(self) -> Self::Result { - self.to_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self } } -unsafe impl BnStrCompatible for BnString { +unsafe impl AsCStr for BnString { type Result = Self; - fn into_bytes_with_nul(self) -> Self::Result { + fn to_cstr(self) -> Self::Result { self } } -unsafe impl BnStrCompatible for &BnString { - type Result = Self; +unsafe impl AsCStr for &BnString { + type Result = BnString; - fn into_bytes_with_nul(self) -> Self::Result { - self + fn to_cstr(self) -> Self::Result { + self.clone() } } -unsafe impl BnStrCompatible for CString { - type Result = Vec; +unsafe impl AsCStr for CString { + type Result = Self; - fn into_bytes_with_nul(self) -> Self::Result { - self.into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self } } -unsafe impl BnStrCompatible for &str { - type Result = Vec; +unsafe impl AsCStr for &str { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - let ret = CString::new(self).expect("can't pass strings with internal nul bytes to core!"); - ret.into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + CString::new(self).expect("can't pass strings with internal nul bytes to core!") } } -unsafe impl BnStrCompatible for String { - type Result = Vec; +unsafe impl AsCStr for String { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.as_str().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + CString::new(self).expect("can't pass strings with internal nul bytes to core!") } } -unsafe impl BnStrCompatible for &String { - type Result = Vec; +unsafe impl AsCStr for &String { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.as_str().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self.clone().to_cstr() } } -unsafe impl<'a> BnStrCompatible for &'a Cow<'a, str> { - type Result = Vec; +unsafe impl<'a> AsCStr for &'a Cow<'a, str> { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.to_string().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self.to_string().to_cstr() } } -unsafe impl BnStrCompatible for Cow<'_, str> { - type Result = Vec; +unsafe impl AsCStr for Cow<'_, str> { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.to_string().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self.to_string().to_cstr() } } -unsafe impl BnStrCompatible for &QualifiedName { - type Result = Vec; +unsafe impl AsCStr for &QualifiedName { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.to_string().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self.to_string().to_cstr() } } -unsafe impl BnStrCompatible for PathBuf { - type Result = Vec; +unsafe impl AsCStr for PathBuf { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - self.as_path().into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + self.as_path().to_cstr() } } -unsafe impl BnStrCompatible for &Path { - type Result = Vec; +unsafe impl AsCStr for &Path { + type Result = CString; - fn into_bytes_with_nul(self) -> Self::Result { - let ret = CString::new(self.as_os_str().as_encoded_bytes()) - .expect("can't pass paths with internal nul bytes to core!"); - ret.into_bytes_with_nul() + fn to_cstr(self) -> Self::Result { + CString::new(self.as_os_str().as_encoded_bytes()) + .expect("can't pass paths with internal nul bytes to core!") } } pub trait IntoJson { - type Output: BnStrCompatible; + type Output: AsCStr; fn get_json_string(self) -> Result; } -impl IntoJson for S { +impl IntoJson for S { type Output = S; fn get_json_string(self) -> Result { diff --git a/rust/src/symbol.rs b/rust/src/symbol.rs index 2ff92db537..b06a0f2fdc 100644 --- a/rust/src/symbol.rs +++ b/rust/src/symbol.rs @@ -153,9 +153,9 @@ impl SymbolBuilder { } pub fn create(self) -> Ref { - let raw_name = self.raw_name.into_bytes_with_nul(); - let short_name = self.short_name.map(|s| s.into_bytes_with_nul()); - let full_name = self.full_name.map(|s| s.into_bytes_with_nul()); + let raw_name = self.raw_name.to_cstr(); + let short_name = self.short_name.map(|s| s.to_cstr()); + let full_name = self.full_name.map(|s| s.to_cstr()); // Lifetimes, man let raw_name = raw_name.as_ptr() as _; diff --git a/rust/src/tags.rs b/rust/src/tags.rs index 63c3634a75..30cc46827a 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -42,8 +42,8 @@ impl Tag { Ref::new(Self { handle }) } - pub fn new(t: &TagType, data: S) -> Ref { - let data = data.into_bytes_with_nul(); + pub fn new(t: &TagType, data: S) -> Ref { + let data = data.to_cstr(); unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ref().as_ptr() as *mut _)) } } @@ -59,8 +59,8 @@ impl Tag { unsafe { TagType::ref_from_raw(BNTagGetType(self.handle)) } } - pub fn set_data(&self, data: S) { - let data = data.into_bytes_with_nul(); + pub fn set_data(&self, data: S) { + let data = data.to_cstr(); unsafe { BNTagSetData(self.handle, data.as_ref().as_ptr() as *mut _); } @@ -134,11 +134,7 @@ impl TagType { Ref::new(Self { handle }) } - pub fn create( - view: &BinaryView, - name: N, - icon: I, - ) -> Ref { + pub fn create(view: &BinaryView, name: N, icon: I) -> Ref { let tag_type = unsafe { Self::ref_from_raw(BNCreateTagType(view.handle)) }; tag_type.set_name(name); tag_type.set_icon(icon); @@ -153,8 +149,8 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetIcon(self.handle)) } } - pub fn set_icon(&self, icon: S) { - let icon = icon.into_bytes_with_nul(); + pub fn set_icon(&self, icon: S) { + let icon = icon.to_cstr(); unsafe { BNTagTypeSetIcon(self.handle, icon.as_ref().as_ptr() as *mut _); } @@ -164,8 +160,8 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetName(self.handle)) } } - pub fn set_name(&self, name: S) { - let name = name.into_bytes_with_nul(); + pub fn set_name(&self, name: S) { + let name = name.to_cstr(); unsafe { BNTagTypeSetName(self.handle, name.as_ref().as_ptr() as *mut _); } @@ -183,8 +179,8 @@ impl TagType { unsafe { BNTagTypeGetType(self.handle) } } - pub fn set_type(&self, t: S) { - let t = t.into_bytes_with_nul(); + pub fn set_type(&self, t: S) { + let t = t.to_cstr(); unsafe { BNTagTypeSetName(self.handle, t.as_ref().as_ptr() as *mut _); } diff --git a/rust/src/template_simplifier.rs b/rust/src/template_simplifier.rs index dd815f69a8..57d2b0b4ea 100644 --- a/rust/src/template_simplifier.rs +++ b/rust/src/template_simplifier.rs @@ -1,16 +1,16 @@ use crate::{ - string::{BnStrCompatible, BnString}, + string::{AsCStr, BnString}, types::QualifiedName, }; use binaryninjacore_sys::{BNRustSimplifyStrToFQN, BNRustSimplifyStrToStr}; -pub fn simplify_str_to_str(input: S) -> BnString { - let name = input.into_bytes_with_nul(); +pub fn simplify_str_to_str(input: S) -> BnString { + let name = input.to_cstr(); unsafe { BnString::from_raw(BNRustSimplifyStrToStr(name.as_ref().as_ptr() as *mut _)) } } -pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { - let name = input.into_bytes_with_nul(); +pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { + let name = input.to_cstr(); unsafe { QualifiedName::from_owned_raw(BNRustSimplifyStrToFQN( name.as_ref().as_ptr() as *mut _, diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index ee4bc276b5..5e94f19e7a 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -10,7 +10,7 @@ use crate::data_buffer::DataBuffer; use crate::metadata::Metadata; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type}; @@ -65,7 +65,7 @@ impl TypeArchive { /// Open the Type Archive at the given path, if it exists. pub fn open(path: impl AsRef) -> Option> { - let raw_path = path.as_ref().into_bytes_with_nul(); + let raw_path = path.as_ref().to_cstr(); let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr() as *const c_char) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } @@ -74,7 +74,7 @@ impl TypeArchive { /// /// If the file has already been created and is not a valid type archive this will return `None`. pub fn create(path: impl AsRef, platform: &Platform) -> Option> { - let raw_path = path.as_ref().into_bytes_with_nul(); + let raw_path = path.as_ref().to_cstr(); let handle = unsafe { BNCreateTypeArchive(raw_path.as_ptr() as *const c_char, platform.handle) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) @@ -83,13 +83,13 @@ impl TypeArchive { /// Create a Type Archive at the given path and id, returning None if it could not be created. /// /// If the file has already been created and is not a valid type archive this will return `None`. - pub fn create_with_id( + pub fn create_with_id( path: impl AsRef, id: I, platform: &Platform, ) -> Option> { - let raw_path = path.as_ref().into_bytes_with_nul(); - let id = id.into_bytes_with_nul(); + let raw_path = path.as_ref().to_cstr(); + let id = id.to_cstr(); let handle = unsafe { BNCreateTypeArchiveWithId( raw_path.as_ptr() as *const c_char, @@ -101,8 +101,8 @@ impl TypeArchive { } /// Get a reference to the Type Archive with the known id, if one exists. - pub fn lookup_by_id(id: S) -> Option> { - let id = id.into_bytes_with_nul(); + pub fn lookup_by_id(id: S) -> Option> { + let id = id.to_cstr(); let handle = unsafe { BNLookupTypeArchiveById(id.as_ref().as_ptr() as *const c_char) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } @@ -156,7 +156,7 @@ impl TypeArchive { } /// Get the ids of the parents to the given snapshot - pub fn get_snapshot_parent_ids( + pub fn get_snapshot_parent_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -172,7 +172,7 @@ impl TypeArchive { } /// Get the ids of the children to the given snapshot - pub fn get_snapshot_child_ids( + pub fn get_snapshot_child_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -235,8 +235,8 @@ impl TypeArchive { /// /// * `id` - Old id of type in archive /// * `new_name` - New type name - pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { - let id = id.into_bytes_with_nul(); + pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { + let id = id.to_cstr(); let raw_name = QualifiedName::into_raw(new_name); let result = unsafe { BNRenameTypeArchiveType( @@ -259,8 +259,8 @@ impl TypeArchive { } /// Delete an existing type in the type archive. - pub fn delete_type_by_id(&self, id: S) -> bool { - let id = id.into_bytes_with_nul(); + pub fn delete_type_by_id(&self, id: S) -> bool { + let id = id.to_cstr(); let result = unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) }; @@ -270,7 +270,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive /// /// * `name` - Type name - pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { + pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset()) } @@ -298,7 +298,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive by id /// /// * `id` - Type id - pub fn get_type_by_id(&self, id: I) -> Option> { + pub fn get_type_by_id(&self, id: I) -> Option> { self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -306,12 +306,12 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_id_from_snapshot( + pub fn get_type_by_id_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> Option> { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let result = unsafe { BNGetTypeArchiveTypeById( self.handle.as_ptr(), @@ -325,7 +325,7 @@ impl TypeArchive { /// Retrieve a type's name by its id /// /// * `id` - Type id - pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { + pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -333,12 +333,12 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_name_by_id_from_snapshot( + pub fn get_type_name_by_id_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> QualifiedName { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let result = unsafe { BNGetTypeArchiveTypeName( self.handle.as_ptr(), @@ -479,7 +479,7 @@ impl TypeArchive { /// Get all types a given type references directly /// /// * `id` - Source type id - pub fn get_outgoing_direct_references(&self, id: I) -> Array { + pub fn get_outgoing_direct_references(&self, id: I) -> Array { self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -487,12 +487,12 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_direct_references_from_snapshot( + pub fn get_outgoing_direct_references_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> Array { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingDirectTypeReferences( @@ -509,7 +509,7 @@ impl TypeArchive { /// Get all types a given type references, and any types that the referenced types reference /// /// * `id` - Source type id - pub fn get_outgoing_recursive_references(&self, id: I) -> Array { + pub fn get_outgoing_recursive_references(&self, id: I) -> Array { self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -517,12 +517,12 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_recursive_references_from_snapshot( + pub fn get_outgoing_recursive_references_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> Array { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingRecursiveTypeReferences( @@ -539,7 +539,7 @@ impl TypeArchive { /// Get all types that reference a given type /// /// * `id` - Target type id - pub fn get_incoming_direct_references(&self, id: I) -> Array { + pub fn get_incoming_direct_references(&self, id: I) -> Array { self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -547,12 +547,12 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types - pub fn get_incoming_direct_references_with_snapshot( + pub fn get_incoming_direct_references_with_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> Array { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingDirectTypeReferences( @@ -569,7 +569,7 @@ impl TypeArchive { /// Get all types that reference a given type, and all types that reference them, recursively /// /// * `id` - Target type id - pub fn get_incoming_recursive_references(&self, id: I) -> Array { + pub fn get_incoming_recursive_references(&self, id: I) -> Array { self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -577,12 +577,12 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types, or empty string to search the latest snapshot - pub fn get_incoming_recursive_references_with_snapshot( + pub fn get_incoming_recursive_references_with_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, ) -> Array { - let id = id.into_bytes_with_nul(); + let id = id.to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingRecursiveTypeReferences( @@ -597,8 +597,8 @@ impl TypeArchive { } /// Look up a metadata entry in the archive - pub fn query_metadata(&self, key: S) -> Option> { - let key = key.into_bytes_with_nul(); + pub fn query_metadata(&self, key: S) -> Option> { + let key = key.to_cstr(); let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) }; @@ -609,8 +609,8 @@ impl TypeArchive { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { - let key = key.into_bytes_with_nul(); + pub fn store_metadata(&self, key: S, md: &Metadata) { + let key = key.to_cstr(); let result = unsafe { BNTypeArchiveStoreMetadata( self.handle.as_ptr(), @@ -622,8 +622,8 @@ impl TypeArchive { } /// Delete a given metadata entry in the archive from the `key` - pub fn remove_metadata(&self, key: S) -> bool { - let key = key.into_bytes_with_nul(); + pub fn remove_metadata(&self, key: S) -> bool { + let key = key.to_cstr(); unsafe { BNTypeArchiveRemoveMetadata( self.handle.as_ptr(), @@ -633,10 +633,7 @@ impl TypeArchive { } /// Turn a given `snapshot` id into a data stream - pub fn serialize_snapshot( - &self, - snapshot: &TypeArchiveSnapshotId, - ) -> DataBuffer { + pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { let result = unsafe { BNTypeArchiveSerializeSnapshot( self.handle.as_ptr(), @@ -709,8 +706,8 @@ impl TypeArchive { // TODO: Make this AsRef? /// Determine if `file` is a Type Archive - pub fn is_type_archive(file: P) -> bool { - let file = file.into_bytes_with_nul(); + pub fn is_type_archive(file: P) -> bool { + let file = file.to_cstr(); unsafe { BNIsTypeArchive(file.as_ref().as_ptr() as *const c_char) } } @@ -734,7 +731,7 @@ impl TypeArchive { parents: &[TypeArchiveSnapshotId], ) -> TypeArchiveSnapshotId where - P: BnStrCompatible, + P: AsCStr, F: FnMut(&TypeArchiveSnapshotId) -> bool, { unsafe extern "C" fn cb_callback bool>( @@ -781,12 +778,12 @@ impl TypeArchive { merge_conflicts: M, ) -> Result> where - B: BnStrCompatible, - F: BnStrCompatible, - S: BnStrCompatible, + B: AsCStr, + F: AsCStr, + S: AsCStr, M: IntoIterator, - MI: BnStrCompatible, - MK: BnStrCompatible, + MI: AsCStr, + MK: AsCStr, { self.merge_snapshots_with_progress( base_snapshot, @@ -816,17 +813,17 @@ impl TypeArchive { mut progress: P, ) -> Result> where - B: BnStrCompatible, - F: BnStrCompatible, - S: BnStrCompatible, + B: AsCStr, + F: AsCStr, + S: AsCStr, M: IntoIterator, - MI: BnStrCompatible, - MK: BnStrCompatible, + MI: AsCStr, + MK: AsCStr, P: ProgressCallback, { - let base_snapshot = base_snapshot.into_bytes_with_nul(); - let first_snapshot = first_snapshot.into_bytes_with_nul(); - let second_snapshot = second_snapshot.into_bytes_with_nul(); + let base_snapshot = base_snapshot.to_cstr(); + let first_snapshot = first_snapshot.to_cstr(); + let second_snapshot = second_snapshot.to_cstr(); let (merge_keys, merge_values): (Vec, Vec) = merge_conflicts .into_iter() .map(|(k, v)| (BnString::new(k), BnString::new(v))) @@ -1170,8 +1167,8 @@ impl TypeArchiveMergeConflict { } // TODO: This needs documentation! - pub fn success(&self, value: S) -> bool { - let value = value.into_bytes_with_nul(); + pub fn success(&self, value: S) -> bool { + let value = value.to_cstr(); unsafe { BNTypeArchiveMergeConflictSuccess( self.handle.as_ptr(), diff --git a/rust/src/type_container.rs b/rust/src/type_container.rs index 1535732d40..5941b31335 100644 --- a/rust/src/type_container.rs +++ b/rust/src/type_container.rs @@ -11,7 +11,7 @@ use crate::platform::Platform; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, Ref}; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::type_parser::{TypeParserError, TypeParserResult}; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; @@ -137,12 +137,8 @@ impl TypeContainer { /// (by id) to use the new name. /// /// Returns true if the type was renamed. - pub fn rename_type, S: BnStrCompatible>( - &self, - name: T, - type_id: S, - ) -> bool { - let type_id = type_id.into_bytes_with_nul(); + pub fn rename_type, S: AsCStr>(&self, name: T, type_id: S) -> bool { + let type_id = type_id.to_cstr(); let raw_name = QualifiedName::into_raw(name.into()); let success = unsafe { BNTypeContainerRenameType( @@ -159,8 +155,8 @@ impl TypeContainer { /// not specified and you may end up with broken references if any still exist. /// /// Returns true if the type was deleted. - pub fn delete_type(&self, type_id: S) -> bool { - let type_id = type_id.into_bytes_with_nul(); + pub fn delete_type(&self, type_id: S) -> bool { + let type_id = type_id.to_cstr(); unsafe { BNTypeContainerDeleteType( self.handle.as_ptr(), @@ -184,8 +180,8 @@ impl TypeContainer { /// Get the unique name of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_name(&self, type_id: S) -> Option { - let type_id = type_id.into_bytes_with_nul(); + pub fn type_name(&self, type_id: S) -> Option { + let type_id = type_id.to_cstr(); let mut result = BNQualifiedName::default(); let success = unsafe { BNTypeContainerGetTypeName( @@ -200,8 +196,8 @@ impl TypeContainer { /// Get the definition of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_by_id(&self, type_id: S) -> Option> { - let type_id = type_id.into_bytes_with_nul(); + pub fn type_by_id(&self, type_id: S) -> Option> { + let type_id = type_id.to_cstr(); let mut result = std::ptr::null_mut(); let success = unsafe { BNTypeContainerGetTypeById( @@ -305,12 +301,12 @@ impl TypeContainer { /// /// * `source` - Source code to parse /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing - pub fn parse_type_string( + pub fn parse_type_string( &self, source: S, import_dependencies: bool, ) -> Result> { - let source = source.into_bytes_with_nul(); + let source = source.to_cstr(); let mut result = BNQualifiedNameAndType::default(); let mut errors = std::ptr::null_mut(); let mut error_count = 0; @@ -351,33 +347,30 @@ impl TypeContainer { import_dependencies: bool, ) -> Result> where - S: BnStrCompatible, - F: BnStrCompatible, + S: AsCStr, + F: AsCStr, O: IntoIterator, - O::Item: BnStrCompatible, + O::Item: AsCStr, D: IntoIterator, - D::Item: BnStrCompatible, - A: BnStrCompatible, + D::Item: AsCStr, + A: AsCStr, { - let source = source.into_bytes_with_nul(); - let filename = filename.into_bytes_with_nul(); - let options: Vec<_> = options - .into_iter() - .map(|o| o.into_bytes_with_nul()) - .collect(); + let source = source.to_cstr(); + let filename = filename.to_cstr(); + let options: Vec<_> = options.into_iter().map(|o| o.to_cstr()).collect(); let options_raw: Vec<*const c_char> = options .iter() .map(|o| o.as_ref().as_ptr() as *const c_char) .collect(); let include_directories: Vec<_> = include_directories .into_iter() - .map(|d| d.into_bytes_with_nul()) + .map(|d| d.to_cstr()) .collect(); let include_directories_raw: Vec<*const c_char> = include_directories .iter() .map(|d| d.as_ref().as_ptr() as *const c_char) .collect(); - let auto_type_source = auto_type_source.into_bytes_with_nul(); + let auto_type_source = auto_type_source.to_cstr(); let mut raw_result = BNTypeParserResult::default(); let mut errors = std::ptr::null_mut(); let mut error_count = 0; diff --git a/rust/src/type_library.rs b/rust/src/type_library.rs index ee978513e9..91e86c61bc 100644 --- a/rust/src/type_library.rs +++ b/rust/src/type_library.rs @@ -7,7 +7,7 @@ use crate::{ metadata::Metadata, platform::Platform, rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}, - string::{BnStrCompatible, BnString}, + string::{AsCStr, BnString}, types::{QualifiedName, QualifiedNameAndType, Type}, }; @@ -42,8 +42,8 @@ impl TypeLibrary { } /// Creates an empty type library object with a random GUID and the provided name. - pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { - let name = name.into_bytes_with_nul(); + pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { + let name = name.to_cstr(); let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) }; unsafe { TypeLibrary::from_raw(ptr::NonNull::new(new_lib).unwrap()) } @@ -57,9 +57,9 @@ impl TypeLibrary { } /// Decompresses a type library file to a file on disk. - pub fn decompress_to_file(path: P, output: O) -> bool { - let path = path.into_bytes_with_nul(); - let output = output.into_bytes_with_nul(); + pub fn decompress_to_file(path: P, output: O) -> bool { + let path = path.to_cstr(); + let output = output.to_cstr(); unsafe { BNTypeLibraryDecompressToFile( path.as_ref().as_ptr() as *const ffi::c_char, @@ -69,16 +69,16 @@ impl TypeLibrary { } /// Loads a finalized type library instance from file - pub fn load_from_file(path: S) -> Option { - let path = path.into_bytes_with_nul(); + pub fn load_from_file(path: S) -> Option { + let path = path.to_cstr(); let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) } /// Saves a finalized type library instance to file - pub fn write_to_file(&self, path: S) -> bool { - let path = path.into_bytes_with_nul(); + pub fn write_to_file(&self, path: S) -> bool { + let path = path.to_cstr(); unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) } @@ -86,8 +86,8 @@ impl TypeLibrary { /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. - pub fn from_name(arch: CoreArchitecture, name: S) -> Option { - let name = name.into_bytes_with_nul(); + pub fn from_name(arch: CoreArchitecture, name: S) -> Option { + let name = name.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) }; @@ -95,8 +95,8 @@ impl TypeLibrary { } /// Attempts to grab a type library associated with the provided Architecture and GUID pair - pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { - let guid = guid.into_bytes_with_nul(); + pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { + let guid = guid.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ref().as_ptr() as *const ffi::c_char) }; @@ -117,8 +117,8 @@ impl TypeLibrary { } /// Sets the name of a type library instance that has not been finalized - pub fn set_name(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn set_name(&self, value: S) { + let value = value.to_cstr(); unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) } @@ -135,8 +135,8 @@ impl TypeLibrary { } /// Sets the dependency name of a type library instance that has not been finalized - pub fn set_dependency_name(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn set_dependency_name(&self, value: S) { + let value = value.to_cstr(); unsafe { BNSetTypeLibraryDependencyName( self.as_raw(), @@ -152,8 +152,8 @@ impl TypeLibrary { } /// Sets the GUID of a type library instance that has not been finalized - pub fn set_guid(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn set_guid(&self, value: S) { + let value = value.to_cstr(); unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) } @@ -168,8 +168,8 @@ impl TypeLibrary { } /// Adds an extra name to this type library used during library lookups and dependency resolution - pub fn add_alternate_name(&self, value: S) { - let value = value.into_bytes_with_nul(); + pub fn add_alternate_name(&self, value: S) { + let value = value.to_cstr(); unsafe { BNAddTypeLibraryAlternateName( self.as_raw(), @@ -212,8 +212,8 @@ impl TypeLibrary { } /// Retrieves a metadata associated with the given key stored in the type library - pub fn query_metadata(&self, key: S) -> Option { - let key = key.into_bytes_with_nul(); + pub fn query_metadata(&self, key: S) -> Option { + let key = key.to_cstr(); let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) }; @@ -231,8 +231,8 @@ impl TypeLibrary { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { - let key = key.into_bytes_with_nul(); + pub fn store_metadata(&self, key: S, md: &Metadata) { + let key = key.to_cstr(); unsafe { BNTypeLibraryStoreMetadata( self.as_raw(), @@ -243,8 +243,8 @@ impl TypeLibrary { } /// Removes the metadata associated with key from the current type library. - pub fn remove_metadata(&self, key: S) { - let key = key.into_bytes_with_nul(); + pub fn remove_metadata(&self, key: S) { + let key = key.to_cstr(); unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) } @@ -299,8 +299,8 @@ impl TypeLibrary { /// Use this api with extreme caution. /// /// - pub fn add_type_source(&self, name: QualifiedName, source: S) { - let source = source.into_bytes_with_nul(); + pub fn add_type_source(&self, name: QualifiedName, source: S) { + let source = source.to_cstr(); let mut raw_name = QualifiedName::into_raw(name); unsafe { BNAddTypeLibraryNamedTypeSource( diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index dbf5a709ad..1cfe346cd7 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -6,7 +6,7 @@ use std::ptr::NonNull; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; @@ -14,7 +14,7 @@ pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity; pub type TypeParserOption = BNTypeParserOption; /// Register a custom parser with the API -pub fn register_type_parser( +pub fn register_type_parser( name: S, parser: T, ) -> (&'static mut T, CoreTypeParser) { @@ -30,10 +30,7 @@ pub fn register_type_parser( freeErrorList: Some(cb_free_error_list), }; let result = unsafe { - BNRegisterTypeParser( - name.into_bytes_with_nul().as_ref().as_ptr() as *const _, - &mut callback, - ) + BNRegisterTypeParser(name.to_cstr().as_ref().as_ptr() as *const _, &mut callback) }; let core = unsafe { CoreTypeParser::from_raw(NonNull::new(result).unwrap()) }; (parser, core) @@ -55,8 +52,8 @@ impl CoreTypeParser { unsafe { Array::new(result, count, ()) } } - pub fn parser_by_name(name: S) -> Option { - let name_raw = name.into_bytes_with_nul(); + pub fn parser_by_name(name: S) -> Option { + let name_raw = name.to_cstr(); let result = unsafe { BNGetTypeParserByName(name_raw.as_ref().as_ptr() as *const c_char) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 67d3657035..b49832def2 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -4,7 +4,7 @@ use crate::binary_view::BinaryView; use crate::disassembly::InstructionTextToken; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use crate::type_container::TypeContainer; use crate::types::{NamedTypeReference, QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; @@ -15,7 +15,7 @@ pub type TokenEscapingType = BNTokenEscapingType; pub type TypeDefinitionLineType = BNTypeDefinitionLineType; /// Register a custom parser with the API -pub fn register_type_printer( +pub fn register_type_printer( name: S, parser: T, ) -> (&'static mut T, CoreTypePrinter) { @@ -36,7 +36,7 @@ pub fn register_type_printer( }; let result = unsafe { BNRegisterTypePrinter( - name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + name.to_cstr().as_ref().as_ptr() as *const c_char, &mut callback, ) }; @@ -61,8 +61,8 @@ impl CoreTypePrinter { unsafe { Array::new(result, count, ()) } } - pub fn printer_by_name(name: S) -> Option { - let name_raw = name.into_bytes_with_nul(); + pub fn printer_by_name(name: S) -> Option { + let name_raw = name.to_cstr(); let result = unsafe { BNGetTypePrinterByName(name_raw.as_ref().as_ptr() as *const c_char) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } diff --git a/rust/src/types.rs b/rust/src/types.rs index a46dce2ebe..710a885771 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -24,7 +24,7 @@ use crate::{ binary_view::{BinaryView, BinaryViewExt}, calling_convention::CoreCallingConvention, rc::*, - string::{BnStrCompatible, BnString}, + string::{AsCStr, BnString}, }; use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE}; @@ -258,10 +258,10 @@ impl TypeBuilder { } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { + pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data + let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data unsafe { Self::from_raw(BNCreateIntegerTypeBuilder( @@ -281,9 +281,9 @@ impl TypeBuilder { } } - pub fn named_float(width: usize, alt_name: S) -> Self { + pub fn named_float(width: usize, alt_name: S) -> Self { // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // See same line in `named_int` above + let alt_name = alt_name.to_cstr(); // See same line in `named_int` above unsafe { Self::from_raw(BNCreateFloatTypeBuilder( @@ -649,10 +649,10 @@ impl Type { } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { + pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data + let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data unsafe { Self::ref_from_raw(BNCreateIntegerType( @@ -672,9 +672,9 @@ impl Type { } } - pub fn named_float(width: usize, alt_name: S) -> Ref { + pub fn named_float(width: usize, alt_name: S) -> Ref { // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.into_bytes_with_nul(); // See same line in `named_int` above + let alt_name = alt_name.to_cstr(); // See same line in `named_int` above unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) } } @@ -1217,24 +1217,24 @@ impl EnumerationBuilder { unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) } } - pub fn append(&mut self, name: S) -> &mut Self { - let name = name.into_bytes_with_nul(); + pub fn append(&mut self, name: S) -> &mut Self { + let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _); } self } - pub fn insert(&mut self, name: S, value: u64) -> &mut Self { - let name = name.into_bytes_with_nul(); + pub fn insert(&mut self, name: S, value: u64) -> &mut Self { + let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value); } self } - pub fn replace(&mut self, id: usize, name: S, value: u64) -> &mut Self { - let name = name.into_bytes_with_nul(); + pub fn replace(&mut self, id: usize, name: S, value: u64) -> &mut Self { + let name = name.to_cstr(); unsafe { BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value); } @@ -1476,14 +1476,14 @@ impl StructureBuilder { self } - pub fn append<'a, S: BnStrCompatible, T: Into>>( + pub fn append<'a, S: AsCStr, T: Into>>( &mut self, ty: T, name: S, access: MemberAccess, scope: MemberScope, ) -> &mut Self { - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let owned_raw_ty = Conf::<&Type>::into_raw(ty.into()); unsafe { BNAddStructureBuilderMember( @@ -1513,7 +1513,7 @@ impl StructureBuilder { self } - pub fn insert<'a, S: BnStrCompatible, T: Into>>( + pub fn insert<'a, S: AsCStr, T: Into>>( &mut self, ty: T, name: S, @@ -1522,7 +1522,7 @@ impl StructureBuilder { access: MemberAccess, scope: MemberScope, ) -> &mut Self { - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let owned_raw_ty = Conf::<&Type>::into_raw(ty.into()); unsafe { BNAddStructureBuilderMemberAtOffset( @@ -1538,14 +1538,14 @@ impl StructureBuilder { self } - pub fn replace<'a, S: BnStrCompatible, T: Into>>( + pub fn replace<'a, S: AsCStr, T: Into>>( &mut self, index: usize, ty: T, name: S, overwrite_existing: bool, ) -> &mut Self { - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let owned_raw_ty = Conf::<&Type>::into_raw(ty.into()); unsafe { BNReplaceStructureBuilderMember( @@ -1870,12 +1870,12 @@ impl NamedTypeReference { /// You should not assign type ids yourself: if you use this to reference a type you are going /// to create but have not yet created, you may run into problems when giving your types to /// a BinaryView. - pub fn new_with_id, S: BnStrCompatible>( + pub fn new_with_id, S: AsCStr>( type_class: NamedTypeReferenceClass, type_id: S, name: T, ) -> Ref { - let type_id = type_id.into_bytes_with_nul(); + let type_id = type_id.to_cstr(); let mut raw_name = QualifiedName::into_raw(name.into()); let result = unsafe { Self::ref_from_raw(BNCreateNamedType( diff --git a/rust/src/websocket/client.rs b/rust/src/websocket/client.rs index 36c7bedd20..43e1e1f785 100644 --- a/rust/src/websocket/client.rs +++ b/rust/src/websocket/client.rs @@ -1,5 +1,5 @@ use crate::rc::{Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void, CStr}; use std::ptr::NonNull; @@ -21,8 +21,8 @@ pub trait WebsocketClient: Sync + Send { fn connect(&self, host: &str, headers: I) -> bool where I: IntoIterator, - K: BnStrCompatible, - V: BnStrCompatible; + K: AsCStr, + V: AsCStr; fn write(&self, data: &[u8]) -> bool; @@ -77,14 +77,14 @@ impl CoreWebsocketClient { ) -> bool where I: IntoIterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, C: WebsocketClientCallback, { - let url = host.into_bytes_with_nul(); + let url = host.to_cstr(); let (header_keys, header_values): (Vec, Vec) = headers .into_iter() - .map(|(k, v)| (k.into_bytes_with_nul(), v.into_bytes_with_nul())) + .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); let header_keys: Vec<*const c_char> = header_keys .iter() @@ -129,7 +129,7 @@ impl CoreWebsocketClient { /// Call the error callback function pub fn notify_error(&self, msg: &str) { - let error = msg.into_bytes_with_nul(); + let error = msg.to_cstr(); unsafe { BNNotifyWebsocketClientError(self.handle.as_ptr(), error.as_ptr() as *const c_char) } diff --git a/rust/src/websocket/provider.rs b/rust/src/websocket/provider.rs index 2d01fbc363..48c198d2b9 100644 --- a/rust/src/websocket/provider.rs +++ b/rust/src/websocket/provider.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use crate::websocket::client; use crate::websocket::client::{CoreWebsocketClient, WebsocketClient}; use binaryninjacore_sys::*; @@ -11,7 +11,7 @@ pub fn register_websocket_provider(name: &str) -> &'static mut W where W: WebsocketProvider, { - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); let provider_uninit = MaybeUninit::uninit(); // SAFETY: Websocket provider is never freed let leaked_provider = Box::leak(Box::new(provider_uninit)); @@ -80,8 +80,8 @@ impl CoreWebsocketProvider { unsafe { Array::new(result, count, ()) } } - pub fn by_name(name: S) -> Option { - let name = name.into_bytes_with_nul(); + pub fn by_name(name: S) -> Option { + let name = name.to_cstr(); let result = unsafe { BNGetWebsocketProviderByName(name.as_ref().as_ptr() as *const c_char) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) diff --git a/rust/src/worker_thread.rs b/rust/src/worker_thread.rs index 349456e5f3..aed872decf 100644 --- a/rust/src/worker_thread.rs +++ b/rust/src/worker_thread.rs @@ -1,4 +1,4 @@ -use crate::string::BnStrCompatible; +use crate::string::AsCStr; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void}; @@ -17,10 +17,10 @@ impl WorkerThreadActionExecutor { } } -pub fn execute_on_worker_thread(name: S, f: F) { +pub fn execute_on_worker_thread(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNWorkerEnqueueNamed( raw_executor as *mut c_void, @@ -30,10 +30,10 @@ pub fn execute_on_worker_thread(name: S, } } -pub fn execute_on_worker_thread_priority(name: S, f: F) { +pub fn execute_on_worker_thread_priority(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNWorkerPriorityEnqueueNamed( raw_executor as *mut c_void, @@ -43,10 +43,10 @@ pub fn execute_on_worker_thread_priority( } } -pub fn execute_on_worker_thread_interactive(name: S, f: F) { +pub fn execute_on_worker_thread_interactive(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); - let name = name.into_bytes_with_nul(); + let name = name.to_cstr(); unsafe { BNWorkerInteractiveEnqueueNamed( raw_executor as *mut c_void, diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 71a60824a7..b502381578 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -9,7 +9,7 @@ use crate::low_level_il::function::{LowLevelILFunction, Mutable, NonSSA, NonSSAV use crate::low_level_il::MutableLiftedILFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{AsCStr, BnString}; use std::ffi::{c_char, c_void}; use std::ptr::NonNull; @@ -108,8 +108,8 @@ impl AnalysisContext { } } - pub fn inform(&self, request: S) -> bool { - let request = request.into_bytes_with_nul(); + pub fn inform(&self, request: S) -> bool { + let request = request.to_cstr(); unsafe { BNAnalysisContextInform( self.handle.as_ptr(), @@ -166,9 +166,9 @@ impl Activity { Ref::new(Self { handle }) } - pub fn new(config: S) -> Ref { + pub fn new(config: S) -> Ref { unsafe extern "C" fn cb_action_nop(_: *mut c_void, _: *mut BNAnalysisContext) {} - let config = config.into_bytes_with_nul(); + let config = config.to_cstr(); let result = unsafe { BNCreateActivity( config.as_ref().as_ptr() as *const c_char, @@ -181,7 +181,7 @@ impl Activity { pub fn new_with_action(config: S, mut action: F) -> Ref where - S: BnStrCompatible, + S: AsCStr, F: FnMut(&AnalysisContext), { unsafe extern "C" fn cb_action( @@ -193,7 +193,7 @@ impl Activity { ctxt(&AnalysisContext::from_raw(analysis)) } } - let config = config.into_bytes_with_nul(); + let config = config.to_cstr(); let result = unsafe { BNCreateActivity( config.as_ref().as_ptr() as *const c_char, @@ -250,8 +250,8 @@ impl Workflow { /// Create a new unregistered [Workflow] with no activities. /// /// To get a copy of an existing registered [Workflow] use [Workflow::clone_to]. - pub fn new(name: S) -> Ref { - let name = name.into_bytes_with_nul(); + pub fn new(name: S) -> Ref { + let name = name.to_cstr(); let result = unsafe { BNCreateWorkflow(name.as_ref().as_ptr() as *const c_char) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -260,7 +260,7 @@ impl Workflow { /// /// * `name` - the name for the new [Workflow] #[must_use] - pub fn clone_to(&self, name: S) -> Ref { + pub fn clone_to(&self, name: S) -> Ref { self.clone_to_with_root(name, "") } @@ -269,13 +269,13 @@ impl Workflow { /// * `name` - the name for the new [Workflow] /// * `root_activity` - perform the clone operation with this activity as the root #[must_use] - pub fn clone_to_with_root( + pub fn clone_to_with_root( &self, name: S, root_activity: A, ) -> Ref { - let raw_name = name.into_bytes_with_nul(); - let activity = root_activity.into_bytes_with_nul(); + let raw_name = name.to_cstr(); + let activity = root_activity.to_cstr(); unsafe { Self::ref_from_raw( NonNull::new(BNWorkflowClone( @@ -288,10 +288,9 @@ impl Workflow { } } - pub fn instance(name: S) -> Ref { - let result = unsafe { - BNWorkflowInstance(name.into_bytes_with_nul().as_ref().as_ptr() as *const c_char) - }; + pub fn instance(name: S) -> Ref { + let result = + unsafe { BNWorkflowInstance(name.to_cstr().as_ref().as_ptr() as *const c_char) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -317,8 +316,8 @@ impl Workflow { /// Register this [Workflow], making it immutable and available for use. /// /// * `configuration` - a JSON representation of the workflow configuration - pub fn register_with_config(&self, config: S) -> Result<(), ()> { - let config = config.into_bytes_with_nul(); + pub fn register_with_config(&self, config: S) -> Result<(), ()> { + let config = config.to_cstr(); if unsafe { BNRegisterWorkflow( self.handle.as_ptr(), @@ -349,12 +348,9 @@ impl Workflow { ) -> Result, ()> where I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let subactivities_raw: Vec<_> = subactivities - .into_iter() - .map(|x| x.into_bytes_with_nul()) - .collect(); + let subactivities_raw: Vec<_> = subactivities.into_iter().map(|x| x.to_cstr()).collect(); let mut subactivities_ptr: Vec<*const _> = subactivities_raw .iter() .map(|x| x.as_ref().as_ptr() as *const c_char) @@ -372,11 +368,11 @@ impl Workflow { } /// Determine if an Activity exists in this [Workflow]. - pub fn contains(&self, activity: A) -> bool { + pub fn contains(&self, activity: A) -> bool { unsafe { BNWorkflowContains( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, ) } } @@ -390,11 +386,11 @@ impl Workflow { /// [Workflow], just for the given `activity`. /// /// `activity` - return the configuration for the `activity` - pub fn configuration_with_activity(&self, activity: A) -> String { + pub fn configuration_with_activity(&self, activity: A) -> String { let result = unsafe { BNWorkflowGetConfiguration( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, ) }; assert!(!result.is_null()); @@ -411,8 +407,8 @@ impl Workflow { } /// Retrieve the Activity object for the specified `name`. - pub fn activity(&self, name: A) -> Option> { - let name = name.into_bytes_with_nul(); + pub fn activity(&self, name: A) -> Option> { + let name = name.to_cstr(); let result = unsafe { BNWorkflowGetActivity( self.handle.as_ptr(), @@ -426,12 +422,12 @@ impl Workflow { /// specified just for the given `activity`. /// /// * `activity` - if specified, return the roots for the `activity` - pub fn activity_roots(&self, activity: A) -> Array { + pub fn activity_roots(&self, activity: A) -> Array { let mut count = 0; let result = unsafe { BNWorkflowGetActivityRoots( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, &mut count, ) }; @@ -443,16 +439,12 @@ impl Workflow { /// /// * `activity` - if specified, return the direct children and optionally the descendants of the `activity` (includes `activity`) /// * `immediate` - whether to include only direct children of `activity` or all descendants - pub fn subactivities( - &self, - activity: A, - immediate: bool, - ) -> Array { + pub fn subactivities(&self, activity: A, immediate: bool) -> Array { let mut count = 0; let result = unsafe { BNWorkflowGetSubactivities( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, immediate, &mut count, ) @@ -467,14 +459,11 @@ impl Workflow { /// * `activities` - the list of Activities to assign pub fn assign_subactivities(&self, activity: A, activities: I) -> bool where - A: BnStrCompatible, + A: AsCStr, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let input_list: Vec<_> = activities - .into_iter() - .map(|a| a.into_bytes_with_nul()) - .collect(); + let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); let mut input_list_ptr: Vec<*const _> = input_list .iter() .map(|x| x.as_ref().as_ptr() as *const c_char) @@ -482,7 +471,7 @@ impl Workflow { unsafe { BNWorkflowAssignSubactivities( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -500,14 +489,11 @@ impl Workflow { /// * `activities` - the list of Activities to insert pub fn insert(&self, activity: A, activities: I) -> bool where - A: BnStrCompatible, + A: AsCStr, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let input_list: Vec<_> = activities - .into_iter() - .map(|a| a.into_bytes_with_nul()) - .collect(); + let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); let mut input_list_ptr: Vec<*const _> = input_list .iter() .map(|x| x.as_ref().as_ptr() as *const c_char) @@ -515,7 +501,7 @@ impl Workflow { unsafe { BNWorkflowInsert( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -528,14 +514,11 @@ impl Workflow { /// * `activities` - the list of Activities to insert pub fn insert_after(&self, activity: A, activities: I) -> bool where - A: BnStrCompatible, + A: AsCStr, I: IntoIterator, - I::Item: BnStrCompatible, + I::Item: AsCStr, { - let input_list: Vec<_> = activities - .into_iter() - .map(|a| a.into_bytes_with_nul()) - .collect(); + let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); let mut input_list_ptr: Vec<*const _> = input_list .iter() .map(|x| x.as_ref().as_ptr() as *const c_char) @@ -543,7 +526,7 @@ impl Workflow { unsafe { BNWorkflowInsertAfter( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -551,11 +534,11 @@ impl Workflow { } /// Remove the specified `activity` - pub fn remove(&self, activity: A) -> bool { + pub fn remove(&self, activity: A) -> bool { unsafe { BNWorkflowRemove( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, ) } } @@ -564,16 +547,12 @@ impl Workflow { /// /// * `activity` - the Activity to replace /// * `new_activity` - the replacement Activity - pub fn replace( - &self, - activity: A, - new_activity: N, - ) -> bool { + pub fn replace(&self, activity: A, new_activity: N) -> bool { unsafe { BNWorkflowReplace( self.handle.as_ptr(), - activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, - new_activity.into_bytes_with_nul().as_ref().as_ptr() as *const c_char, + activity.to_cstr().as_ref().as_ptr() as *const c_char, + new_activity.to_cstr().as_ref().as_ptr() as *const c_char, ) } } @@ -582,13 +561,13 @@ impl Workflow { /// /// * `activity` - if specified, generate the Flowgraph using `activity` as the root /// * `sequential` - whether to generate a **Composite** or **Sequential** style graph - pub fn graph( + pub fn graph( &self, activity: A, sequential: Option, ) -> Option> { let sequential = sequential.unwrap_or(false); - let activity_name = activity.into_bytes_with_nul(); + let activity_name = activity.to_cstr(); let graph = unsafe { BNWorkflowGetGraph( self.handle.as_ptr(), diff --git a/rust/tests/binary_view.rs b/rust/tests/binary_view.rs index e48d5f5299..a240725369 100644 --- a/rust/tests/binary_view.rs +++ b/rust/tests/binary_view.rs @@ -29,7 +29,7 @@ fn test_binary_saving() { let modified_contents = view.read_vec(contents_addr, 4); assert_eq!(modified_contents, [0xff, 0xff, 0xff, 0xff]); - // HACK: To prevent us from deadlocking in save_to_path we wait for all main thread actions to finish. + // HACK: To prevent us from deadlocking in save_to_path, we wait for all main thread actions to finish. execute_on_main_thread_and_wait(|| {}); // Save the modified file @@ -56,7 +56,7 @@ fn test_binary_saving_database() { SymbolBuilder::new(SymbolType::Function, "test", entry_function.start()).create(); view.define_user_symbol(&new_entry_func_symbol); // Verify that we modified the binary - assert_eq!(entry_function.symbol().raw_name().as_str(), "test"); + assert_eq!(entry_function.symbol().raw_name().to_string_lossy(), "test"); // Save the modified database. assert!(view.file().create_database(out_dir.join("atox.obj.bndb"))); // Verify that the file exists and is modified. @@ -65,5 +65,8 @@ fn test_binary_saving_database() { let new_entry_function = new_view .entry_point_function() .expect("Failed to get entry point function"); - assert_eq!(new_entry_function.symbol().raw_name().as_str(), "test"); + assert_eq!( + new_entry_function.symbol().raw_name().to_string_lossy(), + "test" + ); } diff --git a/rust/tests/websocket.rs b/rust/tests/websocket.rs index 97a4ae2bac..01d2d79125 100644 --- a/rust/tests/websocket.rs +++ b/rust/tests/websocket.rs @@ -1,6 +1,6 @@ use binaryninja::headless::Session; use binaryninja::rc::Ref; -use binaryninja::string::BnStrCompatible; +use binaryninja::string::AsCStr; use binaryninja::websocket::{ register_websocket_provider, CoreWebsocketClient, CoreWebsocketProvider, WebsocketClient, WebsocketClientCallback, WebsocketProvider, @@ -34,8 +34,8 @@ impl WebsocketClient for MyWebsocketClient { fn connect(&self, host: &str, _headers: I) -> bool where I: IntoIterator, - K: BnStrCompatible, - V: BnStrCompatible, + K: AsCStr, + V: AsCStr, { assert_eq!(host, "url"); true From cb0d31dccd2e8fa404dcd601de7434bd150d3425 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 19:47:55 -0400 Subject: [PATCH 09/54] [Rust] Simplify usage surrounding c strings `cstring.as_ref().as_ptr() as *const c_char` -> `cstring.as_ptr()` `cstring.as_ref().as_ptr() as *mut _` -> `cstring.as_ptr()` `cstring.as_ptr() as *const c_char` -> `cstring.as_ptr()` With a few fixes for cstrings that might be dropped prematurely. --- rust/src/architecture.rs | 10 +- rust/src/background_task.rs | 6 +- rust/src/binary_view.rs | 131 ++++++++------------------- rust/src/binary_view/memory_map.rs | 74 +++------------ rust/src/calling_convention.rs | 2 +- rust/src/collaboration.rs | 31 ++----- rust/src/collaboration/changeset.rs | 8 +- rust/src/collaboration/file.rs | 35 ++----- rust/src/collaboration/folder.rs | 16 +--- rust/src/collaboration/group.rs | 20 +--- rust/src/collaboration/merge.rs | 27 ++---- rust/src/collaboration/project.rs | 98 +++++--------------- rust/src/collaboration/remote.rs | 99 +++++--------------- rust/src/collaboration/snapshot.rs | 4 +- rust/src/collaboration/sync.rs | 12 +-- rust/src/collaboration/user.rs | 17 +--- rust/src/command.rs | 16 ++-- rust/src/component.rs | 7 +- rust/src/custom_binary_view.rs | 8 +- rust/src/database.rs | 20 ++-- rust/src/database/kvs.rs | 7 +- rust/src/database/snapshot.rs | 4 +- rust/src/debuginfo.rs | 105 ++++++--------------- rust/src/demangle.rs | 23 ++--- rust/src/download_provider.rs | 18 ++-- rust/src/external_library.rs | 14 ++- rust/src/file_metadata.rs | 6 +- rust/src/function.rs | 6 +- rust/src/interaction.rs | 127 +++++++++++--------------- rust/src/lib.rs | 22 ++--- rust/src/logger.rs | 6 +- rust/src/medium_level_il/function.rs | 9 +- rust/src/metadata.rs | 52 +++-------- rust/src/platform.rs | 24 ++--- rust/src/project.rs | 98 +++++++------------- rust/src/project/file.rs | 22 +---- rust/src/project/folder.rs | 18 +--- rust/src/render_layer.rs | 14 +-- rust/src/repository.rs | 7 +- rust/src/repository/manager.rs | 18 +--- rust/src/secrets_provider.rs | 27 ++---- rust/src/section.rs | 17 ++-- rust/src/settings.rs | 108 +++++++--------------- rust/src/string.rs | 9 ++ rust/src/tags.rs | 10 +- rust/src/template_simplifier.rs | 9 +- rust/src/type_archive.rs | 75 +++++---------- rust/src/type_container.rs | 47 +++------- rust/src/type_parser.rs | 7 +- rust/src/type_printer.rs | 10 +- rust/src/update.rs | 19 ++-- rust/src/websocket/client.rs | 14 +-- rust/src/websocket/provider.rs | 7 +- rust/src/worker_thread.rs | 8 +- rust/src/workflow.rs | 123 ++++++++----------------- 55 files changed, 539 insertions(+), 1192 deletions(-) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 74a8dfa409..626938001a 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1404,7 +1404,8 @@ impl CoreArchitecture { } pub fn by_name(name: &str) -> Option { - let handle = unsafe { BNGetArchitectureByName(name.to_cstr().as_ptr() as *mut _) }; + let name = name.to_cstr(); + let handle = unsafe { BNGetArchitectureByName(name.as_ptr()) }; match handle.is_null() { false => Some(CoreArchitecture { handle }), true => None, @@ -1955,9 +1956,7 @@ pub trait ArchitectureExt: Architecture { fn register_by_name(&self, name: S) -> Option { let name = name.to_cstr(); - match unsafe { - BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ref().as_ptr() as *mut _) - } { + match unsafe { BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ptr()) } { 0xffff_ffff => None, reg => self.register_from_id(reg.into()), } @@ -3220,8 +3219,7 @@ where }; unsafe { - let res = - BNRegisterArchitecture(name.as_ref().as_ptr() as *mut _, &mut custom_arch as *mut _); + let res = BNRegisterArchitecture(name.as_ptr(), &mut custom_arch as *mut _); assert!(!res.is_null()); diff --git a/rust/src/background_task.rs b/rust/src/background_task.rs index c9059aca89..95bdda0bb9 100644 --- a/rust/src/background_task.rs +++ b/rust/src/background_task.rs @@ -45,7 +45,7 @@ impl BackgroundTask { pub fn new(initial_text: S, can_cancel: bool) -> Ref { let text = initial_text.to_cstr(); - let handle = unsafe { BNBeginBackgroundTask(text.as_ref().as_ptr() as *mut _, can_cancel) }; + let handle = unsafe { BNBeginBackgroundTask(text.as_ptr(), can_cancel) }; // We should always be returned a valid task. assert!(!handle.is_null()); unsafe { Ref::new(Self { handle }) } @@ -77,9 +77,7 @@ impl BackgroundTask { pub fn set_progress_text(&self, text: S) { let progress_text = text.to_cstr(); - unsafe { - BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ref().as_ptr() as *mut _) - } + unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ptr()) } } pub fn running_tasks() -> Array { diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 854f58f4db..a0fb9081aa 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -267,12 +267,8 @@ pub trait BinaryViewExt: BinaryViewBase { } fn add_analysis_option(&self, name: impl AsCStr) { - unsafe { - BNAddAnalysisOption( - self.as_ref().handle, - name.to_cstr().as_ref().as_ptr() as *mut _, - ) - } + let name = name.to_cstr(); + unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_ptr()) } } fn has_initial_analysis(&self) -> bool { @@ -409,7 +405,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { let raw_sym_ptr = BNGetSymbolByRawName( self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, + raw_name.as_ptr(), std::ptr::null_mut(), ); match raw_sym_ptr.is_null() { @@ -435,7 +431,7 @@ pub trait BinaryViewExt: BinaryViewBase { let mut count = 0; let handles = BNGetSymbolsByName( self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, + raw_name.as_ptr(), &mut count, std::ptr::null_mut(), ); @@ -768,10 +764,9 @@ pub trait BinaryViewExt: BinaryViewBase { } fn type_by_id(&self, id: S) -> Option> { + let id_str = id.to_cstr(); unsafe { - let id_str = id.to_cstr(); - let type_handle = - BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); + let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ptr()); if type_handle.is_null() { return None; } @@ -780,10 +775,9 @@ pub trait BinaryViewExt: BinaryViewBase { } fn type_name_by_id(&self, id: S) -> Option { + let id_str = id.to_cstr(); unsafe { - let id_str = id.to_cstr(); - let name_handle = - BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ref().as_ptr() as *mut _); + let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ptr()); let name = QualifiedName::from_owned_raw(name_handle); // The core will return an empty qualified name if no type name was found. match name.items.is_empty() { @@ -879,7 +873,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn remove_auto_section(&self, name: S) { let raw_name = name.to_cstr(); - let raw_name_ptr = raw_name.as_ref().as_ptr() as *mut _; + let raw_name_ptr = raw_name.as_ptr(); unsafe { BNRemoveAutoSection(self.as_ref().handle, raw_name_ptr); } @@ -887,7 +881,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn remove_user_section(&self, name: S) { let raw_name = name.to_cstr(); - let raw_name_ptr = raw_name.as_ref().as_ptr() as *mut _; + let raw_name_ptr = raw_name.as_ptr(); unsafe { BNRemoveUserSection(self.as_ref().handle, raw_name_ptr); } @@ -896,7 +890,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn section_by_name(&self, name: S) -> Option> { unsafe { let raw_name = name.to_cstr(); - let name_ptr = raw_name.as_ref().as_ptr() as *mut _; + let name_ptr = raw_name.as_ptr(); let raw_section_ptr = BNGetSectionByName(self.as_ref().handle, name_ptr); match raw_section_ptr.is_null() { false => Some(Section::ref_from_raw(raw_section_ptr)), @@ -1112,22 +1106,14 @@ pub trait BinaryViewExt: BinaryViewBase { fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { let raw_name = raw_name.to_cstr(); unsafe { - BNShowGraphReport( - self.as_ref().handle, - raw_name.as_ref().as_ptr() as *mut _, - graph.handle, - ); + BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle); } } fn load_settings(&self, view_type_name: S) -> Result> { let view_type_name = view_type_name.to_cstr(); - let settings_handle = unsafe { - BNBinaryViewGetLoadSettings( - self.as_ref().handle, - view_type_name.as_ref().as_ptr() as *mut _, - ) - }; + let settings_handle = + unsafe { BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_ptr()) }; if settings_handle.is_null() { Err(()) @@ -1142,7 +1128,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNBinaryViewSetLoadSettings( self.as_ref().handle, - view_type_name.as_ref().as_ptr() as *mut _, + view_type_name.as_ptr(), settings.handle, ) }; @@ -1170,7 +1156,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn tag_type_by_name(&self, name: S) -> Option> { let name = name.to_cstr(); unsafe { - let handle = BNGetTagType(self.as_ref().handle, name.as_ref().as_ptr() as *mut _); + let handle = BNGetTagType(self.as_ref().handle, name.as_ptr()); if handle.is_null() { return None; } @@ -1184,7 +1170,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn tag_by_id(&self, id: S) -> Option> { let id = id.to_cstr(); unsafe { - let handle = BNGetTag(self.as_ref().handle, id.as_ref().as_ptr() as *mut _); + let handle = BNGetTag(self.as_ref().handle, id.as_ptr()); if handle.is_null() { return None; } @@ -1234,13 +1220,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// function use [`Function::set_comment_at`] fn set_comment_at(&self, addr: u64, comment: impl AsCStr) { let comment_raw = comment.to_cstr(); - unsafe { - BNSetGlobalCommentForAddress( - self.as_ref().handle, - addr, - comment_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNSetGlobalCommentForAddress(self.as_ref().handle, addr, comment_raw.as_ptr()) } } /// Retrieves a list of the next disassembly lines. @@ -1292,12 +1272,9 @@ pub trait BinaryViewExt: BinaryViewBase { } fn query_metadata(&self, key: S) -> Option> { - let value: *mut BNMetadata = unsafe { - BNBinaryViewQueryMetadata( - self.as_ref().handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, - ) - }; + let key = key.to_cstr(); + let value: *mut BNMetadata = + unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_ptr()) }; if value.is_null() { None } else { @@ -1318,10 +1295,11 @@ pub trait BinaryViewExt: BinaryViewBase { V: Into>, { let md = value.into(); + let key = key.to_cstr(); unsafe { BNBinaryViewStoreMetadata( self.as_ref().handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, + key.as_ptr(), md.as_ref().handle, is_auto, ) @@ -1329,12 +1307,8 @@ pub trait BinaryViewExt: BinaryViewBase { } fn remove_metadata(&self, key: S) { - unsafe { - BNBinaryViewRemoveMetadata( - self.as_ref().handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, - ) - }; + let key = key.to_cstr(); + unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) }; } /// Retrieves a list of [CodeReference]s pointing to a given address. @@ -1460,12 +1434,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn component_by_guid(&self, guid: S) -> Option> { let name = guid.to_cstr(); - let result = unsafe { - BNGetComponentByGuid( - self.as_ref().handle, - name.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } @@ -1476,12 +1445,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn component_by_path(&self, path: P) -> Option> { let path = path.to_cstr(); - let result = unsafe { - BNGetComponentByPath( - self.as_ref().handle, - path.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } @@ -1491,12 +1455,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn remove_component_by_guid(&self, guid: P) -> bool { let path = guid.to_cstr(); - unsafe { - BNRemoveComponentByGuid( - self.as_ref().handle, - path.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } } fn data_variable_parent_components(&self, data_variable: &DataVariable) -> Array { @@ -1519,24 +1478,15 @@ pub trait BinaryViewExt: BinaryViewBase { fn external_library(&self, name: S) -> Option> { let name_ptr = name.to_cstr(); - let result = unsafe { - BNBinaryViewGetExternalLibrary( - self.as_ref().handle, - name_ptr.as_ref().as_ptr() as *const c_char, - ) - }; + let result = + unsafe { BNBinaryViewGetExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; let result_ptr = NonNull::new(result)?; Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) } fn remove_external_library(&self, name: S) { let name_ptr = name.to_cstr(); - unsafe { - BNBinaryViewRemoveExternalLibrary( - self.as_ref().handle, - name_ptr.as_ref().as_ptr() as *const c_char, - ) - }; + unsafe { BNBinaryViewRemoveExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; } fn add_external_library( @@ -1549,7 +1499,7 @@ pub trait BinaryViewExt: BinaryViewBase { let result = unsafe { BNBinaryViewAddExternalLibrary( self.as_ref().handle, - name_ptr.as_ref().as_ptr() as *const c_char, + name_ptr.as_ptr(), backing_file .map(|b| b.handle.as_ptr()) .unwrap_or(std::ptr::null_mut()), @@ -1598,7 +1548,7 @@ pub trait BinaryViewExt: BinaryViewBase { self.as_ref().handle, symbol.handle, library.handle.as_ptr(), - target_symbol_name.as_ref().as_ptr() as *const c_char, + target_symbol_name.as_ptr(), target_address_ptr, target_is_auto, ) @@ -1641,12 +1591,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn type_library_by_name(&self, name: S) -> Option { let name = name.to_cstr(); - let result = unsafe { - BNGetBinaryViewTypeLibrary( - self.as_ref().handle, - name.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) }) } @@ -1739,12 +1684,8 @@ pub trait BinaryViewExt: BinaryViewBase { /// Dict[string_guid, Tuple[string_type_name, type_library_name]] fn import_type_by_guid(&self, guid: S) -> Option> { let guid = guid.to_cstr(); - let result = unsafe { - BNBinaryViewImportTypeLibraryTypeByGuid( - self.as_ref().handle, - guid.as_ref().as_ptr() as *const c_char, - ) - }; + let result = + unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index b173744066..3afe0a20a3 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -5,7 +5,6 @@ use crate::rc::Ref; use crate::segment::SegmentFlags; use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; -use std::ffi::c_char; #[derive(PartialEq, Eq, Hash)] pub struct MemoryMap { @@ -52,7 +51,7 @@ impl MemoryMap { unsafe { BNAddBinaryMemoryRegion( self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), start, view.handle, segment_flags.unwrap_or_default().into_raw(), @@ -71,7 +70,7 @@ impl MemoryMap { unsafe { BNAddDataMemoryRegion( self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), start, data.as_raw(), segment_flags.unwrap_or_default().into_raw(), @@ -90,7 +89,7 @@ impl MemoryMap { unsafe { BNAddRemoteMemoryRegion( self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), start, &mut accessor.api_object, segment_flags.unwrap_or_default().into_raw(), @@ -100,12 +99,7 @@ impl MemoryMap { pub fn remove_memory_region(&mut self, name: impl AsCStr) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNRemoveMemoryRegion( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNRemoveMemoryRegion(self.view.handle, name_raw.as_ptr()) } } pub fn active_memory_region_at(&self, addr: u64) -> String { @@ -117,88 +111,44 @@ impl MemoryMap { pub fn memory_region_flags(&self, name: impl AsCStr) -> SegmentFlags { let name_raw = name.to_cstr(); - let flags_raw = unsafe { - BNGetMemoryRegionFlags( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - ) - }; + let flags_raw = unsafe { BNGetMemoryRegionFlags(self.view.handle, name_raw.as_ptr()) }; SegmentFlags::from_raw(flags_raw) } pub fn set_memory_region_flags(&mut self, name: impl AsCStr, flags: SegmentFlags) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNSetMemoryRegionFlags( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - flags.into_raw(), - ) - } + unsafe { BNSetMemoryRegionFlags(self.view.handle, name_raw.as_ptr(), flags.into_raw()) } } pub fn is_memory_region_enabled(&self, name: impl AsCStr) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNIsMemoryRegionEnabled( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNIsMemoryRegionEnabled(self.view.handle, name_raw.as_ptr()) } } pub fn set_memory_region_enabled(&mut self, name: impl AsCStr, enabled: bool) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNSetMemoryRegionEnabled( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - enabled, - ) - } + unsafe { BNSetMemoryRegionEnabled(self.view.handle, name_raw.as_ptr(), enabled) } } // TODO: Should we just call this is_memory_region_relocatable? pub fn is_memory_region_rebaseable(&self, name: impl AsCStr) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNIsMemoryRegionRebaseable( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNIsMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr()) } } pub fn set_memory_region_rebaseable(&mut self, name: impl AsCStr, enabled: bool) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNSetMemoryRegionRebaseable( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - enabled, - ) - } + unsafe { BNSetMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr(), enabled) } } pub fn memory_region_fill(&self, name: impl AsCStr) -> u8 { let name_raw = name.to_cstr(); - unsafe { - BNGetMemoryRegionFill( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNGetMemoryRegionFill(self.view.handle, name_raw.as_ptr()) } } pub fn set_memory_region_fill(&mut self, name: impl AsCStr, fill: u8) -> bool { let name_raw = name.to_cstr(); - unsafe { - BNSetMemoryRegionFill( - self.view.handle, - name_raw.as_ref().as_ptr() as *const c_char, - fill, - ) - } + unsafe { BNSetMemoryRegionFill(self.view.handle, name_raw.as_ptr(), fill) } } pub fn reset(&mut self) { diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs index f0f0ba4cf7..7db61d8afc 100644 --- a/rust/src/calling_convention.rs +++ b/rust/src/calling_convention.rs @@ -413,7 +413,7 @@ where }; unsafe { - let cc_name = name.as_ref().as_ptr() as *mut _; + let cc_name = name.as_ptr(); let result = BNCreateCallingConvention(arch.as_ref().handle, cc_name, &mut cc); assert!(!result.is_null()); diff --git a/rust/src/collaboration.rs b/rust/src/collaboration.rs index 1f76dc9acf..8a1774f2bc 100644 --- a/rust/src/collaboration.rs +++ b/rust/src/collaboration.rs @@ -75,22 +75,21 @@ pub fn known_remotes() -> Array { /// Get Remote by unique `id` pub fn get_remote_by_id(id: S) -> Option> { let id = id.to_cstr(); - let value = unsafe { BNCollaborationGetRemoteById(id.as_ref().as_ptr() as *const c_char) }; + let value = unsafe { BNCollaborationGetRemoteById(id.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `address` pub fn get_remote_by_address(address: S) -> Option> { let address = address.to_cstr(); - let value = - unsafe { BNCollaborationGetRemoteByAddress(address.as_ref().as_ptr() as *const c_char) }; + let value = unsafe { BNCollaborationGetRemoteByAddress(address.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `name` pub fn get_remote_by_name(name: S) -> Option> { let name = name.to_cstr(); - let value = unsafe { BNCollaborationGetRemoteByName(name.as_ref().as_ptr() as *const c_char) }; + let value = unsafe { BNCollaborationGetRemoteByName(name.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } @@ -116,17 +115,11 @@ where .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let data_keys_ptr: Box<[*const c_char]> = data_keys - .iter() - .map(|k| k.as_ref().as_ptr() as *const c_char) - .collect(); - let data_values_ptr: Box<[*const c_char]> = data_values - .iter() - .map(|v| v.as_ref().as_ptr() as *const c_char) - .collect(); + let data_keys_ptr: Box<[*const c_char]> = data_keys.iter().map(|k| k.as_ptr()).collect(); + let data_values_ptr: Box<[*const c_char]> = data_values.iter().map(|v| v.as_ptr()).collect(); unsafe { BNCollaborationStoreDataInKeychain( - key.as_ref().as_ptr() as *const c_char, + key.as_ptr(), data_keys_ptr.as_ptr() as *mut _, data_values_ptr.as_ptr() as *mut _, data_keys.len(), @@ -136,20 +129,14 @@ where pub fn has_data_in_keychain(key: K) -> bool { let key = key.to_cstr(); - unsafe { BNCollaborationHasDataInKeychain(key.as_ref().as_ptr() as *const c_char) } + unsafe { BNCollaborationHasDataInKeychain(key.as_ptr()) } } pub fn get_data_from_keychain(key: K) -> Option<(Array, Array)> { let key = key.to_cstr(); let mut keys = std::ptr::null_mut(); let mut values = std::ptr::null_mut(); - let count = unsafe { - BNCollaborationGetDataFromKeychain( - key.as_ref().as_ptr() as *const c_char, - &mut keys, - &mut values, - ) - }; + let count = unsafe { BNCollaborationGetDataFromKeychain(key.as_ptr(), &mut keys, &mut values) }; let keys = (!keys.is_null()).then(|| unsafe { Array::new(keys, count, ()) }); let values = (!values.is_null()).then(|| unsafe { Array::new(values, count, ()) }); keys.zip(values) @@ -157,5 +144,5 @@ pub fn get_data_from_keychain(key: K) -> Option<(Array, Arr pub fn delete_data_from_keychain(key: K) -> bool { let key = key.to_cstr(); - unsafe { BNCollaborationDeleteDataFromKeychain(key.as_ref().as_ptr() as *const c_char) } + unsafe { BNCollaborationDeleteDataFromKeychain(key.as_ptr()) } } diff --git a/rust/src/collaboration/changeset.rs b/rust/src/collaboration/changeset.rs index 1cc30d765e..0db384cb93 100644 --- a/rust/src/collaboration/changeset.rs +++ b/rust/src/collaboration/changeset.rs @@ -1,5 +1,4 @@ use binaryninjacore_sys::*; -use std::ffi::c_char; use std::ptr::NonNull; use super::{RemoteFile, RemoteUser}; @@ -68,12 +67,7 @@ impl Changeset { /// Set the name of the changeset, e.g. in a name changeset function. pub fn set_name(&self, value: S) -> bool { let value = value.to_cstr(); - unsafe { - BNCollaborationChangesetSetName( - self.handle.as_ptr(), - value.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNCollaborationChangesetSetName(self.handle.as_ptr(), value.as_ptr()) } } } diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index 2089fbb7e4..251b4f7d53 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::fmt::{Debug, Formatter}; use std::ptr::NonNull; use std::time::SystemTime; @@ -96,12 +96,7 @@ impl RemoteFile { pub fn set_metadata(&self, folder: S) -> Result<(), ()> { let folder_raw = folder.to_cstr(); - let success = unsafe { - BNRemoteFileSetMetadata( - self.handle.as_ptr(), - folder_raw.as_ref().as_ptr() as *const c_char, - ) - }; + let success = unsafe { BNRemoteFileSetMetadata(self.handle.as_ptr(), folder_raw.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -192,12 +187,7 @@ impl RemoteFile { /// Set the description of the file. You will need to push the file to update the remote version. pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); - let success = unsafe { - BNRemoteFileSetName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let success = unsafe { BNRemoteFileSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -211,12 +201,8 @@ impl RemoteFile { /// Set the description of the file. You will need to push the file to update the remote version. pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); - let success = unsafe { - BNRemoteFileSetDescription( - self.handle.as_ptr(), - description.as_ref().as_ptr() as *const c_char, - ) - }; + let success = + unsafe { BNRemoteFileSetDescription(self.handle.as_ptr(), description.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -269,9 +255,7 @@ impl RemoteFile { self.pull_snapshots()?; } let id = id.to_cstr(); - let result = unsafe { - BNRemoteFileGetSnapshotById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNRemoteFileGetSnapshotById(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(result).map(|handle| unsafe { RemoteSnapshot::ref_from_raw(handle) })) } @@ -350,14 +334,11 @@ impl RemoteFile { { let name = name.to_cstr(); let parent_ids: Vec<_> = parent_ids.into_iter().map(|id| id.to_cstr()).collect(); - let mut parent_ids_raw: Vec<_> = parent_ids - .iter() - .map(|x| x.as_ref().as_ptr() as *const c_char) - .collect(); + let mut parent_ids_raw: Vec<_> = parent_ids.iter().map(|x| x.as_ptr()).collect(); let result = unsafe { BNRemoteFileCreateSnapshot( self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), contents.as_mut_ptr(), contents.len(), analysis_cache_contexts.as_mut_ptr(), diff --git a/rust/src/collaboration/folder.rs b/rust/src/collaboration/folder.rs index 0fd2bf874f..b5fde3b47e 100644 --- a/rust/src/collaboration/folder.rs +++ b/rust/src/collaboration/folder.rs @@ -1,6 +1,5 @@ use super::{Remote, RemoteProject}; use binaryninjacore_sys::*; -use std::ffi::c_char; use std::ptr::NonNull; use crate::project::folder::ProjectFolder; @@ -106,12 +105,7 @@ impl RemoteFolder { /// Set the display name of the folder. You will need to push the folder to update the remote version. pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); - let success = unsafe { - BNRemoteFolderSetName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let success = unsafe { BNRemoteFolderSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -125,12 +119,8 @@ impl RemoteFolder { /// Set the description of the folder. You will need to push the folder to update the remote version. pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); - let success = unsafe { - BNRemoteFolderSetDescription( - self.handle.as_ptr(), - description.as_ref().as_ptr() as *const c_char, - ) - }; + let success = + unsafe { BNRemoteFolderSetDescription(self.handle.as_ptr(), description.as_ptr()) }; success.then_some(()).ok_or(()) } } diff --git a/rust/src/collaboration/group.rs b/rust/src/collaboration/group.rs index 942535199b..b8b32c7a20 100644 --- a/rust/src/collaboration/group.rs +++ b/rust/src/collaboration/group.rs @@ -2,7 +2,6 @@ use super::Remote; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{AsCStr, BnString}; use binaryninjacore_sys::*; -use std::ffi::c_char; use std::fmt; use std::fmt::{Display, Formatter}; use std::ptr::NonNull; @@ -52,12 +51,7 @@ impl RemoteGroup { /// You will need to push the group to update the Remote. pub fn set_name(&self, name: U) { let name = name.to_cstr(); - unsafe { - BNCollaborationGroupSetName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNCollaborationGroupSetName(self.handle.as_ptr(), name.as_ptr()) } } /// Get list of users in the group @@ -93,10 +87,7 @@ impl RemoteGroup { I::Item: AsCStr, { let usernames: Vec<_> = usernames.into_iter().map(|u| u.to_cstr()).collect(); - let mut usernames_raw: Vec<_> = usernames - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut usernames_raw: Vec<_> = usernames.iter().map(|s| s.as_ptr()).collect(); // TODO: This should only fail if collaboration is not supported. // TODO: Because you should not have a RemoteGroup at that point we can ignore? // TODO: Do you need any permissions to do this? @@ -113,12 +104,7 @@ impl RemoteGroup { /// Test if a group has a user with the given username pub fn contains_user(&self, username: U) -> bool { let username = username.to_cstr(); - unsafe { - BNCollaborationGroupContainsUser( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNCollaborationGroupContainsUser(self.handle.as_ptr(), username.as_ptr()) } } } diff --git a/rust/src/collaboration/merge.rs b/rust/src/collaboration/merge.rs index 84aa619276..2fb5b3de17 100644 --- a/rust/src/collaboration/merge.rs +++ b/rust/src/collaboration/merge.rs @@ -1,5 +1,4 @@ use binaryninjacore_sys::*; -use std::ffi::c_char; use std::ptr::NonNull; use crate::database::{snapshot::Snapshot, Database}; @@ -52,10 +51,7 @@ impl MergeConflict { pub fn path_item_string(&self, path: S) -> Result { let path = path.to_cstr(); let result = unsafe { - BNAnalysisMergeConflictGetPathItemString( - self.handle.as_ptr(), - path.as_ref().as_ptr() as *const c_char, - ) + BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path.as_ptr()) }; (!result.is_null()) .then(|| unsafe { BnString::from_raw(result) }) @@ -125,24 +121,16 @@ impl MergeConflict { /// Call this when you've resolved the conflict to save the result pub fn success(&self, value: S) -> Result<(), ()> { let value = value.to_cstr(); - let success = unsafe { - BNAnalysisMergeConflictSuccess( - self.handle.as_ptr(), - value.as_ref().as_ptr() as *const c_char, - ) - }; + let success = + unsafe { BNAnalysisMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) }; success.then_some(()).ok_or(()) } // TODO: Make a safe version of this that checks the path and if it holds a number pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { let path_key = path_key.to_cstr(); - let value = unsafe { - BNAnalysisMergeConflictGetPathItem( - self.handle.as_ptr(), - path_key.as_ref().as_ptr() as *const c_char, - ) - }; + let value = + unsafe { BNAnalysisMergeConflictGetPathItem(self.handle.as_ptr(), path_key.as_ptr()) }; match value.is_null() { // SAFETY: The path must be a number. false => Some(value as u64), @@ -153,10 +141,7 @@ impl MergeConflict { pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { let path_key = path_key.to_cstr(); let value = unsafe { - BNAnalysisMergeConflictGetPathItemString( - self.handle.as_ptr(), - path_key.as_ref().as_ptr() as *const c_char, - ) + BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path_key.as_ptr()) }; match value.is_null() { false => Some(unsafe { BnString::from_raw(value) }), diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index 8c04080b23..fce2a5f67c 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::ptr::NonNull; use std::time::SystemTime; @@ -138,12 +138,7 @@ impl RemoteProject { /// Set the description of the file. You will need to push the file to update the remote version. pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); - let success = unsafe { - BNRemoteProjectSetName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let success = unsafe { BNRemoteProjectSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -157,12 +152,8 @@ impl RemoteProject { /// Set the description of the file. You will need to push the file to update the remote version. pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); - let success = unsafe { - BNRemoteProjectSetDescription( - self.handle.as_ptr(), - description.as_ref().as_ptr() as *const c_char, - ) - }; + let success = + unsafe { BNRemoteProjectSetDescription(self.handle.as_ptr(), description.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -236,9 +227,7 @@ impl RemoteProject { self.pull_files()?; } let id = id.to_cstr(); - let result = unsafe { - BNRemoteProjectGetFileById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNRemoteProjectGetFileById(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(result).map(|handle| unsafe { RemoteFile::ref_from_raw(handle) })) } @@ -252,12 +241,7 @@ impl RemoteProject { self.pull_files()?; } let id = name.to_cstr(); - let result = unsafe { - BNRemoteProjectGetFileByName( - self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNRemoteProjectGetFileByName(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(result).map(|handle| unsafe { RemoteFile::ref_from_raw(handle) })) } @@ -360,11 +344,11 @@ impl RemoteProject { let file_ptr = unsafe { BNRemoteProjectCreateFile( self.handle.as_ptr(), - filename.as_ref().as_ptr() as *const c_char, + filename.as_ptr(), contents.as_ptr() as *mut _, contents.len(), - name.as_ref().as_ptr() as *const c_char, - description.as_ref().as_ptr() as *const c_char, + name.as_ptr(), + description.as_ptr(), folder_handle, file_type, Some(P::cb_progress_callback), @@ -393,14 +377,8 @@ impl RemoteProject { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); - let mut values_raw = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); + let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::>(); + let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::>(); let success = unsafe { BNRemoteProjectPushFile( self.handle.as_ptr(), @@ -449,12 +427,7 @@ impl RemoteProject { self.pull_folders()?; } let id = id.to_cstr(); - let result = unsafe { - BNRemoteProjectGetFolderById( - self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNRemoteProjectGetFolderById(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(result).map(|handle| unsafe { RemoteFolder::ref_from_raw(handle) })) } @@ -534,8 +507,8 @@ impl RemoteProject { let file_ptr = unsafe { BNRemoteProjectCreateFolder( self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - description.as_ref().as_ptr() as *const c_char, + name.as_ptr(), + description.as_ptr(), folder_handle, Some(P::cb_progress_callback), &mut progress as *mut P as *mut c_void, @@ -566,14 +539,8 @@ impl RemoteProject { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); - let mut values_raw = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); + let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::>(); + let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::>(); let success = unsafe { BNRemoteProjectPushFolder( self.handle.as_ptr(), @@ -761,7 +728,7 @@ impl RemoteProject { let value = unsafe { BNRemoteProjectCreateUserPermission( self.handle.as_ptr(), - user_id.as_ref().as_ptr() as *const c_char, + user_id.as_ptr(), level, Some(F::cb_progress_callback), &mut progress as *mut F as *mut c_void, @@ -793,14 +760,8 @@ impl RemoteProject { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); - let mut values_raw = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); + let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::>(); + let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::>(); let success = unsafe { BNRemoteProjectPushPermission( @@ -829,12 +790,7 @@ impl RemoteProject { /// * `username` - Username of user to check pub fn can_user_view(&self, username: S) -> bool { let username = username.to_cstr(); - unsafe { - BNRemoteProjectCanUserView( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNRemoteProjectCanUserView(self.handle.as_ptr(), username.as_ptr()) } } /// Determine if a user is in any of the edit/admin groups. @@ -844,12 +800,7 @@ impl RemoteProject { /// * `username` - Username of user to check pub fn can_user_edit(&self, username: S) -> bool { let username = username.to_cstr(); - unsafe { - BNRemoteProjectCanUserEdit( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNRemoteProjectCanUserEdit(self.handle.as_ptr(), username.as_ptr()) } } /// Determine if a user is in the admin group. @@ -859,12 +810,7 @@ impl RemoteProject { /// * `username` - Username of user to check pub fn can_user_admin(&self, username: S) -> bool { let username = username.to_cstr(); - unsafe { - BNRemoteProjectCanUserAdmin( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNRemoteProjectCanUserAdmin(self.handle.as_ptr(), username.as_ptr()) } } /// Get the default directory path for a remote Project. This is based off diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index 3a1f021cfb..ee37e9fbb6 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -1,5 +1,5 @@ use binaryninjacore_sys::*; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::ptr::NonNull; use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser}; @@ -30,12 +30,7 @@ impl Remote { pub fn new(name: N, address: A) -> Ref { let name = name.to_cstr(); let address = address.to_cstr(); - let result = unsafe { - BNCollaborationCreateRemote( - name.as_ref().as_ptr() as *const c_char, - address.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNCollaborationCreateRemote(name.as_ptr(), address.as_ptr()) }; unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -178,8 +173,8 @@ impl Remote { let token = unsafe { BNRemoteRequestAuthenticationToken( self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - password.as_ref().as_ptr() as *const c_char, + username.as_ptr(), + password.as_ptr(), ) }; if token.is_null() { @@ -230,10 +225,8 @@ impl Remote { } }; let username = options.username.to_cstr(); - let username_ptr = username.as_ptr() as *const c_char; let token = token.to_cstr(); - let token_ptr = token.as_ptr() as *const c_char; - let success = unsafe { BNRemoteConnect(self.handle.as_ptr(), username_ptr, token_ptr) }; + let success = unsafe { BNRemoteConnect(self.handle.as_ptr(), username.as_ptr(), token.as_ptr()) }; success.then_some(()).ok_or(()) } @@ -287,9 +280,7 @@ impl Remote { } let id = id.to_cstr(); - let value = unsafe { - BNRemoteGetProjectById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) - }; + let value = unsafe { BNRemoteGetProjectById(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(value).map(|handle| unsafe { RemoteProject::ref_from_raw(handle) })) } @@ -305,12 +296,7 @@ impl Remote { } let name = name.to_cstr(); - let value = unsafe { - BNRemoteGetProjectByName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let value = unsafe { BNRemoteGetProjectByName(self.handle.as_ptr(), name.as_ptr()) }; Ok(NonNull::new(value).map(|handle| unsafe { RemoteProject::ref_from_raw(handle) })) } @@ -358,11 +344,7 @@ impl Remote { let name = name.to_cstr(); let description = description.to_cstr(); let value = unsafe { - BNRemoteCreateProject( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - description.as_ref().as_ptr() as *const c_char, - ) + BNRemoteCreateProject(self.handle.as_ptr(), name.as_ptr(), description.as_ptr()) }; NonNull::new(value) .map(|handle| unsafe { RemoteProject::ref_from_raw(handle) }) @@ -407,14 +389,8 @@ impl Remote { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); - let mut values_raw = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect::>(); + let mut keys_raw = keys.iter().map(|s| s.as_ptr()).collect::>(); + let mut values_raw = values.iter().map(|s| s.as_ptr()).collect::>(); let success = unsafe { BNRemotePushProject( @@ -475,12 +451,7 @@ impl Remote { } let name = name.to_cstr(); - let value = unsafe { - BNRemoteGetGroupByName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let value = unsafe { BNRemoteGetGroupByName(self.handle.as_ptr(), name.as_ptr()) }; Ok(NonNull::new(value).map(|handle| unsafe { RemoteGroup::ref_from_raw(handle) })) } @@ -502,7 +473,7 @@ impl Remote { let success = unsafe { BNRemoteSearchGroups( self.handle.as_ptr(), - prefix.as_ref().as_ptr() as *const c_char, + prefix.as_ptr(), &mut group_ids, &mut group_names, &mut count, @@ -560,15 +531,12 @@ impl Remote { { let name = name.to_cstr(); let usernames: Vec<_> = usernames.into_iter().map(|s| s.to_cstr()).collect(); - let mut username_ptrs: Vec<_> = usernames - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut username_ptrs: Vec<_> = usernames.iter().map(|s| s.as_ptr()).collect(); let value = unsafe { BNRemoteCreateGroup( self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), username_ptrs.as_mut_ptr(), username_ptrs.len(), ) @@ -595,14 +563,8 @@ impl Remote { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw: Vec<_> = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); - let mut values_raw: Vec<_> = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut keys_raw: Vec<_> = keys.iter().map(|s| s.as_ptr()).collect(); + let mut values_raw: Vec<_> = values.iter().map(|s| s.as_ptr()).collect(); let success = unsafe { BNRemotePushGroup( @@ -659,9 +621,7 @@ impl Remote { self.pull_users()?; } let id = id.to_cstr(); - let value = unsafe { - BNRemoteGetUserById(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) - }; + let value = unsafe { BNRemoteGetUserById(self.handle.as_ptr(), id.as_ptr()) }; Ok(NonNull::new(value).map(|handle| unsafe { RemoteUser::ref_from_raw(handle) })) } @@ -682,12 +642,7 @@ impl Remote { self.pull_users()?; } let username = username.to_cstr(); - let value = unsafe { - BNRemoteGetUserByUsername( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - }; + let value = unsafe { BNRemoteGetUserByUsername(self.handle.as_ptr(), username.as_ptr()) }; Ok(NonNull::new(value).map(|handle| unsafe { RemoteUser::ref_from_raw(handle) })) } @@ -720,7 +675,7 @@ impl Remote { let success = unsafe { BNRemoteSearchUsers( self.handle.as_ptr(), - prefix.as_ref().as_ptr() as *const c_char, + prefix.as_ptr(), &mut user_ids, &mut usernames, &mut count, @@ -790,10 +745,10 @@ impl Remote { let value = unsafe { BNRemoteCreateUser( self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - email.as_ref().as_ptr() as *const c_char, + username.as_ptr(), + email.as_ptr(), is_active, - password.as_ref().as_ptr() as *const c_char, + password.as_ptr(), group_ids.as_ptr(), group_ids.len(), user_permission_ids.as_ptr(), @@ -823,14 +778,8 @@ impl Remote { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let mut keys_raw: Vec<_> = keys - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); - let mut values_raw: Vec<_> = values - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut keys_raw: Vec<_> = keys.iter().map(|s| s.as_ptr()).collect(); + let mut values_raw: Vec<_> = values.iter().map(|s| s.as_ptr()).collect(); let success = unsafe { BNRemotePushUser( self.handle.as_ptr(), diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index 465ae46a57..6e1dfb8941 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::ptr::NonNull; use std::time::SystemTime; @@ -237,7 +237,7 @@ impl RemoteSnapshot { self.handle.as_ptr(), parent.is_some(), parent.unwrap_or(0), - data.as_ref().as_ptr() as *const c_char, + data.as_ptr(), ) }; let handle = NonNull::new(value).ok_or(())?; diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index 4c1123362e..5afb8923cf 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -63,7 +63,7 @@ pub fn download_file_with_progress( let result = unsafe { BNCollaborationDownloadFile( file.handle.as_ptr(), - db_path.as_ref().as_ptr() as *const c_char, + db_path.as_ptr(), Some(F::cb_progress_callback), &mut progress as *mut F as *mut c_void, ) @@ -239,7 +239,7 @@ where let success = unsafe { BNCollaborationDownloadDatabaseForFile( file.handle.as_ptr(), - db_path.as_ref().as_ptr() as *const c_char, + db_path.as_ptr(), force, Some(F::cb_progress_callback), &mut progress as *mut _ as *mut c_void, @@ -485,7 +485,7 @@ pub fn set_snapshot_author( BNCollaborationSetSnapshotAuthor( database.handle.as_ptr(), snapshot.handle.as_ptr(), - author.as_ref().as_ptr() as *const c_char, + author.as_ptr(), ) }; success.then_some(()).ok_or(()) @@ -658,7 +658,7 @@ pub fn get_remote_snapshot_from_local_type_archive( let value = unsafe { BNCollaborationGetRemoteSnapshotFromLocalTypeArchive( type_archive.handle.as_ptr(), - snapshot_id.as_ref().as_ptr() as *const c_char, + snapshot_id.as_ptr(), ) }; NonNull::new(value).map(|handle| unsafe { RemoteSnapshot::ref_from_raw(handle) }) @@ -687,7 +687,7 @@ pub fn is_type_archive_snapshot_ignored( unsafe { BNCollaborationIsTypeArchiveSnapshotIgnored( type_archive.handle.as_ptr(), - snapshot_id.as_ref().as_ptr() as *const c_char, + snapshot_id.as_ptr(), ) } } @@ -713,7 +713,7 @@ pub fn download_type_archive_with_progress( let success = unsafe { BNCollaborationDownloadTypeArchive( file.handle.as_ptr(), - db_path.as_ref().as_ptr() as *const c_char, + db_path.as_ptr(), Some(F::cb_progress_callback), &mut progress as *mut F as *mut c_void, &mut value, diff --git a/rust/src/collaboration/user.rs b/rust/src/collaboration/user.rs index 43b4e854ec..d4aea2c504 100644 --- a/rust/src/collaboration/user.rs +++ b/rust/src/collaboration/user.rs @@ -1,6 +1,5 @@ use super::Remote; use binaryninjacore_sys::*; -use std::ffi::c_char; use std::ptr::NonNull; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; @@ -51,12 +50,8 @@ impl RemoteUser { /// Set user's username. You will need to push the user to update the Remote pub fn set_username(&self, username: U) -> Result<(), ()> { let username = username.to_cstr(); - let result = unsafe { - BNCollaborationUserSetUsername( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - }; + let result = + unsafe { BNCollaborationUserSetUsername(self.handle.as_ptr(), username.as_ptr()) }; if result { Ok(()) } else { @@ -74,12 +69,8 @@ impl RemoteUser { /// Set user's email. You will need to push the user to update the Remote pub fn set_email(&self, email: U) -> Result<(), ()> { let username = email.to_cstr(); - let result = unsafe { - BNCollaborationUserSetEmail( - self.handle.as_ptr(), - username.as_ref().as_ptr() as *const c_char, - ) - }; + let result = + unsafe { BNCollaborationUserSetEmail(self.handle.as_ptr(), username.as_ptr()) }; if result { Ok(()) } else { diff --git a/rust/src/command.rs b/rust/src/command.rs index 0297d6cfa4..721f9170c4 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -129,8 +129,8 @@ where let name = name.to_cstr(); let desc = desc.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); + let desc_ptr = desc.as_ptr(); let ctxt = Box::into_raw(Box::new(command)); @@ -230,8 +230,8 @@ where let name = name.to_cstr(); let desc = desc.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); + let desc_ptr = desc.as_ptr(); let ctxt = Box::into_raw(Box::new(command)); @@ -337,8 +337,8 @@ where let name = name.to_cstr(); let desc = desc.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); + let desc_ptr = desc.as_ptr(); let ctxt = Box::into_raw(Box::new(command)); @@ -449,8 +449,8 @@ where let name = name.to_cstr(); let desc = desc.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; - let desc_ptr = desc.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); + let desc_ptr = desc.as_ptr(); let ctxt = Box::into_raw(Box::new(command)); diff --git a/rust/src/component.rs b/rust/src/component.rs index 5fe44b64b9..48c8b110aa 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -166,12 +166,7 @@ impl Component { pub fn set_name(&self, name: S) { let name = name.to_cstr(); - unsafe { - BNComponentSetName( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNComponentSetName(self.handle.as_ptr(), name.as_ptr()) } } /// The component that contains this component, if it exists. diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index adcde09d62..ee32a67fa2 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -15,7 +15,6 @@ //! An interface for providing your own [BinaryView]s to Binary Ninja. use binaryninjacore_sys::*; -use std::ffi::c_char; pub use binaryninjacore_sys::BNModificationStatus as ModificationStatus; @@ -150,10 +149,10 @@ where } let name = name.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); let long_name = long_name.to_cstr(); - let long_name_ptr = long_name.as_ref().as_ptr() as *mut _; + let long_name_ptr = long_name.as_ptr(); let ctxt = Box::leak(Box::new(MaybeUninit::zeroed())); @@ -878,9 +877,10 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> { save: Some(cb_save::), }; + let view_name = view_name.to_cstr(); unsafe { let res = BNCreateCustomBinaryView( - view_name.as_ptr() as *const c_char, + view_name.as_ptr(), file.handle, parent.handle, &mut bn_obj, diff --git a/rust/src/database.rs b/rust/src/database.rs index fd20d1730e..d01839d274 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -4,7 +4,7 @@ pub mod undo; use binaryninjacore_sys::*; use std::collections::HashMap; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::fmt::Debug; use std::ptr::NonNull; @@ -94,7 +94,7 @@ impl Database { P: ProgressCallback, { let name_raw = name.to_cstr(); - let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; + let name_ptr = name_raw.as_ptr(); let new_id = unsafe { BNWriteDatabaseSnapshotData( @@ -135,8 +135,7 @@ impl Database { } pub fn has_global(&self, key: S) -> bool { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; - unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_ptr) != 0 } + unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_raw.as_ptr()) != 0 } } /// Get a list of keys for all globals in the database @@ -158,33 +157,28 @@ impl Database { /// Get a specific global by key pub fn read_global(&self, key: S) -> Option { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; - let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_ptr) }; + let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr()) }; unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database pub fn write_global(&self, key: K, value: V) -> bool { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; let value_raw = value.to_cstr(); - let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; - unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_ptr, value_ptr) } + unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr(), value_raw.as_ptr()) } } /// Get a specific global by key, as a binary buffer pub fn read_global_data(&self, key: S) -> Option { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; - let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_ptr) }; + let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr()) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; - unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_ptr, value.as_raw()) } + unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr(), value.as_raw()) } } /// Get the owning FileMetadata diff --git a/rust/src/database/kvs.rs b/rust/src/database/kvs.rs index 43cf17ebda..e84da7f3ec 100644 --- a/rust/src/database/kvs.rs +++ b/rust/src/database/kvs.rs @@ -9,7 +9,6 @@ use binaryninjacore_sys::{ BNNewKeyValueStoreReference, BNSetKeyValueStoreBuffer, }; use std::collections::HashMap; -use std::ffi::c_char; use std::fmt::Debug; use std::ptr::NonNull; @@ -44,7 +43,7 @@ impl KeyValueStore { /// Get the value for a single key pub fn value(&self, key: S) -> Option { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let key_ptr = key_raw.as_ptr(); let result = unsafe { BNGetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } @@ -52,7 +51,7 @@ impl KeyValueStore { /// Set the value for a single key pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); - let key_ptr = key_raw.as_ref().as_ptr() as *const c_char; + let key_ptr = key_raw.as_ptr(); unsafe { BNSetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr, value.as_raw()) } } @@ -66,7 +65,7 @@ impl KeyValueStore { /// Begin storing new keys into a namespace pub fn begin_namespace(&self, name: S) { let name_raw = name.to_cstr(); - let name_ptr = name_raw.as_ref().as_ptr() as *const c_char; + let name_ptr = name_raw.as_ptr(); unsafe { BNBeginKeyValueStoreNamespace(self.handle.as_ptr(), name_ptr) } } diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs index 7d7e39d198..599a749ac1 100644 --- a/rust/src/database/snapshot.rs +++ b/rust/src/database/snapshot.rs @@ -14,7 +14,7 @@ use binaryninjacore_sys::{ BNReadSnapshotDataWithProgress, BNSetSnapshotName, BNSnapshot, BNSnapshotHasAncestor, BNSnapshotHasContents, BNSnapshotHasUndo, BNSnapshotStoreData, }; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::ptr::NonNull; @@ -52,7 +52,7 @@ impl Snapshot { /// Set the displayed snapshot name pub fn set_name(&self, value: S) { let value_raw = value.to_cstr(); - let value_ptr = value_raw.as_ref().as_ptr() as *const c_char; + let value_ptr = value_raw.as_ptr(); unsafe { BNSetSnapshotName(self.handle.as_ptr(), value_ptr) } } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 0afe4c77e5..9336a28dd8 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -117,7 +117,7 @@ impl DebugInfoParser { /// Returns debug info parser of the given name, if it exists pub fn from_name(name: S) -> Result, ()> { let name = name.to_cstr(); - let parser = unsafe { BNGetDebugInfoParserByName(name.as_ref().as_ptr() as *mut _) }; + let parser = unsafe { BNGetDebugInfoParserByName(name.as_ptr()) }; if parser.is_null() { Err(()) @@ -260,7 +260,7 @@ impl DebugInfoParser { } let name = name.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); let ctxt = Box::into_raw(Box::new(parser_callbacks)); unsafe { @@ -421,13 +421,8 @@ impl DebugInfo { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; - let debug_types_ptr = unsafe { - BNGetDebugTypes( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let debug_types_ptr = + unsafe { BNGetDebugTypes(self.handle, parser_name.as_ptr(), &mut count) }; let result: Vec<_> = unsafe { std::slice::from_raw_parts_mut(debug_types_ptr, count) .iter() @@ -459,13 +454,8 @@ impl DebugInfo { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; - let functions_ptr = unsafe { - BNGetDebugFunctions( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let functions_ptr = + unsafe { BNGetDebugFunctions(self.handle, parser_name.as_ptr(), &mut count) }; let result: Vec = unsafe { std::slice::from_raw_parts_mut(functions_ptr, count) @@ -502,13 +492,8 @@ impl DebugInfo { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; - let data_variables_ptr = unsafe { - BNGetDebugDataVariables( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let data_variables_ptr = + unsafe { BNGetDebugDataVariables(self.handle, parser_name.as_ptr(), &mut count) }; let result: Vec = unsafe { std::slice::from_raw_parts_mut(data_variables_ptr, count) @@ -541,13 +526,8 @@ impl DebugInfo { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); - let result = unsafe { - BNGetDebugTypeByName( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, - ) - }; + let result = + unsafe { BNGetDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) }; if !result.is_null() { Some(unsafe { Type::ref_from_raw(result) }) } else { @@ -566,8 +546,8 @@ impl DebugInfo { unsafe { if BNGetDebugDataVariableByName( self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, + parser_name.as_ptr(), + name.as_ptr(), &mut dv, ) { Some(NamedDataVariableWithType::from_owned_raw(dv)) @@ -585,12 +565,8 @@ impl DebugInfo { let parser_name = parser_name.to_cstr(); let mut dv = BNDataVariableAndName::default(); unsafe { - if BNGetDebugDataVariableByAddress( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - address, - &mut dv, - ) { + if BNGetDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address, &mut dv) + { Some(NamedDataVariableWithType::from_owned_raw(dv)) } else { None @@ -602,9 +578,8 @@ impl DebugInfo { pub fn get_types_by_name(&self, name: S) -> Vec { let mut count: usize = 0; let name = name.to_cstr(); - let raw_names_and_types_ptr = unsafe { - BNGetDebugTypesByName(self.handle, name.as_ref().as_ptr() as *mut _, &mut count) - }; + let raw_names_and_types_ptr = + unsafe { BNGetDebugTypesByName(self.handle, name.as_ptr(), &mut count) }; let raw_names_and_types: &[BNNameAndType] = unsafe { std::slice::from_raw_parts(raw_names_and_types_ptr, count) }; @@ -623,9 +598,8 @@ impl DebugInfo { let name = name.to_cstr(); let mut count: usize = 0; - let raw_variables_and_names = unsafe { - BNGetDebugDataVariablesByName(self.handle, name.as_ref().as_ptr() as *mut _, &mut count) - }; + let raw_variables_and_names = + unsafe { BNGetDebugDataVariablesByName(self.handle, name.as_ptr(), &mut count) }; let variables_and_names: &[*mut BNDataVariableAndName] = unsafe { std::slice::from_raw_parts(raw_variables_and_names as *mut _, count) }; @@ -674,66 +648,44 @@ impl DebugInfo { pub fn remove_parser_info(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ref().as_ptr() as *mut _) } + unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ptr()) } } pub fn remove_parser_types(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ref().as_ptr() as *mut _) } + unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ptr()) } } pub fn remove_parser_functions(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { - BNRemoveDebugParserFunctions(self.handle, parser_name.as_ref().as_ptr() as *mut _) - } + unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ptr()) } } pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { - BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ref().as_ptr() as *mut _) - } + unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ptr()) } } pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); - unsafe { - BNRemoveDebugTypeByName( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - name.as_ref().as_ptr() as *mut _, - ) - } + unsafe { BNRemoveDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) } } pub fn remove_function_by_index(&self, parser_name: S, index: usize) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { - BNRemoveDebugFunctionByIndex( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - index, - ) - } + unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_ptr(), index) } } pub fn remove_data_variable_by_address(&self, parser_name: S, address: u64) -> bool { let parser_name = parser_name.to_cstr(); - unsafe { - BNRemoveDebugDataVariableByAddress( - self.handle, - parser_name.as_ref().as_ptr() as *mut _, - address, - ) - } + unsafe { BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address) } } /// Adds a type scoped under the current parser's name to the debug info @@ -745,7 +697,7 @@ impl DebugInfo { unsafe { BNAddDebugType( self.handle, - name.as_ref().as_ptr() as *mut _, + name.as_ptr(), new_type.handle, raw_components.as_ptr() as *mut _, components.len(), @@ -776,7 +728,8 @@ impl DebugInfo { unsafe { for component in &new_func.components { - components_array.push(BNAllocString(component.clone().to_cstr().as_ptr() as _)); + let component = component.to_cstr(); + components_array.push(BNAllocString(component.as_ptr())); } for local_variable in &new_func.local_variables { @@ -839,7 +792,7 @@ impl DebugInfo { self.handle, address, t.handle, - name.as_ref().as_ptr() as *mut _, + name.as_ptr(), components.as_ptr() as _, components.len(), ) diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index 9cec0c9329..a883dc8294 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -32,14 +32,13 @@ pub fn demangle_generic( view: Option<&BinaryView>, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.to_cstr(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); + let mangled_name = mangled_name.to_cstr(); let mut out_type: *mut BNType = std::ptr::null_mut(); let mut out_name = BNQualifiedName::default(); let res = unsafe { BNDemangleGeneric( arch.handle, - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_type, &mut out_name, view.map(|v| v.handle).unwrap_or(std::ptr::null_mut()), @@ -59,13 +58,12 @@ pub fn demangle_generic( } pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { - let mangled_name_bwn = mangled_name.to_cstr(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); + let mangled_name = mangled_name.to_cstr(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; let res = unsafe { BNDemangleLLVM( - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_name, &mut out_size, simplify, @@ -92,15 +90,14 @@ pub fn demangle_gnu3( mangled_name: S, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.to_cstr(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); + let mangled_name = mangled_name.to_cstr(); let mut out_type: *mut BNType = std::ptr::null_mut(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; let res = unsafe { BNDemangleGNU3( arch.handle, - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_type, &mut out_name, &mut out_size, @@ -133,16 +130,14 @@ pub fn demangle_ms( mangled_name: S, simplify: bool, ) -> Option<(QualifiedName, Option>)> { - let mangled_name_bwn = mangled_name.to_cstr(); - let mangled_name_ptr = mangled_name_bwn.as_ref(); - + let mangled_name = mangled_name.to_cstr(); let mut out_type: *mut BNType = std::ptr::null_mut(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; let res = unsafe { BNDemangleMS( arch.handle, - mangled_name_ptr.as_ptr() as *const c_char, + mangled_name.as_ptr(), &mut out_type, &mut out_name, &mut out_size, @@ -309,7 +304,7 @@ impl Demangler { } let name = name.to_cstr(); - let name_ptr = name.as_ref().as_ptr() as *mut _; + let name_ptr = name.as_ptr(); let ctxt = Box::into_raw(Box::new(demangler)); let callbacks = BNDemanglerCallbacks { diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index f9e21e64e3..7d28058fad 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -14,9 +14,8 @@ pub struct DownloadProvider { impl DownloadProvider { pub fn get(name: S) -> Option { - let result = unsafe { - BNGetDownloadProviderByName(name.to_cstr().as_ref().as_ptr() as *const c_char) - }; + let name = name.to_cstr(); + let result = unsafe { BNGetDownloadProviderByName(name.as_ptr()) }; if result.is_null() { return None; } @@ -145,10 +144,11 @@ impl DownloadInstance { progressContext: callbacks as *mut c_void, }; + let url_raw = url.to_cstr(); let result = unsafe { BNPerformDownloadRequest( self.handle, - url.to_cstr().as_ref().as_ptr() as *const c_char, + url_raw.as_ptr(), &mut cbs as *mut BNDownloadInstanceOutputCallbacks, ) }; @@ -225,8 +225,8 @@ impl DownloadInstance { let mut header_value_ptrs = vec![]; for (key, value) in header_keys.iter().zip(header_values.iter()) { - header_key_ptrs.push(key.as_ref().as_ptr() as *const c_char); - header_value_ptrs.push(value.as_ref().as_ptr() as *const c_char); + header_key_ptrs.push(key.as_ptr()); + header_value_ptrs.push(value.as_ptr()); } let callbacks = Box::into_raw(Box::new(callbacks)); @@ -241,11 +241,13 @@ impl DownloadInstance { let mut response: *mut BNDownloadInstanceResponse = null_mut(); + let method_raw = method.to_cstr(); + let url_raw = url.to_cstr(); let result = unsafe { BNPerformCustomRequest( self.handle, - method.to_cstr().as_ref().as_ptr() as *const c_char, - url.to_cstr().as_ref().as_ptr() as *const c_char, + method_raw.as_ptr(), + url_raw.as_ptr(), header_key_ptrs.len() as u64, header_key_ptrs.as_ptr(), header_value_ptrs.as_ptr(), diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs index 26425ccd74..57848a7a55 100644 --- a/rust/src/external_library.rs +++ b/rust/src/external_library.rs @@ -3,7 +3,6 @@ use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCounta use crate::string::{AsCStr, BnString}; use crate::symbol::Symbol; use binaryninjacore_sys::*; -use std::ffi::c_char; use std::fmt::Debug; use std::ptr::NonNull; @@ -168,10 +167,15 @@ impl ExternalLocation { /// Set the symbol pointed to by this ExternalLocation. /// ExternalLocations must have a valid target address and/or symbol set. pub fn set_target_symbol(&self, symbol: Option) -> bool { - let symbol = symbol - .map(|x| x.to_cstr().as_ref().as_ptr() as *const c_char) - .unwrap_or(std::ptr::null_mut()); - unsafe { BNExternalLocationSetTargetSymbol(self.handle.as_ptr(), symbol) } + match symbol { + Some(sym) => { + let raw_sym = sym.to_cstr(); + unsafe { BNExternalLocationSetTargetSymbol(self.handle.as_ptr(), raw_sym.as_ptr()) } + } + None => unsafe { + BNExternalLocationSetTargetSymbol(self.handle.as_ptr(), std::ptr::null()) + }, + } } } diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index 6b6a79a8b8..100f255b44 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -79,7 +79,7 @@ impl FileMetadata { let name = name.to_cstr(); unsafe { - BNSetFilename(self.handle, name.as_ref().as_ptr() as *mut _); + BNSetFilename(self.handle, name.as_ptr()); } } @@ -275,7 +275,7 @@ impl FileMetadata { pub fn open_database(&self, filename: S) -> Result, ()> { let filename = filename.to_cstr(); - let filename_ptr = filename.as_ref().as_ptr() as *mut _; + let filename_ptr = filename.as_ptr(); let view = unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }; @@ -292,7 +292,7 @@ impl FileMetadata { mut progress: P, ) -> Result, ()> { let filename = filename.to_cstr(); - let filename_ptr = filename.as_ref().as_ptr() as *mut _; + let filename_ptr = filename.as_ptr(); let view = unsafe { BNOpenExistingDatabaseWithProgress( diff --git a/rust/src/function.rs b/rust/src/function.rs index dcefaa3513..36bd1d56c6 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -376,7 +376,7 @@ impl Function { let raw = comment.to_cstr(); unsafe { - BNSetFunctionComment(self.handle, raw.as_ref().as_ptr() as *mut _); + BNSetFunctionComment(self.handle, raw.as_ptr()); } } @@ -398,7 +398,7 @@ impl Function { let raw = comment.to_cstr(); unsafe { - BNSetCommentForAddress(self.handle, addr, raw.as_ref().as_ptr() as *mut _); + BNSetCommentForAddress(self.handle, addr, raw.as_ptr()); } } @@ -1712,7 +1712,7 @@ impl Function { let arch = arch.unwrap_or_else(|| self.arch()); let enum_display_typeid = enum_display_typeid.map(AsCStr::to_cstr); let enum_display_typeid_ptr = enum_display_typeid - .map(|x| x.as_ref().as_ptr() as *const c_char) + .map(|x| x.as_ptr()) .unwrap_or(std::ptr::null()); unsafe { BNSetIntegerConstantDisplayType( diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 7e007eb983..9994608fa0 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -23,16 +23,16 @@ use crate::binary_view::BinaryView; use crate::rc::Ref; use crate::string::{AsCStr, BnString}; +pub type MessageBoxButtonSet = BNMessageBoxButtonSet; +pub type MessageBoxIcon = BNMessageBoxIcon; +pub type MessageBoxButtonResult = BNMessageBoxButtonResult; + pub fn get_text_line_input(prompt: &str, title: &str) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); - let result = unsafe { - BNGetTextLineInput( - &mut value, - prompt.to_cstr().as_ptr() as *mut _, - title.to_cstr().as_ptr() as *mut _, - ) - }; + let prompt = prompt.to_cstr(); + let title = title.to_cstr(); + let result = unsafe { BNGetTextLineInput(&mut value, prompt.as_ptr(), title.as_ptr()) }; if !result { return None; } @@ -43,13 +43,9 @@ pub fn get_text_line_input(prompt: &str, title: &str) -> Option { pub fn get_integer_input(prompt: &str, title: &str) -> Option { let mut value: i64 = 0; - let result = unsafe { - BNGetIntegerInput( - &mut value, - prompt.to_cstr().as_ptr() as *mut _, - title.to_cstr().as_ptr() as *mut _, - ) - }; + let prompt = prompt.to_cstr(); + let title = title.to_cstr(); + let result = unsafe { BNGetIntegerInput(&mut value, prompt.as_ptr(), title.as_ptr()) }; if !result { return None; @@ -61,11 +57,13 @@ pub fn get_integer_input(prompt: &str, title: &str) -> Option { pub fn get_address_input(prompt: &str, title: &str) -> Option { let mut value: u64 = 0; + let prompt = prompt.to_cstr(); + let title = title.to_cstr(); let result = unsafe { BNGetAddressInput( &mut value, - prompt.to_cstr().as_ptr() as *mut _, - title.to_cstr().as_ptr() as *mut _, + prompt.as_ptr(), + title.as_ptr(), std::ptr::null_mut(), 0, ) @@ -81,13 +79,9 @@ pub fn get_address_input(prompt: &str, title: &str) -> Option { pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); - let result = unsafe { - BNGetOpenFileNameInput( - &mut value, - prompt.to_cstr().as_ptr() as *mut _, - extension.to_cstr().as_ptr() as *mut _, - ) - }; + let prompt = prompt.to_cstr(); + let extension = extension.to_cstr(); + let result = unsafe { BNGetOpenFileNameInput(&mut value, prompt.as_ptr(), extension.as_ptr()) }; if !result { return None; } @@ -103,12 +97,15 @@ pub fn get_save_filename_input( ) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); + let prompt = prompt.to_cstr(); + let extension = extension.to_cstr(); + let default_name = default_name.to_cstr(); let result = unsafe { BNGetSaveFileNameInput( &mut value, - prompt.to_cstr().as_ptr() as *mut _, - extension.to_cstr().as_ptr() as *mut _, - default_name.to_cstr().as_ptr() as *mut _, + prompt.as_ptr(), + extension.as_ptr(), + default_name.as_ptr(), ) }; if !result { @@ -122,13 +119,10 @@ pub fn get_save_filename_input( pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); - let result = unsafe { - BNGetDirectoryNameInput( - &mut value, - prompt.to_cstr().as_ptr() as *mut _, - default_name.to_cstr().as_ptr() as *mut _, - ) - }; + let prompt = prompt.to_cstr(); + let default_name = default_name.to_cstr(); + let result = + unsafe { BNGetDirectoryNameInput(&mut value, prompt.as_ptr(), default_name.as_ptr()) }; if !result { return None; } @@ -137,23 +131,15 @@ pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option MessageBoxButtonResult { - unsafe { - BNShowMessageBox( - title.to_cstr().as_ptr() as *mut _, - text.to_cstr().as_ptr() as *mut _, - buttons, - icon, - ) - } + let title = title.to_cstr(); + let text = text.to_cstr(); + unsafe { BNShowMessageBox(title.as_ptr(), text.as_ptr(), buttons, icon) } } pub enum FormResponses { @@ -210,7 +196,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::LabelFormField; result.hasDefault = false; - result.prompt = text.as_ref().as_ptr() as *const c_char; + result.prompt = text.as_ptr(); self.fields.push(result); self.data.push(FormData::Label { _text: text }); @@ -233,10 +219,10 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::TextLineFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_ptr(); } self.fields.push(result); @@ -254,10 +240,10 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::MultilineTextFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_ptr(); } self.fields.push(result); @@ -274,7 +260,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::IntegerFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); result.hasDefault = default.is_some(); if let Some(default) = default { result.intDefault = default; @@ -297,7 +283,7 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::AddressFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); if let Some(view) = view { // the view is being moved into result, there is no need to clone // and drop is intentionally being avoided with `Ref::into_raw` @@ -321,11 +307,8 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::ChoiceFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - let mut raw_choices: Vec<*const c_char> = choices - .iter() - .map(|c| c.as_ref().as_ptr() as *const c_char) - .collect(); + result.prompt = prompt.as_ptr(); + let mut raw_choices: Vec<*const c_char> = choices.iter().map(|c| c.as_ptr()).collect(); result.choices = raw_choices.as_mut_ptr(); result.count = choices.len(); result.hasDefault = default.is_some(); @@ -359,11 +342,11 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::OpenFileNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.ext = ext.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); + result.ext = ext.as_ptr(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_ptr(); } self.fields.push(result); @@ -398,12 +381,12 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::SaveFileNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.ext = ext.as_ref().as_ptr() as *const c_char; - result.defaultName = default_name.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); + result.ext = ext.as_ptr(); + result.defaultName = default_name.as_ptr(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_ptr(); } self.fields.push(result); @@ -433,11 +416,11 @@ impl FormInputBuilder { let mut result = unsafe { std::mem::zeroed::() }; result.type_ = BNFormInputFieldType::DirectoryNameFormField; - result.prompt = prompt.as_ref().as_ptr() as *const c_char; - result.defaultName = default_name.as_ref().as_ptr() as *const c_char; + result.prompt = prompt.as_ptr(); + result.defaultName = default_name.as_ptr(); result.hasDefault = default.is_some(); if let Some(ref default) = default { - result.stringDefault = default.as_ref().as_ptr() as *const c_char; + result.stringDefault = default.as_ptr(); } self.fields.push(result); @@ -491,13 +474,8 @@ impl FormInputBuilder { /// println!("{} {} likes {}", &first_name, &last_name, food); /// ``` pub fn get_form_input(&mut self, title: &str) -> Vec { - if unsafe { - BNGetFormInput( - self.fields.as_mut_ptr(), - self.fields.len(), - title.to_cstr().as_ptr() as *const _, - ) - } { + let title = title.to_cstr(); + if unsafe { BNGetFormInput(self.fields.as_mut_ptr(), self.fields.len(), title.as_ptr()) } { let result = self .fields .iter() @@ -575,9 +553,10 @@ pub fn run_progress_dialog Result<(), ()>>)>( }) } + let title = title.to_cstr(); if unsafe { BNRunProgressDialog( - title.to_cstr().as_ptr() as *mut _, + title.as_ptr(), can_cancel, Some(cb_task::), &mut ctxt as *mut _ as *mut c_void, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 63872be3e1..c0b3a38cb3 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -285,7 +285,7 @@ pub fn bundled_plugin_directory() -> Result { pub fn set_bundled_plugin_directory(new_dir: impl AsRef) { let new_dir = new_dir.as_ref().to_cstr(); - unsafe { BNSetBundledPluginDirectory(new_dir.as_ptr() as *const c_char) }; + unsafe { BNSetBundledPluginDirectory(new_dir.as_ptr()) }; } pub fn user_directory() -> PathBuf { @@ -330,7 +330,7 @@ pub fn save_last_run() { pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = - unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr() as *const c_char) }; + unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } @@ -340,7 +340,7 @@ pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Resu pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = - unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr() as *const c_char) }; + unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } @@ -350,7 +350,7 @@ pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result< pub fn path_relative_to_user_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); let s: *mut c_char = - unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr() as *const c_char) }; + unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } @@ -475,7 +475,7 @@ impl VersionInfo { pub fn from_string(string: S) -> Self { let string = string.to_cstr(); - let result = unsafe { BNParseVersionString(string.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNParseVersionString(string.as_ptr()) }; Self::from_owned_raw(result) } } @@ -534,8 +534,7 @@ pub fn license_count() -> i32 { #[cfg(not(feature = "demo"))] pub fn set_license(license: Option) { let license = license.unwrap_or_default().to_cstr(); - let license_slice = license.as_ref(); - unsafe { BNSetLicense(license_slice.as_ptr() as *const c_char) } + unsafe { BNSetLicense(license.as_ptr()) } } #[cfg(feature = "demo")] @@ -560,8 +559,7 @@ pub fn is_ui_enabled() -> bool { pub fn is_database(filename: S) -> bool { let filename = filename.to_cstr(); - let filename_slice = filename.as_ref(); - unsafe { BNIsDatabase(filename_slice.as_ptr() as *const c_char) } + unsafe { BNIsDatabase(filename.as_ptr()) } } pub fn plugin_abi_version() -> u32 { @@ -589,11 +587,13 @@ pub fn plugin_ui_abi_minimum_version() -> u32 { } pub fn add_required_plugin_dependency(name: S) { - unsafe { BNAddRequiredPluginDependency(name.to_cstr().as_ref().as_ptr() as *const c_char) }; + let raw_name = name.to_cstr(); + unsafe { BNAddRequiredPluginDependency(raw_name.as_ptr()) }; } pub fn add_optional_plugin_dependency(name: S) { - unsafe { BNAddOptionalPluginDependency(name.to_cstr().as_ref().as_ptr() as *const c_char) }; + let raw_name = name.to_cstr(); + unsafe { BNAddOptionalPluginDependency(raw_name.as_ptr()) }; } // Provide ABI version automatically so that the core can verify binary compatibility diff --git a/rust/src/logger.rs b/rust/src/logger.rs index c06f4dfcd8..5f14af695d 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -35,7 +35,7 @@ use binaryninjacore_sys::{ }; use crate::rc::{Ref, RefCountable}; -use crate::string::BnString; +use crate::string::{AsCStr, BnString}; use log; use log::LevelFilter; use std::ffi::{CStr, CString}; @@ -139,12 +139,12 @@ impl log::Log for Ref { if let Ok(msg) = CString::new(format!("{}", record.args())) { let percent_s = CString::new("%s").expect("'%s' has no null bytes"); - let logger_name = self.name(); + let logger_name = self.name().to_cstr(); unsafe { BNLog( self.session_id(), level, - logger_name.as_ptr() as *const c_char, + logger_name.as_ptr(), 0, percent_s.as_ptr(), msg.as_ptr(), diff --git a/rust/src/medium_level_il/function.rs b/rust/src/medium_level_il/function.rs index de3ece02a2..75ccad826b 100644 --- a/rust/src/medium_level_il/function.rs +++ b/rust/src/medium_level_il/function.rs @@ -1,5 +1,4 @@ use binaryninjacore_sys::*; -use std::ffi::c_char; use std::fmt::{Debug, Formatter}; use std::hash::{Hash, Hasher}; @@ -135,7 +134,7 @@ impl MediumLevelILFunction { self.function().handle, offset, &mut owned_raw_var_ty, - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), ) } } @@ -282,13 +281,12 @@ impl MediumLevelILFunction { ) { let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); let name = name.to_cstr(); - let name_c_str = name.as_ref(); unsafe { BNCreateAutoStackVariable( self.function().handle, offset, &mut owned_raw_var_ty, - name_c_str.as_ptr() as *const c_char, + name.as_ptr(), ) } } @@ -307,13 +305,12 @@ impl MediumLevelILFunction { let raw_var = BNVariable::from(var); let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); let name = name.to_cstr(); - let name_c_str = name.as_ref(); unsafe { BNCreateAutoVariable( self.function().handle, &raw_var, &mut owned_raw_var_ty, - name_c_str.as_ptr() as *const c_char, + name.as_ptr(), ignore_disjoint_uses, ) } diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index c31e806b52..cc10885a88 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -271,12 +271,8 @@ impl Metadata { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } - let ptr: *mut BNMetadata = unsafe { - BNMetadataGetForKey( - self.handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, - ) - }; + let raw_key = key.to_cstr(); + let ptr: *mut BNMetadata = unsafe { BNMetadataGetForKey(self.handle, raw_key.as_ptr()) }; if ptr.is_null() { return Ok(None); } @@ -295,14 +291,8 @@ impl Metadata { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } - - unsafe { - BNMetadataSetValueForKey( - self.handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, - value.handle, - ) - }; + let raw_key = key.to_cstr(); + unsafe { BNMetadataSetValueForKey(self.handle, raw_key.as_ptr(), value.handle) }; Ok(()) } @@ -320,12 +310,8 @@ impl Metadata { return Err(()); } - unsafe { - BNMetadataRemoveKey( - self.handle, - key.to_cstr().as_ref().as_ptr() as *const c_char, - ) - }; + let raw_key = key.to_cstr(); + unsafe { BNMetadataRemoveKey(self.handle, raw_key.as_ptr()) }; Ok(()) } } @@ -396,21 +382,15 @@ impl From for Ref { impl From for Ref { fn from(value: String) -> Self { - unsafe { - Metadata::ref_from_raw(BNCreateMetadataStringData( - value.to_cstr().as_ptr() as *const c_char - )) - } + let raw_value = value.to_cstr(); + unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData(raw_value.as_ptr())) } } } impl From<&str> for Ref { fn from(value: &str) -> Self { - unsafe { - Metadata::ref_from_raw(BNCreateMetadataStringData( - value.to_cstr().as_ptr() as *const c_char - )) - } + let raw_value = value.to_cstr(); + unsafe { Metadata::ref_from_raw(BNCreateMetadataStringData(raw_value.as_ptr())) } } } @@ -448,10 +428,7 @@ impl From>> for Ref { fn from(value: HashMap>) -> Self { let data: Vec<(S::Result, Ref)> = value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); - let mut keys: Vec<*const c_char> = data - .iter() - .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) - .collect(); + let mut keys: Vec<*const c_char> = data.iter().map(|(k, _)| k.as_ptr()).collect(); let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); unsafe { @@ -472,10 +449,7 @@ where fn from(value: &[(S, T)]) -> Self { let data: Vec<(S::Result, Ref)> = value.iter().map(|(k, v)| (k.to_cstr(), v.into())).collect(); - let mut keys: Vec<*const c_char> = data - .iter() - .map(|(k, _)| k.as_ref().as_ptr() as *const c_char) - .collect(); + let mut keys: Vec<*const c_char> = data.iter().map(|(k, _)| k.as_ptr()).collect(); let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); unsafe { @@ -552,7 +526,7 @@ impl From> for Ref { } let mut pointers = vec![]; for r in &refs { - pointers.push(r.as_ref().as_ptr() as *const c_char); + pointers.push(r.as_ptr()); } unsafe { Metadata::ref_from_raw(BNCreateMetadataStringListData( diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 1918674059..c225392f83 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -85,7 +85,7 @@ impl Platform { pub fn by_name(name: S) -> Option> { let raw_name = name.to_cstr(); unsafe { - let res = BNGetPlatformByName(raw_name.as_ref().as_ptr() as *mut _); + let res = BNGetPlatformByName(raw_name.as_ptr()); if res.is_null() { None @@ -118,7 +118,7 @@ impl Platform { unsafe { let mut count = 0; - let handles = BNGetPlatformListByOS(raw_name.as_ref().as_ptr() as *mut _, &mut count); + let handles = BNGetPlatformListByOS(raw_name.as_ptr(), &mut count); Array::new(handles, count, ()) } @@ -129,11 +129,8 @@ impl Platform { unsafe { let mut count = 0; - let handles = BNGetPlatformListByOSAndArchitecture( - raw_name.as_ref().as_ptr() as *mut _, - arch.handle, - &mut count, - ); + let handles = + BNGetPlatformListByOSAndArchitecture(raw_name.as_ptr(), arch.handle, &mut count); Array::new(handles, count, ()) } @@ -151,7 +148,7 @@ impl Platform { pub fn new(arch: &A, name: S) -> Ref { let name = name.to_cstr(); unsafe { - let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ref().as_ptr() as *mut _); + let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ptr()); assert!(!handle.is_null()); Ref::new(Self { handle }) } @@ -179,13 +176,8 @@ impl Platform { pub fn get_type_libraries_by_name(&self, name: T) -> Array { let mut count = 0; let name = name.to_cstr(); - let result = unsafe { - BNGetPlatformTypeLibrariesByName( - self.handle, - name.as_ref().as_ptr() as *mut _, - &mut count, - ) - }; + let result = + unsafe { BNGetPlatformTypeLibrariesByName(self.handle, name.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -194,7 +186,7 @@ impl Platform { let os = os.to_cstr(); unsafe { - BNRegisterPlatform(os.as_ref().as_ptr() as *mut _, self.handle); + BNRegisterPlatform(os.as_ptr(), self.handle); } } diff --git a/rust/src/project.rs b/rust/src/project.rs index 453f1c5658..351b6e3f76 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -1,7 +1,7 @@ pub mod file; pub mod folder; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::fmt::Debug; use std::ptr::{null_mut, NonNull}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -42,12 +42,7 @@ impl Project { pub fn create(path: P, name: S) -> Option> { let path_raw = path.to_cstr(); let name_raw = name.to_cstr(); - let handle = unsafe { - BNCreateProject( - path_raw.as_ref().as_ptr() as *const c_char, - name_raw.as_ref().as_ptr() as *const c_char, - ) - }; + let handle = unsafe { BNCreateProject(path_raw.as_ptr(), name_raw.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) } @@ -56,7 +51,7 @@ impl Project { /// * `path` - Path to the project directory (.bnpr) or project metadata file (.bnpm) pub fn open_project(path: P) -> Option> { let path_raw = path.to_cstr(); - let handle = unsafe { BNOpenProject(path_raw.as_ref().as_ptr() as *const c_char) }; + let handle = unsafe { BNOpenProject(path_raw.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) } @@ -101,12 +96,7 @@ impl Project { /// Set the name of the project pub fn set_name(&self, value: S) { let value = value.to_cstr(); - unsafe { - BNProjectSetName( - self.handle.as_ptr(), - value.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectSetName(self.handle.as_ptr(), value.as_ptr()) } } /// Get the description of the project @@ -117,20 +107,13 @@ impl Project { /// Set the description of the project pub fn set_description(&self, value: S) { let value = value.to_cstr(); - unsafe { - BNProjectSetDescription( - self.handle.as_ptr(), - value.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectSetDescription(self.handle.as_ptr(), value.as_ptr()) } } /// Retrieves metadata stored under a key from the project pub fn query_metadata(&self, key: S) -> Ref { let key = key.to_cstr(); - let result = unsafe { - BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; unsafe { Metadata::ref_from_raw(result) } } @@ -140,24 +123,13 @@ impl Project { /// * `value` - Object to store pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { let key_raw = key.to_cstr(); - unsafe { - BNProjectStoreMetadata( - self.handle.as_ptr(), - key_raw.as_ref().as_ptr() as *const c_char, - value.handle, - ) - } + unsafe { BNProjectStoreMetadata(self.handle.as_ptr(), key_raw.as_ptr(), value.handle) } } /// Removes the metadata associated with this `key` from the project pub fn remove_metadata(&self, key: S) { let key_raw = key.to_cstr(); - unsafe { - BNProjectRemoveMetadata( - self.handle.as_ptr(), - key_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectRemoveMetadata(self.handle.as_ptr(), key_raw.as_ptr()) } } pub fn push_folder(&self, file: &ProjectFolder) { @@ -207,9 +179,9 @@ impl Project { unsafe { let result = BNProjectCreateFolderFromPath( self.handle.as_ptr(), - path_raw.as_ref().as_ptr() as *const c_char, + path_raw.as_ptr(), parent_ptr, - description_raw.as_ref().as_ptr() as *const c_char, + description_raw.as_ptr(), &mut progress as *mut PC as *mut c_void, Some(PC::cb_progress_callback), ); @@ -239,8 +211,8 @@ impl Project { let result = BNProjectCreateFolder( self.handle.as_ptr(), parent_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), ); Ok(ProjectFolder::ref_from_raw(NonNull::new(result).ok_or(())?)) } @@ -272,9 +244,9 @@ impl Project { let result = BNProjectCreateFolderUnsafe( self.handle.as_ptr(), parent_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, - id_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), + id_raw.as_ptr(), ); Ok(ProjectFolder::ref_from_raw(NonNull::new(result).ok_or(())?)) } @@ -293,9 +265,8 @@ impl Project { /// Retrieve a folder in the project by unique folder `id` pub fn folder_by_id(&self, id: S) -> Option> { - let id_raw = id.to_cstr(); - let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; - let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), id_ptr) }; + let raw_id = id.to_cstr(); + let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFolder::ref_from_raw(handle) }) } @@ -392,10 +363,10 @@ impl Project { unsafe { let result = BNProjectCreateFileFromPath( self.handle.as_ptr(), - path_raw.as_ref().as_ptr() as *const c_char, + path_raw.as_ptr(), folder_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), &mut progress as *mut PC as *mut c_void, Some(PC::cb_progress_callback), ); @@ -473,11 +444,11 @@ impl Project { unsafe { let result = BNProjectCreateFileFromPathUnsafe( self.handle.as_ptr(), - path_raw.as_ref().as_ptr() as *const c_char, + path_raw.as_ptr(), folder_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, - id_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), + id_raw.as_ptr(), systime_to_bntime(creation_time).unwrap(), &mut progress as *mut PC as *mut c_void, Some(PC::cb_progress_callback), @@ -536,8 +507,8 @@ impl Project { contents.as_ptr(), contents.len(), folder_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), ); @@ -615,9 +586,9 @@ impl Project { contents.as_ptr(), contents.len(), folder_ptr, - name_raw.as_ref().as_ptr() as *const c_char, - description_raw.as_ref().as_ptr() as *const c_char, - id_raw.as_ref().as_ptr() as *const c_char, + name_raw.as_ptr(), + description_raw.as_ptr(), + id_raw.as_ptr(), systime_to_bntime(creation_time).unwrap(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), @@ -636,10 +607,8 @@ impl Project { /// Retrieve a file in the project by unique `id` pub fn file_by_id(&self, id: S) -> Option> { - let id_raw = id.to_cstr(); - let id_ptr = id_raw.as_ref().as_ptr() as *const c_char; - - let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), id_ptr) }; + let raw_id = id.to_cstr(); + let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFile::ref_from_raw(handle) }) } @@ -647,9 +616,8 @@ impl Project { /// Retrieve a file in the project by the `path` on disk pub fn file_by_path(&self, path: S) -> Option> { let path_raw = path.to_cstr(); - let path_ptr = path_raw.as_ref().as_ptr() as *const c_char; - - let result = unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_ptr) }; + let result = + unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_raw.as_ptr()) }; let handle = NonNull::new(result)?; Some(unsafe { ProjectFile::ref_from_raw(handle) }) } diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs index d1724ab0f0..bc486ed9bd 100644 --- a/rust/src/project/file.rs +++ b/rust/src/project/file.rs @@ -8,7 +8,6 @@ use binaryninjacore_sys::{ BNProjectFileGetPathOnDisk, BNProjectFileGetProject, BNProjectFileSetDescription, BNProjectFileSetFolder, BNProjectFileSetName, }; -use std::ffi::c_char; use std::fmt::Debug; use std::ptr::{null_mut, NonNull}; use std::time::SystemTime; @@ -59,12 +58,7 @@ impl ProjectFile { /// Set the name of this file pub fn set_name(&self, value: S) -> bool { let value_raw = value.to_cstr(); - unsafe { - BNProjectFileSetName( - self.handle.as_ptr(), - value_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectFileSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the description of this file @@ -75,12 +69,7 @@ impl ProjectFile { /// Set the description of this file pub fn set_description(&self, value: S) -> bool { let value_raw = value.to_cstr(); - unsafe { - BNProjectFileSetDescription( - self.handle.as_ptr(), - value_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectFileSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the file creation time @@ -106,12 +95,7 @@ impl ProjectFile { /// * `dest` - Destination path for the exported contents pub fn export(&self, dest: S) -> bool { let dest_raw = dest.to_cstr(); - unsafe { - BNProjectFileExport( - self.handle.as_ptr(), - dest_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectFileExport(self.handle.as_ptr(), dest_raw.as_ptr()) } } } diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index b8881ddcc1..8041619724 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -8,7 +8,7 @@ use binaryninjacore_sys::{ BNProjectFolderGetName, BNProjectFolderGetParent, BNProjectFolderGetProject, BNProjectFolderSetDescription, BNProjectFolderSetName, BNProjectFolderSetParent, }; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::fmt::Debug; use std::ptr::{null_mut, NonNull}; @@ -48,12 +48,7 @@ impl ProjectFolder { /// Set the name of this folder pub fn set_name(&self, value: S) -> bool { let value_raw = value.to_cstr(); - unsafe { - BNProjectFolderSetName( - self.handle.as_ptr(), - value_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectFolderSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the description of this folder @@ -64,12 +59,7 @@ impl ProjectFolder { /// Set the description of this folder pub fn set_description(&self, value: S) -> bool { let value_raw = value.to_cstr(); - unsafe { - BNProjectFolderSetDescription( - self.handle.as_ptr(), - value_raw.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNProjectFolderSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the folder that contains this folder @@ -107,7 +97,7 @@ impl ProjectFolder { let success = unsafe { BNProjectFolderExport( self.handle.as_ptr(), - dest_raw.as_ref().as_ptr() as *const c_char, + dest_raw.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), ) diff --git a/rust/src/render_layer.rs b/rust/src/render_layer.rs index 175ee16770..7d79249143 100644 --- a/rust/src/render_layer.rs +++ b/rust/src/render_layer.rs @@ -8,7 +8,7 @@ use crate::linear_view::{LinearDisassemblyLine, LinearDisassemblyLineType, Linea use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; use crate::string::AsCStr; use binaryninjacore_sys::*; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::ptr::NonNull; /// The state in which the [`RenderLayer`] will be registered with. @@ -73,13 +73,9 @@ pub fn register_render_layer( applyToLinearViewObject: Some(cb_apply_to_linear_view_object::), freeLines: Some(cb_free_lines), }; - let result = unsafe { - BNRegisterRenderLayer( - name.to_cstr().as_ref().as_ptr() as *const _, - &mut callback, - default_state.into(), - ) - }; + let name = name.to_cstr(); + let result = + unsafe { BNRegisterRenderLayer(name.as_ptr(), &mut callback, default_state.into()) }; let core = CoreRenderLayer::from_raw(NonNull::new(result).unwrap()); (render_layer, core) } @@ -305,7 +301,7 @@ impl CoreRenderLayer { pub fn render_layer_by_name(name: S) -> Option { let name_raw = name.to_cstr(); - let result = unsafe { BNGetRenderLayerByName(name_raw.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) }; NonNull::new(result).map(Self::from_raw) } diff --git a/rust/src/repository.rs b/rust/src/repository.rs index 8d2fbafe91..27825b966f 100644 --- a/rust/src/repository.rs +++ b/rust/src/repository.rs @@ -54,12 +54,7 @@ impl Repository { pub fn plugin_by_path(&self, path: S) -> Option> { let path = path.to_cstr(); - let result = unsafe { - BNRepositoryGetPluginByPath( - self.handle.as_ptr(), - path.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNRepositoryGetPluginByPath(self.handle.as_ptr(), path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { RepositoryPlugin::ref_from_raw(h) }) } diff --git a/rust/src/repository/manager.rs b/rust/src/repository/manager.rs index e591180281..29c7360569 100644 --- a/rust/src/repository/manager.rs +++ b/rust/src/repository/manager.rs @@ -7,7 +7,6 @@ use binaryninjacore_sys::{ BNRepositoryManagerAddRepository, BNRepositoryManagerCheckForUpdates, BNRepositoryManagerGetDefaultRepository, BNRepositoryManagerGetRepositories, }; -use std::ffi::c_char; use std::fmt::Debug; use std::ptr::NonNull; @@ -31,8 +30,7 @@ impl RepositoryManager { pub fn new(plugins_path: S) -> Ref { let plugins_path = plugins_path.to_cstr(); - let result = - unsafe { BNCreateRepositoryManager(plugins_path.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNCreateRepositoryManager(plugins_path.as_ptr()) }; unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -65,22 +63,14 @@ impl RepositoryManager { let url = url.to_cstr(); let repo_path = repository_path.to_cstr(); unsafe { - BNRepositoryManagerAddRepository( - self.handle.as_ptr(), - url.as_ref().as_ptr() as *const c_char, - repo_path.as_ref().as_ptr() as *const c_char, - ) + BNRepositoryManagerAddRepository(self.handle.as_ptr(), url.as_ptr(), repo_path.as_ptr()) } } pub fn repository_by_path(&self, path: P) -> Option { let path = path.to_cstr(); - let result = unsafe { - BNRepositoryGetRepositoryByPath( - self.handle.as_ptr(), - path.as_ref().as_ptr() as *const c_char, - ) - }; + let result = + unsafe { BNRepositoryGetRepositoryByPath(self.handle.as_ptr(), path.as_ptr()) }; NonNull::new(result).map(|raw| unsafe { Repository::from_raw(raw) }) } diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index 7acf6d4bbc..7a807300c3 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -37,7 +37,7 @@ impl CoreSecretsProvider { deleteData: Some(cb_delete_data::), }; let result = - unsafe { BNRegisterSecretsProvider(name.as_ptr() as *const c_char, &mut callbacks) }; + unsafe { BNRegisterSecretsProvider(name.as_ptr(), &mut callbacks) }; unsafe { Self::from_raw(NonNull::new(result).unwrap()) } } @@ -52,7 +52,7 @@ impl CoreSecretsProvider { /// Retrieve a provider by name pub fn by_name(name: S) -> Option { let name = name.to_cstr(); - let result = unsafe { BNGetSecretsProviderByName(name.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNGetSecretsProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) } @@ -65,17 +65,13 @@ impl CoreSecretsProvider { /// Check if data for a specific key exists, but do not retrieve it pub fn has_data(&self, key: S) -> bool { let key = key.to_cstr(); - unsafe { - BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) - } + unsafe { BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ptr()) } } /// Retrieve data for the given key, if it exists pub fn get_data(&self, key: S) -> String { let key = key.to_cstr(); - let result = unsafe { - BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) }; unsafe { BnString::into_string(result) } } @@ -83,24 +79,13 @@ impl CoreSecretsProvider { pub fn store_data(&self, key: K, value: V) -> bool { let key = key.to_cstr(); let value = value.to_cstr(); - unsafe { - BNStoreSecretsProviderData( - self.handle.as_ptr(), - key.as_ref().as_ptr() as *const c_char, - value.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNStoreSecretsProviderData(self.handle.as_ptr(), key.as_ptr(), value.as_ptr()) } } /// Delete stored data with the given key pub fn delete_data(&self, key: S) -> bool { let key = key.to_cstr(); - unsafe { - BNDeleteSecretsProviderData( - self.handle.as_ptr(), - key.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNDeleteSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) } } } diff --git a/rust/src/section.rs b/rust/src/section.rs index d1098e6776..53afffb335 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -14,7 +14,6 @@ //! Sections are [crate::segment::Segment]s that are loaded into memory at run time -use std::ffi::c_char; use std::fmt; use std::ops::Range; @@ -282,29 +281,29 @@ impl SectionBuilder { if self.is_auto { BNAddAutoSection( view.handle, - name.as_ptr() as *const c_char, + name.as_ptr(), start, len, self.semantics.into(), - ty.as_ptr() as *const c_char, + ty.as_ptr(), self.align, self.entry_size, - linked_section.as_ptr() as *const c_char, - info_section.as_ptr() as *const c_char, + linked_section.as_ptr(), + info_section.as_ptr(), self.info_data, ); } else { BNAddUserSection( view.handle, - name.as_ptr() as *const c_char, + name.as_ptr(), start, len, self.semantics.into(), - ty.as_ptr() as *const c_char, + ty.as_ptr(), self.align, self.entry_size, - linked_section.as_ptr() as *const c_char, - info_section.as_ptr() as *const c_char, + linked_section.as_ptr(), + info_section.as_ptr(), self.info_data, ); } diff --git a/rust/src/settings.rs b/rust/src/settings.rs index b49dbdea8b..be2fd955f5 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -47,7 +47,7 @@ impl Settings { pub fn new_with_id(instance_id: S) -> Ref { let instance_id = instance_id.to_cstr(); unsafe { - let handle = BNCreateSettings(instance_id.as_ref().as_ptr() as *mut _); + let handle = BNCreateSettings(instance_id.as_ptr()); debug_assert!(!handle.is_null()); Ref::new(Self { handle }) } @@ -55,7 +55,7 @@ impl Settings { pub fn set_resource_id(&self, resource_id: S) { let resource_id = resource_id.to_cstr(); - unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ref().as_ptr() as *mut _) }; + unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ptr()) }; } pub fn serialize_schema(&self) -> String { @@ -72,20 +72,13 @@ impl Settings { scope: SettingsScope, ) -> bool { let schema = schema.to_cstr(); - unsafe { - BNSettingsDeserializeSchema( - self.handle, - schema.as_ref().as_ptr() as *mut _, - scope, - true, - ) - } + unsafe { BNSettingsDeserializeSchema(self.handle, schema.as_ptr(), scope, true) } } pub fn contains(&self, key: S) -> bool { let key = key.to_cstr(); - unsafe { BNSettingsContains(self.handle, key.as_ref().as_ptr() as *mut _) } + unsafe { BNSettingsContains(self.handle, key.as_ptr()) } } pub fn keys(&self) -> Array { @@ -114,7 +107,7 @@ impl Settings { unsafe { BNSettingsGetBool( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -139,7 +132,7 @@ impl Settings { unsafe { BNSettingsGetDouble( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -164,7 +157,7 @@ impl Settings { unsafe { BNSettingsGetUInt64( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -189,7 +182,7 @@ impl Settings { unsafe { BnString::into_string(BNSettingsGetString( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -220,7 +213,7 @@ impl Settings { Array::new( BNSettingsGetStringList( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -249,7 +242,7 @@ impl Settings { unsafe { BnString::into_string(BNSettingsGetJson( self.handle, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), view_ptr, func_ptr, &mut options.scope, @@ -277,7 +270,7 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), value, ); } @@ -302,7 +295,7 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), value, ); } @@ -328,7 +321,7 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), value, ); } @@ -360,8 +353,8 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_ptr(), + value.as_ptr(), ); } } @@ -382,10 +375,7 @@ impl Settings { ) -> bool { let key = key.to_cstr(); let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); - let mut raw_list_ptr: Vec<_> = raw_list - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut raw_list_ptr: Vec<_> = raw_list.iter().map(|s| s.as_ptr()).collect(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -401,7 +391,7 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, + key.as_ptr(), raw_list_ptr.as_mut_ptr(), raw_list_ptr.len(), ) @@ -434,8 +424,8 @@ impl Settings { view_ptr, func_ptr, options.scope, - key.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_ptr(), + value.as_ptr(), ) } } @@ -446,8 +436,8 @@ impl Settings { unsafe { BnString::into_string(BNSettingsQueryPropertyString( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_ptr(), + property.as_ptr(), )) } } @@ -460,8 +450,8 @@ impl Settings { Array::new( BNSettingsQueryPropertyStringList( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_ptr(), + property.as_ptr(), &mut size, ) as *mut *mut c_char, size, @@ -474,12 +464,7 @@ impl Settings { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { - BNSettingsUpdateBoolProperty( - self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - value, - ); + BNSettingsUpdateBoolProperty(self.handle, key.as_ptr(), property.as_ptr(), value); } } @@ -487,12 +472,7 @@ impl Settings { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { - BNSettingsUpdateUInt64Property( - self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - value, - ); + BNSettingsUpdateUInt64Property(self.handle, key.as_ptr(), property.as_ptr(), value); } } @@ -500,12 +480,7 @@ impl Settings { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { - BNSettingsUpdateDoubleProperty( - self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - value, - ); + BNSettingsUpdateDoubleProperty(self.handle, key.as_ptr(), property.as_ptr(), value); } } @@ -516,9 +491,9 @@ impl Settings { unsafe { BNSettingsUpdateStringProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, - value.as_ref().as_ptr() as *mut _, + key.as_ptr(), + property.as_ptr(), + value.as_ptr(), ); } } @@ -532,16 +507,13 @@ impl Settings { let key = key.to_cstr(); let property = property.to_cstr(); let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); - let mut raw_list_ptr: Vec<_> = raw_list - .iter() - .map(|s| s.as_ref().as_ptr() as *const c_char) - .collect(); + let mut raw_list_ptr: Vec<_> = raw_list.iter().map(|s| s.as_ptr()).collect(); unsafe { BNSettingsUpdateStringListProperty( self.handle, - key.as_ref().as_ptr() as *mut _, - property.as_ref().as_ptr() as *mut _, + key.as_ptr(), + property.as_ptr(), raw_list_ptr.as_mut_ptr(), raw_list_ptr.len(), ); @@ -552,26 +524,14 @@ impl Settings { let group = group.to_cstr(); let title = title.to_cstr(); - unsafe { - BNSettingsRegisterGroup( - self.handle, - group.as_ref().as_ptr() as *mut _, - title.as_ref().as_ptr() as *mut _, - ) - } + unsafe { BNSettingsRegisterGroup(self.handle, group.as_ptr(), title.as_ptr()) } } pub fn register_setting_json(&self, group: S1, properties: S2) -> bool { let group = group.to_cstr(); let properties = properties.to_cstr(); - unsafe { - BNSettingsRegisterSetting( - self.handle, - group.as_ref().as_ptr() as *mut _, - properties.as_ref().as_ptr() as *mut _, - ) - } + unsafe { BNSettingsRegisterSetting(self.handle, group.as_ptr(), properties.as_ptr()) } } // TODO: register_setting but type-safely turn it into json diff --git a/rust/src/string.rs b/rust/src/string.rs index 17fcf911cf..640731ffc0 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -23,6 +23,7 @@ use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; +use crate::type_archive::TypeArchiveSnapshotId; // TODO: Remove or refactor this. pub(crate) fn raw_to_string(ptr: *const c_char) -> Option { @@ -291,6 +292,14 @@ unsafe impl AsCStr for &Path { } } +unsafe impl AsCStr for TypeArchiveSnapshotId { + type Result = CString; + + fn to_cstr(self) -> Self::Result { + self.to_string().to_cstr() + } +} + pub trait IntoJson { type Output: AsCStr; diff --git a/rust/src/tags.rs b/rust/src/tags.rs index 30cc46827a..72cae705ca 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -44,7 +44,7 @@ impl Tag { pub fn new(t: &TagType, data: S) -> Ref { let data = data.to_cstr(); - unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ref().as_ptr() as *mut _)) } + unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ptr())) } } pub fn id(&self) -> String { @@ -62,7 +62,7 @@ impl Tag { pub fn set_data(&self, data: S) { let data = data.to_cstr(); unsafe { - BNTagSetData(self.handle, data.as_ref().as_ptr() as *mut _); + BNTagSetData(self.handle, data.as_ptr()); } } } @@ -152,7 +152,7 @@ impl TagType { pub fn set_icon(&self, icon: S) { let icon = icon.to_cstr(); unsafe { - BNTagTypeSetIcon(self.handle, icon.as_ref().as_ptr() as *mut _); + BNTagTypeSetIcon(self.handle, icon.as_ptr()); } } @@ -163,7 +163,7 @@ impl TagType { pub fn set_name(&self, name: S) { let name = name.to_cstr(); unsafe { - BNTagTypeSetName(self.handle, name.as_ref().as_ptr() as *mut _); + BNTagTypeSetName(self.handle, name.as_ptr()); } } @@ -182,7 +182,7 @@ impl TagType { pub fn set_type(&self, t: S) { let t = t.to_cstr(); unsafe { - BNTagTypeSetName(self.handle, t.as_ref().as_ptr() as *mut _); + BNTagTypeSetName(self.handle, t.as_ptr()); } } diff --git a/rust/src/template_simplifier.rs b/rust/src/template_simplifier.rs index 57d2b0b4ea..c9e54e72c9 100644 --- a/rust/src/template_simplifier.rs +++ b/rust/src/template_simplifier.rs @@ -6,15 +6,10 @@ use binaryninjacore_sys::{BNRustSimplifyStrToFQN, BNRustSimplifyStrToStr}; pub fn simplify_str_to_str(input: S) -> BnString { let name = input.to_cstr(); - unsafe { BnString::from_raw(BNRustSimplifyStrToStr(name.as_ref().as_ptr() as *mut _)) } + unsafe { BnString::from_raw(BNRustSimplifyStrToStr(name.as_ptr())) } } pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { let name = input.to_cstr(); - unsafe { - QualifiedName::from_owned_raw(BNRustSimplifyStrToFQN( - name.as_ref().as_ptr() as *mut _, - simplify, - )) - } + unsafe { QualifiedName::from_owned_raw(BNRustSimplifyStrToFQN(name.as_ptr(), simplify)) } } diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 5e94f19e7a..2daca983a2 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -66,7 +66,7 @@ impl TypeArchive { /// Open the Type Archive at the given path, if it exists. pub fn open(path: impl AsRef) -> Option> { let raw_path = path.as_ref().to_cstr(); - let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr() as *const c_char) }; + let handle = unsafe { BNOpenTypeArchive(raw_path.as_ptr()) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } @@ -76,7 +76,7 @@ impl TypeArchive { pub fn create(path: impl AsRef, platform: &Platform) -> Option> { let raw_path = path.as_ref().to_cstr(); let handle = - unsafe { BNCreateTypeArchive(raw_path.as_ptr() as *const c_char, platform.handle) }; + unsafe { BNCreateTypeArchive(raw_path.as_ptr(), platform.handle) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } @@ -90,20 +90,15 @@ impl TypeArchive { ) -> Option> { let raw_path = path.as_ref().to_cstr(); let id = id.to_cstr(); - let handle = unsafe { - BNCreateTypeArchiveWithId( - raw_path.as_ptr() as *const c_char, - platform.handle, - id.as_ref().as_ptr() as *const c_char, - ) - }; + let handle = + unsafe { BNCreateTypeArchiveWithId(raw_path.as_ptr(), platform.handle, id.as_ptr()) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } /// Get a reference to the Type Archive with the known id, if one exists. pub fn lookup_by_id(id: S) -> Option> { let id = id.to_cstr(); - let handle = unsafe { BNLookupTypeArchiveById(id.as_ref().as_ptr() as *const c_char) }; + let handle = unsafe { BNLookupTypeArchiveById(id.as_ptr()) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } @@ -238,13 +233,8 @@ impl TypeArchive { pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { let id = id.to_cstr(); let raw_name = QualifiedName::into_raw(new_name); - let result = unsafe { - BNRenameTypeArchiveType( - self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, - &raw_name, - ) - }; + let result = + unsafe { BNRenameTypeArchiveType(self.handle.as_ptr(), id.as_ptr(), &raw_name) }; QualifiedName::free_raw(raw_name); result } @@ -261,9 +251,7 @@ impl TypeArchive { /// Delete an existing type in the type archive. pub fn delete_type_by_id(&self, id: S) -> bool { let id = id.to_cstr(); - let result = unsafe { - BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) }; result } @@ -315,7 +303,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveTypeById( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, ) }; @@ -342,7 +330,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveTypeName( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, ) }; @@ -497,7 +485,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveOutgoingDirectTypeReferences( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, &mut count, ) @@ -527,7 +515,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveOutgoingRecursiveTypeReferences( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, &mut count, ) @@ -557,7 +545,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveIncomingDirectTypeReferences( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, &mut count, ) @@ -587,7 +575,7 @@ impl TypeArchive { let result = unsafe { BNGetTypeArchiveIncomingRecursiveTypeReferences( self.handle.as_ptr(), - id.as_ref().as_ptr() as *const c_char, + id.as_ptr(), snapshot.0.as_ptr() as *const c_char, &mut count, ) @@ -599,9 +587,7 @@ impl TypeArchive { /// Look up a metadata entry in the archive pub fn query_metadata(&self, key: S) -> Option> { let key = key.to_cstr(); - let result = unsafe { - BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ref().as_ptr() as *const c_char) - }; + let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) } @@ -611,25 +597,15 @@ impl TypeArchive { /// * `md` - object to store. pub fn store_metadata(&self, key: S, md: &Metadata) { let key = key.to_cstr(); - let result = unsafe { - BNTypeArchiveStoreMetadata( - self.handle.as_ptr(), - key.as_ref().as_ptr() as *const c_char, - md.handle, - ) - }; + let result = + unsafe { BNTypeArchiveStoreMetadata(self.handle.as_ptr(), key.as_ptr(), md.handle) }; assert!(result); } /// Delete a given metadata entry in the archive from the `key` pub fn remove_metadata(&self, key: S) -> bool { let key = key.to_cstr(); - unsafe { - BNTypeArchiveRemoveMetadata( - self.handle.as_ptr(), - key.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNTypeArchiveRemoveMetadata(self.handle.as_ptr(), key.as_ptr()) } } /// Turn a given `snapshot` id into a data stream @@ -708,7 +684,7 @@ impl TypeArchive { /// Determine if `file` is a Type Archive pub fn is_type_archive(file: P) -> bool { let file = file.to_cstr(); - unsafe { BNIsTypeArchive(file.as_ref().as_ptr() as *const c_char) } + unsafe { BNIsTypeArchive(file.as_ptr()) } } ///// Get the TypeContainer interface for this Type Archive, presenting types @@ -840,9 +816,9 @@ impl TypeArchive { let success = unsafe { BNTypeArchiveMergeSnapshots( self.handle.as_ptr(), - base_snapshot.as_ref().as_ptr() as *const c_char, - first_snapshot.as_ref().as_ptr() as *const c_char, - second_snapshot.as_ref().as_ptr() as *const c_char, + base_snapshot.as_ptr(), + first_snapshot.as_ptr(), + second_snapshot.as_ptr(), merge_keys_raw, merge_values_raw, merge_keys.len(), @@ -1169,12 +1145,7 @@ impl TypeArchiveMergeConflict { // TODO: This needs documentation! pub fn success(&self, value: S) -> bool { let value = value.to_cstr(); - unsafe { - BNTypeArchiveMergeConflictSuccess( - self.handle.as_ptr(), - value.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) } } } diff --git a/rust/src/type_container.rs b/rust/src/type_container.rs index 5941b31335..90b2ebc91e 100644 --- a/rust/src/type_container.rs +++ b/rust/src/type_container.rs @@ -140,13 +140,8 @@ impl TypeContainer { pub fn rename_type, S: AsCStr>(&self, name: T, type_id: S) -> bool { let type_id = type_id.to_cstr(); let raw_name = QualifiedName::into_raw(name.into()); - let success = unsafe { - BNTypeContainerRenameType( - self.handle.as_ptr(), - type_id.as_ref().as_ptr() as *const c_char, - &raw_name, - ) - }; + let success = + unsafe { BNTypeContainerRenameType(self.handle.as_ptr(), type_id.as_ptr(), &raw_name) }; QualifiedName::free_raw(raw_name); success } @@ -157,12 +152,7 @@ impl TypeContainer { /// Returns true if the type was deleted. pub fn delete_type(&self, type_id: S) -> bool { let type_id = type_id.to_cstr(); - unsafe { - BNTypeContainerDeleteType( - self.handle.as_ptr(), - type_id.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNTypeContainerDeleteType(self.handle.as_ptr(), type_id.as_ptr()) } } /// Get the unique id of the type in the Type Container with the given name. @@ -184,11 +174,7 @@ impl TypeContainer { let type_id = type_id.to_cstr(); let mut result = BNQualifiedName::default(); let success = unsafe { - BNTypeContainerGetTypeName( - self.handle.as_ptr(), - type_id.as_ref().as_ptr() as *const c_char, - &mut result, - ) + BNTypeContainerGetTypeName(self.handle.as_ptr(), type_id.as_ptr(), &mut result) }; success.then(|| QualifiedName::from_owned_raw(result)) } @@ -200,11 +186,7 @@ impl TypeContainer { let type_id = type_id.to_cstr(); let mut result = std::ptr::null_mut(); let success = unsafe { - BNTypeContainerGetTypeById( - self.handle.as_ptr(), - type_id.as_ref().as_ptr() as *const c_char, - &mut result, - ) + BNTypeContainerGetTypeById(self.handle.as_ptr(), type_id.as_ptr(), &mut result) }; success.then(|| unsafe { Type::ref_from_raw(result) }) } @@ -313,7 +295,7 @@ impl TypeContainer { let success = unsafe { BNTypeContainerParseTypeString( self.handle.as_ptr(), - source.as_ref().as_ptr() as *const c_char, + source.as_ptr(), import_dependencies, &mut result, &mut errors, @@ -358,18 +340,13 @@ impl TypeContainer { let source = source.to_cstr(); let filename = filename.to_cstr(); let options: Vec<_> = options.into_iter().map(|o| o.to_cstr()).collect(); - let options_raw: Vec<*const c_char> = options - .iter() - .map(|o| o.as_ref().as_ptr() as *const c_char) - .collect(); + let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect(); let include_directories: Vec<_> = include_directories .into_iter() .map(|d| d.to_cstr()) .collect(); - let include_directories_raw: Vec<*const c_char> = include_directories - .iter() - .map(|d| d.as_ref().as_ptr() as *const c_char) - .collect(); + let include_directories_raw: Vec<*const c_char> = + include_directories.iter().map(|d| d.as_ptr()).collect(); let auto_type_source = auto_type_source.to_cstr(); let mut raw_result = BNTypeParserResult::default(); let mut errors = std::ptr::null_mut(); @@ -377,13 +354,13 @@ impl TypeContainer { let success = unsafe { BNTypeContainerParseTypesFromSource( self.handle.as_ptr(), - source.as_ref().as_ptr() as *const c_char, - filename.as_ref().as_ptr() as *const c_char, + source.as_ptr(), + filename.as_ptr(), options_raw.as_ptr(), options_raw.len(), include_directories_raw.as_ptr(), include_directories_raw.len(), - auto_type_source.as_ref().as_ptr() as *const c_char, + auto_type_source.as_ptr(), import_dependencies, &mut raw_result, &mut errors, diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index 1cfe346cd7..af17a17f72 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -29,9 +29,8 @@ pub fn register_type_parser( freeResult: Some(cb_free_result), freeErrorList: Some(cb_free_error_list), }; - let result = unsafe { - BNRegisterTypeParser(name.to_cstr().as_ref().as_ptr() as *const _, &mut callback) - }; + let name = name.to_cstr(); + let result = unsafe { BNRegisterTypeParser(name.as_ptr(), &mut callback) }; let core = unsafe { CoreTypeParser::from_raw(NonNull::new(result).unwrap()) }; (parser, core) } @@ -54,7 +53,7 @@ impl CoreTypeParser { pub fn parser_by_name(name: S) -> Option { let name_raw = name.to_cstr(); - let result = unsafe { BNGetTypeParserByName(name_raw.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNGetTypeParserByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index b49832def2..278e486a6b 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -34,12 +34,8 @@ pub fn register_type_printer( freeString: Some(cb_free_string), freeLines: Some(cb_free_lines), }; - let result = unsafe { - BNRegisterTypePrinter( - name.to_cstr().as_ref().as_ptr() as *const c_char, - &mut callback, - ) - }; + let raw_name = name.to_cstr(); + let result = unsafe { BNRegisterTypePrinter(raw_name.as_ptr(), &mut callback) }; let core = unsafe { CoreTypePrinter::from_raw(NonNull::new(result).unwrap()) }; (parser, core) } @@ -63,7 +59,7 @@ impl CoreTypePrinter { pub fn printer_by_name(name: S) -> Option { let name_raw = name.to_cstr(); - let result = unsafe { BNGetTypePrinterByName(name_raw.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNGetTypePrinterByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) } diff --git a/rust/src/update.rs b/rust/src/update.rs index aa8c7daf38..b3c45d8404 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{raw_to_string, BnString}; +use crate::string::{raw_to_string, AsCStr, BnString}; use binaryninjacore_sys::*; pub type UpdateResult = BNUpdateResult; @@ -96,8 +96,9 @@ impl UpdateChannel { pub fn versions(&self) -> Result, BnString> { let mut count = 0; let mut errors = std::ptr::null_mut(); + let name = self.name.clone().to_cstr(); let result = unsafe { - BNGetUpdateChannelVersions(self.name.as_ptr() as *const c_char, &mut count, &mut errors) + BNGetUpdateChannelVersions(name.as_ptr(), &mut count, &mut errors) }; if !errors.is_null() { Err(unsafe { BnString::from_raw(errors) }) @@ -122,9 +123,10 @@ impl UpdateChannel { /// Whether updates are available pub fn updates_available(&self) -> Result { let mut errors = std::ptr::null_mut(); + let name = self.name.clone().to_cstr(); let result = unsafe { BNAreUpdatesAvailable( - self.name.as_ptr() as *const c_char, + name.as_ptr(), std::ptr::null_mut(), std::ptr::null_mut(), &mut errors, @@ -147,9 +149,10 @@ impl UpdateChannel { ) -> Result { let mut errors = std::ptr::null_mut(); + let name = self.name.clone().to_cstr(); let result = unsafe { BNUpdateToLatestVersion( - self.name.as_ptr() as *const c_char, + name.as_ptr(), &mut errors, Some(P::cb_progress_callback), &mut progress as *mut P as *mut c_void, @@ -174,10 +177,12 @@ impl UpdateChannel { ) -> Result { let mut errors = std::ptr::null_mut(); + let name = self.name.clone().to_cstr(); + let version = version.version.clone().to_cstr(); let result = unsafe { BNUpdateToVersion( - self.name.as_ptr() as *const c_char, - version.version.as_ptr() as *const c_char, + name.as_ptr(), + version.as_ptr(), &mut errors, Some(P::cb_progress_callback), &mut progress as *mut P as *mut c_void, diff --git a/rust/src/websocket/client.rs b/rust/src/websocket/client.rs index 43e1e1f785..e9e753b185 100644 --- a/rust/src/websocket/client.rs +++ b/rust/src/websocket/client.rs @@ -86,14 +86,8 @@ impl CoreWebsocketClient { .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); - let header_keys: Vec<*const c_char> = header_keys - .iter() - .map(|k| k.as_ref().as_ptr() as *const c_char) - .collect(); - let header_values: Vec<*const c_char> = header_values - .iter() - .map(|v| v.as_ref().as_ptr() as *const c_char) - .collect(); + let header_keys: Vec<*const c_char> = header_keys.iter().map(|k| k.as_ptr()).collect(); + let header_values: Vec<*const c_char> = header_values.iter().map(|v| v.as_ptr()).collect(); // SAFETY: This context will only be live for the duration of BNConnectWebsocketClient // SAFETY: Any subsequent call to BNConnectWebsocketClient will write over the context. let mut output_callbacks = BNWebsocketClientOutputCallbacks { @@ -106,7 +100,7 @@ impl CoreWebsocketClient { unsafe { BNConnectWebsocketClient( self.handle.as_ptr(), - url.as_ptr() as *const c_char, + url.as_ptr(), header_keys.len().try_into().unwrap(), header_keys.as_ptr(), header_values.as_ptr(), @@ -131,7 +125,7 @@ impl CoreWebsocketClient { pub fn notify_error(&self, msg: &str) { let error = msg.to_cstr(); unsafe { - BNNotifyWebsocketClientError(self.handle.as_ptr(), error.as_ptr() as *const c_char) + BNNotifyWebsocketClientError(self.handle.as_ptr(), error.as_ptr()) } } diff --git a/rust/src/websocket/provider.rs b/rust/src/websocket/provider.rs index 48c198d2b9..9cc1de8423 100644 --- a/rust/src/websocket/provider.rs +++ b/rust/src/websocket/provider.rs @@ -3,7 +3,7 @@ use crate::string::{AsCStr, BnString}; use crate::websocket::client; use crate::websocket::client::{CoreWebsocketClient, WebsocketClient}; use binaryninjacore_sys::*; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::mem::MaybeUninit; use std::ptr::NonNull; @@ -17,7 +17,7 @@ where let leaked_provider = Box::leak(Box::new(provider_uninit)); let result = unsafe { BNRegisterWebsocketProvider( - name.as_ptr() as *const c_char, + name.as_ptr(), &mut BNWebsocketProviderCallbacks { context: leaked_provider as *mut _ as *mut c_void, createClient: Some(cb_create_client::), @@ -82,8 +82,7 @@ impl CoreWebsocketProvider { pub fn by_name(name: S) -> Option { let name = name.to_cstr(); - let result = - unsafe { BNGetWebsocketProviderByName(name.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNGetWebsocketProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) } diff --git a/rust/src/worker_thread.rs b/rust/src/worker_thread.rs index aed872decf..e0d7b0dbde 100644 --- a/rust/src/worker_thread.rs +++ b/rust/src/worker_thread.rs @@ -1,6 +1,6 @@ use crate::string::AsCStr; use binaryninjacore_sys::*; -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; pub struct WorkerThreadActionExecutor { func: Box, @@ -25,7 +25,7 @@ pub fn execute_on_worker_thread(name: S, f: F) { BNWorkerEnqueueNamed( raw_executor as *mut c_void, Some(WorkerThreadActionExecutor::cb_execute), - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), ) } } @@ -38,7 +38,7 @@ pub fn execute_on_worker_thread_priority(name: S, BNWorkerPriorityEnqueueNamed( raw_executor as *mut c_void, Some(WorkerThreadActionExecutor::cb_execute), - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), ) } } @@ -51,7 +51,7 @@ pub fn execute_on_worker_thread_interactive(name: BNWorkerInteractiveEnqueueNamed( raw_executor as *mut c_void, Some(WorkerThreadActionExecutor::cb_execute), - name.as_ref().as_ptr() as *const c_char, + name.as_ptr(), ) } } diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index b502381578..9bbc0b312a 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -110,12 +110,7 @@ impl AnalysisContext { pub fn inform(&self, request: S) -> bool { let request = request.to_cstr(); - unsafe { - BNAnalysisContextInform( - self.handle.as_ptr(), - request.as_ref().as_ptr() as *const c_char, - ) - } + unsafe { BNAnalysisContextInform(self.handle.as_ptr(), request.as_ptr()) } } pub fn set_basic_blocks(&self, blocks: I) @@ -169,13 +164,8 @@ impl Activity { pub fn new(config: S) -> Ref { unsafe extern "C" fn cb_action_nop(_: *mut c_void, _: *mut BNAnalysisContext) {} let config = config.to_cstr(); - let result = unsafe { - BNCreateActivity( - config.as_ref().as_ptr() as *const c_char, - std::ptr::null_mut(), - Some(cb_action_nop), - ) - }; + let result = + unsafe { BNCreateActivity(config.as_ptr(), std::ptr::null_mut(), Some(cb_action_nop)) }; unsafe { Activity::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -196,7 +186,7 @@ impl Activity { let config = config.to_cstr(); let result = unsafe { BNCreateActivity( - config.as_ref().as_ptr() as *const c_char, + config.as_ptr(), &mut action as *mut F as *mut c_void, Some(cb_action::), ) @@ -252,7 +242,7 @@ impl Workflow { /// To get a copy of an existing registered [Workflow] use [Workflow::clone_to]. pub fn new(name: S) -> Ref { let name = name.to_cstr(); - let result = unsafe { BNCreateWorkflow(name.as_ref().as_ptr() as *const c_char) }; + let result = unsafe { BNCreateWorkflow(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -280,8 +270,8 @@ impl Workflow { Self::ref_from_raw( NonNull::new(BNWorkflowClone( self.handle.as_ptr(), - raw_name.as_ref().as_ptr() as *const c_char, - activity.as_ref().as_ptr() as *const c_char, + raw_name.as_ptr(), + activity.as_ptr(), )) .unwrap(), ) @@ -289,8 +279,8 @@ impl Workflow { } pub fn instance(name: S) -> Ref { - let result = - unsafe { BNWorkflowInstance(name.to_cstr().as_ref().as_ptr() as *const c_char) }; + let name = name.to_cstr(); + let result = unsafe { BNWorkflowInstance(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } } @@ -318,12 +308,7 @@ impl Workflow { /// * `configuration` - a JSON representation of the workflow configuration pub fn register_with_config(&self, config: S) -> Result<(), ()> { let config = config.to_cstr(); - if unsafe { - BNRegisterWorkflow( - self.handle.as_ptr(), - config.as_ref().as_ptr() as *const c_char, - ) - } { + if unsafe { BNRegisterWorkflow(self.handle.as_ptr(), config.as_ptr()) } { Ok(()) } else { Err(()) @@ -351,10 +336,8 @@ impl Workflow { I::Item: AsCStr, { let subactivities_raw: Vec<_> = subactivities.into_iter().map(|x| x.to_cstr()).collect(); - let mut subactivities_ptr: Vec<*const _> = subactivities_raw - .iter() - .map(|x| x.as_ref().as_ptr() as *const c_char) - .collect(); + let mut subactivities_ptr: Vec<*const _> = + subactivities_raw.iter().map(|x| x.as_ptr()).collect(); let result = unsafe { BNWorkflowRegisterActivity( self.handle.as_ptr(), @@ -369,12 +352,8 @@ impl Workflow { /// Determine if an Activity exists in this [Workflow]. pub fn contains(&self, activity: A) -> bool { - unsafe { - BNWorkflowContains( - self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, - ) - } + let activity = activity.to_cstr(); + unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.as_ptr()) } } /// Retrieve the configuration as an adjacency list in JSON for the [Workflow]. @@ -387,12 +366,8 @@ impl Workflow { /// /// `activity` - return the configuration for the `activity` pub fn configuration_with_activity(&self, activity: A) -> String { - let result = unsafe { - BNWorkflowGetConfiguration( - self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, - ) - }; + let activity = activity.to_cstr(); + let result = unsafe { BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.as_ptr()) }; assert!(!result.is_null()); unsafe { BnString::into_string(result) } } @@ -409,12 +384,7 @@ impl Workflow { /// Retrieve the Activity object for the specified `name`. pub fn activity(&self, name: A) -> Option> { let name = name.to_cstr(); - let result = unsafe { - BNWorkflowGetActivity( - self.handle.as_ptr(), - name.as_ref().as_ptr() as *const c_char, - ) - }; + let result = unsafe { BNWorkflowGetActivity(self.handle.as_ptr(), name.as_ptr()) }; NonNull::new(result).map(|a| unsafe { Activity::ref_from_raw(a) }) } @@ -423,13 +393,10 @@ impl Workflow { /// /// * `activity` - if specified, return the roots for the `activity` pub fn activity_roots(&self, activity: A) -> Array { + let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { - BNWorkflowGetActivityRoots( - self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, - &mut count, - ) + BNWorkflowGetActivityRoots(self.handle.as_ptr(), activity.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result as *mut *mut c_char, count, ()) } @@ -440,11 +407,12 @@ impl Workflow { /// * `activity` - if specified, return the direct children and optionally the descendants of the `activity` (includes `activity`) /// * `immediate` - whether to include only direct children of `activity` or all descendants pub fn subactivities(&self, activity: A, immediate: bool) -> Array { + let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { BNWorkflowGetSubactivities( self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, + activity.as_ptr(), immediate, &mut count, ) @@ -463,15 +431,13 @@ impl Workflow { I: IntoIterator, I::Item: AsCStr, { + let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); - let mut input_list_ptr: Vec<*const _> = input_list - .iter() - .map(|x| x.as_ref().as_ptr() as *const c_char) - .collect(); + let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect(); unsafe { BNWorkflowAssignSubactivities( self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, + activity.as_ptr(), input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -493,15 +459,13 @@ impl Workflow { I: IntoIterator, I::Item: AsCStr, { + let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); - let mut input_list_ptr: Vec<*const _> = input_list - .iter() - .map(|x| x.as_ref().as_ptr() as *const c_char) - .collect(); + let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect(); unsafe { BNWorkflowInsert( self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, + activity.as_ptr(), input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -518,15 +482,13 @@ impl Workflow { I: IntoIterator, I::Item: AsCStr, { + let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); - let mut input_list_ptr: Vec<*const _> = input_list - .iter() - .map(|x| x.as_ref().as_ptr() as *const c_char) - .collect(); + let mut input_list_ptr: Vec<*const _> = input_list.iter().map(|x| x.as_ptr()).collect(); unsafe { BNWorkflowInsertAfter( self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, + activity.as_ptr(), input_list_ptr.as_mut_ptr(), input_list.len(), ) @@ -535,12 +497,8 @@ impl Workflow { /// Remove the specified `activity` pub fn remove(&self, activity: A) -> bool { - unsafe { - BNWorkflowRemove( - self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, - ) - } + let activity = activity.to_cstr(); + unsafe { BNWorkflowRemove(self.handle.as_ptr(), activity.as_ptr()) } } /// Replace the specified `activity`. @@ -548,11 +506,13 @@ impl Workflow { /// * `activity` - the Activity to replace /// * `new_activity` - the replacement Activity pub fn replace(&self, activity: A, new_activity: N) -> bool { + let activity = activity.to_cstr(); + let new_activity = new_activity.to_cstr(); unsafe { BNWorkflowReplace( self.handle.as_ptr(), - activity.to_cstr().as_ref().as_ptr() as *const c_char, - new_activity.to_cstr().as_ref().as_ptr() as *const c_char, + activity.as_ptr(), + new_activity.as_ptr(), ) } } @@ -567,14 +527,9 @@ impl Workflow { sequential: Option, ) -> Option> { let sequential = sequential.unwrap_or(false); - let activity_name = activity.to_cstr(); - let graph = unsafe { - BNWorkflowGetGraph( - self.handle.as_ptr(), - activity_name.as_ref().as_ptr() as *const c_char, - sequential, - ) - }; + let activity = activity.to_cstr(); + let graph = + unsafe { BNWorkflowGetGraph(self.handle.as_ptr(), activity.as_ptr(), sequential) }; if graph.is_null() { return None; } From ae40689c1d92f1f5b70de7da27c857eb6aa90cda Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 20:33:35 -0400 Subject: [PATCH 10/54] [Rust] Make `Section::name` return `BnString` Section names come from the binary itself, we want to preserve the name as is --- rust/src/section.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/src/section.rs b/rust/src/section.rs index 53afffb335..a86c54e2c5 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -89,8 +89,8 @@ impl Section { SectionBuilder::new(name, range) } - pub fn name(&self) -> String { - unsafe { BnString::into_string(BNSectionGetName(self.handle)) } + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNSectionGetName(self.handle)) } } pub fn section_type(&self) -> String { From 6f0aa6bfb722943daffb4cc4e9440dda6edec153 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 20:43:32 -0400 Subject: [PATCH 11/54] [Rust] More cleanup regarding `BnString` - Removed `to_string` shortcut from `BnString`. - Misc formatting --- .../dwarf/dwarf_import/src/dwarfdebuginfo.rs | 2 +- plugins/dwarf/dwarf_import/src/functions.rs | 2 +- plugins/dwarf/dwarf_import/src/lib.rs | 2 ++ plugins/warp/src/cache.rs | 2 +- plugins/warp/src/convert.rs | 2 +- plugins/warp/src/plugin/copy.rs | 4 +-- rust/src/binary_view/memory_map.rs | 4 +-- rust/src/collaboration/remote.rs | 7 ++--- rust/src/database.rs | 4 +-- rust/src/debuginfo.rs | 1 + rust/src/lib.rs | 9 +++---- rust/src/metadata.rs | 26 +++++++------------ rust/src/platform.rs | 2 +- rust/src/secrets_provider.rs | 3 +-- rust/src/string.rs | 16 ++++-------- rust/src/type_archive.rs | 3 +-- rust/src/type_parser.rs | 15 ++++------- rust/src/types.rs | 10 +++---- rust/src/update.rs | 4 +-- rust/src/websocket/client.rs | 4 +-- 20 files changed, 49 insertions(+), 73 deletions(-) diff --git a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs index 136a7a8b58..017ed4befd 100644 --- a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -622,7 +622,7 @@ impl DebugInfoBuilder { .items .len() { - func.full_name = Some(symbol_full_name.to_string()); + func.full_name = Some(symbol_full_name.to_string_lossy().to_string()); } } } diff --git a/plugins/dwarf/dwarf_import/src/functions.rs b/plugins/dwarf/dwarf_import/src/functions.rs index 6400ea84fa..6277c6b547 100644 --- a/plugins/dwarf/dwarf_import/src/functions.rs +++ b/plugins/dwarf/dwarf_import/src/functions.rs @@ -117,7 +117,7 @@ pub(crate) fn parse_function_entry( if let Ok(demangled) = sym.demangle(demangle_options) { let cleaned = abi_regex.replace_all(&demangled, ""); let simplified = simplify_str_to_str(&cleaned); - full_name = Some(simplified.to_string()); + full_name = Some(simplified.to_string_lossy().to_string()); } } } diff --git a/plugins/dwarf/dwarf_import/src/lib.rs b/plugins/dwarf/dwarf_import/src/lib.rs index d51b4e1db7..1e3d02d59b 100644 --- a/plugins/dwarf/dwarf_import/src/lib.rs +++ b/plugins/dwarf/dwarf_import/src/lib.rs @@ -234,6 +234,7 @@ fn recover_names_internal( .collect::>() .join("::"), ) + .to_string_lossy() .to_string(), ); } @@ -251,6 +252,7 @@ fn recover_names_internal( .collect::>() .join("::"), ) + .to_string_lossy() .to_string(), ); } diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index 8c82c68747..7219b54712 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -439,7 +439,7 @@ pub struct TypeRefID(u64); impl From<&BNNamedTypeReference> for TypeRefID { fn from(value: &BNNamedTypeReference) -> Self { let mut hasher = DefaultHasher::new(); - hasher.write(value.id().to_bytes()); + hasher.write(value.id().as_bytes()); Self(hasher.finish()) } } diff --git a/plugins/warp/src/convert.rs b/plugins/warp/src/convert.rs index 01ba167cda..2e0fb3f101 100644 --- a/plugins/warp/src/convert.rs +++ b/plugins/warp/src/convert.rs @@ -35,7 +35,7 @@ use warp::symbol::{Symbol, SymbolModifiers}; pub fn from_bn_symbol(raw_symbol: &BNSymbol) -> Symbol { // TODO: Use this? let _is_export = raw_symbol.external(); - let symbol_name = raw_symbol.raw_name().to_string(); + let symbol_name = raw_symbol.raw_name().to_string_lossy().to_string(); match raw_symbol.sym_type() { BNSymbolType::ImportAddress => { Symbol::new( diff --git a/plugins/warp/src/plugin/copy.rs b/plugins/warp/src/plugin/copy.rs index 18da7dfb7b..b9b985fcc2 100644 --- a/plugins/warp/src/plugin/copy.rs +++ b/plugins/warp/src/plugin/copy.rs @@ -14,8 +14,8 @@ impl FunctionCommand for CopyFunctionGUID { }; let guid = cached_function_guid(func, &llil); log::info!( - "Function GUID for {}... {}", - func.symbol().short_name().to_string(), + "Function GUID for {:?}... {}", + func.symbol().short_name(), guid ); if let Ok(mut clipboard) = arboard::Clipboard::new() { diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index 3afe0a20a3..6b6d3d20a3 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -21,13 +21,13 @@ impl MemoryMap { /// JSON string representation of the base [`MemoryMap`], consisting of unresolved auto and user segments. pub fn base_description(&self) -> String { let desc_raw = unsafe { BNGetBaseMemoryMapDescription(self.view.handle) }; - unsafe { BnString::from_raw(desc_raw) }.to_string() + unsafe { BnString::into_string(desc_raw) } } /// JSON string representation of the [`MemoryMap`]. pub fn description(&self) -> String { let desc_raw = unsafe { BNGetMemoryMapDescription(self.view.handle) }; - unsafe { BnString::from_raw(desc_raw) }.to_string() + unsafe { BnString::into_string(desc_raw) } } // When enabled, the memory map will present a simplified, logical view that merges and abstracts virtual memory diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index ee37e9fbb6..4d69873aff 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -167,7 +167,7 @@ impl Remote { &self, username: U, password: P, - ) -> Option { + ) -> Option { let username = username.to_cstr(); let password = password.to_cstr(); let token = unsafe { @@ -180,7 +180,7 @@ impl Remote { if token.is_null() { None } else { - Some(unsafe { BnString::from_raw(token) }) + Some(unsafe { BnString::into_string(token) }) } } @@ -226,7 +226,8 @@ impl Remote { }; let username = options.username.to_cstr(); let token = token.to_cstr(); - let success = unsafe { BNRemoteConnect(self.handle.as_ptr(), username.as_ptr(), token.as_ptr()) }; + let success = + unsafe { BNRemoteConnect(self.handle.as_ptr(), username.as_ptr(), token.as_ptr()) }; success.then_some(()).ok_or(()) } diff --git a/rust/src/database.rs b/rust/src/database.rs index d01839d274..61d6f608ef 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -147,10 +147,10 @@ impl Database { } /// Get a dictionary of all globals - pub fn globals(&self) -> HashMap { + pub fn globals(&self) -> HashMap { self.global_keys() .iter() - .filter_map(|key| Some((key.to_string(), self.read_global(key)?.to_string()))) + .filter_map(|key| Some((key.to_string(), self.read_global(key)?))) .collect() } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 9336a28dd8..92c0170d6c 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -319,6 +319,7 @@ unsafe impl CoreArrayProviderInner for DebugInfoParser { /// /// Functions will not be created if an address is not provided, but will be able to be queried from debug info for later user analysis. pub struct DebugFunctionInfo { + // TODO: These need to be BnString if we want to support invalid UTF-8 short_name: Option, full_name: Option, raw_name: Option, diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c0b3a38cb3..08abc349f0 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -329,8 +329,7 @@ pub fn save_last_run() { pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); - let s: *mut c_char = - unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr()) }; + let s: *mut c_char = unsafe { BNGetPathRelativeToBundledPluginDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } @@ -339,8 +338,7 @@ pub fn path_relative_to_bundled_plugin_directory(path: impl AsRef) -> Resu pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); - let s: *mut c_char = - unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr()) }; + let s: *mut c_char = unsafe { BNGetPathRelativeToUserPluginDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } @@ -349,8 +347,7 @@ pub fn path_relative_to_user_plugin_directory(path: impl AsRef) -> Result< pub fn path_relative_to_user_directory(path: impl AsRef) -> Result { let path_raw = path.as_ref().to_cstr(); - let s: *mut c_char = - unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr()) }; + let s: *mut c_char = unsafe { BNGetPathRelativeToUserDirectory(path_raw.as_ptr()) }; if s.is_null() { return Err(()); } diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index cc10885a88..b6b3ce6119 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -213,7 +213,7 @@ impl Metadata { } } - pub fn get_value_store(&self) -> Result>, ()> { + pub fn get_value_store(&self) -> Result>, ()> { match self.get_type() { MetadataType::KeyValueDataType => { let ptr: *mut BNMetadataValueStore = @@ -230,7 +230,7 @@ impl Metadata { let mut map = HashMap::new(); for i in 0..size { - let key = unsafe { BnString::from_raw(keys[i]) }; + let key = unsafe { BnString::into_string(keys[i]) }; let value = unsafe { Ref::::new(Self { @@ -589,7 +589,7 @@ impl TryFrom<&Metadata> for String { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string().map(|s| s.to_string()) + value.get_string().map(|s| s.to_string_lossy().to_string()) } } @@ -637,9 +637,11 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value - .get_string_list() - .map(|v| v.into_iter().map(|s| s.to_string()).collect()) + value.get_string_list().map(|v| { + v.into_iter() + .map(|s| s.to_string_lossy().to_string()) + .collect() + }) } } @@ -659,21 +661,11 @@ impl TryFrom<&Metadata> for Array { } } -impl TryFrom<&Metadata> for HashMap> { - type Error = (); - - fn try_from(value: &Metadata) -> Result { - value.get_value_store() - } -} - impl TryFrom<&Metadata> for HashMap> { type Error = (); fn try_from(value: &Metadata) -> Result { - value - .get_value_store() - .map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect()) + value.get_value_store() } } diff --git a/rust/src/platform.rs b/rust/src/platform.rs index c225392f83..b51ad61dca 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -334,7 +334,7 @@ impl Platform { assert!(!error_string.is_null()); Err(TypeParserError::new( TypeParserErrorSeverity::FatalSeverity, - unsafe { BnString::from_raw(error_string) }.to_string(), + unsafe { BnString::into_string(error_string) }, filename.to_string(), 0, 0, diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index 7a807300c3..fcb2064411 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -36,8 +36,7 @@ impl CoreSecretsProvider { storeData: Some(cb_store_data::), deleteData: Some(cb_delete_data::), }; - let result = - unsafe { BNRegisterSecretsProvider(name.as_ptr(), &mut callbacks) }; + let result = unsafe { BNRegisterSecretsProvider(name.as_ptr(), &mut callbacks) }; unsafe { Self::from_raw(NonNull::new(result).unwrap()) } } diff --git a/rust/src/string.rs b/rust/src/string.rs index 640731ffc0..5be623c121 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -15,6 +15,7 @@ //! String wrappers for core-owned strings and strings being passed to the core use crate::rc::*; +use crate::type_archive::TypeArchiveSnapshotId; use crate::types::QualifiedName; use std::borrow::Cow; use std::ffi::{c_char, CStr, CString}; @@ -23,7 +24,6 @@ use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; -use crate::type_archive::TypeArchiveSnapshotId; // TODO: Remove or refactor this. pub(crate) fn raw_to_string(ptr: *const c_char) -> Option { @@ -72,7 +72,7 @@ impl BnString { /// /// This expects the passed raw string to be owned, as in, freed by us. pub unsafe fn into_string(raw: *mut c_char) -> String { - Self::from_raw(raw).to_string() + Self::from_raw(raw).to_string_lossy().to_string() } /// Construct a BnString from an owned const char* allocated by BNAllocString @@ -160,15 +160,9 @@ impl PartialEq for BnString { impl Eq for BnString {} -impl fmt::Display for BnString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string_lossy()) - } -} - impl fmt::Debug for BnString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_string_lossy().fmt(f) + write!(f, "{}", self.to_string_lossy()) } } @@ -294,10 +288,10 @@ unsafe impl AsCStr for &Path { unsafe impl AsCStr for TypeArchiveSnapshotId { type Result = CString; - + fn to_cstr(self) -> Self::Result { self.to_string().to_cstr() - } + } } pub trait IntoJson { diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 2daca983a2..05929561b1 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -75,8 +75,7 @@ impl TypeArchive { /// If the file has already been created and is not a valid type archive this will return `None`. pub fn create(path: impl AsRef, platform: &Platform) -> Option> { let raw_path = path.as_ref().to_cstr(); - let handle = - unsafe { BNCreateTypeArchive(raw_path.as_ptr(), platform.handle) }; + let handle = unsafe { BNCreateTypeArchive(raw_path.as_ptr(), platform.handle) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) } diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index af17a17f72..53827e65d7 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -67,18 +67,13 @@ impl CoreTypeParser { impl TypeParser for CoreTypeParser { fn get_option_text(&self, option: TypeParserOption, value: &str) -> Option { let mut output = std::ptr::null_mut(); - let value_cstr = BnString::new(value); + let value_ptr = std::ptr::null_mut(); let result = unsafe { - BNGetTypeParserOptionText( - self.handle.as_ptr(), - option, - value_cstr.as_ptr(), - &mut output, - ) + BNGetTypeParserOptionText(self.handle.as_ptr(), option, value_ptr, &mut output) }; result.then(|| { assert!(!output.is_null()); - value_cstr.to_string() + unsafe { BnString::into_string(value_ptr) } }) } @@ -114,8 +109,8 @@ impl TypeParser for CoreTypeParser { }; if success { assert!(!result.is_null()); - let bn_result = unsafe { BnString::from_raw(result) }; - Ok(bn_result.to_string()) + let bn_result = unsafe { BnString::into_string(result) }; + Ok(bn_result) } else { let errors: Array = unsafe { Array::new(errors, error_count, ()) }; Err(errors.to_vec()) diff --git a/rust/src/types.rs b/rust/src/types.rs index 710a885771..42c1f8d2bd 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -430,7 +430,7 @@ impl TypeBuilder { impl Display for TypeBuilder { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", unsafe { - BnString::from_raw(BNGetTypeBuilderString(self.handle, std::ptr::null_mut())) + BnString::into_string(BNGetTypeBuilderString(self.handle, std::ptr::null_mut())) }) } } @@ -944,7 +944,7 @@ impl Type { impl Display for Type { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", unsafe { - BnString::from_raw(BNGetTypeString( + BnString::into_string(BNGetTypeString( self.handle, std::ptr::null_mut(), BNTokenEscapingType::NoTokenEscapingType, @@ -1893,15 +1893,15 @@ impl NamedTypeReference { QualifiedName::from_owned_raw(raw_name) } - pub fn id(&self) -> BnString { - unsafe { BnString::from_raw(BNGetTypeReferenceId(self.handle)) } + pub fn id(&self) -> String { + unsafe { BnString::into_string(BNGetTypeReferenceId(self.handle)) } } pub fn class(&self) -> NamedTypeReferenceClass { unsafe { BNGetTypeReferenceClass(self.handle) } } - fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet) -> Option> { + fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet) -> Option> { let ty = bv.type_by_id(self.id())?; match ty.type_class() { TypeClass::NamedTypeReferenceClass => { diff --git a/rust/src/update.rs b/rust/src/update.rs index b3c45d8404..be85c93e1c 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -97,9 +97,7 @@ impl UpdateChannel { let mut count = 0; let mut errors = std::ptr::null_mut(); let name = self.name.clone().to_cstr(); - let result = unsafe { - BNGetUpdateChannelVersions(name.as_ptr(), &mut count, &mut errors) - }; + let result = unsafe { BNGetUpdateChannelVersions(name.as_ptr(), &mut count, &mut errors) }; if !errors.is_null() { Err(unsafe { BnString::from_raw(errors) }) } else { diff --git a/rust/src/websocket/client.rs b/rust/src/websocket/client.rs index e9e753b185..8e2c6db083 100644 --- a/rust/src/websocket/client.rs +++ b/rust/src/websocket/client.rs @@ -124,9 +124,7 @@ impl CoreWebsocketClient { /// Call the error callback function pub fn notify_error(&self, msg: &str) { let error = msg.to_cstr(); - unsafe { - BNNotifyWebsocketClientError(self.handle.as_ptr(), error.as_ptr()) - } + unsafe { BNNotifyWebsocketClientError(self.handle.as_ptr(), error.as_ptr()) } } /// Call the read callback function, forward the callback returned value From c266596022a0570c425ea10287f963acb075dfd1 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 4 May 2025 20:51:33 -0400 Subject: [PATCH 12/54] [Rust] Misc clippy lints --- rust/src/headless.rs | 8 ++++---- rust/src/project/folder.rs | 7 ++----- rust/src/string.rs | 2 +- rust/src/type_archive.rs | 3 +-- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/rust/src/headless.rs b/rust/src/headless.rs index 7279a45980..1e56321b0c 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -255,10 +255,10 @@ impl MainThreadHandler for HeadlessMainThreadSender { } fn is_enterprise_product() -> bool { - match crate::product().as_str() { - "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => true, - _ => false, - } + matches!( + crate::product().as_str(), + "Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" + ) } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index 8041619724..c7ec82e41a 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -93,17 +93,14 @@ impl ProjectFolder { P: ProgressCallback, { let dest_raw = dest.to_cstr(); - - let success = unsafe { + unsafe { BNProjectFolderExport( self.handle.as_ptr(), dest_raw.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), ) - }; - - success + } } } diff --git a/rust/src/string.rs b/rust/src/string.rs index 5be623c121..820418d066 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -189,7 +189,7 @@ pub unsafe trait AsCStr { fn to_cstr(self) -> Self::Result; } -unsafe impl<'a> AsCStr for &'a CStr { +unsafe impl AsCStr for &CStr { type Result = Self; fn to_cstr(self) -> Self::Result { diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 05929561b1..8d9dd670cf 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -250,8 +250,7 @@ impl TypeArchive { /// Delete an existing type in the type archive. pub fn delete_type_by_id(&self, id: S) -> bool { let id = id.to_cstr(); - let result = unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) }; - result + unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) } } /// Retrieve a stored type in the archive From d73c19afc590a3ddec725194265a990a6add7fdd Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 5 May 2025 13:17:30 -0400 Subject: [PATCH 13/54] [Rust] Rename `AsCStr` to `IntoCStr` --- rust/src/architecture.rs | 8 +-- rust/src/background_task.rs | 4 +- rust/src/binary_view.rs | 64 ++++++++++---------- rust/src/binary_view/memory_map.rs | 26 ++++---- rust/src/calling_convention.rs | 2 +- rust/src/collaboration.rs | 20 +++---- rust/src/collaboration/changeset.rs | 4 +- rust/src/collaboration/file.rs | 26 ++++---- rust/src/collaboration/folder.rs | 6 +- rust/src/collaboration/group.rs | 8 +-- rust/src/collaboration/merge.rs | 10 ++-- rust/src/collaboration/project.rs | 56 +++++++++--------- rust/src/collaboration/remote.rs | 40 ++++++------- rust/src/collaboration/snapshot.rs | 4 +- rust/src/collaboration/sync.rs | 20 +++---- rust/src/collaboration/user.rs | 6 +- rust/src/command.rs | 10 ++-- rust/src/component.rs | 4 +- rust/src/custom_binary_view.rs | 4 +- rust/src/data_buffer.rs | 2 +- rust/src/database.rs | 16 ++--- rust/src/database/kvs.rs | 8 +-- rust/src/database/snapshot.rs | 4 +- rust/src/debuginfo.rs | 47 ++++++++------- rust/src/demangle.rs | 18 +++--- rust/src/disassembly.rs | 4 +- rust/src/download_provider.rs | 16 ++--- rust/src/enterprise.rs | 10 ++-- rust/src/external_library.rs | 4 +- rust/src/file_metadata.rs | 22 +++---- rust/src/function.rs | 10 ++-- rust/src/high_level_il/operation.rs | 6 +- rust/src/interaction.rs | 2 +- rust/src/lib.rs | 14 ++--- rust/src/logger.rs | 2 +- rust/src/medium_level_il/function.rs | 10 ++-- rust/src/metadata.rs | 16 ++--- rust/src/platform.rs | 12 ++-- rust/src/project.rs | 88 ++++++++++++++-------------- rust/src/project/file.rs | 8 +-- rust/src/project/folder.rs | 10 ++-- rust/src/relocation.rs | 4 +- rust/src/render_layer.rs | 6 +- rust/src/repository.rs | 4 +- rust/src/repository/manager.rs | 8 +-- rust/src/secrets_provider.rs | 12 ++-- rust/src/settings.rs | 82 ++++++++++++++------------ rust/src/string.rs | 34 +++++------ rust/src/tags.rs | 12 ++-- rust/src/template_simplifier.rs | 6 +- rust/src/type_archive.rs | 74 +++++++++++------------ rust/src/type_container.rs | 22 +++---- rust/src/type_library.rs | 30 +++++----- rust/src/type_parser.rs | 6 +- rust/src/type_printer.rs | 6 +- rust/src/types.rs | 24 ++++---- rust/src/update.rs | 2 +- rust/src/websocket/client.rs | 10 ++-- rust/src/websocket/provider.rs | 4 +- rust/src/worker_thread.rs | 8 +-- rust/src/workflow.rs | 48 +++++++-------- rust/tests/websocket.rs | 6 +- 62 files changed, 535 insertions(+), 524 deletions(-) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 626938001a..c02fc717bc 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -27,7 +27,7 @@ use crate::{ platform::Platform, rc::*, relocation::CoreRelocationHandler, - string::AsCStr, + string::IntoCStr, string::*, types::{NameAndType, Type}, Endianness, @@ -1953,7 +1953,7 @@ macro_rules! cc_func { /// Contains helper methods for all types implementing 'Architecture' pub trait ArchitectureExt: Architecture { - fn register_by_name(&self, name: S) -> Option { + fn register_by_name(&self, name: S) -> Option { let name = name.to_cstr(); match unsafe { BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ptr()) } { @@ -2031,7 +2031,7 @@ pub trait ArchitectureExt: Architecture { fn register_relocation_handler(&self, name: S, func: F) where - S: AsCStr, + S: IntoCStr, R: 'static + RelocationHandler> + Send @@ -2054,7 +2054,7 @@ impl ArchitectureExt for T {} pub fn register_architecture(name: S, func: F) -> &'static A where - S: AsCStr, + S: IntoCStr, A: 'static + Architecture> + Send + Sync + Sized, F: FnOnce(CustomArchitectureHandle, CoreArchitecture) -> A, { diff --git a/rust/src/background_task.rs b/rust/src/background_task.rs index 95bdda0bb9..b0537fa815 100644 --- a/rust/src/background_task.rs +++ b/rust/src/background_task.rs @@ -43,7 +43,7 @@ impl BackgroundTask { Self { handle } } - pub fn new(initial_text: S, can_cancel: bool) -> Ref { + pub fn new(initial_text: S, can_cancel: bool) -> Ref { let text = initial_text.to_cstr(); let handle = unsafe { BNBeginBackgroundTask(text.as_ptr(), can_cancel) }; // We should always be returned a valid task. @@ -75,7 +75,7 @@ impl BackgroundTask { unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) } } - pub fn set_progress_text(&self, text: S) { + pub fn set_progress_text(&self, text: S) { let progress_text = text.to_cstr(); unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ptr()) } } diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index a0fb9081aa..7259efbf1c 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -266,7 +266,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNGetEndOffset(self.as_ref().handle) } } - fn add_analysis_option(&self, name: impl AsCStr) { + fn add_analysis_option(&self, name: impl IntoCStr) { let name = name.to_cstr(); unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_ptr()) } } @@ -399,7 +399,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_raw_name(&self, raw_name: S) -> Option> { + fn symbol_by_raw_name(&self, raw_name: S) -> Option> { let raw_name = raw_name.to_cstr(); unsafe { @@ -424,7 +424,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_by_name(&self, name: S) -> Array { + fn symbols_by_name(&self, name: S) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -585,7 +585,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_type, S: AsCStr>( + fn define_auto_type, S: IntoCStr>( &self, name: T, source: S, @@ -602,7 +602,7 @@ pub trait BinaryViewExt: BinaryViewBase { QualifiedName::from_owned_raw(name_handle) } - fn define_auto_type_with_id, S: AsCStr>( + fn define_auto_type_with_id, S: IntoCStr>( &self, name: T, id: S, @@ -712,7 +712,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn undefine_auto_type(&self, id: S) { + fn undefine_auto_type(&self, id: S) { let id_str = id.to_cstr(); unsafe { BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _); @@ -763,7 +763,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_by_id(&self, id: S) -> Option> { + fn type_by_id(&self, id: S) -> Option> { let id_str = id.to_cstr(); unsafe { let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ptr()); @@ -774,7 +774,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_name_by_id(&self, id: S) -> Option { + fn type_name_by_id(&self, id: S) -> Option { let id_str = id.to_cstr(); unsafe { let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ptr()); @@ -871,7 +871,7 @@ pub trait BinaryViewExt: BinaryViewBase { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: S) { + fn remove_auto_section(&self, name: S) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -879,7 +879,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn remove_user_section(&self, name: S) { + fn remove_user_section(&self, name: S) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -887,7 +887,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn section_by_name(&self, name: S) -> Option> { + fn section_by_name(&self, name: S) -> Option> { unsafe { let raw_name = name.to_cstr(); let name_ptr = raw_name.as_ptr(); @@ -1103,14 +1103,14 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } } - fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { + fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { let raw_name = raw_name.to_cstr(); unsafe { BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle); } } - fn load_settings(&self, view_type_name: S) -> Result> { + fn load_settings(&self, view_type_name: S) -> Result> { let view_type_name = view_type_name.to_cstr(); let settings_handle = unsafe { BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_ptr()) }; @@ -1122,7 +1122,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_load_settings(&self, view_type_name: S, settings: &Settings) { + fn set_load_settings(&self, view_type_name: S, settings: &Settings) { let view_type_name = view_type_name.to_cstr(); unsafe { @@ -1139,7 +1139,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Arguments /// * `name` - the name for the tag /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag - fn create_tag_type(&self, name: N, icon: I) -> Ref { + fn create_tag_type(&self, name: N, icon: I) -> Ref { let tag_type = TagType::create(self.as_ref(), name, icon); unsafe { BNAddTagType(self.as_ref().handle, tag_type.handle); @@ -1153,7 +1153,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Get a tag type by its name. - fn tag_type_by_name(&self, name: S) -> Option> { + fn tag_type_by_name(&self, name: S) -> Option> { let name = name.to_cstr(); unsafe { let handle = BNGetTagType(self.as_ref().handle, name.as_ptr()); @@ -1167,7 +1167,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Get a tag by its id. /// /// Note this does not tell you anything about where it is used. - fn tag_by_id(&self, id: S) -> Option> { + fn tag_by_id(&self, id: S) -> Option> { let id = id.to_cstr(); unsafe { let handle = BNGetTag(self.as_ref().handle, id.as_ptr()); @@ -1181,7 +1181,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Creates and adds a tag to an address /// /// User tag creations will be added to the undo buffer - fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { + fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { let tag = Tag::new(t, data); unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) } @@ -1218,7 +1218,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// NOTE: This is different from setting a comment at the function-level. To set a comment in a /// function use [`Function::set_comment_at`] - fn set_comment_at(&self, addr: u64, comment: impl AsCStr) { + fn set_comment_at(&self, addr: u64, comment: impl IntoCStr) { let comment_raw = comment.to_cstr(); unsafe { BNSetGlobalCommentForAddress(self.as_ref().handle, addr, comment_raw.as_ptr()) } } @@ -1271,7 +1271,7 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn query_metadata(&self, key: S) -> Option> { + fn query_metadata(&self, key: S) -> Option> { let key = key.to_cstr(); let value: *mut BNMetadata = unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_ptr()) }; @@ -1282,7 +1282,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_metadata(&self, key: S) -> Option> + fn get_metadata(&self, key: S) -> Option> where T: for<'a> TryFrom<&'a Metadata>, { @@ -1290,7 +1290,7 @@ pub trait BinaryViewExt: BinaryViewBase { .map(|md| T::try_from(md.as_ref()).map_err(|_| ())) } - fn store_metadata(&self, key: S, value: V, is_auto: bool) + fn store_metadata(&self, key: S, value: V, is_auto: bool) where V: Into>, { @@ -1306,7 +1306,7 @@ pub trait BinaryViewExt: BinaryViewBase { }; } - fn remove_metadata(&self, key: S) { + fn remove_metadata(&self, key: S) { let key = key.to_cstr(); unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) }; } @@ -1432,7 +1432,7 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn component_by_guid(&self, guid: S) -> Option> { + fn component_by_guid(&self, guid: S) -> Option> { let name = guid.to_cstr(); let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) @@ -1443,7 +1443,7 @@ pub trait BinaryViewExt: BinaryViewBase { NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn component_by_path(&self, path: P) -> Option> { + fn component_by_path(&self, path: P) -> Option> { let path = path.to_cstr(); let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) @@ -1453,7 +1453,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) } } - fn remove_component_by_guid(&self, guid: P) -> bool { + fn remove_component_by_guid(&self, guid: P) -> bool { let path = guid.to_cstr(); unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } } @@ -1476,7 +1476,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { Array::new(result, count, ()) } } - fn external_library(&self, name: S) -> Option> { + fn external_library(&self, name: S) -> Option> { let name_ptr = name.to_cstr(); let result = unsafe { BNBinaryViewGetExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; @@ -1484,12 +1484,12 @@ pub trait BinaryViewExt: BinaryViewBase { Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) } - fn remove_external_library(&self, name: S) { + fn remove_external_library(&self, name: S) { let name_ptr = name.to_cstr(); unsafe { BNBinaryViewRemoveExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; } - fn add_external_library( + fn add_external_library( &self, name: S, backing_file: Option<&ProjectFile>, @@ -1531,7 +1531,7 @@ pub trait BinaryViewExt: BinaryViewBase { } // TODO: This is awful, rewrite this. - fn add_external_location( + fn add_external_location( &self, symbol: &Symbol, library: &ExternalLibrary, @@ -1589,7 +1589,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } } - fn type_library_by_name(&self, name: S) -> Option { + fn type_library_by_name(&self, name: S) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) }) @@ -1682,7 +1682,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// contain a metadata key called "type_guids" which is a map /// Dict[string_guid, string_type_name] or /// Dict[string_guid, Tuple[string_type_name, type_library_name]] - fn import_type_by_guid(&self, guid: S) -> Option> { + fn import_type_by_guid(&self, guid: S) -> Option> { let guid = guid.to_cstr(); let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) }; diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index 6b6d3d20a3..ad7c8ea1e3 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -3,7 +3,7 @@ use crate::data_buffer::DataBuffer; use crate::file_accessor::FileAccessor; use crate::rc::Ref; use crate::segment::SegmentFlags; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::*; #[derive(PartialEq, Eq, Hash)] @@ -42,7 +42,7 @@ impl MemoryMap { pub fn add_binary_memory_region( &mut self, - name: impl AsCStr, + name: impl IntoCStr, start: u64, view: &BinaryView, segment_flags: Option, @@ -61,7 +61,7 @@ impl MemoryMap { pub fn add_data_memory_region( &mut self, - name: impl AsCStr, + name: impl IntoCStr, start: u64, data: &DataBuffer, segment_flags: Option, @@ -80,7 +80,7 @@ impl MemoryMap { pub fn add_remote_memory_region( &mut self, - name: impl AsCStr, + name: impl IntoCStr, start: u64, accessor: &mut FileAccessor, segment_flags: Option, @@ -97,7 +97,7 @@ impl MemoryMap { } } - pub fn remove_memory_region(&mut self, name: impl AsCStr) -> bool { + pub fn remove_memory_region(&mut self, name: impl IntoCStr) -> bool { let name_raw = name.to_cstr(); unsafe { BNRemoveMemoryRegion(self.view.handle, name_raw.as_ptr()) } } @@ -109,44 +109,44 @@ impl MemoryMap { } } - pub fn memory_region_flags(&self, name: impl AsCStr) -> SegmentFlags { + pub fn memory_region_flags(&self, name: impl IntoCStr) -> SegmentFlags { let name_raw = name.to_cstr(); let flags_raw = unsafe { BNGetMemoryRegionFlags(self.view.handle, name_raw.as_ptr()) }; SegmentFlags::from_raw(flags_raw) } - pub fn set_memory_region_flags(&mut self, name: impl AsCStr, flags: SegmentFlags) -> bool { + pub fn set_memory_region_flags(&mut self, name: impl IntoCStr, flags: SegmentFlags) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFlags(self.view.handle, name_raw.as_ptr(), flags.into_raw()) } } - pub fn is_memory_region_enabled(&self, name: impl AsCStr) -> bool { + pub fn is_memory_region_enabled(&self, name: impl IntoCStr) -> bool { let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionEnabled(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_enabled(&mut self, name: impl AsCStr, enabled: bool) -> bool { + pub fn set_memory_region_enabled(&mut self, name: impl IntoCStr, enabled: bool) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionEnabled(self.view.handle, name_raw.as_ptr(), enabled) } } // TODO: Should we just call this is_memory_region_relocatable? - pub fn is_memory_region_rebaseable(&self, name: impl AsCStr) -> bool { + pub fn is_memory_region_rebaseable(&self, name: impl IntoCStr) -> bool { let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_rebaseable(&mut self, name: impl AsCStr, enabled: bool) -> bool { + pub fn set_memory_region_rebaseable(&mut self, name: impl IntoCStr, enabled: bool) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr(), enabled) } } - pub fn memory_region_fill(&self, name: impl AsCStr) -> u8 { + pub fn memory_region_fill(&self, name: impl IntoCStr) -> u8 { let name_raw = name.to_cstr(); unsafe { BNGetMemoryRegionFill(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_fill(&mut self, name: impl AsCStr, fill: u8) -> bool { + pub fn set_memory_region_fill(&mut self, name: impl IntoCStr, fill: u8) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFill(self.view.handle, name_raw.as_ptr(), fill) } } diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs index 7db61d8afc..90af3aa876 100644 --- a/rust/src/calling_convention.rs +++ b/rust/src/calling_convention.rs @@ -58,7 +58,7 @@ pub trait CallingConvention: Sync { pub fn register_calling_convention(arch: &A, name: N, cc: C) -> Ref where A: Architecture, - N: AsCStr, + N: IntoCStr, C: 'static + CallingConvention, { struct CustomCallingConventionContext diff --git a/rust/src/collaboration.rs b/rust/src/collaboration.rs index 8a1774f2bc..9a97a0e8b2 100644 --- a/rust/src/collaboration.rs +++ b/rust/src/collaboration.rs @@ -30,7 +30,7 @@ pub use user::*; use binaryninjacore_sys::*; use crate::rc::{Array, Ref}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; // TODO: Should we pull metadata and information required to call a function? Or should we add documentation // TODO: on what functions need to have been called prior? I feel like we should make the user have to pull @@ -73,21 +73,21 @@ pub fn known_remotes() -> Array { } /// Get Remote by unique `id` -pub fn get_remote_by_id(id: S) -> Option> { +pub fn get_remote_by_id(id: S) -> Option> { let id = id.to_cstr(); let value = unsafe { BNCollaborationGetRemoteById(id.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `address` -pub fn get_remote_by_address(address: S) -> Option> { +pub fn get_remote_by_address(address: S) -> Option> { let address = address.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByAddress(address.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `name` -pub fn get_remote_by_name(name: S) -> Option> { +pub fn get_remote_by_name(name: S) -> Option> { let name = name.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByName(name.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) @@ -105,10 +105,10 @@ pub fn save_remotes() { pub fn store_data_in_keychain(key: K, data: I) -> bool where - K: AsCStr, + K: IntoCStr, I: IntoIterator, - DK: AsCStr, - DV: AsCStr, + DK: IntoCStr, + DV: IntoCStr, { let key = key.to_cstr(); let (data_keys, data_values): (Vec, Vec) = data @@ -127,12 +127,12 @@ where } } -pub fn has_data_in_keychain(key: K) -> bool { +pub fn has_data_in_keychain(key: K) -> bool { let key = key.to_cstr(); unsafe { BNCollaborationHasDataInKeychain(key.as_ptr()) } } -pub fn get_data_from_keychain(key: K) -> Option<(Array, Array)> { +pub fn get_data_from_keychain(key: K) -> Option<(Array, Array)> { let key = key.to_cstr(); let mut keys = std::ptr::null_mut(); let mut values = std::ptr::null_mut(); @@ -142,7 +142,7 @@ pub fn get_data_from_keychain(key: K) -> Option<(Array, Arr keys.zip(values) } -pub fn delete_data_from_keychain(key: K) -> bool { +pub fn delete_data_from_keychain(key: K) -> bool { let key = key.to_cstr(); unsafe { BNCollaborationDeleteDataFromKeychain(key.as_ptr()) } } diff --git a/rust/src/collaboration/changeset.rs b/rust/src/collaboration/changeset.rs index 0db384cb93..b07f23deff 100644 --- a/rust/src/collaboration/changeset.rs +++ b/rust/src/collaboration/changeset.rs @@ -6,7 +6,7 @@ use super::{RemoteFile, RemoteUser}; use crate::database::snapshot::SnapshotId; use crate::database::Database; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; /// A collection of snapshots in a local database #[repr(transparent)] @@ -65,7 +65,7 @@ impl Changeset { } /// Set the name of the changeset, e.g. in a name changeset function. - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: S) -> bool { let value = value.to_cstr(); unsafe { BNCollaborationChangesetSetName(self.handle.as_ptr(), value.as_ptr()) } } diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index 251b4f7d53..699b34b842 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -16,7 +16,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback, SplitProgressBuilder}; use crate::project::file::ProjectFile; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub type RemoteFileType = BNRemoteFileType; @@ -94,7 +94,7 @@ impl RemoteFile { success.then_some(()).ok_or(()) } - pub fn set_metadata(&self, folder: S) -> Result<(), ()> { + pub fn set_metadata(&self, folder: S) -> Result<(), ()> { let folder_raw = folder.to_cstr(); let success = unsafe { BNRemoteFileSetMetadata(self.handle.as_ptr(), folder_raw.as_ptr()) }; success.then_some(()).ok_or(()) @@ -185,7 +185,7 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteFileSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -199,7 +199,7 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteFileSetDescription(self.handle.as_ptr(), description.as_ptr()) }; @@ -249,7 +249,7 @@ impl RemoteFile { /// Get a specific Snapshot in the File by its id /// /// NOTE: If snapshots have not been pulled, they will be pulled upon calling this. - pub fn snapshot_by_id(&self, id: S) -> Result>, ()> { + pub fn snapshot_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_snapshots() { self.pull_snapshots()?; @@ -295,9 +295,9 @@ impl RemoteFile { parent_ids: I, ) -> Result, ()> where - S: AsCStr, + S: IntoCStr, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { self.create_snapshot_with_progress( name, @@ -327,10 +327,10 @@ impl RemoteFile { mut progress: P, ) -> Result, ()> where - S: AsCStr, + S: IntoCStr, P: ProgressCallback, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let name = name.to_cstr(); let parent_ids: Vec<_> = parent_ids.into_iter().map(|id| id.to_cstr()).collect(); @@ -405,7 +405,7 @@ impl RemoteFile { /// * `progress_function` - Function to call for progress updates pub fn download(&self, db_path: S) -> Result, ()> where - S: AsCStr, + S: IntoCStr, { sync::download_file(self, db_path) } @@ -422,14 +422,14 @@ impl RemoteFile { progress_function: F, ) -> Result, ()> where - S: AsCStr, + S: IntoCStr, F: ProgressCallback, { sync::download_file_with_progress(self, db_path, progress_function) } /// Download a remote file and save it to a BNDB at the given `path`, returning the associated [`FileMetadata`]. - pub fn download_database(&self, path: S) -> Result, ()> { + pub fn download_database(&self, path: S) -> Result, ()> { let file = self.download(path)?; let database = file.database().ok_or(())?; self.sync(&database, DatabaseConflictHandlerFail, NoNameChangeset)?; @@ -439,7 +439,7 @@ impl RemoteFile { // TODO: This might be a bad helper... maybe remove... // TODO: AsRef /// Download a remote file and save it to a BNDB at the given `path`. - pub fn download_database_with_progress( + pub fn download_database_with_progress( &self, path: S, progress: impl ProgressCallback, diff --git a/rust/src/collaboration/folder.rs b/rust/src/collaboration/folder.rs index b5fde3b47e..35ff078803 100644 --- a/rust/src/collaboration/folder.rs +++ b/rust/src/collaboration/folder.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use crate::project::folder::ProjectFolder; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; #[repr(transparent)] pub struct RemoteFolder { @@ -103,7 +103,7 @@ impl RemoteFolder { } /// Set the display name of the folder. You will need to push the folder to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteFolderSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -117,7 +117,7 @@ impl RemoteFolder { } /// Set the description of the folder. You will need to push the folder to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteFolderSetDescription(self.handle.as_ptr(), description.as_ptr()) }; diff --git a/rust/src/collaboration/group.rs b/rust/src/collaboration/group.rs index b8b32c7a20..08efa0795b 100644 --- a/rust/src/collaboration/group.rs +++ b/rust/src/collaboration/group.rs @@ -1,6 +1,6 @@ use super::Remote; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::*; use std::fmt; use std::fmt::{Display, Formatter}; @@ -49,7 +49,7 @@ impl RemoteGroup { /// Set group name /// You will need to push the group to update the Remote. - pub fn set_name(&self, name: U) { + pub fn set_name(&self, name: U) { let name = name.to_cstr(); unsafe { BNCollaborationGroupSetName(self.handle.as_ptr(), name.as_ptr()) } } @@ -84,7 +84,7 @@ impl RemoteGroup { pub fn set_users(&self, usernames: I) -> Result<(), ()> where I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let usernames: Vec<_> = usernames.into_iter().map(|u| u.to_cstr()).collect(); let mut usernames_raw: Vec<_> = usernames.iter().map(|s| s.as_ptr()).collect(); @@ -102,7 +102,7 @@ impl RemoteGroup { } /// Test if a group has a user with the given username - pub fn contains_user(&self, username: U) -> bool { + pub fn contains_user(&self, username: U) -> bool { let username = username.to_cstr(); unsafe { BNCollaborationGroupContainsUser(self.handle.as_ptr(), username.as_ptr()) } } diff --git a/rust/src/collaboration/merge.rs b/rust/src/collaboration/merge.rs index 2fb5b3de17..9ebf4cda71 100644 --- a/rust/src/collaboration/merge.rs +++ b/rust/src/collaboration/merge.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use crate::database::{snapshot::Snapshot, Database}; use crate::file_metadata::FileMetadata; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub type MergeConflictDataType = BNMergeConflictDataType; @@ -48,7 +48,7 @@ impl MergeConflict { NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) } - pub fn path_item_string(&self, path: S) -> Result { + pub fn path_item_string(&self, path: S) -> Result { let path = path.to_cstr(); let result = unsafe { BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path.as_ptr()) @@ -119,7 +119,7 @@ impl MergeConflict { } /// Call this when you've resolved the conflict to save the result - pub fn success(&self, value: S) -> Result<(), ()> { + pub fn success(&self, value: S) -> Result<(), ()> { let value = value.to_cstr(); let success = unsafe { BNAnalysisMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) }; @@ -127,7 +127,7 @@ impl MergeConflict { } // TODO: Make a safe version of this that checks the path and if it holds a number - pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { + pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItem(self.handle.as_ptr(), path_key.as_ptr()) }; @@ -138,7 +138,7 @@ impl MergeConflict { } } - pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { + pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path_key.as_ptr()) diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index fce2a5f67c..3d34da9e55 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -15,7 +15,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; #[repr(transparent)] pub struct RemoteProject { @@ -136,7 +136,7 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: S) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteProjectSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -150,7 +150,7 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: S) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteProjectSetDescription(self.handle.as_ptr(), description.as_ptr()) }; @@ -221,7 +221,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_id(&self, id: S) -> Result>, ()> { + pub fn get_file_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; @@ -235,7 +235,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_name(&self, name: S) -> Result>, ()> { + pub fn get_file_by_name(&self, name: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; @@ -292,9 +292,9 @@ impl RemoteProject { file_type: RemoteFileType, ) -> Result, ()> where - F: AsCStr, - N: AsCStr, - D: AsCStr, + F: IntoCStr, + N: IntoCStr, + D: IntoCStr, { self.create_file_with_progress( filename, @@ -329,9 +329,9 @@ impl RemoteProject { mut progress: P, ) -> Result, ()> where - F: AsCStr, - N: AsCStr, - D: AsCStr, + F: IntoCStr, + N: IntoCStr, + D: IntoCStr, P: ProgressCallback, { // TODO: This sync should be removed? @@ -367,8 +367,8 @@ impl RemoteProject { pub fn push_file(&self, file: &RemoteFile, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { // TODO: This sync should be removed? self.open()?; @@ -421,7 +421,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If folders have not been pulled, they will be pulled upon calling this. - pub fn get_folder_by_id(&self, id: S) -> Result>, ()> { + pub fn get_folder_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_folders() { self.pull_folders()?; @@ -472,8 +472,8 @@ impl RemoteProject { parent_folder: Option<&RemoteFolder>, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, + N: IntoCStr, + D: IntoCStr, { self.create_folder_with_progress(name, description, parent_folder, NoProgressCallback) } @@ -494,8 +494,8 @@ impl RemoteProject { mut progress: P, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, + N: IntoCStr, + D: IntoCStr, P: ProgressCallback, { // TODO: This sync should be removed? @@ -529,8 +529,8 @@ impl RemoteProject { pub fn push_folder(&self, folder: &RemoteFolder, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { // TODO: This sync should be removed? self.open()?; @@ -598,7 +598,7 @@ impl RemoteProject { /// Get a specific permission in the Project by its id. /// /// NOTE: If group or user permissions have not been pulled, they will be pulled upon calling this. - pub fn get_permission_by_id(&self, id: S) -> Result>, ()> { + pub fn get_permission_by_id(&self, id: S) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_user_permissions() { self.pull_user_permissions()?; @@ -703,7 +703,7 @@ impl RemoteProject { /// /// * `user_id` - User id /// * `level` - Permission level - pub fn create_user_permission( + pub fn create_user_permission( &self, user_id: S, level: CollaborationPermissionLevel, @@ -718,7 +718,7 @@ impl RemoteProject { /// * `user_id` - User id /// * `level` - Permission level /// * `progress` - The progress callback to call - pub fn create_user_permission_with_progress( + pub fn create_user_permission_with_progress( &self, user_id: S, level: CollaborationPermissionLevel, @@ -753,8 +753,8 @@ impl RemoteProject { ) -> Result<(), ()> where I: Iterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -788,7 +788,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_view(&self, username: S) -> bool { + pub fn can_user_view(&self, username: S) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserView(self.handle.as_ptr(), username.as_ptr()) } } @@ -798,7 +798,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_edit(&self, username: S) -> bool { + pub fn can_user_edit(&self, username: S) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserEdit(self.handle.as_ptr(), username.as_ptr()) } } @@ -808,7 +808,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_admin(&self, username: S) -> bool { + pub fn can_user_admin(&self, username: S) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserAdmin(self.handle.as_ptr(), username.as_ptr()) } } diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index 4d69873aff..baeba412fc 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -10,7 +10,7 @@ use crate::enterprise; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; #[repr(transparent)] pub struct Remote { @@ -27,7 +27,7 @@ impl Remote { } /// Create a Remote and add it to the list of known remotes (saved to Settings) - pub fn new(name: N, address: A) -> Ref { + pub fn new(name: N, address: A) -> Ref { let name = name.to_cstr(); let address = address.to_cstr(); let result = unsafe { BNCollaborationCreateRemote(name.as_ptr(), address.as_ptr()) }; @@ -163,7 +163,7 @@ impl Remote { } /// Requests an authentication token using a username and password. - pub fn request_authentication_token( + pub fn request_authentication_token( &self, username: U, password: P, @@ -275,7 +275,7 @@ impl Remote { /// Gets a specific project in the Remote by its id. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_id(&self, id: S) -> Result>, ()> { + pub fn get_project_by_id(&self, id: S) -> Result>, ()> { if !self.has_pulled_projects() { self.pull_projects()?; } @@ -288,7 +288,7 @@ impl Remote { /// Gets a specific project in the Remote by its name. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_name( + pub fn get_project_by_name( &self, name: S, ) -> Result>, ()> { @@ -331,7 +331,7 @@ impl Remote { /// /// * `name` - Project name /// * `description` - Project description - pub fn create_project( + pub fn create_project( &self, name: N, description: D, @@ -383,8 +383,8 @@ impl Remote { pub fn push_project(&self, project: &RemoteProject, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -446,7 +446,7 @@ impl Remote { /// /// If groups have not been pulled, they will be pulled upon calling this. /// This function is only available to accounts with admin status on the Remote. - pub fn get_group_by_name(&self, name: S) -> Result>, ()> { + pub fn get_group_by_name(&self, name: S) -> Result>, ()> { if !self.has_pulled_groups() { self.pull_groups()?; } @@ -462,7 +462,7 @@ impl Remote { /// # Arguments /// /// * `prefix` - Prefix of name for groups - pub fn search_groups( + pub fn search_groups( &self, prefix: S, ) -> Result<(Array, Array), ()> { @@ -526,9 +526,9 @@ impl Remote { /// * `usernames` - List of usernames of users in the group pub fn create_group(&self, name: N, usernames: I) -> Result, ()> where - N: AsCStr, + N: IntoCStr, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let name = name.to_cstr(); let usernames: Vec<_> = usernames.into_iter().map(|s| s.to_cstr()).collect(); @@ -557,8 +557,8 @@ impl Remote { pub fn push_group(&self, group: &RemoteGroup, extra_fields: I) -> Result<(), ()> where I: IntoIterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -617,7 +617,7 @@ impl Remote { /// # Arguments /// /// * `id` - The identifier of the user to retrieve. - pub fn get_user_by_id(&self, id: S) -> Result>, ()> { + pub fn get_user_by_id(&self, id: S) -> Result>, ()> { if !self.has_pulled_users() { self.pull_users()?; } @@ -635,7 +635,7 @@ impl Remote { /// # Arguments /// /// * `username` - The username of the user to retrieve. - pub fn get_user_by_username( + pub fn get_user_by_username( &self, username: S, ) -> Result>, ()> { @@ -665,7 +665,7 @@ impl Remote { /// # Arguments /// /// * `prefix` - The prefix to search for in usernames. - pub fn search_users( + pub fn search_users( &self, prefix: S, ) -> Result<(Array, Array), ()> { @@ -730,7 +730,7 @@ impl Remote { /// # Arguments /// /// * Various details about the new user to be created. - pub fn create_user( + pub fn create_user( &self, username: U, email: E, @@ -772,8 +772,8 @@ impl Remote { pub fn push_user(&self, user: &RemoteUser, extra_fields: I) -> Result<(), ()> where I: Iterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index 6e1dfb8941..c825660828 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -8,7 +8,7 @@ use crate::collaboration::undo::{RemoteUndoEntry, RemoteUndoEntryId}; use crate::database::snapshot::Snapshot; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::*; // TODO: RemoteSnapshotId ? @@ -226,7 +226,7 @@ impl RemoteSnapshot { } /// Create a new Undo Entry in this snapshot. - pub fn create_undo_entry( + pub fn create_undo_entry( &self, parent: Option, data: S, diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index 5afb8923cf..b1b26982a2 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -11,7 +11,7 @@ use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::rc::Ref; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_archive::{TypeArchive, TypeArchiveMergeConflict}; // TODO: PathBuf @@ -43,7 +43,7 @@ pub fn default_file_path(file: &RemoteFile) -> Result { /// /// * `file` - Remote File to download and open /// * `db_path` - File path for saved database -pub fn download_file(file: &RemoteFile, db_path: S) -> Result, ()> { +pub fn download_file(file: &RemoteFile, db_path: S) -> Result, ()> { download_file_with_progress(file, db_path, NoProgressCallback) } @@ -54,7 +54,7 @@ pub fn download_file(file: &RemoteFile, db_path: S) -> Result( +pub fn download_file_with_progress( file: &RemoteFile, db_path: S, mut progress: F, @@ -220,7 +220,7 @@ pub fn get_local_snapshot_for_remote( pub fn download_database(file: &RemoteFile, location: S, force: bool) -> Result<(), ()> where - S: AsCStr, + S: IntoCStr, { download_database_with_progress(file, location, force, NoProgressCallback) } @@ -232,7 +232,7 @@ pub fn download_database_with_progress( mut progress: F, ) -> Result<(), ()> where - S: AsCStr, + S: IntoCStr, F: ProgressCallback, { let db_path = location.to_cstr(); @@ -475,7 +475,7 @@ pub fn get_snapshot_author( /// * `database` - Parent database /// * `snapshot` - Snapshot to edit /// * `author` - Target author -pub fn set_snapshot_author( +pub fn set_snapshot_author( database: &Database, snapshot: &Snapshot, author: S, @@ -650,7 +650,7 @@ pub fn get_remote_file_for_local_type_archive(database: &TypeArchive) -> Option< } /// Get the remote snapshot associated with a local snapshot (if it exists) in a Type Archive -pub fn get_remote_snapshot_from_local_type_archive( +pub fn get_remote_snapshot_from_local_type_archive( type_archive: &TypeArchive, snapshot_id: S, ) -> Option> { @@ -679,7 +679,7 @@ pub fn get_local_snapshot_from_remote_type_archive( } /// Test if a snapshot is ignored from the archive -pub fn is_type_archive_snapshot_ignored( +pub fn is_type_archive_snapshot_ignored( type_archive: &TypeArchive, snapshot_id: S, ) -> bool { @@ -694,7 +694,7 @@ pub fn is_type_archive_snapshot_ignored( /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive( +pub fn download_type_archive( file: &RemoteFile, location: S, ) -> Result>, ()> { @@ -703,7 +703,7 @@ pub fn download_type_archive( /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive_with_progress( +pub fn download_type_archive_with_progress( file: &RemoteFile, location: S, mut progress: F, diff --git a/rust/src/collaboration/user.rs b/rust/src/collaboration/user.rs index d4aea2c504..6b49094261 100644 --- a/rust/src/collaboration/user.rs +++ b/rust/src/collaboration/user.rs @@ -3,7 +3,7 @@ use binaryninjacore_sys::*; use std::ptr::NonNull; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; #[repr(transparent)] pub struct RemoteUser { @@ -48,7 +48,7 @@ impl RemoteUser { } /// Set user's username. You will need to push the user to update the Remote - pub fn set_username(&self, username: U) -> Result<(), ()> { + pub fn set_username(&self, username: U) -> Result<(), ()> { let username = username.to_cstr(); let result = unsafe { BNCollaborationUserSetUsername(self.handle.as_ptr(), username.as_ptr()) }; @@ -67,7 +67,7 @@ impl RemoteUser { } /// Set user's email. You will need to push the user to update the Remote - pub fn set_email(&self, email: U) -> Result<(), ()> { + pub fn set_email(&self, email: U) -> Result<(), ()> { let username = email.to_cstr(); let result = unsafe { BNCollaborationUserSetEmail(self.handle.as_ptr(), username.as_ptr()) }; diff --git a/rust/src/command.rs b/rust/src/command.rs index 721f9170c4..099eafa84a 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -42,7 +42,7 @@ use std::os::raw::c_void; use crate::binary_view::BinaryView; use crate::function::Function; -use crate::string::AsCStr; +use crate::string::IntoCStr; /// The trait required for generic commands. See [register_command] for example usage. pub trait Command: 'static + Sync { @@ -95,7 +95,7 @@ where /// ``` pub fn register_command(name: S, desc: S, command: C) where - S: AsCStr, + S: IntoCStr, C: Command, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView) @@ -196,7 +196,7 @@ where /// ``` pub fn register_command_for_address(name: S, desc: S, command: C) where - S: AsCStr, + S: IntoCStr, C: AddressCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) @@ -298,7 +298,7 @@ where /// ``` pub fn register_command_for_range(name: S, desc: S, command: C) where - S: AsCStr, + S: IntoCStr, C: RangeCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64) @@ -405,7 +405,7 @@ where /// ``` pub fn register_command_for_function(name: S, desc: S, command: C) where - S: AsCStr, + S: IntoCStr, C: FunctionCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction) diff --git a/rust/src/component.rs b/rust/src/component.rs index 48c8b110aa..ae5fd55ed8 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -1,7 +1,7 @@ use crate::binary_view::{BinaryView, BinaryViewExt}; use crate::function::Function; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::types::ComponentReferencedType; use std::ffi::c_char; use std::fmt::Debug; @@ -164,7 +164,7 @@ impl Component { unsafe { BnString::into_string(result) } } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: S) { let name = name.to_cstr(); unsafe { BNComponentSetName(self.handle.as_ptr(), name.as_ptr()) } } diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index ee32a67fa2..7e5c0a2409 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -41,7 +41,7 @@ use crate::Endianness; /// implementation of the `CustomBinaryViewType` must return. pub fn register_view_type(name: S, long_name: S, constructor: F) -> &'static T where - S: AsCStr, + S: IntoCStr, T: CustomBinaryViewType, F: FnOnce(BinaryViewType) -> T, { @@ -359,7 +359,7 @@ impl BinaryViewType { } /// Looks up a BinaryViewType by its short name - pub fn by_name(name: N) -> Result { + pub fn by_name(name: N) -> Result { let bytes = name.to_cstr(); let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; match handle.is_null() { diff --git a/rust/src/data_buffer.rs b/rust/src/data_buffer.rs index a163d3464d..bfffc33fdb 100644 --- a/rust/src/data_buffer.rs +++ b/rust/src/data_buffer.rs @@ -19,7 +19,7 @@ use binaryninjacore_sys::*; use std::ffi::c_void; use std::slice; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub struct DataBuffer(*mut BNDataBuffer); diff --git a/rust/src/database.rs b/rust/src/database.rs index 61d6f608ef..1746b405dc 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -15,7 +15,7 @@ use crate::database::snapshot::{Snapshot, SnapshotId}; use crate::file_metadata::FileMetadata; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub struct Database { pub(crate) handle: NonNull, @@ -62,7 +62,7 @@ impl Database { unsafe { BNSetDatabaseCurrentSnapshot(self.handle.as_ptr(), id.0) } } - pub fn write_snapshot_data( + pub fn write_snapshot_data( &self, parents: &[SnapshotId], file: &BinaryView, @@ -90,7 +90,7 @@ impl Database { mut progress: P, ) -> SnapshotId where - N: AsCStr, + N: IntoCStr, P: ProgressCallback, { let name_raw = name.to_cstr(); @@ -133,7 +133,7 @@ impl Database { Err(()) } } - pub fn has_global(&self, key: S) -> bool { + pub fn has_global(&self, key: S) -> bool { let key_raw = key.to_cstr(); unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_raw.as_ptr()) != 0 } } @@ -155,28 +155,28 @@ impl Database { } /// Get a specific global by key - pub fn read_global(&self, key: S) -> Option { + pub fn read_global(&self, key: S) -> Option { let key_raw = key.to_cstr(); let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr()) }; unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database - pub fn write_global(&self, key: K, value: V) -> bool { + pub fn write_global(&self, key: K, value: V) -> bool { let key_raw = key.to_cstr(); let value_raw = value.to_cstr(); unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr(), value_raw.as_ptr()) } } /// Get a specific global by key, as a binary buffer - pub fn read_global_data(&self, key: S) -> Option { + pub fn read_global_data(&self, key: S) -> Option { let key_raw = key.to_cstr(); let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr()) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database - pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { + pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr(), value.as_raw()) } } diff --git a/rust/src/database/kvs.rs b/rust/src/database/kvs.rs index e84da7f3ec..5b7cbbe87e 100644 --- a/rust/src/database/kvs.rs +++ b/rust/src/database/kvs.rs @@ -1,6 +1,6 @@ use crate::data_buffer::DataBuffer; use crate::rc::{Array, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::{ BNBeginKeyValueStoreNamespace, BNEndKeyValueStoreNamespace, BNFreeKeyValueStore, BNGetKeyValueStoreBuffer, BNGetKeyValueStoreDataSize, BNGetKeyValueStoreKeys, @@ -41,7 +41,7 @@ impl KeyValueStore { } /// Get the value for a single key - pub fn value(&self, key: S) -> Option { + pub fn value(&self, key: S) -> Option { let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ptr(); let result = unsafe { BNGetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr) }; @@ -49,7 +49,7 @@ impl KeyValueStore { } /// Set the value for a single key - pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { + pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ptr(); unsafe { BNSetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr, value.as_raw()) } @@ -63,7 +63,7 @@ impl KeyValueStore { } /// Begin storing new keys into a namespace - pub fn begin_namespace(&self, name: S) { + pub fn begin_namespace(&self, name: S) { let name_raw = name.to_cstr(); let name_ptr = name_raw.as_ptr(); unsafe { BNBeginKeyValueStoreNamespace(self.handle.as_ptr(), name_ptr) } diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs index 599a749ac1..d9ff030aba 100644 --- a/rust/src/database/snapshot.rs +++ b/rust/src/database/snapshot.rs @@ -4,7 +4,7 @@ use crate::database::undo::UndoEntry; use crate::database::Database; use crate::progress::ProgressCallback; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::{ BNCollaborationFreeSnapshotIdList, BNFreeSnapshot, BNFreeSnapshotList, BNGetSnapshotChildren, BNGetSnapshotDatabase, BNGetSnapshotFileContents, BNGetSnapshotFileContentsHash, @@ -50,7 +50,7 @@ impl Snapshot { } /// Set the displayed snapshot name - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: S) { let value_raw = value.to_cstr(); let value_ptr = value_raw.as_ptr(); unsafe { BNSetSnapshotName(self.handle.as_ptr(), value_ptr) } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 92c0170d6c..248726f38e 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -83,7 +83,7 @@ use crate::{ binary_view::BinaryView, platform::Platform, rc::*, - string::{raw_to_string, AsCStr, BnString}, + string::{raw_to_string, BnString, IntoCStr}, types::{NameAndType, Type}, }; @@ -115,7 +115,7 @@ impl DebugInfoParser { } /// Returns debug info parser of the given name, if it exists - pub fn from_name(name: S) -> Result, ()> { + pub fn from_name(name: S) -> Result, ()> { let name = name.to_cstr(); let parser = unsafe { BNGetDebugInfoParserByName(name.as_ptr()) }; @@ -209,7 +209,7 @@ impl DebugInfoParser { // Registers a DebugInfoParser. See `binaryninja::debuginfo::DebugInfoParser` for more details. pub fn register(name: S, parser_callbacks: C) -> Ref where - S: AsCStr, + S: IntoCStr, C: CustomDebugInfoParser, { extern "C" fn cb_is_valid(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool @@ -418,7 +418,7 @@ impl DebugInfo { } /// Returns all types within the parser - pub fn types_by_name(&self, parser_name: S) -> Vec { + pub fn types_by_name(&self, parser_name: S) -> Vec { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; @@ -451,7 +451,7 @@ impl DebugInfo { } /// Returns all functions within the parser - pub fn functions_by_name(&self, parser_name: S) -> Vec { + pub fn functions_by_name(&self, parser_name: S) -> Vec { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; @@ -486,7 +486,7 @@ impl DebugInfo { } /// Returns all data variables within the parser - pub fn data_variables_by_name( + pub fn data_variables_by_name( &self, parser_name: S, ) -> Vec { @@ -523,7 +523,7 @@ impl DebugInfo { result } - pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { + pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); @@ -536,7 +536,7 @@ impl DebugInfo { } } - pub fn get_data_variable_by_name( + pub fn get_data_variable_by_name( &self, parser_name: S, name: S, @@ -558,7 +558,7 @@ impl DebugInfo { } } - pub fn get_data_variable_by_address( + pub fn get_data_variable_by_address( &self, parser_name: S, address: u64, @@ -576,7 +576,7 @@ impl DebugInfo { } /// Returns a list of [`NameAndType`] where the `name` is the parser the type originates from. - pub fn get_types_by_name(&self, name: S) -> Vec { + pub fn get_types_by_name(&self, name: S) -> Vec { let mut count: usize = 0; let name = name.to_cstr(); let raw_names_and_types_ptr = @@ -595,7 +595,10 @@ impl DebugInfo { } // The tuple is (DebugInfoParserName, address, type) - pub fn get_data_variables_by_name(&self, name: S) -> Vec<(String, u64, Ref)> { + pub fn get_data_variables_by_name( + &self, + name: S, + ) -> Vec<(String, u64, Ref)> { let name = name.to_cstr(); let mut count: usize = 0; @@ -646,51 +649,55 @@ impl DebugInfo { result } - pub fn remove_parser_info(&self, parser_name: S) -> bool { + pub fn remove_parser_info(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_types(&self, parser_name: S) -> bool { + pub fn remove_parser_types(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_functions(&self, parser_name: S) -> bool { + pub fn remove_parser_functions(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { + pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ptr()) } } - pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { + pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); unsafe { BNRemoveDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) } } - pub fn remove_function_by_index(&self, parser_name: S, index: usize) -> bool { + pub fn remove_function_by_index(&self, parser_name: S, index: usize) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_ptr(), index) } } - pub fn remove_data_variable_by_address(&self, parser_name: S, address: u64) -> bool { + pub fn remove_data_variable_by_address( + &self, + parser_name: S, + address: u64, + ) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address) } } /// Adds a type scoped under the current parser's name to the debug info - pub fn add_type(&self, name: S, new_type: &Type, components: &[&str]) -> bool { + pub fn add_type(&self, name: S, new_type: &Type, components: &[&str]) -> bool { // SAFETY: Lifetime of `components` will live long enough, so passing as_ptr is safe. let raw_components: Vec<_> = components.iter().map(|&c| c.as_ptr()).collect(); @@ -772,7 +779,7 @@ impl DebugInfo { } /// Adds a data variable scoped under the current parser's name to the debug info - pub fn add_data_variable( + pub fn add_data_variable( &self, address: u64, t: &Type, diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index a883dc8294..68b349ca97 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -19,14 +19,14 @@ use std::ffi::{c_char, c_void}; use crate::architecture::CoreArchitecture; use crate::binary_view::BinaryView; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::types::{QualifiedName, Type}; use crate::rc::*; pub type Result = std::result::Result; -pub fn demangle_generic( +pub fn demangle_generic( arch: &CoreArchitecture, mangled_name: S, view: Option<&BinaryView>, @@ -57,7 +57,7 @@ pub fn demangle_generic( } } -pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { +pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { let mangled_name = mangled_name.to_cstr(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; @@ -85,7 +85,7 @@ pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option( +pub fn demangle_gnu3( arch: &CoreArchitecture, mangled_name: S, simplify: bool, @@ -125,7 +125,7 @@ pub fn demangle_gnu3( } } -pub fn demangle_ms( +pub fn demangle_ms( arch: &CoreArchitecture, mangled_name: S, simplify: bool, @@ -182,12 +182,12 @@ impl Demangler { unsafe { Array::::new(demanglers, count, ()) } } - pub fn is_mangled_string(&self, name: S) -> bool { + pub fn is_mangled_string(&self, name: S) -> bool { let bytes = name.to_cstr(); unsafe { BNIsDemanglerMangledName(self.handle, bytes.as_ref().as_ptr() as *const _) } } - pub fn demangle( + pub fn demangle( &self, arch: &CoreArchitecture, name: S, @@ -231,7 +231,7 @@ impl Demangler { unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) } } - pub fn from_name(name: S) -> Option { + pub fn from_name(name: S) -> Option { let name_bytes = name.to_cstr(); let demangler = unsafe { BNGetDemanglerByName(name_bytes.as_ref().as_ptr() as *const _) }; if demangler.is_null() { @@ -243,7 +243,7 @@ impl Demangler { pub fn register(name: S, demangler: C) -> Self where - S: AsCStr, + S: IntoCStr, C: CustomDemangler, { extern "C" fn cb_is_mangled_string(ctxt: *mut c_void, name: *const c_char) -> bool diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 5964324d82..396bcfcc2f 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -22,7 +22,7 @@ use crate::function::{Location, NativeBlock}; use crate::high_level_il as hlil; use crate::low_level_il as llil; use crate::medium_level_il as mlil; -use crate::string::AsCStr; +use crate::string::IntoCStr; use crate::string::{raw_to_string, strings_to_string_list, BnString}; use crate::rc::*; @@ -1242,7 +1242,7 @@ impl DisassemblyTextRenderer { unsafe { Array::new(tokens, count, ()) } } - pub fn wrap_comment( + pub fn wrap_comment( &self, cur_line: DisassemblyTextLine, comment: S1, diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index 7d28058fad..e74274f44f 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -1,6 +1,6 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::settings::Settings; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::ffi::{c_void, CStr}; @@ -13,7 +13,7 @@ pub struct DownloadProvider { } impl DownloadProvider { - pub fn get(name: S) -> Option { + pub fn get(name: S) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetDownloadProviderByName(name.as_ptr()) }; if result.is_null() { @@ -131,7 +131,7 @@ impl DownloadInstance { } } - pub fn perform_request( + pub fn perform_request( &mut self, url: S, callbacks: DownloadInstanceOutputCallbacks, @@ -202,11 +202,11 @@ impl DownloadInstance { } pub fn perform_custom_request< - M: AsCStr, - U: AsCStr, - HK: AsCStr, - HV: AsCStr, - I: IntoIterator, + M: IntoCStr, + U: IntoCStr, + HK: IntoCStr, + HV: IntoCStr, + I: Iterator, >( &mut self, method: M, diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index 74389d4563..7c2aad19f6 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -1,5 +1,5 @@ use crate::rc::Array; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use std::ffi::c_void; use std::marker::PhantomData; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -120,7 +120,7 @@ pub fn server_url() -> String { unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } } -pub fn set_server_url(url: S) -> Result<(), ()> { +pub fn set_server_url(url: S) -> Result<(), ()> { let url = url.to_cstr(); let result = unsafe { binaryninjacore_sys::BNSetEnterpriseServerUrl( @@ -185,8 +185,8 @@ pub fn is_server_license_still_activated() -> bool { pub fn authenticate_server_with_credentials(username: U, password: P, remember: bool) -> bool where - U: AsCStr, - P: AsCStr, + U: IntoCStr, + P: IntoCStr, { let username = username.to_cstr(); let password = password.to_cstr(); @@ -199,7 +199,7 @@ where } } -pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { +pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { let method = method.to_cstr(); unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithMethod( diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs index 57848a7a55..4f6e0e84ae 100644 --- a/rust/src/external_library.rs +++ b/rust/src/external_library.rs @@ -1,6 +1,6 @@ use crate::project::file::ProjectFile; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::symbol::Symbol; use binaryninjacore_sys::*; use std::fmt::Debug; @@ -166,7 +166,7 @@ impl ExternalLocation { /// Set the symbol pointed to by this ExternalLocation. /// ExternalLocations must have a valid target address and/or symbol set. - pub fn set_target_symbol(&self, symbol: Option) -> bool { + pub fn set_target_symbol(&self, symbol: Option) -> bool { match symbol { Some(sym) => { let raw_sym = sym.to_cstr(); diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index 100f255b44..deec36f0c8 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -52,7 +52,7 @@ impl FileMetadata { Self::ref_from_raw(unsafe { BNCreateFileMetadata() }) } - pub fn with_filename(name: S) -> Ref { + pub fn with_filename(name: S) -> Ref { let ret = FileMetadata::new(); ret.set_filename(name); ret @@ -75,7 +75,7 @@ impl FileMetadata { } } - pub fn set_filename(&self, name: S) { + pub fn set_filename(&self, name: S) { let name = name.to_cstr(); unsafe { @@ -107,7 +107,7 @@ impl FileMetadata { self.is_database_backed_for_view_type("") } - pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { + pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { let view_type = view_type.to_cstr(); unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } @@ -135,14 +135,14 @@ impl FileMetadata { unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } - pub fn commit_undo_actions(&self, id: S) { + pub fn commit_undo_actions(&self, id: S) { let id = id.to_cstr(); unsafe { BNCommitUndoActions(self.handle, id.as_ref().as_ptr() as *const _); } } - pub fn revert_undo_actions(&self, id: S) { + pub fn revert_undo_actions(&self, id: S) { let id = id.to_cstr(); unsafe { BNRevertUndoActions(self.handle, id.as_ref().as_ptr() as *const _); @@ -169,7 +169,7 @@ impl FileMetadata { unsafe { BNGetCurrentOffset(self.handle) } } - pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { + pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { let view = view.to_cstr(); unsafe { @@ -181,7 +181,7 @@ impl FileMetadata { } } - pub fn view_of_type(&self, view: S) -> Option> { + pub fn view_of_type(&self, view: S) -> Option> { let view = view.to_cstr(); unsafe { @@ -226,7 +226,7 @@ impl FileMetadata { } // TODO: Pass settings? - pub fn create_database_with_progress( + pub fn create_database_with_progress( &self, file_path: impl AsRef, mut progress: P, @@ -256,7 +256,7 @@ impl FileMetadata { unsafe { BNSaveAutoSnapshot(raw_view.handle, ptr::null_mut() as *mut _) } } - pub fn open_database_for_configuration( + pub fn open_database_for_configuration( &self, filename: S, ) -> Result, ()> { @@ -273,7 +273,7 @@ impl FileMetadata { } } - pub fn open_database(&self, filename: S) -> Result, ()> { + pub fn open_database(&self, filename: S) -> Result, ()> { let filename = filename.to_cstr(); let filename_ptr = filename.as_ptr(); @@ -286,7 +286,7 @@ impl FileMetadata { } } - pub fn open_database_with_progress( + pub fn open_database_with_progress( &self, filename: S, mut progress: P, diff --git a/rust/src/function.rs b/rust/src/function.rs index 36bd1d56c6..5ebb84f6d7 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -372,7 +372,7 @@ impl Function { unsafe { BnString::into_string(BNGetFunctionComment(self.handle)) } } - pub fn set_comment(&self, comment: S) { + pub fn set_comment(&self, comment: S) { let raw = comment.to_cstr(); unsafe { @@ -394,7 +394,7 @@ impl Function { unsafe { BnString::into_string(BNGetCommentForAddress(self.handle, addr)) } } - pub fn set_comment_at(&self, addr: u64, comment: S) { + pub fn set_comment_at(&self, addr: u64, comment: S) { let raw = comment.to_cstr(); unsafe { @@ -1103,7 +1103,7 @@ impl Function { /// let crash = bv.create_tag_type("Crashes", "🎯"); /// fun.add_tag(&crash, "Nullpointer dereference", Some(0x1337), false, None); /// ``` - pub fn add_tag( + pub fn add_tag( &self, tag_type: &TagType, data: S, @@ -1707,10 +1707,10 @@ impl Function { operand: usize, display_type: IntegerDisplayType, arch: Option, - enum_display_typeid: Option, + enum_display_typeid: Option, ) { let arch = arch.unwrap_or_else(|| self.arch()); - let enum_display_typeid = enum_display_typeid.map(AsCStr::to_cstr); + let enum_display_typeid = enum_display_typeid.map(IntoCStr::to_cstr); let enum_display_typeid_ptr = enum_display_typeid .map(|x| x.as_ptr()) .unwrap_or(std::ptr::null()); diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs index 302a6d737e..8f7e9d81d4 100644 --- a/rust/src/high_level_il/operation.rs +++ b/rust/src/high_level_il/operation.rs @@ -6,7 +6,7 @@ use super::HighLevelILLiftedInstruction; use crate::architecture::CoreIntrinsic; use crate::function::Function; use crate::rc::Ref; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::variable::{ConstantData, SSAVariable, Variable}; #[derive(Clone, PartialEq, Eq)] @@ -20,7 +20,7 @@ impl GotoLabel { unsafe { BnString::into_string(BNGetGotoLabelName(self.function.handle, self.target)) } } - fn set_name(&self, name: S) { + fn set_name(&self, name: S) { let raw = name.to_cstr(); unsafe { BNSetUserGotoLabelName( @@ -327,7 +327,7 @@ impl LiftedLabel { self.target.name() } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: S) { self.target.set_name(name) } } diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 9994608fa0..fad207d149 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -21,7 +21,7 @@ use std::path::PathBuf; use crate::binary_view::BinaryView; use crate::rc::Ref; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub type MessageBoxButtonSet = BNMessageBoxButtonSet; pub type MessageBoxIcon = BNMessageBoxIcon; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 08abc349f0..8d8fae13ef 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -102,8 +102,8 @@ use std::cmp; use std::collections::HashMap; use std::ffi::{c_char, c_void, CStr}; use std::path::{Path, PathBuf}; -use string::AsCStr; use string::BnString; +use string::IntoCStr; use string::IntoJson; use crate::progress::{NoProgressCallback, ProgressCallback}; @@ -470,7 +470,7 @@ impl VersionInfo { unsafe { BnString::free_raw(value.channel) }; } - pub fn from_string(string: S) -> Self { + pub fn from_string(string: S) -> Self { let string = string.to_cstr(); let result = unsafe { BNParseVersionString(string.as_ptr()) }; Self::from_owned_raw(result) @@ -529,13 +529,13 @@ pub fn license_count() -> i32 { /// 1. Check the BN_LICENSE environment variable /// 2. Check the Binary Ninja user directory for license.dat #[cfg(not(feature = "demo"))] -pub fn set_license(license: Option) { +pub fn set_license(license: Option) { let license = license.unwrap_or_default().to_cstr(); unsafe { BNSetLicense(license.as_ptr()) } } #[cfg(feature = "demo")] -pub fn set_license(_license: Option) {} +pub fn set_license(_license: Option) {} pub fn product() -> String { unsafe { BnString::into_string(BNGetProduct()) } @@ -554,7 +554,7 @@ pub fn is_ui_enabled() -> bool { unsafe { BNIsUIEnabled() } } -pub fn is_database(filename: S) -> bool { +pub fn is_database(filename: S) -> bool { let filename = filename.to_cstr(); unsafe { BNIsDatabase(filename.as_ptr()) } } @@ -583,12 +583,12 @@ pub fn plugin_ui_abi_minimum_version() -> u32 { BN_MINIMUM_UI_ABI_VERSION } -pub fn add_required_plugin_dependency(name: S) { +pub fn add_required_plugin_dependency(name: S) { let raw_name = name.to_cstr(); unsafe { BNAddRequiredPluginDependency(raw_name.as_ptr()) }; } -pub fn add_optional_plugin_dependency(name: S) { +pub fn add_optional_plugin_dependency(name: S) { let raw_name = name.to_cstr(); unsafe { BNAddOptionalPluginDependency(raw_name.as_ptr()) }; } diff --git a/rust/src/logger.rs b/rust/src/logger.rs index 5f14af695d..ad6bd9d167 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -35,7 +35,7 @@ use binaryninjacore_sys::{ }; use crate::rc::{Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use log; use log::LevelFilter; use std::ffi::{CStr, CString}; diff --git a/rust/src/medium_level_il/function.rs b/rust/src/medium_level_il/function.rs index 75ccad826b..0b88c16635 100644 --- a/rust/src/medium_level_il/function.rs +++ b/rust/src/medium_level_il/function.rs @@ -10,7 +10,7 @@ use crate::disassembly::DisassemblySettings; use crate::flowgraph::FlowGraph; use crate::function::{Function, Location}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; -use crate::string::AsCStr; +use crate::string::IntoCStr; use crate::types::Type; use crate::variable::{PossibleValueSet, RegisterValue, SSAVariable, UserVariableValue, Variable}; @@ -121,7 +121,7 @@ impl MediumLevelILFunction { unsafe { Array::new(raw_instr_idxs, count, self.to_owned()) } } - pub fn create_user_stack_var<'a, S: AsCStr, C: Into>>( + pub fn create_user_stack_var<'a, S: IntoCStr, C: Into>>( self, offset: i64, var_type: C, @@ -143,7 +143,7 @@ impl MediumLevelILFunction { unsafe { BNDeleteUserStackVariable(self.function().handle, offset) } } - pub fn create_user_var<'a, S: AsCStr, C: Into>>( + pub fn create_user_var<'a, S: IntoCStr, C: Into>>( &self, var: &Variable, var_type: C, @@ -273,7 +273,7 @@ impl MediumLevelILFunction { Ok(()) } - pub fn create_auto_stack_var<'a, T: Into>, S: AsCStr>( + pub fn create_auto_stack_var<'a, T: Into>, S: IntoCStr>( &self, offset: i64, var_type: T, @@ -295,7 +295,7 @@ impl MediumLevelILFunction { unsafe { BNDeleteAutoStackVariable(self.function().handle, offset) } } - pub fn create_auto_var<'a, S: AsCStr, C: Into>>( + pub fn create_auto_var<'a, S: IntoCStr, C: Into>>( &self, var: &Variable, var_type: C, diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index b6b3ce6119..2ccd9d5249 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString, IntoJson}; +use crate::string::{BnString, IntoCStr, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::os::raw::c_char; @@ -267,7 +267,7 @@ impl Metadata { Ok(Some(unsafe { Self::ref_from_raw(ptr) })) } - pub fn get(&self, key: S) -> Result>, ()> { + pub fn get(&self, key: S) -> Result>, ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -287,7 +287,7 @@ impl Metadata { Ok(()) } - pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { + pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -305,7 +305,7 @@ impl Metadata { Ok(()) } - pub fn remove_key(&self, key: S) -> Result<(), ()> { + pub fn remove_key(&self, key: S) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -424,7 +424,7 @@ impl From<&Array> for Ref { } } -impl From>> for Ref { +impl From>> for Ref { fn from(value: HashMap>) -> Self { let data: Vec<(S::Result, Ref)> = value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); @@ -443,7 +443,7 @@ impl From>> for Ref { impl From<&[(S, T)]> for Ref where - S: AsCStr + Copy, + S: IntoCStr + Copy, for<'a> &'a T: Into>, { fn from(value: &[(S, T)]) -> Self { @@ -464,7 +464,7 @@ where impl From<[(S, T); N]> for Ref where - S: AsCStr + Copy, + S: IntoCStr + Copy, for<'a> &'a T: Into>, { fn from(value: [(S, T); N]) -> Self { @@ -518,7 +518,7 @@ impl From<&Vec> for Ref { } } -impl From> for Ref { +impl From> for Ref { fn from(value: Vec) -> Self { let mut refs = vec![]; for v in value { diff --git a/rust/src/platform.rs b/rust/src/platform.rs index b51ad61dca..d7d3b99027 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -82,7 +82,7 @@ impl Platform { Ref::new(Self { handle }) } - pub fn by_name(name: S) -> Option> { + pub fn by_name(name: S) -> Option> { let raw_name = name.to_cstr(); unsafe { let res = BNGetPlatformByName(raw_name.as_ptr()); @@ -113,7 +113,7 @@ impl Platform { } } - pub fn list_by_os(name: S) -> Array { + pub fn list_by_os(name: S) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -124,7 +124,7 @@ impl Platform { } } - pub fn list_by_os_and_arch(name: S, arch: &CoreArchitecture) -> Array { + pub fn list_by_os_and_arch(name: S, arch: &CoreArchitecture) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -145,7 +145,7 @@ impl Platform { } } - pub fn new(arch: &A, name: S) -> Ref { + pub fn new(arch: &A, name: S) -> Ref { let name = name.to_cstr(); unsafe { let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ptr()); @@ -173,7 +173,7 @@ impl Platform { unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } - pub fn get_type_libraries_by_name(&self, name: T) -> Array { + pub fn get_type_libraries_by_name(&self, name: T) -> Array { let mut count = 0; let name = name.to_cstr(); let result = @@ -182,7 +182,7 @@ impl Platform { unsafe { Array::new(result, count, ()) } } - pub fn register_os(&self, os: S) { + pub fn register_os(&self, os: S) { let os = os.to_cstr(); unsafe { diff --git a/rust/src/project.rs b/rust/src/project.rs index 351b6e3f76..7b6a263ea6 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -13,7 +13,7 @@ use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::project::folder::ProjectFolder; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub struct Project { pub(crate) handle: NonNull, @@ -39,7 +39,7 @@ impl Project { /// /// * `path` - Path to the project directory (.bnpr) /// * `name` - Name of the new project - pub fn create(path: P, name: S) -> Option> { + pub fn create(path: P, name: S) -> Option> { let path_raw = path.to_cstr(); let name_raw = name.to_cstr(); let handle = unsafe { BNCreateProject(path_raw.as_ptr(), name_raw.as_ptr()) }; @@ -49,7 +49,7 @@ impl Project { /// Open an existing project /// /// * `path` - Path to the project directory (.bnpr) or project metadata file (.bnpm) - pub fn open_project(path: P) -> Option> { + pub fn open_project(path: P) -> Option> { let path_raw = path.to_cstr(); let handle = unsafe { BNOpenProject(path_raw.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) @@ -94,7 +94,7 @@ impl Project { } /// Set the name of the project - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: S) { let value = value.to_cstr(); unsafe { BNProjectSetName(self.handle.as_ptr(), value.as_ptr()) } } @@ -105,13 +105,13 @@ impl Project { } /// Set the description of the project - pub fn set_description(&self, value: S) { + pub fn set_description(&self, value: S) { let value = value.to_cstr(); unsafe { BNProjectSetDescription(self.handle.as_ptr(), value.as_ptr()) } } /// Retrieves metadata stored under a key from the project - pub fn query_metadata(&self, key: S) -> Ref { + pub fn query_metadata(&self, key: S) -> Ref { let key = key.to_cstr(); let result = unsafe { BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; unsafe { Metadata::ref_from_raw(result) } @@ -121,13 +121,13 @@ impl Project { /// /// * `key` - Key under which to store the Metadata object /// * `value` - Object to store - pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { + pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { let key_raw = key.to_cstr(); unsafe { BNProjectStoreMetadata(self.handle.as_ptr(), key_raw.as_ptr(), value.handle) } } /// Removes the metadata associated with this `key` from the project - pub fn remove_metadata(&self, key: S) { + pub fn remove_metadata(&self, key: S) { let key_raw = key.to_cstr(); unsafe { BNProjectRemoveMetadata(self.handle.as_ptr(), key_raw.as_ptr()) } } @@ -148,8 +148,8 @@ impl Project { description: D, ) -> Result, ()> where - P: AsCStr, - D: AsCStr, + P: IntoCStr, + D: IntoCStr, { self.create_folder_from_path_with_progress(path, parent, description, NoProgressCallback) } @@ -168,8 +168,8 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: AsCStr, - D: AsCStr, + P: IntoCStr, + D: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -201,8 +201,8 @@ impl Project { description: D, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, + N: IntoCStr, + D: IntoCStr, { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); @@ -232,9 +232,9 @@ impl Project { id: I, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, - I: AsCStr, + N: IntoCStr, + D: IntoCStr, + I: IntoCStr, { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); @@ -264,7 +264,7 @@ impl Project { } /// Retrieve a folder in the project by unique folder `id` - pub fn folder_by_id(&self, id: S) -> Option> { + pub fn folder_by_id(&self, id: S) -> Option> { let raw_id = id.to_cstr(); let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; @@ -321,9 +321,9 @@ impl Project { description: D, ) -> Result, ()> where - P: AsCStr, - N: AsCStr, - D: AsCStr, + P: IntoCStr, + N: IntoCStr, + D: IntoCStr, { self.create_file_from_path_with_progress( path, @@ -350,9 +350,9 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: AsCStr, - N: AsCStr, - D: AsCStr, + P: IntoCStr, + N: IntoCStr, + D: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -392,10 +392,10 @@ impl Project { creation_time: SystemTime, ) -> Result, ()> where - P: AsCStr, - N: AsCStr, - D: AsCStr, - I: AsCStr, + P: IntoCStr, + N: IntoCStr, + D: IntoCStr, + I: IntoCStr, { self.create_file_from_path_unsafe_with_progress( path, @@ -429,10 +429,10 @@ impl Project { mut progress: PC, ) -> Result, ()> where - P: AsCStr, - N: AsCStr, - D: AsCStr, - I: AsCStr, + P: IntoCStr, + N: IntoCStr, + D: IntoCStr, + I: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -471,8 +471,8 @@ impl Project { description: D, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, + N: IntoCStr, + D: IntoCStr, { self.create_file_with_progress(contents, folder, name, description, NoProgressCallback) } @@ -493,8 +493,8 @@ impl Project { mut progress: P, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, + N: IntoCStr, + D: IntoCStr, P: ProgressCallback, { let name_raw = name.to_cstr(); @@ -534,9 +534,9 @@ impl Project { creation_time: SystemTime, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, - I: AsCStr, + N: IntoCStr, + D: IntoCStr, + I: IntoCStr, { self.create_file_unsafe_with_progress( contents, @@ -570,9 +570,9 @@ impl Project { mut progress: P, ) -> Result, ()> where - N: AsCStr, - D: AsCStr, - I: AsCStr, + N: IntoCStr, + D: IntoCStr, + I: IntoCStr, P: ProgressCallback, { let name_raw = name.to_cstr(); @@ -606,7 +606,7 @@ impl Project { } /// Retrieve a file in the project by unique `id` - pub fn file_by_id(&self, id: S) -> Option> { + pub fn file_by_id(&self, id: S) -> Option> { let raw_id = id.to_cstr(); let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; @@ -614,7 +614,7 @@ impl Project { } /// Retrieve a file in the project by the `path` on disk - pub fn file_by_path(&self, path: S) -> Option> { + pub fn file_by_path(&self, path: S) -> Option> { let path_raw = path.to_cstr(); let result = unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_raw.as_ptr()) }; diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs index bc486ed9bd..4a1d6fec53 100644 --- a/rust/src/project/file.rs +++ b/rust/src/project/file.rs @@ -1,6 +1,6 @@ use crate::project::{systime_from_bntime, Project, ProjectFolder}; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::{ BNFreeProjectFile, BNFreeProjectFileList, BNNewProjectFileReference, BNProjectFile, BNProjectFileExistsOnDisk, BNProjectFileExport, BNProjectFileGetCreationTimestamp, @@ -56,7 +56,7 @@ impl ProjectFile { } /// Set the name of this file - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: S) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFileSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -67,7 +67,7 @@ impl ProjectFile { } /// Set the description of this file - pub fn set_description(&self, value: S) -> bool { + pub fn set_description(&self, value: S) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFileSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -93,7 +93,7 @@ impl ProjectFile { /// Export this file to disk, `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { + pub fn export(&self, dest: S) -> bool { let dest_raw = dest.to_cstr(); unsafe { BNProjectFileExport(self.handle.as_ptr(), dest_raw.as_ptr()) } } diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index c7ec82e41a..acb663fb16 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -1,7 +1,7 @@ use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::{ BNFreeProjectFolder, BNFreeProjectFolderList, BNNewProjectFolderReference, BNProjectFolder, BNProjectFolderExport, BNProjectFolderGetDescription, BNProjectFolderGetId, @@ -46,7 +46,7 @@ impl ProjectFolder { } /// Set the name of this folder - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: S) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -57,7 +57,7 @@ impl ProjectFolder { } /// Set the description of this folder - pub fn set_description(&self, value: S) -> bool { + pub fn set_description(&self, value: S) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -78,7 +78,7 @@ impl ProjectFolder { /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { + pub fn export(&self, dest: S) -> bool { self.export_with_progress(dest, NoProgressCallback) } @@ -89,7 +89,7 @@ impl ProjectFolder { /// * `progress` - [`ProgressCallback`] that will be called as contents are exporting pub fn export_with_progress(&self, dest: S, mut progress: P) -> bool where - S: AsCStr, + S: IntoCStr, P: ProgressCallback, { let dest_raw = dest.to_cstr(); diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index b794f698f7..756c76bfaf 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -1,6 +1,6 @@ use crate::low_level_il::RegularLowLevelILFunction; use crate::rc::Guard; -use crate::string::AsCStr; +use crate::string::IntoCStr; use crate::{ architecture::CoreArchitecture, binary_view::BinaryView, @@ -404,7 +404,7 @@ unsafe impl RefCountable for CoreRelocationHandler { pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: S, func: F) where - S: AsCStr, + S: IntoCStr, R: 'static + RelocationHandler> + Send + Sync + Sized, F: FnOnce(CustomRelocationHandlerHandle, CoreRelocationHandler) -> R, { diff --git a/rust/src/render_layer.rs b/rust/src/render_layer.rs index 7d79249143..3fd94a3ac8 100644 --- a/rust/src/render_layer.rs +++ b/rust/src/render_layer.rs @@ -6,7 +6,7 @@ use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; use crate::linear_view::{LinearDisassemblyLine, LinearDisassemblyLineType, LinearViewObject}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::AsCStr; +use crate::string::IntoCStr; use binaryninjacore_sys::*; use std::ffi::c_void; use std::ptr::NonNull; @@ -61,7 +61,7 @@ impl Default for RenderLayerDefaultState { } /// Register a [`RenderLayer`] with the API. -pub fn register_render_layer( +pub fn register_render_layer( name: S, render_layer: T, default_state: RenderLayerDefaultState, @@ -299,7 +299,7 @@ impl CoreRenderLayer { unsafe { Array::new(result, count, ()) } } - pub fn render_layer_by_name(name: S) -> Option { + pub fn render_layer_by_name(name: S) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) }; NonNull::new(result).map(Self::from_raw) diff --git a/rust/src/repository.rs b/rust/src/repository.rs index 27825b966f..8d9a8f403e 100644 --- a/rust/src/repository.rs +++ b/rust/src/repository.rs @@ -9,7 +9,7 @@ use binaryninjacore_sys::*; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::repository::plugin::RepositoryPlugin; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub use manager::RepositoryManager; @@ -52,7 +52,7 @@ impl Repository { unsafe { Array::new(result, count, ()) } } - pub fn plugin_by_path(&self, path: S) -> Option> { + pub fn plugin_by_path(&self, path: S) -> Option> { let path = path.to_cstr(); let result = unsafe { BNRepositoryGetPluginByPath(self.handle.as_ptr(), path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { RepositoryPlugin::ref_from_raw(h) }) diff --git a/rust/src/repository/manager.rs b/rust/src/repository/manager.rs index 29c7360569..42d8aa42e5 100644 --- a/rust/src/repository/manager.rs +++ b/rust/src/repository/manager.rs @@ -1,6 +1,6 @@ use crate::rc::{Array, Ref, RefCountable}; use crate::repository::Repository; -use crate::string::AsCStr; +use crate::string::IntoCStr; use binaryninjacore_sys::{ BNCreateRepositoryManager, BNFreeRepositoryManager, BNGetRepositoryManager, BNNewRepositoryManagerReference, BNRepositoryGetRepositoryByPath, BNRepositoryManager, @@ -28,7 +28,7 @@ impl RepositoryManager { Ref::new(Self { handle }) } - pub fn new(plugins_path: S) -> Ref { + pub fn new(plugins_path: S) -> Ref { let plugins_path = plugins_path.to_cstr(); let result = unsafe { BNCreateRepositoryManager(plugins_path.as_ptr()) }; unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } @@ -59,7 +59,7 @@ impl RepositoryManager { /// * `repository_path` - path to where the repository will be stored on disk locally /// /// Returns true if the repository was successfully added, false otherwise. - pub fn add_repository(&self, url: U, repository_path: P) -> bool { + pub fn add_repository(&self, url: U, repository_path: P) -> bool { let url = url.to_cstr(); let repo_path = repository_path.to_cstr(); unsafe { @@ -67,7 +67,7 @@ impl RepositoryManager { } } - pub fn repository_by_path(&self, path: P) -> Option { + pub fn repository_by_path(&self, path: P) -> Option { let path = path.to_cstr(); let result = unsafe { BNRepositoryGetRepositoryByPath(self.handle.as_ptr(), path.as_ptr()) }; diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index fcb2064411..5924b9fb56 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use std::ptr::NonNull; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; pub trait SecretsProvider { fn has_data(&mut self, key: &str) -> bool; @@ -49,7 +49,7 @@ impl CoreSecretsProvider { } /// Retrieve a provider by name - pub fn by_name(name: S) -> Option { + pub fn by_name(name: S) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetSecretsProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) @@ -62,27 +62,27 @@ impl CoreSecretsProvider { } /// Check if data for a specific key exists, but do not retrieve it - pub fn has_data(&self, key: S) -> bool { + pub fn has_data(&self, key: S) -> bool { let key = key.to_cstr(); unsafe { BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ptr()) } } /// Retrieve data for the given key, if it exists - pub fn get_data(&self, key: S) -> String { + pub fn get_data(&self, key: S) -> String { let key = key.to_cstr(); let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) }; unsafe { BnString::into_string(result) } } /// Store data with the given key - pub fn store_data(&self, key: K, value: V) -> bool { + pub fn store_data(&self, key: K, value: V) -> bool { let key = key.to_cstr(); let value = value.to_cstr(); unsafe { BNStoreSecretsProviderData(self.handle.as_ptr(), key.as_ptr(), value.as_ptr()) } } /// Delete stored data with the given key - pub fn delete_data(&self, key: S) -> bool { + pub fn delete_data(&self, key: S) -> bool { let key = key.to_cstr(); unsafe { BNDeleteSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) } } diff --git a/rust/src/settings.rs b/rust/src/settings.rs index be2fd955f5..35f7b7a05c 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -20,7 +20,7 @@ use std::fmt::Debug; use crate::binary_view::BinaryView; use crate::rc::*; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::function::Function; @@ -44,7 +44,7 @@ impl Settings { Self::new_with_id(GLOBAL_INSTANCE_ID) } - pub fn new_with_id(instance_id: S) -> Ref { + pub fn new_with_id(instance_id: S) -> Ref { let instance_id = instance_id.to_cstr(); unsafe { let handle = BNCreateSettings(instance_id.as_ptr()); @@ -53,7 +53,7 @@ impl Settings { } } - pub fn set_resource_id(&self, resource_id: S) { + pub fn set_resource_id(&self, resource_id: S) { let resource_id = resource_id.to_cstr(); unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ptr()) }; } @@ -62,11 +62,11 @@ impl Settings { unsafe { BnString::into_string(BNSettingsSerializeSchema(self.handle)) } } - pub fn deserialize_schema(&self, schema: S) -> bool { + pub fn deserialize_schema(&self, schema: S) -> bool { self.deserialize_schema_with_scope(schema, SettingsScope::SettingsAutoScope) } - pub fn deserialize_schema_with_scope( + pub fn deserialize_schema_with_scope( &self, schema: S, scope: SettingsScope, @@ -75,7 +75,7 @@ impl Settings { unsafe { BNSettingsDeserializeSchema(self.handle, schema.as_ptr(), scope, true) } } - pub fn contains(&self, key: S) -> bool { + pub fn contains(&self, key: S) -> bool { let key = key.to_cstr(); unsafe { BNSettingsContains(self.handle, key.as_ptr()) } @@ -90,11 +90,11 @@ impl Settings { // TODO Update the settings API to take an optional BinaryView or Function. Separate functions or...? - pub fn get_bool(&self, key: S) -> bool { + pub fn get_bool(&self, key: S) -> bool { self.get_bool_with_opts(key, &mut QueryOptions::default()) } - pub fn get_bool_with_opts(&self, key: S, options: &mut QueryOptions) -> bool { + pub fn get_bool_with_opts(&self, key: S, options: &mut QueryOptions) -> bool { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -115,11 +115,11 @@ impl Settings { } } - pub fn get_double(&self, key: S) -> f64 { + pub fn get_double(&self, key: S) -> f64 { self.get_double_with_opts(key, &mut QueryOptions::default()) } - pub fn get_double_with_opts(&self, key: S, options: &mut QueryOptions) -> f64 { + pub fn get_double_with_opts(&self, key: S, options: &mut QueryOptions) -> f64 { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -140,11 +140,11 @@ impl Settings { } } - pub fn get_integer(&self, key: S) -> u64 { + pub fn get_integer(&self, key: S) -> u64 { self.get_integer_with_opts(key, &mut QueryOptions::default()) } - pub fn get_integer_with_opts(&self, key: S, options: &mut QueryOptions) -> u64 { + pub fn get_integer_with_opts(&self, key: S, options: &mut QueryOptions) -> u64 { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -165,11 +165,11 @@ impl Settings { } } - pub fn get_string(&self, key: S) -> String { + pub fn get_string(&self, key: S) -> String { self.get_string_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + pub fn get_string_with_opts(&self, key: S, options: &mut QueryOptions) -> String { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -190,11 +190,11 @@ impl Settings { } } - pub fn get_string_list(&self, key: S) -> Array { + pub fn get_string_list(&self, key: S) -> Array { self.get_string_list_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_list_with_opts( + pub fn get_string_list_with_opts( &self, key: S, options: &mut QueryOptions, @@ -225,11 +225,11 @@ impl Settings { } } - pub fn get_json(&self, key: S) -> String { + pub fn get_json(&self, key: S) -> String { self.get_json_with_opts(key, &mut QueryOptions::default()) } - pub fn get_json_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + pub fn get_json_with_opts(&self, key: S, options: &mut QueryOptions) -> String { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -250,11 +250,11 @@ impl Settings { } } - pub fn set_bool(&self, key: S, value: bool) { + pub fn set_bool(&self, key: S, value: bool) { self.set_bool_with_opts(key, value, &QueryOptions::default()) } - pub fn set_bool_with_opts(&self, key: S, value: bool, options: &QueryOptions) { + pub fn set_bool_with_opts(&self, key: S, value: bool, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -276,10 +276,10 @@ impl Settings { } } - pub fn set_double(&self, key: S, value: f64) { + pub fn set_double(&self, key: S, value: f64) { self.set_double_with_opts(key, value, &QueryOptions::default()) } - pub fn set_double_with_opts(&self, key: S, value: f64, options: &QueryOptions) { + pub fn set_double_with_opts(&self, key: S, value: f64, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -301,11 +301,11 @@ impl Settings { } } - pub fn set_integer(&self, key: S, value: u64) { + pub fn set_integer(&self, key: S, value: u64) { self.set_integer_with_opts(key, value, &QueryOptions::default()) } - pub fn set_integer_with_opts(&self, key: S, value: u64, options: &QueryOptions) { + pub fn set_integer_with_opts(&self, key: S, value: u64, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -327,11 +327,11 @@ impl Settings { } } - pub fn set_string(&self, key: S1, value: S2) { + pub fn set_string(&self, key: S1, value: S2) { self.set_string_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_with_opts( + pub fn set_string_with_opts( &self, key: S1, value: S2, @@ -359,7 +359,7 @@ impl Settings { } } - pub fn set_string_list>( + pub fn set_string_list>( &self, key: S1, value: I, @@ -367,7 +367,7 @@ impl Settings { self.set_string_list_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_list_with_opts>( + pub fn set_string_list_with_opts>( &self, key: S1, value: I, @@ -398,11 +398,11 @@ impl Settings { } } - pub fn set_json(&self, key: S1, value: S2) -> bool { + pub fn set_json(&self, key: S1, value: S2) -> bool { self.set_json_with_opts(key, value, &QueryOptions::default()) } - pub fn set_json_with_opts( + pub fn set_json_with_opts( &self, key: S1, value: S2, @@ -430,7 +430,7 @@ impl Settings { } } - pub fn get_property_string(&self, key: S, property: S) -> String { + pub fn get_property_string(&self, key: S, property: S) -> String { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -442,7 +442,7 @@ impl Settings { } } - pub fn get_property_string_list(&self, key: S, property: S) -> Array { + pub fn get_property_string_list(&self, key: S, property: S) -> Array { let key = key.to_cstr(); let property = property.to_cstr(); let mut size: usize = 0; @@ -460,7 +460,7 @@ impl Settings { } } - pub fn update_bool_property(&self, key: S, property: S, value: bool) { + pub fn update_bool_property(&self, key: S, property: S, value: bool) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -468,7 +468,7 @@ impl Settings { } } - pub fn update_integer_property(&self, key: S, property: S, value: u64) { + pub fn update_integer_property(&self, key: S, property: S, value: u64) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -476,7 +476,7 @@ impl Settings { } } - pub fn update_double_property(&self, key: S, property: S, value: f64) { + pub fn update_double_property(&self, key: S, property: S, value: f64) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -484,7 +484,7 @@ impl Settings { } } - pub fn update_string_property(&self, key: S, property: S, value: S) { + pub fn update_string_property(&self, key: S, property: S, value: S) { let key = key.to_cstr(); let property = property.to_cstr(); let value = value.to_cstr(); @@ -498,7 +498,7 @@ impl Settings { } } - pub fn update_string_list_property>( + pub fn update_string_list_property>( &self, key: S, property: S, @@ -520,14 +520,18 @@ impl Settings { } } - pub fn register_group(&self, group: S1, title: S2) -> bool { + pub fn register_group(&self, group: S1, title: S2) -> bool { let group = group.to_cstr(); let title = title.to_cstr(); unsafe { BNSettingsRegisterGroup(self.handle, group.as_ptr(), title.as_ptr()) } } - pub fn register_setting_json(&self, group: S1, properties: S2) -> bool { + pub fn register_setting_json( + &self, + group: S1, + properties: S2, + ) -> bool { let group = group.to_cstr(); let properties = properties.to_cstr(); diff --git a/rust/src/string.rs b/rust/src/string.rs index 820418d066..a670320ba5 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -62,7 +62,7 @@ pub struct BnString { } impl BnString { - pub fn new(s: S) -> Self { + pub fn new(s: S) -> Self { use binaryninjacore_sys::BNAllocString; let raw = s.to_cstr(); unsafe { Self::from_raw(BNAllocString(raw.as_ptr())) } @@ -183,13 +183,13 @@ unsafe impl CoreArrayProviderInner for BnString { } } -pub unsafe trait AsCStr { +pub unsafe trait IntoCStr { type Result: Deref; fn to_cstr(self) -> Self::Result; } -unsafe impl AsCStr for &CStr { +unsafe impl IntoCStr for &CStr { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -197,7 +197,7 @@ unsafe impl AsCStr for &CStr { } } -unsafe impl AsCStr for BnString { +unsafe impl IntoCStr for BnString { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -205,7 +205,7 @@ unsafe impl AsCStr for BnString { } } -unsafe impl AsCStr for &BnString { +unsafe impl IntoCStr for &BnString { type Result = BnString; fn to_cstr(self) -> Self::Result { @@ -213,7 +213,7 @@ unsafe impl AsCStr for &BnString { } } -unsafe impl AsCStr for CString { +unsafe impl IntoCStr for CString { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -221,7 +221,7 @@ unsafe impl AsCStr for CString { } } -unsafe impl AsCStr for &str { +unsafe impl IntoCStr for &str { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -229,7 +229,7 @@ unsafe impl AsCStr for &str { } } -unsafe impl AsCStr for String { +unsafe impl IntoCStr for String { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -237,7 +237,7 @@ unsafe impl AsCStr for String { } } -unsafe impl AsCStr for &String { +unsafe impl IntoCStr for &String { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -245,7 +245,7 @@ unsafe impl AsCStr for &String { } } -unsafe impl<'a> AsCStr for &'a Cow<'a, str> { +unsafe impl<'a> IntoCStr for &'a Cow<'a, str> { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -253,7 +253,7 @@ unsafe impl<'a> AsCStr for &'a Cow<'a, str> { } } -unsafe impl AsCStr for Cow<'_, str> { +unsafe impl IntoCStr for Cow<'_, str> { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -261,7 +261,7 @@ unsafe impl AsCStr for Cow<'_, str> { } } -unsafe impl AsCStr for &QualifiedName { +unsafe impl IntoCStr for &QualifiedName { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -269,7 +269,7 @@ unsafe impl AsCStr for &QualifiedName { } } -unsafe impl AsCStr for PathBuf { +unsafe impl IntoCStr for PathBuf { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -277,7 +277,7 @@ unsafe impl AsCStr for PathBuf { } } -unsafe impl AsCStr for &Path { +unsafe impl IntoCStr for &Path { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -286,7 +286,7 @@ unsafe impl AsCStr for &Path { } } -unsafe impl AsCStr for TypeArchiveSnapshotId { +unsafe impl IntoCStr for TypeArchiveSnapshotId { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -295,12 +295,12 @@ unsafe impl AsCStr for TypeArchiveSnapshotId { } pub trait IntoJson { - type Output: AsCStr; + type Output: IntoCStr; fn get_json_string(self) -> Result; } -impl IntoJson for S { +impl IntoJson for S { type Output = S; fn get_json_string(self) -> Result { diff --git a/rust/src/tags.rs b/rust/src/tags.rs index 72cae705ca..e7a2d44d5d 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -42,7 +42,7 @@ impl Tag { Ref::new(Self { handle }) } - pub fn new(t: &TagType, data: S) -> Ref { + pub fn new(t: &TagType, data: S) -> Ref { let data = data.to_cstr(); unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ptr())) } } @@ -59,7 +59,7 @@ impl Tag { unsafe { TagType::ref_from_raw(BNTagGetType(self.handle)) } } - pub fn set_data(&self, data: S) { + pub fn set_data(&self, data: S) { let data = data.to_cstr(); unsafe { BNTagSetData(self.handle, data.as_ptr()); @@ -134,7 +134,7 @@ impl TagType { Ref::new(Self { handle }) } - pub fn create(view: &BinaryView, name: N, icon: I) -> Ref { + pub fn create(view: &BinaryView, name: N, icon: I) -> Ref { let tag_type = unsafe { Self::ref_from_raw(BNCreateTagType(view.handle)) }; tag_type.set_name(name); tag_type.set_icon(icon); @@ -149,7 +149,7 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetIcon(self.handle)) } } - pub fn set_icon(&self, icon: S) { + pub fn set_icon(&self, icon: S) { let icon = icon.to_cstr(); unsafe { BNTagTypeSetIcon(self.handle, icon.as_ptr()); @@ -160,7 +160,7 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetName(self.handle)) } } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: S) { let name = name.to_cstr(); unsafe { BNTagTypeSetName(self.handle, name.as_ptr()); @@ -179,7 +179,7 @@ impl TagType { unsafe { BNTagTypeGetType(self.handle) } } - pub fn set_type(&self, t: S) { + pub fn set_type(&self, t: S) { let t = t.to_cstr(); unsafe { BNTagTypeSetName(self.handle, t.as_ptr()); diff --git a/rust/src/template_simplifier.rs b/rust/src/template_simplifier.rs index c9e54e72c9..81f8deb403 100644 --- a/rust/src/template_simplifier.rs +++ b/rust/src/template_simplifier.rs @@ -1,15 +1,15 @@ use crate::{ - string::{AsCStr, BnString}, + string::{BnString, IntoCStr}, types::QualifiedName, }; use binaryninjacore_sys::{BNRustSimplifyStrToFQN, BNRustSimplifyStrToStr}; -pub fn simplify_str_to_str(input: S) -> BnString { +pub fn simplify_str_to_str(input: S) -> BnString { let name = input.to_cstr(); unsafe { BnString::from_raw(BNRustSimplifyStrToStr(name.as_ptr())) } } -pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { +pub fn simplify_str_to_fqn(input: S, simplify: bool) -> QualifiedName { let name = input.to_cstr(); unsafe { QualifiedName::from_owned_raw(BNRustSimplifyStrToFQN(name.as_ptr(), simplify)) } } diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 8d9dd670cf..84e9fdeec5 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -10,7 +10,7 @@ use crate::data_buffer::DataBuffer; use crate::metadata::Metadata; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type}; @@ -82,7 +82,7 @@ impl TypeArchive { /// Create a Type Archive at the given path and id, returning None if it could not be created. /// /// If the file has already been created and is not a valid type archive this will return `None`. - pub fn create_with_id( + pub fn create_with_id( path: impl AsRef, id: I, platform: &Platform, @@ -95,7 +95,7 @@ impl TypeArchive { } /// Get a reference to the Type Archive with the known id, if one exists. - pub fn lookup_by_id(id: S) -> Option> { + pub fn lookup_by_id(id: S) -> Option> { let id = id.to_cstr(); let handle = unsafe { BNLookupTypeArchiveById(id.as_ptr()) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) @@ -150,7 +150,7 @@ impl TypeArchive { } /// Get the ids of the parents to the given snapshot - pub fn get_snapshot_parent_ids( + pub fn get_snapshot_parent_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -166,7 +166,7 @@ impl TypeArchive { } /// Get the ids of the children to the given snapshot - pub fn get_snapshot_child_ids( + pub fn get_snapshot_child_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -229,7 +229,7 @@ impl TypeArchive { /// /// * `id` - Old id of type in archive /// * `new_name` - New type name - pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { + pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { let id = id.to_cstr(); let raw_name = QualifiedName::into_raw(new_name); let result = @@ -248,7 +248,7 @@ impl TypeArchive { } /// Delete an existing type in the type archive. - pub fn delete_type_by_id(&self, id: S) -> bool { + pub fn delete_type_by_id(&self, id: S) -> bool { let id = id.to_cstr(); unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) } } @@ -256,7 +256,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive /// /// * `name` - Type name - pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { + pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset()) } @@ -284,7 +284,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive by id /// /// * `id` - Type id - pub fn get_type_by_id(&self, id: I) -> Option> { + pub fn get_type_by_id(&self, id: I) -> Option> { self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -292,7 +292,7 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_id_from_snapshot( + pub fn get_type_by_id_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -311,7 +311,7 @@ impl TypeArchive { /// Retrieve a type's name by its id /// /// * `id` - Type id - pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { + pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -319,7 +319,7 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_name_by_id_from_snapshot( + pub fn get_type_name_by_id_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -465,7 +465,7 @@ impl TypeArchive { /// Get all types a given type references directly /// /// * `id` - Source type id - pub fn get_outgoing_direct_references(&self, id: I) -> Array { + pub fn get_outgoing_direct_references(&self, id: I) -> Array { self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -473,7 +473,7 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_direct_references_from_snapshot( + pub fn get_outgoing_direct_references_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -495,7 +495,7 @@ impl TypeArchive { /// Get all types a given type references, and any types that the referenced types reference /// /// * `id` - Source type id - pub fn get_outgoing_recursive_references(&self, id: I) -> Array { + pub fn get_outgoing_recursive_references(&self, id: I) -> Array { self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -503,7 +503,7 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_recursive_references_from_snapshot( + pub fn get_outgoing_recursive_references_from_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -525,7 +525,7 @@ impl TypeArchive { /// Get all types that reference a given type /// /// * `id` - Target type id - pub fn get_incoming_direct_references(&self, id: I) -> Array { + pub fn get_incoming_direct_references(&self, id: I) -> Array { self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -533,7 +533,7 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types - pub fn get_incoming_direct_references_with_snapshot( + pub fn get_incoming_direct_references_with_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -555,7 +555,7 @@ impl TypeArchive { /// Get all types that reference a given type, and all types that reference them, recursively /// /// * `id` - Target type id - pub fn get_incoming_recursive_references(&self, id: I) -> Array { + pub fn get_incoming_recursive_references(&self, id: I) -> Array { self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -563,7 +563,7 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types, or empty string to search the latest snapshot - pub fn get_incoming_recursive_references_with_snapshot( + pub fn get_incoming_recursive_references_with_snapshot( &self, id: I, snapshot: &TypeArchiveSnapshotId, @@ -583,7 +583,7 @@ impl TypeArchive { } /// Look up a metadata entry in the archive - pub fn query_metadata(&self, key: S) -> Option> { + pub fn query_metadata(&self, key: S) -> Option> { let key = key.to_cstr(); let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) @@ -593,7 +593,7 @@ impl TypeArchive { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { + pub fn store_metadata(&self, key: S, md: &Metadata) { let key = key.to_cstr(); let result = unsafe { BNTypeArchiveStoreMetadata(self.handle.as_ptr(), key.as_ptr(), md.handle) }; @@ -601,13 +601,13 @@ impl TypeArchive { } /// Delete a given metadata entry in the archive from the `key` - pub fn remove_metadata(&self, key: S) -> bool { + pub fn remove_metadata(&self, key: S) -> bool { let key = key.to_cstr(); unsafe { BNTypeArchiveRemoveMetadata(self.handle.as_ptr(), key.as_ptr()) } } /// Turn a given `snapshot` id into a data stream - pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { + pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { let result = unsafe { BNTypeArchiveSerializeSnapshot( self.handle.as_ptr(), @@ -680,7 +680,7 @@ impl TypeArchive { // TODO: Make this AsRef? /// Determine if `file` is a Type Archive - pub fn is_type_archive(file: P) -> bool { + pub fn is_type_archive(file: P) -> bool { let file = file.to_cstr(); unsafe { BNIsTypeArchive(file.as_ptr()) } } @@ -705,7 +705,7 @@ impl TypeArchive { parents: &[TypeArchiveSnapshotId], ) -> TypeArchiveSnapshotId where - P: AsCStr, + P: IntoCStr, F: FnMut(&TypeArchiveSnapshotId) -> bool, { unsafe extern "C" fn cb_callback bool>( @@ -752,12 +752,12 @@ impl TypeArchive { merge_conflicts: M, ) -> Result> where - B: AsCStr, - F: AsCStr, - S: AsCStr, + B: IntoCStr, + F: IntoCStr, + S: IntoCStr, M: IntoIterator, - MI: AsCStr, - MK: AsCStr, + MI: IntoCStr, + MK: IntoCStr, { self.merge_snapshots_with_progress( base_snapshot, @@ -787,12 +787,12 @@ impl TypeArchive { mut progress: P, ) -> Result> where - B: AsCStr, - F: AsCStr, - S: AsCStr, + B: IntoCStr, + F: IntoCStr, + S: IntoCStr, M: IntoIterator, - MI: AsCStr, - MK: AsCStr, + MI: IntoCStr, + MK: IntoCStr, P: ProgressCallback, { let base_snapshot = base_snapshot.to_cstr(); @@ -1141,7 +1141,7 @@ impl TypeArchiveMergeConflict { } // TODO: This needs documentation! - pub fn success(&self, value: S) -> bool { + pub fn success(&self, value: S) -> bool { let value = value.to_cstr(); unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) } } diff --git a/rust/src/type_container.rs b/rust/src/type_container.rs index 90b2ebc91e..2257a2973d 100644 --- a/rust/src/type_container.rs +++ b/rust/src/type_container.rs @@ -11,7 +11,7 @@ use crate::platform::Platform; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, Ref}; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_parser::{TypeParserError, TypeParserResult}; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; @@ -137,7 +137,7 @@ impl TypeContainer { /// (by id) to use the new name. /// /// Returns true if the type was renamed. - pub fn rename_type, S: AsCStr>(&self, name: T, type_id: S) -> bool { + pub fn rename_type, S: IntoCStr>(&self, name: T, type_id: S) -> bool { let type_id = type_id.to_cstr(); let raw_name = QualifiedName::into_raw(name.into()); let success = @@ -150,7 +150,7 @@ impl TypeContainer { /// not specified and you may end up with broken references if any still exist. /// /// Returns true if the type was deleted. - pub fn delete_type(&self, type_id: S) -> bool { + pub fn delete_type(&self, type_id: S) -> bool { let type_id = type_id.to_cstr(); unsafe { BNTypeContainerDeleteType(self.handle.as_ptr(), type_id.as_ptr()) } } @@ -170,7 +170,7 @@ impl TypeContainer { /// Get the unique name of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_name(&self, type_id: S) -> Option { + pub fn type_name(&self, type_id: S) -> Option { let type_id = type_id.to_cstr(); let mut result = BNQualifiedName::default(); let success = unsafe { @@ -182,7 +182,7 @@ impl TypeContainer { /// Get the definition of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_by_id(&self, type_id: S) -> Option> { + pub fn type_by_id(&self, type_id: S) -> Option> { let type_id = type_id.to_cstr(); let mut result = std::ptr::null_mut(); let success = unsafe { @@ -283,7 +283,7 @@ impl TypeContainer { /// /// * `source` - Source code to parse /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing - pub fn parse_type_string( + pub fn parse_type_string( &self, source: S, import_dependencies: bool, @@ -329,13 +329,13 @@ impl TypeContainer { import_dependencies: bool, ) -> Result> where - S: AsCStr, - F: AsCStr, + S: IntoCStr, + F: IntoCStr, O: IntoIterator, - O::Item: AsCStr, + O::Item: IntoCStr, D: IntoIterator, - D::Item: AsCStr, - A: AsCStr, + D::Item: IntoCStr, + A: IntoCStr, { let source = source.to_cstr(); let filename = filename.to_cstr(); diff --git a/rust/src/type_library.rs b/rust/src/type_library.rs index 91e86c61bc..29634c389b 100644 --- a/rust/src/type_library.rs +++ b/rust/src/type_library.rs @@ -7,7 +7,7 @@ use crate::{ metadata::Metadata, platform::Platform, rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}, - string::{AsCStr, BnString}, + string::{BnString, IntoCStr}, types::{QualifiedName, QualifiedNameAndType, Type}, }; @@ -42,7 +42,7 @@ impl TypeLibrary { } /// Creates an empty type library object with a random GUID and the provided name. - pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { + pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { let name = name.to_cstr(); let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) }; @@ -57,7 +57,7 @@ impl TypeLibrary { } /// Decompresses a type library file to a file on disk. - pub fn decompress_to_file(path: P, output: O) -> bool { + pub fn decompress_to_file(path: P, output: O) -> bool { let path = path.to_cstr(); let output = output.to_cstr(); unsafe { @@ -69,7 +69,7 @@ impl TypeLibrary { } /// Loads a finalized type library instance from file - pub fn load_from_file(path: S) -> Option { + pub fn load_from_file(path: S) -> Option { let path = path.to_cstr(); let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; @@ -77,7 +77,7 @@ impl TypeLibrary { } /// Saves a finalized type library instance to file - pub fn write_to_file(&self, path: S) -> bool { + pub fn write_to_file(&self, path: S) -> bool { let path = path.to_cstr(); unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) @@ -86,7 +86,7 @@ impl TypeLibrary { /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. - pub fn from_name(arch: CoreArchitecture, name: S) -> Option { + pub fn from_name(arch: CoreArchitecture, name: S) -> Option { let name = name.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) @@ -95,7 +95,7 @@ impl TypeLibrary { } /// Attempts to grab a type library associated with the provided Architecture and GUID pair - pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { + pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { let guid = guid.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ref().as_ptr() as *const ffi::c_char) @@ -117,7 +117,7 @@ impl TypeLibrary { } /// Sets the name of a type library instance that has not been finalized - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: S) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) @@ -135,7 +135,7 @@ impl TypeLibrary { } /// Sets the dependency name of a type library instance that has not been finalized - pub fn set_dependency_name(&self, value: S) { + pub fn set_dependency_name(&self, value: S) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryDependencyName( @@ -152,7 +152,7 @@ impl TypeLibrary { } /// Sets the GUID of a type library instance that has not been finalized - pub fn set_guid(&self, value: S) { + pub fn set_guid(&self, value: S) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) @@ -168,7 +168,7 @@ impl TypeLibrary { } /// Adds an extra name to this type library used during library lookups and dependency resolution - pub fn add_alternate_name(&self, value: S) { + pub fn add_alternate_name(&self, value: S) { let value = value.to_cstr(); unsafe { BNAddTypeLibraryAlternateName( @@ -212,7 +212,7 @@ impl TypeLibrary { } /// Retrieves a metadata associated with the given key stored in the type library - pub fn query_metadata(&self, key: S) -> Option { + pub fn query_metadata(&self, key: S) -> Option { let key = key.to_cstr(); let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) @@ -231,7 +231,7 @@ impl TypeLibrary { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { + pub fn store_metadata(&self, key: S, md: &Metadata) { let key = key.to_cstr(); unsafe { BNTypeLibraryStoreMetadata( @@ -243,7 +243,7 @@ impl TypeLibrary { } /// Removes the metadata associated with key from the current type library. - pub fn remove_metadata(&self, key: S) { + pub fn remove_metadata(&self, key: S) { let key = key.to_cstr(); unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) @@ -299,7 +299,7 @@ impl TypeLibrary { /// Use this api with extreme caution. /// /// - pub fn add_type_source(&self, name: QualifiedName, source: S) { + pub fn add_type_source(&self, name: QualifiedName, source: S) { let source = source.to_cstr(); let mut raw_name = QualifiedName::into_raw(name); unsafe { diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index 53827e65d7..e2134b2bb0 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -6,7 +6,7 @@ use std::ptr::NonNull; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_container::TypeContainer; use crate::types::{QualifiedName, QualifiedNameAndType, Type}; @@ -14,7 +14,7 @@ pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity; pub type TypeParserOption = BNTypeParserOption; /// Register a custom parser with the API -pub fn register_type_parser( +pub fn register_type_parser( name: S, parser: T, ) -> (&'static mut T, CoreTypeParser) { @@ -51,7 +51,7 @@ impl CoreTypeParser { unsafe { Array::new(result, count, ()) } } - pub fn parser_by_name(name: S) -> Option { + pub fn parser_by_name(name: S) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetTypeParserByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 278e486a6b..206478a2c9 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -4,7 +4,7 @@ use crate::binary_view::BinaryView; use crate::disassembly::InstructionTextToken; use crate::platform::Platform; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_container::TypeContainer; use crate::types::{NamedTypeReference, QualifiedName, QualifiedNameAndType, Type}; use binaryninjacore_sys::*; @@ -15,7 +15,7 @@ pub type TokenEscapingType = BNTokenEscapingType; pub type TypeDefinitionLineType = BNTypeDefinitionLineType; /// Register a custom parser with the API -pub fn register_type_printer( +pub fn register_type_printer( name: S, parser: T, ) -> (&'static mut T, CoreTypePrinter) { @@ -57,7 +57,7 @@ impl CoreTypePrinter { unsafe { Array::new(result, count, ()) } } - pub fn printer_by_name(name: S) -> Option { + pub fn printer_by_name(name: S) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetTypePrinterByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) diff --git a/rust/src/types.rs b/rust/src/types.rs index 42c1f8d2bd..339729658b 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -24,7 +24,7 @@ use crate::{ binary_view::{BinaryView, BinaryViewExt}, calling_convention::CoreCallingConvention, rc::*, - string::{AsCStr, BnString}, + string::{BnString, IntoCStr}, }; use crate::confidence::{Conf, MAX_CONFIDENCE, MIN_CONFIDENCE}; @@ -258,7 +258,7 @@ impl TypeBuilder { } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { + pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); // let alt_name = BnString::new(alt_name); let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data @@ -281,7 +281,7 @@ impl TypeBuilder { } } - pub fn named_float(width: usize, alt_name: S) -> Self { + pub fn named_float(width: usize, alt_name: S) -> Self { // let alt_name = BnString::new(alt_name); let alt_name = alt_name.to_cstr(); // See same line in `named_int` above @@ -649,7 +649,7 @@ impl Type { } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { + pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); // let alt_name = BnString::new(alt_name); let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data @@ -672,7 +672,7 @@ impl Type { } } - pub fn named_float(width: usize, alt_name: S) -> Ref { + pub fn named_float(width: usize, alt_name: S) -> Ref { // let alt_name = BnString::new(alt_name); let alt_name = alt_name.to_cstr(); // See same line in `named_int` above @@ -1217,7 +1217,7 @@ impl EnumerationBuilder { unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) } } - pub fn append(&mut self, name: S) -> &mut Self { + pub fn append(&mut self, name: S) -> &mut Self { let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _); @@ -1225,7 +1225,7 @@ impl EnumerationBuilder { self } - pub fn insert(&mut self, name: S, value: u64) -> &mut Self { + pub fn insert(&mut self, name: S, value: u64) -> &mut Self { let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value); @@ -1233,7 +1233,7 @@ impl EnumerationBuilder { self } - pub fn replace(&mut self, id: usize, name: S, value: u64) -> &mut Self { + pub fn replace(&mut self, id: usize, name: S, value: u64) -> &mut Self { let name = name.to_cstr(); unsafe { BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value); @@ -1476,7 +1476,7 @@ impl StructureBuilder { self } - pub fn append<'a, S: AsCStr, T: Into>>( + pub fn append<'a, S: IntoCStr, T: Into>>( &mut self, ty: T, name: S, @@ -1513,7 +1513,7 @@ impl StructureBuilder { self } - pub fn insert<'a, S: AsCStr, T: Into>>( + pub fn insert<'a, S: IntoCStr, T: Into>>( &mut self, ty: T, name: S, @@ -1538,7 +1538,7 @@ impl StructureBuilder { self } - pub fn replace<'a, S: AsCStr, T: Into>>( + pub fn replace<'a, S: IntoCStr, T: Into>>( &mut self, index: usize, ty: T, @@ -1870,7 +1870,7 @@ impl NamedTypeReference { /// You should not assign type ids yourself: if you use this to reference a type you are going /// to create but have not yet created, you may run into problems when giving your types to /// a BinaryView. - pub fn new_with_id, S: AsCStr>( + pub fn new_with_id, S: IntoCStr>( type_class: NamedTypeReferenceClass, type_id: S, name: T, diff --git a/rust/src/update.rs b/rust/src/update.rs index be85c93e1c..48d841fb99 100644 --- a/rust/src/update.rs +++ b/rust/src/update.rs @@ -4,7 +4,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner}; -use crate::string::{raw_to_string, AsCStr, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use binaryninjacore_sys::*; pub type UpdateResult = BNUpdateResult; diff --git a/rust/src/websocket/client.rs b/rust/src/websocket/client.rs index 8e2c6db083..aa69c381d3 100644 --- a/rust/src/websocket/client.rs +++ b/rust/src/websocket/client.rs @@ -1,5 +1,5 @@ use crate::rc::{Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void, CStr}; use std::ptr::NonNull; @@ -21,8 +21,8 @@ pub trait WebsocketClient: Sync + Send { fn connect(&self, host: &str, headers: I) -> bool where I: IntoIterator, - K: AsCStr, - V: AsCStr; + K: IntoCStr, + V: IntoCStr; fn write(&self, data: &[u8]) -> bool; @@ -77,8 +77,8 @@ impl CoreWebsocketClient { ) -> bool where I: IntoIterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, C: WebsocketClientCallback, { let url = host.to_cstr(); diff --git a/rust/src/websocket/provider.rs b/rust/src/websocket/provider.rs index 9cc1de8423..40235c2bd1 100644 --- a/rust/src/websocket/provider.rs +++ b/rust/src/websocket/provider.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::websocket::client; use crate::websocket::client::{CoreWebsocketClient, WebsocketClient}; use binaryninjacore_sys::*; @@ -80,7 +80,7 @@ impl CoreWebsocketProvider { unsafe { Array::new(result, count, ()) } } - pub fn by_name(name: S) -> Option { + pub fn by_name(name: S) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetWebsocketProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) diff --git a/rust/src/worker_thread.rs b/rust/src/worker_thread.rs index e0d7b0dbde..8fbfb8efb1 100644 --- a/rust/src/worker_thread.rs +++ b/rust/src/worker_thread.rs @@ -1,4 +1,4 @@ -use crate::string::AsCStr; +use crate::string::IntoCStr; use binaryninjacore_sys::*; use std::ffi::c_void; @@ -17,7 +17,7 @@ impl WorkerThreadActionExecutor { } } -pub fn execute_on_worker_thread(name: S, f: F) { +pub fn execute_on_worker_thread(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); @@ -30,7 +30,7 @@ pub fn execute_on_worker_thread(name: S, f: F) { } } -pub fn execute_on_worker_thread_priority(name: S, f: F) { +pub fn execute_on_worker_thread_priority(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); @@ -43,7 +43,7 @@ pub fn execute_on_worker_thread_priority(name: S, } } -pub fn execute_on_worker_thread_interactive(name: S, f: F) { +pub fn execute_on_worker_thread_interactive(name: S, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 9bbc0b312a..5b908ddd40 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -9,7 +9,7 @@ use crate::low_level_il::function::{LowLevelILFunction, Mutable, NonSSA, NonSSAV use crate::low_level_il::MutableLiftedILFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{AsCStr, BnString}; +use crate::string::{BnString, IntoCStr}; use std::ffi::{c_char, c_void}; use std::ptr::NonNull; @@ -108,7 +108,7 @@ impl AnalysisContext { } } - pub fn inform(&self, request: S) -> bool { + pub fn inform(&self, request: S) -> bool { let request = request.to_cstr(); unsafe { BNAnalysisContextInform(self.handle.as_ptr(), request.as_ptr()) } } @@ -161,7 +161,7 @@ impl Activity { Ref::new(Self { handle }) } - pub fn new(config: S) -> Ref { + pub fn new(config: S) -> Ref { unsafe extern "C" fn cb_action_nop(_: *mut c_void, _: *mut BNAnalysisContext) {} let config = config.to_cstr(); let result = @@ -171,7 +171,7 @@ impl Activity { pub fn new_with_action(config: S, mut action: F) -> Ref where - S: AsCStr, + S: IntoCStr, F: FnMut(&AnalysisContext), { unsafe extern "C" fn cb_action( @@ -240,7 +240,7 @@ impl Workflow { /// Create a new unregistered [Workflow] with no activities. /// /// To get a copy of an existing registered [Workflow] use [Workflow::clone_to]. - pub fn new(name: S) -> Ref { + pub fn new(name: S) -> Ref { let name = name.to_cstr(); let result = unsafe { BNCreateWorkflow(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } @@ -250,7 +250,7 @@ impl Workflow { /// /// * `name` - the name for the new [Workflow] #[must_use] - pub fn clone_to(&self, name: S) -> Ref { + pub fn clone_to(&self, name: S) -> Ref { self.clone_to_with_root(name, "") } @@ -259,7 +259,7 @@ impl Workflow { /// * `name` - the name for the new [Workflow] /// * `root_activity` - perform the clone operation with this activity as the root #[must_use] - pub fn clone_to_with_root( + pub fn clone_to_with_root( &self, name: S, root_activity: A, @@ -278,7 +278,7 @@ impl Workflow { } } - pub fn instance(name: S) -> Ref { + pub fn instance(name: S) -> Ref { let name = name.to_cstr(); let result = unsafe { BNWorkflowInstance(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } @@ -306,7 +306,7 @@ impl Workflow { /// Register this [Workflow], making it immutable and available for use. /// /// * `configuration` - a JSON representation of the workflow configuration - pub fn register_with_config(&self, config: S) -> Result<(), ()> { + pub fn register_with_config(&self, config: S) -> Result<(), ()> { let config = config.to_cstr(); if unsafe { BNRegisterWorkflow(self.handle.as_ptr(), config.as_ptr()) } { Ok(()) @@ -333,7 +333,7 @@ impl Workflow { ) -> Result, ()> where I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let subactivities_raw: Vec<_> = subactivities.into_iter().map(|x| x.to_cstr()).collect(); let mut subactivities_ptr: Vec<*const _> = @@ -351,7 +351,7 @@ impl Workflow { } /// Determine if an Activity exists in this [Workflow]. - pub fn contains(&self, activity: A) -> bool { + pub fn contains(&self, activity: A) -> bool { let activity = activity.to_cstr(); unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.as_ptr()) } } @@ -365,7 +365,7 @@ impl Workflow { /// [Workflow], just for the given `activity`. /// /// `activity` - return the configuration for the `activity` - pub fn configuration_with_activity(&self, activity: A) -> String { + pub fn configuration_with_activity(&self, activity: A) -> String { let activity = activity.to_cstr(); let result = unsafe { BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.as_ptr()) }; assert!(!result.is_null()); @@ -382,7 +382,7 @@ impl Workflow { } /// Retrieve the Activity object for the specified `name`. - pub fn activity(&self, name: A) -> Option> { + pub fn activity(&self, name: A) -> Option> { let name = name.to_cstr(); let result = unsafe { BNWorkflowGetActivity(self.handle.as_ptr(), name.as_ptr()) }; NonNull::new(result).map(|a| unsafe { Activity::ref_from_raw(a) }) @@ -392,7 +392,7 @@ impl Workflow { /// specified just for the given `activity`. /// /// * `activity` - if specified, return the roots for the `activity` - pub fn activity_roots(&self, activity: A) -> Array { + pub fn activity_roots(&self, activity: A) -> Array { let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { @@ -406,7 +406,7 @@ impl Workflow { /// /// * `activity` - if specified, return the direct children and optionally the descendants of the `activity` (includes `activity`) /// * `immediate` - whether to include only direct children of `activity` or all descendants - pub fn subactivities(&self, activity: A, immediate: bool) -> Array { + pub fn subactivities(&self, activity: A, immediate: bool) -> Array { let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { @@ -427,9 +427,9 @@ impl Workflow { /// * `activities` - the list of Activities to assign pub fn assign_subactivities(&self, activity: A, activities: I) -> bool where - A: AsCStr, + A: IntoCStr, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); @@ -455,9 +455,9 @@ impl Workflow { /// * `activities` - the list of Activities to insert pub fn insert(&self, activity: A, activities: I) -> bool where - A: AsCStr, + A: IntoCStr, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); @@ -478,9 +478,9 @@ impl Workflow { /// * `activities` - the list of Activities to insert pub fn insert_after(&self, activity: A, activities: I) -> bool where - A: AsCStr, + A: IntoCStr, I: IntoIterator, - I::Item: AsCStr, + I::Item: IntoCStr, { let activity = activity.to_cstr(); let input_list: Vec<_> = activities.into_iter().map(|a| a.to_cstr()).collect(); @@ -496,7 +496,7 @@ impl Workflow { } /// Remove the specified `activity` - pub fn remove(&self, activity: A) -> bool { + pub fn remove(&self, activity: A) -> bool { let activity = activity.to_cstr(); unsafe { BNWorkflowRemove(self.handle.as_ptr(), activity.as_ptr()) } } @@ -505,7 +505,7 @@ impl Workflow { /// /// * `activity` - the Activity to replace /// * `new_activity` - the replacement Activity - pub fn replace(&self, activity: A, new_activity: N) -> bool { + pub fn replace(&self, activity: A, new_activity: N) -> bool { let activity = activity.to_cstr(); let new_activity = new_activity.to_cstr(); unsafe { @@ -521,7 +521,7 @@ impl Workflow { /// /// * `activity` - if specified, generate the Flowgraph using `activity` as the root /// * `sequential` - whether to generate a **Composite** or **Sequential** style graph - pub fn graph( + pub fn graph( &self, activity: A, sequential: Option, diff --git a/rust/tests/websocket.rs b/rust/tests/websocket.rs index 01d2d79125..c5cf6be4cc 100644 --- a/rust/tests/websocket.rs +++ b/rust/tests/websocket.rs @@ -1,6 +1,6 @@ use binaryninja::headless::Session; use binaryninja::rc::Ref; -use binaryninja::string::AsCStr; +use binaryninja::string::IntoCStr; use binaryninja::websocket::{ register_websocket_provider, CoreWebsocketClient, CoreWebsocketProvider, WebsocketClient, WebsocketClientCallback, WebsocketProvider, @@ -34,8 +34,8 @@ impl WebsocketClient for MyWebsocketClient { fn connect(&self, host: &str, _headers: I) -> bool where I: IntoIterator, - K: AsCStr, - V: AsCStr, + K: IntoCStr, + V: IntoCStr, { assert_eq!(host, "url"); true From 23b6e8ffa6a95bee6c9826531093aaecbcbffdb2 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 16:33:11 -0400 Subject: [PATCH 14/54] [Rust] Add string tests --- rust/tests/string.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 rust/tests/string.rs diff --git a/rust/tests/string.rs b/rust/tests/string.rs new file mode 100644 index 0000000000..4f33394059 --- /dev/null +++ b/rust/tests/string.rs @@ -0,0 +1,51 @@ +use binaryninja::string::{BnString, IntoCStr}; +use std::ffi::{CStr, CString}; + +#[test] +fn test_bnstring() { + // Test a basic ASCII string + let str_0 = BnString::new("test"); + assert_eq!(str_0.to_string_lossy(), "test"); + assert_eq!(str_0.to_bytes_with_nul(), b"test\0"); + + // Test non-UTF8 bytes + let invalid_utf8 = CStr::from_bytes_with_nul(&[0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xFF, 0x00]) + .expect("Failed to create string"); + let str_2 = BnString::new(invalid_utf8); + assert_eq!(str_2.to_string_lossy(), "Hello�"); + assert_eq!( + str_2.to_bytes_with_nul(), + &[0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xFF, 0x00] + ); + + // Test empty string + let str_3 = BnString::new(""); + assert_eq!(str_3.to_string_lossy(), ""); + assert_eq!(str_3.to_bytes_with_nul(), b"\0"); + + // Test string with Unicode + let str_4 = BnString::new("Hello 世界"); + assert_eq!(str_4.to_string_lossy(), "Hello 世界"); + assert_eq!( + str_4.to_bytes_with_nul(), + b"Hello \xE4\xB8\x96\xE7\x95\x8C\0" + ); +} + +#[test] +fn test_cstr() { + let str_0 = BnString::new("test"); + let cstr_0: BnString = str_0.to_cstr(); + assert_eq!(cstr_0.to_str().unwrap(), "test"); + assert_eq!(cstr_0.to_bytes_with_nul(), b"test\0"); + + let str_1 = String::from("test"); + let cstr_1: CString = str_1.to_cstr(); + assert_eq!(cstr_1.to_str().unwrap(), "test"); + assert_eq!(cstr_1.to_bytes_with_nul(), b"test\0"); + + let str_2 = "test"; + let cstr_2: CString = str_2.to_cstr(); + assert_eq!(cstr_2.to_str().unwrap(), "test"); + assert_eq!(cstr_2.to_bytes_with_nul(), b"test\0"); +} From 730a9681165c28b4fb01652e0f3ea025ac61cd42 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 19:22:21 -0400 Subject: [PATCH 15/54] [Rust] Reduce usage of `IntoCStr` in function signatures This is being done to reduce complexity in function signatures, specifically many of the strings we are passing ultimately should be new types themselves instead of "just strings", things such as type ids. Another place which was confusing was dealing with filesystem related APIs, this commit turns most of those params into a stricter `Path` type. This is bringing the rust api more inline with both python and C++, where the wrapper eagerly converts the string into the languages standard string type. Special consideration must be made for symbols or other possible non utf-8 objects. This commit will be followed up with one that adds the `IntoCStr` bound on API's we want to keep as invalid utf-8 so we can for example, get section by name on a section with invalid utf-8. --- .../dwarf/dwarf_import/src/die_handlers.rs | 16 +- .../dwarf/dwarf_import/src/dwarfdebuginfo.rs | 2 +- plugins/dwarf/dwarf_import/src/helpers.rs | 6 +- plugins/dwarf/dwarf_import/src/types.rs | 8 +- plugins/dwarf/shared/src/lib.rs | 7 +- plugins/idb_import/src/lib.rs | 9 +- plugins/idb_import/src/types.rs | 8 +- plugins/pdb-ng/src/lib.rs | 12 +- plugins/pdb-ng/src/parser.rs | 10 +- plugins/pdb-ng/src/struct_grouper.rs | 10 +- plugins/pdb-ng/src/symbol_parser.rs | 4 +- plugins/pdb-ng/src/type_parser.rs | 10 +- plugins/svd/src/mapper.rs | 12 +- plugins/svd/src/settings.rs | 12 +- plugins/warp/src/convert.rs | 6 +- plugins/warp/src/matcher.rs | 14 +- plugins/warp/src/plugin.rs | 2 +- plugins/warp/src/plugin/create.rs | 4 +- plugins/warp/src/plugin/find.rs | 2 +- plugins/warp/src/plugin/types.rs | 4 +- plugins/warp/src/plugin/workflow.rs | 4 +- rust/examples/high_level_il.rs | 2 +- rust/examples/medium_level_il.rs | 2 +- rust/examples/simple.rs | 2 +- rust/examples/type_printer.rs | 2 +- rust/src/architecture.rs | 8 +- rust/src/background_task.rs | 4 +- rust/src/binary_view.rs | 85 ++++---- rust/src/binary_view/memory_map.rs | 24 +-- rust/src/calling_convention.rs | 3 +- rust/src/collaboration.rs | 21 +- rust/src/collaboration/changeset.rs | 2 +- rust/src/collaboration/file.rs | 42 ++-- rust/src/collaboration/folder.rs | 4 +- rust/src/collaboration/group.rs | 7 +- rust/src/collaboration/merge.rs | 8 +- rust/src/collaboration/project.rs | 97 ++++----- rust/src/collaboration/remote.rs | 74 ++----- rust/src/collaboration/snapshot.rs | 4 +- rust/src/collaboration/sync.rs | 64 +++--- rust/src/collaboration/user.rs | 4 +- rust/src/command.rs | 21 +- rust/src/component.rs | 2 +- rust/src/custom_binary_view.rs | 5 +- rust/src/data_buffer.rs | 3 +- rust/src/database.rs | 19 +- rust/src/database/kvs.rs | 6 +- rust/src/database/snapshot.rs | 2 +- rust/src/debuginfo.rs | 57 ++--- rust/src/demangle.rs | 28 ++- rust/src/disassembly.rs | 8 +- rust/src/download_provider.rs | 25 +-- rust/src/enterprise.rs | 16 +- rust/src/external_library.rs | 2 +- rust/src/file_metadata.rs | 46 ++-- rust/src/function.rs | 10 +- rust/src/headless.rs | 2 +- rust/src/high_level_il/operation.rs | 4 +- rust/src/lib.rs | 25 ++- rust/src/medium_level_il/function.rs | 16 +- rust/src/metadata.rs | 6 +- rust/src/platform.rs | 13 +- rust/src/project.rs | 197 +++++++----------- rust/src/project/file.rs | 9 +- rust/src/project/folder.rs | 12 +- rust/src/relocation.rs | 3 +- rust/src/render_layer.rs | 6 +- rust/src/repository.rs | 14 +- rust/src/repository/manager.rs | 7 +- rust/src/repository/plugin.rs | 11 +- rust/src/secrets_provider.rs | 10 +- rust/src/settings.rs | 110 ++++------ rust/src/tags.rs | 12 +- rust/src/type_archive.rs | 139 ++++++------ rust/src/type_container.rs | 35 ++-- rust/src/type_library.rs | 34 +-- rust/src/type_parser.rs | 6 +- rust/src/type_printer.rs | 8 +- rust/src/types.rs | 85 +++----- rust/src/websocket/client.rs | 25 +-- rust/src/websocket/provider.rs | 2 +- rust/src/worker_thread.rs | 6 +- rust/src/workflow.rs | 50 ++--- rust/tests/collaboration.rs | 16 +- rust/tests/debug_info.rs | 2 +- rust/tests/initialization.rs | 2 +- rust/tests/project.rs | 6 +- rust/tests/repository.rs | 4 +- rust/tests/type_container.rs | 2 +- rust/tests/types.rs | 2 +- rust/tests/websocket.rs | 19 +- 91 files changed, 765 insertions(+), 1006 deletions(-) diff --git a/plugins/dwarf/dwarf_import/src/die_handlers.rs b/plugins/dwarf/dwarf_import/src/die_handlers.rs index 52280320a0..f71fdabcf8 100644 --- a/plugins/dwarf/dwarf_import/src/die_handlers.rs +++ b/plugins/dwarf/dwarf_import/src/die_handlers.rs @@ -47,19 +47,19 @@ pub(crate) fn handle_base_type( constants::DW_ATE_address => None, constants::DW_ATE_boolean => Some(Type::bool()), constants::DW_ATE_complex_float => None, - constants::DW_ATE_float => Some(Type::named_float(size, name)), - constants::DW_ATE_signed => Some(Type::named_int(size, true, name)), - constants::DW_ATE_signed_char => Some(Type::named_int(size, true, name)), - constants::DW_ATE_unsigned => Some(Type::named_int(size, false, name)), - constants::DW_ATE_unsigned_char => Some(Type::named_int(size, false, name)), + constants::DW_ATE_float => Some(Type::named_float(size, &name)), + constants::DW_ATE_signed => Some(Type::named_int(size, true, &name)), + constants::DW_ATE_signed_char => Some(Type::named_int(size, true, &name)), + constants::DW_ATE_unsigned => Some(Type::named_int(size, false, &name)), + constants::DW_ATE_unsigned_char => Some(Type::named_int(size, false, &name)), constants::DW_ATE_imaginary_float => None, constants::DW_ATE_packed_decimal => None, constants::DW_ATE_numeric_string => None, constants::DW_ATE_edited => None, constants::DW_ATE_signed_fixed => None, constants::DW_ATE_unsigned_fixed => None, - constants::DW_ATE_decimal_float => Some(Type::named_float(size, name)), - constants::DW_ATE_UTF => Some(Type::named_int(size, false, name)), // TODO : Verify + constants::DW_ATE_decimal_float => Some(Type::named_float(size, &name)), + constants::DW_ATE_UTF => Some(Type::named_int(size, false, &name)), // TODO : Verify constants::DW_ATE_UCS => None, constants::DW_ATE_ASCII => None, // Some sort of array? constants::DW_ATE_lo_user => None, @@ -114,7 +114,7 @@ pub(crate) fn handle_enum( match &child.entry().attr(constants::DW_AT_const_value) { Ok(Some(attr)) => { if let Some(value) = get_attr_as_u64(attr) { - enumeration_builder.insert(name, value); + enumeration_builder.insert(&name, value); } else { // Somehow the child entry is not a const value. log::error!("Unhandled enum member value type for `{}`", name); diff --git a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs index 017ed4befd..1cedbdf22c 100644 --- a/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs +++ b/plugins/dwarf/dwarf_import/src/dwarfdebuginfo.rs @@ -546,7 +546,7 @@ impl DebugInfoBuilder { assert!(debug_info.add_data_variable( address, &self.get_type(*type_uid).unwrap().ty, - name.clone(), + name.as_deref(), &[] // TODO : Components )); } diff --git a/plugins/dwarf/dwarf_import/src/helpers.rs b/plugins/dwarf/dwarf_import/src/helpers.rs index e23eb4988c..f2f6717029 100644 --- a/plugins/dwarf/dwarf_import/src/helpers.rs +++ b/plugins/dwarf/dwarf_import/src/helpers.rs @@ -14,7 +14,7 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; -use std::{collections::HashMap, ops::Deref, str::FromStr, sync::mpsc}; +use std::{ops::Deref, str::FromStr, sync::mpsc}; use crate::{DebugInfoBuilderContext, ReaderType}; use binaryninja::binary_view::BinaryViewBase; @@ -450,8 +450,8 @@ pub(crate) fn download_debug_info( let result = inst .perform_custom_request( "GET", - artifact_url, - HashMap::::new(), + &artifact_url, + vec![], DownloadInstanceInputOutputCallbacks { read: None, write: Some(Box::new(write)), diff --git a/plugins/dwarf/dwarf_import/src/types.rs b/plugins/dwarf/dwarf_import/src/types.rs index 1e9dd146c5..789925104e 100644 --- a/plugins/dwarf/dwarf_import/src/types.rs +++ b/plugins/dwarf/dwarf_import/src/types.rs @@ -215,8 +215,8 @@ fn do_structure_parse( }); structure_builder.insert( - child_type.as_ref(), - child_name, + &child_type, + &child_name, struct_offset, false, MemberAccess::NoAccess, // TODO : Resolve actual scopes, if possible @@ -224,8 +224,8 @@ fn do_structure_parse( ); } else { structure_builder.append( - child_type.as_ref(), - child_name, + &child_type, + &child_name, MemberAccess::NoAccess, MemberScope::NoScope, ); diff --git a/plugins/dwarf/shared/src/lib.rs b/plugins/dwarf/shared/src/lib.rs index c4ed7937e0..7aa3b4863f 100644 --- a/plugins/dwarf/shared/src/lib.rs +++ b/plugins/dwarf/shared/src/lib.rs @@ -179,9 +179,10 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>( } } // Truncate Mach-O section names to 16 bytes - else if let Some(section) = - view.section_by_name("__".to_string() + §ion_name[1..section_name.len().min(15)]) - { + else if let Some(section) = view.section_by_name(&format!( + "__{}", + §ion_name[1..section_name.len().min(15)] + )) { Ok(EndianRcSlice::new( Rc::from(view.read_vec(section.start(), section.len()).as_slice()), endian, diff --git a/plugins/idb_import/src/lib.rs b/plugins/idb_import/src/lib.rs index c554831df9..46acfd42a0 100644 --- a/plugins/idb_import/src/lib.rs +++ b/plugins/idb_import/src/lib.rs @@ -198,7 +198,7 @@ pub fn import_til_section( if let TranslateTypeResult::Translated(bn_ty) | TranslateTypeResult::PartiallyTranslated(bn_ty, _) = &ty.ty { - if !debug_info.add_type(ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) { + if !debug_info.add_type(&ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) { error!("Unable to add type `{}`", ty.name.as_utf8_lossy()) } } @@ -209,7 +209,7 @@ pub fn import_til_section( if let TranslateTypeResult::Translated(bn_ty) | TranslateTypeResult::PartiallyTranslated(bn_ty, _) = &ty.ty { - if !debug_info.add_type(ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) { + if !debug_info.add_type(&ty.name.as_utf8_lossy(), bn_ty, &[/* TODO */]) { error!("Unable to fix type `{}`", ty.name.as_utf8_lossy()) } } @@ -239,10 +239,7 @@ fn parse_id0_section_info( } = info; // TODO set comments to address here for function in &bv.functions_containing(addr) { - function.set_comment_at( - addr, - String::from_utf8_lossy(&comments.join(&b"\n"[..])).to_string(), - ); + function.set_comment_at(addr, &String::from_utf8_lossy(&comments.join(&b"\n"[..]))); } let bnty = ty diff --git a/plugins/idb_import/src/types.rs b/plugins/idb_import/src/types.rs index 7b4ca67540..b3c9bea059 100644 --- a/plugins/idb_import/src/types.rs +++ b/plugins/idb_import/src/types.rs @@ -335,7 +335,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { format!("bitfield_{}_{}", offset + start_idx, offset + (i - 1)) }; let field = field_from_bytes(bytes); - struct_builder.append(&field, name, MemberAccess::NoAccess, MemberScope::NoScope); + struct_builder.append(&field, &name, MemberAccess::NoAccess, MemberScope::NoScope); }; for (i, member) in members { @@ -423,7 +423,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { .as_ref() .map(|name| name.as_utf8_lossy().to_string()) .unwrap_or_else(|| format!("member_{i}")); - structure.append(&mem, name, MemberAccess::NoAccess, MemberScope::NoScope); + structure.append(&mem, &name, MemberAccess::NoAccess, MemberScope::NoScope); } if let Some(start_idx) = first_bitfield_seq { let members_bitrange = &ty_struct.members[start_idx..]; @@ -470,7 +470,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { .as_ref() .map(|name| name.as_utf8_lossy().to_string()) .unwrap_or_else(|| format!("member_{i}")); - structure.append(&mem, name, MemberAccess::NoAccess, MemberScope::NoScope); + structure.append(&mem, &name, MemberAccess::NoAccess, MemberScope::NoScope); } let str_ref = structure.finalize(); @@ -492,7 +492,7 @@ impl Result<(), ()>> TranslateIDBTypes<'_, F> { .as_ref() .map(|name| name.as_utf8_lossy().to_string()) .unwrap_or_else(|| format!("member_{i}")); - eb.insert(name, member.value); + eb.insert(&name, member.value); } Type::enumeration( &eb.finalize(), diff --git a/plugins/pdb-ng/src/lib.rs b/plugins/pdb-ng/src/lib.rs index 188b2ed505..a87a807633 100644 --- a/plugins/pdb-ng/src/lib.rs +++ b/plugins/pdb-ng/src/lib.rs @@ -13,7 +13,6 @@ // limitations under the License. #![allow(dead_code)] -use std::collections::HashMap; use std::env::{current_dir, current_exe, temp_dir}; use std::io::Cursor; use std::path::PathBuf; @@ -31,7 +30,6 @@ use binaryninja::download_provider::{DownloadInstanceInputOutputCallbacks, Downl use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet}; use binaryninja::logger::Logger; use binaryninja::settings::{QueryOptions, Settings}; -use binaryninja::string::BnString; use binaryninja::{interaction, user_directory}; use parser::PDBParserInstance; @@ -196,7 +194,7 @@ fn read_from_sym_store(bv: &BinaryView, path: &str) -> Result<(bool, Vec)> { .perform_custom_request( "GET", path, - HashMap::::new(), + vec![], DownloadInstanceInputOutputCallbacks { read: None, write: Some(Box::new(write)), @@ -278,21 +276,21 @@ fn search_sym_store( } fn parse_pdb_info(view: &BinaryView) -> Option { - match view.get_metadata::("DEBUG_INFO_TYPE") { + match view.get_metadata::("DEBUG_INFO_TYPE") { Some(Ok(0x53445352 /* 'SDSR' */)) => {} _ => return None, } // This is stored in the BV by the PE loader - let file_path = match view.get_metadata::("PDB_FILENAME") { + let file_path = match view.get_metadata::("PDB_FILENAME") { Some(Ok(md)) => md, _ => return None, }; - let mut guid = match view.get_metadata::, _>("PDB_GUID") { + let mut guid = match view.get_metadata::>("PDB_GUID") { Some(Ok(md)) => md, _ => return None, }; - let age = match view.get_metadata::("PDB_AGE") { + let age = match view.get_metadata::("PDB_AGE") { Some(Ok(md)) => md as u32, _ => return None, }; diff --git a/plugins/pdb-ng/src/parser.rs b/plugins/pdb-ng/src/parser.rs index 783a8a2d43..2ca8e209ec 100644 --- a/plugins/pdb-ng/src/parser.rs +++ b/plugins/pdb-ng/src/parser.rs @@ -168,7 +168,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { ) -> Result<()> { self.parse_types(Self::split_progress(&progress, 0, &[1.0, 3.0, 0.5, 0.5]))?; for (name, ty) in self.named_types.iter() { - self.debug_info.add_type(name, ty.as_ref(), &[]); // TODO : Components + self.debug_info + .add_type(&name.to_string(), ty.as_ref(), &[]); // TODO : Components } info!( @@ -406,7 +407,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { match class { NamedTypeReferenceClass::UnknownNamedTypeClass | NamedTypeReferenceClass::TypedefNamedTypeClass => { - self.debug_info.add_type(&name, Type::void().as_ref(), &[]); + self.debug_info + .add_type(&name.to_string(), Type::void().as_ref(), &[]); // TODO : Components } NamedTypeReferenceClass::ClassNamedTypeClass @@ -429,7 +431,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { structure.alignment(1); self.debug_info.add_type( - &name, + &name.to_string(), Type::structure(structure.finalize().as_ref()).as_ref(), &[], // TODO : Components ); @@ -437,7 +439,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { NamedTypeReferenceClass::EnumNamedTypeClass => { let enumeration = EnumerationBuilder::new(); self.debug_info.add_type( - &name, + &name.to_string(), Type::enumeration( enumeration.finalize().as_ref(), self.arch.default_integer_size().try_into()?, diff --git a/plugins/pdb-ng/src/struct_grouper.rs b/plugins/pdb-ng/src/struct_grouper.rs index 09a81fa7e1..ff911afdd6 100644 --- a/plugins/pdb-ng/src/struct_grouper.rs +++ b/plugins/pdb-ng/src/struct_grouper.rs @@ -361,7 +361,7 @@ pub fn group_structure( for member in members { structure.insert( &member.ty, - member.name.clone(), + &member.name, member.offset, false, member.access, @@ -390,7 +390,7 @@ fn apply_groups( if offset > member.offset { structure.insert( &member.ty, - member.name.clone(), + &member.name, 0, false, member.access, @@ -399,7 +399,7 @@ fn apply_groups( } else { structure.insert( &member.ty, - member.name.clone(), + &member.name, member.offset - offset, false, member.access, @@ -412,7 +412,7 @@ fn apply_groups( apply_groups(members, &mut inner, children, inner_offset); structure.insert( &Conf::new(Type::structure(inner.finalize().as_ref()), MAX_CONFIDENCE), - format!("__inner{}", i), + &format!("__inner{}", i), inner_offset - offset, false, MemberAccess::PublicAccess, @@ -425,7 +425,7 @@ fn apply_groups( apply_groups(members, &mut inner, children, inner_offset); structure.insert( &Conf::new(Type::structure(inner.finalize().as_ref()), MAX_CONFIDENCE), - format!("__inner{}", i), + &format!("__inner{}", i), inner_offset - offset, false, MemberAccess::PublicAccess, diff --git a/plugins/pdb-ng/src/symbol_parser.rs b/plugins/pdb-ng/src/symbol_parser.rs index 6d6e978e57..79049d0399 100644 --- a/plugins/pdb-ng/src/symbol_parser.rs +++ b/plugins/pdb-ng/src/symbol_parser.rs @@ -2027,13 +2027,13 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { Some(X86(xreg)) => { self.log(|| format!("Register {:?} ==> {:?}", reg, xreg)); self.arch - .register_by_name(xreg.to_string().to_lowercase()) + .register_by_name(&xreg.to_string().to_lowercase()) .map(|reg| reg.id()) } Some(AMD64(areg)) => { self.log(|| format!("Register {:?} ==> {:?}", reg, areg)); self.arch - .register_by_name(areg.to_string().to_lowercase()) + .register_by_name(&areg.to_string().to_lowercase()) .map(|reg| reg.id()) } // TODO: Other arches diff --git a/plugins/pdb-ng/src/type_parser.rs b/plugins/pdb-ng/src/type_parser.rs index 61c6421835..d4d5feb41a 100644 --- a/plugins/pdb-ng/src/type_parser.rs +++ b/plugins/pdb-ng/src/type_parser.rs @@ -898,7 +898,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { bitfield_builder .as_mut() .expect("Invariant") - .insert(&m.ty, m.name, 0, false, m.access, m.scope); + .insert(&m.ty, &m.name, 0, false, m.access, m.scope); } (None, None) => { if let Some(mut builder) = bitfield_builder.take() { @@ -1633,7 +1633,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { for field in fields { match field { ParsedType::Enumerate(member) => { - enumeration.insert(member.name.clone(), member.value); + enumeration.insert(&member.name, member.value); } e => return Err(anyhow!("Unexpected enumerate member: {:?}", e)), } @@ -1803,7 +1803,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { if group.len() == 1 { structure.insert( &group[0].ty, - group[0].name.clone(), + &group[0].name, group[0].offset, false, group[0].access, @@ -1814,7 +1814,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { for member in group { inner_struct.insert( &member.ty, - member.name.clone(), + &member.name, member.offset, false, member.access, @@ -1826,7 +1826,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> { Type::structure(inner_struct.finalize().as_ref()), MAX_CONFIDENCE, ), - format!("__inner{:x}", i), + &format!("__inner{:x}", i), 0, false, MemberAccess::PublicAccess, diff --git a/plugins/svd/src/mapper.rs b/plugins/svd/src/mapper.rs index 2d51161542..314fba7660 100644 --- a/plugins/svd/src/mapper.rs +++ b/plugins/svd/src/mapper.rs @@ -205,7 +205,7 @@ impl DeviceMapper { let peripheral_ty_id = format!("SVD:{}", peripheral.name); let id = view.define_auto_type_with_id( &peripheral.name, - peripheral_ty_id, + &peripheral_ty_id, &peripheral_ty, ); let ntr = @@ -224,14 +224,14 @@ impl DeviceMapper { view.define_auto_symbol(&symbol); view.set_comment_at( block_addr, - format!("Buffer block with size {}", address_block.size), + &format!("Buffer block with size {}", address_block.size), ); } AddressBlockUsage::Reserved => { // TODO: What to do for reserved blocks? view.set_comment_at( block_addr, - format!("Reserved block with size {}", address_block.size), + &format!("Reserved block with size {}", address_block.size), ); } } @@ -286,11 +286,11 @@ impl DeviceMapper { for (field_addr, comments) in unaligned_comments { let comment = comments.join("\n"); - view.set_comment_at(field_addr, comment); + view.set_comment_at(field_addr, &comment); } } } - view.file().commit_undo_actions(undo_id); + view.file().commit_undo_actions(&undo_id); } pub fn peripheral_block_memory_info( @@ -662,7 +662,7 @@ impl DeviceMapper { current_value = enumerated_value.value.unwrap_or(current_value + 1); // TODO: The Rust API needs to expose this... let _is_default = enumerated_value.is_default.unwrap_or(false); - enum_builder.insert(enumerated_value.name.to_owned(), current_value); + enum_builder.insert(&enumerated_value.name, current_value); } let enum_width = NonZeroUsize::new(byte_aligned_width as usize).unwrap(); diff --git a/plugins/svd/src/settings.rs b/plugins/svd/src/settings.rs index 9621da6415..fb2f680c96 100644 --- a/plugins/svd/src/settings.rs +++ b/plugins/svd/src/settings.rs @@ -32,7 +32,7 @@ impl LoadSettings { }); bn_settings.register_setting_json( Self::ADD_BACKING_REGIONS_SETTING, - add_backing_region_props.to_string(), + &add_backing_region_props.to_string(), ); let add_bitfields_props = json!({ @@ -41,8 +41,10 @@ impl LoadSettings { "default" : Self::ADD_BITFIELDS_DEFAULT, "description" : "Whether to add bitfields. Bitfields are not supported by Binary Ninja, so this is a workaround using unions.", }); - bn_settings - .register_setting_json(Self::ADD_BITFIELDS_SETTING, add_bitfields_props.to_string()); + bn_settings.register_setting_json( + Self::ADD_BITFIELDS_SETTING, + &add_bitfields_props.to_string(), + ); let add_comments_props = json!({ "title" : "Add Comments", @@ -51,7 +53,7 @@ impl LoadSettings { "description" : "Whether to add comments. If you see comment placement is off, try disabling this.", }); bn_settings - .register_setting_json(Self::ADD_COMMENTS_SETTING, add_comments_props.to_string()); + .register_setting_json(Self::ADD_COMMENTS_SETTING, &add_comments_props.to_string()); let file_props = json!({ "title" : "SVD File", @@ -60,7 +62,7 @@ impl LoadSettings { "description" : "The SVD File to automatically load when opening the view.", "uiSelectionAction" : "file" }); - bn_settings.register_setting_json(Self::AUTO_LOAD_FILE_SETTING, file_props.to_string()); + bn_settings.register_setting_json(Self::AUTO_LOAD_FILE_SETTING, &file_props.to_string()); } pub fn from_view_settings(view: &BinaryView) -> Self { diff --git a/plugins/warp/src/convert.rs b/plugins/warp/src/convert.rs index 2e0fb3f101..b6c2f7b4e4 100644 --- a/plugins/warp/src/convert.rs +++ b/plugins/warp/src/convert.rs @@ -431,7 +431,7 @@ pub fn to_bn_type(arch: &A, ty: &Type) -> BNRef { let base_struct_ntr = match c.guid { Some(guid) => BNNamedTypeReference::new_with_id( NamedTypeReferenceClass::UnknownNamedTypeClass, - guid.to_string(), + &guid.to_string(), base_struct_ntr_name, ), None => BNNamedTypeReference::new( @@ -475,7 +475,7 @@ pub fn to_bn_type(arch: &A, ty: &Type) -> BNRef { // TODO: Add default name? let member_name = member.name.to_owned().unwrap_or("enum_VAL".into()); let member_value = member.constant; - builder.insert(member_name, member_value); + builder.insert(&member_name, member_value); } // TODO: Warn if enumeration has no size. let width = bits_to_bytes(c.member_type.size().unwrap()) as usize; @@ -545,7 +545,7 @@ pub fn to_bn_type(arch: &A, ty: &Type) -> BNRef { let ntr_name = c.name.to_owned().unwrap_or(guid_str.clone()); NamedTypeReference::new_with_id( NamedTypeReferenceClass::UnknownNamedTypeClass, - guid_str, + &guid_str, ntr_name, ) } diff --git a/plugins/warp/src/matcher.rs b/plugins/warp/src/matcher.rs index 6352cd7ae8..0ce258ade6 100644 --- a/plugins/warp/src/matcher.rs +++ b/plugins/warp/src/matcher.rs @@ -159,7 +159,7 @@ impl Matcher { if let Some(ref_guid) = c.guid { // NOTE: We do not need to check for cyclic reference here because // NOTE: GUID references are unable to be referenced by themselves. - if view.type_by_id(ref_guid.to_string()).is_none() { + if view.type_by_id(&ref_guid.to_string()).is_none() { // Add the referrer to the view if it is in the Matcher types if let Some(ref_ty) = matcher.types.get(&ref_guid) { inner_add_type_to_view(matcher, view, arch, visited_refs, &ref_ty); @@ -186,7 +186,7 @@ impl Matcher { // All nested types _should_ be added now, we can add this type. // TODO: Do we want to make unnamed types visible? I think we should, but some people might be opposed. let ty_name = ty.name.to_owned().unwrap_or_else(|| ty_id_str.clone()); - view.define_auto_type_with_id(ty_name, ty_id_str, &to_bn_type(arch, ty)); + view.define_auto_type_with_id(ty_name, &ty_id_str, &to_bn_type(arch, ty)); } _ => {} } @@ -409,7 +409,7 @@ impl MatcherSettings { }); bn_settings.register_setting_json( Self::TRIVIAL_FUNCTION_LEN_SETTING, - trivial_function_len_props.to_string(), + &trivial_function_len_props.to_string(), ); let minimum_function_len_props = json!({ @@ -421,7 +421,7 @@ impl MatcherSettings { }); bn_settings.register_setting_json( Self::MINIMUM_FUNCTION_LEN_SETTING, - minimum_function_len_props.to_string(), + &minimum_function_len_props.to_string(), ); let maximum_function_len_props = json!({ @@ -433,7 +433,7 @@ impl MatcherSettings { }); bn_settings.register_setting_json( Self::MAXIMUM_FUNCTION_LEN_SETTING, - maximum_function_len_props.to_string(), + &maximum_function_len_props.to_string(), ); let minimum_matched_constraints_props = json!({ @@ -445,7 +445,7 @@ impl MatcherSettings { }); bn_settings.register_setting_json( Self::MINIMUM_MATCHED_CONSTRAINTS_SETTING, - minimum_matched_constraints_props.to_string(), + &minimum_matched_constraints_props.to_string(), ); let trivial_function_adjacent_allowed_props = json!({ @@ -457,7 +457,7 @@ impl MatcherSettings { }); bn_settings.register_setting_json( Self::TRIVIAL_FUNCTION_ADJACENT_ALLOWED_SETTING, - trivial_function_adjacent_allowed_props.to_string(), + &trivial_function_adjacent_allowed_props.to_string(), ); } diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs index b84173f79c..ec903f9cb5 100644 --- a/plugins/warp/src/plugin.rs +++ b/plugins/warp/src/plugin.rs @@ -52,7 +52,7 @@ pub fn on_matched_function(function: &Function, matched: &WarpFunction) { // TODO: Add metadata. (both binja metadata and warp metadata) function.add_tag( &get_warp_tag_type(&view), - matched.guid.to_string(), + &matched.guid.to_string(), None, true, None, diff --git a/plugins/warp/src/plugin/create.rs b/plugins/warp/src/plugin/create.rs index e84e42ad3e..1dd83e6ea6 100644 --- a/plugins/warp/src/plugin/create.rs +++ b/plugins/warp/src/plugin/create.rs @@ -31,7 +31,7 @@ impl Command for CreateSignatureFile { let total_functions = view.functions().len(); let done_functions = AtomicUsize::default(); let background_task = binaryninja::background_task::BackgroundTask::new( - format!("Generating signatures... ({}/{})", 0, total_functions), + &format!("Generating signatures... ({}/{})", 0, total_functions), true, ); @@ -43,7 +43,7 @@ impl Command for CreateSignatureFile { .par_iter() .inspect(|_| { done_functions.fetch_add(1, Relaxed); - background_task.set_progress_text(format!( + background_task.set_progress_text(&format!( "Generating signatures... ({}/{})", done_functions.load(Relaxed), total_functions diff --git a/plugins/warp/src/plugin/find.rs b/plugins/warp/src/plugin/find.rs index b2102e5e21..accc015d6e 100644 --- a/plugins/warp/src/plugin/find.rs +++ b/plugins/warp/src/plugin/find.rs @@ -27,7 +27,7 @@ impl Command for FindFunctionFromGUID { let funcs = view.functions(); thread::spawn(move || { let background_task = binaryninja::background_task::BackgroundTask::new( - format!("Searching functions for GUID... {}", searched_guid), + &format!("Searching functions for GUID... {}", searched_guid), false, ); diff --git a/plugins/warp/src/plugin/types.rs b/plugins/warp/src/plugin/types.rs index 057d5f98c4..41e03cd34c 100644 --- a/plugins/warp/src/plugin/types.rs +++ b/plugins/warp/src/plugin/types.rs @@ -35,7 +35,7 @@ impl Command for LoadTypes { let view = view.to_owned(); std::thread::spawn(move || { let background_task = binaryninja::background_task::BackgroundTask::new( - format!("Applying {} types...", data.types.len()), + &format!("Applying {} types...", data.types.len()), true, ); @@ -43,7 +43,7 @@ impl Command for LoadTypes { for comp_ty in data.types { let ty_id = comp_ty.guid.to_string(); let ty_name = comp_ty.ty.name.to_owned().unwrap_or_else(|| ty_id.clone()); - view.define_auto_type_with_id(ty_name, ty_id, &to_bn_type(&arch, &comp_ty.ty)); + view.define_auto_type_with_id(ty_name, &ty_id, &to_bn_type(&arch, &comp_ty.ty)); } log::info!("Type application took {:?}", start.elapsed()); diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs index 5a857fbb45..9f7c4d0d4f 100644 --- a/plugins/warp/src/plugin/workflow.rs +++ b/plugins/warp/src/plugin/workflow.rs @@ -44,7 +44,7 @@ impl Command for RunMatcher { .for_each(|function| cached_function_matcher(&function)); log::info!("Function matching took {:?}", start.elapsed()); background_task.finish(); - view.file().commit_undo_actions(undo_id); + view.file().commit_undo_actions(&undo_id); // Now we want to trigger re-analysis. view.update_analysis(); }); @@ -66,7 +66,7 @@ pub fn insert_workflow() { .for_each(|function| cached_function_matcher(&function)); log::info!("Function matching took {:?}", start.elapsed()); background_task.finish(); - view.file().commit_undo_actions(undo_id); + view.file().commit_undo_actions(&undo_id); // Now we want to trigger re-analysis. view.update_analysis(); }; diff --git a/rust/examples/high_level_il.rs b/rust/examples/high_level_il.rs index d57509da47..ddc8f08d1b 100644 --- a/rust/examples/high_level_il.rs +++ b/rust/examples/high_level_il.rs @@ -16,7 +16,7 @@ fn main() { println!("Function count: {}", bv.functions().len()); for func in &bv.functions() { - println!("{}:", func.symbol().full_name()); + println!("{:?}:", func.symbol().full_name()); let Ok(il) = func.high_level_il(true) else { continue; diff --git a/rust/examples/medium_level_il.rs b/rust/examples/medium_level_il.rs index 61c3a33041..543a085629 100644 --- a/rust/examples/medium_level_il.rs +++ b/rust/examples/medium_level_il.rs @@ -16,7 +16,7 @@ fn main() { println!("Function count: {}", bv.functions().len()); for func in &bv.functions() { - println!("{}:", func.symbol().full_name()); + println!("{:?}:", func.symbol().full_name()); let Ok(il) = func.medium_level_il() else { continue; diff --git a/rust/examples/simple.rs b/rust/examples/simple.rs index f41cbf344f..c6065d48ef 100644 --- a/rust/examples/simple.rs +++ b/rust/examples/simple.rs @@ -17,7 +17,7 @@ fn main() { println!("Function count: {}", bv.functions().len()); for func in &bv.functions() { - println!("{}:", func.symbol().full_name()); + println!("{:?}:", func.symbol().full_name()); for basic_block in &func.basic_blocks() { // TODO : This is intended to be refactored to be more nice to work with soon(TM) for addr in basic_block.as_ref() { diff --git a/rust/examples/type_printer.rs b/rust/examples/type_printer.rs index ea9c6a4db1..846e1a0908 100644 --- a/rust/examples/type_printer.rs +++ b/rust/examples/type_printer.rs @@ -35,5 +35,5 @@ fn main() { TokenEscapingType::NoTokenEscapingType, ); - println!("{}", printed_types.unwrap()); + println!("{:?}", printed_types.unwrap()); } diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index c02fc717bc..a48cbce36a 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -1953,7 +1953,7 @@ macro_rules! cc_func { /// Contains helper methods for all types implementing 'Architecture' pub trait ArchitectureExt: Architecture { - fn register_by_name(&self, name: S) -> Option { + fn register_by_name(&self, name: &str) -> Option { let name = name.to_cstr(); match unsafe { BNGetArchitectureRegisterByName(self.as_ref().handle, name.as_ptr()) } { @@ -2029,9 +2029,8 @@ pub trait ArchitectureExt: Architecture { } } - fn register_relocation_handler(&self, name: S, func: F) + fn register_relocation_handler(&self, name: &str, func: F) where - S: IntoCStr, R: 'static + RelocationHandler> + Send @@ -2052,9 +2051,8 @@ pub trait ArchitectureExt: Architecture { impl ArchitectureExt for T {} -pub fn register_architecture(name: S, func: F) -> &'static A +pub fn register_architecture(name: &str, func: F) -> &'static A where - S: IntoCStr, A: 'static + Architecture> + Send + Sync + Sized, F: FnOnce(CustomArchitectureHandle, CoreArchitecture) -> A, { diff --git a/rust/src/background_task.rs b/rust/src/background_task.rs index b0537fa815..ea1e3b0db2 100644 --- a/rust/src/background_task.rs +++ b/rust/src/background_task.rs @@ -43,7 +43,7 @@ impl BackgroundTask { Self { handle } } - pub fn new(initial_text: S, can_cancel: bool) -> Ref { + pub fn new(initial_text: &str, can_cancel: bool) -> Ref { let text = initial_text.to_cstr(); let handle = unsafe { BNBeginBackgroundTask(text.as_ptr(), can_cancel) }; // We should always be returned a valid task. @@ -75,7 +75,7 @@ impl BackgroundTask { unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) } } - pub fn set_progress_text(&self, text: S) { + pub fn set_progress_text(&self, text: &str) { let progress_text = text.to_cstr(); unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ptr()) } } diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 7259efbf1c..35383f0b44 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -266,7 +266,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNGetEndOffset(self.as_ref().handle) } } - fn add_analysis_option(&self, name: impl IntoCStr) { + fn add_analysis_option(&self, name: &str) { let name = name.to_cstr(); unsafe { BNAddAnalysisOption(self.as_ref().handle, name.as_ptr()) } } @@ -399,7 +399,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbol_by_raw_name(&self, raw_name: S) -> Option> { + fn symbol_by_raw_name(&self, raw_name: impl IntoCStr) -> Option> { let raw_name = raw_name.to_cstr(); unsafe { @@ -424,7 +424,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn symbols_by_name(&self, name: S) -> Array { + fn symbols_by_name(&self, name: impl IntoCStr) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -585,10 +585,10 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn define_auto_type, S: IntoCStr>( + fn define_auto_type>( &self, name: T, - source: S, + source: &str, type_obj: &Type, ) -> QualifiedName { let mut raw_name = QualifiedName::into_raw(name.into()); @@ -602,10 +602,10 @@ pub trait BinaryViewExt: BinaryViewBase { QualifiedName::from_owned_raw(name_handle) } - fn define_auto_type_with_id, S: IntoCStr>( + fn define_auto_type_with_id>( &self, name: T, - id: S, + id: &str, type_obj: &Type, ) -> QualifiedName { let mut raw_name = QualifiedName::into_raw(name.into()); @@ -712,7 +712,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn undefine_auto_type(&self, id: S) { + fn undefine_auto_type(&self, id: &str) { let id_str = id.to_cstr(); unsafe { BNUndefineAnalysisType(self.as_ref().handle, id_str.as_ref().as_ptr() as *const _); @@ -763,7 +763,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_by_id(&self, id: S) -> Option> { + fn type_by_id(&self, id: &str) -> Option> { let id_str = id.to_cstr(); unsafe { let type_handle = BNGetAnalysisTypeById(self.as_ref().handle, id_str.as_ptr()); @@ -774,7 +774,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_name_by_id(&self, id: S) -> Option { + fn type_name_by_id(&self, id: &str) -> Option { let id_str = id.to_cstr(); unsafe { let name_handle = BNGetAnalysisTypeNameById(self.as_ref().handle, id_str.as_ptr()); @@ -787,12 +787,12 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn type_id_by_name>(&self, name: T) -> Option { + fn type_id_by_name>(&self, name: T) -> Option { let mut raw_name = QualifiedName::into_raw(name.into()); unsafe { let id_cstr = BNGetAnalysisTypeId(self.as_ref().handle, &mut raw_name); QualifiedName::free_raw(raw_name); - let id = BnString::from_raw(id_cstr); + let id = BnString::into_string(id_cstr); match id.is_empty() { true => None, false => Some(id), @@ -871,7 +871,7 @@ pub trait BinaryViewExt: BinaryViewBase { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: S) { + fn remove_auto_section(&self, name: &str) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -879,7 +879,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn remove_user_section(&self, name: S) { + fn remove_user_section(&self, name: &str) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -887,7 +887,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn section_by_name(&self, name: S) -> Option> { + fn section_by_name(&self, name: &str) -> Option> { unsafe { let raw_name = name.to_cstr(); let name_ptr = raw_name.as_ptr(); @@ -1103,14 +1103,14 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } } - fn show_graph_report(&self, raw_name: S, graph: &FlowGraph) { + fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) { let raw_name = raw_name.to_cstr(); unsafe { BNShowGraphReport(self.as_ref().handle, raw_name.as_ptr(), graph.handle); } } - fn load_settings(&self, view_type_name: S) -> Result> { + fn load_settings(&self, view_type_name: &str) -> Result> { let view_type_name = view_type_name.to_cstr(); let settings_handle = unsafe { BNBinaryViewGetLoadSettings(self.as_ref().handle, view_type_name.as_ptr()) }; @@ -1122,7 +1122,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn set_load_settings(&self, view_type_name: S, settings: &Settings) { + fn set_load_settings(&self, view_type_name: &str, settings: &Settings) { let view_type_name = view_type_name.to_cstr(); unsafe { @@ -1139,7 +1139,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// # Arguments /// * `name` - the name for the tag /// * `icon` - the icon (recommended 1 emoji or 2 chars) for the tag - fn create_tag_type(&self, name: N, icon: I) -> Ref { + fn create_tag_type(&self, name: &str, icon: &str) -> Ref { let tag_type = TagType::create(self.as_ref(), name, icon); unsafe { BNAddTagType(self.as_ref().handle, tag_type.handle); @@ -1153,7 +1153,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Get a tag type by its name. - fn tag_type_by_name(&self, name: S) -> Option> { + fn tag_type_by_name(&self, name: &str) -> Option> { let name = name.to_cstr(); unsafe { let handle = BNGetTagType(self.as_ref().handle, name.as_ptr()); @@ -1167,7 +1167,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Get a tag by its id. /// /// Note this does not tell you anything about where it is used. - fn tag_by_id(&self, id: S) -> Option> { + fn tag_by_id(&self, id: &str) -> Option> { let id = id.to_cstr(); unsafe { let handle = BNGetTag(self.as_ref().handle, id.as_ptr()); @@ -1181,7 +1181,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// Creates and adds a tag to an address /// /// User tag creations will be added to the undo buffer - fn add_tag(&self, addr: u64, t: &TagType, data: S, user: bool) { + fn add_tag(&self, addr: u64, t: &TagType, data: &str, user: bool) { let tag = Tag::new(t, data); unsafe { BNAddTag(self.as_ref().handle, tag.handle, user) } @@ -1204,11 +1204,11 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNRemoveUserDataTag(self.as_ref().handle, addr, tag.handle) } } - fn comment_at(&self, addr: u64) -> Option { + fn comment_at(&self, addr: u64) -> Option { unsafe { let comment_raw = BNGetGlobalCommentForAddress(self.as_ref().handle, addr); match comment_raw.is_null() { - false => Some(BnString::from_raw(comment_raw)), + false => Some(BnString::into_string(comment_raw)), true => None, } } @@ -1218,7 +1218,7 @@ pub trait BinaryViewExt: BinaryViewBase { /// /// NOTE: This is different from setting a comment at the function-level. To set a comment in a /// function use [`Function::set_comment_at`] - fn set_comment_at(&self, addr: u64, comment: impl IntoCStr) { + fn set_comment_at(&self, addr: u64, comment: &str) { let comment_raw = comment.to_cstr(); unsafe { BNSetGlobalCommentForAddress(self.as_ref().handle, addr, comment_raw.as_ptr()) } } @@ -1271,7 +1271,7 @@ pub trait BinaryViewExt: BinaryViewBase { result } - fn query_metadata(&self, key: S) -> Option> { + fn query_metadata(&self, key: &str) -> Option> { let key = key.to_cstr(); let value: *mut BNMetadata = unsafe { BNBinaryViewQueryMetadata(self.as_ref().handle, key.as_ptr()) }; @@ -1282,7 +1282,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn get_metadata(&self, key: S) -> Option> + fn get_metadata(&self, key: &str) -> Option> where T: for<'a> TryFrom<&'a Metadata>, { @@ -1290,7 +1290,7 @@ pub trait BinaryViewExt: BinaryViewBase { .map(|md| T::try_from(md.as_ref()).map_err(|_| ())) } - fn store_metadata(&self, key: S, value: V, is_auto: bool) + fn store_metadata(&self, key: &str, value: V, is_auto: bool) where V: Into>, { @@ -1306,7 +1306,7 @@ pub trait BinaryViewExt: BinaryViewBase { }; } - fn remove_metadata(&self, key: S) { + fn remove_metadata(&self, key: &str) { let key = key.to_cstr(); unsafe { BNBinaryViewRemoveMetadata(self.as_ref().handle, key.as_ptr()) }; } @@ -1432,7 +1432,7 @@ pub trait BinaryViewExt: BinaryViewBase { .collect() } - fn component_by_guid(&self, guid: S) -> Option> { + fn component_by_guid(&self, guid: &str) -> Option> { let name = guid.to_cstr(); let result = unsafe { BNGetComponentByGuid(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) @@ -1443,7 +1443,7 @@ pub trait BinaryViewExt: BinaryViewBase { NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) } - fn component_by_path(&self, path: P) -> Option> { + fn component_by_path(&self, path: &str) -> Option> { let path = path.to_cstr(); let result = unsafe { BNGetComponentByPath(self.as_ref().handle, path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Component::ref_from_raw(h) }) @@ -1453,7 +1453,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNRemoveComponent(self.as_ref().handle, component.handle.as_ptr()) } } - fn remove_component_by_guid(&self, guid: P) -> bool { + fn remove_component_by_guid(&self, guid: &str) -> bool { let path = guid.to_cstr(); unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } } @@ -1476,7 +1476,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { Array::new(result, count, ()) } } - fn external_library(&self, name: S) -> Option> { + fn external_library(&self, name: &str) -> Option> { let name_ptr = name.to_cstr(); let result = unsafe { BNBinaryViewGetExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; @@ -1484,14 +1484,14 @@ pub trait BinaryViewExt: BinaryViewBase { Some(unsafe { ExternalLibrary::ref_from_raw(result_ptr) }) } - fn remove_external_library(&self, name: S) { + fn remove_external_library(&self, name: &str) { let name_ptr = name.to_cstr(); unsafe { BNBinaryViewRemoveExternalLibrary(self.as_ref().handle, name_ptr.as_ptr()) }; } - fn add_external_library( + fn add_external_library( &self, - name: S, + name: &str, backing_file: Option<&ProjectFile>, auto: bool, ) -> Option> { @@ -1531,11 +1531,11 @@ pub trait BinaryViewExt: BinaryViewBase { } // TODO: This is awful, rewrite this. - fn add_external_location( + fn add_external_location( &self, symbol: &Symbol, library: &ExternalLibrary, - target_symbol_name: S, + target_symbol_name: &str, target_address: Option, target_is_auto: bool, ) -> Option> { @@ -1589,7 +1589,7 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } } - fn type_library_by_name(&self, name: S) -> Option { + fn type_library_by_name(&self, name: &str) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) }) @@ -1677,12 +1677,7 @@ pub trait BinaryViewExt: BinaryViewBase { } /// Recursively imports a type interface given its GUID. - /// - /// .. note:: To support this type of lookup a type library must have - /// contain a metadata key called "type_guids" which is a map - /// Dict[string_guid, string_type_name] or - /// Dict[string_guid, Tuple[string_type_name, type_library_name]] - fn import_type_by_guid(&self, guid: S) -> Option> { + fn import_type_by_guid(&self, guid: &str) -> Option> { let guid = guid.to_cstr(); let result = unsafe { BNBinaryViewImportTypeLibraryTypeByGuid(self.as_ref().handle, guid.as_ptr()) }; diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index ad7c8ea1e3..28b5236976 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -42,7 +42,7 @@ impl MemoryMap { pub fn add_binary_memory_region( &mut self, - name: impl IntoCStr, + name: &str, start: u64, view: &BinaryView, segment_flags: Option, @@ -61,7 +61,7 @@ impl MemoryMap { pub fn add_data_memory_region( &mut self, - name: impl IntoCStr, + name: &str, start: u64, data: &DataBuffer, segment_flags: Option, @@ -80,7 +80,7 @@ impl MemoryMap { pub fn add_remote_memory_region( &mut self, - name: impl IntoCStr, + name: &str, start: u64, accessor: &mut FileAccessor, segment_flags: Option, @@ -97,7 +97,7 @@ impl MemoryMap { } } - pub fn remove_memory_region(&mut self, name: impl IntoCStr) -> bool { + pub fn remove_memory_region(&mut self, name: &str) -> bool { let name_raw = name.to_cstr(); unsafe { BNRemoveMemoryRegion(self.view.handle, name_raw.as_ptr()) } } @@ -109,44 +109,44 @@ impl MemoryMap { } } - pub fn memory_region_flags(&self, name: impl IntoCStr) -> SegmentFlags { + pub fn memory_region_flags(&self, name: &str) -> SegmentFlags { let name_raw = name.to_cstr(); let flags_raw = unsafe { BNGetMemoryRegionFlags(self.view.handle, name_raw.as_ptr()) }; SegmentFlags::from_raw(flags_raw) } - pub fn set_memory_region_flags(&mut self, name: impl IntoCStr, flags: SegmentFlags) -> bool { + pub fn set_memory_region_flags(&mut self, name: &str, flags: SegmentFlags) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFlags(self.view.handle, name_raw.as_ptr(), flags.into_raw()) } } - pub fn is_memory_region_enabled(&self, name: impl IntoCStr) -> bool { + pub fn is_memory_region_enabled(&self, name: &str) -> bool { let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionEnabled(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_enabled(&mut self, name: impl IntoCStr, enabled: bool) -> bool { + pub fn set_memory_region_enabled(&mut self, name: &str, enabled: bool) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionEnabled(self.view.handle, name_raw.as_ptr(), enabled) } } // TODO: Should we just call this is_memory_region_relocatable? - pub fn is_memory_region_rebaseable(&self, name: impl IntoCStr) -> bool { + pub fn is_memory_region_rebaseable(&self, name: &str) -> bool { let name_raw = name.to_cstr(); unsafe { BNIsMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_rebaseable(&mut self, name: impl IntoCStr, enabled: bool) -> bool { + pub fn set_memory_region_rebaseable(&mut self, name: &str, enabled: bool) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionRebaseable(self.view.handle, name_raw.as_ptr(), enabled) } } - pub fn memory_region_fill(&self, name: impl IntoCStr) -> u8 { + pub fn memory_region_fill(&self, name: &str) -> u8 { let name_raw = name.to_cstr(); unsafe { BNGetMemoryRegionFill(self.view.handle, name_raw.as_ptr()) } } - pub fn set_memory_region_fill(&mut self, name: impl IntoCStr, fill: u8) -> bool { + pub fn set_memory_region_fill(&mut self, name: &str, fill: u8) -> bool { let name_raw = name.to_cstr(); unsafe { BNSetMemoryRegionFill(self.view.handle, name_raw.as_ptr(), fill) } } diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs index 90af3aa876..04d8539644 100644 --- a/rust/src/calling_convention.rs +++ b/rust/src/calling_convention.rs @@ -55,10 +55,9 @@ pub trait CallingConvention: Sync { fn are_argument_registers_used_for_var_args(&self) -> bool; } -pub fn register_calling_convention(arch: &A, name: N, cc: C) -> Ref +pub fn register_calling_convention(arch: &A, name: &str, cc: C) -> Ref where A: Architecture, - N: IntoCStr, C: 'static + CallingConvention, { struct CustomCallingConventionContext diff --git a/rust/src/collaboration.rs b/rust/src/collaboration.rs index 9a97a0e8b2..0a17d94ca2 100644 --- a/rust/src/collaboration.rs +++ b/rust/src/collaboration.rs @@ -73,21 +73,21 @@ pub fn known_remotes() -> Array { } /// Get Remote by unique `id` -pub fn get_remote_by_id(id: S) -> Option> { +pub fn get_remote_by_id(id: &str) -> Option> { let id = id.to_cstr(); let value = unsafe { BNCollaborationGetRemoteById(id.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `address` -pub fn get_remote_by_address(address: S) -> Option> { +pub fn get_remote_by_address(address: &str) -> Option> { let address = address.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByAddress(address.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) } /// Get Remote by `name` -pub fn get_remote_by_name(name: S) -> Option> { +pub fn get_remote_by_name(name: &str) -> Option> { let name = name.to_cstr(); let value = unsafe { BNCollaborationGetRemoteByName(name.as_ptr()) }; NonNull::new(value).map(|h| unsafe { Remote::ref_from_raw(h) }) @@ -103,15 +103,12 @@ pub fn save_remotes() { unsafe { BNCollaborationSaveRemotes() } } -pub fn store_data_in_keychain(key: K, data: I) -> bool +pub fn store_data_in_keychain(key: &str, data: I) -> bool where - K: IntoCStr, - I: IntoIterator, - DK: IntoCStr, - DV: IntoCStr, + I: IntoIterator, { let key = key.to_cstr(); - let (data_keys, data_values): (Vec, Vec) = data + let (data_keys, data_values): (Vec<_>, Vec<_>) = data .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); @@ -127,12 +124,12 @@ where } } -pub fn has_data_in_keychain(key: K) -> bool { +pub fn has_data_in_keychain(key: &str) -> bool { let key = key.to_cstr(); unsafe { BNCollaborationHasDataInKeychain(key.as_ptr()) } } -pub fn get_data_from_keychain(key: K) -> Option<(Array, Array)> { +pub fn get_data_from_keychain(key: &str) -> Option<(Array, Array)> { let key = key.to_cstr(); let mut keys = std::ptr::null_mut(); let mut values = std::ptr::null_mut(); @@ -142,7 +139,7 @@ pub fn get_data_from_keychain(key: K) -> Option<(Array, A keys.zip(values) } -pub fn delete_data_from_keychain(key: K) -> bool { +pub fn delete_data_from_keychain(key: &str) -> bool { let key = key.to_cstr(); unsafe { BNCollaborationDeleteDataFromKeychain(key.as_ptr()) } } diff --git a/rust/src/collaboration/changeset.rs b/rust/src/collaboration/changeset.rs index b07f23deff..cce750e6e0 100644 --- a/rust/src/collaboration/changeset.rs +++ b/rust/src/collaboration/changeset.rs @@ -65,7 +65,7 @@ impl Changeset { } /// Set the name of the changeset, e.g. in a name changeset function. - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: &str) -> bool { let value = value.to_cstr(); unsafe { BNCollaborationChangesetSetName(self.handle.as_ptr(), value.as_ptr()) } } diff --git a/rust/src/collaboration/file.rs b/rust/src/collaboration/file.rs index 699b34b842..624a731a86 100644 --- a/rust/src/collaboration/file.rs +++ b/rust/src/collaboration/file.rs @@ -1,5 +1,6 @@ use std::ffi::c_void; use std::fmt::{Debug, Formatter}; +use std::path::Path; use std::ptr::NonNull; use std::time::SystemTime; @@ -94,7 +95,7 @@ impl RemoteFile { success.then_some(()).ok_or(()) } - pub fn set_metadata(&self, folder: S) -> Result<(), ()> { + pub fn set_metadata(&self, folder: &str) -> Result<(), ()> { let folder_raw = folder.to_cstr(); let success = unsafe { BNRemoteFileSetMetadata(self.handle.as_ptr(), folder_raw.as_ptr()) }; success.then_some(()).ok_or(()) @@ -185,7 +186,7 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: &str) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteFileSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -199,7 +200,7 @@ impl RemoteFile { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: &str) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteFileSetDescription(self.handle.as_ptr(), description.as_ptr()) }; @@ -249,7 +250,7 @@ impl RemoteFile { /// Get a specific Snapshot in the File by its id /// /// NOTE: If snapshots have not been pulled, they will be pulled upon calling this. - pub fn snapshot_by_id(&self, id: S) -> Result>, ()> { + pub fn snapshot_by_id(&self, id: &str) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_snapshots() { self.pull_snapshots()?; @@ -286,18 +287,16 @@ impl RemoteFile { /// * `analysis_cache_contents` - Contents of analysis cache of snapshot /// * `file` - New file contents (if contents changed) /// * `parent_ids` - List of ids of parent snapshots (or empty if this is a root snapshot) - pub fn create_snapshot( + pub fn create_snapshot( &self, - name: S, + name: &str, contents: &mut [u8], analysis_cache_contexts: &mut [u8], file: &mut [u8], parent_ids: I, ) -> Result, ()> where - S: IntoCStr, - I: IntoIterator, - I::Item: IntoCStr, + I: IntoIterator, { self.create_snapshot_with_progress( name, @@ -317,9 +316,9 @@ impl RemoteFile { /// * `file` - New file contents (if contents changed) /// * `parent_ids` - List of ids of parent snapshots (or empty if this is a root snapshot) /// * `progress` - Function to call on progress updates - pub fn create_snapshot_with_progress( + pub fn create_snapshot_with_progress( &self, - name: S, + name: &str, contents: &mut [u8], analysis_cache_contexts: &mut [u8], file: &mut [u8], @@ -327,10 +326,8 @@ impl RemoteFile { mut progress: P, ) -> Result, ()> where - S: IntoCStr, + I: IntoIterator, P: ProgressCallback, - I: IntoIterator, - I::Item: IntoCStr, { let name = name.to_cstr(); let parent_ids: Vec<_> = parent_ids.into_iter().map(|id| id.to_cstr()).collect(); @@ -403,10 +400,7 @@ impl RemoteFile { /// /// * `db_path` - File path for saved database /// * `progress_function` - Function to call for progress updates - pub fn download(&self, db_path: S) -> Result, ()> - where - S: IntoCStr, - { + pub fn download(&self, db_path: &Path) -> Result, ()> { sync::download_file(self, db_path) } @@ -416,20 +410,19 @@ impl RemoteFile { /// /// * `db_path` - File path for saved database /// * `progress_function` - Function to call for progress updates - pub fn download_with_progress( + pub fn download_with_progress( &self, - db_path: S, + db_path: &Path, progress_function: F, ) -> Result, ()> where - S: IntoCStr, F: ProgressCallback, { sync::download_file_with_progress(self, db_path, progress_function) } /// Download a remote file and save it to a BNDB at the given `path`, returning the associated [`FileMetadata`]. - pub fn download_database(&self, path: S) -> Result, ()> { + pub fn download_database(&self, path: &Path) -> Result, ()> { let file = self.download(path)?; let database = file.database().ok_or(())?; self.sync(&database, DatabaseConflictHandlerFail, NoNameChangeset)?; @@ -437,11 +430,10 @@ impl RemoteFile { } // TODO: This might be a bad helper... maybe remove... - // TODO: AsRef /// Download a remote file and save it to a BNDB at the given `path`. - pub fn download_database_with_progress( + pub fn download_database_with_progress( &self, - path: S, + path: &Path, progress: impl ProgressCallback, ) -> Result, ()> { let mut progress = progress.split(&[50, 50]); diff --git a/rust/src/collaboration/folder.rs b/rust/src/collaboration/folder.rs index 35ff078803..797bcdd4de 100644 --- a/rust/src/collaboration/folder.rs +++ b/rust/src/collaboration/folder.rs @@ -103,7 +103,7 @@ impl RemoteFolder { } /// Set the display name of the folder. You will need to push the folder to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: &str) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteFolderSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -117,7 +117,7 @@ impl RemoteFolder { } /// Set the description of the folder. You will need to push the folder to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: &str) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteFolderSetDescription(self.handle.as_ptr(), description.as_ptr()) }; diff --git a/rust/src/collaboration/group.rs b/rust/src/collaboration/group.rs index 08efa0795b..01f9216932 100644 --- a/rust/src/collaboration/group.rs +++ b/rust/src/collaboration/group.rs @@ -49,7 +49,7 @@ impl RemoteGroup { /// Set group name /// You will need to push the group to update the Remote. - pub fn set_name(&self, name: U) { + pub fn set_name(&self, name: &str) { let name = name.to_cstr(); unsafe { BNCollaborationGroupSetName(self.handle.as_ptr(), name.as_ptr()) } } @@ -83,8 +83,7 @@ impl RemoteGroup { /// You will need to push the group to update the Remote. pub fn set_users(&self, usernames: I) -> Result<(), ()> where - I: IntoIterator, - I::Item: IntoCStr, + I: IntoIterator, { let usernames: Vec<_> = usernames.into_iter().map(|u| u.to_cstr()).collect(); let mut usernames_raw: Vec<_> = usernames.iter().map(|s| s.as_ptr()).collect(); @@ -102,7 +101,7 @@ impl RemoteGroup { } /// Test if a group has a user with the given username - pub fn contains_user(&self, username: U) -> bool { + pub fn contains_user(&self, username: &str) -> bool { let username = username.to_cstr(); unsafe { BNCollaborationGroupContainsUser(self.handle.as_ptr(), username.as_ptr()) } } diff --git a/rust/src/collaboration/merge.rs b/rust/src/collaboration/merge.rs index 9ebf4cda71..aea117015d 100644 --- a/rust/src/collaboration/merge.rs +++ b/rust/src/collaboration/merge.rs @@ -48,7 +48,7 @@ impl MergeConflict { NonNull::new(result).map(|handle| unsafe { Snapshot::from_raw(handle) }) } - pub fn path_item_string(&self, path: S) -> Result { + pub fn path_item_string(&self, path: &str) -> Result { let path = path.to_cstr(); let result = unsafe { BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path.as_ptr()) @@ -119,7 +119,7 @@ impl MergeConflict { } /// Call this when you've resolved the conflict to save the result - pub fn success(&self, value: S) -> Result<(), ()> { + pub fn success(&self, value: &str) -> Result<(), ()> { let value = value.to_cstr(); let success = unsafe { BNAnalysisMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) }; @@ -127,7 +127,7 @@ impl MergeConflict { } // TODO: Make a safe version of this that checks the path and if it holds a number - pub unsafe fn get_path_item_number(&self, path_key: S) -> Option { + pub unsafe fn get_path_item_number(&self, path_key: &str) -> Option { let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItem(self.handle.as_ptr(), path_key.as_ptr()) }; @@ -138,7 +138,7 @@ impl MergeConflict { } } - pub unsafe fn get_path_item_string(&self, path_key: S) -> Option { + pub unsafe fn get_path_item_string(&self, path_key: &str) -> Option { let path_key = path_key.to_cstr(); let value = unsafe { BNAnalysisMergeConflictGetPathItemString(self.handle.as_ptr(), path_key.as_ptr()) diff --git a/rust/src/collaboration/project.rs b/rust/src/collaboration/project.rs index 3d34da9e55..fa46e477cd 100644 --- a/rust/src/collaboration/project.rs +++ b/rust/src/collaboration/project.rs @@ -1,4 +1,5 @@ use std::ffi::c_void; +use std::path::PathBuf; use std::ptr::NonNull; use std::time::SystemTime; @@ -136,7 +137,7 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_name(&self, name: S) -> Result<(), ()> { + pub fn set_name(&self, name: &str) -> Result<(), ()> { let name = name.to_cstr(); let success = unsafe { BNRemoteProjectSetName(self.handle.as_ptr(), name.as_ptr()) }; success.then_some(()).ok_or(()) @@ -150,7 +151,7 @@ impl RemoteProject { } /// Set the description of the file. You will need to push the file to update the remote version. - pub fn set_description(&self, description: S) -> Result<(), ()> { + pub fn set_description(&self, description: &str) -> Result<(), ()> { let description = description.to_cstr(); let success = unsafe { BNRemoteProjectSetDescription(self.handle.as_ptr(), description.as_ptr()) }; @@ -169,7 +170,7 @@ impl RemoteProject { /// Get the default directory path for a remote Project. This is based off the Setting for /// collaboration.directory, the project's id, and the project's remote's id. - pub fn default_path(&self) -> Result { + pub fn default_path(&self) -> Result { sync::default_project_path(self) } @@ -221,7 +222,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_id(&self, id: S) -> Result>, ()> { + pub fn get_file_by_id(&self, id: &str) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; @@ -235,7 +236,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If files have not been pulled, they will be pulled upon calling this. - pub fn get_file_by_name(&self, name: S) -> Result>, ()> { + pub fn get_file_by_name(&self, name: &str) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_files() { self.pull_files()?; @@ -282,20 +283,15 @@ impl RemoteProject { /// * `description` - File description /// * `parent_folder` - Folder that will contain the file /// * `file_type` - Type of File to create - pub fn create_file( + pub fn create_file( &self, - filename: F, + filename: &str, contents: &[u8], - name: N, - description: D, + name: &str, + description: &str, parent_folder: Option<&RemoteFolder>, file_type: RemoteFileType, - ) -> Result, ()> - where - F: IntoCStr, - N: IntoCStr, - D: IntoCStr, - { + ) -> Result, ()> { self.create_file_with_progress( filename, contents, @@ -318,20 +314,17 @@ impl RemoteProject { /// * `parent_folder` - Folder that will contain the file /// * `file_type` - Type of File to create /// * `progress` - Function to call on upload progress updates - pub fn create_file_with_progress( + pub fn create_file_with_progress

( &self, - filename: F, + filename: &str, contents: &[u8], - name: N, - description: D, + name: &str, + description: &str, parent_folder: Option<&RemoteFolder>, file_type: RemoteFileType, mut progress: P, ) -> Result, ()> where - F: IntoCStr, - N: IntoCStr, - D: IntoCStr, P: ProgressCallback, { // TODO: This sync should be removed? @@ -364,11 +357,9 @@ impl RemoteProject { /// Push an updated File object to the Remote /// /// NOTE: If the project has not been opened, it will be opened upon calling this. - pub fn push_file(&self, file: &RemoteFile, extra_fields: I) -> Result<(), ()> + pub fn push_file(&self, file: &RemoteFile, extra_fields: I) -> Result<(), ()> where - I: Iterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { // TODO: This sync should be removed? self.open()?; @@ -421,7 +412,7 @@ impl RemoteProject { /// /// NOTE: If the project has not been opened, it will be opened upon calling this. /// NOTE: If folders have not been pulled, they will be pulled upon calling this. - pub fn get_folder_by_id(&self, id: S) -> Result>, ()> { + pub fn get_folder_by_id(&self, id: &str) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_folders() { self.pull_folders()?; @@ -465,16 +456,12 @@ impl RemoteProject { /// * `name` - Displayed folder name /// * `description` - Folder description /// * `parent` - Parent folder (optional) - pub fn create_folder( + pub fn create_folder( &self, - name: N, - description: D, + name: &str, + description: &str, parent_folder: Option<&RemoteFolder>, - ) -> Result, ()> - where - N: IntoCStr, - D: IntoCStr, - { + ) -> Result, ()> { self.create_folder_with_progress(name, description, parent_folder, NoProgressCallback) } @@ -486,16 +473,14 @@ impl RemoteProject { /// * `description` - Folder description /// * `parent` - Parent folder (optional) /// * `progress` - Function to call on upload progress updates - pub fn create_folder_with_progress( + pub fn create_folder_with_progress

( &self, - name: N, - description: D, + name: &str, + description: &str, parent_folder: Option<&RemoteFolder>, mut progress: P, ) -> Result, ()> where - N: IntoCStr, - D: IntoCStr, P: ProgressCallback, { // TODO: This sync should be removed? @@ -526,11 +511,9 @@ impl RemoteProject { /// /// * `folder` - Folder object which has been updated /// * `extra_fields` - Extra HTTP fields to send with the update - pub fn push_folder(&self, folder: &RemoteFolder, extra_fields: I) -> Result<(), ()> + pub fn push_folder(&self, folder: &RemoteFolder, extra_fields: I) -> Result<(), ()> where - I: Iterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { // TODO: This sync should be removed? self.open()?; @@ -598,7 +581,7 @@ impl RemoteProject { /// Get a specific permission in the Project by its id. /// /// NOTE: If group or user permissions have not been pulled, they will be pulled upon calling this. - pub fn get_permission_by_id(&self, id: S) -> Result>, ()> { + pub fn get_permission_by_id(&self, id: &str) -> Result>, ()> { // TODO: This sync should be removed? if !self.has_pulled_user_permissions() { self.pull_user_permissions()?; @@ -703,9 +686,9 @@ impl RemoteProject { /// /// * `user_id` - User id /// * `level` - Permission level - pub fn create_user_permission( + pub fn create_user_permission( &self, - user_id: S, + user_id: &str, level: CollaborationPermissionLevel, ) -> Result, ()> { self.create_user_permission_with_progress(user_id, level, NoProgressCallback) @@ -718,9 +701,9 @@ impl RemoteProject { /// * `user_id` - User id /// * `level` - Permission level /// * `progress` - The progress callback to call - pub fn create_user_permission_with_progress( + pub fn create_user_permission_with_progress( &self, - user_id: S, + user_id: &str, level: CollaborationPermissionLevel, mut progress: F, ) -> Result, ()> { @@ -746,15 +729,9 @@ impl RemoteProject { /// /// * `permission` - Permission object which has been updated /// * `extra_fields` - Extra HTTP fields to send with the update - pub fn push_permission( - &self, - permission: &Permission, - extra_fields: I, - ) -> Result<(), ()> + pub fn push_permission(&self, permission: &Permission, extra_fields: I) -> Result<(), ()> where - I: Iterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -788,7 +765,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_view(&self, username: S) -> bool { + pub fn can_user_view(&self, username: &str) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserView(self.handle.as_ptr(), username.as_ptr()) } } @@ -798,7 +775,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_edit(&self, username: S) -> bool { + pub fn can_user_edit(&self, username: &str) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserEdit(self.handle.as_ptr(), username.as_ptr()) } } @@ -808,7 +785,7 @@ impl RemoteProject { /// # Arguments /// /// * `username` - Username of user to check - pub fn can_user_admin(&self, username: S) -> bool { + pub fn can_user_admin(&self, username: &str) -> bool { let username = username.to_cstr(); unsafe { BNRemoteProjectCanUserAdmin(self.handle.as_ptr(), username.as_ptr()) } } diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index baeba412fc..7b5828efe2 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -27,7 +27,7 @@ impl Remote { } /// Create a Remote and add it to the list of known remotes (saved to Settings) - pub fn new(name: N, address: A) -> Ref { + pub fn new(name: &str, address: &str) -> Ref { let name = name.to_cstr(); let address = address.to_cstr(); let result = unsafe { BNCollaborationCreateRemote(name.as_ptr(), address.as_ptr()) }; @@ -163,11 +163,7 @@ impl Remote { } /// Requests an authentication token using a username and password. - pub fn request_authentication_token( - &self, - username: U, - password: P, - ) -> Option { + pub fn request_authentication_token(&self, username: &str, password: &str) -> Option { let username = username.to_cstr(); let password = password.to_cstr(); let token = unsafe { @@ -219,7 +215,7 @@ impl Remote { let password = options .password .expect("No password or token for connection!"); - let token = self.request_authentication_token(&options.username, password); + let token = self.request_authentication_token(&options.username, &password); // TODO: Error if None. token.unwrap().to_string() } @@ -275,7 +271,7 @@ impl Remote { /// Gets a specific project in the Remote by its id. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_id(&self, id: S) -> Result>, ()> { + pub fn get_project_by_id(&self, id: &str) -> Result>, ()> { if !self.has_pulled_projects() { self.pull_projects()?; } @@ -288,10 +284,7 @@ impl Remote { /// Gets a specific project in the Remote by its name. /// /// NOTE: If projects have not been pulled, they will be pulled upon calling this. - pub fn get_project_by_name( - &self, - name: S, - ) -> Result>, ()> { + pub fn get_project_by_name(&self, name: &str) -> Result>, ()> { if !self.has_pulled_projects() { self.pull_projects()?; } @@ -331,11 +324,7 @@ impl Remote { /// /// * `name` - Project name /// * `description` - Project description - pub fn create_project( - &self, - name: N, - description: D, - ) -> Result, ()> { + pub fn create_project(&self, name: &str, description: &str) -> Result, ()> { // TODO: Do we want this? // TODO: If you have not yet pulled projects you will have never filled the map you will be placing your // TODO: New project in. @@ -380,11 +369,9 @@ impl Remote { /// /// * `project` - Project object which has been updated /// * `extra_fields` - Extra HTTP fields to send with the update - pub fn push_project(&self, project: &RemoteProject, extra_fields: I) -> Result<(), ()> + pub fn push_project(&self, project: &RemoteProject, extra_fields: I) -> Result<(), ()> where - I: Iterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -446,7 +433,7 @@ impl Remote { /// /// If groups have not been pulled, they will be pulled upon calling this. /// This function is only available to accounts with admin status on the Remote. - pub fn get_group_by_name(&self, name: S) -> Result>, ()> { + pub fn get_group_by_name(&self, name: &str) -> Result>, ()> { if !self.has_pulled_groups() { self.pull_groups()?; } @@ -462,10 +449,7 @@ impl Remote { /// # Arguments /// /// * `prefix` - Prefix of name for groups - pub fn search_groups( - &self, - prefix: S, - ) -> Result<(Array, Array), ()> { + pub fn search_groups(&self, prefix: &str) -> Result<(Array, Array), ()> { let prefix = prefix.to_cstr(); let mut count = 0; let mut group_ids = std::ptr::null_mut(); @@ -524,11 +508,9 @@ impl Remote { /// /// * `name` - Group name /// * `usernames` - List of usernames of users in the group - pub fn create_group(&self, name: N, usernames: I) -> Result, ()> + pub fn create_group(&self, name: &str, usernames: I) -> Result, ()> where - N: IntoCStr, - I: IntoIterator, - I::Item: IntoCStr, + I: IntoIterator, { let name = name.to_cstr(); let usernames: Vec<_> = usernames.into_iter().map(|s| s.to_cstr()).collect(); @@ -554,11 +536,9 @@ impl Remote { /// /// * `group` - Group object which has been updated /// * `extra_fields` - Extra HTTP fields to send with the update - pub fn push_group(&self, group: &RemoteGroup, extra_fields: I) -> Result<(), ()> + pub fn push_group(&self, group: &RemoteGroup, extra_fields: I) -> Result<(), ()> where - I: IntoIterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() @@ -617,7 +597,7 @@ impl Remote { /// # Arguments /// /// * `id` - The identifier of the user to retrieve. - pub fn get_user_by_id(&self, id: S) -> Result>, ()> { + pub fn get_user_by_id(&self, id: &str) -> Result>, ()> { if !self.has_pulled_users() { self.pull_users()?; } @@ -635,10 +615,7 @@ impl Remote { /// # Arguments /// /// * `username` - The username of the user to retrieve. - pub fn get_user_by_username( - &self, - username: S, - ) -> Result>, ()> { + pub fn get_user_by_username(&self, username: &str) -> Result>, ()> { if !self.has_pulled_users() { self.pull_users()?; } @@ -665,10 +642,7 @@ impl Remote { /// # Arguments /// /// * `prefix` - The prefix to search for in usernames. - pub fn search_users( - &self, - prefix: S, - ) -> Result<(Array, Array), ()> { + pub fn search_users(&self, prefix: &str) -> Result<(Array, Array), ()> { let prefix = prefix.to_cstr(); let mut count = 0; let mut user_ids = std::ptr::null_mut(); @@ -730,12 +704,12 @@ impl Remote { /// # Arguments /// /// * Various details about the new user to be created. - pub fn create_user( + pub fn create_user( &self, - username: U, - email: E, + username: &str, + email: &str, is_active: bool, - password: P, + password: &str, group_ids: &[u64], user_permission_ids: &[u64], ) -> Result, ()> { @@ -769,11 +743,9 @@ impl Remote { /// /// * `user` - Reference to the `RemoteUser` object to push. /// * `extra_fields` - Optional extra fields to send with the update. - pub fn push_user(&self, user: &RemoteUser, extra_fields: I) -> Result<(), ()> + pub fn push_user(&self, user: &RemoteUser, extra_fields: I) -> Result<(), ()> where - I: Iterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { let (keys, values): (Vec<_>, Vec<_>) = extra_fields .into_iter() diff --git a/rust/src/collaboration/snapshot.rs b/rust/src/collaboration/snapshot.rs index c825660828..203d8677fb 100644 --- a/rust/src/collaboration/snapshot.rs +++ b/rust/src/collaboration/snapshot.rs @@ -226,10 +226,10 @@ impl RemoteSnapshot { } /// Create a new Undo Entry in this snapshot. - pub fn create_undo_entry( + pub fn create_undo_entry( &self, parent: Option, - data: S, + data: &str, ) -> Result, ()> { let data = data.to_cstr(); let value = unsafe { diff --git a/rust/src/collaboration/sync.rs b/rust/src/collaboration/sync.rs index b1b26982a2..a8006b8b3c 100644 --- a/rust/src/collaboration/sync.rs +++ b/rust/src/collaboration/sync.rs @@ -3,6 +3,7 @@ use super::{ }; use binaryninjacore_sys::*; use std::ffi::{c_char, c_void}; +use std::path::{Path, PathBuf}; use std::ptr::NonNull; use crate::binary_view::{BinaryView, BinaryViewExt}; @@ -14,49 +15,45 @@ use crate::rc::Ref; use crate::string::{raw_to_string, BnString, IntoCStr}; use crate::type_archive::{TypeArchive, TypeArchiveMergeConflict}; -// TODO: PathBuf /// Get the default directory path for a remote Project. This is based off the Setting for /// collaboration.directory, the project's id, and the project's remote's id. -pub fn default_project_path(project: &RemoteProject) -> Result { +pub fn default_project_path(project: &RemoteProject) -> Result { let result = unsafe { BNCollaborationDefaultProjectPath(project.handle.as_ptr()) }; let success = !result.is_null(); success - .then(|| unsafe { BnString::from_raw(result) }) + .then(|| PathBuf::from(unsafe { BnString::into_string(result) })) .ok_or(()) } -// TODO: PathBuf // Get the default filepath for a remote File. This is based off the Setting for // collaboration.directory, the file's id, the file's project's id, and the file's // remote's id. -pub fn default_file_path(file: &RemoteFile) -> Result { +pub fn default_file_path(file: &RemoteFile) -> Result { let result = unsafe { BNCollaborationDefaultFilePath(file.handle.as_ptr()) }; let success = !result.is_null(); success - .then(|| unsafe { BnString::from_raw(result) }) + .then(|| PathBuf::from(unsafe { BnString::into_string(result) })) .ok_or(()) } -// TODO: AsRef /// Download a file from its remote, saving all snapshots to a database in the /// specified location. Returns a FileContext for opening the file later. /// /// * `file` - Remote File to download and open /// * `db_path` - File path for saved database -pub fn download_file(file: &RemoteFile, db_path: S) -> Result, ()> { +pub fn download_file(file: &RemoteFile, db_path: &Path) -> Result, ()> { download_file_with_progress(file, db_path, NoProgressCallback) } -// TODO: AsRef /// Download a file from its remote, saving all snapshots to a database in the /// specified location. Returns a FileContext for opening the file later. /// /// * `file` - Remote File to download and open /// * `db_path` - File path for saved database /// * `progress` - Function to call for progress updates -pub fn download_file_with_progress( +pub fn download_file_with_progress( file: &RemoteFile, - db_path: S, + db_path: &Path, mut progress: F, ) -> Result, ()> { let db_path = db_path.to_cstr(); @@ -218,22 +215,18 @@ pub fn get_local_snapshot_for_remote( .ok_or(()) } -pub fn download_database(file: &RemoteFile, location: S, force: bool) -> Result<(), ()> -where - S: IntoCStr, -{ +pub fn download_database(file: &RemoteFile, location: &Path, force: bool) -> Result<(), ()> { download_database_with_progress(file, location, force, NoProgressCallback) } -pub fn download_database_with_progress( +pub fn download_database_with_progress( file: &RemoteFile, - location: S, + location: &Path, force: bool, - mut progress: F, + mut progress: PC, ) -> Result<(), ()> where - S: IntoCStr, - F: ProgressCallback, + PC: ProgressCallback, { let db_path = location.to_cstr(); let success = unsafe { @@ -241,8 +234,8 @@ where file.handle.as_ptr(), db_path.as_ptr(), force, - Some(F::cb_progress_callback), - &mut progress as *mut _ as *mut c_void, + Some(PC::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, ) }; success.then_some(()).ok_or(()) @@ -475,10 +468,10 @@ pub fn get_snapshot_author( /// * `database` - Parent database /// * `snapshot` - Snapshot to edit /// * `author` - Target author -pub fn set_snapshot_author( +pub fn set_snapshot_author( database: &Database, snapshot: &Snapshot, - author: S, + author: &str, ) -> Result<(), ()> { let author = author.to_cstr(); let success = unsafe { @@ -650,9 +643,9 @@ pub fn get_remote_file_for_local_type_archive(database: &TypeArchive) -> Option< } /// Get the remote snapshot associated with a local snapshot (if it exists) in a Type Archive -pub fn get_remote_snapshot_from_local_type_archive( +pub fn get_remote_snapshot_from_local_type_archive( type_archive: &TypeArchive, - snapshot_id: S, + snapshot_id: &str, ) -> Option> { let snapshot_id = snapshot_id.to_cstr(); let value = unsafe { @@ -679,10 +672,7 @@ pub fn get_local_snapshot_from_remote_type_archive( } /// Test if a snapshot is ignored from the archive -pub fn is_type_archive_snapshot_ignored( - type_archive: &TypeArchive, - snapshot_id: S, -) -> bool { +pub fn is_type_archive_snapshot_ignored(type_archive: &TypeArchive, snapshot_id: &str) -> bool { let snapshot_id = snapshot_id.to_cstr(); unsafe { BNCollaborationIsTypeArchiveSnapshotIgnored( @@ -694,19 +684,19 @@ pub fn is_type_archive_snapshot_ignored( /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive( +pub fn download_type_archive( file: &RemoteFile, - location: S, + location: &Path, ) -> Result>, ()> { download_type_archive_with_progress(file, location, NoProgressCallback) } /// Download a type archive from its remote, saving all snapshots to an archive in the /// specified `location`. Returns a [`TypeArchive`] for using later. -pub fn download_type_archive_with_progress( +pub fn download_type_archive_with_progress( file: &RemoteFile, - location: S, - mut progress: F, + location: &Path, + mut progress: PC, ) -> Result>, ()> { let mut value = std::ptr::null_mut(); let db_path = location.to_cstr(); @@ -714,8 +704,8 @@ pub fn download_type_archive_with_progress( BNCollaborationDownloadTypeArchive( file.handle.as_ptr(), db_path.as_ptr(), - Some(F::cb_progress_callback), - &mut progress as *mut F as *mut c_void, + Some(PC::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, &mut value, ) }; diff --git a/rust/src/collaboration/user.rs b/rust/src/collaboration/user.rs index 6b49094261..51bdebb54a 100644 --- a/rust/src/collaboration/user.rs +++ b/rust/src/collaboration/user.rs @@ -48,7 +48,7 @@ impl RemoteUser { } /// Set user's username. You will need to push the user to update the Remote - pub fn set_username(&self, username: U) -> Result<(), ()> { + pub fn set_username(&self, username: &str) -> Result<(), ()> { let username = username.to_cstr(); let result = unsafe { BNCollaborationUserSetUsername(self.handle.as_ptr(), username.as_ptr()) }; @@ -67,7 +67,7 @@ impl RemoteUser { } /// Set user's email. You will need to push the user to update the Remote - pub fn set_email(&self, email: U) -> Result<(), ()> { + pub fn set_email(&self, email: &str) -> Result<(), ()> { let username = email.to_cstr(); let result = unsafe { BNCollaborationUserSetEmail(self.handle.as_ptr(), username.as_ptr()) }; diff --git a/rust/src/command.rs b/rust/src/command.rs index 099eafa84a..46f43bbd51 100644 --- a/rust/src/command.rs +++ b/rust/src/command.rs @@ -93,11 +93,7 @@ where /// true /// } /// ``` -pub fn register_command(name: S, desc: S, command: C) -where - S: IntoCStr, - C: Command, -{ +pub fn register_command(name: &str, desc: &str, command: C) { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView) where C: Command, @@ -194,11 +190,7 @@ where /// true /// } /// ``` -pub fn register_command_for_address(name: S, desc: S, command: C) -where - S: IntoCStr, - C: AddressCommand, -{ +pub fn register_command_for_address(name: &str, desc: &str, command: C) { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64) where C: AddressCommand, @@ -296,9 +288,8 @@ where /// true /// } /// ``` -pub fn register_command_for_range(name: S, desc: S, command: C) +pub fn register_command_for_range(name: &str, desc: &str, command: C) where - S: IntoCStr, C: RangeCommand, { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, addr: u64, len: u64) @@ -403,11 +394,7 @@ where /// true /// } /// ``` -pub fn register_command_for_function(name: S, desc: S, command: C) -where - S: IntoCStr, - C: FunctionCommand, -{ +pub fn register_command_for_function(name: &str, desc: &str, command: C) { extern "C" fn cb_action(ctxt: *mut c_void, view: *mut BNBinaryView, func: *mut BNFunction) where C: FunctionCommand, diff --git a/rust/src/component.rs b/rust/src/component.rs index ae5fd55ed8..4c5d5992d2 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -164,7 +164,7 @@ impl Component { unsafe { BnString::into_string(result) } } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: &str) { let name = name.to_cstr(); unsafe { BNComponentSetName(self.handle.as_ptr(), name.as_ptr()) } } diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index 7e5c0a2409..f809f251f3 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -39,9 +39,8 @@ use crate::Endianness; /// the core. The `BinaryViewType` argument passed to `constructor` is the object that the /// `AsRef` /// implementation of the `CustomBinaryViewType` must return. -pub fn register_view_type(name: S, long_name: S, constructor: F) -> &'static T +pub fn register_view_type(name: &str, long_name: &str, constructor: F) -> &'static T where - S: IntoCStr, T: CustomBinaryViewType, F: FnOnce(BinaryViewType) -> T, { @@ -359,7 +358,7 @@ impl BinaryViewType { } /// Looks up a BinaryViewType by its short name - pub fn by_name(name: N) -> Result { + pub fn by_name(name: &str) -> Result { let bytes = name.to_cstr(); let handle = unsafe { BNGetBinaryViewTypeByName(bytes.as_ref().as_ptr() as *const _) }; match handle.is_null() { diff --git a/rust/src/data_buffer.rs b/rust/src/data_buffer.rs index bfffc33fdb..a3f51d54ae 100644 --- a/rust/src/data_buffer.rs +++ b/rust/src/data_buffer.rs @@ -120,7 +120,8 @@ impl DataBuffer { } } - pub fn from_escaped_string(value: &BnString) -> Self { + pub fn from_escaped_string(value: &str) -> Self { + let value = value.to_cstr(); Self(unsafe { BNDecodeEscapedString(value.as_ptr()) }) } diff --git a/rust/src/database.rs b/rust/src/database.rs index 1746b405dc..4f2b3f6a8e 100644 --- a/rust/src/database.rs +++ b/rust/src/database.rs @@ -62,11 +62,11 @@ impl Database { unsafe { BNSetDatabaseCurrentSnapshot(self.handle.as_ptr(), id.0) } } - pub fn write_snapshot_data( + pub fn write_snapshot_data( &self, parents: &[SnapshotId], file: &BinaryView, - name: N, + name: &str, data: &KeyValueStore, auto_save: bool, ) -> SnapshotId { @@ -80,17 +80,16 @@ impl Database { ) } - pub fn write_snapshot_data_with_progress( + pub fn write_snapshot_data_with_progress

( &self, parents: &[SnapshotId], file: &BinaryView, - name: N, + name: &str, data: &KeyValueStore, auto_save: bool, mut progress: P, ) -> SnapshotId where - N: IntoCStr, P: ProgressCallback, { let name_raw = name.to_cstr(); @@ -133,7 +132,7 @@ impl Database { Err(()) } } - pub fn has_global(&self, key: S) -> bool { + pub fn has_global(&self, key: &str) -> bool { let key_raw = key.to_cstr(); unsafe { BNDatabaseHasGlobal(self.handle.as_ptr(), key_raw.as_ptr()) != 0 } } @@ -155,28 +154,28 @@ impl Database { } /// Get a specific global by key - pub fn read_global(&self, key: S) -> Option { + pub fn read_global(&self, key: &str) -> Option { let key_raw = key.to_cstr(); let result = unsafe { BNReadDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr()) }; unsafe { NonNull::new(result).map(|_| BnString::from_raw(result)) } } /// Write a global into the database - pub fn write_global(&self, key: K, value: V) -> bool { + pub fn write_global(&self, key: &str, value: &str) -> bool { let key_raw = key.to_cstr(); let value_raw = value.to_cstr(); unsafe { BNWriteDatabaseGlobal(self.handle.as_ptr(), key_raw.as_ptr(), value_raw.as_ptr()) } } /// Get a specific global by key, as a binary buffer - pub fn read_global_data(&self, key: S) -> Option { + pub fn read_global_data(&self, key: &str) -> Option { let key_raw = key.to_cstr(); let result = unsafe { BNReadDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr()) }; NonNull::new(result).map(|_| DataBuffer::from_raw(result)) } /// Write a binary buffer into a global in the database - pub fn write_global_data(&self, key: K, value: &DataBuffer) -> bool { + pub fn write_global_data(&self, key: &str, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); unsafe { BNWriteDatabaseGlobalData(self.handle.as_ptr(), key_raw.as_ptr(), value.as_raw()) } } diff --git a/rust/src/database/kvs.rs b/rust/src/database/kvs.rs index 5b7cbbe87e..13b1796218 100644 --- a/rust/src/database/kvs.rs +++ b/rust/src/database/kvs.rs @@ -41,7 +41,7 @@ impl KeyValueStore { } /// Get the value for a single key - pub fn value(&self, key: S) -> Option { + pub fn value(&self, key: &str) -> Option { let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ptr(); let result = unsafe { BNGetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr) }; @@ -49,7 +49,7 @@ impl KeyValueStore { } /// Set the value for a single key - pub fn set_value(&self, key: S, value: &DataBuffer) -> bool { + pub fn set_value(&self, key: &str, value: &DataBuffer) -> bool { let key_raw = key.to_cstr(); let key_ptr = key_raw.as_ptr(); unsafe { BNSetKeyValueStoreBuffer(self.handle.as_ptr(), key_ptr, value.as_raw()) } @@ -63,7 +63,7 @@ impl KeyValueStore { } /// Begin storing new keys into a namespace - pub fn begin_namespace(&self, name: S) { + pub fn begin_namespace(&self, name: &str) { let name_raw = name.to_cstr(); let name_ptr = name_raw.as_ptr(); unsafe { BNBeginKeyValueStoreNamespace(self.handle.as_ptr(), name_ptr) } diff --git a/rust/src/database/snapshot.rs b/rust/src/database/snapshot.rs index d9ff030aba..85c57f4ea0 100644 --- a/rust/src/database/snapshot.rs +++ b/rust/src/database/snapshot.rs @@ -50,7 +50,7 @@ impl Snapshot { } /// Set the displayed snapshot name - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: &str) { let value_raw = value.to_cstr(); let value_ptr = value_raw.as_ptr(); unsafe { BNSetSnapshotName(self.handle.as_ptr(), value_ptr) } diff --git a/rust/src/debuginfo.rs b/rust/src/debuginfo.rs index 248726f38e..a4d0b13970 100644 --- a/rust/src/debuginfo.rs +++ b/rust/src/debuginfo.rs @@ -115,7 +115,7 @@ impl DebugInfoParser { } /// Returns debug info parser of the given name, if it exists - pub fn from_name(name: S) -> Result, ()> { + pub fn from_name(name: &str) -> Result, ()> { let name = name.to_cstr(); let parser = unsafe { BNGetDebugInfoParserByName(name.as_ptr()) }; @@ -207,9 +207,8 @@ impl DebugInfoParser { } // Registers a DebugInfoParser. See `binaryninja::debuginfo::DebugInfoParser` for more details. - pub fn register(name: S, parser_callbacks: C) -> Ref + pub fn register(name: &str, parser_callbacks: C) -> Ref where - S: IntoCStr, C: CustomDebugInfoParser, { extern "C" fn cb_is_valid(ctxt: *mut c_void, view: *mut BNBinaryView) -> bool @@ -418,7 +417,7 @@ impl DebugInfo { } /// Returns all types within the parser - pub fn types_by_name(&self, parser_name: S) -> Vec { + pub fn types_by_name(&self, parser_name: &str) -> Vec { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; @@ -451,7 +450,7 @@ impl DebugInfo { } /// Returns all functions within the parser - pub fn functions_by_name(&self, parser_name: S) -> Vec { + pub fn functions_by_name(&self, parser_name: &str) -> Vec { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; @@ -486,10 +485,7 @@ impl DebugInfo { } /// Returns all data variables within the parser - pub fn data_variables_by_name( - &self, - parser_name: S, - ) -> Vec { + pub fn data_variables_by_name(&self, parser_name: &str) -> Vec { let parser_name = parser_name.to_cstr(); let mut count: usize = 0; @@ -523,7 +519,7 @@ impl DebugInfo { result } - pub fn type_by_name(&self, parser_name: S, name: S) -> Option> { + pub fn type_by_name(&self, parser_name: &str, name: &str) -> Option> { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); @@ -536,10 +532,10 @@ impl DebugInfo { } } - pub fn get_data_variable_by_name( + pub fn get_data_variable_by_name( &self, - parser_name: S, - name: S, + parser_name: &str, + name: &str, ) -> Option { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); @@ -558,9 +554,9 @@ impl DebugInfo { } } - pub fn get_data_variable_by_address( + pub fn get_data_variable_by_address( &self, - parser_name: S, + parser_name: &str, address: u64, ) -> Option { let parser_name = parser_name.to_cstr(); @@ -576,7 +572,7 @@ impl DebugInfo { } /// Returns a list of [`NameAndType`] where the `name` is the parser the type originates from. - pub fn get_types_by_name(&self, name: S) -> Vec { + pub fn get_types_by_name(&self, name: &str) -> Vec { let mut count: usize = 0; let name = name.to_cstr(); let raw_names_and_types_ptr = @@ -595,10 +591,7 @@ impl DebugInfo { } // The tuple is (DebugInfoParserName, address, type) - pub fn get_data_variables_by_name( - &self, - name: S, - ) -> Vec<(String, u64, Ref)> { + pub fn get_data_variables_by_name(&self, name: &str) -> Vec<(String, u64, Ref)> { let name = name.to_cstr(); let mut count: usize = 0; @@ -649,55 +642,51 @@ impl DebugInfo { result } - pub fn remove_parser_info(&self, parser_name: S) -> bool { + pub fn remove_parser_info(&self, parser_name: &str) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserInfo(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_types(&self, parser_name: S) -> bool { + pub fn remove_parser_types(&self, parser_name: &str) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserTypes(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_functions(&self, parser_name: S) -> bool { + pub fn remove_parser_functions(&self, parser_name: &str) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserFunctions(self.handle, parser_name.as_ptr()) } } - pub fn remove_parser_data_variables(&self, parser_name: S) -> bool { + pub fn remove_parser_data_variables(&self, parser_name: &str) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugParserDataVariables(self.handle, parser_name.as_ptr()) } } - pub fn remove_type_by_name(&self, parser_name: S, name: S) -> bool { + pub fn remove_type_by_name(&self, parser_name: &str, name: &str) -> bool { let parser_name = parser_name.to_cstr(); let name = name.to_cstr(); unsafe { BNRemoveDebugTypeByName(self.handle, parser_name.as_ptr(), name.as_ptr()) } } - pub fn remove_function_by_index(&self, parser_name: S, index: usize) -> bool { + pub fn remove_function_by_index(&self, parser_name: &str, index: usize) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugFunctionByIndex(self.handle, parser_name.as_ptr(), index) } } - pub fn remove_data_variable_by_address( - &self, - parser_name: S, - address: u64, - ) -> bool { + pub fn remove_data_variable_by_address(&self, parser_name: &str, address: u64) -> bool { let parser_name = parser_name.to_cstr(); unsafe { BNRemoveDebugDataVariableByAddress(self.handle, parser_name.as_ptr(), address) } } /// Adds a type scoped under the current parser's name to the debug info - pub fn add_type(&self, name: S, new_type: &Type, components: &[&str]) -> bool { + pub fn add_type(&self, name: &str, new_type: &Type, components: &[&str]) -> bool { // SAFETY: Lifetime of `components` will live long enough, so passing as_ptr is safe. let raw_components: Vec<_> = components.iter().map(|&c| c.as_ptr()).collect(); @@ -779,11 +768,11 @@ impl DebugInfo { } /// Adds a data variable scoped under the current parser's name to the debug info - pub fn add_data_variable( + pub fn add_data_variable( &self, address: u64, t: &Type, - name: Option, + name: Option<&str>, components: &[&str], ) -> bool { let mut components_array: Vec<*const ::std::os::raw::c_char> = diff --git a/rust/src/demangle.rs b/rust/src/demangle.rs index 68b349ca97..50878bdad6 100644 --- a/rust/src/demangle.rs +++ b/rust/src/demangle.rs @@ -26,9 +26,9 @@ use crate::rc::*; pub type Result = std::result::Result; -pub fn demangle_generic( +pub fn demangle_generic( arch: &CoreArchitecture, - mangled_name: S, + mangled_name: &str, view: Option<&BinaryView>, simplify: bool, ) -> Option<(QualifiedName, Option>)> { @@ -57,7 +57,7 @@ pub fn demangle_generic( } } -pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option { +pub fn demangle_llvm(mangled_name: &str, simplify: bool) -> Option { let mangled_name = mangled_name.to_cstr(); let mut out_name: *mut *mut std::os::raw::c_char = std::ptr::null_mut(); let mut out_size: usize = 0; @@ -85,9 +85,9 @@ pub fn demangle_llvm(mangled_name: S, simplify: bool) -> Option( +pub fn demangle_gnu3( arch: &CoreArchitecture, - mangled_name: S, + mangled_name: &str, simplify: bool, ) -> Option<(QualifiedName, Option>)> { let mangled_name = mangled_name.to_cstr(); @@ -125,9 +125,9 @@ pub fn demangle_gnu3( } } -pub fn demangle_ms( +pub fn demangle_ms( arch: &CoreArchitecture, - mangled_name: S, + mangled_name: &str, simplify: bool, ) -> Option<(QualifiedName, Option>)> { let mangled_name = mangled_name.to_cstr(); @@ -182,15 +182,15 @@ impl Demangler { unsafe { Array::::new(demanglers, count, ()) } } - pub fn is_mangled_string(&self, name: S) -> bool { + pub fn is_mangled_string(&self, name: &str) -> bool { let bytes = name.to_cstr(); unsafe { BNIsDemanglerMangledName(self.handle, bytes.as_ref().as_ptr() as *const _) } } - pub fn demangle( + pub fn demangle( &self, arch: &CoreArchitecture, - name: S, + name: &str, view: Option<&BinaryView>, ) -> Option<(QualifiedName, Option>)> { let name_bytes = name.to_cstr(); @@ -231,7 +231,7 @@ impl Demangler { unsafe { BnString::into_string(BNGetDemanglerName(self.handle)) } } - pub fn from_name(name: S) -> Option { + pub fn from_name(name: &str) -> Option { let name_bytes = name.to_cstr(); let demangler = unsafe { BNGetDemanglerByName(name_bytes.as_ref().as_ptr() as *const _) }; if demangler.is_null() { @@ -241,11 +241,7 @@ impl Demangler { } } - pub fn register(name: S, demangler: C) -> Self - where - S: IntoCStr, - C: CustomDemangler, - { + pub fn register(name: &str, demangler: C) -> Self { extern "C" fn cb_is_mangled_string(ctxt: *mut c_void, name: *const c_char) -> bool where C: CustomDemangler, diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs index 396bcfcc2f..973fd57cb3 100644 --- a/rust/src/disassembly.rs +++ b/rust/src/disassembly.rs @@ -1242,13 +1242,13 @@ impl DisassemblyTextRenderer { unsafe { Array::new(tokens, count, ()) } } - pub fn wrap_comment( + pub fn wrap_comment( &self, cur_line: DisassemblyTextLine, - comment: S1, + comment: &str, has_auto_annotations: bool, - leading_spaces: S2, - indent_spaces: S3, + leading_spaces: &str, + indent_spaces: &str, ) -> Array { let cur_line_raw = DisassemblyTextLine::into_raw(cur_line); let comment_raw = comment.to_cstr(); diff --git a/rust/src/download_provider.rs b/rust/src/download_provider.rs index e74274f44f..9fd803a7de 100644 --- a/rust/src/download_provider.rs +++ b/rust/src/download_provider.rs @@ -13,7 +13,7 @@ pub struct DownloadProvider { } impl DownloadProvider { - pub fn get(name: S) -> Option { + pub fn get(name: &str) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetDownloadProviderByName(name.as_ptr()) }; if result.is_null() { @@ -37,7 +37,7 @@ impl DownloadProvider { pub fn try_default() -> Result { let s = Settings::new(); let dp_name = s.get_string("network.downloadProviderName"); - Self::get(dp_name).ok_or(()) + Self::get(&dp_name).ok_or(()) } pub(crate) fn from_raw(handle: *mut BNDownloadProvider) -> DownloadProvider { @@ -131,9 +131,9 @@ impl DownloadInstance { } } - pub fn perform_request( + pub fn perform_request( &mut self, - url: S, + url: &str, callbacks: DownloadInstanceOutputCallbacks, ) -> Result<(), String> { let callbacks = Box::into_raw(Box::new(callbacks)); @@ -201,19 +201,16 @@ impl DownloadInstance { } } - pub fn perform_custom_request< - M: IntoCStr, - U: IntoCStr, - HK: IntoCStr, - HV: IntoCStr, - I: Iterator, - >( + pub fn perform_custom_request( &mut self, - method: M, - url: U, + method: &str, + url: &str, headers: I, callbacks: DownloadInstanceInputOutputCallbacks, - ) -> Result { + ) -> Result + where + I: IntoIterator, + { let mut header_keys = vec![]; let mut header_values = vec![]; for (key, value) in headers { diff --git a/rust/src/enterprise.rs b/rust/src/enterprise.rs index 7c2aad19f6..68ad069cb1 100644 --- a/rust/src/enterprise.rs +++ b/rust/src/enterprise.rs @@ -66,7 +66,7 @@ pub fn checkout_license( .map_err(|_| EnterpriseCheckoutError::NoUsername)?; let password = std::env::var("BN_ENTERPRISE_PASSWORD") .map_err(|_| EnterpriseCheckoutError::NoPassword)?; - if !authenticate_server_with_credentials(username, password, true) { + if !authenticate_server_with_credentials(&username, &password, true) { return Err(EnterpriseCheckoutError::NotAuthenticated); } } @@ -120,7 +120,7 @@ pub fn server_url() -> String { unsafe { BnString::into_string(binaryninjacore_sys::BNGetEnterpriseServerUrl()) } } -pub fn set_server_url(url: S) -> Result<(), ()> { +pub fn set_server_url(url: &str) -> Result<(), ()> { let url = url.to_cstr(); let result = unsafe { binaryninjacore_sys::BNSetEnterpriseServerUrl( @@ -183,11 +183,11 @@ pub fn is_server_license_still_activated() -> bool { unsafe { binaryninjacore_sys::BNIsEnterpriseServerLicenseStillActivated() } } -pub fn authenticate_server_with_credentials(username: U, password: P, remember: bool) -> bool -where - U: IntoCStr, - P: IntoCStr, -{ +pub fn authenticate_server_with_credentials( + username: &str, + password: &str, + remember: bool, +) -> bool { let username = username.to_cstr(); let password = password.to_cstr(); unsafe { @@ -199,7 +199,7 @@ where } } -pub fn authenticate_server_with_method(method: S, remember: bool) -> bool { +pub fn authenticate_server_with_method(method: &str, remember: bool) -> bool { let method = method.to_cstr(); unsafe { binaryninjacore_sys::BNAuthenticateEnterpriseServerWithMethod( diff --git a/rust/src/external_library.rs b/rust/src/external_library.rs index 4f6e0e84ae..148fd030f6 100644 --- a/rust/src/external_library.rs +++ b/rust/src/external_library.rs @@ -166,7 +166,7 @@ impl ExternalLocation { /// Set the symbol pointed to by this ExternalLocation. /// ExternalLocations must have a valid target address and/or symbol set. - pub fn set_target_symbol(&self, symbol: Option) -> bool { + pub fn set_target_symbol(&self, symbol: Option<&str>) -> bool { match symbol { Some(sym) => { let raw_sym = sym.to_cstr(); diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index deec36f0c8..d4de13a264 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -52,7 +52,7 @@ impl FileMetadata { Self::ref_from_raw(unsafe { BNCreateFileMetadata() }) } - pub fn with_filename(name: S) -> Ref { + pub fn with_filename(name: &str) -> Ref { let ret = FileMetadata::new(); ret.set_filename(name); ret @@ -75,7 +75,7 @@ impl FileMetadata { } } - pub fn set_filename(&self, name: S) { + pub fn set_filename(&self, name: &str) { let name = name.to_cstr(); unsafe { @@ -107,7 +107,7 @@ impl FileMetadata { self.is_database_backed_for_view_type("") } - pub fn is_database_backed_for_view_type(&self, view_type: S) -> bool { + pub fn is_database_backed_for_view_type(&self, view_type: &str) -> bool { let view_type = view_type.to_cstr(); unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } @@ -121,11 +121,11 @@ impl FileMetadata { let result = func(); match result { Ok(t) => { - self.commit_undo_actions(undo); + self.commit_undo_actions(&undo); Ok(t) } Err(e) => { - self.revert_undo_actions(undo); + self.revert_undo_actions(&undo); Err(e) } } @@ -135,14 +135,14 @@ impl FileMetadata { unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } - pub fn commit_undo_actions(&self, id: S) { + pub fn commit_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { BNCommitUndoActions(self.handle, id.as_ref().as_ptr() as *const _); } } - pub fn revert_undo_actions(&self, id: S) { + pub fn revert_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { BNRevertUndoActions(self.handle, id.as_ref().as_ptr() as *const _); @@ -169,7 +169,7 @@ impl FileMetadata { unsafe { BNGetCurrentOffset(self.handle) } } - pub fn navigate_to(&self, view: S, offset: u64) -> Result<(), ()> { + pub fn navigate_to(&self, view: &str, offset: u64) -> Result<(), ()> { let view = view.to_cstr(); unsafe { @@ -181,7 +181,7 @@ impl FileMetadata { } } - pub fn view_of_type(&self, view: S) -> Option> { + pub fn view_of_type(&self, view: &str) -> Option> { let view = view.to_cstr(); unsafe { @@ -226,7 +226,7 @@ impl FileMetadata { } // TODO: Pass settings? - pub fn create_database_with_progress( + pub fn create_database_with_progress( &self, file_path: impl AsRef, mut progress: P, @@ -256,14 +256,11 @@ impl FileMetadata { unsafe { BNSaveAutoSnapshot(raw_view.handle, ptr::null_mut() as *mut _) } } - pub fn open_database_for_configuration( - &self, - filename: S, - ) -> Result, ()> { - let filename = filename.to_cstr(); + pub fn open_database_for_configuration(&self, file: &Path) -> Result, ()> { + let file = file.to_cstr(); unsafe { let bv = - BNOpenDatabaseForConfiguration(self.handle, filename.as_ref().as_ptr() as *const _); + BNOpenDatabaseForConfiguration(self.handle, file.as_ref().as_ptr() as *const _); if bv.is_null() { Err(()) @@ -273,11 +270,9 @@ impl FileMetadata { } } - pub fn open_database(&self, filename: S) -> Result, ()> { - let filename = filename.to_cstr(); - let filename_ptr = filename.as_ptr(); - - let view = unsafe { BNOpenExistingDatabase(self.handle, filename_ptr) }; + pub fn open_database(&self, file: &Path) -> Result, ()> { + let file = file.to_cstr(); + let view = unsafe { BNOpenExistingDatabase(self.handle, file.as_ptr()) }; if view.is_null() { Err(()) @@ -286,18 +281,17 @@ impl FileMetadata { } } - pub fn open_database_with_progress( + pub fn open_database_with_progress( &self, - filename: S, + file: &Path, mut progress: P, ) -> Result, ()> { - let filename = filename.to_cstr(); - let filename_ptr = filename.as_ptr(); + let file = file.to_cstr(); let view = unsafe { BNOpenExistingDatabaseWithProgress( self.handle, - filename_ptr, + file.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), ) diff --git a/rust/src/function.rs b/rust/src/function.rs index 5ebb84f6d7..c1c29873ed 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -372,7 +372,7 @@ impl Function { unsafe { BnString::into_string(BNGetFunctionComment(self.handle)) } } - pub fn set_comment(&self, comment: S) { + pub fn set_comment(&self, comment: &str) { let raw = comment.to_cstr(); unsafe { @@ -394,7 +394,7 @@ impl Function { unsafe { BnString::into_string(BNGetCommentForAddress(self.handle, addr)) } } - pub fn set_comment_at(&self, addr: u64, comment: S) { + pub fn set_comment_at(&self, addr: u64, comment: &str) { let raw = comment.to_cstr(); unsafe { @@ -1103,10 +1103,10 @@ impl Function { /// let crash = bv.create_tag_type("Crashes", "🎯"); /// fun.add_tag(&crash, "Nullpointer dereference", Some(0x1337), false, None); /// ``` - pub fn add_tag( + pub fn add_tag( &self, tag_type: &TagType, - data: S, + data: &str, addr: Option, user: bool, arch: Option, @@ -1707,7 +1707,7 @@ impl Function { operand: usize, display_type: IntegerDisplayType, arch: Option, - enum_display_typeid: Option, + enum_display_typeid: Option<&str>, ) { let arch = arch.unwrap_or_else(|| self.arch()); let enum_display_typeid = enum_display_typeid.map(IntoCStr::to_cstr); diff --git a/rust/src/headless.rs b/rust/src/headless.rs index 1e56321b0c..5910cd85e6 100644 --- a/rust/src/headless.rs +++ b/rust/src/headless.rs @@ -212,7 +212,7 @@ pub fn init_with_opts(options: InitializationOptions) -> Result<(), Initializati } } - if let Some(license) = options.license { + if let Some(license) = &options.license { // We were given a license override, use it! set_license(Some(license)); } diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs index 8f7e9d81d4..9c2182278d 100644 --- a/rust/src/high_level_il/operation.rs +++ b/rust/src/high_level_il/operation.rs @@ -20,7 +20,7 @@ impl GotoLabel { unsafe { BnString::into_string(BNGetGotoLabelName(self.function.handle, self.target)) } } - fn set_name(&self, name: S) { + fn set_name(&self, name: &str) { let raw = name.to_cstr(); unsafe { BNSetUserGotoLabelName( @@ -327,7 +327,7 @@ impl LiftedLabel { self.target.name() } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: &str) { self.target.set_name(name) } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8d8fae13ef..7056e529a6 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -469,11 +469,18 @@ impl VersionInfo { pub(crate) fn free_raw(value: BNVersionInfo) { unsafe { BnString::free_raw(value.channel) }; } +} + +impl TryFrom<&str> for VersionInfo { + type Error = (); - pub fn from_string(string: S) -> Self { - let string = string.to_cstr(); + fn try_from(value: &str) -> Result { + let string = value.to_cstr(); let result = unsafe { BNParseVersionString(string.as_ptr()) }; - Self::from_owned_raw(result) + if result.build == 0 && result.channel.is_null() && result.major == 0 && result.minor == 0 { + return Err(()); + } + Ok(Self::from_owned_raw(result)) } } @@ -529,13 +536,13 @@ pub fn license_count() -> i32 { /// 1. Check the BN_LICENSE environment variable /// 2. Check the Binary Ninja user directory for license.dat #[cfg(not(feature = "demo"))] -pub fn set_license(license: Option) { +pub fn set_license(license: Option<&str>) { let license = license.unwrap_or_default().to_cstr(); unsafe { BNSetLicense(license.as_ptr()) } } #[cfg(feature = "demo")] -pub fn set_license(_license: Option) {} +pub fn set_license(_license: Option<&str>) {} pub fn product() -> String { unsafe { BnString::into_string(BNGetProduct()) } @@ -554,8 +561,8 @@ pub fn is_ui_enabled() -> bool { unsafe { BNIsUIEnabled() } } -pub fn is_database(filename: S) -> bool { - let filename = filename.to_cstr(); +pub fn is_database(file: &Path) -> bool { + let filename = file.to_cstr(); unsafe { BNIsDatabase(filename.as_ptr()) } } @@ -583,12 +590,12 @@ pub fn plugin_ui_abi_minimum_version() -> u32 { BN_MINIMUM_UI_ABI_VERSION } -pub fn add_required_plugin_dependency(name: S) { +pub fn add_required_plugin_dependency(name: &str) { let raw_name = name.to_cstr(); unsafe { BNAddRequiredPluginDependency(raw_name.as_ptr()) }; } -pub fn add_optional_plugin_dependency(name: S) { +pub fn add_optional_plugin_dependency(name: &str) { let raw_name = name.to_cstr(); unsafe { BNAddOptionalPluginDependency(raw_name.as_ptr()) }; } diff --git a/rust/src/medium_level_il/function.rs b/rust/src/medium_level_il/function.rs index 0b88c16635..bdbe315945 100644 --- a/rust/src/medium_level_il/function.rs +++ b/rust/src/medium_level_il/function.rs @@ -121,11 +121,11 @@ impl MediumLevelILFunction { unsafe { Array::new(raw_instr_idxs, count, self.to_owned()) } } - pub fn create_user_stack_var<'a, S: IntoCStr, C: Into>>( + pub fn create_user_stack_var<'a, C: Into>>( self, offset: i64, var_type: C, - name: S, + name: &str, ) { let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); let name = name.to_cstr(); @@ -143,11 +143,11 @@ impl MediumLevelILFunction { unsafe { BNDeleteUserStackVariable(self.function().handle, offset) } } - pub fn create_user_var<'a, S: IntoCStr, C: Into>>( + pub fn create_user_var<'a, C: Into>>( &self, var: &Variable, var_type: C, - name: S, + name: &str, ignore_disjoint_uses: bool, ) { let raw_var = BNVariable::from(var); @@ -273,11 +273,11 @@ impl MediumLevelILFunction { Ok(()) } - pub fn create_auto_stack_var<'a, T: Into>, S: IntoCStr>( + pub fn create_auto_stack_var<'a, T: Into>>( &self, offset: i64, var_type: T, - name: S, + name: &str, ) { let mut owned_raw_var_ty = Conf::<&Type>::into_raw(var_type.into()); let name = name.to_cstr(); @@ -295,11 +295,11 @@ impl MediumLevelILFunction { unsafe { BNDeleteAutoStackVariable(self.function().handle, offset) } } - pub fn create_auto_var<'a, S: IntoCStr, C: Into>>( + pub fn create_auto_var<'a, C: Into>>( &self, var: &Variable, var_type: C, - name: S, + name: &str, ignore_disjoint_uses: bool, ) { let raw_var = BNVariable::from(var); diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index 2ccd9d5249..6cf1cbce57 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -267,7 +267,7 @@ impl Metadata { Ok(Some(unsafe { Self::ref_from_raw(ptr) })) } - pub fn get(&self, key: S) -> Result>, ()> { + pub fn get(&self, key: &str) -> Result>, ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -287,7 +287,7 @@ impl Metadata { Ok(()) } - pub fn insert(&self, key: S, value: &Metadata) -> Result<(), ()> { + pub fn insert(&self, key: &str, value: &Metadata) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } @@ -305,7 +305,7 @@ impl Metadata { Ok(()) } - pub fn remove_key(&self, key: S) -> Result<(), ()> { + pub fn remove_key(&self, key: &str) -> Result<(), ()> { if self.get_type() != MetadataType::KeyValueDataType { return Err(()); } diff --git a/rust/src/platform.rs b/rust/src/platform.rs index d7d3b99027..013f709d6a 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -82,7 +82,7 @@ impl Platform { Ref::new(Self { handle }) } - pub fn by_name(name: S) -> Option> { + pub fn by_name(name: &str) -> Option> { let raw_name = name.to_cstr(); unsafe { let res = BNGetPlatformByName(raw_name.as_ptr()); @@ -113,7 +113,7 @@ impl Platform { } } - pub fn list_by_os(name: S) -> Array { + pub fn list_by_os(name: &str) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -124,7 +124,7 @@ impl Platform { } } - pub fn list_by_os_and_arch(name: S, arch: &CoreArchitecture) -> Array { + pub fn list_by_os_and_arch(name: &str, arch: &CoreArchitecture) -> Array { let raw_name = name.to_cstr(); unsafe { @@ -145,7 +145,7 @@ impl Platform { } } - pub fn new(arch: &A, name: S) -> Ref { + pub fn new(arch: &A, name: &str) -> Ref { let name = name.to_cstr(); unsafe { let handle = BNCreatePlatform(arch.as_ref().handle, name.as_ptr()); @@ -173,7 +173,7 @@ impl Platform { unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } - pub fn get_type_libraries_by_name(&self, name: T) -> Array { + pub fn get_type_libraries_by_name(&self, name: &str) -> Array { let mut count = 0; let name = name.to_cstr(); let result = @@ -182,9 +182,8 @@ impl Platform { unsafe { Array::new(result, count, ()) } } - pub fn register_os(&self, os: S) { + pub fn register_os(&self, os: &str) { let os = os.to_cstr(); - unsafe { BNRegisterPlatform(os.as_ptr(), self.handle); } diff --git a/rust/src/project.rs b/rust/src/project.rs index 7b6a263ea6..8b5f594a33 100644 --- a/rust/src/project.rs +++ b/rust/src/project.rs @@ -35,21 +35,23 @@ impl Project { unsafe { Array::new(result, count, ()) } } + // TODO: Path here is actually local path? /// Create a new project /// /// * `path` - Path to the project directory (.bnpr) /// * `name` - Name of the new project - pub fn create(path: P, name: S) -> Option> { + pub fn create(path: &str, name: &str) -> Option> { let path_raw = path.to_cstr(); let name_raw = name.to_cstr(); let handle = unsafe { BNCreateProject(path_raw.as_ptr(), name_raw.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) } + // TODO: Path here is actually local path? /// Open an existing project /// /// * `path` - Path to the project directory (.bnpr) or project metadata file (.bnpm) - pub fn open_project(path: P) -> Option> { + pub fn open_project(path: &str) -> Option> { let path_raw = path.to_cstr(); let handle = unsafe { BNOpenProject(path_raw.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { Self::ref_from_raw(h) }) @@ -94,7 +96,7 @@ impl Project { } /// Set the name of the project - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: &str) { let value = value.to_cstr(); unsafe { BNProjectSetName(self.handle.as_ptr(), value.as_ptr()) } } @@ -105,13 +107,13 @@ impl Project { } /// Set the description of the project - pub fn set_description(&self, value: S) { + pub fn set_description(&self, value: &str) { let value = value.to_cstr(); unsafe { BNProjectSetDescription(self.handle.as_ptr(), value.as_ptr()) } } /// Retrieves metadata stored under a key from the project - pub fn query_metadata(&self, key: S) -> Ref { + pub fn query_metadata(&self, key: &str) -> Ref { let key = key.to_cstr(); let result = unsafe { BNProjectQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; unsafe { Metadata::ref_from_raw(result) } @@ -121,13 +123,13 @@ impl Project { /// /// * `key` - Key under which to store the Metadata object /// * `value` - Object to store - pub fn store_metadata(&self, key: S, value: &Metadata) -> bool { + pub fn store_metadata(&self, key: &str, value: &Metadata) -> bool { let key_raw = key.to_cstr(); unsafe { BNProjectStoreMetadata(self.handle.as_ptr(), key_raw.as_ptr(), value.handle) } } /// Removes the metadata associated with this `key` from the project - pub fn remove_metadata(&self, key: S) { + pub fn remove_metadata(&self, key: &str) { let key_raw = key.to_cstr(); unsafe { BNProjectRemoveMetadata(self.handle.as_ptr(), key_raw.as_ptr()) } } @@ -141,16 +143,12 @@ impl Project { /// * `path` - Path to folder on disk /// * `parent` - Parent folder in the project that will contain the new contents /// * `description` - Description for created root folder - pub fn create_folder_from_path( + pub fn create_folder_from_path( &self, - path: P, + path: &str, parent: Option<&ProjectFolder>, - description: D, - ) -> Result, ()> - where - P: IntoCStr, - D: IntoCStr, - { + description: &str, + ) -> Result, ()> { self.create_folder_from_path_with_progress(path, parent, description, NoProgressCallback) } @@ -160,16 +158,14 @@ impl Project { /// * `parent` - Parent folder in the project that will contain the new contents /// * `description` - Description for created root folder /// * `progress` - [`ProgressCallback`] that will be called as the [`ProjectFolder`] is being created - pub fn create_folder_from_path_with_progress( + pub fn create_folder_from_path_with_progress( &self, - path: P, + path: &str, parent: Option<&ProjectFolder>, - description: D, + description: &str, mut progress: PC, ) -> Result, ()> where - P: IntoCStr, - D: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -194,16 +190,12 @@ impl Project { /// * `parent` - Parent folder in the project that will contain the new folder /// * `name` - Name for the created folder /// * `description` - Description for created folder - pub fn create_folder( + pub fn create_folder( &self, parent: Option<&ProjectFolder>, - name: N, - description: D, - ) -> Result, ()> - where - N: IntoCStr, - D: IntoCStr, - { + name: &str, + description: &str, + ) -> Result, ()> { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); @@ -224,18 +216,13 @@ impl Project { /// * `name` - Name for the created folder /// * `description` - Description for created folder /// * `id` - id unique ID - pub unsafe fn create_folder_unsafe( + pub unsafe fn create_folder_unsafe( &self, parent: Option<&ProjectFolder>, - name: N, - description: D, - id: I, - ) -> Result, ()> - where - N: IntoCStr, - D: IntoCStr, - I: IntoCStr, - { + name: &str, + description: &str, + id: &str, + ) -> Result, ()> { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); let parent_ptr = parent.map(|p| p.handle.as_ptr()).unwrap_or(null_mut()); @@ -264,7 +251,7 @@ impl Project { } /// Retrieve a folder in the project by unique folder `id` - pub fn folder_by_id(&self, id: S) -> Option> { + pub fn folder_by_id(&self, id: &str) -> Option> { let raw_id = id.to_cstr(); let result = unsafe { BNProjectGetFolderById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; @@ -282,17 +269,17 @@ impl Project { /// /// * `folder` - [`ProjectFolder`] to delete recursively /// * `progress` - [`ProgressCallback`] that will be called as objects get deleted - pub fn delete_folder_with_progress( + pub fn delete_folder_with_progress( &self, folder: &ProjectFolder, - mut progress: P, + mut progress: PC, ) -> Result<(), ()> { let result = unsafe { BNProjectDeleteFolder( self.handle.as_ptr(), folder.handle.as_ptr(), - &mut progress as *mut P as *mut c_void, - Some(P::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, + Some(PC::cb_progress_callback), ) }; @@ -313,18 +300,13 @@ impl Project { /// * `folder` - Folder to place the created file in /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file - pub fn create_file_from_path( + pub fn create_file_from_path( &self, - path: P, + path: &str, folder: Option<&ProjectFolder>, - name: N, - description: D, - ) -> Result, ()> - where - P: IntoCStr, - N: IntoCStr, - D: IntoCStr, - { + name: &str, + description: &str, + ) -> Result, ()> { self.create_file_from_path_with_progress( path, folder, @@ -341,18 +323,15 @@ impl Project { /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file /// * `progress` - [`ProgressCallback`] that will be called as the [`ProjectFile`] is being added - pub fn create_file_from_path_with_progress( + pub fn create_file_from_path_with_progress( &self, - path: P, + path: &str, folder: Option<&ProjectFolder>, - name: N, - description: D, + name: &str, + description: &str, mut progress: PC, ) -> Result, ()> where - P: IntoCStr, - N: IntoCStr, - D: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -382,21 +361,15 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - pub unsafe fn create_file_from_path_unsafe( + pub unsafe fn create_file_from_path_unsafe( &self, - path: P, + path: &str, folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: &str, + description: &str, + id: &str, creation_time: SystemTime, - ) -> Result, ()> - where - P: IntoCStr, - N: IntoCStr, - D: IntoCStr, - I: IntoCStr, - { + ) -> Result, ()> { self.create_file_from_path_unsafe_with_progress( path, folder, @@ -418,21 +391,17 @@ impl Project { /// * `creation_time` - Creation time of the file /// * `progress` - [`ProgressCallback`] that will be called as the [`ProjectFile`] is being created #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_from_path_unsafe_with_progress( + pub unsafe fn create_file_from_path_unsafe_with_progress( &self, - path: P, + path: &str, folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: &str, + description: &str, + id: &str, creation_time: SystemTime, mut progress: PC, ) -> Result, ()> where - P: IntoCStr, - N: IntoCStr, - D: IntoCStr, - I: IntoCStr, PC: ProgressCallback, { let path_raw = path.to_cstr(); @@ -463,17 +432,13 @@ impl Project { /// * `folder` - Folder to place the created file in /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file - pub fn create_file( + pub fn create_file( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - ) -> Result, ()> - where - N: IntoCStr, - D: IntoCStr, - { + name: &str, + description: &str, + ) -> Result, ()> { self.create_file_with_progress(contents, folder, name, description, NoProgressCallback) } @@ -484,18 +449,16 @@ impl Project { /// * `name` - Name to assign to the created file /// * `description` - Description to assign to the created file /// * `progress` - [`ProgressCallback`] that will be called as the [`ProjectFile`] is being created - pub fn create_file_with_progress( + pub fn create_file_with_progress( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - mut progress: P, + name: &str, + description: &str, + mut progress: PC, ) -> Result, ()> where - N: IntoCStr, - D: IntoCStr, - P: ProgressCallback, + PC: ProgressCallback, { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); @@ -509,8 +472,8 @@ impl Project { folder_ptr, name_raw.as_ptr(), description_raw.as_ptr(), - &mut progress as *mut P as *mut c_void, - Some(P::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, + Some(PC::cb_progress_callback), ); Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } @@ -524,20 +487,15 @@ impl Project { /// * `description` - Description to assign to the created file /// * `id` - id unique ID /// * `creation_time` - Creation time of the file - pub unsafe fn create_file_unsafe( + pub unsafe fn create_file_unsafe( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: &str, + description: &str, + id: &str, creation_time: SystemTime, - ) -> Result, ()> - where - N: IntoCStr, - D: IntoCStr, - I: IntoCStr, - { + ) -> Result, ()> { self.create_file_unsafe_with_progress( contents, folder, @@ -559,21 +517,18 @@ impl Project { /// * `creation_time` - Creation time of the file /// * `progress` - [`ProgressCallback`] that will be called as the [`ProjectFile`] is being created #[allow(clippy::too_many_arguments)] - pub unsafe fn create_file_unsafe_with_progress( + pub unsafe fn create_file_unsafe_with_progress( &self, contents: &[u8], folder: Option<&ProjectFolder>, - name: N, - description: D, - id: I, + name: &str, + description: &str, + id: &str, creation_time: SystemTime, - mut progress: P, + mut progress: PC, ) -> Result, ()> where - N: IntoCStr, - D: IntoCStr, - I: IntoCStr, - P: ProgressCallback, + PC: ProgressCallback, { let name_raw = name.to_cstr(); let description_raw = description.to_cstr(); @@ -590,8 +545,8 @@ impl Project { description_raw.as_ptr(), id_raw.as_ptr(), systime_to_bntime(creation_time).unwrap(), - &mut progress as *mut P as *mut c_void, - Some(P::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, + Some(PC::cb_progress_callback), ); Ok(ProjectFile::ref_from_raw(NonNull::new(result).ok_or(())?)) } @@ -606,7 +561,7 @@ impl Project { } /// Retrieve a file in the project by unique `id` - pub fn file_by_id(&self, id: S) -> Option> { + pub fn file_by_id(&self, id: &str) -> Option> { let raw_id = id.to_cstr(); let result = unsafe { BNProjectGetFileById(self.handle.as_ptr(), raw_id.as_ptr()) }; let handle = NonNull::new(result)?; @@ -614,7 +569,7 @@ impl Project { } /// Retrieve a file in the project by the `path` on disk - pub fn file_by_path(&self, path: S) -> Option> { + pub fn file_by_path(&self, path: &str) -> Option> { let path_raw = path.to_cstr(); let result = unsafe { BNProjectGetFileByPathOnDisk(self.handle.as_ptr(), path_raw.as_ptr()) }; diff --git a/rust/src/project/file.rs b/rust/src/project/file.rs index 4a1d6fec53..3b3e48f7af 100644 --- a/rust/src/project/file.rs +++ b/rust/src/project/file.rs @@ -9,6 +9,7 @@ use binaryninjacore_sys::{ BNProjectFileSetFolder, BNProjectFileSetName, }; use std::fmt::Debug; +use std::path::Path; use std::ptr::{null_mut, NonNull}; use std::time::SystemTime; @@ -56,7 +57,7 @@ impl ProjectFile { } /// Set the name of this file - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFileSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -67,7 +68,7 @@ impl ProjectFile { } /// Set the description of this file - pub fn set_description(&self, value: S) -> bool { + pub fn set_description(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFileSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -92,8 +93,8 @@ impl ProjectFile { /// Export this file to disk, `true' if the export succeeded /// - /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { + /// * `dest` - Destination file path for the exported contents, passing a directory will append the file name. + pub fn export(&self, dest: &Path) -> bool { let dest_raw = dest.to_cstr(); unsafe { BNProjectFileExport(self.handle.as_ptr(), dest_raw.as_ptr()) } } diff --git a/rust/src/project/folder.rs b/rust/src/project/folder.rs index acb663fb16..d5d95e7641 100644 --- a/rust/src/project/folder.rs +++ b/rust/src/project/folder.rs @@ -10,6 +10,7 @@ use binaryninjacore_sys::{ }; use std::ffi::c_void; use std::fmt::Debug; +use std::path::Path; use std::ptr::{null_mut, NonNull}; #[repr(transparent)] @@ -46,7 +47,7 @@ impl ProjectFolder { } /// Set the name of this folder - pub fn set_name(&self, value: S) -> bool { + pub fn set_name(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -57,7 +58,7 @@ impl ProjectFolder { } /// Set the description of this folder - pub fn set_description(&self, value: S) -> bool { + pub fn set_description(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } @@ -74,22 +75,19 @@ impl ProjectFolder { unsafe { BNProjectFolderSetParent(self.handle.as_ptr(), folder_handle) } } - // TODO: Take Path? /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents - pub fn export(&self, dest: S) -> bool { + pub fn export(&self, dest: &Path) -> bool { self.export_with_progress(dest, NoProgressCallback) } - // TODO: Take Path? /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents /// * `progress` - [`ProgressCallback`] that will be called as contents are exporting - pub fn export_with_progress(&self, dest: S, mut progress: P) -> bool + pub fn export_with_progress

(&self, dest: &Path, mut progress: P) -> bool where - S: IntoCStr, P: ProgressCallback, { let dest_raw = dest.to_cstr(); diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index 756c76bfaf..2b24279bfc 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -402,9 +402,8 @@ unsafe impl RefCountable for CoreRelocationHandler { } } -pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: S, func: F) +pub(crate) fn register_relocation_handler(arch: &CoreArchitecture, name: &str, func: F) where - S: IntoCStr, R: 'static + RelocationHandler> + Send + Sync + Sized, F: FnOnce(CustomRelocationHandlerHandle, CoreRelocationHandler) -> R, { diff --git a/rust/src/render_layer.rs b/rust/src/render_layer.rs index 3fd94a3ac8..08553552a2 100644 --- a/rust/src/render_layer.rs +++ b/rust/src/render_layer.rs @@ -61,8 +61,8 @@ impl Default for RenderLayerDefaultState { } /// Register a [`RenderLayer`] with the API. -pub fn register_render_layer( - name: S, +pub fn register_render_layer( + name: &str, render_layer: T, default_state: RenderLayerDefaultState, ) -> (&'static mut T, CoreRenderLayer) { @@ -299,7 +299,7 @@ impl CoreRenderLayer { unsafe { Array::new(result, count, ()) } } - pub fn render_layer_by_name(name: S) -> Option { + pub fn render_layer_by_name(name: &str) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) }; NonNull::new(result).map(Self::from_raw) diff --git a/rust/src/repository.rs b/rust/src/repository.rs index 8d9a8f403e..a29be323d7 100644 --- a/rust/src/repository.rs +++ b/rust/src/repository.rs @@ -3,6 +3,7 @@ mod plugin; use std::ffi::c_char; use std::fmt::Debug; +use std::path::{Path, PathBuf}; use std::ptr::NonNull; use binaryninjacore_sys::*; @@ -38,10 +39,11 @@ impl Repository { } /// String local path to store the given plugin repository - pub fn path(&self) -> String { + pub fn path(&self) -> PathBuf { let result = unsafe { BNRepositoryGetRepoPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::into_string(result as *mut c_char) } + let result_str = unsafe { BnString::into_string(result as *mut c_char) }; + PathBuf::from(result_str) } /// List of RepoPlugin objects contained within this repository @@ -52,18 +54,18 @@ impl Repository { unsafe { Array::new(result, count, ()) } } - pub fn plugin_by_path(&self, path: S) -> Option> { + pub fn plugin_by_path(&self, path: &Path) -> Option> { let path = path.to_cstr(); let result = unsafe { BNRepositoryGetPluginByPath(self.handle.as_ptr(), path.as_ptr()) }; NonNull::new(result).map(|h| unsafe { RepositoryPlugin::ref_from_raw(h) }) } - // TODO: Make this a PathBuf? /// String full path the repository - pub fn full_path(&self) -> String { + pub fn full_path(&self) -> PathBuf { let result = unsafe { BNRepositoryGetPluginsPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::into_string(result as *mut c_char) } + let result_str = unsafe { BnString::into_string(result as *mut c_char) }; + PathBuf::from(result_str) } } diff --git a/rust/src/repository/manager.rs b/rust/src/repository/manager.rs index 42d8aa42e5..cf0118adce 100644 --- a/rust/src/repository/manager.rs +++ b/rust/src/repository/manager.rs @@ -8,6 +8,7 @@ use binaryninjacore_sys::{ BNRepositoryManagerGetDefaultRepository, BNRepositoryManagerGetRepositories, }; use std::fmt::Debug; +use std::path::Path; use std::ptr::NonNull; /// Keeps track of all the repositories and keeps the `enabled_plugins.json` @@ -28,7 +29,7 @@ impl RepositoryManager { Ref::new(Self { handle }) } - pub fn new(plugins_path: S) -> Ref { + pub fn new(plugins_path: &str) -> Ref { let plugins_path = plugins_path.to_cstr(); let result = unsafe { BNCreateRepositoryManager(plugins_path.as_ptr()) }; unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) } @@ -59,7 +60,7 @@ impl RepositoryManager { /// * `repository_path` - path to where the repository will be stored on disk locally /// /// Returns true if the repository was successfully added, false otherwise. - pub fn add_repository(&self, url: U, repository_path: P) -> bool { + pub fn add_repository(&self, url: &str, repository_path: &Path) -> bool { let url = url.to_cstr(); let repo_path = repository_path.to_cstr(); unsafe { @@ -67,7 +68,7 @@ impl RepositoryManager { } } - pub fn repository_by_path(&self, path: P) -> Option { + pub fn repository_by_path(&self, path: &Path) -> Option { let path = path.to_cstr(); let result = unsafe { BNRepositoryGetRepositoryByPath(self.handle.as_ptr(), path.as_ptr()) }; diff --git a/rust/src/repository/plugin.rs b/rust/src/repository/plugin.rs index 82309e7935..e0ab96792d 100644 --- a/rust/src/repository/plugin.rs +++ b/rust/src/repository/plugin.rs @@ -5,6 +5,7 @@ use crate::VersionInfo; use binaryninjacore_sys::*; use std::ffi::c_char; use std::fmt::Debug; +use std::path::PathBuf; use std::ptr::NonNull; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -112,17 +113,19 @@ impl RepositoryPlugin { } /// Relative path from the base of the repository to the actual plugin - pub fn path(&self) -> String { + pub fn path(&self) -> PathBuf { let result = unsafe { BNPluginGetPath(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::into_string(result as *mut c_char) } + let result_str = unsafe { BnString::into_string(result as *mut c_char) }; + PathBuf::from(result_str) } /// Optional sub-directory the plugin code lives in as a relative path from the plugin root - pub fn subdir(&self) -> String { + pub fn subdir(&self) -> PathBuf { let result = unsafe { BNPluginGetSubdir(self.handle.as_ptr()) }; assert!(!result.is_null()); - unsafe { BnString::into_string(result as *mut c_char) } + let result_str = unsafe { BnString::into_string(result as *mut c_char) }; + PathBuf::from(result_str) } /// Dependencies required for installing this plugin diff --git a/rust/src/secrets_provider.rs b/rust/src/secrets_provider.rs index 5924b9fb56..a310b08e65 100644 --- a/rust/src/secrets_provider.rs +++ b/rust/src/secrets_provider.rs @@ -49,7 +49,7 @@ impl CoreSecretsProvider { } /// Retrieve a provider by name - pub fn by_name(name: S) -> Option { + pub fn by_name(name: &str) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetSecretsProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) @@ -62,27 +62,27 @@ impl CoreSecretsProvider { } /// Check if data for a specific key exists, but do not retrieve it - pub fn has_data(&self, key: S) -> bool { + pub fn has_data(&self, key: &str) -> bool { let key = key.to_cstr(); unsafe { BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ptr()) } } /// Retrieve data for the given key, if it exists - pub fn get_data(&self, key: S) -> String { + pub fn get_data(&self, key: &str) -> String { let key = key.to_cstr(); let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) }; unsafe { BnString::into_string(result) } } /// Store data with the given key - pub fn store_data(&self, key: K, value: V) -> bool { + pub fn store_data(&self, key: &str, value: &str) -> bool { let key = key.to_cstr(); let value = value.to_cstr(); unsafe { BNStoreSecretsProviderData(self.handle.as_ptr(), key.as_ptr(), value.as_ptr()) } } /// Delete stored data with the given key - pub fn delete_data(&self, key: S) -> bool { + pub fn delete_data(&self, key: &str) -> bool { let key = key.to_cstr(); unsafe { BNDeleteSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) } } diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 35f7b7a05c..0047f57036 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -44,7 +44,7 @@ impl Settings { Self::new_with_id(GLOBAL_INSTANCE_ID) } - pub fn new_with_id(instance_id: S) -> Ref { + pub fn new_with_id(instance_id: &str) -> Ref { let instance_id = instance_id.to_cstr(); unsafe { let handle = BNCreateSettings(instance_id.as_ptr()); @@ -53,7 +53,7 @@ impl Settings { } } - pub fn set_resource_id(&self, resource_id: S) { + pub fn set_resource_id(&self, resource_id: &str) { let resource_id = resource_id.to_cstr(); unsafe { BNSettingsSetResourceId(self.handle, resource_id.as_ptr()) }; } @@ -62,20 +62,16 @@ impl Settings { unsafe { BnString::into_string(BNSettingsSerializeSchema(self.handle)) } } - pub fn deserialize_schema(&self, schema: S) -> bool { + pub fn deserialize_schema(&self, schema: &str) -> bool { self.deserialize_schema_with_scope(schema, SettingsScope::SettingsAutoScope) } - pub fn deserialize_schema_with_scope( - &self, - schema: S, - scope: SettingsScope, - ) -> bool { + pub fn deserialize_schema_with_scope(&self, schema: &str, scope: SettingsScope) -> bool { let schema = schema.to_cstr(); unsafe { BNSettingsDeserializeSchema(self.handle, schema.as_ptr(), scope, true) } } - pub fn contains(&self, key: S) -> bool { + pub fn contains(&self, key: &str) -> bool { let key = key.to_cstr(); unsafe { BNSettingsContains(self.handle, key.as_ptr()) } @@ -90,11 +86,11 @@ impl Settings { // TODO Update the settings API to take an optional BinaryView or Function. Separate functions or...? - pub fn get_bool(&self, key: S) -> bool { + pub fn get_bool(&self, key: &str) -> bool { self.get_bool_with_opts(key, &mut QueryOptions::default()) } - pub fn get_bool_with_opts(&self, key: S, options: &mut QueryOptions) -> bool { + pub fn get_bool_with_opts(&self, key: &str, options: &mut QueryOptions) -> bool { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -115,11 +111,11 @@ impl Settings { } } - pub fn get_double(&self, key: S) -> f64 { + pub fn get_double(&self, key: &str) -> f64 { self.get_double_with_opts(key, &mut QueryOptions::default()) } - pub fn get_double_with_opts(&self, key: S, options: &mut QueryOptions) -> f64 { + pub fn get_double_with_opts(&self, key: &str, options: &mut QueryOptions) -> f64 { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -140,11 +136,11 @@ impl Settings { } } - pub fn get_integer(&self, key: S) -> u64 { + pub fn get_integer(&self, key: &str) -> u64 { self.get_integer_with_opts(key, &mut QueryOptions::default()) } - pub fn get_integer_with_opts(&self, key: S, options: &mut QueryOptions) -> u64 { + pub fn get_integer_with_opts(&self, key: &str, options: &mut QueryOptions) -> u64 { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -165,11 +161,11 @@ impl Settings { } } - pub fn get_string(&self, key: S) -> String { + pub fn get_string(&self, key: &str) -> String { self.get_string_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + pub fn get_string_with_opts(&self, key: &str, options: &mut QueryOptions) -> String { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -190,13 +186,13 @@ impl Settings { } } - pub fn get_string_list(&self, key: S) -> Array { + pub fn get_string_list(&self, key: &str) -> Array { self.get_string_list_with_opts(key, &mut QueryOptions::default()) } - pub fn get_string_list_with_opts( + pub fn get_string_list_with_opts( &self, - key: S, + key: &str, options: &mut QueryOptions, ) -> Array { let key = key.to_cstr(); @@ -225,11 +221,11 @@ impl Settings { } } - pub fn get_json(&self, key: S) -> String { + pub fn get_json(&self, key: &str) -> String { self.get_json_with_opts(key, &mut QueryOptions::default()) } - pub fn get_json_with_opts(&self, key: S, options: &mut QueryOptions) -> String { + pub fn get_json_with_opts(&self, key: &str, options: &mut QueryOptions) -> String { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -250,11 +246,11 @@ impl Settings { } } - pub fn set_bool(&self, key: S, value: bool) { + pub fn set_bool(&self, key: &str, value: bool) { self.set_bool_with_opts(key, value, &QueryOptions::default()) } - pub fn set_bool_with_opts(&self, key: S, value: bool, options: &QueryOptions) { + pub fn set_bool_with_opts(&self, key: &str, value: bool, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -276,10 +272,10 @@ impl Settings { } } - pub fn set_double(&self, key: S, value: f64) { + pub fn set_double(&self, key: &str, value: f64) { self.set_double_with_opts(key, value, &QueryOptions::default()) } - pub fn set_double_with_opts(&self, key: S, value: f64, options: &QueryOptions) { + pub fn set_double_with_opts(&self, key: &str, value: f64, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -301,11 +297,11 @@ impl Settings { } } - pub fn set_integer(&self, key: S, value: u64) { + pub fn set_integer(&self, key: &str, value: u64) { self.set_integer_with_opts(key, value, &QueryOptions::default()) } - pub fn set_integer_with_opts(&self, key: S, value: u64, options: &QueryOptions) { + pub fn set_integer_with_opts(&self, key: &str, value: u64, options: &QueryOptions) { let key = key.to_cstr(); let view_ptr = match options.view.as_ref() { Some(view) => view.handle, @@ -327,16 +323,11 @@ impl Settings { } } - pub fn set_string(&self, key: S1, value: S2) { + pub fn set_string(&self, key: &str, value: &str) { self.set_string_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_with_opts( - &self, - key: S1, - value: S2, - options: &QueryOptions, - ) { + pub fn set_string_with_opts(&self, key: &str, value: &str, options: &QueryOptions) { let key = key.to_cstr(); let value = value.to_cstr(); let view_ptr = match options.view.as_ref() { @@ -359,22 +350,18 @@ impl Settings { } } - pub fn set_string_list>( - &self, - key: S1, - value: I, - ) -> bool { + pub fn set_string_list>(&self, key: &str, value: I) -> bool { self.set_string_list_with_opts(key, value, &QueryOptions::default()) } - pub fn set_string_list_with_opts>( + pub fn set_string_list_with_opts>( &self, - key: S1, + key: &str, value: I, options: &QueryOptions, ) -> bool { let key = key.to_cstr(); - let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); + let raw_list: Vec<_> = value.into_iter().map(|s| s.to_cstr()).collect(); let mut raw_list_ptr: Vec<_> = raw_list.iter().map(|s| s.as_ptr()).collect(); let view_ptr = match options.view.as_ref() { @@ -398,16 +385,11 @@ impl Settings { } } - pub fn set_json(&self, key: S1, value: S2) -> bool { + pub fn set_json(&self, key: &str, value: &str) -> bool { self.set_json_with_opts(key, value, &QueryOptions::default()) } - pub fn set_json_with_opts( - &self, - key: S1, - value: S2, - options: &QueryOptions, - ) -> bool { + pub fn set_json_with_opts(&self, key: &str, value: &str, options: &QueryOptions) -> bool { let key = key.to_cstr(); let value = value.to_cstr(); let view_ptr = match options.view.as_ref() { @@ -430,7 +412,7 @@ impl Settings { } } - pub fn get_property_string(&self, key: S, property: S) -> String { + pub fn get_property_string(&self, key: &str, property: &str) -> String { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -442,7 +424,7 @@ impl Settings { } } - pub fn get_property_string_list(&self, key: S, property: S) -> Array { + pub fn get_property_string_list(&self, key: &str, property: &str) -> Array { let key = key.to_cstr(); let property = property.to_cstr(); let mut size: usize = 0; @@ -460,7 +442,7 @@ impl Settings { } } - pub fn update_bool_property(&self, key: S, property: S, value: bool) { + pub fn update_bool_property(&self, key: &str, property: &str, value: bool) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -468,7 +450,7 @@ impl Settings { } } - pub fn update_integer_property(&self, key: S, property: S, value: u64) { + pub fn update_integer_property(&self, key: &str, property: &str, value: u64) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -476,7 +458,7 @@ impl Settings { } } - pub fn update_double_property(&self, key: S, property: S, value: f64) { + pub fn update_double_property(&self, key: &str, property: &str, value: f64) { let key = key.to_cstr(); let property = property.to_cstr(); unsafe { @@ -484,7 +466,7 @@ impl Settings { } } - pub fn update_string_property(&self, key: S, property: S, value: S) { + pub fn update_string_property(&self, key: &str, property: &str, value: &str) { let key = key.to_cstr(); let property = property.to_cstr(); let value = value.to_cstr(); @@ -498,15 +480,15 @@ impl Settings { } } - pub fn update_string_list_property>( + pub fn update_string_list_property>( &self, - key: S, - property: S, + key: &str, + property: &str, value: I, ) { let key = key.to_cstr(); let property = property.to_cstr(); - let raw_list: Vec<_> = value.map(|s| s.to_cstr()).collect(); + let raw_list: Vec<_> = value.into_iter().map(|s| s.to_cstr()).collect(); let mut raw_list_ptr: Vec<_> = raw_list.iter().map(|s| s.as_ptr()).collect(); unsafe { @@ -520,18 +502,14 @@ impl Settings { } } - pub fn register_group(&self, group: S1, title: S2) -> bool { + pub fn register_group(&self, group: &str, title: &str) -> bool { let group = group.to_cstr(); let title = title.to_cstr(); unsafe { BNSettingsRegisterGroup(self.handle, group.as_ptr(), title.as_ptr()) } } - pub fn register_setting_json( - &self, - group: S1, - properties: S2, - ) -> bool { + pub fn register_setting_json(&self, group: &str, properties: &str) -> bool { let group = group.to_cstr(); let properties = properties.to_cstr(); diff --git a/rust/src/tags.rs b/rust/src/tags.rs index e7a2d44d5d..a8c4d5d4b5 100644 --- a/rust/src/tags.rs +++ b/rust/src/tags.rs @@ -42,7 +42,7 @@ impl Tag { Ref::new(Self { handle }) } - pub fn new(t: &TagType, data: S) -> Ref { + pub fn new(t: &TagType, data: &str) -> Ref { let data = data.to_cstr(); unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ptr())) } } @@ -59,7 +59,7 @@ impl Tag { unsafe { TagType::ref_from_raw(BNTagGetType(self.handle)) } } - pub fn set_data(&self, data: S) { + pub fn set_data(&self, data: &str) { let data = data.to_cstr(); unsafe { BNTagSetData(self.handle, data.as_ptr()); @@ -134,7 +134,7 @@ impl TagType { Ref::new(Self { handle }) } - pub fn create(view: &BinaryView, name: N, icon: I) -> Ref { + pub fn create(view: &BinaryView, name: &str, icon: &str) -> Ref { let tag_type = unsafe { Self::ref_from_raw(BNCreateTagType(view.handle)) }; tag_type.set_name(name); tag_type.set_icon(icon); @@ -149,7 +149,7 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetIcon(self.handle)) } } - pub fn set_icon(&self, icon: S) { + pub fn set_icon(&self, icon: &str) { let icon = icon.to_cstr(); unsafe { BNTagTypeSetIcon(self.handle, icon.as_ptr()); @@ -160,7 +160,7 @@ impl TagType { unsafe { BnString::into_string(BNTagTypeGetName(self.handle)) } } - pub fn set_name(&self, name: S) { + pub fn set_name(&self, name: &str) { let name = name.to_cstr(); unsafe { BNTagTypeSetName(self.handle, name.as_ptr()); @@ -179,7 +179,7 @@ impl TagType { unsafe { BNTagTypeGetType(self.handle) } } - pub fn set_type(&self, t: S) { + pub fn set_type(&self, t: &str) { let t = t.to_cstr(); unsafe { BNTagTypeSetName(self.handle, t.as_ptr()); diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index 84e9fdeec5..f4d1087c4e 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -82,9 +82,9 @@ impl TypeArchive { /// Create a Type Archive at the given path and id, returning None if it could not be created. /// /// If the file has already been created and is not a valid type archive this will return `None`. - pub fn create_with_id( + pub fn create_with_id( path: impl AsRef, - id: I, + id: &str, platform: &Platform, ) -> Option> { let raw_path = path.as_ref().to_cstr(); @@ -95,7 +95,7 @@ impl TypeArchive { } /// Get a reference to the Type Archive with the known id, if one exists. - pub fn lookup_by_id(id: S) -> Option> { + pub fn lookup_by_id(id: &str) -> Option> { let id = id.to_cstr(); let handle = unsafe { BNLookupTypeArchiveById(id.as_ptr()) }; NonNull::new(handle).map(|handle| unsafe { TypeArchive::ref_from_raw(handle) }) @@ -104,19 +104,16 @@ impl TypeArchive { /// Get the path to the Type Archive's file pub fn path(&self) -> Option { let result = unsafe { BNGetTypeArchivePath(self.handle.as_ptr()) }; - match result.is_null() { - false => { - let path_str = unsafe { BnString::into_string(result) }; - Some(PathBuf::from(path_str)) - } - true => None, - } + assert!(!result.is_null()); + let path_str = unsafe { BnString::into_string(result) }; + Some(PathBuf::from(path_str)) } /// Get the guid for a Type Archive - pub fn id(&self) -> Option { + pub fn id(&self) -> BnString { let result = unsafe { BNGetTypeArchiveId(self.handle.as_ptr()) }; - (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } } /// Get the associated Platform for a Type Archive @@ -150,7 +147,7 @@ impl TypeArchive { } /// Get the ids of the parents to the given snapshot - pub fn get_snapshot_parent_ids( + pub fn get_snapshot_parent_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -166,7 +163,7 @@ impl TypeArchive { } /// Get the ids of the children to the given snapshot - pub fn get_snapshot_child_ids( + pub fn get_snapshot_child_ids( &self, snapshot: &TypeArchiveSnapshotId, ) -> Option> { @@ -219,7 +216,7 @@ impl TypeArchive { /// * `new_name` - New type name pub fn rename_type(&self, old_name: QualifiedName, new_name: QualifiedName) -> bool { if let Some(id) = self.get_type_id(old_name) { - self.rename_type_by_id(id, new_name) + self.rename_type_by_id(&id, new_name) } else { false } @@ -229,7 +226,7 @@ impl TypeArchive { /// /// * `id` - Old id of type in archive /// * `new_name` - New type name - pub fn rename_type_by_id(&self, id: S, new_name: QualifiedName) -> bool { + pub fn rename_type_by_id(&self, id: &str, new_name: QualifiedName) -> bool { let id = id.to_cstr(); let raw_name = QualifiedName::into_raw(new_name); let result = @@ -241,14 +238,14 @@ impl TypeArchive { /// Delete an existing type in the type archive. pub fn delete_type(&self, name: QualifiedName) -> bool { if let Some(type_id) = self.get_type_id(name) { - self.delete_type_by_id(type_id) + self.delete_type_by_id(&type_id) } else { false } } /// Delete an existing type in the type archive. - pub fn delete_type_by_id(&self, id: S) -> bool { + pub fn delete_type_by_id(&self, id: &str) -> bool { let id = id.to_cstr(); unsafe { BNDeleteTypeArchiveType(self.handle.as_ptr(), id.as_ptr()) } } @@ -256,7 +253,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive /// /// * `name` - Type name - pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { + pub fn get_type_by_name(&self, name: QualifiedName) -> Option> { self.get_type_by_name_from_snapshot(name, &TypeArchiveSnapshotId::unset()) } @@ -284,7 +281,7 @@ impl TypeArchive { /// Retrieve a stored type in the archive by id /// /// * `id` - Type id - pub fn get_type_by_id(&self, id: I) -> Option> { + pub fn get_type_by_id(&self, id: &str) -> Option> { self.get_type_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -292,9 +289,9 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_by_id_from_snapshot( + pub fn get_type_by_id_from_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> Option> { let id = id.to_cstr(); @@ -311,7 +308,7 @@ impl TypeArchive { /// Retrieve a type's name by its id /// /// * `id` - Type id - pub fn get_type_name_by_id(&self, id: I) -> QualifiedName { + pub fn get_type_name_by_id(&self, id: &str) -> QualifiedName { self.get_type_name_by_id_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -319,9 +316,9 @@ impl TypeArchive { /// /// * `id` - Type id /// * `snapshot` - Snapshot id to search for types - pub fn get_type_name_by_id_from_snapshot( + pub fn get_type_name_by_id_from_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> QualifiedName { let id = id.to_cstr(); @@ -338,7 +335,7 @@ impl TypeArchive { /// Retrieve a type's id by its name /// /// * `name` - Type name - pub fn get_type_id(&self, name: QualifiedName) -> Option { + pub fn get_type_id(&self, name: QualifiedName) -> Option { self.get_type_id_from_snapshot(name, &TypeArchiveSnapshotId::unset()) } @@ -350,7 +347,7 @@ impl TypeArchive { &self, name: QualifiedName, snapshot: &TypeArchiveSnapshotId, - ) -> Option { + ) -> Option { let raw_name = QualifiedName::into_raw(name); let result = unsafe { BNGetTypeArchiveTypeId( @@ -360,7 +357,7 @@ impl TypeArchive { ) }; QualifiedName::free_raw(raw_name); - (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + (!result.is_null()).then(|| unsafe { BnString::into_string(result) }) } /// Retrieve all stored types in the archive at a snapshot @@ -465,7 +462,7 @@ impl TypeArchive { /// Get all types a given type references directly /// /// * `id` - Source type id - pub fn get_outgoing_direct_references(&self, id: I) -> Array { + pub fn get_outgoing_direct_references(&self, id: &str) -> Array { self.get_outgoing_direct_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -473,9 +470,9 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_direct_references_from_snapshot( + pub fn get_outgoing_direct_references_from_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); @@ -495,7 +492,7 @@ impl TypeArchive { /// Get all types a given type references, and any types that the referenced types reference /// /// * `id` - Source type id - pub fn get_outgoing_recursive_references(&self, id: I) -> Array { + pub fn get_outgoing_recursive_references(&self, id: &str) -> Array { self.get_outgoing_recursive_references_from_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -503,9 +500,9 @@ impl TypeArchive { /// /// * `id` - Source type id /// * `snapshot` - Snapshot id to search for types - pub fn get_outgoing_recursive_references_from_snapshot( + pub fn get_outgoing_recursive_references_from_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); @@ -525,7 +522,7 @@ impl TypeArchive { /// Get all types that reference a given type /// /// * `id` - Target type id - pub fn get_incoming_direct_references(&self, id: I) -> Array { + pub fn get_incoming_direct_references(&self, id: &str) -> Array { self.get_incoming_direct_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -533,9 +530,9 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types - pub fn get_incoming_direct_references_with_snapshot( + pub fn get_incoming_direct_references_with_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); @@ -555,7 +552,7 @@ impl TypeArchive { /// Get all types that reference a given type, and all types that reference them, recursively /// /// * `id` - Target type id - pub fn get_incoming_recursive_references(&self, id: I) -> Array { + pub fn get_incoming_recursive_references(&self, id: &str) -> Array { self.get_incoming_recursive_references_with_snapshot(id, &TypeArchiveSnapshotId::unset()) } @@ -563,9 +560,9 @@ impl TypeArchive { /// /// * `id` - Target type id /// * `snapshot` - Snapshot id to search for types, or empty string to search the latest snapshot - pub fn get_incoming_recursive_references_with_snapshot( + pub fn get_incoming_recursive_references_with_snapshot( &self, - id: I, + id: &str, snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); @@ -583,7 +580,7 @@ impl TypeArchive { } /// Look up a metadata entry in the archive - pub fn query_metadata(&self, key: S) -> Option> { + pub fn query_metadata(&self, key: &str) -> Option> { let key = key.to_cstr(); let result = unsafe { BNTypeArchiveQueryMetadata(self.handle.as_ptr(), key.as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) @@ -593,7 +590,7 @@ impl TypeArchive { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { + pub fn store_metadata(&self, key: &str, md: &Metadata) { let key = key.to_cstr(); let result = unsafe { BNTypeArchiveStoreMetadata(self.handle.as_ptr(), key.as_ptr(), md.handle) }; @@ -601,13 +598,13 @@ impl TypeArchive { } /// Delete a given metadata entry in the archive from the `key` - pub fn remove_metadata(&self, key: S) -> bool { + pub fn remove_metadata(&self, key: &str) -> bool { let key = key.to_cstr(); unsafe { BNTypeArchiveRemoveMetadata(self.handle.as_ptr(), key.as_ptr()) } } /// Turn a given `snapshot` id into a data stream - pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { + pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { let result = unsafe { BNTypeArchiveSerializeSnapshot( self.handle.as_ptr(), @@ -678,9 +675,8 @@ impl TypeArchive { unsafe { BNCloseTypeArchive(self.handle.as_ptr()) } } - // TODO: Make this AsRef? /// Determine if `file` is a Type Archive - pub fn is_type_archive(file: P) -> bool { + pub fn is_type_archive(file: &Path) -> bool { let file = file.to_cstr(); unsafe { BNIsTypeArchive(file.as_ptr()) } } @@ -699,13 +695,12 @@ impl TypeArchive { /// * `parents` - Parent snapshot ids /// /// Returns Created snapshot id - pub fn new_snapshot_transaction( + pub fn new_snapshot_transaction( &self, mut function: F, parents: &[TypeArchiveSnapshotId], ) -> TypeArchiveSnapshotId where - P: IntoCStr, F: FnMut(&TypeArchiveSnapshotId) -> bool, { unsafe extern "C" fn cb_callback bool>( @@ -744,20 +739,15 @@ impl TypeArchive { /// /// Returns Snapshot id, if merge was successful, otherwise the List of /// conflicting type ids - pub fn merge_snapshots( + pub fn merge_snapshots( &self, - base_snapshot: B, - first_snapshot: F, - second_snapshot: S, + base_snapshot: &str, + first_snapshot: &str, + second_snapshot: &str, merge_conflicts: M, ) -> Result> where - B: IntoCStr, - F: IntoCStr, - S: IntoCStr, - M: IntoIterator, - MI: IntoCStr, - MK: IntoCStr, + M: IntoIterator, { self.merge_snapshots_with_progress( base_snapshot, @@ -778,22 +768,17 @@ impl TypeArchive { /// /// Returns Snapshot id, if merge was successful, otherwise the List of /// conflicting type ids - pub fn merge_snapshots_with_progress( + pub fn merge_snapshots_with_progress( &self, - base_snapshot: B, - first_snapshot: F, - second_snapshot: S, + base_snapshot: &str, + first_snapshot: &str, + second_snapshot: &str, merge_conflicts: M, - mut progress: P, + mut progress: PC, ) -> Result> where - B: IntoCStr, - F: IntoCStr, - S: IntoCStr, - M: IntoIterator, - MI: IntoCStr, - MK: IntoCStr, - P: ProgressCallback, + M: IntoIterator, + PC: ProgressCallback, { let base_snapshot = base_snapshot.to_cstr(); let first_snapshot = first_snapshot.to_cstr(); @@ -823,8 +808,8 @@ impl TypeArchive { &mut conflicts_errors, &mut conflicts_errors_count, &mut result, - Some(P::cb_progress_callback), - &mut progress as *mut P as *mut c_void, + Some(PC::cb_progress_callback), + &mut progress as *mut PC as *mut c_void, ) }; @@ -867,7 +852,7 @@ impl Eq for TypeArchive {} impl Hash for TypeArchive { fn hash(&self, state: &mut H) { - (self.handle.as_ptr() as usize).hash(state); + self.id().hash(state); } } @@ -1140,10 +1125,10 @@ impl TypeArchiveMergeConflict { TypeArchiveSnapshotId(id) } - // TODO: This needs documentation! - pub fn success(&self, value: S) -> bool { - let value = value.to_cstr(); - unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), value.as_ptr()) } + /// Call this when you've resolved the conflict to save the result. + pub fn success(&self, result: &str) -> bool { + let result = result.to_cstr(); + unsafe { BNTypeArchiveMergeConflictSuccess(self.handle.as_ptr(), result.as_ptr()) } } } diff --git a/rust/src/type_container.rs b/rust/src/type_container.rs index 2257a2973d..d68fc9c078 100644 --- a/rust/src/type_container.rs +++ b/rust/src/type_container.rs @@ -137,7 +137,7 @@ impl TypeContainer { /// (by id) to use the new name. /// /// Returns true if the type was renamed. - pub fn rename_type, S: IntoCStr>(&self, name: T, type_id: S) -> bool { + pub fn rename_type>(&self, name: T, type_id: &str) -> bool { let type_id = type_id.to_cstr(); let raw_name = QualifiedName::into_raw(name.into()); let success = @@ -150,7 +150,7 @@ impl TypeContainer { /// not specified and you may end up with broken references if any still exist. /// /// Returns true if the type was deleted. - pub fn delete_type(&self, type_id: S) -> bool { + pub fn delete_type(&self, type_id: &str) -> bool { let type_id = type_id.to_cstr(); unsafe { BNTypeContainerDeleteType(self.handle.as_ptr(), type_id.as_ptr()) } } @@ -158,19 +158,19 @@ impl TypeContainer { /// Get the unique id of the type in the Type Container with the given name. /// /// If no type with that name exists, returns None. - pub fn type_id>(&self, name: T) -> Option { + pub fn type_id>(&self, name: T) -> Option { let mut result = std::ptr::null_mut(); let raw_name = QualifiedName::into_raw(name.into()); let success = unsafe { BNTypeContainerGetTypeId(self.handle.as_ptr(), &raw_name, &mut result) }; QualifiedName::free_raw(raw_name); - success.then(|| unsafe { BnString::from_raw(result) }) + success.then(|| unsafe { BnString::into_string(result) }) } /// Get the unique name of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_name(&self, type_id: S) -> Option { + pub fn type_name(&self, type_id: &str) -> Option { let type_id = type_id.to_cstr(); let mut result = BNQualifiedName::default(); let success = unsafe { @@ -182,7 +182,7 @@ impl TypeContainer { /// Get the definition of the type in the Type Container with the given id. /// /// If no type with that id exists, returns None. - pub fn type_by_id(&self, type_id: S) -> Option> { + pub fn type_by_id(&self, type_id: &str) -> Option> { let type_id = type_id.to_cstr(); let mut result = std::ptr::null_mut(); let success = unsafe { @@ -283,9 +283,9 @@ impl TypeContainer { /// /// * `source` - Source code to parse /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing - pub fn parse_type_string( + pub fn parse_type_string( &self, - source: S, + source: &str, import_dependencies: bool, ) -> Result> { let source = source.to_cstr(); @@ -319,23 +319,18 @@ impl TypeContainer { /// * `include_dirs` - List of directories to include in the header search path /// * `auto_type_source` - Source of types if used for automatically generated types /// * `import_dependencies` - If Type Library / Type Archive types should be imported during parsing - pub fn parse_types_from_source( + pub fn parse_types_from_source( &self, - source: S, - filename: F, + source: &str, + filename: &str, options: O, - include_directories: D, - auto_type_source: A, + include_directories: I, + auto_type_source: &str, import_dependencies: bool, ) -> Result> where - S: IntoCStr, - F: IntoCStr, - O: IntoIterator, - O::Item: IntoCStr, - D: IntoIterator, - D::Item: IntoCStr, - A: IntoCStr, + O: IntoIterator, + I: IntoIterator, { let source = source.to_cstr(); let filename = filename.to_cstr(); diff --git a/rust/src/type_library.rs b/rust/src/type_library.rs index 29634c389b..6d09abfadd 100644 --- a/rust/src/type_library.rs +++ b/rust/src/type_library.rs @@ -1,7 +1,5 @@ use binaryninjacore_sys::*; -use core::{ffi, mem, ptr}; - use crate::{ architecture::CoreArchitecture, metadata::Metadata, @@ -10,6 +8,8 @@ use crate::{ string::{BnString, IntoCStr}, types::{QualifiedName, QualifiedNameAndType, Type}, }; +use core::{ffi, mem, ptr}; +use std::path::Path; #[repr(transparent)] pub struct TypeLibrary { @@ -42,7 +42,7 @@ impl TypeLibrary { } /// Creates an empty type library object with a random GUID and the provided name. - pub fn new(arch: CoreArchitecture, name: S) -> TypeLibrary { + pub fn new(arch: CoreArchitecture, name: &str) -> TypeLibrary { let name = name.to_cstr(); let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) }; @@ -57,9 +57,9 @@ impl TypeLibrary { } /// Decompresses a type library file to a file on disk. - pub fn decompress_to_file(path: P, output: O) -> bool { + pub fn decompress_to_file(path: &Path, output_path: &Path) -> bool { let path = path.to_cstr(); - let output = output.to_cstr(); + let output = output_path.to_cstr(); unsafe { BNTypeLibraryDecompressToFile( path.as_ref().as_ptr() as *const ffi::c_char, @@ -69,7 +69,7 @@ impl TypeLibrary { } /// Loads a finalized type library instance from file - pub fn load_from_file(path: S) -> Option { + pub fn load_from_file(path: &Path) -> Option { let path = path.to_cstr(); let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; @@ -77,7 +77,7 @@ impl TypeLibrary { } /// Saves a finalized type library instance to file - pub fn write_to_file(&self, path: S) -> bool { + pub fn write_to_file(&self, path: &Path) -> bool { let path = path.to_cstr(); unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) @@ -86,7 +86,7 @@ impl TypeLibrary { /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. - pub fn from_name(arch: CoreArchitecture, name: S) -> Option { + pub fn from_name(arch: CoreArchitecture, name: &str) -> Option { let name = name.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) @@ -95,7 +95,7 @@ impl TypeLibrary { } /// Attempts to grab a type library associated with the provided Architecture and GUID pair - pub fn from_guid(arch: CoreArchitecture, guid: S) -> Option { + pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option { let guid = guid.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ref().as_ptr() as *const ffi::c_char) @@ -117,7 +117,7 @@ impl TypeLibrary { } /// Sets the name of a type library instance that has not been finalized - pub fn set_name(&self, value: S) { + pub fn set_name(&self, value: &str) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) @@ -135,7 +135,7 @@ impl TypeLibrary { } /// Sets the dependency name of a type library instance that has not been finalized - pub fn set_dependency_name(&self, value: S) { + pub fn set_dependency_name(&self, value: &str) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryDependencyName( @@ -152,7 +152,7 @@ impl TypeLibrary { } /// Sets the GUID of a type library instance that has not been finalized - pub fn set_guid(&self, value: S) { + pub fn set_guid(&self, value: &str) { let value = value.to_cstr(); unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) @@ -168,7 +168,7 @@ impl TypeLibrary { } /// Adds an extra name to this type library used during library lookups and dependency resolution - pub fn add_alternate_name(&self, value: S) { + pub fn add_alternate_name(&self, value: &str) { let value = value.to_cstr(); unsafe { BNAddTypeLibraryAlternateName( @@ -212,7 +212,7 @@ impl TypeLibrary { } /// Retrieves a metadata associated with the given key stored in the type library - pub fn query_metadata(&self, key: S) -> Option { + pub fn query_metadata(&self, key: &str) -> Option { let key = key.to_cstr(); let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) @@ -231,7 +231,7 @@ impl TypeLibrary { /// /// * `key` - key value to associate the Metadata object with /// * `md` - object to store. - pub fn store_metadata(&self, key: S, md: &Metadata) { + pub fn store_metadata(&self, key: &str, md: &Metadata) { let key = key.to_cstr(); unsafe { BNTypeLibraryStoreMetadata( @@ -243,7 +243,7 @@ impl TypeLibrary { } /// Removes the metadata associated with key from the current type library. - pub fn remove_metadata(&self, key: S) { + pub fn remove_metadata(&self, key: &str) { let key = key.to_cstr(); unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) @@ -299,7 +299,7 @@ impl TypeLibrary { /// Use this api with extreme caution. /// /// - pub fn add_type_source(&self, name: QualifiedName, source: S) { + pub fn add_type_source(&self, name: QualifiedName, source: &str) { let source = source.to_cstr(); let mut raw_name = QualifiedName::into_raw(name); unsafe { diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index e2134b2bb0..0ce46a50fc 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -14,8 +14,8 @@ pub type TypeParserErrorSeverity = BNTypeParserErrorSeverity; pub type TypeParserOption = BNTypeParserOption; /// Register a custom parser with the API -pub fn register_type_parser( - name: S, +pub fn register_type_parser( + name: &str, parser: T, ) -> (&'static mut T, CoreTypeParser) { let parser = Box::leak(Box::new(parser)); @@ -51,7 +51,7 @@ impl CoreTypeParser { unsafe { Array::new(result, count, ()) } } - pub fn parser_by_name(name: S) -> Option { + pub fn parser_by_name(name: &str) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetTypeParserByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index 206478a2c9..c9bec6090f 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -15,8 +15,8 @@ pub type TokenEscapingType = BNTokenEscapingType; pub type TypeDefinitionLineType = BNTypeDefinitionLineType; /// Register a custom parser with the API -pub fn register_type_printer( - name: S, +pub fn register_type_printer( + name: &str, parser: T, ) -> (&'static mut T, CoreTypePrinter) { let parser = Box::leak(Box::new(parser)); @@ -57,7 +57,7 @@ impl CoreTypePrinter { unsafe { Array::new(result, count, ()) } } - pub fn printer_by_name(name: S) -> Option { + pub fn printer_by_name(name: &str) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetTypePrinterByName(name_raw.as_ptr()) }; NonNull::new(result).map(|x| unsafe { Self::from_raw(x) }) @@ -363,7 +363,7 @@ impl Default for CoreTypePrinter { // TODO: Remove this entirely, there is no "default", its view specific lets not make this some defined behavior. let default_settings = crate::settings::Settings::new(); let name = default_settings.get_string("analysis.types.printerName"); - Self::printer_by_name(name).unwrap() + Self::printer_by_name(&name).unwrap() } } diff --git a/rust/src/types.rs b/rust/src/types.rs index 339729658b..5a39eb275e 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -258,7 +258,7 @@ impl TypeBuilder { } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Self { + pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Self { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); // let alt_name = BnString::new(alt_name); let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data @@ -273,24 +273,12 @@ impl TypeBuilder { } pub fn float(width: usize) -> Self { - unsafe { - Self::from_raw(BNCreateFloatTypeBuilder( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, c"".as_ptr())) } } - pub fn named_float(width: usize, alt_name: S) -> Self { - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.to_cstr(); // See same line in `named_int` above - - unsafe { - Self::from_raw(BNCreateFloatTypeBuilder( - width, - alt_name.as_ref().as_ptr() as _, - )) - } + pub fn named_float(width: usize, alt_name: &str) -> Self { + let alt_name = alt_name.to_cstr(); + unsafe { Self::from_raw(BNCreateFloatTypeBuilder(width, alt_name.as_ptr())) } } pub fn array<'a, T: Into>>(ty: T, count: u64) -> Self { @@ -630,53 +618,34 @@ impl Type { } pub fn wide_char(width: usize) -> Ref { - unsafe { - Self::ref_from_raw(BNCreateWideCharType( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateWideCharType(width, c"".as_ptr())) } } pub fn int(width: usize, is_signed: bool) -> Ref { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); - unsafe { - Self::ref_from_raw(BNCreateIntegerType( - width, - &mut is_signed, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateIntegerType(width, &mut is_signed, c"".as_ptr())) } } - pub fn named_int(width: usize, is_signed: bool, alt_name: S) -> Ref { + pub fn named_int(width: usize, is_signed: bool, alt_name: &str) -> Ref { let mut is_signed = Conf::new(is_signed, MAX_CONFIDENCE).into(); - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.to_cstr(); // This segfaulted once, so the above version is there if we need to change to it, but in theory this is copied into a `const string&` on the C++ side; I'm just not 100% confident that a constant reference copies data + let alt_name = alt_name.to_cstr(); unsafe { Self::ref_from_raw(BNCreateIntegerType( width, &mut is_signed, - alt_name.as_ref().as_ptr() as _, + alt_name.as_ptr(), )) } } pub fn float(width: usize) -> Ref { - unsafe { - Self::ref_from_raw(BNCreateFloatType( - width, - BnString::new("").as_ptr() as *mut _, - )) - } + unsafe { Self::ref_from_raw(BNCreateFloatType(width, c"".as_ptr())) } } - pub fn named_float(width: usize, alt_name: S) -> Ref { - // let alt_name = BnString::new(alt_name); - let alt_name = alt_name.to_cstr(); // See same line in `named_int` above - - unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ref().as_ptr() as _)) } + pub fn named_float(width: usize, alt_name: &str) -> Ref { + let alt_name = alt_name.to_cstr(); + unsafe { Self::ref_from_raw(BNCreateFloatType(width, alt_name.as_ptr())) } } pub fn array<'a, T: Into>>(ty: T, count: u64) -> Ref { @@ -1217,7 +1186,7 @@ impl EnumerationBuilder { unsafe { Enumeration::ref_from_raw(BNFinalizeEnumerationBuilder(self.handle)) } } - pub fn append(&mut self, name: S) -> &mut Self { + pub fn append(&mut self, name: &str) -> &mut Self { let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMember(self.handle, name.as_ref().as_ptr() as _); @@ -1225,7 +1194,7 @@ impl EnumerationBuilder { self } - pub fn insert(&mut self, name: S, value: u64) -> &mut Self { + pub fn insert(&mut self, name: &str, value: u64) -> &mut Self { let name = name.to_cstr(); unsafe { BNAddEnumerationBuilderMemberWithValue(self.handle, name.as_ref().as_ptr() as _, value); @@ -1233,7 +1202,7 @@ impl EnumerationBuilder { self } - pub fn replace(&mut self, id: usize, name: S, value: u64) -> &mut Self { + pub fn replace(&mut self, id: usize, name: &str, value: u64) -> &mut Self { let name = name.to_cstr(); unsafe { BNReplaceEnumerationBuilderMember(self.handle, id, name.as_ref().as_ptr() as _, value); @@ -1476,10 +1445,10 @@ impl StructureBuilder { self } - pub fn append<'a, S: IntoCStr, T: Into>>( + pub fn append<'a, T: Into>>( &mut self, ty: T, - name: S, + name: &str, access: MemberAccess, scope: MemberScope, ) -> &mut Self { @@ -1504,7 +1473,7 @@ impl StructureBuilder { ) -> &mut Self { self.insert( &member.ty, - member.name, + &member.name, member.offset, overwrite_existing, member.access, @@ -1513,10 +1482,10 @@ impl StructureBuilder { self } - pub fn insert<'a, S: IntoCStr, T: Into>>( + pub fn insert<'a, T: Into>>( &mut self, ty: T, - name: S, + name: &str, offset: u64, overwrite_existing: bool, access: MemberAccess, @@ -1538,11 +1507,11 @@ impl StructureBuilder { self } - pub fn replace<'a, S: IntoCStr, T: Into>>( + pub fn replace<'a, T: Into>>( &mut self, index: usize, ty: T, - name: S, + name: &str, overwrite_existing: bool, ) -> &mut Self { let name = name.to_cstr(); @@ -1870,9 +1839,9 @@ impl NamedTypeReference { /// You should not assign type ids yourself: if you use this to reference a type you are going /// to create but have not yet created, you may run into problems when giving your types to /// a BinaryView. - pub fn new_with_id, S: IntoCStr>( + pub fn new_with_id>( type_class: NamedTypeReferenceClass, - type_id: S, + type_id: &str, name: T, ) -> Ref { let type_id = type_id.to_cstr(); @@ -1902,7 +1871,7 @@ impl NamedTypeReference { } fn target_helper(&self, bv: &BinaryView, visited: &mut HashSet) -> Option> { - let ty = bv.type_by_id(self.id())?; + let ty = bv.type_by_id(&self.id())?; match ty.type_class() { TypeClass::NamedTypeReferenceClass => { // Recurse into the NTR type until we get the target type. diff --git a/rust/src/websocket/client.rs b/rust/src/websocket/client.rs index aa69c381d3..fc56dc0ba9 100644 --- a/rust/src/websocket/client.rs +++ b/rust/src/websocket/client.rs @@ -18,11 +18,9 @@ pub trait WebsocketClient: Sync + Send { /// Called to construct this client object with the given core object. fn from_core(core: Ref) -> Self; - fn connect(&self, host: &str, headers: I) -> bool + fn connect(&self, host: &str, headers: I) -> bool where - I: IntoIterator, - K: IntoCStr, - V: IntoCStr; + I: IntoIterator; fn write(&self, data: &[u8]) -> bool; @@ -69,20 +67,13 @@ impl CoreWebsocketClient { /// * `host` - Full url with scheme, domain, optionally port, and path /// * `headers` - HTTP header keys and values /// * `callback` - Callbacks for various websocket events - pub fn initialize_connection( - &self, - host: &str, - headers: I, - callbacks: &mut C, - ) -> bool + pub fn initialize_connection(&self, host: &str, headers: I, callbacks: &mut C) -> bool where - I: IntoIterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, C: WebsocketClientCallback, { let url = host.to_cstr(); - let (header_keys, header_values): (Vec, Vec) = headers + let (header_keys, header_values): (Vec<_>, Vec<_>) = headers .into_iter() .map(|(k, v)| (k.to_cstr(), v.to_cstr())) .unzip(); @@ -187,8 +178,10 @@ pub(crate) unsafe extern "C" fn cb_connect( let header_count = usize::try_from(header_count).unwrap(); let header_keys = core::slice::from_raw_parts(header_keys as *const BnString, header_count); let header_values = core::slice::from_raw_parts(header_values as *const BnString, header_count); - let header_keys_str = header_keys.iter().map(|s| s.to_string_lossy()); - let header_values_str = header_values.iter().map(|s| s.to_string_lossy()); + let header_keys_str = header_keys.iter().map(|s| s.to_string_lossy().to_string()); + let header_values_str = header_values + .iter() + .map(|s| s.to_string_lossy().to_string()); let header = header_keys_str.zip(header_values_str); ctxt.connect(&host.to_string_lossy(), header) } diff --git a/rust/src/websocket/provider.rs b/rust/src/websocket/provider.rs index 40235c2bd1..914a3f165c 100644 --- a/rust/src/websocket/provider.rs +++ b/rust/src/websocket/provider.rs @@ -80,7 +80,7 @@ impl CoreWebsocketProvider { unsafe { Array::new(result, count, ()) } } - pub fn by_name(name: S) -> Option { + pub fn by_name(name: &str) -> Option { let name = name.to_cstr(); let result = unsafe { BNGetWebsocketProviderByName(name.as_ptr()) }; NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) diff --git a/rust/src/worker_thread.rs b/rust/src/worker_thread.rs index 8fbfb8efb1..113a7d0b01 100644 --- a/rust/src/worker_thread.rs +++ b/rust/src/worker_thread.rs @@ -17,7 +17,7 @@ impl WorkerThreadActionExecutor { } } -pub fn execute_on_worker_thread(name: S, f: F) { +pub fn execute_on_worker_thread(name: &str, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); @@ -30,7 +30,7 @@ pub fn execute_on_worker_thread(name: S, f: F) { } } -pub fn execute_on_worker_thread_priority(name: S, f: F) { +pub fn execute_on_worker_thread_priority(name: &str, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); @@ -43,7 +43,7 @@ pub fn execute_on_worker_thread_priority(name: S } } -pub fn execute_on_worker_thread_interactive(name: S, f: F) { +pub fn execute_on_worker_thread_interactive(name: &str, f: F) { let boxed_executor = Box::new(WorkerThreadActionExecutor { func: Box::new(f) }); let raw_executor = Box::into_raw(boxed_executor); let name = name.to_cstr(); diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 5b908ddd40..0b1925a9e4 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -108,7 +108,7 @@ impl AnalysisContext { } } - pub fn inform(&self, request: S) -> bool { + pub fn inform(&self, request: &str) -> bool { let request = request.to_cstr(); unsafe { BNAnalysisContextInform(self.handle.as_ptr(), request.as_ptr()) } } @@ -161,7 +161,7 @@ impl Activity { Ref::new(Self { handle }) } - pub fn new(config: S) -> Ref { + pub fn new(config: &str) -> Ref { unsafe extern "C" fn cb_action_nop(_: *mut c_void, _: *mut BNAnalysisContext) {} let config = config.to_cstr(); let result = @@ -169,9 +169,8 @@ impl Activity { unsafe { Activity::ref_from_raw(NonNull::new(result).unwrap()) } } - pub fn new_with_action(config: S, mut action: F) -> Ref + pub fn new_with_action(config: &str, mut action: F) -> Ref where - S: IntoCStr, F: FnMut(&AnalysisContext), { unsafe extern "C" fn cb_action( @@ -240,7 +239,7 @@ impl Workflow { /// Create a new unregistered [Workflow] with no activities. /// /// To get a copy of an existing registered [Workflow] use [Workflow::clone_to]. - pub fn new(name: S) -> Ref { + pub fn new(name: &str) -> Ref { let name = name.to_cstr(); let result = unsafe { BNCreateWorkflow(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } @@ -250,7 +249,7 @@ impl Workflow { /// /// * `name` - the name for the new [Workflow] #[must_use] - pub fn clone_to(&self, name: S) -> Ref { + pub fn clone_to(&self, name: &str) -> Ref { self.clone_to_with_root(name, "") } @@ -259,11 +258,7 @@ impl Workflow { /// * `name` - the name for the new [Workflow] /// * `root_activity` - perform the clone operation with this activity as the root #[must_use] - pub fn clone_to_with_root( - &self, - name: S, - root_activity: A, - ) -> Ref { + pub fn clone_to_with_root(&self, name: &str, root_activity: &str) -> Ref { let raw_name = name.to_cstr(); let activity = root_activity.to_cstr(); unsafe { @@ -278,7 +273,7 @@ impl Workflow { } } - pub fn instance(name: S) -> Ref { + pub fn instance(name: &str) -> Ref { let name = name.to_cstr(); let result = unsafe { BNWorkflowInstance(name.as_ptr()) }; unsafe { Workflow::ref_from_raw(NonNull::new(result).unwrap()) } @@ -306,7 +301,7 @@ impl Workflow { /// Register this [Workflow], making it immutable and available for use. /// /// * `configuration` - a JSON representation of the workflow configuration - pub fn register_with_config(&self, config: S) -> Result<(), ()> { + pub fn register_with_config(&self, config: &str) -> Result<(), ()> { let config = config.to_cstr(); if unsafe { BNRegisterWorkflow(self.handle.as_ptr(), config.as_ptr()) } { Ok(()) @@ -351,7 +346,7 @@ impl Workflow { } /// Determine if an Activity exists in this [Workflow]. - pub fn contains(&self, activity: A) -> bool { + pub fn contains(&self, activity: &str) -> bool { let activity = activity.to_cstr(); unsafe { BNWorkflowContains(self.handle.as_ptr(), activity.as_ptr()) } } @@ -365,7 +360,7 @@ impl Workflow { /// [Workflow], just for the given `activity`. /// /// `activity` - return the configuration for the `activity` - pub fn configuration_with_activity(&self, activity: A) -> String { + pub fn configuration_with_activity(&self, activity: &str) -> String { let activity = activity.to_cstr(); let result = unsafe { BNWorkflowGetConfiguration(self.handle.as_ptr(), activity.as_ptr()) }; assert!(!result.is_null()); @@ -382,7 +377,7 @@ impl Workflow { } /// Retrieve the Activity object for the specified `name`. - pub fn activity(&self, name: A) -> Option> { + pub fn activity(&self, name: &str) -> Option> { let name = name.to_cstr(); let result = unsafe { BNWorkflowGetActivity(self.handle.as_ptr(), name.as_ptr()) }; NonNull::new(result).map(|a| unsafe { Activity::ref_from_raw(a) }) @@ -392,7 +387,7 @@ impl Workflow { /// specified just for the given `activity`. /// /// * `activity` - if specified, return the roots for the `activity` - pub fn activity_roots(&self, activity: A) -> Array { + pub fn activity_roots(&self, activity: &str) -> Array { let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { @@ -406,7 +401,7 @@ impl Workflow { /// /// * `activity` - if specified, return the direct children and optionally the descendants of the `activity` (includes `activity`) /// * `immediate` - whether to include only direct children of `activity` or all descendants - pub fn subactivities(&self, activity: A, immediate: bool) -> Array { + pub fn subactivities(&self, activity: &str, immediate: bool) -> Array { let activity = activity.to_cstr(); let mut count = 0; let result = unsafe { @@ -425,9 +420,8 @@ impl Workflow { /// /// * `activity` - the Activity node to assign children /// * `activities` - the list of Activities to assign - pub fn assign_subactivities(&self, activity: A, activities: I) -> bool + pub fn assign_subactivities(&self, activity: &str, activities: I) -> bool where - A: IntoCStr, I: IntoIterator, I::Item: IntoCStr, { @@ -453,9 +447,8 @@ impl Workflow { /// /// * `activity` - the Activity node for which to insert `activities` before /// * `activities` - the list of Activities to insert - pub fn insert(&self, activity: A, activities: I) -> bool + pub fn insert(&self, activity: &str, activities: I) -> bool where - A: IntoCStr, I: IntoIterator, I::Item: IntoCStr, { @@ -476,9 +469,8 @@ impl Workflow { /// /// * `activity` - the Activity node for which to insert `activities` after /// * `activities` - the list of Activities to insert - pub fn insert_after(&self, activity: A, activities: I) -> bool + pub fn insert_after(&self, activity: &str, activities: I) -> bool where - A: IntoCStr, I: IntoIterator, I::Item: IntoCStr, { @@ -496,7 +488,7 @@ impl Workflow { } /// Remove the specified `activity` - pub fn remove(&self, activity: A) -> bool { + pub fn remove(&self, activity: &str) -> bool { let activity = activity.to_cstr(); unsafe { BNWorkflowRemove(self.handle.as_ptr(), activity.as_ptr()) } } @@ -505,7 +497,7 @@ impl Workflow { /// /// * `activity` - the Activity to replace /// * `new_activity` - the replacement Activity - pub fn replace(&self, activity: A, new_activity: N) -> bool { + pub fn replace(&self, activity: &str, new_activity: &str) -> bool { let activity = activity.to_cstr(); let new_activity = new_activity.to_cstr(); unsafe { @@ -521,11 +513,7 @@ impl Workflow { /// /// * `activity` - if specified, generate the Flowgraph using `activity` as the root /// * `sequential` - whether to generate a **Composite** or **Sequential** style graph - pub fn graph( - &self, - activity: A, - sequential: Option, - ) -> Option> { + pub fn graph(&self, activity: &str, sequential: Option) -> Option> { let sequential = sequential.unwrap_or(false); let activity = activity.to_cstr(); let graph = diff --git a/rust/tests/collaboration.rs b/rust/tests/collaboration.rs index 210492e463..3526a6f807 100644 --- a/rust/tests/collaboration.rs +++ b/rust/tests/collaboration.rs @@ -109,7 +109,7 @@ fn test_project_creation() { .expect("Failed to delete file"); assert!( !project - .get_file_by_id(created_file_id) + .get_file_by_id(&created_file_id) .is_ok_and(|f| f.is_some()), "File was not deleted" ); @@ -136,7 +136,7 @@ fn test_project_creation() { let created_folder_file_id = created_folder_file.id(); // Verify the file exists in the folder. let check_folder_file = project - .get_file_by_id(created_folder_file_id) + .get_file_by_id(&created_folder_file_id) .expect("Failed to get folder file by id") .unwrap(); assert_eq!(check_folder_file.name().as_str(), "test_folder_file"); @@ -155,7 +155,7 @@ fn test_project_creation() { .expect("Failed to delete folder"); assert!( !project - .get_folder_by_id(created_folder_id) + .get_folder_by_id(&created_folder_id) .is_ok_and(|f| f.is_some()), "Folder was not deleted" ); @@ -190,7 +190,7 @@ fn test_project_sync() { SymbolBuilder::new(SymbolType::Function, "test", entry_function.start()).create(); view.define_user_symbol(&new_entry_func_symbol); // Verify that we modified the binary - assert_eq!(entry_function.symbol().raw_name().as_str(), "test"); + assert_eq!(entry_function.symbol().raw_name(), "test".into()); // Make new snapshot. assert!(view.file().save_auto_snapshot()); // We should have two snapshots. @@ -210,20 +210,20 @@ fn test_project_sync() { drop(view); // Verify that the remote file exists. project - .get_file_by_id(remote_file.id()) + .get_file_by_id(&remote_file.id()) .expect("Failed to get remote file by id"); // Download the remote database with our changes. let downloaded_file = remote_file - .download_database(out_dir.join("downloaded_atox.obj.bndb")) + .download_database(&out_dir.join("downloaded_atox.obj.bndb")) .expect("Failed to download database"); let downloaded_view = downloaded_file - .view_of_type(view_type) + .view_of_type(&view_type) .expect("Failed to open downloaded view"); // Verify the changes in the entry function. let entry_function = downloaded_view .entry_point_function() .expect("Failed to get entry point function"); - assert_eq!(entry_function.symbol().raw_name().as_str(), "test"); + assert_eq!(entry_function.symbol().raw_name(), "test".into()); project .delete_file(&remote_file) .expect("Failed to delete file"); diff --git a/rust/tests/debug_info.rs b/rust/tests/debug_info.rs index 8b83363b45..407b41d5a5 100644 --- a/rust/tests/debug_info.rs +++ b/rust/tests/debug_info.rs @@ -69,7 +69,7 @@ fn test_debug_info() { let func = view .function_at(&view.default_platform().unwrap(), 0x3b440) .expect("Debug info test function exists"); - assert_eq!(func.symbol().raw_name().to_string(), "test_func"); + assert_eq!(func.symbol().raw_name().to_string_lossy(), "test_func"); view.file().close(); } diff --git a/rust/tests/initialization.rs b/rust/tests/initialization.rs index 7ec52598ab..00063215d6 100644 --- a/rust/tests/initialization.rs +++ b/rust/tests/initialization.rs @@ -23,7 +23,7 @@ fn test_license_validation() { Err(e) => panic!("Unexpected error: {:?}", e), } // Reset the license so that it actually can validate license. - set_license::(None); + set_license(None); // Actually make sure we can initialize. init().expect("Failed to initialize, make sure you have a license before trying to run tests!"); // Open an empty binary and make sure it succeeds. diff --git a/rust/tests/project.rs b/rust/tests/project.rs index f7d49badfa..0b03e64767 100644 --- a/rust/tests/project.rs +++ b/rust/tests/project.rs @@ -152,7 +152,7 @@ fn modify_project() { .unwrap(); assert_eq!(project.folders().unwrap().len(), 5); - let last_folder = project.folder_by_id(folder_5.id()).unwrap(); + let last_folder = project.folder_by_id(&folder_5.id()).unwrap(); project.delete_folder(&last_folder).unwrap(); assert_eq!(project.folders().unwrap().len(), 4); drop(folder_5); @@ -245,8 +245,8 @@ fn modify_project() { .unwrap(); assert_eq!(project.files().len(), 10); - let file_a = project.file_by_id(file_8.id()).unwrap(); - let file_b = project.file_by_path(file_7.path_on_disk()).unwrap(); + let file_a = project.file_by_id(&file_8.id()).unwrap(); + let file_b = project.file_by_path(&file_7.path_on_disk()).unwrap(); project.delete_file(&file_a); project.delete_file(&file_b); assert_eq!(project.files().len(), 8); diff --git a/rust/tests/repository.rs b/rust/tests/repository.rs index b1efee11e9..ac861b2cde 100644 --- a/rust/tests/repository.rs +++ b/rust/tests/repository.rs @@ -8,7 +8,7 @@ fn test_list() { let repositories = manager.repositories(); for repository in &repositories { let repo_path = repository.path(); - let repository_by_path = manager.repository_by_path(repo_path).unwrap(); + let repository_by_path = manager.repository_by_path(&repo_path).unwrap(); assert_eq!(repository.url(), repository_by_path.url()); } @@ -19,7 +19,7 @@ fn test_list() { let plugins = repository.plugins(); for plugin in &plugins { let plugin_path = plugin.path(); - let plugin_by_path = repository.plugin_by_path(plugin_path).unwrap(); + let plugin_by_path = repository.plugin_by_path(&plugin_path).unwrap(); assert_eq!(plugin.package_url(), plugin_by_path.package_url()); } } diff --git a/rust/tests/type_container.rs b/rust/tests/type_container.rs index 4a0175411e..96f3bc4a0e 100644 --- a/rust/tests/type_container.rs +++ b/rust/tests/type_container.rs @@ -49,7 +49,7 @@ fn test_add_delete_type() { .type_id("mytype") .expect("mytype not found"); assert!( - view_type_container.delete_type(my_type_id), + view_type_container.delete_type(&my_type_id), "Type was deleted!" ); // There should be no type ids if the type was actually deleted diff --git a/rust/tests/types.rs b/rust/tests/types.rs index 4ed4caf7d6..1768277795 100644 --- a/rust/tests/types.rs +++ b/rust/tests/types.rs @@ -65,7 +65,7 @@ fn add_type_to_view() { empty_view.define_auto_type("test", "me", &test_type); assert!(empty_view.type_by_name("test").is_some()); empty_view.undefine_auto_type( - empty_view + &empty_view .type_id_by_name("test") .expect("Failed to get type id"), ); diff --git a/rust/tests/websocket.rs b/rust/tests/websocket.rs index c5cf6be4cc..2c25a81095 100644 --- a/rust/tests/websocket.rs +++ b/rust/tests/websocket.rs @@ -1,6 +1,5 @@ use binaryninja::headless::Session; use binaryninja::rc::Ref; -use binaryninja::string::IntoCStr; use binaryninja::websocket::{ register_websocket_provider, CoreWebsocketClient, CoreWebsocketProvider, WebsocketClient, WebsocketClientCallback, WebsocketProvider, @@ -31,11 +30,9 @@ impl WebsocketClient for MyWebsocketClient { Self { core } } - fn connect(&self, host: &str, _headers: I) -> bool + fn connect(&self, host: &str, _headers: I) -> bool where - I: IntoIterator, - K: IntoCStr, - V: IntoCStr, + I: IntoIterator, { assert_eq!(host, "url"); true @@ -89,7 +86,11 @@ fn reg_websocket_provider() { let provider = register_websocket_provider::("RustWebsocketProvider"); let client = provider.create_client().unwrap(); let mut callback = MyClientCallbacks::default(); - let success = client.initialize_connection("url", [("header", "value")], &mut callback); + let success = client.initialize_connection( + "url", + [("header".to_string(), "value".to_string())], + &mut callback, + ); assert!(success, "Failed to initialize connection!"); } @@ -100,7 +101,11 @@ fn listen_websocket_provider() { let client = provider.create_client().unwrap(); let mut callback = MyClientCallbacks::default(); - client.initialize_connection("url", [("header", "value")], &mut callback); + client.initialize_connection( + "url", + [("header".to_string(), "value".to_string())], + &mut callback, + ); assert!(client.write("test1".as_bytes())); assert!(client.write("test2".as_bytes())); From b4cb6c74e5c8130bdd8f951d26e81e991301bf8a Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 20:32:06 -0400 Subject: [PATCH 16/54] [Rust] Add section tests --- rust/tests/section.rs | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 rust/tests/section.rs diff --git a/rust/tests/section.rs b/rust/tests/section.rs new file mode 100644 index 0000000000..ea3d8e06f1 --- /dev/null +++ b/rust/tests/section.rs @@ -0,0 +1,56 @@ +use binaryninja::binary_view::BinaryViewExt; +use binaryninja::headless::Session; +use binaryninja::section::{SectionBuilder, Semantics}; +use std::path::PathBuf; + +#[test] +fn test_binary_section() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + // This binary has a lot of sections! + assert_eq!(view.sections().len(), 139); + + // Make sure we are not grabbing garbage. + assert_eq!(view.section_by_name("test"), None); + + // Just test a bunch of properties of a section. + let section = view.section_by_name(".rdata").unwrap(); + assert_eq!(section.name(), ".rdata".into()); + let image_base = view.original_image_base(); + let section_start = image_base + 0x25efc; + let section_end = image_base + 0x25f04; + assert_eq!(section.start(), section_start); + assert_eq!(section.end(), image_base + 0x25f04); + assert_eq!(section.len(), 0x8); + assert_eq!(section.address_range(), section_start..section_end); + assert_eq!(section.auto_defined(), true); + assert_eq!(section.semantics(), Semantics::ReadOnlyData); + + let sections_at = view.sections_at(image_base + 0x25efc); + assert_eq!(sections_at.len(), 1); + let same_section = sections_at.to_vec()[0].to_owned(); + assert_eq!(section, same_section); +} + +#[test] +fn test_add_remove_section() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + + // Remove the rdata section! + let old_section = view + .section_by_name(".rdata") + .expect("Failed to find rdata section"); + view.remove_auto_section(".rdata"); + assert!(view.section_by_name(".rdata").is_none()); + + // Add a new section and compare with the old section + let new_section_builder = SectionBuilder::from(&old_section); + view.add_section(new_section_builder); + let new_section = view + .section_by_name(".rdata") + .expect("Failed to find new section"); + assert_eq!(old_section, new_section); +} From fdca9b2c19e31d83123bcd4aed573af50d932474 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:20:15 -0400 Subject: [PATCH 17/54] [Rust] Retain core string for section strings Might want to key off the section string in the core, so we should give it back as a `BnString` --- rust/src/binary_view.rs | 6 +++--- rust/src/section.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 35383f0b44..04a60a0d08 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -871,7 +871,7 @@ pub trait BinaryViewExt: BinaryViewBase { section.create(self.as_ref()); } - fn remove_auto_section(&self, name: &str) { + fn remove_auto_section(&self, name: impl IntoCStr) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -879,7 +879,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn remove_user_section(&self, name: &str) { + fn remove_user_section(&self, name: impl IntoCStr) { let raw_name = name.to_cstr(); let raw_name_ptr = raw_name.as_ptr(); unsafe { @@ -887,7 +887,7 @@ pub trait BinaryViewExt: BinaryViewBase { } } - fn section_by_name(&self, name: &str) -> Option> { + fn section_by_name(&self, name: impl IntoCStr) -> Option> { unsafe { let raw_name = name.to_cstr(); let name_ptr = raw_name.as_ptr(); diff --git a/rust/src/section.rs b/rust/src/section.rs index a86c54e2c5..77e402324f 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -121,12 +121,12 @@ impl Section { unsafe { BNSectionGetSemantics(self.handle).into() } } - pub fn linked_section(&self) -> String { - unsafe { BnString::into_string(BNSectionGetLinkedSection(self.handle)) } + pub fn linked_section(&self) -> BnString { + unsafe { BnString::from_raw(BNSectionGetLinkedSection(self.handle)) } } - pub fn info_section(&self) -> String { - unsafe { BnString::into_string(BNSectionGetInfoSection(self.handle)) } + pub fn info_section(&self) -> BnString { + unsafe { BnString::from_raw(BNSectionGetInfoSection(self.handle)) } } pub fn info_data(&self) -> u64 { From 9464371f74771c818be70b966e65b11a2746c0dc Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:21:06 -0400 Subject: [PATCH 18/54] [Rust] Correct impls for `Section` Previously we were comparing the section raw pointer and hashing it --- rust/src/section.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/rust/src/section.rs b/rust/src/section.rs index 77e402324f..edf19582a5 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -15,6 +15,7 @@ //! Sections are [crate::segment::Segment]s that are loaded into memory at run time use std::fmt; +use std::hash::{Hash, Hasher}; use std::ops::Range; use binaryninjacore_sys::*; @@ -61,7 +62,6 @@ impl From for BNSectionSemantics { } } -#[derive(PartialEq, Eq, Hash)] pub struct Section { handle: *mut BNSection, } @@ -161,6 +161,30 @@ impl fmt::Debug for Section { } } +impl PartialEq for Section { + fn eq(&self, other: &Self) -> bool { + // TODO: Do we want to make this complete match like this? + self.name() == other.name() + && self.address_range() == other.address_range() + && self.semantics() == other.semantics() + && self.linked_section() == other.linked_section() + && self.info_section() == other.info_section() + && self.info_data() == other.info_data() + && self.align() == other.align() + && self.entry_size() == other.entry_size() + && self.auto_defined() == other.auto_defined() + } +} + +impl Eq for Section {} + +impl Hash for Section { + fn hash(&self, state: &mut H) { + self.name().hash(state); + self.address_range().hash(state); + } +} + impl ToOwned for Section { type Owned = Ref; From d539d18edd88c262b92179677d99324ec4c55798 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:21:21 -0400 Subject: [PATCH 19/54] [Rust] Construct a `SectionBuilder` from a `Section` --- rust/src/section.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rust/src/section.rs b/rust/src/section.rs index edf19582a5..75b3e836c6 100644 --- a/rust/src/section.rs +++ b/rust/src/section.rs @@ -334,3 +334,26 @@ impl SectionBuilder { } } } + +impl> From for SectionBuilder { + fn from(value: T) -> Self { + let value = value.as_ref(); + let name = value.name().to_string_lossy().to_string(); + let ty = value.section_type().to_string(); + let linked_section = value.linked_section().to_string_lossy().to_string(); + let info_section = value.info_section().to_string_lossy().to_string(); + + Self { + is_auto: value.auto_defined(), + name, + range: value.address_range(), + semantics: value.semantics(), + ty, + align: value.align(), + entry_size: value.entry_size() as u64, + linked_section, + info_section, + info_data: value.info_data(), + } + } +} From 4359153a5cc52c22dd0ef9898ceaadc10ba56638 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:22:48 -0400 Subject: [PATCH 20/54] [Rust] Metadata API improvements - Don't use Result for some or none values - Fix freeing of key value store objects - Improve ergonomics a little bit - Add unit tests --- rust/src/metadata.rs | 173 +++++++++++++++++++++-------------------- rust/tests/metadata.rs | 50 ++++++++++++ 2 files changed, 138 insertions(+), 85 deletions(-) create mode 100644 rust/tests/metadata.rs diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index 6cf1cbce57..e541577de8 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -1,5 +1,5 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; -use crate::string::{BnString, IntoCStr, IntoJson}; +use crate::string::{raw_to_string, BnString, IntoCStr, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; use std::os::raw::c_char; @@ -30,129 +30,129 @@ impl Metadata { unsafe { BNMetadataGetType(self.handle) } } - pub fn get_boolean(&self) -> Result { + pub fn get_boolean(&self) -> Option { match self.get_type() { - MetadataType::BooleanDataType => Ok(unsafe { BNMetadataGetBoolean(self.handle) }), - _ => Err(()), + MetadataType::BooleanDataType => Some(unsafe { BNMetadataGetBoolean(self.handle) }), + _ => None, } } - pub fn get_unsigned_integer(&self) -> Result { + pub fn get_unsigned_integer(&self) -> Option { match self.get_type() { MetadataType::UnsignedIntegerDataType => { - Ok(unsafe { BNMetadataGetUnsignedInteger(self.handle) }) + Some(unsafe { BNMetadataGetUnsignedInteger(self.handle) }) } - _ => Err(()), + _ => None, } } - pub fn get_signed_integer(&self) -> Result { + pub fn get_signed_integer(&self) -> Option { match self.get_type() { MetadataType::SignedIntegerDataType => { - Ok(unsafe { BNMetadataGetSignedInteger(self.handle) }) + Some(unsafe { BNMetadataGetSignedInteger(self.handle) }) } - _ => Err(()), + _ => None, } } - pub fn get_double(&self) -> Result { + pub fn get_double(&self) -> Option { match self.get_type() { - MetadataType::DoubleDataType => Ok(unsafe { BNMetadataGetDouble(self.handle) }), - _ => Err(()), + MetadataType::DoubleDataType => Some(unsafe { BNMetadataGetDouble(self.handle) }), + _ => None, } } - pub fn get_string(&self) -> Result { + pub fn get_string(&self) -> Option { match self.get_type() { MetadataType::StringDataType => { let ptr: *mut c_char = unsafe { BNMetadataGetString(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { BnString::from_raw(ptr) }) + Some(unsafe { BnString::from_raw(ptr) }) } - _ => Err(()), + _ => None, } } - pub fn get_boolean_list(&self) -> Result, ()> { + pub fn get_boolean_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut bool = unsafe { BNMetadataGetBooleanList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataBooleanList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_unsigned_integer_list(&self) -> Result, ()> { + pub fn get_unsigned_integer_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut u64 = unsafe { BNMetadataGetUnsignedIntegerList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataUnsignedIntegerList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_signed_integer_list(&self) -> Result, ()> { + pub fn get_signed_integer_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut i64 = unsafe { BNMetadataGetSignedIntegerList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataSignedIntegerList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_double_list(&self) -> Result, ()> { + pub fn get_double_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut f64 = unsafe { BNMetadataGetDoubleList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataDoubleList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_string_list(&self) -> Result, ()> { + pub fn get_string_list(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut *mut c_char = unsafe { BNMetadataGetStringList(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = list @@ -160,66 +160,66 @@ impl Metadata { .map(|ptr| unsafe { BnString::from_raw(*ptr) }) .collect::>(); unsafe { BNFreeMetadataStringList(ptr, size) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_json_string(&self) -> Result { + pub fn get_json_string(&self) -> Option { match self.get_type() { MetadataType::StringDataType => { let ptr: *mut c_char = unsafe { BNMetadataGetJsonString(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { BnString::from_raw(ptr) }) + Some(unsafe { BnString::from_raw(ptr) }) } - _ => Err(()), + _ => None, } } - pub fn get_raw(&self) -> Result, ()> { + pub fn get_raw(&self) -> Option> { match self.get_type() { MetadataType::RawDataType => { let mut size: usize = 0; let ptr: *mut u8 = unsafe { BNMetadataGetRaw(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } let list = unsafe { slice::from_raw_parts(ptr, size) }; let vec = Vec::from(list); unsafe { BNFreeMetadataRaw(ptr) }; - Ok(vec) + Some(vec) } - _ => Err(()), + _ => None, } } - pub fn get_array(&self) -> Result, ()> { + pub fn get_array(&self) -> Option> { match self.get_type() { MetadataType::ArrayDataType => { let mut size: usize = 0; let ptr: *mut *mut BNMetadata = unsafe { BNMetadataGetArray(self.handle, &mut size) }; if ptr.is_null() { - return Err(()); + return None; } - Ok(unsafe { Array::new(ptr, size, ()) }) + Some(unsafe { Array::new(ptr, size, ()) }) } - _ => Err(()), + _ => None, } } - pub fn get_value_store(&self) -> Result>, ()> { + pub fn get_value_store(&self) -> Option>> { match self.get_type() { MetadataType::KeyValueDataType => { let ptr: *mut BNMetadataValueStore = unsafe { BNMetadataGetValueStore(self.handle) }; if ptr.is_null() { - return Err(()); + return None; } let size = unsafe { (*ptr).size }; @@ -230,21 +230,16 @@ impl Metadata { let mut map = HashMap::new(); for i in 0..size { - let key = unsafe { BnString::into_string(keys[i]) }; - - let value = unsafe { - Ref::::new(Self { - handle: BNNewMetadataReference(values[i]), - }) - }; + let key = raw_to_string(keys[i]).unwrap(); + let value = unsafe { Ref::::new(Self { handle: values[i] }) }; map.insert(key, value); } unsafe { BNFreeMetadataValueStore(ptr) }; - Ok(map) + Some(map) } - _ => Err(()), + _ => None, } } @@ -424,10 +419,12 @@ impl From<&Array> for Ref { } } -impl From>> for Ref { - fn from(value: HashMap>) -> Self { - let data: Vec<(S::Result, Ref)> = - value.into_iter().map(|(k, v)| (k.to_cstr(), v)).collect(); +impl>> From> for Ref { + fn from(value: HashMap) -> Self { + let data: Vec<(S::Result, Ref)> = value + .into_iter() + .map(|(k, v)| (k.to_cstr(), v.into())) + .collect(); let mut keys: Vec<*const c_char> = data.iter().map(|(k, _)| k.as_ptr()).collect(); let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect(); @@ -549,7 +546,7 @@ impl TryFrom<&Metadata> for bool { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_boolean() + value.get_boolean().ok_or(()) } } @@ -557,7 +554,7 @@ impl TryFrom<&Metadata> for u64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_unsigned_integer() + value.get_unsigned_integer().ok_or(()) } } @@ -565,7 +562,7 @@ impl TryFrom<&Metadata> for i64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_signed_integer() + value.get_signed_integer().ok_or(()) } } @@ -573,7 +570,7 @@ impl TryFrom<&Metadata> for f64 { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_double() + value.get_double().ok_or(()) } } @@ -581,7 +578,7 @@ impl TryFrom<&Metadata> for BnString { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string() + value.get_string().ok_or(()) } } @@ -589,7 +586,10 @@ impl TryFrom<&Metadata> for String { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string().map(|s| s.to_string_lossy().to_string()) + value + .get_string() + .map(|s| s.to_string_lossy().to_string()) + .ok_or(()) } } @@ -597,7 +597,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_boolean_list() + value.get_boolean_list().ok_or(()) } } @@ -605,7 +605,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_unsigned_integer_list() + value.get_unsigned_integer_list().ok_or(()) } } @@ -613,7 +613,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_signed_integer_list() + value.get_signed_integer_list().ok_or(()) } } @@ -621,7 +621,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_double_list() + value.get_double_list().ok_or(()) } } @@ -629,7 +629,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string_list() + value.get_string_list().ok_or(()) } } @@ -637,11 +637,14 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_string_list().map(|v| { - v.into_iter() - .map(|s| s.to_string_lossy().to_string()) - .collect() - }) + value + .get_string_list() + .map(|v| { + v.into_iter() + .map(|s| s.to_string_lossy().to_string()) + .collect() + }) + .ok_or(()) } } @@ -649,7 +652,7 @@ impl TryFrom<&Metadata> for Vec { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_raw() + value.get_raw().ok_or(()) } } @@ -657,7 +660,7 @@ impl TryFrom<&Metadata> for Array { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_array() + value.get_array().ok_or(()) } } @@ -665,20 +668,20 @@ impl TryFrom<&Metadata> for HashMap> { type Error = (); fn try_from(value: &Metadata) -> Result { - value.get_value_store() + value.get_value_store().ok_or(()) } } impl IntoJson for &Metadata { type Output = BnString; fn get_json_string(self) -> Result { - Metadata::get_json_string(self) + Metadata::get_json_string(self).ok_or(()) } } impl IntoJson for Ref { type Output = BnString; fn get_json_string(self) -> Result { - Metadata::get_json_string(&self) + Metadata::get_json_string(&self).ok_or(()) } } diff --git a/rust/tests/metadata.rs b/rust/tests/metadata.rs new file mode 100644 index 0000000000..6b67c5e05a --- /dev/null +++ b/rust/tests/metadata.rs @@ -0,0 +1,50 @@ +use binaryninja::metadata::{Metadata, MetadataType}; +use binaryninja::rc::Ref; +use std::collections::HashMap; + +#[test] +fn basic_metadata() { + let metadata = Metadata::new_of_type(MetadataType::UnsignedIntegerDataType); + assert_eq!(metadata.get_type(), MetadataType::UnsignedIntegerDataType); + assert_eq!(metadata.get_unsigned_integer(), Some(0)); + + let metadata_0: Ref = 1u64.into(); + assert_eq!(metadata_0.get_type(), MetadataType::UnsignedIntegerDataType); + assert_eq!(metadata_0.get_unsigned_integer(), Some(1)); + + let metadata_1: Ref = true.into(); + assert_eq!(metadata_1.get_type(), MetadataType::BooleanDataType); + assert_eq!(metadata_1.get_boolean(), Some(true)); + + let metadata_2: Ref = 0.55f64.into(); + assert_eq!(metadata_2.get_type(), MetadataType::DoubleDataType); + assert_eq!(metadata_2.get_double(), Some(0.55f64)); + + let metadata_3: Ref = From::from(&vec![1i64, 2i64]); + assert_eq!(metadata_3.get_type(), MetadataType::ArrayDataType); + assert_eq!(metadata_3.get_signed_integer_list(), Some(vec![1i64, 2i64])); + + let metadata_4: Ref = From::from(&vec![1.55f64, 2.55f64]); + assert_eq!(metadata_4.get_type(), MetadataType::ArrayDataType); + assert_eq!(metadata_4.get_double_list(), Some(vec![1.55f64, 2.55f64])); +} + +#[test] +fn object_metadata() { + let metadata = Metadata::new_of_type(MetadataType::UnsignedIntegerDataType); + assert_eq!(metadata.get_type(), MetadataType::UnsignedIntegerDataType); + assert_eq!(metadata.get_unsigned_integer(), Some(0)); + + let mut map = HashMap::new(); + map.insert("key", 1u64); + + let metadata_0: Ref = From::from(map); + assert_eq!(metadata_0.get_type(), MetadataType::KeyValueDataType); + + let value_store = metadata_0 + .get_value_store() + .expect("Expected a value store"); + let key_value = value_store.get("key").expect("Expected a key to exist"); + assert_eq!(key_value.get_type(), MetadataType::UnsignedIntegerDataType); + assert_eq!(key_value.get_unsigned_integer(), Some(1)); +} From 41861d5f250fd569adc0bca3f025254256295a19 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Wed, 7 May 2025 23:23:44 -0400 Subject: [PATCH 21/54] [Rust] Improve `FileAccessor` - Add unit tests - Expose read/write functionality - Add some much needed documentation when passing to memory map --- rust/src/binary_view.rs | 13 +++-- rust/src/binary_view/memory_map.rs | 20 +++++-- rust/src/file_accessor.rs | 94 ++++++++++++++++++++---------- rust/tests/file_accessor.rs | 22 +++++++ 4 files changed, 108 insertions(+), 41 deletions(-) create mode 100644 rust/tests/file_accessor.rs diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 04a60a0d08..55b0d4db7d 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -32,7 +32,7 @@ use crate::confidence::Conf; use crate::data_buffer::DataBuffer; use crate::debuginfo::DebugInfo; use crate::external_library::{ExternalLibrary, ExternalLocation}; -use crate::file_accessor::FileAccessor; +use crate::file_accessor::{Accessor, FileAccessor}; use crate::file_metadata::FileMetadata; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; @@ -1832,8 +1832,11 @@ impl BinaryView { unsafe { Ok(Ref::new(Self { handle })) } } - pub fn from_accessor(meta: &FileMetadata, file: &mut FileAccessor) -> Result> { - let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.api_object) }; + pub fn from_accessor( + meta: &FileMetadata, + file: &mut FileAccessor, + ) -> Result> { + let handle = unsafe { BNCreateBinaryDataViewFromFile(meta.handle, &mut file.raw) }; if handle.is_null() { return Err(()); @@ -1875,8 +1878,8 @@ impl BinaryView { /// /// To avoid the above issue use [`crate::main_thread::execute_on_main_thread_and_wait`] to verify there /// are no queued up main thread actions. - pub fn save_to_accessor(&self, file: &mut FileAccessor) -> bool { - unsafe { BNSaveToFile(self.handle, &mut file.api_object) } + pub fn save_to_accessor(&self, file: &mut FileAccessor) -> bool { + unsafe { BNSaveToFile(self.handle, &mut file.raw) } } } diff --git a/rust/src/binary_view/memory_map.rs b/rust/src/binary_view/memory_map.rs index 28b5236976..34ebd572e7 100644 --- a/rust/src/binary_view/memory_map.rs +++ b/rust/src/binary_view/memory_map.rs @@ -1,6 +1,6 @@ use crate::binary_view::BinaryView; use crate::data_buffer::DataBuffer; -use crate::file_accessor::FileAccessor; +use crate::file_accessor::{Accessor, FileAccessor}; use crate::rc::Ref; use crate::segment::SegmentFlags; use crate::string::{BnString, IntoCStr}; @@ -59,6 +59,9 @@ impl MemoryMap { } } + /// Adds the memory region using a [`DataBuffer`]. + /// + /// This will add the contents of the [`DataBuffer`] to the database. pub fn add_data_memory_region( &mut self, name: &str, @@ -78,11 +81,20 @@ impl MemoryMap { } } - pub fn add_remote_memory_region( + // TODO: This really cant be safe until BNFileAccessor is ARC'd and can be freed. Probably need another thing + // TODO: Ontop of a file accessor in the core that would manage it. (I.e. BNFileAccessorHandle) or something. + /// Adds the memory region using a [`FileAccessor`]. + /// + /// This does not add the region contents to the database, instead accesses to the contents + /// are done "remotely" to a [`FileAccessor`]. + /// + /// NOTE: The [`FileAccessor`] MUST live as long as the region is available, currently there is no gurentee by + /// the type checker that the file accessor is tied to that of the memory region. + pub fn add_remote_memory_region( &mut self, name: &str, start: u64, - accessor: &mut FileAccessor, + accessor: &mut FileAccessor, segment_flags: Option, ) -> bool { let name_raw = name.to_cstr(); @@ -91,7 +103,7 @@ impl MemoryMap { self.view.handle, name_raw.as_ptr(), start, - &mut accessor.api_object, + &mut accessor.raw, segment_flags.unwrap_or_default().into_raw(), ) } diff --git a/rust/src/file_accessor.rs b/rust/src/file_accessor.rs index 12d25ff0c3..2ba7938ffb 100644 --- a/rust/src/file_accessor.rs +++ b/rust/src/file_accessor.rs @@ -13,41 +13,36 @@ // limitations under the License. use binaryninjacore_sys::BNFileAccessor; -use std::io::{Read, Seek, SeekFrom, Write}; +use std::io::{ErrorKind, Read, Seek, SeekFrom, Write}; use std::marker::PhantomData; use std::slice; -pub struct FileAccessor<'a> { - pub(crate) api_object: BNFileAccessor, - _ref: PhantomData<&'a mut ()>, +pub trait Accessor: Read + Write + Seek + Sized {} + +impl Accessor for T {} + +pub struct FileAccessor { + pub(crate) raw: BNFileAccessor, + accessor: PhantomData, } -impl<'a> FileAccessor<'a> { - pub fn new(f: &'a mut F) -> Self - where - F: 'a + Read + Write + Seek + Sized, - { +impl FileAccessor { + pub fn new(accessor: A) -> Self { use std::os::raw::c_void; - extern "C" fn cb_get_length(ctxt: *mut c_void) -> u64 - where - F: Read + Write + Seek + Sized, - { - let f = unsafe { &mut *(ctxt as *mut F) }; + extern "C" fn cb_get_length(ctxt: *mut c_void) -> u64 { + let f = unsafe { &mut *(ctxt as *mut A) }; f.seek(SeekFrom::End(0)).unwrap_or(0) } - extern "C" fn cb_read( + extern "C" fn cb_read( ctxt: *mut c_void, dest: *mut c_void, offset: u64, len: usize, - ) -> usize - where - F: Read + Write + Seek + Sized, - { - let f = unsafe { &mut *(ctxt as *mut F) }; + ) -> usize { + let f = unsafe { &mut *(ctxt as *mut A) }; let dest = unsafe { slice::from_raw_parts_mut(dest as *mut u8, len) }; if f.seek(SeekFrom::Start(offset)).is_err() { @@ -58,16 +53,13 @@ impl<'a> FileAccessor<'a> { } } - extern "C" fn cb_write( + extern "C" fn cb_write( ctxt: *mut c_void, offset: u64, src: *const c_void, len: usize, - ) -> usize - where - F: Read + Write + Seek + Sized, - { - let f = unsafe { &mut *(ctxt as *mut F) }; + ) -> usize { + let f = unsafe { &mut *(ctxt as *mut A) }; let src = unsafe { slice::from_raw_parts(src as *const u8, len) }; if f.seek(SeekFrom::Start(offset)).is_err() { @@ -77,14 +69,52 @@ impl<'a> FileAccessor<'a> { } } + let boxed_accessor = Box::new(accessor); + let leaked_accessor = Box::leak(boxed_accessor); + Self { - api_object: BNFileAccessor { - context: f as *mut F as *mut _, - getLength: Some(cb_get_length::), - read: Some(cb_read::), - write: Some(cb_write::), + raw: BNFileAccessor { + context: leaked_accessor as *mut A as *mut _, + getLength: Some(cb_get_length::), + read: Some(cb_read::), + write: Some(cb_write::), }, - _ref: PhantomData, + accessor: PhantomData, + } + } + + pub fn read(&self, addr: u64, len: usize) -> Result, ErrorKind> { + let cb_read = self.raw.read.unwrap(); + let mut buf = vec![0; len]; + let read_len = unsafe { cb_read(self.raw.context, buf.as_mut_ptr() as *mut _, addr, len) }; + if read_len != len { + return Err(ErrorKind::UnexpectedEof); + } + Ok(buf) + } + + pub fn write(&self, addr: u64, data: &[u8]) -> usize { + let cb_write = self.raw.write.unwrap(); + unsafe { + cb_write( + self.raw.context, + addr, + data.as_ptr() as *const _, + data.len(), + ) + } + } + + pub fn length(&self) -> u64 { + let cb_get_length = self.raw.getLength.unwrap(); + unsafe { cb_get_length(self.raw.context) } + } +} + +impl Drop for FileAccessor { + fn drop(&mut self) { + unsafe { + let _ = Box::from_raw(self.raw.context as *mut A); } } } diff --git a/rust/tests/file_accessor.rs b/rust/tests/file_accessor.rs new file mode 100644 index 0000000000..ce79d277fc --- /dev/null +++ b/rust/tests/file_accessor.rs @@ -0,0 +1,22 @@ +use binaryninja::file_accessor::FileAccessor; +use std::io::Cursor; + +#[test] +fn test_file_accessor() { + let mut mock_data = Cursor::new(vec![0u8; 100]); + let accessor = FileAccessor::new(&mut mock_data); + assert_eq!( + accessor.length(), + 100, + "File accessor length does not match" + ); + assert_eq!( + accessor.write(0x10, &[0xff]), + 1, + "Failed to write to file accessor" + ); + let read_value = accessor + .read(0x10, 1) + .expect("Failed to read from file accessor"); + assert_eq!(read_value, &[0xff], "Read value does not match"); +} From aeae725f4e91c192d31a71d72aa4131c6900b3d2 Mon Sep 17 00:00:00 2001 From: rbran Date: Thu, 10 Apr 2025 12:58:27 +0000 Subject: [PATCH 22/54] [Rust] Implement `LanguageRepresentation` and `LineFormatter` --- rust/src/function.rs | 37 ++ rust/src/high_level_il.rs | 1 + rust/src/high_level_il/function.rs | 7 +- rust/src/high_level_il/token_emitter.rs | 400 +++++++++++++++ rust/src/language_representation.rs | 635 ++++++++++++++++++++++++ rust/src/lib.rs | 2 + rust/src/line_formatter.rs | 172 +++++++ rust/src/render_layer.rs | 4 +- rust/src/type_parser.rs | 2 +- rust/src/type_printer.rs | 2 +- rust/tests/language_representation.rs | 186 +++++++ rust/tests/line_formatter.rs | 24 + rust/tests/render_layer.rs | 2 +- 13 files changed, 1468 insertions(+), 6 deletions(-) create mode 100644 rust/src/high_level_il/token_emitter.rs create mode 100644 rust/src/language_representation.rs create mode 100644 rust/src/line_formatter.rs create mode 100644 rust/tests/language_representation.rs create mode 100644 rust/tests/line_formatter.rs diff --git a/rust/src/function.rs b/rust/src/function.rs index c1c29873ed..edde15a7b5 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -40,6 +40,7 @@ pub use binaryninjacore_sys::BNHighlightStandardColor as HighlightStandardColor; use crate::architecture::RegisterId; use crate::confidence::Conf; use crate::high_level_il::HighLevelILFunction; +use crate::language_representation::CoreLanguageRepresentationFunction; use crate::low_level_il::{LiftedILFunction, RegularLowLevelILFunction}; use crate::medium_level_il::MediumLevelILFunction; use crate::variable::{ @@ -476,6 +477,42 @@ impl Function { } } + /// Get the language representation of the function. + /// + /// * `language` - The language representation, ex. "Pseudo C". + pub fn language_representation( + &self, + language: S, + ) -> Option> { + let lang_name = language.into_bytes_with_nul(); + let repr = unsafe { + BNGetFunctionLanguageRepresentation( + self.handle, + lang_name.as_ref().as_ptr() as *const c_char, + ) + }; + NonNull::new(repr) + .map(|handle| unsafe { CoreLanguageRepresentationFunction::ref_from_raw(handle) }) + } + + /// Get the language representation of the function, if available. + /// + /// * `language` - The language representation, ex. "Pseudo C". + pub fn language_representation_if_available( + &self, + language: S, + ) -> Option> { + let lang_name = language.into_bytes_with_nul(); + let repr = unsafe { + BNGetFunctionLanguageRepresentationIfAvailable( + self.handle, + lang_name.as_ref().as_ptr() as *const c_char, + ) + }; + NonNull::new(repr) + .map(|handle| unsafe { CoreLanguageRepresentationFunction::ref_from_raw(handle) }) + } + pub fn high_level_il(&self, full_ast: bool) -> Result, ()> { unsafe { let hlil_ptr = BNGetFunctionHighLevelIL(self.handle); diff --git a/rust/src/high_level_il.rs b/rust/src/high_level_il.rs index adb44a7eee..8d02720dc3 100644 --- a/rust/src/high_level_il.rs +++ b/rust/src/high_level_il.rs @@ -4,6 +4,7 @@ mod function; mod instruction; mod lift; pub mod operation; +pub mod token_emitter; pub use self::block::*; pub use self::function::*; diff --git a/rust/src/high_level_il/function.rs b/rust/src/high_level_il/function.rs index 0813ad0458..a65a244c84 100644 --- a/rust/src/high_level_il/function.rs +++ b/rust/src/high_level_il/function.rs @@ -15,12 +15,17 @@ pub struct HighLevelILFunction { } impl HighLevelILFunction { + pub(crate) unsafe fn from_raw(handle: *mut BNHighLevelILFunction, full_ast: bool) -> Self { + debug_assert!(!handle.is_null()); + Self { handle, full_ast } + } + pub(crate) unsafe fn ref_from_raw( handle: *mut BNHighLevelILFunction, full_ast: bool, ) -> Ref { debug_assert!(!handle.is_null()); - Self { handle, full_ast }.to_owned() + Ref::new(Self { handle, full_ast }) } pub fn instruction_from_index( diff --git a/rust/src/high_level_il/token_emitter.rs b/rust/src/high_level_il/token_emitter.rs new file mode 100644 index 0000000000..2f1236a94b --- /dev/null +++ b/rust/src/high_level_il/token_emitter.rs @@ -0,0 +1,400 @@ +use std::ptr::NonNull; + +use binaryninjacore_sys::*; + +use crate::disassembly::{ + DisassemblySettings, DisassemblyTextLine, InstructionTextToken, InstructionTextTokenContext, + InstructionTextTokenType, +}; +use crate::high_level_il::HighLevelILFunction; +use crate::language_representation::{OperatorPrecedence, SymbolDisplayResult, SymbolDisplayType}; +use crate::rc::{Array, Ref, RefCountable}; +use crate::variable::Variable; + +pub type ScopeType = BNScopeType; +pub type TokenEmitterExpr = BNTokenEmitterExpr; +pub type BraceRequirement = BNBraceRequirement; + +#[derive(PartialEq, Eq, Hash)] +pub struct HighLevelILTokenEmitter { + handle: NonNull, +} + +impl HighLevelILTokenEmitter { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + /// Returns the list of [`InstructionTextToken`] on the current line. + pub fn current_tokens(&self) -> Array { + let mut count = 0; + let array = + unsafe { BNHighLevelILTokenEmitterGetCurrentTokens(self.handle.as_ptr(), &mut count) }; + unsafe { Array::new(array, count, ()) } + } + + /// Returns the list of [`DisassemblyTextLine`] in the output. + pub fn lines(&self) -> Array { + let mut count = 0; + let array = unsafe { BNHighLevelILTokenEmitterGetLines(self.handle.as_ptr(), &mut count) }; + unsafe { Array::new(array, count, ()) } + } + + pub fn prepend_collapse_blank_indicator(&self) { + unsafe { BNHighLevelILTokenPrependCollapseBlankIndicator(self.handle.as_ptr()) }; + } + + pub fn prepend_collapse_indicator(&self, context: InstructionTextTokenContext, hash: u64) { + unsafe { + BNHighLevelILTokenPrependCollapseIndicator(self.handle.as_ptr(), context.into(), hash) + }; + } + + pub fn has_collapsable_regions(&self) -> bool { + unsafe { BNHighLevelILTokenEmitterHasCollapsableRegions(self.handle.as_ptr()) } + } + + pub fn set_has_collapsable_regions(&self, state: bool) { + unsafe { BNHighLevelILTokenEmitterSetHasCollapsableRegions(self.handle.as_ptr(), state) }; + } + + pub fn append(&self, token: InstructionTextToken) { + let mut raw_token = InstructionTextToken::into_raw(token); + unsafe { BNHighLevelILTokenEmitterAppend(self.handle.as_ptr(), &mut raw_token) }; + InstructionTextToken::free_raw(raw_token); + } + + /// Starts a new line in the output. + pub fn init_line(&self) { + unsafe { BNHighLevelILTokenEmitterInitLine(self.handle.as_ptr()) }; + } + + // TODO: Difference from `init_line`? + /// Starts a new line in the output. + pub fn new_line(&self) { + unsafe { BNHighLevelILTokenEmitterNewLine(self.handle.as_ptr()) }; + } + + /// Increases the indentation level by one. + pub fn increase_indent(&self) { + unsafe { BNHighLevelILTokenEmitterIncreaseIndent(self.handle.as_ptr()) }; + } + + /// Decreases the indentation level by one. + pub fn decrease_indent(&self) { + unsafe { BNHighLevelILTokenEmitterDecreaseIndent(self.handle.as_ptr()) }; + } + + /// Indicates that visual separation of scopes is desirable at the current position. + /// + /// By default, this will insert a blank line, but this can be configured by the user. + pub fn scope_separator(&self) { + unsafe { BNHighLevelILTokenEmitterScopeSeparator(self.handle.as_ptr()) }; + } + + /// Begins a new scope. Insertion of newlines and braces will be handled using the current settings. + pub fn begin_scope(&self, ty: ScopeType) { + unsafe { BNHighLevelILTokenEmitterBeginScope(self.handle.as_ptr(), ty) }; + } + + /// Ends the current scope. + /// + /// The type `ty` should be equal to what was passed to [`HighLevelILTokenEmitter::begin_scope`]. + pub fn end_scope(&self, ty: ScopeType) { + unsafe { BNHighLevelILTokenEmitterEndScope(self.handle.as_ptr(), ty) }; + } + + /// Continues the previous scope with a new associated scope. This is most commonly used for else statements. + /// + /// If `force_same_line` is true, the continuation will always be placed on the same line as the previous scope. + pub fn scope_continuation(&self, force_same_line: bool) { + unsafe { + BNHighLevelILTokenEmitterScopeContinuation(self.handle.as_ptr(), force_same_line) + }; + } + + /// Finalizes the previous scope, indicating that there are no more associated scopes. + pub fn finalize_scope(&self) { + unsafe { BNHighLevelILTokenEmitterFinalizeScope(self.handle.as_ptr()) }; + } + + /// Forces there to be no indentation for the next line. + pub fn no_indent_for_this_line(&self) { + unsafe { BNHighLevelILTokenEmitterNoIndentForThisLine(self.handle.as_ptr()) }; + } + + /// Begins a region of tokens that always have zero confidence. + pub fn begin_force_zero_confidence(&self) { + unsafe { BNHighLevelILTokenEmitterBeginForceZeroConfidence(self.handle.as_ptr()) }; + } + + /// Ends a region of tokens that always have zero confidence. + pub fn end_force_zero_confidence(&self) { + unsafe { BNHighLevelILTokenEmitterEndForceZeroConfidence(self.handle.as_ptr()) }; + } + + /// Sets the current expression. Returning the [`CurrentTokenEmitterExpr`] which when dropped + /// will restore the previously active [`TokenEmitterExpr`]. + pub fn set_current_expr(&self, expr: TokenEmitterExpr) -> CurrentTokenEmitterExpr { + let previous_expr = + unsafe { BNHighLevelILTokenEmitterSetCurrentExpr(self.handle.as_ptr(), expr) }; + CurrentTokenEmitterExpr::new(self.to_owned(), expr, previous_expr) + } + + fn restore_current_expr(&self, expr: TokenEmitterExpr) { + unsafe { BNHighLevelILTokenEmitterRestoreCurrentExpr(self.handle.as_ptr(), expr) }; + } + + /// Finalizes the outputted lines. + pub fn finalize(&self) { + unsafe { BNHighLevelILTokenEmitterFinalize(self.handle.as_ptr()) }; + } + + /// Appends `(`. + pub fn append_open_paren(&self) { + unsafe { BNHighLevelILTokenEmitterAppendOpenParen(self.handle.as_ptr()) }; + } + + /// Appends `)`. + pub fn append_close_paren(&self) { + unsafe { BNHighLevelILTokenEmitterAppendCloseParen(self.handle.as_ptr()) }; + } + + /// Appends `[`. + pub fn append_open_bracket(&self) { + unsafe { BNHighLevelILTokenEmitterAppendOpenBracket(self.handle.as_ptr()) }; + } + + /// Appends `]`. + pub fn append_close_bracket(&self) { + unsafe { BNHighLevelILTokenEmitterAppendCloseBracket(self.handle.as_ptr()) }; + } + + /// Appends `{`. + pub fn append_open_brace(&self) { + unsafe { BNHighLevelILTokenEmitterAppendOpenBrace(self.handle.as_ptr()) }; + } + + /// Appends `}`. + pub fn append_close_brace(&self) { + unsafe { BNHighLevelILTokenEmitterAppendCloseBrace(self.handle.as_ptr()) }; + } + + /// Appends `;`. + pub fn append_semicolon(&self) { + unsafe { BNHighLevelILTokenEmitterAppendSemicolon(self.handle.as_ptr()) }; + } + + /// Sets the requirement for insertion of braces around scopes in the output. + pub fn set_brace_requirement(&self, required: BraceRequirement) { + unsafe { BNHighLevelILTokenEmitterSetBraceRequirement(self.handle.as_ptr(), required) }; + } + + /// Sets whether cases within switch statements should always have braces around them. + pub fn set_braces_around_switch_cases(&self, braces: bool) { + unsafe { + BNHighLevelILTokenEmitterSetBracesAroundSwitchCases(self.handle.as_ptr(), braces) + }; + } + + /// Sets whether braces should default to being on the same line as the statement that begins the scope. + /// + /// If the user has explicitly set a preference, this setting will be ignored and the user's preference will be used instead. + pub fn set_default_braces_on_same_line(&self, same_line: bool) { + unsafe { + BNHighLevelILTokenEmitterSetDefaultBracesOnSameLine(self.handle.as_ptr(), same_line) + }; + } + + /// Sets whether omitting braces around single-line scopes is allowed. + pub fn set_simple_scope_allowed(&self, allowed: bool) { + unsafe { BNHighLevelILTokenEmitterSetSimpleScopeAllowed(self.handle.as_ptr(), allowed) }; + } + + pub fn brace_requirement(&self) -> BraceRequirement { + unsafe { BNHighLevelILTokenEmitterGetBraceRequirement(self.handle.as_ptr()) } + } + + pub fn has_braces_around_switch_cases(&self) -> bool { + unsafe { BNHighLevelILTokenEmitterHasBracesAroundSwitchCases(self.handle.as_ptr()) } + } + + pub fn default_braces_on_same_line(&self) -> bool { + unsafe { BNHighLevelILTokenEmitterGetDefaultBracesOnSameLine(self.handle.as_ptr()) } + } + + pub fn is_simple_scope_allowed(&self) -> bool { + unsafe { BNHighLevelILTokenEmitterIsSimpleScopeAllowed(self.handle.as_ptr()) } + } + + /// Appends a size token for the given size in the High Level IL syntax. + pub fn append_size_token(&self, size: usize, ty: InstructionTextTokenType) { + unsafe { BNAddHighLevelILSizeToken(size, ty, self.handle.as_ptr()) } + } + + /// Appends a floating point size token for the given size in the High Level IL syntax. + pub fn append_float_size_token(&self, size: usize, ty: InstructionTextTokenType) { + unsafe { BNAddHighLevelILFloatSizeToken(size, ty, self.handle.as_ptr()) } + } + + /// Appends tokens for access to a variable. + pub fn append_var_text_token( + &self, + func: &HighLevelILFunction, + var: Variable, + expr_index: usize, + size: usize, + ) { + unsafe { + BNAddHighLevelILVarTextToken( + func.handle, + &BNVariable::from(var), + self.handle.as_ptr(), + expr_index, + size, + ) + } + } + + /// Appends tokens for a constant integer value. + pub fn append_integer_text_token( + &self, + func: &HighLevelILFunction, + expr_index: usize, + val: i64, + size: usize, + ) { + unsafe { + BNAddHighLevelILIntegerTextToken( + func.handle, + expr_index, + val, + size, + self.handle.as_ptr(), + ) + } + } + + /// Appends tokens for accessing an array by constant index. + pub fn append_array_index_token( + &self, + func: &HighLevelILFunction, + expr_index: usize, + val: i64, + size: usize, + address: Option, + ) { + unsafe { + BNAddHighLevelILArrayIndexToken( + func.handle, + expr_index, + val, + size, + self.handle.as_ptr(), + address.unwrap_or(0), + ) + } + } + + /// Appends tokens for displaying a constant pointer value. + /// + /// If `allow_short_string` is true, then a string will be shown even if it is "short". + pub fn append_pointer_text_token( + &self, + func: &HighLevelILFunction, + expr_index: usize, + val: i64, + settings: &DisassemblySettings, + symbol_display: SymbolDisplayType, + precedence: OperatorPrecedence, + allow_short_string: bool, + ) -> SymbolDisplayResult { + unsafe { + BNAddHighLevelILPointerTextToken( + func.handle, + expr_index, + val, + self.handle.as_ptr(), + settings.handle, + symbol_display, + precedence, + allow_short_string, + ) + } + } + + /// Appends tokens for a constant value. + pub fn append_constant_text_token( + &self, + func: &HighLevelILFunction, + expr_index: usize, + val: i64, + size: usize, + settings: &DisassemblySettings, + precedence: OperatorPrecedence, + ) { + unsafe { + BNAddHighLevelILConstantTextToken( + func.handle, + expr_index, + val, + size, + self.handle.as_ptr(), + settings.handle, + precedence, + ) + } + } +} + +unsafe impl Send for HighLevelILTokenEmitter {} +unsafe impl Sync for HighLevelILTokenEmitter {} + +unsafe impl RefCountable for HighLevelILTokenEmitter { + unsafe fn inc_ref(handle: &Self) -> Ref { + let handle = BNNewHighLevelILTokenEmitterReference(handle.handle.as_ptr()); + let handle = NonNull::new(handle).unwrap(); + Ref::new(HighLevelILTokenEmitter { handle }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeHighLevelILTokenEmitter(handle.handle.as_ptr()) + } +} + +impl ToOwned for HighLevelILTokenEmitter { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +/// Manages the currently active [`TokenEmitterExpr`] for the given [`HighLevelILTokenEmitter`]. +/// +/// When this object is destroyed, the previously active [`TokenEmitterExpr`] will become active again. +pub struct CurrentTokenEmitterExpr { + pub emitter: Ref, + pub expr: TokenEmitterExpr, + pub previous_expr: TokenEmitterExpr, +} + +impl CurrentTokenEmitterExpr { + pub fn new( + emitter: Ref, + expr: TokenEmitterExpr, + previous_expr: TokenEmitterExpr, + ) -> Self { + Self { + emitter, + expr, + previous_expr, + } + } +} + +impl Drop for CurrentTokenEmitterExpr { + fn drop(&mut self) { + self.emitter.restore_current_expr(self.previous_expr); + } +} diff --git a/rust/src/language_representation.rs b/rust/src/language_representation.rs new file mode 100644 index 0000000000..50e7b710d8 --- /dev/null +++ b/rust/src/language_representation.rs @@ -0,0 +1,635 @@ +use std::ffi::{c_char, c_void}; +use std::mem::MaybeUninit; +use std::ptr::NonNull; + +use binaryninjacore_sys::*; + +use crate::architecture::{Architecture, CoreArchitecture}; +use crate::basic_block::{BasicBlock, BlockContext}; +use crate::binary_view::BinaryView; +use crate::disassembly::{DisassemblySettings, DisassemblyTextLine}; +use crate::function::{Function, HighlightColor}; +use crate::high_level_il::token_emitter::HighLevelILTokenEmitter; +use crate::high_level_il::{HighLevelILFunction, HighLevelInstructionIndex}; +use crate::line_formatter::CoreLineFormatter; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; +use crate::string::{BnStrCompatible, BnString}; +use crate::type_parser::CoreTypeParser; +use crate::type_printer::CoreTypePrinter; + +pub type InstructionTextTokenContext = BNInstructionTextTokenContext; +pub type ScopeType = BNScopeType; +pub type BraceRequirement = BNBraceRequirement; +pub type SymbolDisplayType = BNSymbolDisplayType; +pub type OperatorPrecedence = BNOperatorPrecedence; +pub type SymbolDisplayResult = BNSymbolDisplayResult; + +pub fn register_language_representation_function_type< + C: LanguageRepresentationFunctionType, + F: FnOnce(CoreLanguageRepresentationFunctionType) -> C, + B: BnStrCompatible, +>( + creator: F, + name: B, +) -> CoreLanguageRepresentationFunctionType { + let custom = Box::leak(Box::new(MaybeUninit::uninit())); + let mut callbacks = BNCustomLanguageRepresentationFunctionType { + context: custom as *mut MaybeUninit as *mut c_void, + create: Some(cb_create::), + isValid: Some(cb_is_valid::), + getTypePrinter: Some(cb_get_type_printer::), + getTypeParser: Some(cb_get_type_parser::), + getLineFormatter: Some(cb_get_line_formatter::), + getFunctionTypeTokens: Some(cb_get_function_type_tokens::), + freeLines: Some(cb_free_lines), + }; + let name = name.into_bytes_with_nul(); + let core = unsafe { + BNRegisterLanguageRepresentationFunctionType( + name.as_ref().as_ptr() as *const c_char, + &mut callbacks, + ) + }; + let core = + unsafe { CoreLanguageRepresentationFunctionType::from_raw(NonNull::new(core).unwrap()) }; + custom.write(creator(core)); + core +} + +pub trait LanguageRepresentationFunction: Send + Sync { + fn on_token_emitter_init(&self, tokens: &HighLevelILTokenEmitter); + + fn expr_text( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + tokens: &HighLevelILTokenEmitter, + settings: &DisassemblySettings, + as_full_ast: bool, + precedence: OperatorPrecedence, + statement: bool, + ); + + fn begin_lines( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + tokens: &HighLevelILTokenEmitter, + ); + + fn end_lines( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + tokens: &HighLevelILTokenEmitter, + ); + + fn comment_start_string(&self) -> &str; + + fn comment_end_string(&self) -> &str; + + fn annotation_start_string(&self) -> &str; + + fn annotation_end_string(&self) -> &str; +} + +pub trait LanguageRepresentationFunctionType: Send + Sync { + fn create( + &self, + arch: &CoreArchitecture, + owner: &Function, + high_level_il: &HighLevelILFunction, + ) -> Ref; + + fn is_valid(&self, view: &BinaryView) -> bool; + + fn type_printer(&self) -> Option { + None + } + + fn type_parser(&self) -> Option { + None + } + + fn line_formatter(&self) -> Option { + None + } + + fn function_type_tokens( + &self, + func: &Function, + settings: &DisassemblySettings, + ) -> Vec; +} + +// NOTE static, it never gets freed, so we can clone/copy it +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct CoreLanguageRepresentationFunctionType { + handle: NonNull, +} + +impl CoreLanguageRepresentationFunctionType { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) fn as_raw(&self) -> *mut BNLanguageRepresentationFunctionType { + self.handle.as_ptr() + } + + pub fn from_name(name: S) -> Option { + let name = name.into_bytes_with_nul(); + let result = unsafe { + BNGetLanguageRepresentationFunctionTypeByName(name.as_ref().as_ptr() as *const c_char) + }; + NonNull::new(result).map(|handle| unsafe { Self::from_raw(handle) }) + } + + pub fn all() -> Array { + let mut count = 0; + let result = unsafe { BNGetLanguageRepresentationFunctionTypeList(&mut count) }; + unsafe { Array::new(result, count, ()) } + } + + pub fn tokens( + &self, + func: &Function, + settings: &DisassemblySettings, + ) -> Array { + let mut count = 0; + let result = unsafe { + BNGetLanguageRepresentationFunctionTypeFunctionTypeTokens( + self.handle.as_ptr(), + func.handle, + settings.handle, + &mut count, + ) + }; + unsafe { Array::new(result, count, ()) } + } + + pub fn name(&self) -> BnString { + unsafe { + BnString::from_raw(BNGetLanguageRepresentationFunctionTypeName( + self.handle.as_ptr(), + )) + } + } + + pub fn create(&self, func: &Function) -> Ref { + let repr_func = unsafe { + BNCreateLanguageRepresentationFunction( + self.handle.as_ptr(), + func.arch().handle, + func.handle, + match func.high_level_il(false) { + Ok(hlil) => hlil.handle, + Err(_) => std::ptr::null_mut(), + }, + ) + }; + + unsafe { + CoreLanguageRepresentationFunction::ref_from_raw(NonNull::new(repr_func).unwrap()) + } + } + + pub fn is_valid(&self, view: &BinaryView) -> bool { + unsafe { BNIsLanguageRepresentationFunctionTypeValid(self.handle.as_ptr(), view.handle) } + } + + pub fn printer(&self) -> CoreTypePrinter { + let type_printer = + unsafe { BNGetLanguageRepresentationFunctionTypePrinter(self.handle.as_ptr()) }; + unsafe { CoreTypePrinter::from_raw(NonNull::new(type_printer).unwrap()) } + } + + pub fn parser(&self) -> CoreTypeParser { + let type_parser = + unsafe { BNGetLanguageRepresentationFunctionTypeParser(self.handle.as_ptr()) }; + unsafe { CoreTypeParser::from_raw(NonNull::new(type_parser).unwrap()) } + } + + pub fn line_formatter(&self) -> CoreLineFormatter { + let formatter = + unsafe { BNGetLanguageRepresentationFunctionTypeLineFormatter(self.handle.as_ptr()) }; + CoreLineFormatter::from_raw(NonNull::new(formatter).unwrap()) + } +} + +impl CoreArrayProvider for CoreLanguageRepresentationFunctionType { + type Raw = *mut BNLanguageRepresentationFunctionType; + type Context = (); + type Wrapped<'a> = &'a CoreLanguageRepresentationFunctionType; +} + +unsafe impl CoreArrayProviderInner for CoreLanguageRepresentationFunctionType { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeLanguageRepresentationFunctionTypeList(raw) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + // SAFETY: CoreLanguageRepresentationFunctionType and BNCoreLanguageRepresentationFunctionType + // transparent + std::mem::transmute::< + &*mut BNLanguageRepresentationFunctionType, + &CoreLanguageRepresentationFunctionType, + >(raw) + } +} + +pub struct CoreLanguageRepresentationFunction { + handle: NonNull, +} + +impl CoreLanguageRepresentationFunction { + pub(crate) unsafe fn ref_from_raw( + handle: NonNull, + ) -> Ref { + unsafe { Ref::new(Self { handle }) } + } + + pub fn new( + repr_type: &CoreLanguageRepresentationFunctionType, + repr_context: C, + arch: &A, + func: &Function, + high_level_il: &HighLevelILFunction, + ) -> Ref { + let core_arch: &CoreArchitecture = arch.as_ref(); + let context: &mut C = Box::leak(Box::new(repr_context)); + let mut callbacks = BNCustomLanguageRepresentationFunction { + context: context as *mut C as *mut c_void, + freeObject: Some(cb_free_object::), + externalRefTaken: Some(cb_external_ref_taken::), + externalRefReleased: Some(cb_external_ref_released::), + initTokenEmitter: Some(cb_init_token_emitter::), + getExprText: Some(cb_get_expr_text::), + beginLines: Some(cb_begin_lines::), + endLines: Some(cb_end_lines::), + getCommentStartString: Some(cb_get_comment_start_string::), + getCommentEndString: Some(cb_get_comment_end_string::), + getAnnotationStartString: Some(cb_get_annotation_start_string::), + getAnnotationEndString: Some(cb_get_annotation_end_string::), + }; + let handle = unsafe { + BNCreateCustomLanguageRepresentationFunction( + repr_type.as_raw(), + core_arch.handle, + func.handle, + high_level_il.handle, + &mut callbacks, + ) + }; + unsafe { Self::ref_from_raw(NonNull::new(handle).unwrap()) } + } + + pub fn expr_text( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + settings: &DisassemblySettings, + as_full_ast: bool, + precedence: OperatorPrecedence, + statement: bool, + ) -> Array { + let mut count = 0; + let result = unsafe { + BNGetLanguageRepresentationFunctionExprText( + self.handle.as_ptr(), + il.handle, + expr_index.0, + settings.handle, + as_full_ast, + precedence, + statement, + &mut count, + ) + }; + unsafe { Array::new(result, count, ()) } + } + + pub fn linear_lines( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + settings: &DisassemblySettings, + as_full_ast: bool, + ) -> Array { + let mut count = 0; + let result = unsafe { + BNGetLanguageRepresentationFunctionLinearLines( + self.handle.as_ptr(), + il.handle, + expr_index.0, + settings.handle, + as_full_ast, + &mut count, + ) + }; + unsafe { Array::new(result, count, ()) } + } + + pub fn block_lines( + &self, + block: &BasicBlock, + settings: &DisassemblySettings, + ) -> Array { + let mut count = 0; + let result = unsafe { + BNGetLanguageRepresentationFunctionBlockLines( + self.handle.as_ptr(), + block.handle, + settings.handle, + &mut count, + ) + }; + unsafe { Array::new(result, count, ()) } + } + + pub fn highlight(&self, block: &BasicBlock) -> HighlightColor { + let result = unsafe { + BNGetLanguageRepresentationFunctionHighlight(self.handle.as_ptr(), block.handle) + }; + result.into() + } + + pub fn get_type(&self) -> CoreLanguageRepresentationFunctionType { + let repr_type = unsafe { BNGetLanguageRepresentationType(self.handle.as_ptr()) }; + unsafe { + CoreLanguageRepresentationFunctionType::from_raw(NonNull::new(repr_type).unwrap()) + } + } + + pub fn arch(&self) -> CoreArchitecture { + let arch = unsafe { BNGetLanguageRepresentationArchitecture(self.handle.as_ptr()) }; + unsafe { CoreArchitecture::from_raw(arch) } + } + + pub fn owner_function(&self) -> Ref { + let func = unsafe { BNGetLanguageRepresentationOwnerFunction(self.handle.as_ptr()) }; + unsafe { Function::ref_from_raw(func) } + } + + pub fn hlil(&self) -> Ref { + let hlil = unsafe { BNGetLanguageRepresentationILFunction(self.handle.as_ptr()) }; + unsafe { HighLevelILFunction::ref_from_raw(hlil, false) } + } + + pub fn comment_start_string(&self) -> BnString { + unsafe { + BnString::from_raw(BNGetLanguageRepresentationFunctionCommentStartString( + self.handle.as_ptr(), + )) + } + } + + pub fn comment_end_string(&self) -> BnString { + unsafe { + BnString::from_raw(BNGetLanguageRepresentationFunctionCommentEndString( + self.handle.as_ptr(), + )) + } + } + + pub fn annotation_start_string(&self) -> BnString { + unsafe { + BnString::from_raw(BNGetLanguageRepresentationFunctionAnnotationStartString( + self.handle.as_ptr(), + )) + } + } + + pub fn annotation_end_string(&self) -> BnString { + unsafe { + BnString::from_raw(BNGetLanguageRepresentationFunctionAnnotationEndString( + self.handle.as_ptr(), + )) + } + } +} + +unsafe impl RefCountable for CoreLanguageRepresentationFunction { + unsafe fn inc_ref(handle: &Self) -> Ref { + Self::ref_from_raw( + NonNull::new(BNNewLanguageRepresentationFunctionReference( + handle.handle.as_ptr(), + )) + .unwrap(), + ) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeLanguageRepresentationFunction(handle.handle.as_ptr()) + } +} + +impl ToOwned for CoreLanguageRepresentationFunction { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { ::inc_ref(self) } + } +} + +unsafe extern "C" fn cb_create( + ctxt: *mut c_void, + arch: *mut BNArchitecture, + owner: *mut BNFunction, + high_level_il: *mut BNHighLevelILFunction, +) -> *mut BNLanguageRepresentationFunction { + let ctxt = ctxt as *mut C; + let arch = CoreArchitecture::from_raw(arch); + let owner = Function::from_raw(owner); + let high_level_il = HighLevelILFunction { + full_ast: false, + handle: high_level_il, + }; + let result = (*ctxt).create(&arch, &owner, &high_level_il); + Ref::into_raw(result).handle.as_ptr() +} + +unsafe extern "C" fn cb_is_valid( + ctxt: *mut c_void, + view: *mut BNBinaryView, +) -> bool { + let ctxt = ctxt as *mut C; + let view = BinaryView::from_raw(view); + (*ctxt).is_valid(&view) +} + +unsafe extern "C" fn cb_get_type_printer( + ctxt: *mut c_void, +) -> *mut BNTypePrinter { + let ctxt = ctxt as *mut C; + match (*ctxt).type_printer() { + None => std::ptr::null_mut(), + Some(printer) => printer.handle.as_ptr(), + } +} + +unsafe extern "C" fn cb_get_type_parser( + ctxt: *mut c_void, +) -> *mut BNTypeParser { + let ctxt = ctxt as *mut C; + match (*ctxt).type_parser() { + None => std::ptr::null_mut(), + Some(parser) => parser.handle.as_ptr(), + } +} + +unsafe extern "C" fn cb_get_line_formatter( + ctxt: *mut c_void, +) -> *mut BNLineFormatter { + let ctxt = ctxt as *mut C; + match (*ctxt).line_formatter() { + None => std::ptr::null_mut(), + Some(formatter) => formatter.handle.as_ptr(), + } +} + +unsafe extern "C" fn cb_get_function_type_tokens( + ctxt: *mut c_void, + func: *mut BNFunction, + settings: *mut BNDisassemblySettings, + count: *mut usize, +) -> *mut BNDisassemblyTextLine { + let ctxt = ctxt as *mut C; + let func = Function::from_raw(func); + let settings = DisassemblySettings { handle: settings }; + let result = (*ctxt).function_type_tokens(&func, &settings); + *count = result.len(); + let result: Box<[BNDisassemblyTextLine]> = result + .into_iter() + .map(DisassemblyTextLine::into_raw) + .collect(); + // NOTE freed by function_type_free_lines_ffi + Box::leak(result).as_mut_ptr() +} + +unsafe extern "C" fn cb_free_lines( + _ctxt: *mut c_void, + lines: *mut BNDisassemblyTextLine, + count: usize, +) { + let lines: Box<[BNDisassemblyTextLine]> = + Box::from_raw(core::slice::from_raw_parts_mut(lines, count)); + for line in lines { + DisassemblyTextLine::free_raw(line); + } +} + +unsafe extern "C" fn cb_free_object(ctxt: *mut c_void) { + let ctxt = ctxt as *mut C; + drop(Box::from_raw(ctxt)) +} + +unsafe extern "C" fn cb_external_ref_taken(_ctxt: *mut c_void) { + // TODO Make an Arc? conflict with free? +} + +unsafe extern "C" fn cb_external_ref_released( + _ctxt: *mut c_void, +) { + // TODO Make an Arc? conflict with free? +} + +unsafe extern "C" fn cb_init_token_emitter( + ctxt: *mut c_void, + tokens: *mut BNHighLevelILTokenEmitter, +) { + let ctxt = ctxt as *mut C; + let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap()); + (*ctxt).on_token_emitter_init(&tokens) +} + +unsafe extern "C" fn cb_get_expr_text( + ctxt: *mut c_void, + il: *mut BNHighLevelILFunction, + expr_index: usize, + tokens: *mut BNHighLevelILTokenEmitter, + settings: *mut BNDisassemblySettings, + as_full_ast: bool, + precedence: BNOperatorPrecedence, + statement: bool, +) { + let ctxt = ctxt as *mut C; + let il = HighLevelILFunction { + full_ast: as_full_ast, + handle: il, + }; + let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap()); + let settings = DisassemblySettings { handle: settings }; + (*ctxt).expr_text( + &il, + expr_index.into(), + &tokens, + &settings, + as_full_ast, + precedence, + statement, + ); +} + +unsafe extern "C" fn cb_begin_lines( + ctxt: *mut c_void, + il: *mut BNHighLevelILFunction, + expr_index: usize, + tokens: *mut BNHighLevelILTokenEmitter, +) { + let ctxt = ctxt as *mut C; + let il = HighLevelILFunction { + full_ast: false, + handle: il, + }; + let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap()); + (*ctxt).begin_lines(&il, expr_index.into(), &tokens) +} + +unsafe extern "C" fn cb_end_lines( + ctxt: *mut c_void, + il: *mut BNHighLevelILFunction, + expr_index: usize, + tokens: *mut BNHighLevelILTokenEmitter, +) { + let ctxt = ctxt as *mut C; + let il = HighLevelILFunction { + full_ast: false, + handle: il, + }; + let tokens = HighLevelILTokenEmitter::from_raw(NonNull::new(tokens).unwrap()); + (*ctxt).end_lines(&il, expr_index.into(), &tokens) +} + +unsafe extern "C" fn cb_get_comment_start_string( + ctxt: *mut c_void, +) -> *mut c_char { + let ctxt = ctxt as *mut C; + let result = (*ctxt).comment_start_string(); + BnString::into_raw(BnString::new(result)) +} + +unsafe extern "C" fn cb_get_comment_end_string( + ctxt: *mut c_void, +) -> *mut c_char { + let ctxt = ctxt as *mut C; + let result = (*ctxt).comment_end_string(); + BnString::into_raw(BnString::new(result)) +} + +unsafe extern "C" fn cb_get_annotation_start_string( + ctxt: *mut c_void, +) -> *mut c_char { + let ctxt = ctxt as *mut C; + let result = (*ctxt).annotation_start_string(); + BnString::into_raw(BnString::new(result)) +} + +unsafe extern "C" fn cb_get_annotation_end_string( + ctxt: *mut c_void, +) -> *mut c_char { + let ctxt = ctxt as *mut C; + let result = (*ctxt).annotation_end_string(); + BnString::into_raw(BnString::new(result)) +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 7056e529a6..1b02da0d79 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -57,6 +57,8 @@ pub mod function_recognizer; pub mod headless; pub mod high_level_il; pub mod interaction; +pub mod language_representation; +pub mod line_formatter; pub mod linear_view; pub mod logger; pub mod low_level_il; diff --git a/rust/src/line_formatter.rs b/rust/src/line_formatter.rs new file mode 100644 index 0000000000..5dc07c5c70 --- /dev/null +++ b/rust/src/line_formatter.rs @@ -0,0 +1,172 @@ +use std::ffi::{c_char, c_void}; +use std::ptr::NonNull; + +use binaryninjacore_sys::*; + +use crate::disassembly::DisassemblyTextLine; +use crate::high_level_il::HighLevelILFunction; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; +use crate::string::{raw_to_string, BnStrCompatible, BnString}; + +/// Register a [`LineFormatter`] with the API. +pub fn register_line_formatter( + name: B, + formatter: C, +) -> CoreLineFormatter { + let custom = Box::leak(Box::new(formatter)); + let mut callbacks = BNCustomLineFormatter { + context: custom as *mut C as *mut c_void, + formatLines: Some(cb_format_lines::), + freeLines: Some(cb_free_lines), + }; + let name = name.into_bytes_with_nul(); + let handle = + unsafe { BNRegisterLineFormatter(name.as_ref().as_ptr() as *const c_char, &mut callbacks) }; + CoreLineFormatter::from_raw(NonNull::new(handle).unwrap()) +} + +pub trait LineFormatter: Sized { + fn format_lines( + &self, + lines: &[DisassemblyTextLine], + settings: &LineFormatterSettings, + ) -> Vec; +} + +#[repr(transparent)] +pub struct CoreLineFormatter { + pub(crate) handle: NonNull, +} + +impl CoreLineFormatter { + pub fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + /// Get the default [`CoreLineFormatter`] if available, because the user might have disabled it. + pub fn default_if_available() -> Option { + Some(unsafe { Self::from_raw(NonNull::new(BNGetDefaultLineFormatter())?) }) + } + + pub fn all() -> Array { + let mut count = 0; + let result = unsafe { BNGetLineFormatterList(&mut count) }; + unsafe { Array::new(result, count, ()) } + } + + pub fn from_name(name: S) -> Option { + let name_raw = name.into_bytes_with_nul(); + let result = + unsafe { BNGetLineFormatterByName(name_raw.as_ref().as_ptr() as *const c_char) }; + NonNull::new(result).map(Self::from_raw) + } + + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNGetLineFormatterName(self.handle.as_ptr())) } + } +} + +impl CoreArrayProvider for CoreLineFormatter { + type Raw = *mut BNLineFormatter; + type Context = (); + type Wrapped<'a> = Self; +} + +unsafe impl CoreArrayProviderInner for CoreLineFormatter { + unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) { + BNFreeLineFormatterList(raw) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + // TODO: Because handle is a NonNull we should prob make Self::Raw that as well... + let handle = NonNull::new(*raw).unwrap(); + CoreLineFormatter::from_raw(handle) + } +} + +#[derive(Clone, Debug)] +pub struct LineFormatterSettings { + pub high_level_il: Option>, + pub desired_line_len: usize, + pub min_content_len: usize, + pub tab_width: usize, + pub lang_name: String, + pub comment_start: String, + pub comment_end: String, + pub annotation_start: String, + pub annotation_end: String, +} + +impl LineFormatterSettings { + pub(crate) fn from_raw(value: &BNLineFormatterSettings) -> Self { + Self { + high_level_il: match value.highLevelIL.is_null() { + false => Some( + unsafe { HighLevelILFunction::from_raw(value.highLevelIL, false) }.to_owned(), + ), + true => None, + }, + desired_line_len: value.desiredLineLength, + min_content_len: value.minimumContentLength, + tab_width: value.tabWidth, + lang_name: raw_to_string(value.languageName as *mut _).unwrap(), + comment_start: raw_to_string(value.commentStartString as *mut _).unwrap(), + comment_end: raw_to_string(value.commentEndString as *mut _).unwrap(), + annotation_start: raw_to_string(value.annotationStartString as *mut _).unwrap(), + annotation_end: raw_to_string(value.annotationEndString as *mut _).unwrap(), + } + } + + #[allow(unused)] + pub(crate) fn from_owned_raw(value: BNLineFormatterSettings) -> Self { + let owned = Self::from_raw(&value); + Self::free_raw(value); + owned + } + + #[allow(unused)] + pub(crate) fn free_raw(value: BNLineFormatterSettings) { + let _ = unsafe { HighLevelILFunction::ref_from_raw(value.highLevelIL, false) }; + let _ = unsafe { BnString::from_raw(value.languageName as *mut _) }; + let _ = unsafe { BnString::from_raw(value.commentStartString as *mut _) }; + let _ = unsafe { BnString::from_raw(value.commentEndString as *mut _) }; + let _ = unsafe { BnString::from_raw(value.annotationStartString as *mut _) }; + let _ = unsafe { BnString::from_raw(value.annotationEndString as *mut _) }; + } +} + +unsafe extern "C" fn cb_format_lines( + ctxt: *mut c_void, + in_lines: *mut BNDisassemblyTextLine, + in_count: usize, + raw_settings: *const BNLineFormatterSettings, + out_count: *mut usize, +) -> *mut BNDisassemblyTextLine { + // NOTE dropped by line_formatter_free_lines_ffi + let ctxt = ctxt as *mut C; + let lines_slice = core::slice::from_raw_parts(in_lines, in_count); + let lines: Vec<_> = lines_slice + .iter() + .map(DisassemblyTextLine::from_raw) + .collect(); + let settings = LineFormatterSettings::from_raw(&*raw_settings); + let result = (*ctxt).format_lines(&lines, &settings); + *out_count = result.len(); + let result: Box<[BNDisassemblyTextLine]> = result + .into_iter() + .map(DisassemblyTextLine::into_raw) + .collect(); + Box::leak(result).as_mut_ptr() +} + +unsafe extern "C" fn cb_free_lines( + _ctxt: *mut c_void, + raw_lines: *mut BNDisassemblyTextLine, + count: usize, +) { + let lines: Box<[BNDisassemblyTextLine]> = + Box::from_raw(core::slice::from_raw_parts_mut(raw_lines, count)); + for line in lines { + DisassemblyTextLine::free_raw(line); + } +} diff --git a/rust/src/render_layer.rs b/rust/src/render_layer.rs index 08553552a2..181294d4ac 100644 --- a/rust/src/render_layer.rs +++ b/rust/src/render_layer.rs @@ -293,13 +293,13 @@ impl CoreRenderLayer { Self { handle } } - pub fn render_layers() -> Array { + pub fn all() -> Array { let mut count = 0; let result = unsafe { BNGetRenderLayerList(&mut count) }; unsafe { Array::new(result, count, ()) } } - pub fn render_layer_by_name(name: &str) -> Option { + pub fn from_name(name: &str) -> Option { let name_raw = name.to_cstr(); let result = unsafe { BNGetRenderLayerByName(name_raw.as_ptr()) }; NonNull::new(result).map(Self::from_raw) diff --git a/rust/src/type_parser.rs b/rust/src/type_parser.rs index 0ce46a50fc..13985c4434 100644 --- a/rust/src/type_parser.rs +++ b/rust/src/type_parser.rs @@ -37,7 +37,7 @@ pub fn register_type_parser( #[repr(transparent)] pub struct CoreTypeParser { - handle: NonNull, + pub(crate) handle: NonNull, } impl CoreTypeParser { diff --git a/rust/src/type_printer.rs b/rust/src/type_printer.rs index c9bec6090f..a7495f1c16 100644 --- a/rust/src/type_printer.rs +++ b/rust/src/type_printer.rs @@ -42,7 +42,7 @@ pub fn register_type_printer( #[repr(transparent)] pub struct CoreTypePrinter { - handle: NonNull, + pub(crate) handle: NonNull, } impl CoreTypePrinter { diff --git a/rust/tests/language_representation.rs b/rust/tests/language_representation.rs new file mode 100644 index 0000000000..5c034c2f5e --- /dev/null +++ b/rust/tests/language_representation.rs @@ -0,0 +1,186 @@ +use std::path::PathBuf; + +use binaryninja::architecture::CoreArchitecture; +use binaryninja::binary_view::{BinaryView, BinaryViewExt}; +use binaryninja::disassembly::{ + DisassemblySettings, DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind, +}; +use binaryninja::function::Function; +use binaryninja::headless::Session; +use binaryninja::high_level_il::token_emitter::HighLevelILTokenEmitter; +use binaryninja::high_level_il::{HighLevelILFunction, HighLevelInstructionIndex}; +use binaryninja::language_representation::{ + register_language_representation_function_type, CoreLanguageRepresentationFunction, + CoreLanguageRepresentationFunctionType, LanguageRepresentationFunction, + LanguageRepresentationFunctionType, OperatorPrecedence, +}; +use binaryninja::rc::Ref; + +struct MyLangReprType { + core: CoreLanguageRepresentationFunctionType, +} + +impl LanguageRepresentationFunctionType for MyLangReprType { + fn create( + &self, + arch: &CoreArchitecture, + func: &Function, + high_level_il: &HighLevelILFunction, + ) -> Ref { + CoreLanguageRepresentationFunction::new( + &self.core, + MyLangRepr {}, + arch, + func, + high_level_il, + ) + } + + fn is_valid(&self, _view: &BinaryView) -> bool { + true + } + + fn function_type_tokens( + &self, + _func: &Function, + _settings: &DisassemblySettings, + ) -> Vec { + todo!() + } +} + +unsafe impl Send for MyLangReprType {} +unsafe impl Sync for MyLangReprType {} + +struct MyLangRepr; + +impl LanguageRepresentationFunction for MyLangRepr { + fn on_token_emitter_init(&self, _tokens: &HighLevelILTokenEmitter) {} + + fn expr_text( + &self, + il: &HighLevelILFunction, + expr_index: HighLevelInstructionIndex, + tokens: &HighLevelILTokenEmitter, + _settings: &DisassemblySettings, + _as_full_ast: bool, + _precedence: OperatorPrecedence, + _statement: bool, + ) { + let instr = il.instruction_from_expr_index(expr_index).unwrap(); + let instr = instr.lift(); + use binaryninja::high_level_il::HighLevelILLiftedInstructionKind::*; + match &instr.kind { + Block(block) => { + tokens.append(InstructionTextToken::new( + format!("block {}\n", block.body.len()), + InstructionTextTokenKind::Text, + )); + for block_inst in &block.body { + self.expr_text( + il, + block_inst.expr_index, + tokens, + _settings, + _as_full_ast, + _precedence, + _statement, + ); + } + } + Unimpl | Unreachable | Undef => panic!(), + _kind => { + tokens.append(InstructionTextToken::new( + format!("other instr {:x}\n", instr.address), + InstructionTextTokenKind::Text, + )); + } + } + } + + fn begin_lines( + &self, + _il: &HighLevelILFunction, + _expr_index: HighLevelInstructionIndex, + _tokens: &HighLevelILTokenEmitter, + ) { + } + + fn end_lines( + &self, + _il: &HighLevelILFunction, + _expr_index: HighLevelInstructionIndex, + _tokens: &HighLevelILTokenEmitter, + ) { + } + + fn comment_start_string(&self) -> &str { + "/* " + } + + fn comment_end_string(&self) -> &str { + " */" + } + + fn annotation_start_string(&self) -> &str { + "{" + } + + fn annotation_end_string(&self) -> &str { + "}" + } +} + +#[test] +fn test_custom_language_representation() { + const LANG_REPR_NAME: &str = "test_lang_repr"; + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + + let my_repr = register_language_representation_function_type( + |core| MyLangReprType { core }, + LANG_REPR_NAME, + ); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + let func = view + .function_at(&view.default_platform().unwrap(), 0x36760) + .unwrap(); + let _repr = my_repr.create(&func); + let il = func.high_level_il(false).unwrap(); + + let settings = DisassemblySettings::new(); + let root_idx = il.root_instruction_index(); + let result = _repr.linear_lines(&il, root_idx, &settings, false); + let output: String = result.iter().map(|dis| dis.to_string()).collect(); + assert_eq!( + format!("{output}"), + "block 26 +other instr 36775 +other instr 3679e +other instr 3679e +other instr 367ba +other instr 367e6 +other instr 3682f +other instr 3682f +other instr 36834 +other instr 3683e +other instr 3684e +other instr 36867 +other instr 36881 +other instr 36881 +other instr 36881 +other instr 36896 +other instr 368a0 +other instr 368bb +other instr 368d2 +other instr 3694a +other instr 36960 +other instr 369e1 +other instr 369ec +other instr 36a2e +other instr 36ab5 +other instr 36abd +other instr 36ac2 +" + ); +} diff --git a/rust/tests/line_formatter.rs b/rust/tests/line_formatter.rs new file mode 100644 index 0000000000..72968238fe --- /dev/null +++ b/rust/tests/line_formatter.rs @@ -0,0 +1,24 @@ +use binaryninja::disassembly::DisassemblyTextLine; +use binaryninja::headless::Session; +use binaryninja::line_formatter::{register_line_formatter, LineFormatter, LineFormatterSettings}; +use std::path::PathBuf; + +struct MyLineFormatter; + +impl LineFormatter for MyLineFormatter { + fn format_lines( + &self, + lines: &[DisassemblyTextLine], + _settings: &LineFormatterSettings, + ) -> Vec { + lines.to_vec() + } +} + +#[test] +fn test_custom_line_formatter() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let line_formatter = register_line_formatter("my_line_formatter", MyLineFormatter {}); + assert_eq!(line_formatter.name().as_str(), "my_line_formatter"); +} diff --git a/rust/tests/render_layer.rs b/rust/tests/render_layer.rs index 05ea17f6bd..6f6ebc9818 100644 --- a/rust/tests/render_layer.rs +++ b/rust/tests/render_layer.rs @@ -13,7 +13,7 @@ fn test_render_layer_register() { struct EmptyRenderLayer; impl RenderLayer for EmptyRenderLayer {} register_render_layer("Test Render Layer", EmptyRenderLayer, Default::default()); - CoreRenderLayer::render_layer_by_name("Test Render Layer").expect("Failed to get render layer"); + CoreRenderLayer::from_name("Test Render Layer").expect("Failed to get render layer"); } #[test] From 11ff31bc342398f24234a9311b602e0ef4655ee7 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Thu, 8 May 2025 14:21:34 -0400 Subject: [PATCH 23/54] [Rust] Add doc comments for undo actions --- rust/src/file_metadata.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index d4de13a264..56c8a9e9a6 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -113,6 +113,16 @@ impl FileMetadata { unsafe { BNIsBackedByDatabase(self.handle, view_type.as_ref().as_ptr() as *const _) } } + /// Runs a failable function where the failure state will revert any undo actions that occurred + /// during the time of the function's execution. + /// + /// NOTE: This will commit or undo any actions that occurred on **any** thread as this state is not thread local. + /// + /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread + /// and the thread executing this function, you can deadlock. You should also never call this function + /// on multiple threads at a time. See the following issues: + /// - https://github.com/Vector35/binaryninja-api/issues/6289 + /// - https://github.com/Vector35/binaryninja-api/issues/6325 pub fn run_undoable_transaction Result, T, E>( &self, func: F, @@ -131,10 +141,24 @@ impl FileMetadata { } } + /// Creates a new undo entry, any undo actions after this will be added to this entry. + /// + /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread + /// and the thread executing this function, you can deadlock. You should also never call this function + /// on multiple threads at a time. See the following issues: + /// - https://github.com/Vector35/binaryninja-api/issues/6289 + /// - https://github.com/Vector35/binaryninja-api/issues/6325 pub fn begin_undo_actions(&self, anonymous_allowed: bool) -> String { unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } + /// Commits the undo entry with the id to the undo buffer. + /// + /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread + /// and the thread executing this function, you can deadlock. You should also never call this function + /// on multiple threads at a time. See the following issues: + /// - https://github.com/Vector35/binaryninja-api/issues/6289 + /// - https://github.com/Vector35/binaryninja-api/issues/6325 pub fn commit_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { @@ -142,6 +166,13 @@ impl FileMetadata { } } + /// Reverts the undo actions committed in the undo entry. + /// + /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread + /// and the thread executing this function, you can deadlock. You should also never call this function + /// on multiple threads at a time. See the following issues: + /// - https://github.com/Vector35/binaryninja-api/issues/6289 + /// - https://github.com/Vector35/binaryninja-api/issues/6325 pub fn revert_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { From 12cc1e004b74ea3d915e7190fa6e9173496dc038 Mon Sep 17 00:00:00 2001 From: rbran Date: Wed, 23 Apr 2025 19:24:45 +0000 Subject: [PATCH 24/54] [Rust] Implement custom interactive handler --- plugins/dwarf/dwarf_export/src/lib.rs | 180 ++++---- rust/src/binary_view.rs | 40 ++ rust/src/function.rs | 16 +- rust/src/interaction.rs | 433 +++---------------- rust/src/interaction/form.rs | 411 ++++++++++++++++++ rust/src/interaction/handler.rs | 598 ++++++++++++++++++++++++++ rust/src/interaction/report.rs | 311 ++++++++++++++ rust/src/language_representation.rs | 23 +- rust/src/line_formatter.rs | 21 +- rust/src/string.rs | 12 +- rust/tests/interaction.rs | 169 ++++++++ 11 files changed, 1695 insertions(+), 519 deletions(-) create mode 100644 rust/src/interaction/form.rs create mode 100644 rust/src/interaction/handler.rs create mode 100644 rust/src/interaction/report.rs create mode 100644 rust/tests/interaction.rs diff --git a/plugins/dwarf/dwarf_export/src/lib.rs b/plugins/dwarf/dwarf_export/src/lib.rs index d1754d2950..283a60abe0 100644 --- a/plugins/dwarf/dwarf_export/src/lib.rs +++ b/plugins/dwarf/dwarf_export/src/lib.rs @@ -1,27 +1,26 @@ mod edit_distance; -use gimli::{ - constants, - write::{ - Address, AttributeValue, DwarfUnit, EndianVec, Expression, Range, RangeList, Sections, - UnitEntryId, - }, -}; -use object::{write, Architecture, BinaryFormat, SectionKind}; -use std::fs; - +use binaryninja::interaction::form::{Form, FormInputField}; use binaryninja::logger::Logger; use binaryninja::{ binary_view::{BinaryView, BinaryViewBase, BinaryViewExt}, command::{register_command, Command}, confidence::Conf, - interaction, - interaction::{FormResponses, FormResponses::Index}, rc::Ref, symbol::SymbolType, types::{MemberAccess, StructureType, Type, TypeClass}, }; +use gimli::{ + constants, + write::{ + Address, AttributeValue, DwarfUnit, EndianVec, Expression, Range, RangeList, Sections, + UnitEntryId, + }, +}; use log::{error, info, LevelFilter}; +use object::{write, Architecture, BinaryFormat, SectionKind}; +use std::fs; +use std::path::{Path, PathBuf}; fn export_type( name: String, @@ -598,10 +597,11 @@ fn export_data_vars( } } -fn present_form(bv_arch: &str) -> Vec { - // TODO : Verify inputs (like save location) so that we can fail early - // TODO : Add Language field - // TODO : Choose to export types/functions/etc +// TODO : Verify inputs (like save location) so that we can fail early +// TODO : Add Language field +// TODO : Choose to export types/functions/etc +// TODO: Add actual / better support for formats other than elf? +fn create_export_form(bv_arch: &str) -> Form { let archs = [ "Unknown", "AArch64", @@ -627,80 +627,37 @@ fn present_form(bv_arch: &str) -> Vec { "Wasm32", "Xtensa", ]; - interaction::FormInputBuilder::new() - .save_file_field( - "Save Location", - Some("Debug Files (*.dwo *.debug);;All Files (*)"), - None, - None, - ) - .choice_field( - "Architecture", - &archs, - archs - .iter() - .enumerate() - .min_by(|&(_, arch_name_1), &(_, arch_name_2)| { - edit_distance::distance(bv_arch, arch_name_1) - .cmp(&edit_distance::distance(bv_arch, arch_name_2)) - }) - .map(|(index, _)| index), - ) - // Add actual / better support for formats other than elf? - // .choice_field( - // "Container Format", - // &["Coff", "Elf", "MachO", "Pe", "Wasm", "Xcoff"], - // None, - // ) - .get_form_input("Export as DWARF") + + let mut form = Form::new("Export as DWARF"); + form.add_field(FormInputField::SaveFileName { + prompt: "Save Location".to_string(), + extension: Some("Debug Files (*.dwo *.debug);;All Files (*)".to_string()), + default_name: None, + default: None, + value: None, + }); + form.add_field(FormInputField::Choice { + prompt: "Architecture".to_string(), + choices: archs.iter().map(|arch| arch.to_string()).collect(), + default: archs + .iter() + .enumerate() + .min_by(|&(_, arch_name_1), &(_, arch_name_2)| { + edit_distance::distance(bv_arch, arch_name_1) + .cmp(&edit_distance::distance(bv_arch, arch_name_2)) + }) + .map(|(index, _)| index), + value: 0, + }); + form } fn write_dwarf( - responses: Vec, + file_path: &Path, + arch: Architecture, endian: T, dwarf: &mut DwarfUnit, ) { - if responses.len() < 2 { - return; - } - - let arch = match responses[1] { - Index(0) => Architecture::Unknown, - Index(1) => Architecture::Aarch64, - Index(2) => Architecture::Aarch64_Ilp32, - Index(3) => Architecture::Arm, - Index(4) => Architecture::Avr, - Index(5) => Architecture::Bpf, - Index(6) => Architecture::I386, - Index(7) => Architecture::X86_64, - Index(8) => Architecture::X86_64_X32, - Index(9) => Architecture::Hexagon, - Index(10) => Architecture::LoongArch64, - Index(11) => Architecture::Mips, - Index(12) => Architecture::Mips64, - Index(13) => Architecture::Msp430, - Index(14) => Architecture::PowerPc, - Index(15) => Architecture::PowerPc64, - Index(16) => Architecture::Riscv32, - Index(17) => Architecture::Riscv64, - Index(18) => Architecture::S390x, - Index(19) => Architecture::Sbf, - Index(20) => Architecture::Sparc64, - Index(21) => Architecture::Wasm32, - Index(22) => Architecture::Xtensa, - _ => Architecture::Unknown, - }; - - // let format = match responses[2] { - // Index(0) => BinaryFormat::Coff, - // Index(1) => BinaryFormat::Elf, - // Index(2) => BinaryFormat::MachO, - // Index(3) => BinaryFormat::Pe, - // Index(4) => BinaryFormat::Wasm, - // Index(5) => BinaryFormat::Xcoff, - // _ => BinaryFormat::Elf, - // }; - // TODO : Look in to other options (mangling, flags, etc (see Object::new)) let mut out_object = write::Object::new( BinaryFormat::Elf, @@ -738,16 +695,14 @@ fn write_dwarf( }) .unwrap(); - if let interaction::FormResponses::String(filename) = &responses[0] { - if let Ok(out_data) = out_object.write() { - if let Err(err) = fs::write(filename, out_data) { - error!("Failed to write DWARF file: {}", err); - } else { - info!("Successfully saved as DWARF to `{}`", filename); - } + if let Ok(out_data) = out_object.write() { + if let Err(err) = fs::write(file_path, out_data) { + error!("Failed to write DWARF file: {}", err); } else { - error!("Failed to write DWARF with requested settings"); + info!("Successfully saved as DWARF to `{:?}`", file_path); } + } else { + error!("Failed to write DWARF with requested settings"); } } @@ -757,7 +712,42 @@ fn export_dwarf(bv: &BinaryView) { } else { String::from("Unknown") }; - let responses = present_form(arch_name.as_str()); + let mut export_form = create_export_form(arch_name.as_str()); + if !export_form.prompt() { + return; + } + + let arch_field = export_form.get_field_with_name("Architecture").unwrap(); + let arch_field_idx = arch_field.try_value_index().unwrap_or_default(); + let arch = match arch_field_idx { + 0 => Architecture::Unknown, + 1 => Architecture::Aarch64, + 2 => Architecture::Aarch64_Ilp32, + 3 => Architecture::Arm, + 4 => Architecture::Avr, + 5 => Architecture::Bpf, + 6 => Architecture::I386, + 7 => Architecture::X86_64, + 8 => Architecture::X86_64_X32, + 9 => Architecture::Hexagon, + 10 => Architecture::LoongArch64, + 11 => Architecture::Mips, + 12 => Architecture::Mips64, + 13 => Architecture::Msp430, + 14 => Architecture::PowerPc, + 15 => Architecture::PowerPc64, + 16 => Architecture::Riscv32, + 17 => Architecture::Riscv64, + 18 => Architecture::S390x, + 19 => Architecture::Sbf, + 20 => Architecture::Sparc64, + 21 => Architecture::Wasm32, + 22 => Architecture::Xtensa, + _ => Architecture::Unknown, + }; + + let save_loc_field = export_form.get_field_with_name("Save Location").unwrap(); + let save_loc_path = PathBuf::from(save_loc_field.try_value_string().unwrap_or_default()); let encoding = gimli::Encoding { format: gimli::Format::Dwarf32, @@ -782,9 +772,9 @@ fn export_dwarf(bv: &BinaryView) { // TODO: Sections? Segments? if bv.default_endianness() == binaryninja::Endianness::LittleEndian { - write_dwarf(responses, gimli::LittleEndian, &mut dwarf); + write_dwarf(&save_loc_path, arch, gimli::LittleEndian, &mut dwarf); } else { - write_dwarf(responses, gimli::BigEndian, &mut dwarf); + write_dwarf(&save_loc_path, arch, gimli::BigEndian, &mut dwarf); }; } diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 55b0d4db7d..65bab46385 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -1103,6 +1103,46 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNApplyDebugInfo(self.as_ref().handle, debug_info.handle) } } + fn show_plaintext_report(&self, title: &str, plaintext: &str) { + let title = title.to_cstr(); + let plaintext = plaintext.to_cstr(); + unsafe { + BNShowPlainTextReport( + self.as_ref().handle, + title.as_ref().as_ptr() as *mut _, + plaintext.as_ref().as_ptr() as *mut _, + ) + } + } + + fn show_markdown_report(&self, title: &str, contents: &str, plaintext: &str) { + let title = title.to_cstr(); + let contents = contents.to_cstr(); + let plaintext = plaintext.to_cstr(); + unsafe { + BNShowMarkdownReport( + self.as_ref().handle, + title.as_ref().as_ptr() as *mut _, + contents.as_ref().as_ptr() as *mut _, + plaintext.as_ref().as_ptr() as *mut _, + ) + } + } + + fn show_html_report(&self, title: &str, contents: &str, plaintext: &str) { + let title = title.to_cstr(); + let contents = contents.to_cstr(); + let plaintext = plaintext.to_cstr(); + unsafe { + BNShowHTMLReport( + self.as_ref().handle, + title.as_ref().as_ptr() as *mut _, + contents.as_ref().as_ptr() as *mut _, + plaintext.as_ref().as_ptr() as *mut _, + ) + } + } + fn show_graph_report(&self, raw_name: &str, graph: &FlowGraph) { let raw_name = raw_name.to_cstr(); unsafe { diff --git a/rust/src/function.rs b/rust/src/function.rs index edde15a7b5..e7e5e9b0e1 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -480,15 +480,15 @@ impl Function { /// Get the language representation of the function. /// /// * `language` - The language representation, ex. "Pseudo C". - pub fn language_representation( + pub fn language_representation( &self, - language: S, + language: &str, ) -> Option> { - let lang_name = language.into_bytes_with_nul(); + let lang_name = language.to_cstr(); let repr = unsafe { BNGetFunctionLanguageRepresentation( self.handle, - lang_name.as_ref().as_ptr() as *const c_char, + lang_name.as_ptr(), ) }; NonNull::new(repr) @@ -498,15 +498,15 @@ impl Function { /// Get the language representation of the function, if available. /// /// * `language` - The language representation, ex. "Pseudo C". - pub fn language_representation_if_available( + pub fn language_representation_if_available( &self, - language: S, + language: &str, ) -> Option> { - let lang_name = language.into_bytes_with_nul(); + let lang_name = language.to_cstr(); let repr = unsafe { BNGetFunctionLanguageRepresentationIfAvailable( self.handle, - lang_name.as_ref().as_ptr() as *const c_char, + lang_name.as_ptr(), ) }; NonNull::new(repr) diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index fad207d149..1a3ef2aaf1 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -14,15 +14,17 @@ //! Interfaces for asking the user for information: forms, opening files, etc. -use binaryninjacore_sys::*; - -use std::ffi::{c_char, c_void, CStr}; +use std::ffi::{c_char, c_void}; use std::path::PathBuf; -use crate::binary_view::BinaryView; -use crate::rc::Ref; +use binaryninjacore_sys::*; + use crate::string::{BnString, IntoCStr}; +pub mod form; +pub mod handler; +pub mod report; + pub type MessageBoxButtonSet = BNMessageBoxButtonSet; pub type MessageBoxIcon = BNMessageBoxIcon; pub type MessageBoxButtonResult = BNMessageBoxButtonResult; @@ -76,6 +78,48 @@ pub fn get_address_input(prompt: &str, title: &str) -> Option { Some(value) } +pub fn get_choice_input(prompt: &str, title: &str, choices: &[&str]) -> Option { + let prompt = prompt.to_cstr(); + let title = title.to_cstr(); + let mut choices_inner: Vec = choices.iter().copied().map(BnString::new).collect(); + // SAFETY BnString and *const c_char are transparent + let choices: &mut [*const c_char] = unsafe { + core::mem::transmute::<&mut [BnString], &mut [*const c_char]>(&mut choices_inner[..]) + }; + let mut result = 0; + let succ = unsafe { + BNGetChoiceInput( + &mut result, + prompt.as_ptr(), + title.as_ptr(), + choices.as_mut_ptr(), + choices.len(), + ) + }; + succ.then_some(result) +} + +pub fn get_large_choice_input(prompt: &str, title: &str, choices: &[&str]) -> Option { + let prompt = prompt.to_cstr(); + let title = title.to_cstr(); + let mut choices_inner: Vec = choices.iter().copied().map(BnString::new).collect(); + // SAFETY BnString and *const c_char are transparent + let choices: &mut [*const c_char] = unsafe { + core::mem::transmute::<&mut [BnString], &mut [*const c_char]>(&mut choices_inner[..]) + }; + let mut result = 0; + let succ = unsafe { + BNGetLargeChoiceInput( + &mut result, + prompt.as_ptr(), + title.as_ptr(), + choices.as_mut_ptr(), + choices.len(), + ) + }; + succ.then_some(result) +} + pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option { let mut value: *mut c_char = std::ptr::null_mut(); @@ -142,385 +186,6 @@ pub fn show_message_box( unsafe { BNShowMessageBox(title.as_ptr(), text.as_ptr(), buttons, icon) } } -pub enum FormResponses { - None, - String(String), - Integer(i64), - Address(u64), - Index(usize), -} - -enum FormData { - Label { - _text: BnString, - }, - Text { - _prompt: BnString, - _default: Option, - }, - Choice { - _prompt: BnString, - _choices: Vec, - _raw: Vec<*const c_char>, - }, - File { - _prompt: BnString, - _ext: BnString, - _default: Option, - }, - FileSave { - _prompt: BnString, - _ext: BnString, - _default_name: BnString, - _default: Option, - }, -} - -pub struct FormInputBuilder { - fields: Vec, - data: Vec, -} - -impl FormInputBuilder { - pub fn new() -> Self { - Self { - fields: vec![], - data: vec![], - } - } - - /// Form Field: Text output - pub fn label_field(mut self, text: &str) -> Self { - let text = BnString::new(text); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::LabelFormField; - result.hasDefault = false; - result.prompt = text.as_ptr(); - self.fields.push(result); - - self.data.push(FormData::Label { _text: text }); - self - } - - /// Form Field: Vertical spacing - pub fn separator_field(mut self) -> Self { - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::SeparatorFormField; - result.hasDefault = false; - self.fields.push(result); - self - } - - /// Form Field: Prompt for a string value - pub fn text_field(mut self, prompt: &str, default: Option<&str>) -> Self { - let prompt = BnString::new(prompt); - let default = default.map(BnString::new); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::TextLineFormField; - result.prompt = prompt.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(ref default) = default { - result.stringDefault = default.as_ptr(); - } - self.fields.push(result); - - self.data.push(FormData::Text { - _prompt: prompt, - _default: default, - }); - self - } - - /// Form Field: Prompt for multi-line string value - pub fn multiline_field(mut self, prompt: &str, default: Option<&str>) -> Self { - let prompt = BnString::new(prompt); - let default = default.map(BnString::new); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::MultilineTextFormField; - result.prompt = prompt.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(ref default) = default { - result.stringDefault = default.as_ptr(); - } - self.fields.push(result); - - self.data.push(FormData::Text { - _prompt: prompt, - _default: default, - }); - self - } - - /// Form Field: Prompt for an integer - pub fn integer_field(mut self, prompt: &str, default: Option) -> Self { - let prompt = BnString::new(prompt); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::IntegerFormField; - result.prompt = prompt.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(default) = default { - result.intDefault = default; - } - self.fields.push(result); - - self.data.push(FormData::Label { _text: prompt }); - self - } - - /// Form Field: Prompt for an address - pub fn address_field( - mut self, - prompt: &str, - view: Option>, - current_address: Option, - default: Option, - ) -> Self { - let prompt = BnString::new(prompt); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::AddressFormField; - result.prompt = prompt.as_ptr(); - if let Some(view) = view { - // the view is being moved into result, there is no need to clone - // and drop is intentionally being avoided with `Ref::into_raw` - result.view = unsafe { Ref::into_raw(view) }.handle; - } - result.currentAddress = current_address.unwrap_or(0); - result.hasDefault = default.is_some(); - if let Some(default) = default { - result.addressDefault = default; - } - self.fields.push(result); - - self.data.push(FormData::Label { _text: prompt }); - self - } - - /// Form Field: Prompt for a choice from provided options - pub fn choice_field(mut self, prompt: &str, choices: &[&str], default: Option) -> Self { - let prompt = BnString::new(prompt); - let choices: Vec = choices.iter().map(|&s| BnString::new(s)).collect(); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::ChoiceFormField; - result.prompt = prompt.as_ptr(); - let mut raw_choices: Vec<*const c_char> = choices.iter().map(|c| c.as_ptr()).collect(); - result.choices = raw_choices.as_mut_ptr(); - result.count = choices.len(); - result.hasDefault = default.is_some(); - if let Some(default) = default { - result.indexDefault = default; - } - self.fields.push(result); - - self.data.push(FormData::Choice { - _prompt: prompt, - _choices: choices, - _raw: raw_choices, - }); - self - } - - /// Form Field: Prompt for file to open - pub fn open_file_field( - mut self, - prompt: &str, - ext: Option<&str>, - default: Option<&str>, - ) -> Self { - let prompt = BnString::new(prompt); - let ext = if let Some(ext) = ext { - BnString::new(ext) - } else { - BnString::new("") - }; - let default = default.map(BnString::new); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::OpenFileNameFormField; - result.prompt = prompt.as_ptr(); - result.ext = ext.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(ref default) = default { - result.stringDefault = default.as_ptr(); - } - self.fields.push(result); - - self.data.push(FormData::File { - _prompt: prompt, - _ext: ext, - _default: default, - }); - self - } - - /// Form Field: Prompt for file to save to - pub fn save_file_field( - mut self, - prompt: &str, - ext: Option<&str>, - default_name: Option<&str>, - default: Option<&str>, - ) -> Self { - let prompt = BnString::new(prompt); - let ext = if let Some(ext) = ext { - BnString::new(ext) - } else { - BnString::new("") - }; - let default_name = if let Some(default_name) = default_name { - BnString::new(default_name) - } else { - BnString::new("") - }; - let default = default.map(BnString::new); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::SaveFileNameFormField; - result.prompt = prompt.as_ptr(); - result.ext = ext.as_ptr(); - result.defaultName = default_name.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(ref default) = default { - result.stringDefault = default.as_ptr(); - } - self.fields.push(result); - - self.data.push(FormData::FileSave { - _prompt: prompt, - _ext: ext, - _default_name: default_name, - _default: default, - }); - self - } - - /// Form Field: Prompt for directory name - pub fn directory_name_field( - mut self, - prompt: &str, - default_name: Option<&str>, - default: Option<&str>, - ) -> Self { - let prompt = BnString::new(prompt); - let default_name = if let Some(default_name) = default_name { - BnString::new(default_name) - } else { - BnString::new("") - }; - let default = default.map(BnString::new); - - let mut result = unsafe { std::mem::zeroed::() }; - result.type_ = BNFormInputFieldType::DirectoryNameFormField; - result.prompt = prompt.as_ptr(); - result.defaultName = default_name.as_ptr(); - result.hasDefault = default.is_some(); - if let Some(ref default) = default { - result.stringDefault = default.as_ptr(); - } - self.fields.push(result); - - self.data.push(FormData::File { - _prompt: prompt, - _ext: default_name, - _default: default, - }); - self - } - - /// Prompts the user for a set of inputs specified in `fields` with given title. - /// The fields parameter is a list which can contain the following types: - /// - /// This API is flexible and works both in the UI via a pop-up dialog and on the command-line. - /// - /// ```no_run - /// # use binaryninja::interaction::FormInputBuilder; - /// # use binaryninja::interaction::FormResponses; - /// let responses = FormInputBuilder::new() - /// .text_field("First Name", None) - /// .text_field("Last Name", None) - /// .choice_field( - /// "Favorite Food", - /// &vec![ - /// "Pizza", - /// "Also Pizza", - /// "Also Pizza", - /// "Yummy Pizza", - /// "Wrong Answer", - /// ], - /// Some(0), - /// ) - /// .get_form_input("Form Title"); - /// - /// let food = match responses[2] { - /// FormResponses::Index(0) => "Pizza", - /// FormResponses::Index(1) => "Also Pizza", - /// FormResponses::Index(2) => "Also Pizza", - /// FormResponses::Index(3) => "Wrong Answer", - /// _ => panic!("This person doesn't like pizza?!?"), - /// }; - /// - /// let FormResponses::String(last_name) = &responses[0] else { - /// unreachable!() - /// }; - /// let FormResponses::String(first_name) = &responses[1] else { - /// unreachable!() - /// }; - /// - /// println!("{} {} likes {}", &first_name, &last_name, food); - /// ``` - pub fn get_form_input(&mut self, title: &str) -> Vec { - let title = title.to_cstr(); - if unsafe { BNGetFormInput(self.fields.as_mut_ptr(), self.fields.len(), title.as_ptr()) } { - let result = self - .fields - .iter() - .map(|form_field| match form_field.type_ { - BNFormInputFieldType::LabelFormField - | BNFormInputFieldType::SeparatorFormField => FormResponses::None, - - BNFormInputFieldType::TextLineFormField - | BNFormInputFieldType::MultilineTextFormField - | BNFormInputFieldType::OpenFileNameFormField - | BNFormInputFieldType::SaveFileNameFormField - | BNFormInputFieldType::DirectoryNameFormField => { - FormResponses::String(unsafe { - CStr::from_ptr(form_field.stringResult) - .to_str() - .unwrap() - .to_owned() - }) - } - - BNFormInputFieldType::IntegerFormField => { - FormResponses::Integer(form_field.intResult) - } - BNFormInputFieldType::AddressFormField => { - FormResponses::Address(form_field.addressResult) - } - BNFormInputFieldType::ChoiceFormField => { - FormResponses::Index(form_field.indexResult) - } - }) - .collect(); - unsafe { BNFreeFormInputResults(self.fields.as_mut_ptr(), self.fields.len()) }; - result - } else { - vec![] - } - } -} - -impl Default for FormInputBuilder { - fn default() -> Self { - Self::new() - } -} - struct TaskContext Result<(), ()>>)>(F); pub fn run_progress_dialog Result<(), ()>>)>( diff --git a/rust/src/interaction/form.rs b/rust/src/interaction/form.rs new file mode 100644 index 0000000000..06799681d1 --- /dev/null +++ b/rust/src/interaction/form.rs @@ -0,0 +1,411 @@ +use std::ffi::c_char; + +use binaryninjacore_sys::*; + +use crate::binary_view::BinaryView; +use crate::rc::{Array, Ref}; +use crate::string::{raw_to_string, strings_to_string_list, BnString, IntoCStr}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Form { + pub title: String, + pub fields: Vec, +} + +impl Form { + pub fn new(title: impl Into) -> Self { + Self::new_with_fields(title, vec![]) + } + + pub fn new_with_fields(title: impl Into, fields: Vec) -> Self { + Self { + title: title.into(), + fields, + } + } + + pub fn add_field(&mut self, field: FormInputField) { + self.fields.push(field); + } + + /// Prompt the user (or interaction handler) for the form input. + /// + /// Updates the field's values and returns whether the form was accepted or not. + pub fn prompt(&mut self) -> bool { + let title = self.title.clone().to_cstr(); + let mut raw_fields = self + .fields + .iter() + .map(FormInputField::into_raw) + .collect::>(); + let success = + unsafe { BNGetFormInput(raw_fields.as_mut_ptr(), raw_fields.len(), title.as_ptr()) }; + // Update the fields with the new field values. + self.fields = raw_fields + .into_iter() + .map(FormInputField::from_owned_raw) + .collect(); + success + } + + pub fn get_field_with_name(&self, name: &str) -> Option<&FormInputField> { + self.fields + .iter() + .find(|field| field.try_prompt() == Some(name.to_string())) + } +} + +/// A field within a form. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FormInputField { + Label { + prompt: String, + }, + Separator, + TextLine { + prompt: String, + default: Option, + value: Option, + }, + MultilineText { + prompt: String, + default: Option, + value: Option, + }, + Integer { + prompt: String, + default: Option, + value: i64, + }, + Address { + prompt: String, + view: Option>, + current_address: u64, + default: Option, + value: u64, + }, + Choice { + prompt: String, + choices: Vec, + default: Option, + value: usize, + }, + OpenFileName { + prompt: String, + /// File extension to filter on. + extension: Option, + default: Option, + value: Option, + }, + SaveFileName { + prompt: String, + /// File extension to filter on. + extension: Option, + /// Default file name to fill. + default_name: Option, + default: Option, + value: Option, + }, + DirectoryName { + prompt: String, + default_name: Option, + default: Option, + value: Option, + }, +} + +impl FormInputField { + pub fn from_raw(value: &BNFormInputField) -> Self { + let prompt = raw_to_string(value.prompt).unwrap_or_default(); + let view = match value.view.is_null() { + false => Some(unsafe { BinaryView::from_raw(value.view) }.to_owned()), + true => None, + }; + let name_default = value + .hasDefault + .then_some(raw_to_string(value.defaultName).unwrap_or_default()); + let string_default = value + .hasDefault + .then_some(raw_to_string(value.stringDefault).unwrap_or_default()); + let int_default = value.hasDefault.then_some(value.intDefault); + let address_default = value.hasDefault.then_some(value.addressDefault); + let index_default = value.hasDefault.then_some(value.indexDefault); + let extension = raw_to_string(value.ext); + let current_address = value.currentAddress; + let string_result = raw_to_string(value.stringResult); + let int_result = value.intResult; + let address_result = value.addressResult; + let index_result = value.indexResult; + match value.type_ { + BNFormInputFieldType::LabelFormField => Self::Label { prompt }, + BNFormInputFieldType::SeparatorFormField => Self::Separator, + BNFormInputFieldType::TextLineFormField => Self::TextLine { + prompt, + default: string_default, + value: string_result, + }, + BNFormInputFieldType::MultilineTextFormField => Self::MultilineText { + prompt, + default: string_default, + value: string_result, + }, + BNFormInputFieldType::IntegerFormField => Self::Integer { + prompt, + default: int_default, + value: int_result, + }, + BNFormInputFieldType::AddressFormField => Self::Address { + prompt, + view, + current_address, + default: address_default, + value: address_result, + }, + BNFormInputFieldType::ChoiceFormField => Self::Choice { + prompt, + choices: vec![], + default: index_default, + value: index_result, + }, + BNFormInputFieldType::OpenFileNameFormField => Self::OpenFileName { + prompt, + extension, + default: string_default, + value: string_result, + }, + BNFormInputFieldType::SaveFileNameFormField => Self::SaveFileName { + prompt, + extension, + default_name: name_default, + default: string_default, + value: string_result, + }, + BNFormInputFieldType::DirectoryNameFormField => Self::DirectoryName { + prompt, + default_name: name_default, + default: string_default, + value: string_result, + }, + } + } + + pub fn from_owned_raw(value: BNFormInputField) -> Self { + let owned = Self::from_raw(&value); + Self::free_raw(value); + owned + } + + pub fn into_raw(&self) -> BNFormInputField { + let bn_prompt = BnString::new(self.try_prompt().unwrap_or_default()); + let bn_extension = BnString::new(self.try_extension().unwrap_or_default()); + let bn_default_string = BnString::new(self.try_default_string().unwrap_or_default()); + let bn_default_name = BnString::new(self.try_default_name().unwrap_or_default()); + let bn_value_string = BnString::new(self.try_value_string().unwrap_or_default()); + // Expected to be freed by [`FormInputField::free_raw`]. + BNFormInputField { + type_: self.as_type(), + prompt: BnString::into_raw(bn_prompt), + view: match self.try_view() { + None => std::ptr::null_mut(), + Some(view) => unsafe { Ref::into_raw(view) }.handle, + }, + currentAddress: self.try_current_address().unwrap_or_default(), + choices: match self.try_choices() { + None => std::ptr::null_mut(), + Some(choices) => strings_to_string_list(choices.as_slice()) as *mut *const c_char, + }, + // NOTE: `count` is the length of the `choices` array. + count: self.try_choices().unwrap_or_default().len(), + ext: BnString::into_raw(bn_extension), + defaultName: BnString::into_raw(bn_default_name), + intResult: self.try_value_int().unwrap_or_default(), + addressResult: self.try_value_address().unwrap_or_default(), + stringResult: BnString::into_raw(bn_value_string), + indexResult: self.try_value_index().unwrap_or_default(), + hasDefault: self.try_has_default().unwrap_or_default(), + intDefault: self.try_default_int().unwrap_or_default(), + addressDefault: self.try_default_address().unwrap_or_default(), + stringDefault: BnString::into_raw(bn_default_string), + indexDefault: self.try_default_index().unwrap_or_default(), + } + } + + pub fn free_raw(value: BNFormInputField) { + unsafe { + BnString::free_raw(value.defaultName as *mut c_char); + BnString::free_raw(value.prompt as *mut c_char); + BnString::free_raw(value.ext as *mut c_char); + BnString::free_raw(value.stringDefault as *mut c_char); + BnString::free_raw(value.stringResult); + // TODO: Would like access to a `Array::free_raw` or something. + Array::::new(value.choices as *mut *mut c_char, value.count, ()); + // Free the view ref if provided. + if !value.view.is_null() { + BinaryView::ref_from_raw(value.view); + } + } + } + + pub fn as_type(&self) -> BNFormInputFieldType { + match self { + FormInputField::Label { .. } => BNFormInputFieldType::LabelFormField, + FormInputField::Separator => BNFormInputFieldType::SeparatorFormField, + FormInputField::TextLine { .. } => BNFormInputFieldType::TextLineFormField, + FormInputField::MultilineText { .. } => BNFormInputFieldType::MultilineTextFormField, + FormInputField::Integer { .. } => BNFormInputFieldType::IntegerFormField, + FormInputField::Address { .. } => BNFormInputFieldType::AddressFormField, + FormInputField::Choice { .. } => BNFormInputFieldType::ChoiceFormField, + FormInputField::OpenFileName { .. } => BNFormInputFieldType::OpenFileNameFormField, + FormInputField::SaveFileName { .. } => BNFormInputFieldType::SaveFileNameFormField, + FormInputField::DirectoryName { .. } => BNFormInputFieldType::DirectoryNameFormField, + } + } + + /// Mapping to the [`BNFormInputField::prompt`] field. + pub fn try_prompt(&self) -> Option { + match self { + FormInputField::Label { prompt, .. } => Some(prompt.clone()), + FormInputField::Separator => None, + FormInputField::TextLine { prompt, .. } => Some(prompt.clone()), + FormInputField::MultilineText { prompt, .. } => Some(prompt.clone()), + FormInputField::Integer { prompt, .. } => Some(prompt.clone()), + FormInputField::Address { prompt, .. } => Some(prompt.clone()), + FormInputField::Choice { prompt, .. } => Some(prompt.clone()), + FormInputField::OpenFileName { prompt, .. } => Some(prompt.clone()), + FormInputField::SaveFileName { prompt, .. } => Some(prompt.clone()), + FormInputField::DirectoryName { prompt, .. } => Some(prompt.clone()), + } + } + + /// Mapping to the [`BNFormInputField::view`] field. + pub fn try_view(&self) -> Option> { + match self { + FormInputField::Address { view, .. } => view.clone(), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::currentAddress`] field. + pub fn try_current_address(&self) -> Option { + match self { + FormInputField::Address { + current_address, .. + } => Some(*current_address), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::choices`] field. + pub fn try_choices(&self) -> Option> { + match self { + FormInputField::Choice { choices, .. } => Some(choices.clone()), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::ext`] field. + pub fn try_extension(&self) -> Option { + match self { + Self::SaveFileName { extension, .. } => extension.clone(), + Self::OpenFileName { extension, .. } => extension.clone(), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::hasDefault`] field. + pub fn try_has_default(&self) -> Option { + match self { + FormInputField::Label { .. } => None, + FormInputField::Separator => None, + FormInputField::TextLine { default, .. } => Some(default.is_some()), + FormInputField::MultilineText { default, .. } => Some(default.is_some()), + FormInputField::Integer { default, .. } => Some(default.is_some()), + FormInputField::Address { default, .. } => Some(default.is_some()), + FormInputField::Choice { default, .. } => Some(default.is_some()), + FormInputField::OpenFileName { default, .. } => Some(default.is_some()), + FormInputField::SaveFileName { default, .. } => Some(default.is_some()), + FormInputField::DirectoryName { default, .. } => Some(default.is_some()), + } + } + + /// Mapping to the [`BNFormInputField::defaultName`] field. + pub fn try_default_name(&self) -> Option { + match self { + Self::SaveFileName { default_name, .. } => default_name.clone(), + Self::DirectoryName { default_name, .. } => default_name.clone(), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::intDefault`] field. + pub fn try_default_int(&self) -> Option { + match self { + FormInputField::Integer { default, .. } => *default, + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::addressDefault`] field. + pub fn try_default_address(&self) -> Option { + match self { + FormInputField::Address { default, .. } => *default, + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::stringDefault`] field. + pub fn try_default_string(&self) -> Option { + match self { + FormInputField::TextLine { default, .. } => default.clone(), + FormInputField::MultilineText { default, .. } => default.clone(), + FormInputField::OpenFileName { default, .. } => default.clone(), + FormInputField::SaveFileName { default, .. } => default.clone(), + FormInputField::DirectoryName { default, .. } => default.clone(), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::indexDefault`] field. + pub fn try_default_index(&self) -> Option { + match self { + FormInputField::Choice { default, .. } => *default, + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::intResult`] field. + pub fn try_value_int(&self) -> Option { + match self { + FormInputField::Integer { value, .. } => Some(*value), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::addressResult`] field. + pub fn try_value_address(&self) -> Option { + match self { + FormInputField::Address { value, .. } => Some(*value), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::stringResult`] field. + pub fn try_value_string(&self) -> Option { + match self { + FormInputField::TextLine { value, .. } => value.clone(), + FormInputField::MultilineText { value, .. } => value.clone(), + FormInputField::OpenFileName { value, .. } => value.clone(), + FormInputField::SaveFileName { value, .. } => value.clone(), + FormInputField::DirectoryName { value, .. } => value.clone(), + _ => None, + } + } + + /// Mapping to the [`BNFormInputField::indexResult`] field. + pub fn try_value_index(&self) -> Option { + match self { + FormInputField::Choice { value, .. } => Some(*value), + _ => None, + } + } +} diff --git a/rust/src/interaction/handler.rs b/rust/src/interaction/handler.rs new file mode 100644 index 0000000000..fa1681d132 --- /dev/null +++ b/rust/src/interaction/handler.rs @@ -0,0 +1,598 @@ +use std::ffi::{c_char, c_void, CStr}; +use std::ptr; + +use binaryninjacore_sys::*; + +use crate::binary_view::BinaryView; +use crate::flowgraph::FlowGraph; +use crate::interaction::form::{Form, FormInputField}; +use crate::interaction::report::{Report, ReportCollection}; +use crate::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon}; +use crate::string::{raw_to_string, BnString}; + +pub fn register_interaction_handler(custom: R) { + let leak_custom = Box::leak(Box::new(custom)); + let mut callbacks = BNInteractionHandlerCallbacks { + context: leak_custom as *mut R as *mut c_void, + showPlainTextReport: Some(cb_show_plain_text_report::), + showMarkdownReport: Some(cb_show_markdown_report::), + showHTMLReport: Some(cb_show_html_report::), + showGraphReport: Some(cb_show_graph_report::), + showReportCollection: Some(cb_show_report_collection::), + getTextLineInput: Some(cb_get_text_line_input::), + getIntegerInput: Some(cb_get_integer_input::), + getAddressInput: Some(cb_get_address_input::), + getChoiceInput: Some(cb_get_choice_input::), + getLargeChoiceInput: Some(cb_get_large_choice_input::), + getOpenFileNameInput: Some(cb_get_open_file_name_input::), + getSaveFileNameInput: Some(cb_get_save_file_name_input::), + getDirectoryNameInput: Some(cb_get_directory_name_input::), + getFormInput: Some(cb_get_form_input::), + showMessageBox: Some(cb_show_message_box::), + openUrl: Some(cb_open_url::), + runProgressDialog: Some(cb_run_progress_dialog::), + }; + unsafe { BNRegisterInteractionHandler(&mut callbacks) } +} + +pub trait InteractionHandler: Sync + Send + 'static { + fn show_message_box( + &mut self, + title: &str, + text: &str, + buttons: MessageBoxButtonSet, + icon: MessageBoxIcon, + ) -> MessageBoxButtonResult; + + fn open_url(&mut self, url: &str) -> bool; + + fn run_progress_dialog( + &mut self, + title: &str, + can_cancel: bool, + task: &InteractionHandlerTask, + ) -> bool; + + fn show_plain_text_report(&mut self, view: &BinaryView, title: &str, contents: &str); + + fn show_graph_report(&mut self, view: &BinaryView, title: &str, graph: &FlowGraph); + + fn show_markdown_report( + &mut self, + view: &BinaryView, + title: &str, + _contents: &str, + plain_text: &str, + ) { + self.show_plain_text_report(view, title, plain_text); + } + + fn show_html_report( + &mut self, + view: &BinaryView, + title: &str, + _contents: &str, + plain_text: &str, + ) { + self.show_plain_text_report(view, title, plain_text); + } + + fn show_report_collection(&mut self, _title: &str, reports: &ReportCollection) { + for report in reports { + match &report { + Report::PlainText(rpt) => { + self.show_plain_text_report(&report.view(), &report.title(), &rpt.contents()) + } + Report::Markdown(rm) => self.show_markdown_report( + &report.view(), + &report.title(), + &rm.contents(), + &rm.plaintext(), + ), + Report::Html(rh) => self.show_html_report( + &report.view(), + &report.title(), + &rh.contents(), + &rh.plaintext(), + ), + Report::FlowGraph(rfg) => { + self.show_graph_report(&report.view(), &report.title(), &rfg.flow_graph()) + } + } + } + } + + fn get_form_input(&mut self, form: &mut Form) -> bool; + + fn get_text_line_input(&mut self, prompt: &str, title: &str) -> Option { + let mut form = Form::new(title.to_owned()); + form.add_field(FormInputField::TextLine { + prompt: prompt.to_string(), + default: None, + value: None, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_string()) + } + + fn get_integer_input(&mut self, prompt: &str, title: &str) -> Option { + let mut form = Form::new(title.to_owned()); + form.add_field(FormInputField::Integer { + prompt: prompt.to_string(), + value: 0, + default: None, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_int()) + } + + fn get_address_input( + &mut self, + prompt: &str, + title: &str, + view: Option<&BinaryView>, + current_addr: u64, + ) -> Option { + let mut form = Form::new(title.to_owned()); + form.add_field(FormInputField::Address { + prompt: prompt.to_string(), + view: view.map(|v| v.to_owned()), + current_address: current_addr, + value: 0, + default: None, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_address()) + } + + fn get_choice_input( + &mut self, + prompt: &str, + title: &str, + choices: Vec, + ) -> Option { + let mut form = Form::new(title.to_owned()); + form.add_field(FormInputField::Choice { + prompt: prompt.to_string(), + choices, + default: None, + value: 0, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_index()) + } + + fn get_large_choice_input( + &mut self, + prompt: &str, + title: &str, + choices: Vec, + ) -> Option { + self.get_choice_input(prompt, title, choices) + } + + fn get_open_file_name_input( + &mut self, + prompt: &str, + extension: Option, + ) -> Option { + let mut form = Form::new(prompt.to_owned()); + form.add_field(FormInputField::OpenFileName { + prompt: prompt.to_string(), + default: None, + value: None, + extension, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_string()) + } + + fn get_save_file_name_input( + &mut self, + prompt: &str, + extension: Option, + default_name: Option, + ) -> Option { + let mut form = Form::new(prompt.to_owned()); + form.add_field(FormInputField::SaveFileName { + prompt: prompt.to_string(), + extension, + default: None, + value: None, + default_name, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_string()) + } + + fn get_directory_name_input( + &mut self, + prompt: &str, + default_name: Option, + ) -> Option { + let mut form = Form::new(prompt.to_owned()); + form.add_field(FormInputField::DirectoryName { + prompt: prompt.to_string(), + default_name, + default: None, + value: None, + }); + if !self.get_form_input(&mut form) { + return None; + } + form.get_field_with_name(prompt) + .and_then(|f| f.try_value_string()) + } +} + +pub struct InteractionHandlerTask { + ctxt: *mut c_void, + task: Option< + unsafe extern "C" fn( + taskCtxt: *mut c_void, + progress: Option< + unsafe extern "C" fn(progressCtxt: *mut c_void, cur: usize, max: usize) -> bool, + >, + progressCtxt: *mut c_void, + ), + >, +} + +impl InteractionHandlerTask { + pub fn task bool>(&mut self, progress: &mut P) { + let Some(task) = self.task else { + // Assuming a nullptr task mean nothing need to be done + return; + }; + + let progress_ctxt = progress as *mut P as *mut c_void; + ffi_wrap!("custom_interation_run_progress_dialog", unsafe { + task( + self.ctxt, + Some(cb_custom_interation_handler_task::

), + progress_ctxt, + ) + }) + } +} + +unsafe extern "C" fn cb_custom_interation_handler_task bool>( + ctxt: *mut c_void, + cur: usize, + max: usize, +) -> bool { + let ctxt = ctxt as *mut P; + (*ctxt)(cur, max) +} + +unsafe extern "C" fn cb_show_plain_text_report( + ctxt: *mut c_void, + view: *mut BNBinaryView, + title: *const c_char, + contents: *const c_char, +) { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + let contents = raw_to_string(contents).unwrap(); + (*ctxt).show_plain_text_report(&BinaryView::from_raw(view), &title, &contents) +} + +unsafe extern "C" fn cb_show_markdown_report( + ctxt: *mut c_void, + view: *mut BNBinaryView, + title: *const c_char, + contents: *const c_char, + plaintext: *const c_char, +) { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + let contents = raw_to_string(contents).unwrap(); + let plaintext = raw_to_string(plaintext).unwrap(); + (*ctxt).show_markdown_report(&BinaryView::from_raw(view), &title, &contents, &plaintext) +} + +unsafe extern "C" fn cb_show_html_report( + ctxt: *mut c_void, + view: *mut BNBinaryView, + title: *const c_char, + contents: *const c_char, + plaintext: *const c_char, +) { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + let contents = raw_to_string(contents).unwrap(); + let plaintext = raw_to_string(plaintext).unwrap(); + (*ctxt).show_html_report(&BinaryView::from_raw(view), &title, &contents, &plaintext) +} + +unsafe extern "C" fn cb_show_graph_report( + ctxt: *mut c_void, + view: *mut BNBinaryView, + title: *const c_char, + graph: *mut BNFlowGraph, +) { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + (*ctxt).show_graph_report( + &BinaryView::from_raw(view), + &title, + &FlowGraph::from_raw(graph), + ) +} + +unsafe extern "C" fn cb_show_report_collection( + ctxt: *mut c_void, + title: *const c_char, + report: *mut BNReportCollection, +) { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + (*ctxt).show_report_collection( + &title, + &ReportCollection::from_raw(ptr::NonNull::new(report).unwrap()), + ) +} + +unsafe extern "C" fn cb_get_text_line_input( + ctxt: *mut c_void, + result_ffi: *mut *mut c_char, + prompt: *const c_char, + title: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let title = raw_to_string(title).unwrap(); + let result = (*ctxt).get_text_line_input(&prompt, &title); + if let Some(result) = result { + unsafe { *result_ffi = BnString::into_raw(BnString::new(result)) }; + true + } else { + unsafe { *result_ffi = ptr::null_mut() }; + false + } +} + +unsafe extern "C" fn cb_get_integer_input( + ctxt: *mut c_void, + result_ffi: *mut i64, + prompt: *const c_char, + title: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let title = raw_to_string(title).unwrap(); + let result = (*ctxt).get_integer_input(&prompt, &title); + if let Some(result) = result { + unsafe { *result_ffi = result }; + true + } else { + unsafe { *result_ffi = 0 }; + false + } +} + +unsafe extern "C" fn cb_get_address_input( + ctxt: *mut c_void, + result_ffi: *mut u64, + prompt: *const c_char, + title: *const c_char, + view: *mut BNBinaryView, + current_addr: u64, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let title = raw_to_string(title).unwrap(); + let view = (!view.is_null()).then(|| BinaryView::from_raw(view)); + let result = (*ctxt).get_address_input(&prompt, &title, view.as_ref(), current_addr); + if let Some(result) = result { + unsafe { *result_ffi = result }; + true + } else { + unsafe { *result_ffi = 0 }; + false + } +} + +unsafe extern "C" fn cb_get_choice_input( + ctxt: *mut c_void, + result_ffi: *mut usize, + prompt: *const c_char, + title: *const c_char, + choices: *mut *const c_char, + count: usize, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let title = raw_to_string(title).unwrap(); + let choices = unsafe { core::slice::from_raw_parts(choices, count) }; + // SAFETY: BnString and *const c_char are transparent + let choices = unsafe { core::mem::transmute::<&[*const c_char], &[BnString]>(choices) }; + let choices: Vec = choices + .iter() + .map(|x| x.to_string_lossy().to_string()) + .collect(); + let result = (*ctxt).get_choice_input(&prompt, &title, choices); + if let Some(result) = result { + unsafe { *result_ffi = result }; + true + } else { + unsafe { *result_ffi = 0 }; + false + } +} + +unsafe extern "C" fn cb_get_large_choice_input( + ctxt: *mut c_void, + result_ffi: *mut usize, + prompt: *const c_char, + title: *const c_char, + choices: *mut *const c_char, + count: usize, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let title = raw_to_string(title).unwrap(); + let choices = unsafe { core::slice::from_raw_parts(choices, count) }; + // SAFETY: BnString and *const c_char are transparent + let choices = unsafe { core::mem::transmute::<&[*const c_char], &[BnString]>(choices) }; + let choices: Vec = choices + .iter() + .map(|x| x.to_string_lossy().to_string()) + .collect(); + let result = (*ctxt).get_large_choice_input(&prompt, &title, choices); + if let Some(result) = result { + unsafe { *result_ffi = result }; + true + } else { + unsafe { *result_ffi = 0 }; + false + } +} + +unsafe extern "C" fn cb_get_open_file_name_input( + ctxt: *mut c_void, + result_ffi: *mut *mut c_char, + prompt: *const c_char, + ext: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let ext = (!ext.is_null()).then(|| unsafe { CStr::from_ptr(ext) }); + let result = + (*ctxt).get_open_file_name_input(&prompt, ext.map(|x| x.to_string_lossy().to_string())); + if let Some(result) = result { + unsafe { *result_ffi = BnString::into_raw(BnString::new(result)) }; + true + } else { + unsafe { *result_ffi = ptr::null_mut() }; + false + } +} + +unsafe extern "C" fn cb_get_save_file_name_input( + ctxt: *mut c_void, + result_ffi: *mut *mut c_char, + prompt: *const c_char, + ext: *const c_char, + default_name: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let ext = raw_to_string(ext); + let default_name = raw_to_string(default_name); + let result = (*ctxt).get_save_file_name_input(&prompt, ext, default_name); + if let Some(result) = result { + unsafe { *result_ffi = BnString::into_raw(BnString::new(result)) }; + true + } else { + unsafe { *result_ffi = ptr::null_mut() }; + false + } +} + +unsafe extern "C" fn cb_get_directory_name_input( + ctxt: *mut c_void, + result_ffi: *mut *mut c_char, + prompt: *const c_char, + default_name: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let prompt = raw_to_string(prompt).unwrap(); + let default_name = raw_to_string(default_name); + let result = (*ctxt).get_directory_name_input(&prompt, default_name); + if let Some(result) = result { + unsafe { *result_ffi = BnString::into_raw(BnString::new(result)) }; + true + } else { + unsafe { *result_ffi = ptr::null_mut() }; + false + } +} + +unsafe extern "C" fn cb_get_form_input( + ctxt: *mut c_void, + fields: *mut BNFormInputField, + count: usize, + title: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let raw_fields = unsafe { core::slice::from_raw_parts_mut(fields, count) }; + let fields: Vec<_> = raw_fields + .iter_mut() + .map(|x| FormInputField::from_raw(x)) + .collect(); + let title = raw_to_string(title).unwrap(); + let mut form = Form::new_with_fields(title, fields); + let results = (*ctxt).get_form_input(&mut form); + // Update the fields with the new values. Freeing the old ones. + raw_fields + .iter_mut() + .enumerate() + .for_each(|(idx, raw_field)| { + FormInputField::free_raw(*raw_field); + *raw_field = form.fields[idx].into_raw(); + }); + results +} + +unsafe extern "C" fn cb_show_message_box( + ctxt: *mut c_void, + title: *const c_char, + text: *const c_char, + buttons: BNMessageBoxButtonSet, + icon: BNMessageBoxIcon, +) -> BNMessageBoxButtonResult { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + let text = raw_to_string(text).unwrap(); + (*ctxt).show_message_box(&title, &text, buttons, icon) +} + +unsafe extern "C" fn cb_open_url( + ctxt: *mut c_void, + url: *const c_char, +) -> bool { + let ctxt = ctxt as *mut R; + let url = raw_to_string(url).unwrap(); + (*ctxt).open_url(&url) +} + +unsafe extern "C" fn cb_run_progress_dialog( + ctxt: *mut c_void, + title: *const c_char, + can_cancel: bool, + task: Option< + unsafe extern "C" fn( + *mut c_void, + Option bool>, + *mut c_void, + ), + >, + task_ctxt: *mut c_void, +) -> bool { + let ctxt = ctxt as *mut R; + let title = raw_to_string(title).unwrap(); + let task = InteractionHandlerTask { + ctxt: task_ctxt, + task, + }; + (*ctxt).run_progress_dialog(&title, can_cancel, &task) +} diff --git a/rust/src/interaction/report.rs b/rust/src/interaction/report.rs new file mode 100644 index 0000000000..a20d8f1f8e --- /dev/null +++ b/rust/src/interaction/report.rs @@ -0,0 +1,311 @@ +use std::ffi::c_char; +use std::ptr::NonNull; + +use binaryninjacore_sys::*; + +use crate::binary_view::BinaryView; +use crate::flowgraph::FlowGraph; +use crate::rc::{Ref, RefCountable}; +use crate::string::{BnString, IntoCStr}; + +pub type ReportType = BNReportType; + +#[repr(transparent)] +pub struct ReportCollection { + handle: NonNull, +} + +impl ReportCollection { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + unsafe { Ref::new(Self { handle }) } + } + + pub fn new() -> Ref { + let raw = unsafe { BNCreateReportCollection() }; + unsafe { Self::ref_from_raw(NonNull::new(raw).unwrap()) } + } + + pub fn show(&self, title: &str) { + let title = title.to_cstr(); + unsafe { BNShowReportCollection(title.as_ptr(), self.handle.as_ptr()) } + } + + pub fn count(&self) -> usize { + unsafe { BNGetReportCollectionCount(self.handle.as_ptr()) } + } + + fn report_type(&self, i: usize) -> ReportType { + unsafe { BNGetReportType(self.handle.as_ptr(), i) } + } + + pub fn get(&self, i: usize) -> Report<'_> { + Report::new(self, i) + } + + fn view(&self, i: usize) -> Ref { + let raw = unsafe { BNGetReportView(self.handle.as_ptr(), i) }; + unsafe { BinaryView::ref_from_raw(raw) } + } + + fn title(&self, i: usize) -> String { + let raw = unsafe { BNGetReportTitle(self.handle.as_ptr(), i) }; + unsafe { BnString::into_string(raw) } + } + + fn contents(&self, i: usize) -> String { + let raw = unsafe { BNGetReportContents(self.handle.as_ptr(), i) }; + unsafe { BnString::into_string(raw) } + } + + fn plain_text(&self, i: usize) -> String { + let raw = unsafe { BNGetReportPlainText(self.handle.as_ptr(), i) }; + unsafe { BnString::into_string(raw) } + } + + fn flow_graph(&self, i: usize) -> Ref { + let raw = unsafe { BNGetReportFlowGraph(self.handle.as_ptr(), i) }; + unsafe { FlowGraph::ref_from_raw(raw) } + } + + pub fn add_text(&self, view: &BinaryView, title: &str, contents: &str) { + let title = title.to_cstr(); + let contents = contents.to_cstr(); + unsafe { + BNAddPlainTextReportToCollection( + self.handle.as_ptr(), + view.handle, + title.as_ref().as_ptr() as *const c_char, + contents.as_ref().as_ptr() as *const c_char, + ) + } + } + + pub fn add_markdown(&self, view: &BinaryView, title: &str, contents: &str, plaintext: &str) { + let title = title.to_cstr(); + let contents = contents.to_cstr(); + let plaintext = plaintext.to_cstr(); + unsafe { + BNAddMarkdownReportToCollection( + self.handle.as_ptr(), + view.handle, + title.as_ref().as_ptr() as *const c_char, + contents.as_ref().as_ptr() as *const c_char, + plaintext.as_ref().as_ptr() as *const c_char, + ) + } + } + + pub fn add_html(&self, view: &BinaryView, title: &str, contents: &str, plaintext: &str) { + let title = title.to_cstr(); + let contents = contents.to_cstr(); + let plaintext = plaintext.to_cstr(); + unsafe { + BNAddHTMLReportToCollection( + self.handle.as_ptr(), + view.handle, + title.as_ref().as_ptr() as *const c_char, + contents.as_ref().as_ptr() as *const c_char, + plaintext.as_ref().as_ptr() as *const c_char, + ) + } + } + + pub fn add_graph(&self, view: &BinaryView, title: &str, graph: &FlowGraph) { + let title = title.to_cstr(); + unsafe { + BNAddGraphReportToCollection( + self.handle.as_ptr(), + view.handle, + title.as_ref().as_ptr() as *const c_char, + graph.handle, + ) + } + } + + fn update_report_flow_graph(&self, i: usize, graph: &FlowGraph) { + unsafe { BNUpdateReportFlowGraph(self.handle.as_ptr(), i, graph.handle) } + } + + pub fn iter(&self) -> ReportCollectionIter<'_> { + ReportCollectionIter::new(self) + } +} + +unsafe impl RefCountable for ReportCollection { + unsafe fn inc_ref(handle: &Self) -> Ref { + let raw = unsafe { BNNewReportCollectionReference(handle.handle.as_ptr()) }; + unsafe { Self::ref_from_raw(NonNull::new(raw).unwrap()) } + } + + unsafe fn dec_ref(handle: &Self) { + unsafe { BNFreeReportCollection(handle.handle.as_ptr()) } + } +} + +impl ToOwned for ReportCollection { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +impl<'a> IntoIterator for &'a ReportCollection { + type Item = Report<'a>; + type IntoIter = ReportCollectionIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +pub enum Report<'a> { + PlainText(ReportPlainText<'a>), + Markdown(ReportMarkdown<'a>), + Html(ReportHtml<'a>), + FlowGraph(ReportFlowGraph<'a>), +} + +impl<'a> Report<'a> { + fn new(collection: &'a ReportCollection, index: usize) -> Self { + let inner = ReportInner { collection, index }; + match inner.type_() { + ReportType::PlainTextReportType => Report::PlainText(ReportPlainText(inner)), + ReportType::MarkdownReportType => Report::Markdown(ReportMarkdown(inner)), + ReportType::HTMLReportType => Report::Html(ReportHtml(inner)), + ReportType::FlowGraphReportType => Report::FlowGraph(ReportFlowGraph(inner)), + } + } + + fn _inner(&self) -> &ReportInner<'a> { + match self { + Report::PlainText(ReportPlainText(x)) + | Report::Markdown(ReportMarkdown(x)) + | Report::Html(ReportHtml(x)) + | Report::FlowGraph(ReportFlowGraph(x)) => x, + } + } + + pub fn view(&self) -> Ref { + self._inner().view() + } + + pub fn title(&self) -> String { + self._inner().title() + } +} + +pub struct ReportPlainText<'a>(ReportInner<'a>); + +impl ReportPlainText<'_> { + pub fn contents(&self) -> String { + self.0.contents() + } +} + +pub struct ReportMarkdown<'a>(ReportInner<'a>); + +impl ReportMarkdown<'_> { + pub fn contents(&self) -> String { + self.0.contents() + } + + pub fn plaintext(&self) -> String { + self.0.plain_text() + } +} + +pub struct ReportHtml<'a>(ReportInner<'a>); + +impl ReportHtml<'_> { + pub fn contents(&self) -> String { + self.0.contents() + } + + pub fn plaintext(&self) -> String { + self.0.plain_text() + } +} + +pub struct ReportFlowGraph<'a>(ReportInner<'a>); + +impl ReportFlowGraph<'_> { + pub fn flow_graph(&self) -> Ref { + self.0.flow_graph() + } + + pub fn update_report_flow_graph(&self, graph: &FlowGraph) { + self.0.update_report_flow_graph(graph) + } +} + +struct ReportInner<'a> { + collection: &'a ReportCollection, + index: usize, +} + +impl ReportInner<'_> { + fn type_(&self) -> ReportType { + self.collection.report_type(self.index) + } + + fn view(&self) -> Ref { + self.collection.view(self.index) + } + + fn title(&self) -> String { + self.collection.title(self.index) + } + + fn contents(&self) -> String { + self.collection.contents(self.index) + } + + fn plain_text(&self) -> String { + self.collection.plain_text(self.index) + } + + fn flow_graph(&self) -> Ref { + self.collection.flow_graph(self.index) + } + + fn update_report_flow_graph(&self, graph: &FlowGraph) { + self.collection.update_report_flow_graph(self.index, graph) + } +} + +pub struct ReportCollectionIter<'a> { + report: &'a ReportCollection, + current_index: usize, + count: usize, +} + +impl<'a> ReportCollectionIter<'a> { + pub fn new(report: &'a ReportCollection) -> Self { + Self { + report, + current_index: 0, + count: report.count(), + } + } + + pub fn collection(&self) -> &ReportCollection { + self.report + } +} + +impl<'a> Iterator for ReportCollectionIter<'a> { + type Item = Report<'a>; + + fn next(&mut self) -> Option { + (self.current_index < self.count).then(|| { + let result = Report::new(self.report, self.current_index); + self.current_index += 1; + result + }) + } +} diff --git a/rust/src/language_representation.rs b/rust/src/language_representation.rs index 50e7b710d8..536203fe71 100644 --- a/rust/src/language_representation.rs +++ b/rust/src/language_representation.rs @@ -13,7 +13,7 @@ use crate::high_level_il::token_emitter::HighLevelILTokenEmitter; use crate::high_level_il::{HighLevelILFunction, HighLevelInstructionIndex}; use crate::line_formatter::CoreLineFormatter; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable}; -use crate::string::{BnStrCompatible, BnString}; +use crate::string::{BnString, IntoCStr}; use crate::type_parser::CoreTypeParser; use crate::type_printer::CoreTypePrinter; @@ -27,10 +27,9 @@ pub type SymbolDisplayResult = BNSymbolDisplayResult; pub fn register_language_representation_function_type< C: LanguageRepresentationFunctionType, F: FnOnce(CoreLanguageRepresentationFunctionType) -> C, - B: BnStrCompatible, >( creator: F, - name: B, + name: &str, ) -> CoreLanguageRepresentationFunctionType { let custom = Box::leak(Box::new(MaybeUninit::uninit())); let mut callbacks = BNCustomLanguageRepresentationFunctionType { @@ -43,13 +42,9 @@ pub fn register_language_representation_function_type< getFunctionTypeTokens: Some(cb_get_function_type_tokens::), freeLines: Some(cb_free_lines), }; - let name = name.into_bytes_with_nul(); - let core = unsafe { - BNRegisterLanguageRepresentationFunctionType( - name.as_ref().as_ptr() as *const c_char, - &mut callbacks, - ) - }; + let name = name.to_cstr(); + let core = + unsafe { BNRegisterLanguageRepresentationFunctionType(name.as_ptr(), &mut callbacks) }; let core = unsafe { CoreLanguageRepresentationFunctionType::from_raw(NonNull::new(core).unwrap()) }; custom.write(creator(core)); @@ -138,11 +133,9 @@ impl CoreLanguageRepresentationFunctionType { self.handle.as_ptr() } - pub fn from_name(name: S) -> Option { - let name = name.into_bytes_with_nul(); - let result = unsafe { - BNGetLanguageRepresentationFunctionTypeByName(name.as_ref().as_ptr() as *const c_char) - }; + pub fn from_name(name: &str) -> Option { + let name = name.to_cstr(); + let result = unsafe { BNGetLanguageRepresentationFunctionTypeByName(name.as_ptr()) }; NonNull::new(result).map(|handle| unsafe { Self::from_raw(handle) }) } diff --git a/rust/src/line_formatter.rs b/rust/src/line_formatter.rs index 5dc07c5c70..50f1900c31 100644 --- a/rust/src/line_formatter.rs +++ b/rust/src/line_formatter.rs @@ -1,4 +1,4 @@ -use std::ffi::{c_char, c_void}; +use std::ffi::c_void; use std::ptr::NonNull; use binaryninjacore_sys::*; @@ -6,22 +6,18 @@ use binaryninjacore_sys::*; use crate::disassembly::DisassemblyTextLine; use crate::high_level_il::HighLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; -use crate::string::{raw_to_string, BnStrCompatible, BnString}; +use crate::string::{raw_to_string, BnString, IntoCStr}; /// Register a [`LineFormatter`] with the API. -pub fn register_line_formatter( - name: B, - formatter: C, -) -> CoreLineFormatter { +pub fn register_line_formatter(name: &str, formatter: C) -> CoreLineFormatter { let custom = Box::leak(Box::new(formatter)); let mut callbacks = BNCustomLineFormatter { context: custom as *mut C as *mut c_void, formatLines: Some(cb_format_lines::), freeLines: Some(cb_free_lines), }; - let name = name.into_bytes_with_nul(); - let handle = - unsafe { BNRegisterLineFormatter(name.as_ref().as_ptr() as *const c_char, &mut callbacks) }; + let name = name.to_cstr(); + let handle = unsafe { BNRegisterLineFormatter(name.as_ptr(), &mut callbacks) }; CoreLineFormatter::from_raw(NonNull::new(handle).unwrap()) } @@ -54,10 +50,9 @@ impl CoreLineFormatter { unsafe { Array::new(result, count, ()) } } - pub fn from_name(name: S) -> Option { - let name_raw = name.into_bytes_with_nul(); - let result = - unsafe { BNGetLineFormatterByName(name_raw.as_ref().as_ptr() as *const c_char) }; + pub fn from_name(name: &str) -> Option { + let name_raw = name.to_cstr(); + let result = unsafe { BNGetLineFormatterByName(name_raw.as_ptr()) }; NonNull::new(result).map(Self::from_raw) } diff --git a/rust/src/string.rs b/rust/src/string.rs index a670320ba5..97c3127007 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -34,12 +34,16 @@ pub(crate) fn raw_to_string(ptr: *const c_char) -> Option { } } -// TODO: Make this pass in an iterator over something more generic... -pub(crate) fn strings_to_string_list(strings: &[String]) -> *mut *mut c_char { +pub(crate) fn strings_to_string_list(strings: I) -> *mut *mut c_char +where + I: IntoIterator, + // TODO make `S: BnStrCompatible,` + S: AsRef, +{ use binaryninjacore_sys::BNAllocStringList; let bn_str_list = strings - .iter() - .map(|s| BnString::new(s.as_str())) + .into_iter() + .map(|s| BnString::new(s.as_ref())) .collect::>(); let mut raw_str_list = bn_str_list.iter().map(|s| s.as_ptr()).collect::>(); unsafe { BNAllocStringList(raw_str_list.as_mut_ptr(), raw_str_list.len()) } diff --git a/rust/tests/interaction.rs b/rust/tests/interaction.rs new file mode 100644 index 0000000000..eea906ecfd --- /dev/null +++ b/rust/tests/interaction.rs @@ -0,0 +1,169 @@ +use std::path::PathBuf; + +use binaryninja::binary_view::BinaryView; +use binaryninja::flowgraph::FlowGraph; +use binaryninja::headless::Session; +use binaryninja::interaction::form::{Form, FormInputField}; +use binaryninja::interaction::handler::{ + register_interaction_handler, InteractionHandler, InteractionHandlerTask, +}; +use binaryninja::interaction::report::{Report, ReportCollection}; +use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon}; + +struct MyInteractionHandler; + +impl InteractionHandler for MyInteractionHandler { + fn show_message_box( + &mut self, + _title: &str, + _text: &str, + _buttons: MessageBoxButtonSet, + _icon: MessageBoxIcon, + ) -> MessageBoxButtonResult { + todo!() + } + + fn open_url(&mut self, _url: &str) -> bool { + todo!() + } + + fn run_progress_dialog( + &mut self, + _title: &str, + _can_cancel: bool, + _task: &InteractionHandlerTask, + ) -> bool { + todo!() + } + + fn show_plain_text_report(&mut self, _view: &BinaryView, _title: &str, _contents: &str) { + todo!() + } + + fn show_graph_report(&mut self, _view: &BinaryView, _title: &str, _graph: &FlowGraph) { + todo!() + } + + fn show_report_collection(&mut self, title: &str, reports: &ReportCollection) { + assert_eq!(title, "show_report_collection_title"); + for (i, report) in reports.iter().enumerate() { + assert_eq!(report.title(), format!("title_report_{i}")); + match (i, report) { + (0, Report::PlainText(x)) => { + assert_eq!(x.contents().as_str(), "contents"); + } + (1, Report::Markdown(x)) => { + assert_eq!(x.contents().as_str(), "# contents"); + assert_eq!(x.plaintext().as_str(), "markdown_plain_text"); + } + (2, Report::Html(x)) => { + assert_eq!(x.contents().as_str(), "contents"); + assert_eq!(x.plaintext().as_str(), "html_plain_text"); + } + (3, Report::FlowGraph(x)) => { + assert_eq!(x.flow_graph().get_node_count(), 0); + } + _ => unreachable!(), + } + } + } + + fn get_form_input(&mut self, form: &mut Form) -> bool { + if form.fields.len() != 1 { + return false; + } + + match &mut form.fields[0] { + FormInputField::Integer { ref mut value, .. } => { + *value = 1337; + true + } + FormInputField::Address { + ref mut value, + default, + .. + } => { + *value = default.unwrap_or(0) + 0x10; + true + } + FormInputField::DirectoryName { + ref mut value, + default, + default_name, + .. + } => { + let new_value = format!( + "example{}{}", + default.clone().unwrap_or_default(), + default_name.clone().unwrap_or_default() + ); + *value = Some(new_value); + true + } + _ => false, + } + } +} + +#[test] +fn test_get_integer() { + register_interaction_handler(MyInteractionHandler {}); + let output = binaryninja::interaction::get_integer_input("get_int", "get_int_prompt"); + assert_eq!(output, Some(1337)); +} + +#[test] +fn test_get_directory() { + register_interaction_handler(MyInteractionHandler {}); + let output = binaryninja::interaction::get_directory_name_input("get_dir", ""); + assert_eq!( + output.as_ref().map(|x| x.to_str().unwrap()), + Some("example") + ); +} + +#[test] +fn test_get_directory_default() { + register_interaction_handler(MyInteractionHandler {}); + + let mut my_form = Form::new("get_dir_default"); + my_form.add_field(FormInputField::DirectoryName { + prompt: "get_dir_default".to_string(), + default_name: Some("_default_name".to_string()), + default: Some("_default".to_string()), + value: None, + }); + + assert_eq!(my_form.prompt(), true); + assert_eq!( + my_form.fields[0].try_value_string(), + Some("example_default_default_name".to_string()) + ) +} + +#[test] +fn test_get_address() { + register_interaction_handler(MyInteractionHandler {}); + let output = binaryninja::interaction::get_address_input("address", "Address Prompt"); + assert_eq!(output, Some(0x10)); +} + +#[test] +fn test_show_report_collection() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + + register_interaction_handler(MyInteractionHandler {}); + let collection = ReportCollection::new(); + collection.add_text(&view, "title_report_0", "contents"); + collection.add_markdown(&view, "title_report_1", "# contents", "markdown_plain_text"); + collection.add_html( + &view, + "title_report_2", + "contents", + "html_plain_text", + ); + collection.add_graph(&view, "title_report_3", &FlowGraph::new()); + collection.show("show_report_collection_title"); +} From 603aa11a71d650f2c397844c31c79c644145f242 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Thu, 8 May 2025 21:01:42 -0400 Subject: [PATCH 25/54] [Rust] Misc cleanup --- rust/src/function.rs | 12 ++-------- rust/src/string.rs | 46 +++++++++++++++++------------------- rust/tests/line_formatter.rs | 3 ++- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/rust/src/function.rs b/rust/src/function.rs index e7e5e9b0e1..925383847c 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -485,12 +485,7 @@ impl Function { language: &str, ) -> Option> { let lang_name = language.to_cstr(); - let repr = unsafe { - BNGetFunctionLanguageRepresentation( - self.handle, - lang_name.as_ptr(), - ) - }; + let repr = unsafe { BNGetFunctionLanguageRepresentation(self.handle, lang_name.as_ptr()) }; NonNull::new(repr) .map(|handle| unsafe { CoreLanguageRepresentationFunction::ref_from_raw(handle) }) } @@ -504,10 +499,7 @@ impl Function { ) -> Option> { let lang_name = language.to_cstr(); let repr = unsafe { - BNGetFunctionLanguageRepresentationIfAvailable( - self.handle, - lang_name.as_ptr(), - ) + BNGetFunctionLanguageRepresentationIfAvailable(self.handle, lang_name.as_ptr()) }; NonNull::new(repr) .map(|handle| unsafe { CoreLanguageRepresentationFunction::ref_from_raw(handle) }) diff --git a/rust/src/string.rs b/rust/src/string.rs index 97c3127007..6083d3006a 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -14,9 +14,7 @@ //! String wrappers for core-owned strings and strings being passed to the core -use crate::rc::*; -use crate::type_archive::TypeArchiveSnapshotId; -use crate::types::QualifiedName; +use binaryninjacore_sys::*; use std::borrow::Cow; use std::ffi::{c_char, CStr, CString}; use std::fmt; @@ -25,6 +23,10 @@ use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; +use crate::rc::*; +use crate::type_archive::TypeArchiveSnapshotId; +use crate::types::QualifiedName; + // TODO: Remove or refactor this. pub(crate) fn raw_to_string(ptr: *const c_char) -> Option { if ptr.is_null() { @@ -66,8 +68,7 @@ pub struct BnString { } impl BnString { - pub fn new(s: S) -> Self { - use binaryninjacore_sys::BNAllocString; + pub fn new(s: impl IntoCStr) -> Self { let raw = s.to_cstr(); unsafe { Self::from_raw(BNAllocString(raw.as_ptr())) } } @@ -79,14 +80,13 @@ impl BnString { Self::from_raw(raw).to_string_lossy().to_string() } - /// Construct a BnString from an owned const char* allocated by BNAllocString + /// Construct a BnString from an owned const char* allocated by [`BNAllocString`]. pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self { Self { raw } } - /// Free a raw string allocated by BNAllocString. + /// Free a raw string allocated by [`BNAllocString`]. pub(crate) unsafe fn free_raw(raw: *mut c_char) { - use binaryninjacore_sys::BNFreeString; if !raw.is_null() { BNFreeString(raw); } @@ -115,7 +115,6 @@ impl Drop for BnString { impl Clone for BnString { fn clone(&self) -> Self { - use binaryninjacore_sys::BNAllocString; unsafe { Self { raw: BNAllocString(self.raw), @@ -178,7 +177,6 @@ impl CoreArrayProvider for BnString { unsafe impl CoreArrayProviderInner for BnString { unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { - use binaryninjacore_sys::BNFreeStringList; BNFreeStringList(raw, count); } @@ -187,13 +185,13 @@ unsafe impl CoreArrayProviderInner for BnString { } } -pub unsafe trait IntoCStr { +pub trait IntoCStr { type Result: Deref; fn to_cstr(self) -> Self::Result; } -unsafe impl IntoCStr for &CStr { +impl IntoCStr for &CStr { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -201,7 +199,7 @@ unsafe impl IntoCStr for &CStr { } } -unsafe impl IntoCStr for BnString { +impl IntoCStr for BnString { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -209,7 +207,7 @@ unsafe impl IntoCStr for BnString { } } -unsafe impl IntoCStr for &BnString { +impl IntoCStr for &BnString { type Result = BnString; fn to_cstr(self) -> Self::Result { @@ -217,7 +215,7 @@ unsafe impl IntoCStr for &BnString { } } -unsafe impl IntoCStr for CString { +impl IntoCStr for CString { type Result = Self; fn to_cstr(self) -> Self::Result { @@ -225,7 +223,7 @@ unsafe impl IntoCStr for CString { } } -unsafe impl IntoCStr for &str { +impl IntoCStr for &str { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -233,7 +231,7 @@ unsafe impl IntoCStr for &str { } } -unsafe impl IntoCStr for String { +impl IntoCStr for String { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -241,7 +239,7 @@ unsafe impl IntoCStr for String { } } -unsafe impl IntoCStr for &String { +impl IntoCStr for &String { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -249,7 +247,7 @@ unsafe impl IntoCStr for &String { } } -unsafe impl<'a> IntoCStr for &'a Cow<'a, str> { +impl<'a> IntoCStr for &'a Cow<'a, str> { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -257,7 +255,7 @@ unsafe impl<'a> IntoCStr for &'a Cow<'a, str> { } } -unsafe impl IntoCStr for Cow<'_, str> { +impl IntoCStr for Cow<'_, str> { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -265,7 +263,7 @@ unsafe impl IntoCStr for Cow<'_, str> { } } -unsafe impl IntoCStr for &QualifiedName { +impl IntoCStr for &QualifiedName { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -273,7 +271,7 @@ unsafe impl IntoCStr for &QualifiedName { } } -unsafe impl IntoCStr for PathBuf { +impl IntoCStr for PathBuf { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -281,7 +279,7 @@ unsafe impl IntoCStr for PathBuf { } } -unsafe impl IntoCStr for &Path { +impl IntoCStr for &Path { type Result = CString; fn to_cstr(self) -> Self::Result { @@ -290,7 +288,7 @@ unsafe impl IntoCStr for &Path { } } -unsafe impl IntoCStr for TypeArchiveSnapshotId { +impl IntoCStr for TypeArchiveSnapshotId { type Result = CString; fn to_cstr(self) -> Self::Result { diff --git a/rust/tests/line_formatter.rs b/rust/tests/line_formatter.rs index 72968238fe..eeb5f0e109 100644 --- a/rust/tests/line_formatter.rs +++ b/rust/tests/line_formatter.rs @@ -20,5 +20,6 @@ fn test_custom_line_formatter() { let _session = Session::new().expect("Failed to initialize session"); let out_dir = env!("OUT_DIR").parse::().unwrap(); let line_formatter = register_line_formatter("my_line_formatter", MyLineFormatter {}); - assert_eq!(line_formatter.name().as_str(), "my_line_formatter"); + assert_eq!(line_formatter.name(), "my_line_formatter".into()); + // TODO: Finish this test. } From 81211f5a45bf7b881f22ed43c59672603f5439cc Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Thu, 8 May 2025 21:39:12 -0400 Subject: [PATCH 26/54] [Rust] Flow graph API improvements - Fixed some misc bugs - Added real FlowGraphEdge type - Added accessors for node edges - Added interaction handler to the flow graph example to dump the flow graph to stdin - Split out the flow graph API into smaller files --- rust/examples/flowgraph.rs | 89 ++++++++++++++++++- rust/src/flowgraph.rs | 177 ++----------------------------------- rust/src/flowgraph/edge.rs | 113 +++++++++++++++++++++++ rust/src/flowgraph/node.rs | 155 ++++++++++++++++++++++++++++++++ 4 files changed, 362 insertions(+), 172 deletions(-) create mode 100644 rust/src/flowgraph/edge.rs create mode 100644 rust/src/flowgraph/node.rs diff --git a/rust/examples/flowgraph.rs b/rust/examples/flowgraph.rs index 6666b7fbc7..515d52fe0e 100644 --- a/rust/examples/flowgraph.rs +++ b/rust/examples/flowgraph.rs @@ -1,9 +1,82 @@ +use binaryninja::flowgraph::edge::EdgeStyle; +use binaryninja::flowgraph::FlowGraphNode; +use binaryninja::function::FunctionViewType; +use binaryninja::interaction::form::Form; +use binaryninja::interaction::handler::{ + register_interaction_handler, InteractionHandler, InteractionHandlerTask, +}; +use binaryninja::interaction::{MessageBoxButtonResult, MessageBoxButtonSet, MessageBoxIcon}; use binaryninja::{ binary_view::{BinaryView, BinaryViewExt}, disassembly::{DisassemblyTextLine, InstructionTextToken, InstructionTextTokenKind}, - flowgraph::{BranchType, EdgePenStyle, EdgeStyle, FlowGraph, FlowGraphNode, ThemeColor}, + flowgraph::{BranchType, EdgePenStyle, FlowGraph, ThemeColor}, }; +pub struct GraphPrinter; + +impl GraphPrinter { + pub fn print_graph(&self, _view: &BinaryView, graph: &FlowGraph) { + println!("Printing flow graph:"); + for node in &graph.nodes() { + // Print all disassembly lines in the node + println!("Node @ {:?}:", node.position()); + println!("------------------"); + println!("Disassembly lines:"); + for line in &node.lines() { + println!(" {}", line); + } + + // Print outgoing edges + println!("Outgoing edges:"); + for edge in &node.outgoing_edges() { + println!(" {:?} => {:?}", edge.branch_type, edge.target.position()); + } + println!("------------------"); + } + } +} + +impl InteractionHandler for GraphPrinter { + fn show_message_box( + &mut self, + _title: &str, + _text: &str, + _buttons: MessageBoxButtonSet, + _icon: MessageBoxIcon, + ) -> MessageBoxButtonResult { + MessageBoxButtonResult::CancelButton + } + + fn open_url(&mut self, _url: &str) -> bool { + false + } + + fn run_progress_dialog( + &mut self, + _title: &str, + _can_cancel: bool, + _task: &InteractionHandlerTask, + ) -> bool { + false + } + + fn show_plain_text_report(&mut self, _view: &BinaryView, title: &str, contents: &str) { + println!("Plain text report"); + println!("Title: {}", title); + println!("Contents: {}", contents); + } + + fn show_graph_report(&mut self, view: &BinaryView, title: &str, graph: &FlowGraph) { + println!("Graph report"); + println!("Title: {}", title); + self.print_graph(view, graph); + } + + fn get_form_input(&mut self, _form: &mut Form) -> bool { + false + } +} + fn test_graph(view: &BinaryView) { let graph = FlowGraph::new(); @@ -15,8 +88,10 @@ fn test_graph(view: &BinaryView) { let node_a = FlowGraphNode::new(&graph); node_a.set_lines(disassembly_lines_a); + node_a.set_position(1337, 7331); let node_b = FlowGraphNode::new(&graph); + node_b.set_position(100, 200); let disassembly_lines_b = vec![DisassemblyTextLine::new(vec![ InstructionTextToken::new("Li", InstructionTextTokenKind::Text), InstructionTextToken::new("ne", InstructionTextTokenKind::Text), @@ -49,8 +124,16 @@ fn main() { .load("/bin/cat") .expect("Couldn't open `/bin/cat`"); - // TODO: Register BNInteractionHandlerCallbacks with showGraphReport pointing at our function - // TODO: Idea: register showGraphReport that dumps a dotgraph to stdin + // Register the interaction handler so we can see the graph report headlessly. + register_interaction_handler(GraphPrinter); test_graph(&bv); + + for func in bv.functions().iter().take(5) { + let graph = func.create_graph(FunctionViewType::MediumLevelIL, None); + assert!(!graph.nodes().is_empty()); + let func_name = func.symbol().short_name(); + let title = func_name.to_string_lossy(); + bv.show_graph_report(&title, &graph); + } } diff --git a/rust/src/flowgraph.rs b/rust/src/flowgraph.rs index 976764eb19..0faab0e487 100644 --- a/rust/src/flowgraph.rs +++ b/rust/src/flowgraph.rs @@ -14,17 +14,21 @@ //! Interfaces for creating and displaying pretty CFGs in Binary Ninja. -use crate::disassembly::DisassemblyTextLine; -use crate::rc::*; use binaryninjacore_sys::*; -use crate::basic_block::{BasicBlock, BlockContext}; -use crate::function::HighlightColor; use crate::high_level_il::HighLevelILFunction; use crate::low_level_il::RegularLowLevelILFunction; use crate::medium_level_il::MediumLevelILFunction; +use crate::rc::*; use crate::render_layer::CoreRenderLayer; +pub mod edge; +pub mod node; + +pub use edge::EdgeStyle; +pub use edge::FlowGraphEdge; +pub use node::FlowGraphNode; + pub type BranchType = BNBranchType; pub type EdgePenStyle = BNEdgePenStyle; pub type ThemeColor = BNThemeColor; @@ -162,168 +166,3 @@ impl ToOwned for FlowGraph { unsafe { RefCountable::inc_ref(self) } } } - -#[derive(PartialEq, Eq, Hash)] -pub struct FlowGraphNode { - pub(crate) handle: *mut BNFlowGraphNode, -} - -impl FlowGraphNode { - pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self { - Self { handle: raw } - } - - pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref { - Ref::new(Self { handle: raw }) - } - - pub fn new(graph: &FlowGraph) -> Ref { - unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) } - } - - pub fn basic_block(&self, context: C) -> Option>> { - let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) }; - if block_ptr.is_null() { - return None; - } - Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) }) - } - - pub fn set_basic_block(&self, block: Option<&BasicBlock>) { - match block { - Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) }, - None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) }, - } - } - - pub fn lines(&self) -> Array { - let mut count = 0; - let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) }; - assert!(!result.is_null()); - unsafe { Array::new(result, count, ()) } - } - - pub fn set_lines(&self, lines: impl IntoIterator) { - // NOTE: This will create allocations and increment tag refs, we must call DisassemblyTextLine::free_raw - let mut raw_lines: Vec = lines - .into_iter() - .map(DisassemblyTextLine::into_raw) - .collect(); - unsafe { - BNSetFlowGraphNodeLines(self.handle, raw_lines.as_mut_ptr(), raw_lines.len()); - for raw_line in raw_lines { - DisassemblyTextLine::free_raw(raw_line); - } - } - } - - /// Returns the graph position of the node in X, Y form. - pub fn position(&self) -> (i32, i32) { - let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) }; - let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) }; - (pos_x, pos_y) - } - - /// Sets the graph position of the node. - pub fn set_position(&self, x: i32, y: i32) { - unsafe { BNFlowGraphNodeSetX(self.handle, x) }; - unsafe { BNFlowGraphNodeSetX(self.handle, y) }; - } - - pub fn highlight_color(&self) -> HighlightColor { - let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) }; - HighlightColor::from(raw) - } - - pub fn set_highlight_color(&self, highlight: HighlightColor) { - unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) }; - } - - // TODO: Add getters and setters for edges - - pub fn add_outgoing_edge( - &self, - type_: BranchType, - target: &FlowGraphNode, - edge_style: EdgeStyle, - ) { - unsafe { - BNAddFlowGraphNodeOutgoingEdge(self.handle, type_, target.handle, edge_style.into()) - } - } -} - -unsafe impl RefCountable for FlowGraphNode { - unsafe fn inc_ref(handle: &Self) -> Ref { - Ref::new(Self { - handle: BNNewFlowGraphNodeReference(handle.handle), - }) - } - - unsafe fn dec_ref(handle: &Self) { - BNFreeFlowGraphNode(handle.handle); - } -} - -impl ToOwned for FlowGraphNode { - type Owned = Ref; - - fn to_owned(&self) -> Self::Owned { - unsafe { RefCountable::inc_ref(self) } - } -} - -impl CoreArrayProvider for FlowGraphNode { - type Raw = *mut BNFlowGraphNode; - type Context = (); - type Wrapped<'a> = Guard<'a, FlowGraphNode>; -} - -unsafe impl CoreArrayProviderInner for FlowGraphNode { - unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) { - BNFreeFlowGraphNodeList(raw, count); - } - - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { - Guard::new(Self::from_raw(*raw), context) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub struct EdgeStyle { - style: EdgePenStyle, - width: usize, - color: ThemeColor, -} - -impl EdgeStyle { - pub fn new(style: EdgePenStyle, width: usize, color: ThemeColor) -> Self { - Self { - style, - width, - color, - } - } -} - -impl Default for EdgeStyle { - fn default() -> Self { - Self::new(EdgePenStyle::SolidLine, 0, ThemeColor::AddressColor) - } -} - -impl From for EdgeStyle { - fn from(style: BNEdgeStyle) -> Self { - Self::new(style.style, style.width, style.color) - } -} - -impl From for BNEdgeStyle { - fn from(style: EdgeStyle) -> Self { - Self { - style: style.style, - width: style.width, - color: style.color, - } - } -} diff --git a/rust/src/flowgraph/edge.rs b/rust/src/flowgraph/edge.rs new file mode 100644 index 0000000000..7862f15652 --- /dev/null +++ b/rust/src/flowgraph/edge.rs @@ -0,0 +1,113 @@ +use binaryninjacore_sys::*; + +use crate::flowgraph::node::FlowGraphNode; +use crate::flowgraph::{BranchType, EdgePenStyle, ThemeColor}; +use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref}; + +#[derive(Clone, Debug, PartialEq)] +pub struct FlowGraphEdge { + pub branch_type: BranchType, + pub target: Ref, + pub points: Vec, + pub back_edge: bool, + pub style: EdgeStyle, +} + +impl FlowGraphEdge { + pub fn from_raw(value: &BNFlowGraphEdge) -> Self { + let raw_points = unsafe { std::slice::from_raw_parts(value.points, value.pointCount) }; + let points: Vec<_> = raw_points.iter().copied().map(Point::from).collect(); + Self { + branch_type: value.type_, + target: unsafe { FlowGraphNode::from_raw(value.target) }.to_owned(), + points, + back_edge: value.backEdge, + style: value.style.into(), + } + } +} + +impl CoreArrayProvider for FlowGraphEdge { + type Raw = BNFlowGraphEdge; + type Context = (); + type Wrapped<'a> = FlowGraphEdge; +} + +unsafe impl CoreArrayProviderInner for FlowGraphEdge { + unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) { + BNFreeFlowGraphNodeEdgeList(raw, count); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::from_raw(raw) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Default)] +pub struct Point { + pub x: f32, + pub y: f32, +} + +impl Point { + pub fn new(x: f32, y: f32) -> Self { + Self { x, y } + } +} + +impl From for Point { + fn from(value: BNPoint) -> Self { + Self { + x: value.x, + y: value.y, + } + } +} + +impl From for BNPoint { + fn from(value: Point) -> Self { + Self { + x: value.x, + y: value.y, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct EdgeStyle { + style: EdgePenStyle, + width: usize, + color: ThemeColor, +} + +impl EdgeStyle { + pub fn new(style: EdgePenStyle, width: usize, color: ThemeColor) -> Self { + Self { + style, + width, + color, + } + } +} + +impl Default for EdgeStyle { + fn default() -> Self { + Self::new(EdgePenStyle::SolidLine, 0, ThemeColor::AddressColor) + } +} + +impl From for EdgeStyle { + fn from(style: BNEdgeStyle) -> Self { + Self::new(style.style, style.width, style.color) + } +} + +impl From for BNEdgeStyle { + fn from(style: EdgeStyle) -> Self { + Self { + style: style.style, + width: style.width, + color: style.color, + } + } +} diff --git a/rust/src/flowgraph/node.rs b/rust/src/flowgraph/node.rs new file mode 100644 index 0000000000..5c2b9248da --- /dev/null +++ b/rust/src/flowgraph/node.rs @@ -0,0 +1,155 @@ +use crate::basic_block::{BasicBlock, BlockContext}; +use crate::disassembly::DisassemblyTextLine; +use crate::flowgraph::edge::{EdgeStyle, FlowGraphEdge}; +use crate::flowgraph::{BranchType, FlowGraph}; +use crate::function::HighlightColor; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use binaryninjacore_sys::*; +use std::fmt::{Debug, Formatter}; + +#[derive(PartialEq, Eq, Hash)] +pub struct FlowGraphNode { + pub(crate) handle: *mut BNFlowGraphNode, +} + +impl FlowGraphNode { + pub(crate) unsafe fn from_raw(raw: *mut BNFlowGraphNode) -> Self { + Self { handle: raw } + } + + pub(crate) unsafe fn ref_from_raw(raw: *mut BNFlowGraphNode) -> Ref { + Ref::new(Self { handle: raw }) + } + + pub fn new(graph: &FlowGraph) -> Ref { + unsafe { FlowGraphNode::ref_from_raw(BNCreateFlowGraphNode(graph.handle)) } + } + + pub fn basic_block(&self, context: C) -> Option>> { + let block_ptr = unsafe { BNGetFlowGraphBasicBlock(self.handle) }; + if block_ptr.is_null() { + return None; + } + Some(unsafe { BasicBlock::ref_from_raw(block_ptr, context) }) + } + + pub fn set_basic_block(&self, block: Option<&BasicBlock>) { + match block { + Some(block) => unsafe { BNSetFlowGraphBasicBlock(self.handle, block.handle) }, + None => unsafe { BNSetFlowGraphBasicBlock(self.handle, std::ptr::null_mut()) }, + } + } + + pub fn lines(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetFlowGraphNodeLines(self.handle, &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + pub fn set_lines(&self, lines: impl IntoIterator) { + // NOTE: This will create allocations and increment tag refs, we must call DisassemblyTextLine::free_raw + let mut raw_lines: Vec = lines + .into_iter() + .map(DisassemblyTextLine::into_raw) + .collect(); + unsafe { + BNSetFlowGraphNodeLines(self.handle, raw_lines.as_mut_ptr(), raw_lines.len()); + for raw_line in raw_lines { + DisassemblyTextLine::free_raw(raw_line); + } + } + } + + /// Returns the graph position of the node in X, Y form. + pub fn position(&self) -> (i32, i32) { + let pos_x = unsafe { BNGetFlowGraphNodeX(self.handle) }; + let pos_y = unsafe { BNGetFlowGraphNodeY(self.handle) }; + (pos_x, pos_y) + } + + /// Sets the graph position of the node. + pub fn set_position(&self, x: i32, y: i32) { + unsafe { BNFlowGraphNodeSetX(self.handle, x) }; + unsafe { BNFlowGraphNodeSetY(self.handle, y) }; + } + + pub fn highlight_color(&self) -> HighlightColor { + let raw = unsafe { BNGetFlowGraphNodeHighlight(self.handle) }; + HighlightColor::from(raw) + } + + pub fn set_highlight_color(&self, highlight: HighlightColor) { + unsafe { BNSetFlowGraphNodeHighlight(self.handle, highlight.into()) }; + } + + pub fn incoming_edges(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetFlowGraphNodeIncomingEdges(self.handle, &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + pub fn outgoing_edges(&self) -> Array { + let mut count = 0; + let result = unsafe { BNGetFlowGraphNodeOutgoingEdges(self.handle, &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Connects two flow graph nodes with an edge. + pub fn add_outgoing_edge( + &self, + type_: BranchType, + target: &FlowGraphNode, + edge_style: EdgeStyle, + ) { + unsafe { + BNAddFlowGraphNodeOutgoingEdge(self.handle, type_, target.handle, edge_style.into()) + } + } +} + +impl Debug for FlowGraphNode { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FlowGraphNode") + .field("lines", &self.lines().to_vec()) + .finish() + } +} + +unsafe impl RefCountable for FlowGraphNode { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: BNNewFlowGraphNodeReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeFlowGraphNode(handle.handle); + } +} + +impl ToOwned for FlowGraphNode { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +impl CoreArrayProvider for FlowGraphNode { + type Raw = *mut BNFlowGraphNode; + type Context = (); + type Wrapped<'a> = Guard<'a, FlowGraphNode>; +} + +unsafe impl CoreArrayProviderInner for FlowGraphNode { + unsafe fn free(raw: *mut Self::Raw, count: usize, _: &Self::Context) { + BNFreeFlowGraphNodeList(raw, count); + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Guard::new(Self::from_raw(*raw), context) + } +} From 3e16477d7785b18746a5cc95386250437ff0abb2 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Thu, 8 May 2025 21:50:23 -0400 Subject: [PATCH 27/54] [Rust] Fix misc typos --- rust/Cargo.toml | 5 ++- rust/src/high_level_il/token_emitter.rs | 4 +- rust/src/interaction/handler.rs | 6 +-- rust/tests/language_representation.rs | 54 ++++++++++++------------- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 361b2057a6..aecffb9980 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -22,4 +22,7 @@ thiserror = "2.0" [dev-dependencies] rstest = "0.24" tempfile = "3.15" -serial_test = "3.2" \ No newline at end of file +serial_test = "3.2" + +[package.metadata.typos] +default.extend-ignore-re = ["Collapsable"] \ No newline at end of file diff --git a/rust/src/high_level_il/token_emitter.rs b/rust/src/high_level_il/token_emitter.rs index 2f1236a94b..864ee50dd0 100644 --- a/rust/src/high_level_il/token_emitter.rs +++ b/rust/src/high_level_il/token_emitter.rs @@ -50,11 +50,11 @@ impl HighLevelILTokenEmitter { }; } - pub fn has_collapsable_regions(&self) -> bool { + pub fn has_collapsible_regions(&self) -> bool { unsafe { BNHighLevelILTokenEmitterHasCollapsableRegions(self.handle.as_ptr()) } } - pub fn set_has_collapsable_regions(&self, state: bool) { + pub fn set_has_collapsible_regions(&self, state: bool) { unsafe { BNHighLevelILTokenEmitterSetHasCollapsableRegions(self.handle.as_ptr(), state) }; } diff --git a/rust/src/interaction/handler.rs b/rust/src/interaction/handler.rs index fa1681d132..23ca66e4f3 100644 --- a/rust/src/interaction/handler.rs +++ b/rust/src/interaction/handler.rs @@ -264,17 +264,17 @@ impl InteractionHandlerTask { }; let progress_ctxt = progress as *mut P as *mut c_void; - ffi_wrap!("custom_interation_run_progress_dialog", unsafe { + ffi_wrap!("custom_interaction_run_progress_dialog", unsafe { task( self.ctxt, - Some(cb_custom_interation_handler_task::

), + Some(cb_custom_interaction_handler_task::

), progress_ctxt, ) }) } } -unsafe extern "C" fn cb_custom_interation_handler_task bool>( +unsafe extern "C" fn cb_custom_interaction_handler_task bool>( ctxt: *mut c_void, cur: usize, max: usize, diff --git a/rust/tests/language_representation.rs b/rust/tests/language_representation.rs index 5c034c2f5e..c3d6096678 100644 --- a/rust/tests/language_representation.rs +++ b/rust/tests/language_representation.rs @@ -91,7 +91,7 @@ impl LanguageRepresentationFunction for MyLangRepr { Unimpl | Unreachable | Undef => panic!(), _kind => { tokens.append(InstructionTextToken::new( - format!("other instr {:x}\n", instr.address), + format!("other instr 0x{:x}\n", instr.address), InstructionTextTokenKind::Text, )); } @@ -155,32 +155,32 @@ fn test_custom_language_representation() { assert_eq!( format!("{output}"), "block 26 -other instr 36775 -other instr 3679e -other instr 3679e -other instr 367ba -other instr 367e6 -other instr 3682f -other instr 3682f -other instr 36834 -other instr 3683e -other instr 3684e -other instr 36867 -other instr 36881 -other instr 36881 -other instr 36881 -other instr 36896 -other instr 368a0 -other instr 368bb -other instr 368d2 -other instr 3694a -other instr 36960 -other instr 369e1 -other instr 369ec -other instr 36a2e -other instr 36ab5 -other instr 36abd -other instr 36ac2 +other instr 0x36775 +other instr 0x3679e +other instr 0x3679e +other instr 0x367ba +other instr 0x367e6 +other instr 0x3682f +other instr 0x3682f +other instr 0x36834 +other instr 0x3683e +other instr 0x3684e +other instr 0x36867 +other instr 0x36881 +other instr 0x36881 +other instr 0x36881 +other instr 0x36896 +other instr 0x368a0 +other instr 0x368bb +other instr 0x368d2 +other instr 0x3694a +other instr 0x36960 +other instr 0x369e1 +other instr 0x369ec +other instr 0x36a2e +other instr 0x36ab5 +other instr 0x36abd +other instr 0x36ac2 " ); } From 155def0973baa1fbcc276f53a1f80be4a1cb1176 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Fri, 9 May 2025 14:00:38 -0400 Subject: [PATCH 28/54] [Rust] Support SSA form properly in low level IL --- arch/riscv/src/lib.rs | 2 +- rust/src/low_level_il.rs | 54 ++- rust/src/low_level_il/expression.rs | 280 ++++++----- rust/src/low_level_il/function.rs | 26 +- rust/src/low_level_il/instruction.rs | 108 +++-- rust/src/low_level_il/operation.rs | 669 ++++++++++++++++++++++++++- rust/tests/low_level_il.rs | 85 +++- 7 files changed, 1053 insertions(+), 171 deletions(-) diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index da4c31153f..f43f9bd36b 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -2884,7 +2884,7 @@ impl FunctionRecognizer for RiscVELFPLTRecognizer { LowLevelILInstructionKind::SetReg(r) => match r.source_expr().kind() { LowLevelILExpressionKind::Load(l) => { let target_reg = r.dest_reg(); - let entry = match l.source_mem_expr().kind() { + let entry = match l.source_expr().kind() { LowLevelILExpressionKind::Reg(lr) if lr.source_reg() == auipc_dest => { plt_base } diff --git a/rust/src/low_level_il.rs b/rust/src/low_level_il.rs index 453e05469b..4c52e31301 100644 --- a/rust/src/low_level_il.rs +++ b/rust/src/low_level_il.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::borrow::Cow; use std::fmt; // TODO : provide some way to forbid emitting register reads for certain registers @@ -20,7 +21,7 @@ use std::fmt; // requirements on load/store memory address sizes? // can reg/set_reg be used with sizes that differ from what is in BNRegisterInfo? -use crate::architecture::{Architecture, RegisterId}; +use crate::architecture::{Architecture, Flag, RegisterId}; use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::function::Location; @@ -125,12 +126,19 @@ impl LowLevelILRegisterKind { LowLevelILRegisterKind::Temp(temp.into()) } - fn id(&self) -> RegisterId { + pub fn id(&self) -> RegisterId { match *self { LowLevelILRegisterKind::Arch(ref r) => r.id(), LowLevelILRegisterKind::Temp(temp) => temp.id(), } } + + pub fn name(&self) -> Cow { + match *self { + LowLevelILRegisterKind::Arch(ref r) => r.name(), + LowLevelILRegisterKind::Temp(temp) => Cow::Owned(format!("temp{}", temp.temp_id)), + } + } } impl fmt::Debug for LowLevelILRegisterKind { @@ -149,19 +157,51 @@ impl From for LowLevelILRegisterKind { } #[derive(Copy, Clone, Debug)] -pub enum LowLevelILSSARegister { - Full(LowLevelILRegisterKind, u32), // no such thing as partial access to a temp register, I think - Partial(R, u32, R), // partial accesses only possible for arch registers, I think +pub enum LowLevelILSSARegisterKind { + Full { + kind: LowLevelILRegisterKind, + version: u32, + }, + Partial { + full_reg: CoreRegister, + partial_reg: CoreRegister, + version: u32, + }, } -impl LowLevelILSSARegister { +impl LowLevelILSSARegisterKind { + pub fn new_full(kind: LowLevelILRegisterKind, version: u32) -> Self { + Self::Full { kind, version } + } + + pub fn new_partial(full_reg: CoreRegister, partial_reg: CoreRegister, version: u32) -> Self { + Self::Partial { + full_reg, + partial_reg, + version, + } + } + pub fn version(&self) -> u32 { match *self { - LowLevelILSSARegister::Full(_, ver) | LowLevelILSSARegister::Partial(_, ver, _) => ver, + LowLevelILSSARegisterKind::Full { version, .. } + | LowLevelILSSARegisterKind::Partial { version, .. } => version, } } } +#[derive(Copy, Clone, Debug)] +pub struct LowLevelILSSAFlag { + pub flag: F, + pub version: u32, +} + +impl LowLevelILSSAFlag { + pub fn new(flag: F, version: u32) -> Self { + Self { flag, version } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum VisitorAction { Descend, diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 6addb7e10f..73bec38d8a 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -99,8 +99,7 @@ where { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; - // SAFETY: This is safe we are not exposing the expression kind to the caller. - let kind = unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }; + let kind = LowLevelILExpressionKind::from_raw(self.function, op, self.index); kind.fmt(f) } } @@ -117,7 +116,7 @@ where match op.operation { // Any invalid ops for SSA will be checked here. // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -149,7 +148,7 @@ where match op.operation { // Any invalid ops for Lifted IL will be checked here. // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -181,7 +180,7 @@ where LLIL_FLAG_COND => unreachable!("LLIL_FLAG_COND is only valid in Lifted IL"), LLIL_FLAG_GROUP => unreachable!("LLIL_FLAG_GROUP is only valid in Lifted IL"), // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -216,9 +215,13 @@ where F: FunctionForm, { Load(Operation<'func, M, F, operation::Load>), + LoadSsa(Operation<'func, M, F, operation::LoadSsa>), Pop(Operation<'func, M, F, operation::Pop>), Reg(Operation<'func, M, F, operation::Reg>), + RegSsa(Operation<'func, M, F, operation::RegSsa>), + RegPartialSsa(Operation<'func, M, F, operation::RegPartialSsa>), RegSplit(Operation<'func, M, F, operation::RegSplit>), + RegSplitSsa(Operation<'func, M, F, operation::RegSplitSsa>), Const(Operation<'func, M, F, operation::Const>), ConstPtr(Operation<'func, M, F, operation::Const>), Flag(Operation<'func, M, F, operation::Flag>), @@ -227,6 +230,10 @@ where RegStackPop(Operation<'func, M, F, operation::RegStackPop>), + CallOutputSsa(Operation<'func, M, F, operation::CallOutputSsa>), + CallParamSsa(Operation<'func, M, F, operation::CallParamSsa>), + CallStackSsa(Operation<'func, M, F, operation::CallStackSsa>), + Add(Operation<'func, M, F, operation::BinaryOp>), Adc(Operation<'func, M, F, operation::BinaryOpCarry>), Sub(Operation<'func, M, F, operation::BinaryOp>), @@ -319,116 +326,146 @@ where M: FunctionMutability, F: FunctionForm, { - // TODO: Document what "unchecked" means and how to consume this safely. - pub(crate) unsafe fn from_raw( + pub(crate) fn from_raw( function: &'func LowLevelILFunction, op: BNLowLevelILInstruction, + index: LowLevelExpressionIndex, ) -> Self { use binaryninjacore_sys::BNLowLevelILOperation::*; match op.operation { - LLIL_LOAD | LLIL_LOAD_SSA => { - LowLevelILExpressionKind::Load(Operation::new(function, op)) + LLIL_LOAD => LowLevelILExpressionKind::Load(Operation::new(function, op, index)), + LLIL_LOAD_SSA => LowLevelILExpressionKind::LoadSsa(Operation::new(function, op, index)), + LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op, index)), + LLIL_REG => LowLevelILExpressionKind::Reg(Operation::new(function, op, index)), + LLIL_REG_SSA => LowLevelILExpressionKind::RegSsa(Operation::new(function, op, index)), + LLIL_REG_SSA_PARTIAL => { + LowLevelILExpressionKind::RegPartialSsa(Operation::new(function, op, index)) } - LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op)), - LLIL_REG | LLIL_REG_SSA | LLIL_REG_SSA_PARTIAL => { - LowLevelILExpressionKind::Reg(Operation::new(function, op)) + LLIL_REG_SPLIT => { + LowLevelILExpressionKind::RegSplit(Operation::new(function, op, index)) } - LLIL_REG_SPLIT | LLIL_REG_SPLIT_SSA => { - LowLevelILExpressionKind::RegSplit(Operation::new(function, op)) + LLIL_REG_SPLIT_SSA => { + LowLevelILExpressionKind::RegSplitSsa(Operation::new(function, op, index)) + } + LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op, index)), + LLIL_CONST_PTR => { + LowLevelILExpressionKind::ConstPtr(Operation::new(function, op, index)) } - LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op)), - LLIL_CONST_PTR => LowLevelILExpressionKind::ConstPtr(Operation::new(function, op)), LLIL_FLAG | LLIL_FLAG_SSA => { - LowLevelILExpressionKind::Flag(Operation::new(function, op)) + LowLevelILExpressionKind::Flag(Operation::new(function, op, index)) } LLIL_FLAG_BIT | LLIL_FLAG_BIT_SSA => { - LowLevelILExpressionKind::FlagBit(Operation::new(function, op)) + LowLevelILExpressionKind::FlagBit(Operation::new(function, op, index)) + } + LLIL_EXTERN_PTR => { + LowLevelILExpressionKind::ExternPtr(Operation::new(function, op, index)) } - LLIL_EXTERN_PTR => LowLevelILExpressionKind::ExternPtr(Operation::new(function, op)), LLIL_REG_STACK_POP => { - LowLevelILExpressionKind::RegStackPop(Operation::new(function, op)) - } - - LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op)), - LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op)), - LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op)), - LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op)), - LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op)), - LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op)), - LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op)), - LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op)), - LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op)), - LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op)), - LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op)), - LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op)), - LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op)), - LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op)), - LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op)), - - LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op)), - LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op)), - - LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op)), - LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op)), - - LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op)), - LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op)), - - LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op)), - LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op)), - - LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op)), - LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op)), - - LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op)), - LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op)), - - LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op)), - LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op)), - LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op)), - - LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op)), - LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op)), - LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op)), - LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op)), - LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op)), - LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op)), - LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op)), - LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op)), - LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op)), - LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op)), - - LLIL_BOOL_TO_INT => LowLevelILExpressionKind::BoolToInt(Operation::new(function, op)), - - LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op)), - LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op)), - LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op)), - LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op)), - - LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op)), - LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op)), - LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op)), - LLIL_FLOAT_TO_INT => LowLevelILExpressionKind::FloatToInt(Operation::new(function, op)), - LLIL_INT_TO_FLOAT => LowLevelILExpressionKind::IntToFloat(Operation::new(function, op)), - LLIL_FLOAT_CONV => LowLevelILExpressionKind::FloatConv(Operation::new(function, op)), - LLIL_ROUND_TO_INT => LowLevelILExpressionKind::RoundToInt(Operation::new(function, op)), - LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op)), - LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op)), - LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op)), - - LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op)), - LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op)), - LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op)), - LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op)), - LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op)), - LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op)), - LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op)), - LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op)), - - LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op)), - LLIL_UNIMPL_MEM => LowLevelILExpressionKind::UnimplMem(Operation::new(function, op)), + LowLevelILExpressionKind::RegStackPop(Operation::new(function, op, index)) + } + + LLIL_CALL_OUTPUT_SSA => { + LowLevelILExpressionKind::CallOutputSsa(Operation::new(function, op, index)) + } + LLIL_CALL_PARAM => { + LowLevelILExpressionKind::CallParamSsa(Operation::new(function, op, index)) + } + LLIL_CALL_STACK_SSA => { + LowLevelILExpressionKind::CallStackSsa(Operation::new(function, op, index)) + } + + LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op, index)), + LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op, index)), + LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op, index)), + LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op, index)), + LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op, index)), + LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op, index)), + LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op, index)), + LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op, index)), + LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op, index)), + LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op, index)), + LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op, index)), + LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op, index)), + LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op, index)), + LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op, index)), + LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op, index)), + + LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op, index)), + LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op, index)), + + LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op, index)), + LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op, index)), + + LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op, index)), + LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op, index)), + + LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op, index)), + LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op, index)), + + LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op, index)), + LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op, index)), + + LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op, index)), + LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op, index)), + + LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op, index)), + LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op, index)), + LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op, index)), + + LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op, index)), + LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op, index)), + LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op, index)), + LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op, index)), + LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op, index)), + LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op, index)), + LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op, index)), + LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op, index)), + LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op, index)), + LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op, index)), + + LLIL_BOOL_TO_INT => { + LowLevelILExpressionKind::BoolToInt(Operation::new(function, op, index)) + } + + LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op, index)), + LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op, index)), + LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op, index)), + LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op, index)), + + LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op, index)), + LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op, index)), + LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op, index)), + LLIL_FLOAT_TO_INT => { + LowLevelILExpressionKind::FloatToInt(Operation::new(function, op, index)) + } + LLIL_INT_TO_FLOAT => { + LowLevelILExpressionKind::IntToFloat(Operation::new(function, op, index)) + } + LLIL_FLOAT_CONV => { + LowLevelILExpressionKind::FloatConv(Operation::new(function, op, index)) + } + LLIL_ROUND_TO_INT => { + LowLevelILExpressionKind::RoundToInt(Operation::new(function, op, index)) + } + LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op, index)), + LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op, index)), + LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op, index)), + + LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op, index)), + LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op, index)), + LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op, index)), + LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op, index)), + LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op, index)), + LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op, index)), + LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op, index)), + LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op, index)), + + LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op, index)), + LLIL_UNIMPL_MEM => { + LowLevelILExpressionKind::UnimplMem(Operation::new(function, op, index)) + } // TODO TEST_BIT ADD_OVERFLOW LLIL_REG_STACK_PUSH LLIL_REG_STACK_POP _ => { @@ -439,7 +476,7 @@ where op.address ); - LowLevelILExpressionKind::Undef(Operation::new(function, op)) + LowLevelILExpressionKind::Undef(Operation::new(function, op, index)) } } } @@ -585,12 +622,21 @@ where visit!(op.mem_expr()); } Load(ref op) => { - visit!(op.source_mem_expr()); + visit!(op.source_expr()); } - // Do not have any sub expressions. - Pop(_) | Reg(_) | RegSplit(_) | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) - | ExternPtr(_) | FlagCond(_) | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) => { + LoadSsa(ref op) => { + visit!(op.source_expr()); + } + CallParamSsa(ref op) => { + for param_expr in op.param_exprs() { + visit!(param_expr); + } } + // Do not have any sub expressions. + Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_) + | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_) + | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | CallOutputSsa(_) + | CallStackSsa(_) => {} } VisitorAction::Sibling @@ -614,12 +660,20 @@ where Load(ref op) => &op.op, + LoadSsa(ref op) => &op.op, + Pop(ref op) => &op.op, Reg(ref op) => &op.op, + RegSsa(ref op) => &op.op, + + RegPartialSsa(ref op) => &op.op, + RegSplit(ref op) => &op.op, + RegSplitSsa(ref op) => &op.op, + Flag(ref op) => &op.op, FlagBit(ref op) => &op.op, @@ -630,6 +684,10 @@ where RegStackPop(ref op) => &op.op, + CallOutputSsa(ref op) => &op.op, + CallParamSsa(ref op) => &op.op, + CallStackSsa(ref op) => &op.op, + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op, Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) @@ -670,12 +728,20 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { Load(ref op) => op.flag_write(), + LoadSsa(ref op) => op.flag_write(), + Pop(ref op) => op.flag_write(), Reg(ref op) => op.flag_write(), + RegSsa(ref op) => op.flag_write(), + + RegPartialSsa(ref op) => op.flag_write(), + RegSplit(ref op) => op.flag_write(), + RegSplitSsa(ref op) => op.flag_write(), + Flag(ref op) => op.flag_write(), FlagBit(ref op) => op.flag_write(), @@ -686,6 +752,10 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { RegStackPop(ref op) => op.flag_write(), + CallOutputSsa(ref op) => op.flag_write(), + CallParamSsa(ref op) => op.flag_write(), + CallStackSsa(ref op) => op.flag_write(), + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(), Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 21eebc3cc7..62811b1dfd 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -12,15 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use binaryninjacore_sys::BNFreeLowLevelILFunction; -use binaryninjacore_sys::BNGetLowLevelILOwnerFunction; -use binaryninjacore_sys::BNLowLevelILFunction; -use binaryninjacore_sys::BNNewLowLevelILFunctionReference; - use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use binaryninjacore_sys::*; + use crate::architecture::CoreArchitecture; use crate::basic_block::BasicBlock; use crate::function::Function; @@ -160,13 +157,8 @@ where Function::ref_from_raw(func) } } -} -// LLIL basic blocks are not available until the function object -// is finalized, so ensure we can't try requesting basic blocks -// during lifting -impl LowLevelILFunction { - pub fn basic_blocks(&self) -> Array>> { + pub fn basic_blocks(&self) -> Array>> { use binaryninjacore_sys::BNGetLowLevelILBasicBlockList; unsafe { @@ -178,6 +170,17 @@ impl LowLevelILFunction { } } +impl LowLevelILFunction> { + /// Retrieve the SSA form of the function. + pub fn ssa_form(&self) -> Option>> { + let handle = unsafe { BNGetLowLevelILSSAForm(self.handle) }; + if handle.is_null() { + return None; + } + Some(unsafe { LowLevelILFunction::ref_from_raw(handle) }) + } +} + // Allow instantiating Lifted IL functions for querying Lifted IL from Architectures impl LowLevelILFunction> { // TODO: Document what happens when you pass None for `source_func`. @@ -201,7 +204,6 @@ impl LowLevelILFunction> { pub fn generate_ssa_form(&self) { use binaryninjacore_sys::BNGenerateLowLevelILSSAForm; - unsafe { BNGenerateLowLevelILSSAForm(self.handle) }; } } diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index ded9c6f3e0..90d2f1d89f 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -207,9 +207,14 @@ where { Nop(Operation<'func, M, F, operation::NoArgs>), SetReg(Operation<'func, M, F, operation::SetReg>), + SetRegSsa(Operation<'func, M, F, operation::SetRegSsa>), + SetRegPartialSsa(Operation<'func, M, F, operation::SetRegPartialSsa>), SetRegSplit(Operation<'func, M, F, operation::SetRegSplit>), + SetRegSplitSsa(Operation<'func, M, F, operation::SetRegSplitSsa>), SetFlag(Operation<'func, M, F, operation::SetFlag>), + SetFlagSsa(Operation<'func, M, F, operation::SetFlagSsa>), Store(Operation<'func, M, F, operation::Store>), + StoreSsa(Operation<'func, M, F, operation::StoreSsa>), // TODO needs a real op Push(Operation<'func, M, F, operation::UnaryOp>), @@ -219,7 +224,9 @@ where JumpTo(Operation<'func, M, F, operation::JumpTo>), Call(Operation<'func, M, F, operation::Call>), + CallSsa(Operation<'func, M, F, operation::CallSsa>), TailCall(Operation<'func, M, F, operation::Call>), + TailCallSsa(Operation<'func, M, F, operation::CallSsa>), Ret(Operation<'func, M, F, operation::Ret>), NoRet(Operation<'func, M, F, operation::NoArgs>), @@ -228,6 +235,7 @@ where Goto(Operation<'func, M, F, operation::Goto>), Syscall(Operation<'func, M, F, operation::Syscall>), + SyscallSsa(Operation<'func, M, F, operation::SyscallSsa>), Intrinsic(Operation<'func, M, F, operation::Intrinsic>), Bp(Operation<'func, M, F, operation::NoArgs>), Trap(Operation<'func, M, F, operation::Trap>), @@ -250,50 +258,80 @@ where use binaryninjacore_sys::BNLowLevelILOperation::*; match op.operation { - LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op)), - LLIL_SET_REG | LLIL_SET_REG_SSA => { - LowLevelILInstructionKind::SetReg(Operation::new(function, op)) + LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op, expr_index)), + LLIL_SET_REG => { + LowLevelILInstructionKind::SetReg(Operation::new(function, op, expr_index)) } - LLIL_SET_REG_SPLIT | LLIL_SET_REG_SPLIT_SSA => { - LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op)) + LLIL_SET_REG_SSA => { + LowLevelILInstructionKind::SetRegSsa(Operation::new(function, op, expr_index)) } - LLIL_SET_FLAG | LLIL_SET_FLAG_SSA => { - LowLevelILInstructionKind::SetFlag(Operation::new(function, op)) + LLIL_SET_REG_SSA_PARTIAL => LowLevelILInstructionKind::SetRegPartialSsa( + Operation::new(function, op, expr_index), + ), + LLIL_SET_REG_SPLIT => { + LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op, expr_index)) } - LLIL_STORE | LLIL_STORE_SSA => { - LowLevelILInstructionKind::Store(Operation::new(function, op)) + LLIL_SET_REG_SPLIT_SSA => { + LowLevelILInstructionKind::SetRegSplitSsa(Operation::new(function, op, expr_index)) } - LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op)), + LLIL_SET_FLAG => { + LowLevelILInstructionKind::SetFlag(Operation::new(function, op, expr_index)) + } + LLIL_SET_FLAG_SSA => { + LowLevelILInstructionKind::SetFlagSsa(Operation::new(function, op, expr_index)) + } + LLIL_STORE => { + LowLevelILInstructionKind::Store(Operation::new(function, op, expr_index)) + } + LLIL_STORE_SSA => { + LowLevelILInstructionKind::StoreSsa(Operation::new(function, op, expr_index)) + } + LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op, expr_index)), LLIL_REG_STACK_PUSH => { - LowLevelILInstructionKind::RegStackPush(Operation::new(function, op)) + LowLevelILInstructionKind::RegStackPush(Operation::new(function, op, expr_index)) } - LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op)), - LLIL_JUMP_TO => LowLevelILInstructionKind::JumpTo(Operation::new(function, op)), + LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op, expr_index)), + LLIL_JUMP_TO => { + LowLevelILInstructionKind::JumpTo(Operation::new(function, op, expr_index)) + } - LLIL_CALL | LLIL_CALL_STACK_ADJUST | LLIL_CALL_SSA => { - LowLevelILInstructionKind::Call(Operation::new(function, op)) + LLIL_CALL | LLIL_CALL_STACK_ADJUST => { + LowLevelILInstructionKind::Call(Operation::new(function, op, expr_index)) + } + LLIL_CALL_SSA => { + LowLevelILInstructionKind::CallSsa(Operation::new(function, op, expr_index)) + } + LLIL_TAILCALL => { + LowLevelILInstructionKind::TailCall(Operation::new(function, op, expr_index)) } - LLIL_TAILCALL | LLIL_TAILCALL_SSA => { - LowLevelILInstructionKind::TailCall(Operation::new(function, op)) + LLIL_TAILCALL_SSA => { + LowLevelILInstructionKind::TailCallSsa(Operation::new(function, op, expr_index)) } - LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op)), - LLIL_NORET => LowLevelILInstructionKind::NoRet(Operation::new(function, op)), + LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op, expr_index)), + LLIL_NORET => { + LowLevelILInstructionKind::NoRet(Operation::new(function, op, expr_index)) + } - LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op)), - LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op)), + LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op, expr_index)), + LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op, expr_index)), - LLIL_SYSCALL | LLIL_SYSCALL_SSA => { - LowLevelILInstructionKind::Syscall(Operation::new(function, op)) + LLIL_SYSCALL => { + LowLevelILInstructionKind::Syscall(Operation::new(function, op, expr_index)) + } + LLIL_SYSCALL_SSA => { + LowLevelILInstructionKind::SyscallSsa(Operation::new(function, op, expr_index)) } LLIL_INTRINSIC | LLIL_INTRINSIC_SSA => { - LowLevelILInstructionKind::Intrinsic(Operation::new(function, op)) + LowLevelILInstructionKind::Intrinsic(Operation::new(function, op, expr_index)) + } + LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op, expr_index)), + LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op, expr_index)), + LLIL_UNDEF => { + LowLevelILInstructionKind::Undef(Operation::new(function, op, expr_index)) } - LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op)), - LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op)), - LLIL_UNDEF => LowLevelILInstructionKind::Undef(Operation::new(function, op)), _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)), } } @@ -314,17 +352,31 @@ where match self { SetReg(ref op) => visit!(&op.source_expr()), + SetRegSsa(ref op) => visit!(&op.source_expr()), + SetRegPartialSsa(ref op) => visit!(&op.source_expr()), SetRegSplit(ref op) => visit!(&op.source_expr()), + SetRegSplitSsa(ref op) => visit!(&op.source_expr()), SetFlag(ref op) => visit!(&op.source_expr()), + SetFlagSsa(ref op) => visit!(&op.source_expr()), Store(ref op) => { - visit!(&op.dest_mem_expr()); + visit!(&op.dest_expr()); + visit!(&op.source_expr()); + } + StoreSsa(ref op) => { + visit!(&op.dest_expr()); visit!(&op.source_expr()); } Push(ref op) => visit!(&op.operand()), RegStackPush(ref op) => visit!(&op.source_expr()), Jump(ref op) => visit!(&op.target()), JumpTo(ref op) => visit!(&op.target()), + SyscallSsa(ref op) => { + visit!(&op.output_expr()); + visit!(&op.param_expr()); + visit!(&op.stack_expr()); + } Call(ref op) | TailCall(ref op) => visit!(&op.target()), + CallSsa(ref op) | TailCallSsa(ref op) => visit!(&op.target()), Ret(ref op) => visit!(&op.target()), If(ref op) => visit!(&op.condition()), Intrinsic(ref _op) => { diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index bd68bbb14d..7f31f62bfe 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use binaryninjacore_sys::{BNGetLowLevelILByIndex, BNLowLevelILInstruction}; +use binaryninjacore_sys::{ + BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList, BNLowLevelILGetOperandList, + BNLowLevelILInstruction, +}; use super::*; use crate::architecture::{ @@ -32,6 +35,7 @@ where { pub(crate) function: &'func LowLevelILFunction, pub(crate) op: BNLowLevelILInstruction, + pub(crate) expr_idx: LowLevelExpressionIndex, _args: PhantomData, } @@ -44,10 +48,12 @@ where pub(crate) fn new( function: &'func LowLevelILFunction, op: BNLowLevelILInstruction, + expr_idx: LowLevelExpressionIndex, ) -> Self { Self { function, op, + expr_idx, _args: PhantomData, } } @@ -55,6 +61,22 @@ where pub fn address(&self) -> u64 { self.op.address } + + pub fn get_operand_list(&self, operand_idx: usize) -> Vec { + let mut count = 0; + let raw_list_ptr = unsafe { + BNLowLevelILGetOperandList( + self.function.handle, + self.expr_idx.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNLowLevelILFreeOperandList(raw_list_ptr) }; + list + } } impl Operation<'_, M, NonSSA, O> @@ -109,7 +131,7 @@ where } } -// LLIL_SYSCALL, LLIL_SYSCALL_SSA +// LLIL_SYSCALL pub struct Syscall; impl Debug for Operation<'_, M, F, Syscall> @@ -122,6 +144,59 @@ where } } +// LLIL_SYSCALL_SSA +pub struct SyscallSsa; + +impl<'func, M, F> Operation<'func, M, F, SyscallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + /// Get the output expression of the call. + /// + /// NOTE: This is currently always [`CallOutputSsa`]. + pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Get the parameter expression of the call. + /// + /// NOTE: This is currently always [`CallParamSsa`]. + pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } + + /// Get the stack expression of the call. + /// + /// NOTE: This is currently always [`CallStackSsa`]. + pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, SyscallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SyscallSsa") + .field("output_expr", &self.output_expr()) + .field("param_expr", &self.param_expr()) + .field("stack_expr", &self.stack_expr()) + .finish() + } +} + // LLIL_INTRINSIC, LLIL_INTRINSIC_SSA pub struct Intrinsic; @@ -150,7 +225,7 @@ where } } -// LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA +// LLIL_SET_REG pub struct SetReg; impl<'func, M, F> Operation<'func, M, F, SetReg> @@ -190,7 +265,96 @@ where } } -// LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA +// LLIL_SET_REG_SSA +pub struct SetRegSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, SetRegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_REG_PARTIAL_SSA +pub struct SetRegPartialSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind { + let full_raw_id = RegisterId(self.op.operands[0] as u32); + let version = self.op.operands[1] as u32; + let partial_raw_id = RegisterId(self.op.operands[2] as u32); + let full_reg = + CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID"); + let partial_reg = + CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, SetRegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegPartialSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_REG_SPLIT pub struct SetRegSplit; impl<'func, M, F> Operation<'func, M, F, SetRegSplit> @@ -236,7 +400,63 @@ where } } -// LLIL_SET_FLAG, LLIL_SET_FLAG_SSA +// LLIL_SET_REG_SPLIT_SSA +pub struct SetRegSplitSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + /// Because of the fixed operand list size we use another expression for the dest high register. + /// + /// NOTE: This should always be an expression of [`RegSsa`]. + pub fn dest_expr_high(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Because of the fixed operand list size we use another expression for the dest low register. + /// + /// NOTE: This should always be an expression of [`RegSsa`]. + pub fn dest_expr_low(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, SetRegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegSplitSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_expr_high", &self.dest_expr_high()) + .field("dest_expr_low", &self.dest_expr_low()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_FLAG pub struct SetFlag; impl<'func, M, F> Operation<'func, M, F, SetFlag> @@ -245,12 +465,10 @@ where F: FunctionForm, { pub fn dest_flag(&self) -> CoreFlag { - // TODO: Error handling? - // TODO: Test this. self.function .arch() .flag_from_id(FlagId(self.op.operands[0] as u32)) - .unwrap() + .expect("Bad flag ID") } pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { @@ -275,7 +493,46 @@ where } } -// LLIL_LOAD, LLIL_LOAD_SSA +// LLIL_SET_FLAG_SSA +pub struct SetFlagSsa; + +impl<'func, M, F> Operation<'func, M, F, SetFlagSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_flag(&self) -> LowLevelILSSAFlag { + let flag = self + .function + .arch() + .flag_from_id(FlagId(self.op.operands[0] as u32)) + .expect("Bad flag ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSAFlag::new(flag, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, SetFlagSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetFlagSsa") + .field("address", &self.address()) + .field("dest_flag", &self.dest_flag()) + .field("source_expr", &self.source_expr()) + .finish() + } +} +// LLIL_LOAD pub struct Load; impl<'func, M, F> Operation<'func, M, F, Load> @@ -287,7 +544,7 @@ where self.op.size } - pub fn source_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -304,12 +561,50 @@ where f.debug_struct("Load") .field("address", &self.address()) .field("size", &self.size()) - .field("source_mem_expr", &self.source_mem_expr()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_LOAD_SSA +pub struct LoadSsa; + +impl<'func, M, F> Operation<'func, M, F, LoadSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + pub fn source_memory_version(&self) -> u64 { + self.op.operands[1] + } +} + +impl Debug for Operation<'_, M, F, LoadSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("LoadSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_expr", &self.source_expr()) .finish() } } -// LLIL_STORE, LLIL_STORE_SSA +// LLIL_STORE pub struct Store; impl<'func, M, F> Operation<'func, M, F, Store> @@ -321,7 +616,7 @@ where self.op.size } - pub fn dest_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -345,13 +640,63 @@ where f.debug_struct("Store") .field("address", &self.address()) .field("size", &self.size()) - .field("dest_mem_expr", &self.dest_mem_expr()) + .field("dest_expr", &self.dest_expr()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_STORE_SSA +pub struct StoreSsa; + +impl<'func, M, F> Operation<'func, M, F, StoreSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + pub fn dest_memory_version(&self) -> u64 { + self.op.operands[1] + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } + + pub fn source_memory_version(&self) -> u64 { + self.op.operands[2] + } +} + +impl Debug for Operation<'_, M, F, StoreSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("StoreSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_expr", &self.dest_expr()) .field("source_expr", &self.source_expr()) .finish() } } -// LLIL_REG, LLIL_REG_SSLLIL_REG_SSA_PARTIAL +// LLIL_REG pub struct Reg; impl Operation<'_, M, F, Reg> @@ -383,7 +728,80 @@ where } } -// LLIL_REG_SPLIT, LLIL_REG_SPLIT_SSA +// LLIL_REG_SSA +pub struct RegSsa; + +impl Operation<'_, M, F, RegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl Debug for Operation<'_, M, F, RegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .finish() + } +} + +// LLIL_REG_SSA_PARTIAL +pub struct RegPartialSsa; + +impl Operation<'_, M, F, RegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind { + let full_raw_id = RegisterId(self.op.operands[0] as u32); + let version = self.op.operands[1] as u32; + let partial_raw_id = RegisterId(self.op.operands[2] as u32); + let full_reg = + CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID"); + let partial_reg = + CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version) + } +} + +impl Debug for Operation<'_, M, F, RegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegPartialSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .finish() + } +} + +// LLIL_REG_SPLIT pub struct RegSplit; impl Operation<'_, M, F, RegSplit> @@ -421,6 +839,50 @@ where } } +// LLIL_REG_SPLIT_SSA +pub struct RegSplitSsa; + +impl Operation<'_, M, F, RegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn low_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn high_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[2] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[3] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl Debug for Operation<'_, M, F, RegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegSplitSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("low_reg", &self.low_reg()) + .field("high_reg", &self.high_reg()) + .finish() + } +} + // LLIL_REG_STACK_PUSH pub struct RegStackPush; @@ -630,7 +1092,7 @@ where } } -// LLIL_CALL, LLIL_CALL_SSA +// LLIL_CALL, LLIL_CALL_STACK_ADJUST pub struct Call; impl<'func, M, F> Operation<'func, M, F, Call> @@ -669,6 +1131,165 @@ where } } +// LLIL_CALL_SSA +pub struct CallSsa; + +impl<'func, M, F> Operation<'func, M, F, CallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } + + /// Get the output expression of the call. + /// + /// NOTE: This is currently always [`CallOutputSsa`]. + pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Get the parameter expression of the call. + /// + /// NOTE: This is currently always [`CallParamSsa`]. + pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } + + /// Get the stack expression of the call. + /// + /// NOTE: This is currently always [`CallStackSsa`]. + pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl Debug for Operation<'_, M, F, CallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallSsa") + .field("target", &self.target()) + .field("output_expr", &self.output_expr()) + .field("param_expr", &self.param_expr()) + .field("stack_expr", &self.stack_expr()) + .finish() + } +} + +// LLIL_CALL_OUTPUT_SSA +pub struct CallOutputSsa; + +impl Operation<'_, M, F, CallOutputSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_regs(&self) -> Vec> { + let operand_list = self.get_operand_list(1); + + // The operand list contains a list of ([0: reg, 1: version], ...). + let paired_ssa_reg = |paired: &[u64]| { + let raw_id = RegisterId(paired[0] as u32); + let version = paired[1] as u32; + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + LowLevelILSSARegisterKind::new_full(reg_kind, version) + }; + + operand_list.chunks_exact(2).map(paired_ssa_reg).collect() + } + + pub fn dest_memory_version(&self) -> u64 { + self.op.operands[0] + } +} + +impl Debug for Operation<'_, M, F, CallOutputSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallOutputSsa") + .field("dest_regs", &self.dest_regs()) + .finish() + } +} + +// LLIL_CALL_PARAM_SSA +pub struct CallParamSsa; + +impl<'func, M, F> Operation<'func, M, F, CallParamSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn param_exprs(&self) -> Vec> { + self.get_operand_list(0) + .into_iter() + .map(|val| LowLevelExpressionIndex(val as usize)) + .map(|expr_idx| LowLevelILExpression::new(self.function, expr_idx)) + .collect() + } +} + +impl Debug for Operation<'_, M, F, CallParamSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallParamSsa") + .field("param_exprs", &self.param_exprs()) + .finish() + } +} + +// LLIL_CALL_STACK_SSA +pub struct CallStackSsa; + +impl Operation<'_, M, F, CallStackSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn source_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl Debug for Operation<'_, M, F, CallStackSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallStackSsa") + .field("source_reg", &self.source_reg()) + .finish() + } +} + // LLIL_RET pub struct Ret; @@ -1256,14 +1877,24 @@ pub trait OperationArguments: 'static {} impl OperationArguments for NoArgs {} impl OperationArguments for Pop {} impl OperationArguments for Syscall {} +impl OperationArguments for SyscallSsa {} impl OperationArguments for Intrinsic {} impl OperationArguments for SetReg {} +impl OperationArguments for SetRegSsa {} +impl OperationArguments for SetRegPartialSsa {} impl OperationArguments for SetRegSplit {} +impl OperationArguments for SetRegSplitSsa {} impl OperationArguments for SetFlag {} +impl OperationArguments for SetFlagSsa {} impl OperationArguments for Load {} +impl OperationArguments for LoadSsa {} impl OperationArguments for Store {} +impl OperationArguments for StoreSsa {} impl OperationArguments for Reg {} +impl OperationArguments for RegSsa {} +impl OperationArguments for RegPartialSsa {} impl OperationArguments for RegSplit {} +impl OperationArguments for RegSplitSsa {} impl OperationArguments for RegStackPush {} impl OperationArguments for RegStackPop {} impl OperationArguments for Flag {} @@ -1271,6 +1902,10 @@ impl OperationArguments for FlagBit {} impl OperationArguments for Jump {} impl OperationArguments for JumpTo {} impl OperationArguments for Call {} +impl OperationArguments for CallSsa {} +impl OperationArguments for CallOutputSsa {} +impl OperationArguments for CallParamSsa {} +impl OperationArguments for CallStackSsa {} impl OperationArguments for Ret {} impl OperationArguments for If {} impl OperationArguments for Goto {} diff --git a/rust/tests/low_level_il.rs b/rust/tests/low_level_il.rs index 88d915dc48..db8cc54974 100644 --- a/rust/tests/low_level_il.rs +++ b/rust/tests/low_level_il.rs @@ -7,7 +7,7 @@ use binaryninja::low_level_il::expression::{ use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstructionKind, LowLevelInstructionIndex, }; -use binaryninja::low_level_il::{LowLevelILRegisterKind, VisitorAction}; +use binaryninja::low_level_il::{LowLevelILRegisterKind, LowLevelILSSARegisterKind, VisitorAction}; use std::path::PathBuf; #[test] @@ -225,3 +225,86 @@ fn test_llil_visitor() { }; } } + +#[test] +fn test_llil_ssa() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + let image_base = view.original_image_base(); + let platform = view.default_platform().unwrap(); + + // Sample function: __crt_strtox::c_string_character_source::validate + let sample_function = view.function_at(&platform, image_base + 0x2bd80).unwrap(); + let llil_function = sample_function.low_level_il().unwrap(); + let llil_ssa_function = llil_function.ssa_form().expect("Valid SSA form"); + + let llil_ssa_basic_blocks = llil_ssa_function.basic_blocks(); + let mut llil_ssa_basic_block_iter = llil_ssa_basic_blocks.iter(); + let first_basic_block = llil_ssa_basic_block_iter.next().unwrap(); + let mut llil_instr_iter = first_basic_block.iter(); + + // 0 @ 0002bd80 (LLIL_SET_REG_SSA.d edi#1 = (LLIL_REG_SSA.d edi#0)) + let ssa_instr_0 = llil_instr_iter.next().unwrap(); + assert_eq!(ssa_instr_0.index, LowLevelInstructionIndex(0)); + assert_eq!(ssa_instr_0.address(), image_base + 0x0002bd80); + println!("{:?}", ssa_instr_0); + println!("{:?}", ssa_instr_0.kind()); + match ssa_instr_0.kind() { + LowLevelILInstructionKind::SetRegSsa(op) => { + assert_eq!(op.size(), 4); + match op.dest_reg() { + LowLevelILSSARegisterKind::Full { kind, version } => { + assert_eq!(kind.name(), "edi"); + assert_eq!(version, 1); + } + _ => panic!("Expected LowLevelILSSARegisterKind::Full"), + } + assert_eq!(op.source_expr().index, LowLevelExpressionIndex(0)); + } + _ => panic!("Expected SetRegSsa"), + } + + // 1 @ 0002bd82 (LLIL_STORE_SSA.d [(LLIL_SUB.d (LLIL_REG_SSA.d esp#0) - (LLIL_CONST.d 4)) {__saved_ebp}].d = (LLIL_REG_SSA.d ebp#0) @ mem#0 -> mem#1) + let ssa_instr_1 = llil_instr_iter.next().unwrap(); + assert_eq!(ssa_instr_1.index, LowLevelInstructionIndex(1)); + assert_eq!(ssa_instr_1.address(), image_base + 0x0002bd82); + println!("{:?}", ssa_instr_1); + println!("{:?}", ssa_instr_1.kind()); + match ssa_instr_1.kind() { + LowLevelILInstructionKind::StoreSsa(op) => { + assert_eq!(op.size(), 4); + let source_expr = op.source_expr(); + let source_memory_version = op.source_memory_version(); + assert_eq!(source_memory_version, 0); + assert_eq!(source_expr.index, LowLevelExpressionIndex(5)); + let dest_expr = op.dest_expr(); + let dest_memory_version = op.dest_memory_version(); + assert_eq!(dest_memory_version, 1); + assert_eq!(dest_expr.index, LowLevelExpressionIndex(4)); + } + _ => panic!("Expected StoreSsa"), + } + + // 34 @ 0002bdc7 (LLIL_CALL_SSA eax#8, edx#5, ecx#6, mem#23 = call((LLIL_EXTERN_PTR.d __CrtDbgReportW), stack = esp#18 @ mem#22)) + let ssa_instr_34 = llil_ssa_function + .instruction_from_index(LowLevelInstructionIndex(34)) + .expect("Valid instruction"); + assert_eq!(ssa_instr_34.index, LowLevelInstructionIndex(34)); + assert_eq!(ssa_instr_34.address(), image_base + 0x0002bdc7); + println!("{:?}", ssa_instr_34); + println!("{:?}", ssa_instr_34.kind()); + match ssa_instr_34.kind() { + LowLevelILInstructionKind::CallSsa(op) => match op.target().kind() { + LowLevelILExpressionKind::ExternPtr(extern_ptr) => { + assert_eq!(extern_ptr.size(), 4); + let extern_sym = view + .symbol_by_address(extern_ptr.value()) + .expect("Valid symbol"); + assert_eq!(extern_sym.short_name(), "__CrtDbgReportW".into()) + } + _ => panic!("Expected ExternPtr"), + }, + _ => panic!("Expected CallSsa"), + } +} From 831e18e3888fbc72b8ef784ffb2fed3bf40c3ece Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Fri, 9 May 2025 14:01:25 -0400 Subject: [PATCH 29/54] [Rust] Remove unneeded mut from Architecture trait signatures These are never expressed, just adds another unneeded constraint on the impl --- arch/msp430/src/architecture.rs | 4 ++-- arch/riscv/src/lib.rs | 2 +- rust/src/architecture.rs | 32 ++++++++++++++++---------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index e5815c9198..0ef6e449c6 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -194,7 +194,7 @@ impl Architecture for Msp430 { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &MutableLiftedILFunction, ) -> Option<(usize, bool)> { match msp430_asm::decode(data) { Ok(inst) => { @@ -226,7 +226,7 @@ impl Architecture for Msp430 { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, + _il: &'a MutableLiftedILFunction, ) -> Option> { None } diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index f43f9bd36b..4e9e47834d 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -1062,7 +1062,7 @@ impl Architecture for RiscVArch { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &MutableLiftedILFunction, ) -> Option<(usize, bool)> { let max_width = self.default_integer_size(); diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index a48cbce36a..5ec63eefba 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -467,7 +467,7 @@ pub trait Architecture: 'static + Sized + AsRef { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &MutableLiftedILFunction, ) -> Option<(usize, bool)>; /// Fallback flag value calculation path. This method is invoked when the core is unable to @@ -484,7 +484,7 @@ pub trait Architecture: 'static + Sized + AsRef { flag: Self::Flag, flag_write_type: Self::FlagWrite, op: LowLevelILFlagWriteOp, - il: &'a mut MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, ) -> Option> { let role = flag.role(flag_write_type.class()); Some(get_default_flag_write_llil(self, role, op, il)) @@ -513,7 +513,7 @@ pub trait Architecture: 'static + Sized + AsRef { &self, cond: FlagCondition, class: Option, - il: &'a mut MutableLiftedILFunction, + il: &'a MutableLiftedILFunction, ) -> Option> { Some(get_default_flag_cond_llil(self, cond, class, il)) } @@ -535,7 +535,7 @@ pub trait Architecture: 'static + Sized + AsRef { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, + _il: &'a MutableLiftedILFunction, ) -> Option> { None } @@ -1512,7 +1512,7 @@ impl Architecture for CoreArchitecture { &self, data: &[u8], addr: u64, - il: &mut MutableLiftedILFunction, + il: &MutableLiftedILFunction, ) -> Option<(usize, bool)> { let mut size = data.len(); let success = unsafe { @@ -1537,7 +1537,7 @@ impl Architecture for CoreArchitecture { _flag: Self::Flag, _flag_write: Self::FlagWrite, _op: LowLevelILFlagWriteOp, - _il: &'a mut MutableLiftedILFunction, + _il: &'a MutableLiftedILFunction, ) -> Option> { None } @@ -1574,7 +1574,7 @@ impl Architecture for CoreArchitecture { &self, _cond: FlagCondition, _class: Option, - _il: &'a mut MutableLiftedILFunction, + _il: &'a MutableLiftedILFunction, ) -> Option> { None } @@ -1582,7 +1582,7 @@ impl Architecture for CoreArchitecture { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a mut MutableLiftedILFunction, + _il: &'a MutableLiftedILFunction, ) -> Option> { None } @@ -2223,10 +2223,10 @@ where { let custom_arch = unsafe { &*(ctxt as *mut A) }; let data = unsafe { std::slice::from_raw_parts(data, *len) }; - let mut lifter = + let lifter = unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; - match custom_arch.instruction_llil(data, addr, &mut lifter) { + match custom_arch.instruction_llil(data, addr, &lifter) { Some((res_len, res_value)) => { unsafe { *len = res_len }; res_value @@ -2610,12 +2610,12 @@ where let flag_write = custom_arch.flag_write_from_id(FlagWriteId(flag_write)); let flag = custom_arch.flag_from_id(FlagId(flag)); let operands = unsafe { std::slice::from_raw_parts(operands_raw, operand_count) }; - let mut lifter = + let lifter = unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; if let (Some(flag_write), Some(flag)) = (flag_write, flag) { if let Some(op) = LowLevelILFlagWriteOp::from_op(custom_arch, size, op, operands) { - if let Some(expr) = custom_arch.flag_write_llil(flag, flag_write, op, &mut lifter) { + if let Some(expr) = custom_arch.flag_write_llil(flag, flag_write, op, &lifter) { // TODO verify that returned expr is a bool value return expr.index.0; } @@ -2659,9 +2659,9 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; let class = custom_arch.flag_class_from_id(FlagClassId(class)); - let mut lifter = + let lifter = unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; - if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &mut lifter) { + if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &lifter) { // TODO verify that returned expr is a bool value return expr.index.0; } @@ -2678,11 +2678,11 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let mut lifter = + let lifter = unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) { - if let Some(expr) = custom_arch.flag_group_llil(group, &mut lifter) { + if let Some(expr) = custom_arch.flag_group_llil(group, &lifter) { // TODO verify that returned expr is a bool value return expr.index.0; } From aa02c662b64d35444b0b4fb08120c5b5001608ff Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Fri, 9 May 2025 14:01:54 -0400 Subject: [PATCH 30/54] [Rust] Add `CoreRegister` name to the `Debug` impl --- rust/src/architecture.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 5ec63eefba..211446d1ea 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -863,6 +863,7 @@ impl Debug for CoreRegister { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("CoreRegister") .field("id", &self.id) + .field("name", &self.name()) .finish() } } From 9d23cedec3c7c51e7ce586b7af9207e4bfb8b8e1 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 17:29:24 -0400 Subject: [PATCH 31/54] [Rust] Add Assert and ForceVersion LLIL operations --- rust/src/low_level_il/instruction.rs | 19 ++- rust/src/low_level_il/operation.rs | 170 ++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 4 deletions(-) diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index 90d2f1d89f..19b721af92 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -240,6 +240,10 @@ where Bp(Operation<'func, M, F, operation::NoArgs>), Trap(Operation<'func, M, F, operation::Trap>), Undef(Operation<'func, M, F, operation::NoArgs>), + Assert(Operation<'func, M, F, operation::Assert>), + AssertSsa(Operation<'func, M, F, operation::AssertSsa>), + ForceVersion(Operation<'func, M, F, operation::ForceVersion>), + ForceVersionSsa(Operation<'func, M, F, operation::ForceVersionSsa>), /// The instruction is an expression. Value(LowLevelILExpression<'func, M, F, ValueExpr>), @@ -332,6 +336,18 @@ where LLIL_UNDEF => { LowLevelILInstructionKind::Undef(Operation::new(function, op, expr_index)) } + LLIL_ASSERT => { + LowLevelILInstructionKind::Assert(Operation::new(function, op, expr_index)) + } + LLIL_ASSERT_SSA => { + LowLevelILInstructionKind::AssertSsa(Operation::new(function, op, expr_index)) + } + LLIL_FORCE_VER => { + LowLevelILInstructionKind::ForceVersion(Operation::new(function, op, expr_index)) + } + LLIL_FORCE_VER_SSA => { + LowLevelILInstructionKind::ForceVersionSsa(Operation::new(function, op, expr_index)) + } _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)), } } @@ -384,7 +400,8 @@ where } Value(e) => visit!(e), // Do not have any sub expressions. - Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) => {} + Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) | Assert(_) + | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) => {} } VisitorAction::Sibling diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 7f31f62bfe..f2ce9d1a05 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -13,8 +13,8 @@ // limitations under the License. use binaryninjacore_sys::{ - BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList, BNLowLevelILGetOperandList, - BNLowLevelILInstruction, + BNGetCachedLowLevelILPossibleValueSet, BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList, + BNLowLevelILGetOperandList, BNLowLevelILInstruction, }; use super::*; @@ -22,6 +22,7 @@ use crate::architecture::{ CoreFlag, CoreFlagGroup, CoreFlagWrite, CoreIntrinsic, CoreRegister, CoreRegisterStack, FlagGroupId, FlagId, FlagWriteId, IntrinsicId, RegisterStackId, }; +use crate::variable::PossibleValueSet; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; @@ -62,7 +63,7 @@ where self.op.address } - pub fn get_operand_list(&self, operand_idx: usize) -> Vec { + fn get_operand_list(&self, operand_idx: usize) -> Vec { let mut count = 0; let raw_list_ptr = unsafe { BNLowLevelILGetOperandList( @@ -77,6 +78,16 @@ where unsafe { BNLowLevelILFreeOperandList(raw_list_ptr) }; list } + + fn get_constraint(&self, operand_idx: usize) -> PossibleValueSet { + let raw_pvs = unsafe { + BNGetCachedLowLevelILPossibleValueSet( + self.function.handle, + self.op.operands[operand_idx] as usize, + ) + }; + PossibleValueSet::from_owned_raw(raw_pvs) + } } impl Operation<'_, M, NonSSA, O> @@ -1870,6 +1881,155 @@ where } } +// LLIL_ASSERT +pub struct Assert; + +impl Operation<'_, M, F, Assert> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") + } + + pub fn constraint(&self) -> PossibleValueSet { + self.get_constraint(1) + } +} + +impl Debug for Operation<'_, M, F, Assert> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Assert") + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .field("constraint", &self.constraint()) + .finish() + } +} + +// LLIL_ASSERT_SSA +pub struct AssertSsa; + +impl Operation<'_, M, F, AssertSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn constraint(&self) -> PossibleValueSet { + self.get_constraint(2) + } +} + +impl Debug for Operation<'_, M, F, AssertSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("AssertSsa") + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .field("constraint", &self.constraint()) + .finish() + } +} + +// LLIL_FORCE_VER +pub struct ForceVersion; + +impl Operation<'_, M, F, ForceVersion> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILRegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id).expect("Bad register ID") + } +} + +impl Debug for Operation<'_, M, F, ForceVersion> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ForceVersion") + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .finish() + } +} + +// LLIL_FORCE_VER_SSA +pub struct ForceVersionSsa; + +impl Operation<'_, M, F, ForceVersionSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind { + let raw_id = RegisterId(self.op.operands[2] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[3] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl Debug for Operation<'_, M, F, ForceVersionSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ForceVersionSsa") + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .field("source_reg", &self.source_reg()) + .finish() + } +} + // TODO TEST_BIT pub trait OperationArguments: 'static {} @@ -1923,3 +2083,7 @@ impl OperationArguments for DoublePrecDivOp {} impl OperationArguments for UnaryOp {} impl OperationArguments for Condition {} impl OperationArguments for UnimplMem {} +impl OperationArguments for Assert {} +impl OperationArguments for AssertSsa {} +impl OperationArguments for ForceVersion {} +impl OperationArguments for ForceVersionSsa {} From 39b0d6775813cdc4492296f6ea56aa575d2198c4 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 19:24:35 -0400 Subject: [PATCH 32/54] [Rust] Remove `NonSSAVariant` bound from `LowLevelILFunction` We don't do enough with the lifted il != non lifted il to justify the bound. This makes modifying IL much less work as the historical lifted il bound is gone. --- arch/msp430/src/architecture.rs | 8 +- arch/msp430/src/lift.rs | 8 +- arch/riscv/src/lib.rs | 39 ++++---- plugins/warp/src/cache.rs | 14 ++- plugins/warp/src/lib.rs | 16 ++-- plugins/warp/src/plugin/workflow.rs | 3 +- rust/examples/workflow.rs | 2 +- rust/src/architecture.rs | 50 +++++----- rust/src/flowgraph.rs | 6 +- rust/src/function.rs | 18 ++-- rust/src/function_recognizer.rs | 4 +- rust/src/low_level_il.rs | 27 +++--- rust/src/low_level_il/expression.rs | 48 ++-------- rust/src/low_level_il/function.rs | 27 +++--- rust/src/low_level_il/instruction.rs | 37 +------- rust/src/low_level_il/lifting.rs | 132 ++++++++++++--------------- rust/src/low_level_il/operation.rs | 20 ++-- rust/src/relocation.rs | 8 +- rust/src/workflow.rs | 28 ++---- 19 files changed, 202 insertions(+), 293 deletions(-) diff --git a/arch/msp430/src/architecture.rs b/arch/msp430/src/architecture.rs index 0ef6e449c6..91826193a1 100644 --- a/arch/msp430/src/architecture.rs +++ b/arch/msp430/src/architecture.rs @@ -20,7 +20,7 @@ use binaryninja::architecture::{ BranchKind, FlagClassId, FlagGroupId, FlagId, FlagWriteId, RegisterId, }; use binaryninja::low_level_il::expression::ValueExpr; -use binaryninja::low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}; +use binaryninja::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; use log::error; const MIN_MNEMONIC: usize = 9; @@ -194,7 +194,7 @@ impl Architecture for Msp430 { &self, data: &[u8], addr: u64, - il: &MutableLiftedILFunction, + il: &LowLevelILMutableFunction, ) -> Option<(usize, bool)> { match msp430_asm::decode(data) { Ok(inst) => { @@ -226,8 +226,8 @@ impl Architecture for Msp430 { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a MutableLiftedILFunction, - ) -> Option> { + _il: &'a LowLevelILMutableFunction, + ) -> Option> { None } diff --git a/arch/msp430/src/lift.rs b/arch/msp430/src/lift.rs index 124911f006..3e69b5a481 100644 --- a/arch/msp430/src/lift.rs +++ b/arch/msp430/src/lift.rs @@ -12,7 +12,7 @@ use msp430_asm::single_operand::SingleOperand; use msp430_asm::two_operand::TwoOperand; use binaryninja::low_level_il::expression::ValueExpr; -use binaryninja::low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}; +use binaryninja::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; use log::info; macro_rules! auto_increment { @@ -163,7 +163,7 @@ macro_rules! conditional_jump { }; } -pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &MutableLiftedILFunction) { +pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &LowLevelILMutableFunction) { match inst { Instruction::Rrc(inst) => { let size = match inst.operand_width() { @@ -623,8 +623,8 @@ pub(crate) fn lift_instruction(inst: &Instruction, addr: u64, il: &MutableLifted fn lift_source_operand<'a>( operand: &Operand, size: usize, - il: &'a MutableLiftedILFunction, -) -> MutableLiftedILExpr<'a, ValueExpr> { + il: &'a LowLevelILMutableFunction, +) -> LowLevelILMutableExpression<'a, ValueExpr> { match operand { Operand::RegisterDirect(r) => il.reg(size, Register::try_from(*r as u32).unwrap()), Operand::Indexed((r, offset)) => il diff --git a/arch/riscv/src/lib.rs b/arch/riscv/src/lib.rs index 4e9e47834d..f59e1ebbda 100644 --- a/arch/riscv/src/lib.rs +++ b/arch/riscv/src/lib.rs @@ -43,8 +43,8 @@ use binaryninja::low_level_il::lifting::{ LiftableLowLevelIL, LiftableLowLevelILWithSize, LowLevelILLabel, }; use binaryninja::low_level_il::{ - expression::ExpressionHandler, instruction::InstructionHandler, LowLevelILRegisterKind, - MutableLiftedILExpr, MutableLiftedILFunction, RegularLowLevelILFunction, + expression::ExpressionHandler, instruction::InstructionHandler, LowLevelILMutableExpression, + LowLevelILMutableFunction, LowLevelILRegisterKind, LowLevelILRegularFunction, }; use riscv_dis::{ FloatReg, FloatRegType, Instr, IntRegType, Op, RegFile, Register as RiscVRegister, @@ -207,7 +207,10 @@ impl architecture::Register for Register { impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a> for Register { type Result = ValueExpr; - fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { + fn lift( + il: &'a LowLevelILMutableFunction, + reg: Self, + ) -> LowLevelILMutableExpression<'a, Self::Result> { match reg.reg_type() { RegType::Integer(0) => il.const_int(reg.size(), 0), RegType::Integer(_) => il.reg(reg.size(), reg), @@ -218,10 +221,10 @@ impl<'a, D: RiscVDisassembler> LiftableLowLevelIL<'a> for Register { impl<'a, D: RiscVDisassembler> LiftableLowLevelILWithSize<'a> for Register { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a LowLevelILMutableFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, ValueExpr> { + ) -> LowLevelILMutableExpression<'a, ValueExpr> { #[cfg(debug_assertions)] { if reg.size() < size { @@ -1062,7 +1065,7 @@ impl Architecture for RiscVArch { &self, data: &[u8], addr: u64, - il: &MutableLiftedILFunction, + il: &LowLevelILMutableFunction, ) -> Option<(usize, bool)> { let max_width = self.default_integer_size(); @@ -1306,41 +1309,41 @@ impl Architecture for RiscVArch { Op::Ebreak => il.bp().append(), Op::Uret => { il.intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Uret), - MutableLiftedILFunction::NO_INPUTS, + LowLevelILMutableFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Sret => { il.intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Sret), - MutableLiftedILFunction::NO_INPUTS, + LowLevelILMutableFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Mret => { il.intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Mret), - MutableLiftedILFunction::NO_INPUTS, + LowLevelILMutableFunction::NO_INPUTS, ) .append(); il.no_ret().append(); } Op::Wfi => il .intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Wfi), - MutableLiftedILFunction::NO_INPUTS, + LowLevelILMutableFunction::NO_INPUTS, ) .append(), Op::Fence(i) => il .intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Fence), [il.const_int(4, i.imm() as u32 as u64)], ) @@ -1353,7 +1356,7 @@ impl Architecture for RiscVArch { if i.rd().id() == 0 { il.intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Csrwr), [csr, rs1], ) @@ -1404,7 +1407,7 @@ impl Architecture for RiscVArch { if i.rd().id() == 0 { il.intrinsic( - MutableLiftedILFunction::NO_OUTPUTS, + LowLevelILMutableFunction::NO_OUTPUTS, RiscVIntrinsic::::from(Intrinsic::Csrwr), [csr, imm], ) @@ -2848,7 +2851,7 @@ impl FunctionRecognizer for RiscVELFPLTRecognizer { &self, bv: &BinaryView, func: &Function, - llil: &RegularLowLevelILFunction, + llil: &LowLevelILRegularFunction, ) -> bool { // Look for the following code pattern: // t3 = plt diff --git a/plugins/warp/src/cache.rs b/plugins/warp/src/cache.rs index 7219b54712..cc8dfded13 100644 --- a/plugins/warp/src/cache.rs +++ b/plugins/warp/src/cache.rs @@ -3,10 +3,8 @@ use crate::{build_function, function_guid}; use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::confidence::MAX_CONFIDENCE; use binaryninja::function::Function as BNFunction; -use binaryninja::low_level_il::function::{ - FunctionMutability, LowLevelILFunction, NonSSA, RegularNonSSA, -}; -use binaryninja::low_level_il::RegularLowLevelILFunction; +use binaryninja::low_level_il::function::{FunctionMutability, LowLevelILFunction, NonSSA}; +use binaryninja::low_level_il::LowLevelILRegularFunction; use binaryninja::rc::Guard; use binaryninja::rc::Ref as BNRef; use binaryninja::symbol::Symbol as BNSymbol; @@ -67,7 +65,7 @@ pub fn try_cached_function_match(function: &BNFunction) -> Option { .to_owned() } -pub fn cached_function(function: &BNFunction, llil: &RegularLowLevelILFunction) -> Function { +pub fn cached_function(function: &BNFunction, llil: &LowLevelILRegularFunction) -> Function { let view = function.view(); let view_id = ViewID::from(view.as_ref()); let function_cache = FUNCTION_CACHE.get_or_init(Default::default); @@ -120,7 +118,7 @@ where pub fn cached_function_guid( function: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction, ) -> FunctionGUID { let view = function.view(); let view_id = ViewID::from(view); @@ -198,7 +196,7 @@ pub struct FunctionCache { } impl FunctionCache { - pub fn function(&self, function: &BNFunction, llil: &RegularLowLevelILFunction) -> Function { + pub fn function(&self, function: &BNFunction, llil: &LowLevelILRegularFunction) -> Function { let function_id = FunctionID::from(function); match self.cache.get(&function_id) { Some(function) => function.value().to_owned(), @@ -325,7 +323,7 @@ impl GUIDCache { pub fn function_guid( &self, function: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction, ) -> FunctionGUID { let function_id = FunctionID::from(function); match self.cache.get(&function_id) { diff --git a/plugins/warp/src/lib.rs b/plugins/warp/src/lib.rs index 3d68b4022e..62af0102da 100644 --- a/plugins/warp/src/lib.rs +++ b/plugins/warp/src/lib.rs @@ -10,9 +10,7 @@ use binaryninja::binary_view::BinaryViewExt; use binaryninja::confidence::MAX_CONFIDENCE; use binaryninja::function::{Function as BNFunction, NativeBlock}; use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpressionKind}; -use binaryninja::low_level_il::function::{ - FunctionMutability, LowLevelILFunction, NonSSA, RegularNonSSA, -}; +use binaryninja::low_level_il::function::{FunctionMutability, LowLevelILFunction, NonSSA}; use binaryninja::low_level_il::instruction::{ InstructionHandler, LowLevelILInstruction, LowLevelILInstructionKind, }; @@ -46,7 +44,7 @@ pub fn user_signature_dir() -> PathBuf { pub fn build_function( func: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction, ) -> Function { let bn_fn_ty = func.function_type(); Function { @@ -78,7 +76,7 @@ pub fn sorted_basic_blocks(func: &BNFunction) -> Vec( func: &BNFunction, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction, ) -> FunctionGUID { let basic_blocks = sorted_basic_blocks(func); let basic_block_guids = basic_blocks @@ -90,7 +88,7 @@ pub fn function_guid( pub fn basic_block_guid( basic_block: &BNBasicBlock, - llil: &LowLevelILFunction>, + llil: &LowLevelILFunction, ) -> BasicBlockGUID { let func = basic_block.function(); let view = func.view(); @@ -98,7 +96,7 @@ pub fn basic_block_guid( let max_instr_len = arch.max_instr_len(); // NOPs and useless moves are blacklisted to allow for hot-patchable functions. - let is_blacklisted_instr = |instr: &LowLevelILInstruction>| { + let is_blacklisted_instr = |instr: &LowLevelILInstruction| { match instr.kind() { LowLevelILInstructionKind::Nop(_) => true, LowLevelILInstructionKind::SetReg(op) => { @@ -126,8 +124,8 @@ pub fn basic_block_guid( } }; - let is_variant_instr = |instr: &LowLevelILInstruction>| { - let is_variant_expr = |expr: &LowLevelILExpressionKind>| { + let is_variant_instr = |instr: &LowLevelILInstruction| { + let is_variant_expr = |expr: &LowLevelILExpressionKind| { // TODO: Checking the section here is slow, we should gather all section ranges outside of this. match expr { LowLevelILExpressionKind::ConstPtr(op) diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs index 9f7c4d0d4f..f5763116ae 100644 --- a/plugins/warp/src/plugin/workflow.rs +++ b/plugins/warp/src/plugin/workflow.rs @@ -3,7 +3,6 @@ use crate::matcher::cached_function_matcher; use binaryninja::background_task::BackgroundTask; use binaryninja::binary_view::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; -use binaryninja::low_level_il::function::RegularNonSSA; use binaryninja::workflow::{Activity, AnalysisContext, Workflow}; use std::time::Instant; @@ -74,7 +73,7 @@ pub fn insert_workflow() { let guid_activity = |ctx: &AnalysisContext| { let function = ctx.function(); // TODO: Returning RegularNonSSA means we cant modify the il (the lifting code was written just for lifted il, that needs to be fixed) - if let Some(llil) = unsafe { ctx.llil_function::() } { + if let Some(llil) = unsafe { ctx.llil_function() } { cached_function_guid(&function, &llil); } }; diff --git a/rust/examples/workflow.rs b/rust/examples/workflow.rs index 2d8f00540e..4956057935 100644 --- a/rust/examples/workflow.rs +++ b/rust/examples/workflow.rs @@ -41,7 +41,7 @@ fn example_activity(analysis_context: &AnalysisContext) { } } } - analysis_context.set_lifted_il_function(&llil); + analysis_context.set_llil_function(&llil.finalized()); } } diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs index 211446d1ea..411508402e 100644 --- a/rust/src/architecture.rs +++ b/rust/src/architecture.rs @@ -23,7 +23,6 @@ use crate::{ calling_convention::CoreCallingConvention, data_buffer::DataBuffer, disassembly::InstructionTextToken, - low_level_il::{MutableLiftedILExpr, MutableLiftedILFunction}, platform::Platform, rc::*, relocation::CoreRelocationHandler, @@ -50,6 +49,7 @@ use crate::low_level_il::expression::ValueExpr; use crate::low_level_il::lifting::{ get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp, }; +use crate::low_level_il::{LowLevelILMutableExpression, LowLevelILMutableFunction}; pub use binaryninjacore_sys::BNFlagRole as FlagRole; pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend; pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition; @@ -467,7 +467,7 @@ pub trait Architecture: 'static + Sized + AsRef { &self, data: &[u8], addr: u64, - il: &MutableLiftedILFunction, + il: &LowLevelILMutableFunction, ) -> Option<(usize, bool)>; /// Fallback flag value calculation path. This method is invoked when the core is unable to @@ -484,8 +484,8 @@ pub trait Architecture: 'static + Sized + AsRef { flag: Self::Flag, flag_write_type: Self::FlagWrite, op: LowLevelILFlagWriteOp, - il: &'a MutableLiftedILFunction, - ) -> Option> { + il: &'a LowLevelILMutableFunction, + ) -> Option> { let role = flag.role(flag_write_type.class()); Some(get_default_flag_write_llil(self, role, op, il)) } @@ -513,8 +513,8 @@ pub trait Architecture: 'static + Sized + AsRef { &self, cond: FlagCondition, class: Option, - il: &'a MutableLiftedILFunction, - ) -> Option> { + il: &'a LowLevelILMutableFunction, + ) -> Option> { Some(get_default_flag_cond_llil(self, cond, class, il)) } @@ -535,8 +535,8 @@ pub trait Architecture: 'static + Sized + AsRef { fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a MutableLiftedILFunction, - ) -> Option> { + _il: &'a LowLevelILMutableFunction, + ) -> Option> { None } @@ -1513,7 +1513,7 @@ impl Architecture for CoreArchitecture { &self, data: &[u8], addr: u64, - il: &MutableLiftedILFunction, + il: &LowLevelILMutableFunction, ) -> Option<(usize, bool)> { let mut size = data.len(); let success = unsafe { @@ -1538,8 +1538,8 @@ impl Architecture for CoreArchitecture { _flag: Self::Flag, _flag_write: Self::FlagWrite, _op: LowLevelILFlagWriteOp, - _il: &'a MutableLiftedILFunction, - ) -> Option> { + _il: &'a LowLevelILMutableFunction, + ) -> Option> { None } @@ -1575,16 +1575,16 @@ impl Architecture for CoreArchitecture { &self, _cond: FlagCondition, _class: Option, - _il: &'a MutableLiftedILFunction, - ) -> Option> { + _il: &'a LowLevelILMutableFunction, + ) -> Option> { None } fn flag_group_llil<'a>( &self, _group: Self::FlagGroup, - _il: &'a MutableLiftedILFunction, - ) -> Option> { + _il: &'a LowLevelILMutableFunction, + ) -> Option> { None } @@ -2224,8 +2224,9 @@ where { let custom_arch = unsafe { &*(ctxt as *mut A) }; let data = unsafe { std::slice::from_raw_parts(data, *len) }; - let lifter = - unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; + let lifter = unsafe { + LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) + }; match custom_arch.instruction_llil(data, addr, &lifter) { Some((res_len, res_value)) => { @@ -2611,8 +2612,9 @@ where let flag_write = custom_arch.flag_write_from_id(FlagWriteId(flag_write)); let flag = custom_arch.flag_from_id(FlagId(flag)); let operands = unsafe { std::slice::from_raw_parts(operands_raw, operand_count) }; - let lifter = - unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; + let lifter = unsafe { + LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) + }; if let (Some(flag_write), Some(flag)) = (flag_write, flag) { if let Some(op) = LowLevelILFlagWriteOp::from_op(custom_arch, size, op, operands) { @@ -2660,8 +2662,9 @@ where let custom_arch = unsafe { &*(ctxt as *mut A) }; let class = custom_arch.flag_class_from_id(FlagClassId(class)); - let lifter = - unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; + let lifter = unsafe { + LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) + }; if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &lifter) { // TODO verify that returned expr is a bool value return expr.index.0; @@ -2679,8 +2682,9 @@ where A: 'static + Architecture> + Send + Sync, { let custom_arch = unsafe { &*(ctxt as *mut A) }; - let lifter = - unsafe { MutableLiftedILFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) }; + let lifter = unsafe { + LowLevelILMutableFunction::from_raw_with_arch(il, Some(*custom_arch.as_ref())) + }; if let Some(group) = custom_arch.flag_group_from_id(FlagGroupId(group)) { if let Some(expr) = custom_arch.flag_group_llil(group, &lifter) { diff --git a/rust/src/flowgraph.rs b/rust/src/flowgraph.rs index 0faab0e487..f0b34853e0 100644 --- a/rust/src/flowgraph.rs +++ b/rust/src/flowgraph.rs @@ -17,7 +17,7 @@ use binaryninjacore_sys::*; use crate::high_level_il::HighLevelILFunction; -use crate::low_level_il::RegularLowLevelILFunction; +use crate::low_level_il::LowLevelILRegularFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::*; use crate::render_layer::CoreRenderLayer; @@ -58,11 +58,11 @@ impl FlowGraph { unsafe { Array::new(nodes_ptr, count, ()) } } - pub fn low_level_il(&self) -> Result, ()> { + pub fn low_level_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle); match llil_ptr.is_null() { - false => Ok(RegularLowLevelILFunction::ref_from_raw(llil_ptr)), + false => Ok(LowLevelILRegularFunction::ref_from_raw(llil_ptr)), true => Err(()), } } diff --git a/rust/src/function.rs b/rust/src/function.rs index 925383847c..ec859f7e31 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -41,7 +41,7 @@ use crate::architecture::RegisterId; use crate::confidence::Conf; use crate::high_level_il::HighLevelILFunction; use crate::language_representation::CoreLanguageRepresentationFunction; -use crate::low_level_il::{LiftedILFunction, RegularLowLevelILFunction}; +use crate::low_level_il::LowLevelILRegularFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::variable::{ IndirectBranchInfo, MergedVariable, NamedVariableWithType, RegisterValue, RegisterValueType, @@ -558,38 +558,38 @@ impl Function { } } - pub fn low_level_il(&self) -> Result, ()> { + pub fn low_level_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFunctionLowLevelIL(self.handle); match llil_ptr.is_null() { - false => Ok(RegularLowLevelILFunction::ref_from_raw(llil_ptr)), + false => Ok(LowLevelILRegularFunction::ref_from_raw(llil_ptr)), true => Err(()), } } } - pub fn low_level_il_if_available(&self) -> Option> { + pub fn low_level_il_if_available(&self) -> Option> { let llil_ptr = unsafe { BNGetFunctionLowLevelILIfAvailable(self.handle) }; match llil_ptr.is_null() { - false => Some(unsafe { RegularLowLevelILFunction::ref_from_raw(llil_ptr) }), + false => Some(unsafe { LowLevelILRegularFunction::ref_from_raw(llil_ptr) }), true => None, } } - pub fn lifted_il(&self) -> Result, ()> { + pub fn lifted_il(&self) -> Result, ()> { unsafe { let llil_ptr = BNGetFunctionLiftedIL(self.handle); match llil_ptr.is_null() { - false => Ok(LiftedILFunction::ref_from_raw(llil_ptr)), + false => Ok(LowLevelILRegularFunction::ref_from_raw(llil_ptr)), true => Err(()), } } } - pub fn lifted_il_if_available(&self) -> Option> { + pub fn lifted_il_if_available(&self) -> Option> { let llil_ptr = unsafe { BNGetFunctionLiftedILIfAvailable(self.handle) }; match llil_ptr.is_null() { - false => Some(unsafe { LiftedILFunction::ref_from_raw(llil_ptr) }), + false => Some(unsafe { LowLevelILRegularFunction::ref_from_raw(llil_ptr) }), true => None, } } diff --git a/rust/src/function_recognizer.rs b/rust/src/function_recognizer.rs index cd5592ee75..0d85d827af 100644 --- a/rust/src/function_recognizer.rs +++ b/rust/src/function_recognizer.rs @@ -1,5 +1,5 @@ use crate::low_level_il::function::LowLevelILFunction; -use crate::low_level_il::RegularLowLevelILFunction; +use crate::low_level_il::LowLevelILRegularFunction; use crate::medium_level_il::MediumLevelILFunction; use crate::{architecture::CoreArchitecture, binary_view::BinaryView, function::Function}; use binaryninjacore_sys::*; @@ -10,7 +10,7 @@ pub trait FunctionRecognizer { &self, _bv: &BinaryView, _func: &Function, - _llil: &RegularLowLevelILFunction, + _llil: &LowLevelILRegularFunction, ) -> bool { false } diff --git a/rust/src/low_level_il.rs b/rust/src/low_level_il.rs index 4c52e31301..010fa0bc00 100644 --- a/rust/src/low_level_il.rs +++ b/rust/src/low_level_il.rs @@ -36,19 +36,20 @@ use self::expression::*; use self::function::*; use self::instruction::*; -pub type MutableLiftedILFunction = LowLevelILFunction>; -pub type LiftedILFunction = LowLevelILFunction>; -pub type MutableLiftedILExpr<'a, ReturnType> = - LowLevelILExpression<'a, Mutable, NonSSA, ReturnType>; -pub type RegularLowLevelILFunction = LowLevelILFunction>; -pub type RegularLowLevelILInstruction<'a> = - LowLevelILInstruction<'a, Finalized, NonSSA>; -pub type RegularLowLevelILInstructionKind<'a> = - LowLevelILInstructionKind<'a, Finalized, NonSSA>; -pub type RegularLowLevelILExpression<'a, ReturnType> = - LowLevelILExpression<'a, Finalized, NonSSA, ReturnType>; -pub type RegularLowLevelILExpressionKind<'a> = - LowLevelILExpressionKind<'a, Finalized, NonSSA>; +/// Regular low-level IL, if you are not modifying the functions IL or needing SSA, use this. +pub type LowLevelILRegularFunction = LowLevelILFunction; +pub type LowLevelILRegularInstruction<'a> = LowLevelILInstruction<'a, Finalized, NonSSA>; +pub type LowLevelILRegularInstructionKind<'a> = LowLevelILInstructionKind<'a, Finalized, NonSSA>; +pub type LowLevelILRegularExpression<'a, ReturnType> = + LowLevelILExpression<'a, Finalized, NonSSA, ReturnType>; +pub type LowLevelILRegularExpressionKind<'a> = LowLevelILExpressionKind<'a, Finalized, NonSSA>; + +/// Mutable low-level IL, used when lifting in architectures and modifying IL in workflow activities. +pub type LowLevelILMutableFunction = LowLevelILFunction; +pub type LowLevelILMutableExpression<'a, ReturnType> = + LowLevelILExpression<'a, Mutable, NonSSA, ReturnType>; + +/// SSA Variant of low-level IL, this can never be mutated directly. pub type LowLevelILSSAFunction = LowLevelILFunction; #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 73bec38d8a..8df8dfe0cf 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -135,12 +135,12 @@ where } } -impl<'func, M> ExpressionHandler<'func, M, NonSSA> - for LowLevelILExpression<'func, M, NonSSA, ValueExpr> +impl<'func, M> ExpressionHandler<'func, M, NonSSA> + for LowLevelILExpression<'func, M, NonSSA, ValueExpr> where M: FunctionMutability, { - fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> { + fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; @@ -154,41 +154,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, - { - // Visit the current expression. - match f(self) { - VisitorAction::Descend => { - // Recursively visit sub expressions. - self.kind().visit_sub_expressions(|e| e.visit_tree(f)) - } - action => action, - } - } -} - -impl<'func, M> ExpressionHandler<'func, M, NonSSA> - for LowLevelILExpression<'func, M, NonSSA, ValueExpr> -where - M: FunctionMutability, -{ - fn kind(&self) -> LowLevelILExpressionKind<'func, M, NonSSA> { - use binaryninjacore_sys::BNLowLevelILOperation::*; - let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; - match op.operation { - // Any invalid ops for Non-Lifted IL will be checked here. - LLIL_FLAG_COND => unreachable!("LLIL_FLAG_COND is only valid in Lifted IL"), - LLIL_FLAG_GROUP => unreachable!("LLIL_FLAG_GROUP is only valid in Lifted IL"), - // SAFETY: We have checked for illegal operations. - _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), - } - } - - fn visit_tree(&self, f: &mut T) -> VisitorAction - where - T: FnMut( - &LowLevelILExpression<'func, M, NonSSA, ValueExpr>, - ) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, { // Visit the current expression. match f(self) { @@ -272,9 +238,9 @@ where LowPart(Operation<'func, M, F, operation::UnaryOp>), // Valid only in Lifted IL - FlagCond(Operation<'func, M, NonSSA, operation::FlagCond>), + FlagCond(Operation<'func, M, F, operation::FlagCond>), // Valid only in Lifted IL - FlagGroup(Operation<'func, M, NonSSA, operation::FlagGroup>), + FlagGroup(Operation<'func, M, F, operation::FlagGroup>), CmpE(Operation<'func, M, F, operation::Condition>), CmpNe(Operation<'func, M, F, operation::Condition>), @@ -708,7 +674,7 @@ where } } -impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { +impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { pub fn flag_write(&self) -> Option { use self::LowLevelILExpressionKind::*; diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 62811b1dfd..495aae7905 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -35,23 +35,14 @@ pub trait FunctionMutability: 'static + Debug {} impl FunctionMutability for Mutable {} impl FunctionMutability for Finalized {} -#[derive(Copy, Clone, Debug)] -pub struct LiftedNonSSA; -#[derive(Copy, Clone, Debug)] -pub struct RegularNonSSA; - -pub trait NonSSAVariant: 'static + Debug {} -impl NonSSAVariant for LiftedNonSSA {} -impl NonSSAVariant for RegularNonSSA {} - #[derive(Copy, Clone, Debug)] pub struct SSA; #[derive(Copy, Clone, Debug)] -pub struct NonSSA(V); +pub struct NonSSA; pub trait FunctionForm: 'static + Debug {} impl FunctionForm for SSA {} -impl FunctionForm for NonSSA {} +impl FunctionForm for NonSSA {} pub struct LowLevelILFunction { pub(crate) handle: *mut BNLowLevelILFunction, @@ -170,7 +161,7 @@ where } } -impl LowLevelILFunction> { +impl LowLevelILFunction { /// Retrieve the SSA form of the function. pub fn ssa_form(&self) -> Option>> { let handle = unsafe { BNGetLowLevelILSSAForm(self.handle) }; @@ -182,7 +173,7 @@ impl LowLevelILFunction> { } // Allow instantiating Lifted IL functions for querying Lifted IL from Architectures -impl LowLevelILFunction> { +impl LowLevelILFunction { // TODO: Document what happens when you pass None for `source_func`. // TODO: Doing so would construct a LowLevelILFunction with no basic blocks // TODO: Document why you would want to do that. @@ -208,6 +199,16 @@ impl LowLevelILFunction> { } } +impl Ref> { + pub fn finalized(self) -> Ref> { + unsafe { + BNFinalizeLowLevelILFunction(self.handle); + // Now that we have finalized return the function as is so the caller can reference the "finalized function". + LowLevelILFunction::from_raw(self.handle).to_owned() + } + } +} + impl ToOwned for LowLevelILFunction where M: FunctionMutability, diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index 19b721af92..ef546412ed 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -141,12 +141,11 @@ where } } -impl<'func, M> InstructionHandler<'func, M, NonSSA> - for LowLevelILInstruction<'func, M, NonSSA> +impl<'func, M> InstructionHandler<'func, M, NonSSA> for LowLevelILInstruction<'func, M, NonSSA> where M: FunctionMutability, { - fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> { + fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> { #[allow(unused_imports)] use binaryninjacore_sys::BNLowLevelILOperation::*; let raw_op = self.into_raw(); @@ -162,37 +161,7 @@ where fn visit_tree(&self, f: &mut T) -> VisitorAction where - T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, - { - // Recursively visit sub expressions. - self.kind().visit_sub_expressions(|e| e.visit_tree(f)) - } -} - -impl<'func, M> InstructionHandler<'func, M, NonSSA> - for LowLevelILInstruction<'func, M, NonSSA> -where - M: FunctionMutability, -{ - fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> { - #[allow(unused_imports)] - use binaryninjacore_sys::BNLowLevelILOperation::*; - let raw_op = self.into_raw(); - #[allow(clippy::match_single_binding)] - match raw_op.operation { - // Any invalid ops for Non-Lifted IL will be checked here. - // SAFETY: We have checked for illegal operations. - _ => unsafe { - LowLevelILInstructionKind::from_raw(self.function, self.expr_idx(), raw_op) - }, - } - } - - fn visit_tree(&self, f: &mut T) -> VisitorAction - where - T: FnMut( - &LowLevelILExpression<'func, M, NonSSA, ValueExpr>, - ) -> VisitorAction, + T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction, { // Recursively visit sub expressions. self.kind().visit_sub_expressions(|e| e.visit_tree(f)) diff --git a/rust/src/low_level_il/lifting.rs b/rust/src/low_level_il/lifting.rs index b0f85f11e5..f2850776cf 100644 --- a/rust/src/low_level_il/lifting.rs +++ b/rust/src/low_level_il/lifting.rs @@ -29,17 +29,17 @@ pub trait LiftableLowLevelIL<'func> { type Result: ExpressionResultType; fn lift( - il: &'func MutableLiftedILFunction, + il: &'func LowLevelILMutableFunction, expr: Self, - ) -> MutableLiftedILExpr<'func, Self::Result>; + ) -> LowLevelILMutableExpression<'func, Self::Result>; } pub trait LiftableLowLevelILWithSize<'func>: LiftableLowLevelIL<'func, Result = ValueExpr> { fn lift_with_size( - il: &'func MutableLiftedILFunction, + il: &'func LowLevelILMutableFunction, expr: Self, size: usize, - ) -> MutableLiftedILExpr<'func, ValueExpr>; + ) -> LowLevelILMutableExpression<'func, ValueExpr>; } #[derive(Copy, Clone)] @@ -459,8 +459,8 @@ pub fn get_default_flag_write_llil<'func, A>( arch: &A, role: FlagRole, op: LowLevelILFlagWriteOp, - il: &'func MutableLiftedILFunction, -) -> MutableLiftedILExpr<'func, ValueExpr> + il: &'func LowLevelILMutableFunction, +) -> LowLevelILMutableExpression<'func, ValueExpr> where A: 'func + Architecture, { @@ -487,8 +487,8 @@ pub fn get_default_flag_cond_llil<'func, A>( arch: &A, cond: FlagCondition, class: Option, - il: &'func MutableLiftedILFunction, -) -> MutableLiftedILExpr<'func, ValueExpr> + il: &'func LowLevelILMutableFunction, +) -> LowLevelILMutableExpression<'func, ValueExpr> where A: 'func + Architecture, { @@ -512,16 +512,16 @@ macro_rules! prim_int_lifter { impl<'a> LiftableLowLevelIL<'a> for $x { type Result = ValueExpr; - fn lift(il: &'a MutableLiftedILFunction, val: Self) - -> MutableLiftedILExpr<'a, Self::Result> + fn lift(il: &'a LowLevelILMutableFunction, val: Self) + -> LowLevelILMutableExpression<'a, Self::Result> { il.const_int(std::mem::size_of::(), val as i64 as u64) } } impl<'a> LiftableLowLevelILWithSize<'a> for $x { - fn lift_with_size(il: &'a MutableLiftedILFunction, val: Self, size: usize) - -> MutableLiftedILExpr<'a, ValueExpr> + fn lift_with_size(il: &'a LowLevelILMutableFunction, val: Self, size: usize) + -> LowLevelILMutableExpression<'a, ValueExpr> { let raw = val as i64; @@ -560,7 +560,10 @@ where { type Result = ValueExpr; - fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { + fn lift( + il: &'a LowLevelILMutableFunction, + reg: Self, + ) -> LowLevelILMutableExpression<'a, Self::Result> { match reg { LowLevelILRegisterKind::Arch(r) => R::lift(il, r), LowLevelILRegisterKind::Temp(t) => il.reg( @@ -576,10 +579,10 @@ where R: LiftableLowLevelILWithSize<'a> + Into> + ArchReg, { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a LowLevelILMutableFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, ValueExpr> { + ) -> LowLevelILMutableExpression<'a, ValueExpr> { match reg { LowLevelILRegisterKind::Arch(r) => R::lift_with_size(il, r, size), LowLevelILRegisterKind::Temp(t) => il.reg(size, LowLevelILRegisterKind::::Temp(t)), @@ -595,7 +598,10 @@ where { type Result = ValueExpr; - fn lift(il: &'a MutableLiftedILFunction, reg: Self) -> MutableLiftedILExpr<'a, Self::Result> { + fn lift( + il: &'a LowLevelILMutableFunction, + reg: Self, + ) -> LowLevelILMutableExpression<'a, Self::Result> { match reg { LowLevelILRegisterOrConstant::Register(size, r) => { LowLevelILRegisterKind::::lift_with_size(il, r, size) @@ -612,10 +618,10 @@ where R: LiftableLowLevelILWithSize<'a> + Into> + ArchReg, { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a LowLevelILMutableFunction, reg: Self, size: usize, - ) -> MutableLiftedILExpr<'a, ValueExpr> { + ) -> LowLevelILMutableExpression<'a, ValueExpr> { // TODO ensure requested size is compatible with size of this constant match reg { LowLevelILRegisterOrConstant::Register(_, r) => { @@ -628,26 +634,27 @@ where } } -impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILExpression<'a, Mutable, NonSSA, R> +impl<'a, R> LiftableLowLevelIL<'a> for LowLevelILExpression<'a, Mutable, NonSSA, R> where R: ExpressionResultType, { type Result = R; - fn lift(il: &'a MutableLiftedILFunction, expr: Self) -> MutableLiftedILExpr<'a, Self::Result> { + fn lift( + il: &'a LowLevelILMutableFunction, + expr: Self, + ) -> LowLevelILMutableExpression<'a, Self::Result> { debug_assert!(expr.function.handle == il.handle); expr } } -impl<'a> LiftableLowLevelILWithSize<'a> - for LowLevelILExpression<'a, Mutable, NonSSA, ValueExpr> -{ +impl<'a> LiftableLowLevelILWithSize<'a> for LowLevelILExpression<'a, Mutable, NonSSA, ValueExpr> { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a LowLevelILMutableFunction, expr: Self, _size: usize, - ) -> MutableLiftedILExpr<'a, Self::Result> { + ) -> LowLevelILMutableExpression<'a, Self::Result> { #[cfg(debug_assertions)] { use crate::low_level_il::ExpressionHandler; @@ -667,7 +674,7 @@ impl<'a> LiftableLowLevelILWithSize<'a> } } -impl LowLevelILExpression<'_, Mutable, NonSSA, R> +impl LowLevelILExpression<'_, Mutable, NonSSA, R> where R: ExpressionResultType, { @@ -686,7 +693,7 @@ pub struct ExpressionBuilder<'func, R> where R: ExpressionResultType, { - function: &'func LowLevelILFunction>, + function: &'func LowLevelILFunction, op: BNLowLevelILOperation, size: usize, flag_write: FlagWriteId, @@ -701,7 +708,7 @@ impl<'a, R> ExpressionBuilder<'a, R> where R: ExpressionResultType, { - pub fn from_expr(expr: LowLevelILExpression<'a, Mutable, NonSSA, R>) -> Self { + pub fn from_expr(expr: LowLevelILExpression<'a, Mutable, NonSSA, R>) -> Self { use binaryninjacore_sys::BNGetLowLevelILByIndex; let instr = unsafe { BNGetLowLevelILByIndex(expr.function.handle, expr.index.0) }; @@ -725,7 +732,7 @@ where self } - pub fn build(self) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { + pub fn build(self) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { use binaryninjacore_sys::BNLowLevelILAddExpr; let expr_idx = unsafe { @@ -744,10 +751,7 @@ where LowLevelILExpression::new(self.function, LowLevelExpressionIndex(expr_idx)) } - pub fn with_source_operand( - self, - op: u32, - ) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { + pub fn with_source_operand(self, op: u32) -> LowLevelILExpression<'a, Mutable, NonSSA, R> { self.build().with_source_operand(op) } @@ -763,7 +767,10 @@ where { type Result = R; - fn lift(il: &'a MutableLiftedILFunction, expr: Self) -> MutableLiftedILExpr<'a, Self::Result> { + fn lift( + il: &'a LowLevelILMutableFunction, + expr: Self, + ) -> LowLevelILMutableExpression<'a, Self::Result> { debug_assert!(expr.function.handle == il.handle); expr.build() @@ -772,10 +779,10 @@ where impl<'a> LiftableLowLevelILWithSize<'a> for ExpressionBuilder<'a, ValueExpr> { fn lift_with_size( - il: &'a MutableLiftedILFunction, + il: &'a LowLevelILMutableFunction, expr: Self, _size: usize, - ) -> MutableLiftedILExpr<'a, ValueExpr> { + ) -> LowLevelILMutableExpression<'a, ValueExpr> { #[cfg(debug_assertions)] { use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_UNIMPL, LLIL_UNIMPL_MEM}; @@ -796,7 +803,7 @@ impl<'a> LiftableLowLevelILWithSize<'a> for ExpressionBuilder<'a, ValueExpr> { macro_rules! no_arg_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name(&self) -> LowLevelILExpression, $result> { + pub fn $name(&self) -> LowLevelILExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::$op; @@ -829,10 +836,7 @@ macro_rules! sized_no_arg_lifter { macro_rules! unsized_unary_op_lifter { ($name:ident, $op:ident, $result:ty) => { - pub fn $name<'a, E>( - &'a self, - expr: E, - ) -> LowLevelILExpression<'a, Mutable, NonSSA, $result> + pub fn $name<'a, E>(&'a self, expr: E) -> LowLevelILExpression<'a, Mutable, NonSSA, $result> where E: LiftableLowLevelIL<'a, Result = ValueExpr>, { @@ -967,14 +971,14 @@ macro_rules! binary_op_carry_lifter { }; } -impl LowLevelILFunction> { +impl LowLevelILMutableFunction { pub const NO_INPUTS: [ExpressionBuilder<'static, ValueExpr>; 0] = []; pub const NO_OUTPUTS: [LowLevelILRegisterKind; 0] = []; pub fn expression<'a, E: LiftableLowLevelIL<'a>>( &'a self, expr: E, - ) -> LowLevelILExpression<'a, Mutable, NonSSA, E::Result> { + ) -> LowLevelILExpression<'a, Mutable, NonSSA, E::Result> { E::lift(self, expr) } @@ -1002,11 +1006,7 @@ impl LowLevelILFunction> { true } - pub fn const_int( - &self, - size: usize, - val: u64, - ) -> LowLevelILExpression, ValueExpr> { + pub fn const_int(&self, size: usize, val: u64) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST; @@ -1016,11 +1016,7 @@ impl LowLevelILFunction> { LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn const_ptr_sized( - &self, - size: usize, - val: u64, - ) -> LowLevelILExpression, ValueExpr> { + pub fn const_ptr_sized(&self, size: usize, val: u64) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_CONST_PTR; @@ -1030,14 +1026,11 @@ impl LowLevelILFunction> { LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn const_ptr( - &self, - val: u64, - ) -> LowLevelILExpression, ValueExpr> { + pub fn const_ptr(&self, val: u64) -> LowLevelILMutableExpression { self.const_ptr_sized(self.arch().address_size(), val) } - pub fn trap(&self, val: u64) -> LowLevelILExpression, VoidExpr> { + pub fn trap(&self, val: u64) -> LowLevelILExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_TRAP; @@ -1064,7 +1057,7 @@ impl LowLevelILFunction> { cond: C, true_label: &'b mut LowLevelILLabel, false_label: &'b mut LowLevelILLabel, - ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> + ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> where C: LiftableLowLevelIL<'b, Result = ValueExpr>, { @@ -1104,7 +1097,7 @@ impl LowLevelILFunction> { pub fn goto<'a: 'b, 'b>( &'a self, label: &'b mut LowLevelILLabel, - ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> { + ) -> LowLevelILExpression<'a, Mutable, NonSSA, VoidExpr> { use binaryninjacore_sys::BNLowLevelILGoto; let mut raw_label = BNLowLevelILLabel::from(*label); @@ -1125,7 +1118,7 @@ impl LowLevelILFunction> { &self, size: usize, reg: LR, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG; @@ -1143,7 +1136,7 @@ impl LowLevelILFunction> { size: usize, hi_reg: LR, lo_reg: LR, - ) -> LowLevelILExpression, ValueExpr> { + ) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_REG_SPLIT; @@ -1232,10 +1225,7 @@ impl LowLevelILFunction> { } } - pub fn flag( - &self, - flag: impl Flag, - ) -> LowLevelILExpression, ValueExpr> { + pub fn flag(&self, flag: impl Flag) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG; @@ -1247,10 +1237,7 @@ impl LowLevelILFunction> { LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn flag_cond( - &self, - cond: FlagCondition, - ) -> LowLevelILExpression, ValueExpr> { + pub fn flag_cond(&self, cond: FlagCondition) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_COND; @@ -1261,10 +1248,7 @@ impl LowLevelILFunction> { LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx)) } - pub fn flag_group( - &self, - group: impl FlagGroup, - ) -> LowLevelILExpression, ValueExpr> { + pub fn flag_group(&self, group: impl FlagGroup) -> LowLevelILMutableExpression { use binaryninjacore_sys::BNLowLevelILAddExpr; use binaryninjacore_sys::BNLowLevelILOperation::LLIL_FLAG_GROUP; diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index f2ce9d1a05..6e0dda9150 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -90,11 +90,14 @@ where } } -impl Operation<'_, M, NonSSA, O> +impl Operation<'_, M, NonSSA, O> where M: FunctionMutability, O: OperationArguments, { + /// Get the [`CoreFlagWrite`] for the operation. + /// + /// NOTE: This is only expected to be present for lifted IL. pub fn flag_write(&self) -> Option { match self.op.flags { 0 => None, @@ -1419,9 +1422,10 @@ where // Valid only in Lifted IL pub struct FlagGroup; -impl Operation<'_, M, NonSSA, FlagGroup> +impl Operation<'_, M, F, FlagGroup> where M: FunctionMutability, + F: FunctionForm, { pub fn flag_group(&self) -> CoreFlagGroup { let id = self.op.operands[0] as u32; @@ -1432,9 +1436,10 @@ where } } -impl Debug for Operation<'_, M, NonSSA, FlagGroup> +impl Debug for Operation<'_, M, F, FlagGroup> where M: FunctionMutability, + F: FunctionForm, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("FlagGroup") @@ -1443,15 +1448,6 @@ where } } -impl Debug for Operation<'_, M, SSA, FlagGroup> -where - M: FunctionMutability, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("FlagGroup").finish() - } -} - // LLIL_TRAP pub struct Trap; diff --git a/rust/src/relocation.rs b/rust/src/relocation.rs index 2b24279bfc..a4f9667ece 100644 --- a/rust/src/relocation.rs +++ b/rust/src/relocation.rs @@ -1,4 +1,4 @@ -use crate::low_level_il::RegularLowLevelILFunction; +use crate::low_level_il::LowLevelILRegularFunction; use crate::rc::Guard; use crate::string::IntoCStr; use crate::{ @@ -265,7 +265,7 @@ pub trait RelocationHandler: 'static + Sized + AsRef { _data: &[u8], _addr: u64, // TODO: Are we sure this is not a liftedilfunction? - _il: &RegularLowLevelILFunction, + _il: &LowLevelILRegularFunction, _reloc: &Relocation, ) -> RelocationOperand { RelocationOperand::AutocoerceExternPtr @@ -363,7 +363,7 @@ impl RelocationHandler for CoreRelocationHandler { &self, data: &[u8], addr: u64, - il: &RegularLowLevelILFunction, + il: &LowLevelILRegularFunction, reloc: &Relocation, ) -> RelocationOperand { unsafe { @@ -495,7 +495,7 @@ where return RelocationOperand::Invalid.into(); } let arch = unsafe { CoreArchitecture::from_raw(arch) }; - let il = unsafe { RegularLowLevelILFunction::from_raw_with_arch(il, Some(arch)) }; + let il = unsafe { LowLevelILRegularFunction::from_raw_with_arch(il, Some(arch)) }; custom_handler .get_operand_for_external_relocation(data, addr, &il, &reloc) diff --git a/rust/src/workflow.rs b/rust/src/workflow.rs index 0b1925a9e4..3dcb104251 100644 --- a/rust/src/workflow.rs +++ b/rust/src/workflow.rs @@ -5,8 +5,7 @@ use crate::binary_view::BinaryView; use crate::flowgraph::FlowGraph; use crate::function::{Function, NativeBlock}; use crate::high_level_il::HighLevelILFunction; -use crate::low_level_il::function::{LowLevelILFunction, Mutable, NonSSA, NonSSAVariant}; -use crate::low_level_il::MutableLiftedILFunction; +use crate::low_level_il::{LowLevelILMutableFunction, LowLevelILRegularFunction}; use crate::medium_level_il::MediumLevelILFunction; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnString, IntoCStr}; @@ -45,41 +44,32 @@ impl AnalysisContext { unsafe { Function::ref_from_raw(result) } } - /// [`LowLevelILFunction`] used to represent Low Level IL - pub unsafe fn lifted_il_function(&self) -> Option> { + /// [`LowLevelILMutableFunction`] used to represent Lifted Level IL + pub unsafe fn lifted_il_function(&self) -> Option> { let func = self.function(); let result = unsafe { BNGetFunctionLiftedIL(func.handle) }; unsafe { - Some(LowLevelILFunction::ref_from_raw( + Some(LowLevelILMutableFunction::ref_from_raw( NonNull::new(result)?.as_ptr(), )) } } - pub fn set_lifted_il_function(&self, value: &MutableLiftedILFunction) { + pub fn set_lifted_il_function(&self, value: &LowLevelILRegularFunction) { unsafe { BNSetLiftedILFunction(self.handle.as_ptr(), value.handle) } } - // TODO: This returns LiftedNonSSA because the lifting code was written before we could patch the IL - // TODO: At some point we need to take the lifting code and make it available to regular IL. - /// [`LowLevelILFunction`] used to represent Low Level IL - pub unsafe fn llil_function( - &self, - ) -> Option>>> { + /// [`LowLevelILMutableFunction`] used to represent Low Level IL + pub unsafe fn llil_function(&self) -> Option> { let result = unsafe { BNAnalysisContextGetLowLevelILFunction(self.handle.as_ptr()) }; unsafe { - Some(LowLevelILFunction::ref_from_raw( + Some(LowLevelILMutableFunction::ref_from_raw( NonNull::new(result)?.as_ptr(), )) } } - // TODO: This returns LiftedNonSSA because the lifting code was written before we could patch the IL - // TODO: At some point we need to take the lifting code and make it available to regular IL. - pub fn set_llil_function( - &self, - value: &LowLevelILFunction>, - ) { + pub fn set_llil_function(&self, value: &LowLevelILRegularFunction) { unsafe { BNSetLowLevelILFunction(self.handle.as_ptr(), value.handle) } } From 5fd2f414512f1b588279ac5ee728b247bc2f4b3d Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 20:00:43 -0400 Subject: [PATCH 33/54] [Rust] Move `BinaryReader` and `BinaryWriter` into `binary_view` module Both of these are associated directly to a `BinaryView` and only exist as accessors onto it. --- rust/src/binary_view.rs | 7 ++++++- rust/src/{binary_reader.rs => binary_view/reader.rs} | 4 ++-- rust/src/{binary_writer.rs => binary_view/writer.rs} | 0 rust/src/lib.rs | 2 -- rust/tests/binary_reader.rs | 3 +-- rust/tests/binary_writer.rs | 4 +--- 6 files changed, 10 insertions(+), 10 deletions(-) rename rust/src/{binary_reader.rs => binary_view/reader.rs} (97%) rename rust/src/{binary_writer.rs => binary_view/writer.rs} (100%) diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 65bab46385..1aa9789188 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -26,7 +26,6 @@ use binaryninjacore_sys::*; use crate::architecture::{Architecture, CoreArchitecture}; use crate::base_detection::BaseAddressDetection; use crate::basic_block::BasicBlock; -use crate::binary_view::memory_map::MemoryMap; use crate::component::Component; use crate::confidence::Conf; use crate::data_buffer::DataBuffer; @@ -66,6 +65,12 @@ use std::{result, slice}; // TODO : general reorg of modules related to bv pub mod memory_map; +pub mod reader; +pub mod writer; + +pub use memory_map::MemoryMap; +pub use reader::BinaryReader; +pub use writer::BinaryWriter; pub type Result = result::Result; pub type BinaryViewEventType = BNBinaryViewEventType; diff --git a/rust/src/binary_reader.rs b/rust/src/binary_view/reader.rs similarity index 97% rename from rust/src/binary_reader.rs rename to rust/src/binary_view/reader.rs index e96e552aec..7b49f28dbc 100644 --- a/rust/src/binary_reader.rs +++ b/rust/src/binary_view/reader.rs @@ -68,12 +68,12 @@ impl BinaryReader { unsafe { BNSetBinaryReaderVirtualBase(self.handle, virtual_base_addr) } } - /// Prefer using [crate::binary_reader::BinaryReader::seek] over this. + /// Prefer using [crate::reader::BinaryReader::seek] over this. pub fn seek_to_offset(&mut self, offset: u64) { unsafe { BNSeekBinaryReader(self.handle, offset) } } - /// Prefer using [crate::binary_reader::BinaryReader::seek] over this. + /// Prefer using [crate::reader::BinaryReader::seek] over this. pub fn seek_to_relative_offset(&mut self, offset: i64) { unsafe { BNSeekBinaryReaderRelative(self.handle, offset) } } diff --git a/rust/src/binary_writer.rs b/rust/src/binary_view/writer.rs similarity index 100% rename from rust/src/binary_writer.rs rename to rust/src/binary_view/writer.rs diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1b02da0d79..80baae4386 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -32,9 +32,7 @@ pub mod architecture; pub mod background_task; pub mod base_detection; pub mod basic_block; -pub mod binary_reader; pub mod binary_view; -pub mod binary_writer; pub mod calling_convention; pub mod collaboration; pub mod command; diff --git a/rust/tests/binary_reader.rs b/rust/tests/binary_reader.rs index 12be9706fc..0adac464e0 100644 --- a/rust/tests/binary_reader.rs +++ b/rust/tests/binary_reader.rs @@ -1,5 +1,4 @@ -use binaryninja::binary_reader::BinaryReader; -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; +use binaryninja::binary_view::{BinaryReader, BinaryViewBase, BinaryViewExt}; use binaryninja::headless::Session; use std::io::{Read, Seek, SeekFrom}; use std::path::PathBuf; diff --git a/rust/tests/binary_writer.rs b/rust/tests/binary_writer.rs index 1ec12dd3e4..b74b28374c 100644 --- a/rust/tests/binary_writer.rs +++ b/rust/tests/binary_writer.rs @@ -1,6 +1,4 @@ -use binaryninja::binary_reader::BinaryReader; -use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt}; -use binaryninja::binary_writer::BinaryWriter; +use binaryninja::binary_view::{BinaryReader, BinaryViewBase, BinaryViewExt, BinaryWriter}; use binaryninja::headless::Session; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; From 32a019aba35c98c2867ce9b9a9eab4871fff4d63 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 21:55:22 -0400 Subject: [PATCH 34/54] [Rust] Consult secrets provider when trying to connect to a remote --- Cargo.lock | 1 + rust/Cargo.toml | 2 ++ rust/src/collaboration/remote.rs | 50 +++++++++++++++++++++++--------- rust/tests/data_buffer.rs | 4 +-- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fea9b147b..8e08425f05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,6 +358,7 @@ dependencies = [ "log", "rayon", "rstest", + "serde_json", "serial_test", "tempfile", "thiserror 2.0.11", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index aecffb9980..16743cd919 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -18,6 +18,8 @@ log = { version = "0.4", features = ["std"] } rayon = { version = "1.10", optional = true } binaryninjacore-sys = { path = "binaryninjacore-sys" } thiserror = "2.0" +# Parts of the collaboration and workflow APIs consume and produce JSON. +serde_json = "1.0" [dev-dependencies] rstest = "0.24" diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs index 7b5828efe2..c1ad66786c 100644 --- a/rust/src/collaboration/remote.rs +++ b/rust/src/collaboration/remote.rs @@ -1,15 +1,17 @@ +use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser}; use binaryninjacore_sys::*; +use std::env::VarError; use std::ffi::c_void; use std::ptr::NonNull; -use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser}; - use crate::binary_view::BinaryView; use crate::database::Database; use crate::enterprise; use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; +use crate::secrets_provider::CoreSecretsProvider; +use crate::settings::Settings; use crate::string::{BnString, IntoCStr}; #[repr(transparent)] @@ -185,20 +187,22 @@ impl Remote { /// Use [Remote::connect_with_opts] if you cannot otherwise automatically connect using enterprise. /// /// WARNING: This is currently **not** thread safe, if you try and connect/disconnect to a remote on - /// multiple threads you will be subject to race conditions. To avoid this wrap the [`Remote`] in - /// a synchronization primitive, and pass that to your threads. Or don't try and connect on multiple threads. + /// multiple threads, you will be subject to race conditions. To avoid this, wrap the [`Remote`] in + /// a synchronization primitive and pass that to your threads. Or don't try and connect on multiple threads. pub fn connect(&self) -> Result<(), ()> { - // TODO: implement SecretsProvider if self.is_enterprise()? && enterprise::is_server_authenticated() { self.connect_with_opts(ConnectionOptions::from_enterprise()?) } else { - // TODO: Make this error instead. - let username = - std::env::var("BN_ENTERPRISE_USERNAME").expect("No username for connection!"); - let password = - std::env::var("BN_ENTERPRISE_PASSWORD").expect("No password for connection!"); - let connection_opts = ConnectionOptions::new_with_password(username, password); - self.connect_with_opts(connection_opts) + // Try to load from env vars. + match ConnectionOptions::from_env_variables() { + Ok(connection_opts) => self.connect_with_opts(connection_opts), + Err(_) => { + // Try to load from the enterprise secrets provider. + let secrets_connection_opts = + ConnectionOptions::from_secrets_provider(&self.address())?; + self.connect_with_opts(secrets_connection_opts) + } + } } } @@ -870,11 +874,31 @@ impl ConnectionOptions { // TODO: Check if enterprise is initialized and error if not. let username = enterprise::server_username(); let token = enterprise::server_token(); + Ok(Self::new_with_token(username, token)) + } + + /// Retrieves the [`ConnectionOptions`] for the given address. + /// + /// NOTE: Uses the secret's provider specified by the setting "enterprise.secretsProvider". + pub fn from_secrets_provider(address: &str) -> Result { + let secrets_provider_name = Settings::new().get_string("enterprise.secretsProvider"); + let provider = CoreSecretsProvider::by_name(&secrets_provider_name).ok_or(())?; + let cred_data_str = provider.get_data(address); + if cred_data_str.is_empty() { + return Err(()); + } + let cred_data: serde_json::Value = serde_json::from_str(&cred_data_str).map_err(|_| ())?; + let username = cred_data["username"].as_str().ok_or(())?; + let token = cred_data["token"].as_str().ok_or(())?; Ok(Self::new_with_token( username.to_string(), token.to_string(), )) } - // TODO: from_secrets_provider + pub fn from_env_variables() -> Result { + let username = std::env::var("BN_ENTERPRISE_USERNAME")?; + let password = std::env::var("BN_ENTERPRISE_PASSWORD")?; + Ok(ConnectionOptions::new_with_password(username, password)) + } } diff --git a/rust/tests/data_buffer.rs b/rust/tests/data_buffer.rs index 8480ae71c5..1e095d1952 100644 --- a/rust/tests/data_buffer.rs +++ b/rust/tests/data_buffer.rs @@ -13,7 +13,7 @@ fn get_slice() { #[test] fn set_len_write() { let mut data = DataBuffer::default(); - assert_eq!(data.get_data(), &[]); + assert!(data.get_data().is_empty()); unsafe { data.set_len(DUMMY_DATA_0.len()) }; assert_eq!(data.len(), DUMMY_DATA_0.len()); let mut contents = DUMMY_DATA_0.to_vec(); @@ -29,7 +29,7 @@ fn set_len_write() { assert_eq!(data.get_data(), &DUMMY_DATA_0[..13]); data.clear(); - assert_eq!(data.get_data(), &[]); + assert!(data.get_data().is_empty()); } #[test] From 0ab675c0643d85bc18e27ed5f88d1ffbc624b9bc Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 21:56:06 -0400 Subject: [PATCH 35/54] [Rust] Misc cleanup --- rust/src/logger.rs | 19 +++++++------------ rust/tests/collaboration.rs | 7 ------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/rust/src/logger.rs b/rust/src/logger.rs index ad6bd9d167..2735dd2f4b 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -35,10 +35,10 @@ use binaryninjacore_sys::{ }; use crate::rc::{Ref, RefCountable}; -use crate::string::{BnString, IntoCStr}; +use crate::string::{raw_to_string, BnString, IntoCStr}; use log; use log::LevelFilter; -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::os::raw::{c_char, c_void}; use std::ptr::NonNull; @@ -138,7 +138,6 @@ impl log::Log for Ref { }; if let Ok(msg) = CString::new(format!("{}", record.args())) { - let percent_s = CString::new("%s").expect("'%s' has no null bytes"); let logger_name = self.name().to_cstr(); unsafe { BNLog( @@ -146,7 +145,7 @@ impl log::Log for Ref { level, logger_name.as_ptr(), 0, - percent_s.as_ptr(), + c"%s".as_ptr(), msg.as_ptr(), ); } @@ -160,7 +159,7 @@ unsafe impl Send for Logger {} unsafe impl Sync for Logger {} pub trait LogListener: 'static + Sync { - fn log(&self, session: usize, level: Level, msg: &CStr, logger_name: &CStr, tid: usize); + fn log(&self, session: usize, level: Level, msg: &str, logger_name: &str, tid: usize); fn level(&self) -> Level; fn close(&self) {} } @@ -220,13 +219,9 @@ extern "C" fn cb_log( { ffi_wrap!("LogListener::log", unsafe { let listener = &*(ctxt as *const L); - listener.log( - session, - level, - CStr::from_ptr(msg), - CStr::from_ptr(logger_name), - tid, - ); + let msg_str = raw_to_string(msg).unwrap(); + let logger_name_str = raw_to_string(logger_name).unwrap(); + listener.log(session, level, &msg_str, &logger_name_str, tid); }) } diff --git a/rust/tests/collaboration.rs b/rust/tests/collaboration.rs index 3526a6f807..85f8702e2a 100644 --- a/rust/tests/collaboration.rs +++ b/rust/tests/collaboration.rs @@ -20,13 +20,6 @@ fn temp_project_scope(remote: &Remote, project_name: &str // TODO: have connected by the time this errors out. Maybe? let _ = remote.connect(); } - - if let Ok(home_dir) = env::var("HOME").or_else(|_| env::var("USERPROFILE")) { - eprintln!("Current user directory: {}", home_dir); - } else { - eprintln!("Unable to determine the current user directory."); - } - let project = remote .create_project(project_name, "Test project for test purposes") .expect("Failed to create project"); From 754e7434e2863470a9f5a58fbd08d056c2ea6a8b Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 23:09:10 -0400 Subject: [PATCH 36/54] [Rust] Interaction handler API fixes --- rust/src/interaction/handler.rs | 56 +++++++++++++++++++++------------ rust/src/interaction/report.rs | 11 ++++--- rust/tests/interaction.rs | 9 ++++-- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/rust/src/interaction/handler.rs b/rust/src/interaction/handler.rs index 23ca66e4f3..f854f612f5 100644 --- a/rust/src/interaction/handler.rs +++ b/rust/src/interaction/handler.rs @@ -53,13 +53,13 @@ pub trait InteractionHandler: Sync + Send + 'static { task: &InteractionHandlerTask, ) -> bool; - fn show_plain_text_report(&mut self, view: &BinaryView, title: &str, contents: &str); + fn show_plain_text_report(&mut self, view: Option<&BinaryView>, title: &str, contents: &str); - fn show_graph_report(&mut self, view: &BinaryView, title: &str, graph: &FlowGraph); + fn show_graph_report(&mut self, view: Option<&BinaryView>, title: &str, graph: &FlowGraph); fn show_markdown_report( &mut self, - view: &BinaryView, + view: Option<&BinaryView>, title: &str, _contents: &str, plain_text: &str, @@ -69,7 +69,7 @@ pub trait InteractionHandler: Sync + Send + 'static { fn show_html_report( &mut self, - view: &BinaryView, + view: Option<&BinaryView>, title: &str, _contents: &str, plain_text: &str, @@ -80,24 +80,28 @@ pub trait InteractionHandler: Sync + Send + 'static { fn show_report_collection(&mut self, _title: &str, reports: &ReportCollection) { for report in reports { match &report { - Report::PlainText(rpt) => { - self.show_plain_text_report(&report.view(), &report.title(), &rpt.contents()) - } + Report::PlainText(rpt) => self.show_plain_text_report( + report.view().as_deref(), + &report.title(), + &rpt.contents(), + ), Report::Markdown(rm) => self.show_markdown_report( - &report.view(), + report.view().as_deref(), &report.title(), &rm.contents(), &rm.plaintext(), ), Report::Html(rh) => self.show_html_report( - &report.view(), + report.view().as_deref(), &report.title(), &rh.contents(), &rh.plaintext(), ), - Report::FlowGraph(rfg) => { - self.show_graph_report(&report.view(), &report.title(), &rfg.flow_graph()) - } + Report::FlowGraph(rfg) => self.show_graph_report( + report.view().as_deref(), + &report.title(), + &rfg.flow_graph(), + ), } } } @@ -292,7 +296,11 @@ unsafe extern "C" fn cb_show_plain_text_report( let ctxt = ctxt as *mut R; let title = raw_to_string(title).unwrap(); let contents = raw_to_string(contents).unwrap(); - (*ctxt).show_plain_text_report(&BinaryView::from_raw(view), &title, &contents) + let view = match !view.is_null() { + true => Some(BinaryView::from_raw(view)), + false => None, + }; + (*ctxt).show_plain_text_report(view.as_ref(), &title, &contents) } unsafe extern "C" fn cb_show_markdown_report( @@ -306,7 +314,11 @@ unsafe extern "C" fn cb_show_markdown_report( let title = raw_to_string(title).unwrap(); let contents = raw_to_string(contents).unwrap(); let plaintext = raw_to_string(plaintext).unwrap(); - (*ctxt).show_markdown_report(&BinaryView::from_raw(view), &title, &contents, &plaintext) + let view = match !view.is_null() { + true => Some(BinaryView::from_raw(view)), + false => None, + }; + (*ctxt).show_markdown_report(view.as_ref(), &title, &contents, &plaintext) } unsafe extern "C" fn cb_show_html_report( @@ -320,7 +332,11 @@ unsafe extern "C" fn cb_show_html_report( let title = raw_to_string(title).unwrap(); let contents = raw_to_string(contents).unwrap(); let plaintext = raw_to_string(plaintext).unwrap(); - (*ctxt).show_html_report(&BinaryView::from_raw(view), &title, &contents, &plaintext) + let view = match !view.is_null() { + true => Some(BinaryView::from_raw(view)), + false => None, + }; + (*ctxt).show_html_report(view.as_ref(), &title, &contents, &plaintext) } unsafe extern "C" fn cb_show_graph_report( @@ -331,11 +347,11 @@ unsafe extern "C" fn cb_show_graph_report( ) { let ctxt = ctxt as *mut R; let title = raw_to_string(title).unwrap(); - (*ctxt).show_graph_report( - &BinaryView::from_raw(view), - &title, - &FlowGraph::from_raw(graph), - ) + let view = match !view.is_null() { + true => Some(BinaryView::from_raw(view)), + false => None, + }; + (*ctxt).show_graph_report(view.as_ref(), &title, &FlowGraph::from_raw(graph)) } unsafe extern "C" fn cb_show_report_collection( diff --git a/rust/src/interaction/report.rs b/rust/src/interaction/report.rs index a20d8f1f8e..689b815bb5 100644 --- a/rust/src/interaction/report.rs +++ b/rust/src/interaction/report.rs @@ -46,9 +46,12 @@ impl ReportCollection { Report::new(self, i) } - fn view(&self, i: usize) -> Ref { + fn view(&self, i: usize) -> Option> { let raw = unsafe { BNGetReportView(self.handle.as_ptr(), i) }; - unsafe { BinaryView::ref_from_raw(raw) } + if raw.is_null() { + return None; + } + Some(unsafe { BinaryView::ref_from_raw(raw) }) } fn title(&self, i: usize) -> String { @@ -190,7 +193,7 @@ impl<'a> Report<'a> { } } - pub fn view(&self) -> Ref { + pub fn view(&self) -> Option> { self._inner().view() } @@ -253,7 +256,7 @@ impl ReportInner<'_> { self.collection.report_type(self.index) } - fn view(&self) -> Ref { + fn view(&self) -> Option> { self.collection.view(self.index) } diff --git a/rust/tests/interaction.rs b/rust/tests/interaction.rs index eea906ecfd..5e9606b099 100644 --- a/rust/tests/interaction.rs +++ b/rust/tests/interaction.rs @@ -36,11 +36,16 @@ impl InteractionHandler for MyInteractionHandler { todo!() } - fn show_plain_text_report(&mut self, _view: &BinaryView, _title: &str, _contents: &str) { + fn show_plain_text_report( + &mut self, + _view: Option<&BinaryView>, + _title: &str, + _contents: &str, + ) { todo!() } - fn show_graph_report(&mut self, _view: &BinaryView, _title: &str, _graph: &FlowGraph) { + fn show_graph_report(&mut self, _view: Option<&BinaryView>, _title: &str, _graph: &FlowGraph) { todo!() } From c185a099d1341254088d8bcd81a7ee26d3c6c61e Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sat, 10 May 2025 23:09:22 -0400 Subject: [PATCH 37/54] [Rust] Flowgraph API improvements --- rust/examples/flowgraph.rs | 15 +++--- rust/src/flowgraph.rs | 103 +++++++++++++++++++++++++++++++++---- 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/rust/examples/flowgraph.rs b/rust/examples/flowgraph.rs index 515d52fe0e..ce91d62f93 100644 --- a/rust/examples/flowgraph.rs +++ b/rust/examples/flowgraph.rs @@ -15,7 +15,7 @@ use binaryninja::{ pub struct GraphPrinter; impl GraphPrinter { - pub fn print_graph(&self, _view: &BinaryView, graph: &FlowGraph) { + pub fn print_graph(&self, graph: &FlowGraph) { println!("Printing flow graph:"); for node in &graph.nodes() { // Print all disassembly lines in the node @@ -60,16 +60,16 @@ impl InteractionHandler for GraphPrinter { false } - fn show_plain_text_report(&mut self, _view: &BinaryView, title: &str, contents: &str) { + fn show_plain_text_report(&mut self, _view: Option<&BinaryView>, title: &str, contents: &str) { println!("Plain text report"); println!("Title: {}", title); println!("Contents: {}", contents); } - fn show_graph_report(&mut self, view: &BinaryView, title: &str, graph: &FlowGraph) { + fn show_graph_report(&mut self, _view: Option<&BinaryView>, title: &str, graph: &FlowGraph) { println!("Graph report"); println!("Title: {}", title); - self.print_graph(view, graph); + self.print_graph(graph); } fn get_form_input(&mut self, _form: &mut Form) -> bool { @@ -77,7 +77,7 @@ impl InteractionHandler for GraphPrinter { } } -fn test_graph(view: &BinaryView) { +fn test_graph() { let graph = FlowGraph::new(); let disassembly_lines_a = vec![DisassemblyTextLine::new(vec![ @@ -110,7 +110,7 @@ fn test_graph(view: &BinaryView) { EdgeStyle::default(), ); - view.show_graph_report("Rust Graph Title", &graph); + graph.show("Rust Example Graph"); } fn main() { @@ -127,10 +127,11 @@ fn main() { // Register the interaction handler so we can see the graph report headlessly. register_interaction_handler(GraphPrinter); - test_graph(&bv); + test_graph(); for func in bv.functions().iter().take(5) { let graph = func.create_graph(FunctionViewType::MediumLevelIL, None); + // TODO: Why are the nodes empty? Python its empty until its shown... assert!(!graph.nodes().is_empty()); let func_name = func.symbol().short_name(); let title = func_name.to_string_lossy(); diff --git a/rust/src/flowgraph.rs b/rust/src/flowgraph.rs index f0b34853e0..2d1d986ca3 100644 --- a/rust/src/flowgraph.rs +++ b/rust/src/flowgraph.rs @@ -25,6 +25,9 @@ use crate::render_layer::CoreRenderLayer; pub mod edge; pub mod node; +use crate::binary_view::BinaryView; +use crate::function::Function; +use crate::string::IntoCStr; pub use edge::EdgeStyle; pub use edge::FlowGraphEdge; pub use node::FlowGraphNode; @@ -52,38 +55,101 @@ impl FlowGraph { unsafe { FlowGraph::ref_from_raw(BNCreateFlowGraph()) } } + pub fn has_updates(&self) -> bool { + let query_mode = unsafe { BNFlowGraphUpdateQueryMode(self.handle) }; + match query_mode { + true => unsafe { BNFlowGraphHasUpdates(self.handle) }, + false => false, + } + } + + pub fn update(&self) -> Option> { + let new_graph = unsafe { BNUpdateFlowGraph(self.handle) }; + if new_graph.is_null() { + return None; + } + Some(unsafe { FlowGraph::ref_from_raw(new_graph) }) + } + + pub fn show(&self, title: &str) { + let raw_title = title.to_cstr(); + match self.view() { + None => unsafe { + BNShowGraphReport(std::ptr::null_mut(), raw_title.as_ptr(), self.handle); + }, + Some(view) => unsafe { + BNShowGraphReport(view.handle, raw_title.as_ptr(), self.handle); + }, + } + } + + /// Whether flow graph layout is complete. + pub fn is_layout_complete(&self) -> bool { + unsafe { BNIsFlowGraphLayoutComplete(self.handle) } + } + pub fn nodes(&self) -> Array { let mut count: usize = 0; let nodes_ptr = unsafe { BNGetFlowGraphNodes(self.handle, &mut count as *mut usize) }; unsafe { Array::new(nodes_ptr, count, ()) } } - pub fn low_level_il(&self) -> Result, ()> { + pub fn function(&self) -> Option> { + unsafe { + let func_ptr = BNGetFunctionForFlowGraph(self.handle); + match func_ptr.is_null() { + false => Some(Function::ref_from_raw(func_ptr)), + true => None, + } + } + } + + pub fn set_function(&self, func: Option<&Function>) { + let func_ptr = func.map(|f| f.handle).unwrap_or(std::ptr::null_mut()); + unsafe { BNSetFunctionForFlowGraph(self.handle, func_ptr) } + } + + pub fn view(&self) -> Option> { + unsafe { + let view_ptr = BNGetViewForFlowGraph(self.handle); + match view_ptr.is_null() { + false => Some(BinaryView::ref_from_raw(view_ptr)), + true => None, + } + } + } + + pub fn set_view(&self, view: Option<&BinaryView>) { + let view_ptr = view.map(|v| v.handle).unwrap_or(std::ptr::null_mut()); + unsafe { BNSetViewForFlowGraph(self.handle, view_ptr) } + } + + pub fn low_level_il(&self) -> Option> { unsafe { let llil_ptr = BNGetFlowGraphLowLevelILFunction(self.handle); match llil_ptr.is_null() { - false => Ok(LowLevelILRegularFunction::ref_from_raw(llil_ptr)), - true => Err(()), + false => Some(LowLevelILRegularFunction::ref_from_raw(llil_ptr)), + true => None, } } } - pub fn medium_level_il(&self) -> Result, ()> { + pub fn medium_level_il(&self) -> Option> { unsafe { let mlil_ptr = BNGetFlowGraphMediumLevelILFunction(self.handle); match mlil_ptr.is_null() { - false => Ok(MediumLevelILFunction::ref_from_raw(mlil_ptr)), - true => Err(()), + false => Some(MediumLevelILFunction::ref_from_raw(mlil_ptr)), + true => None, } } } - pub fn high_level_il(&self, full_ast: bool) -> Result, ()> { + pub fn high_level_il(&self, full_ast: bool) -> Option> { unsafe { let hlil_ptr = BNGetFlowGraphHighLevelILFunction(self.handle); match hlil_ptr.is_null() { - false => Ok(HighLevelILFunction::ref_from_raw(hlil_ptr, full_ast)), - true => Err(()), + false => Some(HighLevelILFunction::ref_from_raw(hlil_ptr, full_ast)), + true => None, } } } @@ -105,6 +171,25 @@ impl FlowGraph { unsafe { BNFlowGraphHasNodes(self.handle) } } + /// Returns the graph size in width, height form. + pub fn size(&self) -> (i32, i32) { + let width = unsafe { BNGetFlowGraphWidth(self.handle) }; + let height = unsafe { BNGetFlowGraphHeight(self.handle) }; + (width, height) + } + + /// Returns the graph margins between nodes. + pub fn node_margins(&self) -> (i32, i32) { + let horizontal = unsafe { BNGetHorizontalFlowGraphNodeMargin(self.handle) }; + let vertical = unsafe { BNGetVerticalFlowGraphNodeMargin(self.handle) }; + (horizontal, vertical) + } + + /// Sets the graph margins between nodes. + pub fn set_node_margins(&self, horizontal: i32, vertical: i32) { + unsafe { BNSetFlowGraphNodeMargins(self.handle, horizontal, vertical) }; + } + pub fn append(&self, node: &FlowGraphNode) -> usize { unsafe { BNAddFlowGraphNode(self.handle, node.handle) } } From e371b4a8dfc07c53f9a6758d126071fb6d214610 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Sun, 11 May 2025 07:04:35 -0700 Subject: [PATCH 38/54] [Rust] Don't panic when a Rust plug-in encounters an unhandled MLIL instruction `MediumLevelILInstruction` does not yet handle `MLIL_CALL_OUTPUT`, `MLIL_CALL_PARAM`, `MLIL_CALL_PARAM_SSA`, `MLIL_CALL_OUTPUT_SSA`, `MLIL_MEMORY_INTRINSIC_OUTPUT_SSA`, or `MLIL_MEMORY_INTRINSIC_SSA`. Map these to a `NotYetImplemented` kind rather than panicking since a panic takes down the entire app. --- rust/src/medium_level_il/instruction.rs | 8 +++++--- rust/src/medium_level_il/lift.rs | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index 5e20147818..ae550d91e0 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -609,9 +609,7 @@ impl MediumLevelILInstruction { | MLIL_CALL_PARAM_SSA | MLIL_CALL_OUTPUT_SSA | MLIL_MEMORY_INTRINSIC_OUTPUT_SSA - | MLIL_MEMORY_INTRINSIC_SSA => { - unimplemented!() - } + | MLIL_MEMORY_INTRINSIC_SSA => Op::NotYetImplemented, }; Self { @@ -633,6 +631,7 @@ impl MediumLevelILInstruction { Bp => Lifted::Bp, Undef => Lifted::Undef, Unimpl => Lifted::Unimpl, + NotYetImplemented => Lifted::NotYetImplemented, If(op) => Lifted::If(LiftedIf { condition: self.lift_operand(op.condition), dest_true: op.dest_true, @@ -1629,6 +1628,9 @@ pub enum MediumLevelILInstructionKind { VarSsaField(VarSsaField), VarAliasedField(VarSsaField), Trap(Trap), + // A placeholder for instructions that the Rust bindings do not yet support. + // Distinct from `Unimpl` as that is a valid instruction. + NotYetImplemented, } fn get_float(value: u64, size: usize) -> f64 { diff --git a/rust/src/medium_level_il/lift.rs b/rust/src/medium_level_il/lift.rs index 3f16148477..f5ee45b345 100644 --- a/rust/src/medium_level_il/lift.rs +++ b/rust/src/medium_level_il/lift.rs @@ -175,6 +175,9 @@ pub enum MediumLevelILLiftedInstructionKind { VarSsaField(VarSsaField), VarAliasedField(VarSsaField), Trap(Trap), + // A placeholder for instructions that the Rust bindings do not yet support. + // Distinct from `Unimpl` as that is a valid instruction. + NotYetImplemented, } impl MediumLevelILLiftedInstruction { @@ -186,6 +189,7 @@ impl MediumLevelILLiftedInstruction { Bp => "Bp", Undef => "Undef", Unimpl => "Unimpl", + NotYetImplemented => "NotYetImplemented", If(_) => "If", FloatConst(_) => "FloatConst", Const(_) => "Const", @@ -318,7 +322,7 @@ impl MediumLevelILLiftedInstruction { use MediumLevelILLiftedInstructionKind::*; use MediumLevelILLiftedOperand as Operand; match &self.kind { - Nop | Noret | Bp | Undef | Unimpl => vec![], + Nop | Noret | Bp | Undef | Unimpl | NotYetImplemented => vec![], If(op) => vec![ ("condition", Operand::Expr(*op.condition.clone())), ("dest_true", Operand::InstructionIndex(op.dest_true)), From 586d31ede90c42f5e10e5b17270ed6a98829842e Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 11 May 2025 15:14:28 -0400 Subject: [PATCH 39/54] [Rust] Remove useless alias function --- rust/src/function.rs | 4 ++-- rust/src/medium_level_il/instruction.rs | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/rust/src/function.rs b/rust/src/function.rs index ec859f7e31..58b310c745 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -2154,7 +2154,7 @@ impl Function { /// Splits a variable at the definition site. The given `var` must be the /// variable unique to the definition and should be obtained by using - /// [crate::medium_level_il::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. + /// [crate::medium_level_il::MediumLevelILInstruction::split_var_for_definition] at the definition site. /// /// This function is not meant to split variables that have been previously merged. Use /// [Function::unmerge_variables] to split previously merged variables. @@ -2177,7 +2177,7 @@ impl Function { /// Undoes variable splitting performed with [Function::split_variable]. The given `var` /// must be the variable unique to the definition and should be obtained by using - /// [crate::medium_level_il::MediumLevelILInstruction::get_split_var_for_definition] at the definition site. + /// [crate::medium_level_il::MediumLevelILInstruction::split_var_for_definition] at the definition site. /// /// * `var` - variable to unsplit pub fn unsplit_variable(&self, var: &Variable) { diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index ae550d91e0..b043788d79 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -1376,12 +1376,6 @@ impl MediumLevelILInstruction { Variable::new(var.ty, index, var.storage) } - /// alias for [MediumLevelILInstruction::split_var_for_definition] - #[inline] - pub fn get_split_var_for_definition(&self, var: &Variable) -> Variable { - self.split_var_for_definition(var) - } - fn lift_operand(&self, expr_idx: usize) -> Box { // TODO: UGH, if your gonna call it expr_idx, call the instruction and expression!!!!! // TODO: We dont even need to say instruction in the type! From 2465223d29e4088c2adac36e57c9941ba2c706ab Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 11 May 2025 16:16:11 -0400 Subject: [PATCH 40/54] [Rust] Check lifted call for params and output in mlil test --- rust/tests/medium_level_il.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rust/tests/medium_level_il.rs b/rust/tests/medium_level_il.rs index 544076ccae..7f73cde303 100644 --- a/rust/tests/medium_level_il.rs +++ b/rust/tests/medium_level_il.rs @@ -1,6 +1,6 @@ use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; -use binaryninja::medium_level_il::{MediumLevelILInstructionKind, MediumLevelInstructionIndex}; +use binaryninja::medium_level_il::{MediumLevelILInstructionKind, MediumLevelILLiftedInstructionKind, MediumLevelInstructionIndex}; use std::path::PathBuf; #[test] @@ -68,6 +68,14 @@ fn test_mlil_info() { } _ => panic!("Expected Call"), } + match instr_3.lift().kind { + MediumLevelILLiftedInstructionKind::Call(lifted_call) => { + assert_eq!(lifted_call.dest.index, MediumLevelInstructionIndex(7)); + assert_eq!(lifted_call.output.len(), 1); + assert_eq!(lifted_call.params.len(), 1); + } + _ => panic!("Expected Call"), + } // 4 @ 00025f22 (MLIL_RET return (MLIL_VAR.d eax_1)) let instr_4 = mlil_instr_iter.next().unwrap(); assert_eq!(instr_4.expr_index, MediumLevelInstructionIndex(13)); From e52bba6c00320eb1bdb116bae79d1d20cca015ed Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 11 May 2025 16:16:30 -0400 Subject: [PATCH 41/54] [Rust] Remove extra assert in flowgraph example --- rust/examples/flowgraph.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust/examples/flowgraph.rs b/rust/examples/flowgraph.rs index ce91d62f93..ede7ce84af 100644 --- a/rust/examples/flowgraph.rs +++ b/rust/examples/flowgraph.rs @@ -130,9 +130,8 @@ fn main() { test_graph(); for func in bv.functions().iter().take(5) { - let graph = func.create_graph(FunctionViewType::MediumLevelIL, None); // TODO: Why are the nodes empty? Python its empty until its shown... - assert!(!graph.nodes().is_empty()); + let graph = func.create_graph(FunctionViewType::MediumLevelIL, None); let func_name = func.symbol().short_name(); let title = func_name.to_string_lossy(); bv.show_graph_report(&title, &graph); From 8d791ae10d899439bd29c613fae09dfdc13547e7 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 11 May 2025 21:00:24 -0400 Subject: [PATCH 42/54] [Rust] Simplify operand list retrieval for MLIL and HLIL --- rust/src/high_level_il/instruction.rs | 127 ++++++++--- rust/src/lib.rs | 1 - rust/src/medium_level_il/instruction.rs | 269 ++++++++++++++++-------- rust/src/operand_iter.rs | 237 --------------------- rust/tests/medium_level_il.rs | 4 +- 5 files changed, 276 insertions(+), 362 deletions(-) delete mode 100644 rust/src/operand_iter.rs diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs index 00900de716..67225eea15 100644 --- a/rust/src/high_level_il/instruction.rs +++ b/rust/src/high_level_il/instruction.rs @@ -7,7 +7,6 @@ use super::{HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLifted use crate::architecture::{CoreIntrinsic, IntrinsicId}; use crate::confidence::Conf; use crate::disassembly::DisassemblyTextLine; -use crate::operand_iter::OperandIter; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::types::Type; use crate::variable::{ConstantData, RegisterValue, SSAVariable, Variable}; @@ -552,6 +551,38 @@ impl HighLevelILInstruction { } } + fn get_operand_list(&self, operand_idx: usize) -> Vec { + let mut count = 0; + let raw_list_ptr = unsafe { + BNHighLevelILGetOperandList( + self.function.handle, + self.expr_index.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNHighLevelILFreeOperandList(raw_list_ptr) }; + list + } + + fn get_ssa_var_list(&self, operand_idx: usize) -> Vec { + self.get_operand_list(operand_idx) + .chunks(2) + .map(|chunk| (Variable::from_identifier(chunk[0]), chunk[1] as usize)) + .map(|(var, version)| SSAVariable::new(var, version)) + .collect() + } + + fn get_expr_list(&self, operand_idx: usize) -> Vec { + self.get_operand_list(operand_idx) + .into_iter() + .map(|val| HighLevelInstructionIndex(val as usize)) + .filter_map(|idx| self.function.instruction_from_expr_index(idx)) + .collect() + } + pub fn lift(&self) -> HighLevelILLiftedInstruction { use HighLevelILInstructionKind::*; use HighLevelILLiftedInstructionKind as Lifted; @@ -630,7 +661,11 @@ impl HighLevelILInstruction { src: self.lift_operand(op.src), }), AssignUnpack(op) => Lifted::AssignUnpack(LiftedAssignUnpack { - dest: self.lift_instruction_list(op.first_dest, op.num_dests), + dest: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), src: self.lift_operand(op.src), }), AssignMemSsa(op) => Lifted::AssignMemSsa(LiftedAssignMemSsa { @@ -640,26 +675,42 @@ impl HighLevelILInstruction { src_memory: op.src_memory, }), AssignUnpackMemSsa(op) => Lifted::AssignUnpackMemSsa(LiftedAssignUnpackMemSsa { - dest: self.lift_instruction_list(op.first_dest, op.num_dests), + dest: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src: self.lift_operand(op.src), src_memory: op.src_memory, }), - Block(op) => Lifted::Block(LiftedBlock { - body: self.lift_instruction_list(op.first_param, op.num_params), + Block(_op) => Lifted::Block(LiftedBlock { + body: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), Call(op) => Lifted::Call(self.lift_call(op)), Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), CallSsa(op) => Lifted::CallSsa(LiftedCallSsa { dest: self.lift_operand(op.dest), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), Case(op) => Lifted::Case(LiftedCase { - values: self.lift_instruction_list(op.first_value, op.num_values), + values: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), body: self.lift_operand(op.body), }), Const(op) => Lifted::Const(op), @@ -740,7 +791,11 @@ impl HighLevelILInstruction { IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { intrinsic: CoreIntrinsic::new( @@ -748,7 +803,11 @@ impl HighLevelILInstruction { IntrinsicId(op.intrinsic), ) .expect("Invalid intrinsic"), - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(1) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), @@ -757,10 +816,14 @@ impl HighLevelILInstruction { }), MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_src, op.num_srcs).collect(), + src: self.get_operand_list(1), }), - Ret(op) => Lifted::Ret(LiftedRet { - src: self.lift_instruction_list(op.first_src, op.num_srcs), + Ret(_op) => Lifted::Ret(LiftedRet { + src: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), Split(op) => Lifted::Split(LiftedSplit { high: self.lift_operand(op.high), @@ -771,13 +834,25 @@ impl HighLevelILInstruction { Switch(op) => Lifted::Switch(LiftedSwitch { condition: self.lift_operand(op.condition), default: self.lift_operand(op.default), - cases: self.lift_instruction_list(op.first_case, op.num_cases), + cases: self + .get_expr_list(2) + .iter() + .map(|expr| expr.lift()) + .collect(), }), - Syscall(op) => Lifted::Syscall(LiftedSyscall { - params: self.lift_instruction_list(op.first_param, op.num_params), + Syscall(_op) => Lifted::Syscall(LiftedSyscall { + params: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), }), SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { - params: self.lift_instruction_list(op.first_param, op.num_params), + params: self + .get_expr_list(0) + .iter() + .map(|expr| expr.lift()) + .collect(), dest_memory: op.dest_memory, src_memory: op.src_memory, }), @@ -794,9 +869,7 @@ impl HighLevelILInstruction { }), VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_src, op.num_srcs) - .ssa_vars() - .collect(), + src: self.get_ssa_var_list(2), }), VarSsa(op) => Lifted::VarSsa(op), @@ -907,8 +980,9 @@ impl HighLevelILInstruction { fn lift_call(&self, op: Call) -> LiftedCall { LiftedCall { dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(1) + .iter() .map(|expr| expr.lift()) .collect(), } @@ -936,17 +1010,6 @@ impl HighLevelILInstruction { member_index: op.member_index, } } - - fn lift_instruction_list( - &self, - first_instruction: usize, - num_instructions: usize, - ) -> Vec { - OperandIter::new(&*self.function, first_instruction, num_instructions) - .exprs() - .map(|expr| expr.lift()) - .collect() - } } impl CoreArrayProvider for HighLevelILInstruction { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 80baae4386..05c0107727 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -26,7 +26,6 @@ #[macro_use] mod ffi; -mod operand_iter; pub mod architecture; pub mod background_task; diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index b043788d79..065e28f177 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -621,6 +621,54 @@ impl MediumLevelILInstruction { } } + fn get_operand_list(&self, operand_idx: usize) -> Vec { + let mut count = 0; + let raw_list_ptr = unsafe { + BNMediumLevelILGetOperandList( + self.function.handle, + self.expr_index.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNMediumLevelILFreeOperandList(raw_list_ptr) }; + list + } + + fn get_var_list(&self, operand_idx: usize) -> Vec { + self.get_operand_list(operand_idx) + .into_iter() + .map(Variable::from_identifier) + .collect() + } + + fn get_ssa_var_list(&self, operand_idx: usize) -> Vec { + self.get_operand_list(operand_idx) + .chunks(2) + .map(|chunk| (Variable::from_identifier(chunk[0]), chunk[1] as usize)) + .map(|(var, version)| SSAVariable::new(var, version)) + .collect() + } + + fn get_expr_list(&self, operand_idx: usize) -> Vec { + self.get_operand_list(operand_idx) + .into_iter() + .map(|val| MediumLevelInstructionIndex(val as usize)) + .filter_map(|idx| self.function.instruction_from_expr_index(idx)) + .collect() + } + + fn get_target_map(&self, operand_idx: usize) -> BTreeMap { + self.get_operand_list(operand_idx) + .chunks(2) + // TODO: This filter is kinda redundant. + .filter_map(|chunk| chunk.get(0..2)) + .map(|chunk| (chunk[0], MediumLevelInstructionIndex(chunk[1] as usize))) + .collect() + } + pub fn lift(&self) -> MediumLevelILLiftedInstruction { use MediumLevelILInstructionKind::*; use MediumLevelILLiftedInstructionKind as Lifted; @@ -690,12 +738,7 @@ impl MediumLevelILInstruction { }), JumpTo(op) => Lifted::JumpTo(LiftedJumpTo { dest: self.lift_operand(op.dest), - targets: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .pairs() - .map(|(addr, instr_idx)| { - (addr, MediumLevelInstructionIndex(instr_idx as usize)) - }) - .collect(), + targets: self.get_target_map(1), }), Goto(op) => Lifted::Goto(op), FreeVarSlot(op) => Lifted::FreeVarSlot(op), @@ -732,14 +775,12 @@ impl MediumLevelILInstruction { }), VarPhi(op) => Lifted::VarPhi(LiftedVarPhi { dest: op.dest, - src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .ssa_vars() - .collect(), + src: self.get_ssa_var_list(2), }), MemPhi(op) => Lifted::MemPhi(LiftedMemPhi { dest_memory: op.dest_memory, - src_memory: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .collect(), + // TODO: Make a stronger type for this. + src_memory: self.get_operand_list(0), }), VarSplit(op) => Lifted::VarSplit(op), SetVarSplit(op) => Lifted::SetVarSplit(LiftedSetVarSplit { @@ -809,42 +850,59 @@ impl MediumLevelILInstruction { Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), + output: self.get_var_list(0), intrinsic: CoreIntrinsic::new( self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), }), - Syscall(op) => Lifted::Syscall(LiftedSyscallCall { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + Syscall(_op) => Lifted::Syscall(LiftedSyscallCall { + output: self.get_var_list(0), + params: self + .get_expr_list(2) + .iter() .map(|expr| expr.lift()) .collect(), }), IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .ssa_vars() + output: self.get_ssa_var_list(0), + intrinsic: CoreIntrinsic::new( + self.function.function().arch(), + IntrinsicId(op.intrinsic), + ) + .expect("Valid intrinsic"), + params: self + .get_expr_list(3) + .iter() + .map(|expr| expr.lift()) .collect(), + }), + MemoryIntrinsicSsa(op) => Lifted::MemoryIntrinsicSsa(LiftedMemoryIntrinsicSsa { + output: self.lift_operand(op.output), intrinsic: CoreIntrinsic::new( self.function.function().arch(), IntrinsicId(op.intrinsic), ) .expect("Valid intrinsic"), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), + src_memory: op.src_memory, }), + MemoryIntrinsicOutputSsa(op) => { + Lifted::MemoryIntrinsicOutputSsa(LiftedMemoryIntrinsicOutputSsa { + dest_memory: op.dest_memory, + output: self.get_ssa_var_list(1), + }) + } CallSsa(op) => Lifted::CallSsa(self.lift_call_ssa(op)), TailcallSsa(op) => Lifted::TailcallSsa(self.lift_call_ssa(op)), @@ -853,28 +911,46 @@ impl MediumLevelILInstruction { TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(self.lift_call_untyped_ssa(op)), SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: self + .get_expr_list(1) + .iter() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, }), SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(LiftedSyscallUntypedSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), - params: get_call_params_ssa(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: get_call_params_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), }), CallUntyped(op) => Lifted::CallUntyped(self.lift_call_untyped(op)), TailcallUntyped(op) => Lifted::TailcallUntyped(self.lift_call_untyped(op)), SyscallUntyped(op) => Lifted::SyscallUntyped(LiftedSyscallUntyped { - output: get_call_output(&self.function, op.output).collect(), - params: get_call_params(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + output: get_call_output(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), + params: get_call_params(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), }), @@ -910,21 +986,24 @@ impl MediumLevelILInstruction { src: self.lift_operand(op.src), src_memory: op.src_memory, }), - Ret(op) => Lifted::Ret(LiftedRet { - src: OperandIter::new(&*self.function, op.first_operand, op.num_operands) - .exprs() + Ret(_op) => Lifted::Ret(LiftedRet { + src: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), - SeparateParamList(op) => Lifted::SeparateParamList(LiftedSeparateParamList { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + SeparateParamList(_op) => Lifted::SeparateParamList(LiftedSeparateParamList { + params: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), - SharedParamSlot(op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + SharedParamSlot(_op) => Lifted::SharedParamSlot(LiftedSharedParamSlot { + params: self + .get_expr_list(0) + .iter() .map(|expr| expr.lift()) .collect(), }), @@ -1413,12 +1492,11 @@ impl MediumLevelILInstruction { fn lift_call(&self, op: Call) -> LiftedCall { LiftedCall { - output: OperandIter::new(&*self.function, op.first_output, op.num_outputs) - .vars() - .collect(), + output: self.get_var_list(0), dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(3) + .iter() .map(|expr| expr.lift()) .collect(), } @@ -1426,21 +1504,32 @@ impl MediumLevelILInstruction { fn lift_call_untyped(&self, op: CallUntyped) -> LiftedCallUntyped { LiftedCallUntyped { - output: get_call_output(&self.function, op.output).collect(), + output: get_call_output(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: get_call_params(&self.function, op.params) - .map(|expr| expr.lift()) - .collect(), + params: get_call_params(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|expr| expr.lift()) + .collect(), stack: self.lift_operand(op.stack), } } fn lift_call_ssa(&self, op: CallSsa) -> LiftedCallSsa { LiftedCallSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: OperandIter::new(&*self.function, op.first_param, op.num_params) - .exprs() + params: self + .get_expr_list(2) + .iter() .map(|expr| expr.lift()) .collect(), src_memory: op.src_memory, @@ -1449,11 +1538,18 @@ impl MediumLevelILInstruction { fn lift_call_untyped_ssa(&self, op: CallUntypedSsa) -> LiftedCallUntypedSsa { LiftedCallUntypedSsa { - output: get_call_output_ssa(&self.function, op.output).collect(), + output: get_call_output_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.output), + )), dest: self.lift_operand(op.dest), - params: get_call_params_ssa(&self.function, op.params) - .map(|param| param.lift()) - .collect(), + params: get_call_params_ssa(&MediumLevelILInstruction::new( + self.function.clone(), + MediumLevelInstructionIndex(op.params), + )) + .iter() + .map(|param| param.lift()) + .collect(), stack: self.lift_operand(op.stack), } } @@ -1636,10 +1732,6 @@ fn get_float(value: u64, size: usize) -> f64 { } } -fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction { - unsafe { BNGetMediumLevelILByIndex(function.handle, idx) } -} - fn get_var(id: u64) -> Variable { Variable::from_identifier(id) } @@ -1648,37 +1740,32 @@ fn get_var_ssa(id: u64, version: usize) -> SSAVariable { SSAVariable::new(get_var(id), version) } -fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> impl Iterator { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).vars() +fn get_call_output(instr: &MediumLevelILInstruction) -> Vec { + match instr.kind { + MediumLevelILInstructionKind::CallOutput(_op) => instr.get_var_list(0), + _ => vec![], + } } -fn get_call_params( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM); - OperandIter::new(function, op.operands[1] as usize, op.operands[0] as usize).exprs() +fn get_call_params(instr: &MediumLevelILInstruction) -> Vec { + match instr.kind { + MediumLevelILInstructionKind::CallParam(_op) => instr.get_expr_list(0), + _ => vec![], + } } -fn get_call_output_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).ssa_vars() +fn get_call_output_ssa(instr: &MediumLevelILInstruction) -> Vec { + match instr.kind { + MediumLevelILInstructionKind::CallOutputSsa(_op) => instr.get_ssa_var_list(1), + _ => vec![], + } } -fn get_call_params_ssa( - function: &MediumLevelILFunction, - idx: usize, -) -> impl Iterator { - let op = get_raw_operation(function, idx); - assert_eq!(op.operation, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA); - OperandIter::new(function, op.operands[2] as usize, op.operands[1] as usize).exprs() +fn get_call_params_ssa(instr: &MediumLevelILInstruction) -> Vec { + match instr.kind { + MediumLevelILInstructionKind::CallParamSsa(_op) => instr.get_expr_list(1), + _ => vec![], + } } /// Conditional branching instruction and an expected conditional result diff --git a/rust/src/operand_iter.rs b/rust/src/operand_iter.rs deleted file mode 100644 index fcbf5fad8a..0000000000 --- a/rust/src/operand_iter.rs +++ /dev/null @@ -1,237 +0,0 @@ -use binaryninjacore_sys::BNGetHighLevelILByIndex; -use binaryninjacore_sys::BNGetMediumLevelILByIndex; -use binaryninjacore_sys::BNHighLevelILOperation; -use binaryninjacore_sys::BNMediumLevelILOperation; - -use crate::high_level_il::{ - HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex, -}; -use crate::medium_level_il::{ - MediumLevelILFunction, MediumLevelILInstruction, MediumLevelInstructionIndex, -}; -use crate::rc::{Ref, RefCountable}; -use crate::variable::{SSAVariable, Variable}; - -// TODO: This code needs to go away IMO, we have the facilities to do this for each IL already! - -pub trait ILFunction { - type Instruction; - type InstructionIndex: From; - - // TODO Actually this is il expression from index! - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction; - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5]; -} - -impl ILFunction for MediumLevelILFunction { - type Instruction = MediumLevelILInstruction; - type InstructionIndex = MediumLevelInstructionIndex; - - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction { - self.instruction_from_expr_index(instr_index).unwrap() - } - - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5] { - // TODO: WTF?!?!?! - let node = unsafe { BNGetMediumLevelILByIndex(self.handle, instr_index.0) }; - assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF); - node.operands - } -} - -impl ILFunction for HighLevelILFunction { - type Instruction = HighLevelILInstruction; - type InstructionIndex = HighLevelInstructionIndex; - - fn il_instruction_from_index(&self, instr_index: Self::InstructionIndex) -> Self::Instruction { - self.instruction_from_expr_index(instr_index).unwrap() - } - - fn operands_from_index(&self, instr_index: Self::InstructionIndex) -> [u64; 5] { - let node = unsafe { BNGetHighLevelILByIndex(self.handle, instr_index.0, self.full_ast) }; - assert_eq!(node.operation, BNHighLevelILOperation::HLIL_UNDEF); - node.operands - } -} - -pub struct OperandIter { - function: Ref, - remaining: usize, - next_iter_idx: Option, - current_iter: OperandIterInner, -} - -impl OperandIter { - pub(crate) fn new(function: &F, idx: usize, number: usize) -> Self { - // Zero-length lists immediately finish iteration - let next_iter_idx = if number > 0 { Some(idx) } else { None }; - Self { - function: function.to_owned(), - remaining: number, - next_iter_idx, - current_iter: OperandIterInner::empty(), - } - } - - pub fn pairs(self) -> OperandPairIter { - assert_eq!(self.len() % 2, 0); - OperandPairIter(self) - } - - pub fn exprs(self) -> OperandExprIter { - OperandExprIter(self) - } - - pub fn vars(self) -> OperandVarIter { - OperandVarIter(self) - } - - pub fn ssa_vars(self) -> OperandSSAVarIter { - OperandSSAVarIter(self.pairs()) - } -} - -impl Iterator for OperandIter { - type Item = u64; - - fn next(&mut self) -> Option { - if let Some(item) = self.current_iter.next() { - self.remaining -= 1; - Some(item) - } else { - // Will short-circuit and return `None` once iter is exhausted - let iter_idx = self.next_iter_idx?; - let iter_idx = F::InstructionIndex::from(iter_idx as u64); - let operands = self.function.operands_from_index(iter_idx); - - let next = if self.remaining > 4 { - self.next_iter_idx = Some(operands[4] as usize); - &operands[..4] - } else { - self.next_iter_idx = None; - &operands[..self.remaining] - }; - - self.current_iter = OperandIterInner::from_slice(next); - self.next() - } - } -} - -impl ExactSizeIterator for OperandIter { - fn len(&self) -> usize { - self.remaining + self.current_iter.len() - } -} - -struct OperandIterInner { - arr: [u64; 4], - idx: usize, -} - -impl OperandIterInner { - fn from_slice(slice: &[u64]) -> Self { - assert!(slice.len() <= 4); - let idx = 4 - slice.len(); - let mut arr = [0; 4]; - arr[idx..].copy_from_slice(slice); - Self { arr, idx } - } - - fn empty() -> Self { - Self { - arr: [0; 4], - idx: 4, - } - } -} - -impl Iterator for OperandIterInner { - type Item = u64; - - fn next(&mut self) -> Option { - if self.idx < 4 { - let val = self.arr[self.idx]; - self.idx += 1; - Some(val) - } else { - None - } - } -} - -impl ExactSizeIterator for OperandIterInner { - fn len(&self) -> usize { - 4 - self.idx - } -} - -pub struct OperandPairIter(OperandIter); - -impl Iterator for OperandPairIter { - type Item = (u64, u64); - - fn next(&mut self) -> Option { - let first = self.0.next()?; - let second = self.0.next()?; - Some((first, second)) - } -} -impl ExactSizeIterator for OperandPairIter { - fn len(&self) -> usize { - self.0.len() / 2 - } -} - -pub struct OperandExprIter(OperandIter); - -impl Iterator for OperandExprIter { - type Item = F::Instruction; - - fn next(&mut self) -> Option { - self.0 - .next() - .map(F::InstructionIndex::from) - .map(|idx| self.0.function.il_instruction_from_index(idx)) - } -} - -impl ExactSizeIterator for OperandExprIter { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandVarIter(OperandIter); - -impl Iterator for OperandVarIter { - type Item = Variable; - - fn next(&mut self) -> Option { - self.0.next().map(Variable::from_identifier) - } -} -impl ExactSizeIterator for OperandVarIter { - fn len(&self) -> usize { - self.0.len() - } -} - -pub struct OperandSSAVarIter(OperandPairIter); - -impl Iterator for OperandSSAVarIter { - type Item = SSAVariable; - - fn next(&mut self) -> Option { - self.0.next().map(|(id, version)| { - let var = Variable::from_identifier(id); - SSAVariable::new(var, version as _) - }) - } -} - -impl ExactSizeIterator for OperandSSAVarIter { - fn len(&self) -> usize { - self.0.len() - } -} diff --git a/rust/tests/medium_level_il.rs b/rust/tests/medium_level_il.rs index 7f73cde303..b8c1c108bf 100644 --- a/rust/tests/medium_level_il.rs +++ b/rust/tests/medium_level_il.rs @@ -1,6 +1,8 @@ use binaryninja::binary_view::BinaryViewExt; use binaryninja::headless::Session; -use binaryninja::medium_level_il::{MediumLevelILInstructionKind, MediumLevelILLiftedInstructionKind, MediumLevelInstructionIndex}; +use binaryninja::medium_level_il::{ + MediumLevelILInstructionKind, MediumLevelILLiftedInstructionKind, MediumLevelInstructionIndex, +}; use std::path::PathBuf; #[test] From 5c14e6035a917312ffe72c16d0e43067464ffb90 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Sun, 11 May 2025 21:00:55 -0400 Subject: [PATCH 43/54] [Rust] Add missing instruction types to MLIL --- rust/src/medium_level_il/instruction.rs | 63 +++++++++++++++++--- rust/src/medium_level_il/lift.rs | 32 ++++++++++ rust/src/medium_level_il/operation.rs | 78 +++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 9 deletions(-) diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs index 065e28f177..70d69b7f81 100644 --- a/rust/src/medium_level_il/instruction.rs +++ b/rust/src/medium_level_il/instruction.rs @@ -5,12 +5,12 @@ use crate::architecture::{CoreIntrinsic, FlagId, IntrinsicId, RegisterId}; use crate::basic_block::BasicBlock; use crate::confidence::Conf; use crate::disassembly::InstructionTextToken; -use crate::operand_iter::OperandIter; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; use crate::types::Type; use crate::variable::{ConstantData, PossibleValueSet, RegisterValue, SSAVariable, Variable}; use crate::{DataFlowQueryOption, ILBranchDependence}; use binaryninjacore_sys::*; +use std::collections::BTreeMap; use std::fmt; use std::fmt::{Debug, Display, Formatter}; @@ -411,6 +411,24 @@ impl MediumLevelILInstruction { num_params: op.operands[3] as usize, first_param: op.operands[4] as usize, }), + MLIL_CALL_OUTPUT => Op::CallOutput(CallOutput { + first_output: op.operands[0] as usize, + num_outputs: op.operands[1] as usize, + }), + MLIL_CALL_PARAM => Op::CallParam(CallParam { + first_param: op.operands[0] as usize, + num_params: op.operands[1] as usize, + }), + MLIL_CALL_OUTPUT_SSA => Op::CallOutputSsa(CallOutputSsa { + dest_memory: op.operands[0], + num_outputs: op.operands[1] as usize, + first_output: op.operands[2] as usize, + }), + MLIL_CALL_PARAM_SSA => Op::CallParamSsa(CallParamSsa { + src_memory: op.operands[0], + num_params: op.operands[1] as usize, + first_param: op.operands[2] as usize, + }), MLIL_TAILCALL => Op::Tailcall(Call { num_outputs: op.operands[0] as usize, first_output: op.operands[1] as usize, @@ -438,6 +456,20 @@ impl MediumLevelILInstruction { num_params: op.operands[3] as usize, first_param: op.operands[4] as usize, }), + MLIL_MEMORY_INTRINSIC_SSA => Op::MemoryIntrinsicSsa(MemoryIntrinsicSsa { + output: op.operands[0] as usize, + intrinsic: op.operands[1] as u32, + num_params: op.operands[2] as usize, + first_param: op.operands[3] as usize, + src_memory: op.operands[4], + }), + MLIL_MEMORY_INTRINSIC_OUTPUT_SSA => { + Op::MemoryIntrinsicOutputSsa(MemoryIntrinsicOutputSsa { + dest_memory: op.operands[0], + first_output: op.operands[1] as usize, + num_outputs: op.operands[2] as usize, + }) + } MLIL_CALL_SSA => Op::CallSsa(CallSsa { output: op.operands[0] as usize, dest: op.operands[1] as usize, @@ -602,14 +634,6 @@ impl MediumLevelILInstruction { MLIL_TRAP => Op::Trap(Trap { vector: op.operands[0], }), - // translated directly into a list for Expression or Variables - // TODO MLIL_MEMORY_INTRINSIC_SSA needs to be handled properly - MLIL_CALL_OUTPUT - | MLIL_CALL_PARAM - | MLIL_CALL_PARAM_SSA - | MLIL_CALL_OUTPUT_SSA - | MLIL_MEMORY_INTRINSIC_OUTPUT_SSA - | MLIL_MEMORY_INTRINSIC_SSA => Op::NotYetImplemented, }; Self { @@ -847,6 +871,21 @@ impl MediumLevelILInstruction { Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)), Call(op) => Lifted::Call(self.lift_call(op)), + CallOutput(_op) => Lifted::CallOutput(LiftedCallOutput { + output: self.get_var_list(0), + }), + CallParam(_op) => Lifted::CallParam(LiftedCallParam { + params: self.get_expr_list(0).iter().map(|i| i.lift()).collect(), + }), + CallOutputSsa(op) => Lifted::CallOutputSsa(LiftedCallOutputSsa { + dest_memory: op.dest_memory, + output: self.get_ssa_var_list(1), + }), + CallParamSsa(op) => Lifted::CallParamSsa(LiftedCallParamSsa { + src_memory: op.src_memory, + params: self.get_expr_list(1).iter().map(|i| i.lift()).collect(), + }), + Tailcall(op) => Lifted::Tailcall(self.lift_call(op)), Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic { @@ -1672,10 +1711,16 @@ pub enum MediumLevelILInstructionKind { Rlc(BinaryOpCarry), Rrc(BinaryOpCarry), Call(Call), + CallOutput(CallOutput), + CallParam(CallParam), + CallOutputSsa(CallOutputSsa), + CallParamSsa(CallParamSsa), Tailcall(Call), Syscall(Syscall), Intrinsic(Intrinsic), IntrinsicSsa(IntrinsicSsa), + MemoryIntrinsicSsa(MemoryIntrinsicSsa), + MemoryIntrinsicOutputSsa(MemoryIntrinsicOutputSsa), CallSsa(CallSsa), TailcallSsa(CallSsa), CallUntypedSsa(CallUntypedSsa), diff --git a/rust/src/medium_level_il/lift.rs b/rust/src/medium_level_il/lift.rs index f5ee45b345..399bda78e1 100644 --- a/rust/src/medium_level_il/lift.rs +++ b/rust/src/medium_level_il/lift.rs @@ -129,10 +129,16 @@ pub enum MediumLevelILLiftedInstructionKind { Rlc(LiftedBinaryOpCarry), Rrc(LiftedBinaryOpCarry), Call(LiftedCall), + CallOutput(LiftedCallOutput), + CallParam(LiftedCallParam), + CallOutputSsa(LiftedCallOutputSsa), + CallParamSsa(LiftedCallParamSsa), Tailcall(LiftedCall), Intrinsic(LiftedIntrinsic), Syscall(LiftedSyscallCall), IntrinsicSsa(LiftedIntrinsicSsa), + MemoryIntrinsicSsa(LiftedMemoryIntrinsicSsa), + MemoryIntrinsicOutputSsa(LiftedMemoryIntrinsicOutputSsa), CallSsa(LiftedCallSsa), TailcallSsa(LiftedCallSsa), CallUntypedSsa(LiftedCallUntypedSsa), @@ -269,10 +275,16 @@ impl MediumLevelILLiftedInstruction { Rlc(_) => "Rlc", Rrc(_) => "Rrc", Call(_) => "Call", + CallOutput(_) => "CallOutput", + CallParam(_) => "CallParam", + CallOutputSsa(_) => "CallOutputSsa", + CallParamSsa(_) => "CallParamSsa", Tailcall(_) => "Tailcall", Syscall(_) => "Syscall", Intrinsic(_) => "Intrinsic", IntrinsicSsa(_) => "IntrinsicSsa", + MemoryIntrinsicSsa(_) => "MemoryIntrinsicSsa", + MemoryIntrinsicOutputSsa(_) => "MemoryIntrinsicOutputSsa", CallSsa(_) => "CallSsa", TailcallSsa(_) => "TailcallSsa", CallUntypedSsa(_) => "CallUntypedSsa", @@ -441,6 +453,16 @@ impl MediumLevelILLiftedInstruction { ("dest", Operand::Expr(*op.dest.clone())), ("params", Operand::ExprList(op.params.clone())), ], + CallOutput(op) => vec![("output", Operand::VarList(op.output.clone()))], + CallParam(op) => vec![("params", Operand::ExprList(op.params.clone()))], + CallOutputSsa(op) => vec![ + ("output", Operand::VarSsaList(op.output.clone())), + ("dest_memory", Operand::Int(op.dest_memory)), + ], + CallParamSsa(op) => vec![ + ("params", Operand::ExprList(op.params.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], Syscall(op) => vec![ ("output", Operand::VarList(op.output.clone())), ("params", Operand::ExprList(op.params.clone())), @@ -455,6 +477,16 @@ impl MediumLevelILLiftedInstruction { ("intrinsic", Operand::Intrinsic(op.intrinsic)), ("params", Operand::ExprList(op.params.clone())), ], + MemoryIntrinsicSsa(op) => vec![ + ("output", Operand::Expr(*op.output.clone())), + ("intrinsic", Operand::Intrinsic(op.intrinsic)), + ("params", Operand::ExprList(op.params.clone())), + ("src_memory", Operand::Int(op.src_memory)), + ], + MemoryIntrinsicOutputSsa(op) => vec![ + ("dest_memory", Operand::Int(op.dest_memory)), + ("output", Operand::VarSsaList(op.output.clone())), + ], CallSsa(op) | TailcallSsa(op) => vec![ ("output", Operand::VarSsaList(op.output.clone())), ("dest", Operand::Expr(*op.dest.clone())), diff --git a/rust/src/medium_level_il/operation.rs b/rust/src/medium_level_il/operation.rs index e11f59c8be..e8b70cc6b2 100644 --- a/rust/src/medium_level_il/operation.rs +++ b/rust/src/medium_level_il/operation.rs @@ -329,6 +329,54 @@ pub struct LiftedCall { pub params: Vec, } +// CALL_OUTPUT +#[derive(Debug, Copy, Clone)] +pub struct CallOutput { + pub first_output: usize, + pub num_outputs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCallOutput { + pub output: Vec, +} + +// CALL_PARAM_SSA +#[derive(Debug, Copy, Clone)] +pub struct CallParam { + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCallParam { + pub params: Vec, +} + +// CALL_OUTPUT_SSA +#[derive(Debug, Copy, Clone)] +pub struct CallOutputSsa { + pub dest_memory: u64, + pub first_output: usize, + pub num_outputs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCallOutputSsa { + pub dest_memory: u64, + pub output: Vec, +} + +// CALL_PARAM_SSA +#[derive(Debug, Copy, Clone)] +pub struct CallParamSsa { + pub src_memory: u64, + pub first_param: usize, + pub num_params: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedCallParamSsa { + pub src_memory: u64, + pub params: Vec, +} + // SYSCALL #[derive(Debug, Copy, Clone)] pub struct Syscall { @@ -375,6 +423,36 @@ pub struct LiftedIntrinsicSsa { pub params: Vec, } +// MEMORY_INTRINSIC_SSA +#[derive(Debug, Copy, Clone)] +pub struct MemoryIntrinsicSsa { + pub output: usize, + pub intrinsic: u32, + pub first_param: usize, + pub num_params: usize, + pub src_memory: u64, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedMemoryIntrinsicSsa { + pub output: Box, + pub intrinsic: CoreIntrinsic, + pub params: Vec, + pub src_memory: u64, +} + +// MEMORY_INTRINSIC_OUTPUT_SSA +#[derive(Debug, Copy, Clone)] +pub struct MemoryIntrinsicOutputSsa { + pub dest_memory: u64, + pub first_output: usize, + pub num_outputs: usize, +} +#[derive(Clone, Debug, PartialEq)] +pub struct LiftedMemoryIntrinsicOutputSsa { + pub dest_memory: u64, + pub output: Vec, +} + // CALL_SSA, TAILCALL_SSA #[derive(Debug, Copy, Clone)] pub struct CallSsa { From 069ba4411c8f81b8a403363397b294be9e51a753 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 12:06:22 -0400 Subject: [PATCH 44/54] [Rust] Misc cleanup --- rust/src/binary_view.rs | 2 +- rust/src/binary_view/reader.rs | 4 ++-- rust/src/custom_binary_view.rs | 4 ++-- rust/src/file_metadata.rs | 16 ++++++++-------- rust/src/settings.rs | 10 ++-------- 5 files changed, 15 insertions(+), 21 deletions(-) diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 1aa9789188..4379e7f512 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -1163,7 +1163,7 @@ pub trait BinaryViewExt: BinaryViewBase { if settings_handle.is_null() { Err(()) } else { - Ok(unsafe { Settings::from_raw(settings_handle) }) + Ok(unsafe { Settings::ref_from_raw(settings_handle) }) } } diff --git a/rust/src/binary_view/reader.rs b/rust/src/binary_view/reader.rs index 7b49f28dbc..685914e210 100644 --- a/rust/src/binary_view/reader.rs +++ b/rust/src/binary_view/reader.rs @@ -68,12 +68,12 @@ impl BinaryReader { unsafe { BNSetBinaryReaderVirtualBase(self.handle, virtual_base_addr) } } - /// Prefer using [crate::reader::BinaryReader::seek] over this. + /// Prefer using [BinaryReader::seek] over this. pub fn seek_to_offset(&mut self, offset: u64) { unsafe { BNSeekBinaryReader(self.handle, offset) } } - /// Prefer using [crate::reader::BinaryReader::seek] over this. + /// Prefer using [BinaryReader::seek] over this. pub fn seek_to_relative_offset(&mut self, offset: i64) { unsafe { BNSeekBinaryReaderRelative(self.handle, offset) } } diff --git a/rust/src/custom_binary_view.rs b/rust/src/custom_binary_view.rs index f809f251f3..a0b1df2142 100644 --- a/rust/src/custom_binary_view.rs +++ b/rust/src/custom_binary_view.rs @@ -200,7 +200,7 @@ pub trait BinaryViewTypeBase: AsRef { if settings_handle.is_null() { None } else { - unsafe { Some(Settings::from_raw(settings_handle)) } + unsafe { Some(Settings::ref_from_raw(settings_handle)) } } } @@ -388,7 +388,7 @@ impl BinaryViewTypeBase for BinaryViewType { if settings_handle.is_null() { None } else { - unsafe { Some(Settings::from_raw(settings_handle)) } + unsafe { Some(Settings::ref_from_raw(settings_handle)) } } } } diff --git a/rust/src/file_metadata.rs b/rust/src/file_metadata.rs index 56c8a9e9a6..ed85977564 100644 --- a/rust/src/file_metadata.rs +++ b/rust/src/file_metadata.rs @@ -121,8 +121,8 @@ impl FileMetadata { /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread /// and the thread executing this function, you can deadlock. You should also never call this function /// on multiple threads at a time. See the following issues: - /// - https://github.com/Vector35/binaryninja-api/issues/6289 - /// - https://github.com/Vector35/binaryninja-api/issues/6325 + /// - + /// - pub fn run_undoable_transaction Result, T, E>( &self, func: F, @@ -146,8 +146,8 @@ impl FileMetadata { /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread /// and the thread executing this function, you can deadlock. You should also never call this function /// on multiple threads at a time. See the following issues: - /// - https://github.com/Vector35/binaryninja-api/issues/6289 - /// - https://github.com/Vector35/binaryninja-api/issues/6325 + /// - + /// - pub fn begin_undo_actions(&self, anonymous_allowed: bool) -> String { unsafe { BnString::into_string(BNBeginUndoActions(self.handle, anonymous_allowed)) } } @@ -157,8 +157,8 @@ impl FileMetadata { /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread /// and the thread executing this function, you can deadlock. You should also never call this function /// on multiple threads at a time. See the following issues: - /// - https://github.com/Vector35/binaryninja-api/issues/6289 - /// - https://github.com/Vector35/binaryninja-api/issues/6325 + /// - + /// - pub fn commit_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { @@ -171,8 +171,8 @@ impl FileMetadata { /// NOTE: This is **NOT** thread safe, if you are holding any locks that might be held by both the main thread /// and the thread executing this function, you can deadlock. You should also never call this function /// on multiple threads at a time. See the following issues: - /// - https://github.com/Vector35/binaryninja-api/issues/6289 - /// - https://github.com/Vector35/binaryninja-api/issues/6325 + /// - + /// - pub fn revert_undo_actions(&self, id: &str) { let id = id.to_cstr(); unsafe { diff --git a/rust/src/settings.rs b/rust/src/settings.rs index 0047f57036..3882ce4d20 100644 --- a/rust/src/settings.rs +++ b/rust/src/settings.rs @@ -35,7 +35,7 @@ pub struct Settings { } impl Settings { - pub(crate) unsafe fn from_raw(handle: *mut BNSettings) -> Ref { + pub(crate) unsafe fn ref_from_raw(handle: *mut BNSettings) -> Ref { debug_assert!(!handle.is_null()); Ref::new(Self { handle }) } @@ -46,11 +46,7 @@ impl Settings { pub fn new_with_id(instance_id: &str) -> Ref { let instance_id = instance_id.to_cstr(); - unsafe { - let handle = BNCreateSettings(instance_id.as_ptr()); - debug_assert!(!handle.is_null()); - Ref::new(Self { handle }) - } + unsafe { Self::ref_from_raw(BNCreateSettings(instance_id.as_ptr())) } } pub fn set_resource_id(&self, resource_id: &str) { @@ -84,8 +80,6 @@ impl Settings { unsafe { Array::new(result as *mut *mut c_char, count, ()) } } - // TODO Update the settings API to take an optional BinaryView or Function. Separate functions or...? - pub fn get_bool(&self, key: &str) -> bool { self.get_bool_with_opts(key, &mut QueryOptions::default()) } From 1f778acf24fe636f0fdd433a1a116d92f50d0c9d Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 12:48:56 -0400 Subject: [PATCH 45/54] [Rust] Add type printer tests --- rust/tests/type_printer.rs | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 rust/tests/type_printer.rs diff --git a/rust/tests/type_printer.rs b/rust/tests/type_printer.rs new file mode 100644 index 0000000000..4ff67232da --- /dev/null +++ b/rust/tests/type_printer.rs @@ -0,0 +1,169 @@ +use binaryninja::binary_view::BinaryView; +use binaryninja::disassembly::InstructionTextToken; +use binaryninja::headless::Session; +use binaryninja::platform::Platform; +use binaryninja::rc::Ref; +use binaryninja::type_container::TypeContainer; +use binaryninja::type_printer::{ + register_type_printer, CoreTypePrinter, TokenEscapingType, TypeDefinitionLine, TypePrinter, +}; +use binaryninja::types::{ + MemberAccess, MemberScope, QualifiedName, Structure, StructureMember, Type, +}; +use std::path::PathBuf; + +#[test] +fn test_type_printer() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + + let type_printer = CoreTypePrinter::default(); + let my_structure = Type::structure( + &Structure::builder() + .insert_member( + StructureMember::new( + Type::int(4, false).into(), + "my_field".to_string(), + 0, + MemberAccess::PublicAccess, + MemberScope::NoScope, + ), + false, + ) + .finalize(), + ); + + let printed_types = type_printer + .print_all_types( + [("my_struct", my_structure)], + &view, + 4, + TokenEscapingType::NoTokenEscapingType, + ) + .expect("Failed to print types"); + + // TODO: Assert this + /* + // "my_struct" + struct my_struct + { + uint32_t my_field; + }; + */ + + println!("{:#?}", printed_types); +} + +struct MyTypePrinter; + +impl TypePrinter for MyTypePrinter { + fn get_type_tokens>( + &self, + _type_: Ref, + _platform: Option>, + _name: T, + _base_confidence: u8, + _escaping: TokenEscapingType, + ) -> Option> { + todo!() + } + + fn get_type_tokens_before_name( + &self, + _type_: Ref, + _platform: Option>, + _base_confidence: u8, + _parent_type: Option>, + _escaping: TokenEscapingType, + ) -> Option> { + todo!() + } + + fn get_type_tokens_after_name( + &self, + _type_: Ref, + _platform: Option>, + _base_confidence: u8, + _parent_type: Option>, + _escaping: TokenEscapingType, + ) -> Option> { + todo!() + } + + fn get_type_string>( + &self, + _type_: Ref, + _platform: Option>, + _name: T, + _escaping: TokenEscapingType, + ) -> Option { + todo!() + } + + fn get_type_string_before_name( + &self, + _type_: Ref, + _platform: Option>, + _escaping: TokenEscapingType, + ) -> Option { + todo!() + } + + fn get_type_string_after_name( + &self, + _type_: Ref, + _platform: Option>, + _escaping: TokenEscapingType, + ) -> Option { + todo!() + } + + fn get_type_lines>( + &self, + _type_: Ref, + _types: &TypeContainer, + _name: T, + _padding_cols: isize, + _collapsed: bool, + _escaping: TokenEscapingType, + ) -> Option> { + todo!() + } + + fn print_all_types( + &self, + names: Vec, + types: Vec>, + _data: Ref, + padding_cols: isize, + escaping: TokenEscapingType, + ) -> Option { + let printed = format!("{:?}, {:?}, {}, {:?}", names, types, padding_cols, escaping); + Some(printed) + } +} + +#[test] +fn test_custom_type_printer() { + let _session = Session::new().expect("Failed to initialize session"); + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + + let type_printer = MyTypePrinter; + register_type_printer("my_type_printer", type_printer); + + let core_type_printer = CoreTypePrinter::printer_by_name("my_type_printer") + .expect("Failed to get core type printer"); + let printed_types = core_type_printer + .print_all_types( + vec![("test", Type::int(4, false))], + &view, + 0, + TokenEscapingType::NoTokenEscapingType, + ) + .expect("Failed to print types"); + + // TODO: Assert this + println!("{:#?}", printed_types); +} From 38b6bc676547d39be43ce01b3194816954648344 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 13:14:09 -0400 Subject: [PATCH 46/54] [Rust] Make TypeLibrary ref counted And some other misc cleanup --- rust/src/binary_view.rs | 12 ++-- rust/src/type_library.rs | 137 +++++++++++++++------------------------ 2 files changed, 57 insertions(+), 92 deletions(-) diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs index 4379e7f512..cae53e66fa 100644 --- a/rust/src/binary_view.rs +++ b/rust/src/binary_view.rs @@ -1634,10 +1634,10 @@ pub trait BinaryViewExt: BinaryViewBase { unsafe { BNAddBinaryViewTypeLibrary(self.as_ref().handle, library.as_raw()) } } - fn type_library_by_name(&self, name: &str) -> Option { + fn type_library_by_name(&self, name: &str) -> Option> { let name = name.to_cstr(); let result = unsafe { BNGetBinaryViewTypeLibrary(self.as_ref().handle, name.as_ptr()) }; - NonNull::new(result).map(|h| unsafe { TypeLibrary::from_raw(h) }) + NonNull::new(result).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } /// Should be called by custom py:py:class:`BinaryView` implementations @@ -1782,7 +1782,7 @@ pub trait BinaryViewExt: BinaryViewBase { &self, addr: u64, platform: &Platform, - ) -> Option<(TypeLibrary, QualifiedName)> { + ) -> Option<(Ref, QualifiedName)> { let mut result_lib = std::ptr::null_mut(); let mut result_name = BNQualifiedName::default(); let success = unsafe { @@ -1797,7 +1797,7 @@ pub trait BinaryViewExt: BinaryViewBase { if !success { return None; } - let lib = unsafe { TypeLibrary::from_raw(NonNull::new(result_lib)?) }; + let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) }; let name = QualifiedName::from_owned_raw(result_name); Some((lib, name)) } @@ -1808,7 +1808,7 @@ pub trait BinaryViewExt: BinaryViewBase { fn lookup_imported_type_library>( &self, name: T, - ) -> Option<(TypeLibrary, QualifiedName)> { + ) -> Option<(Ref, QualifiedName)> { let raw_name = QualifiedName::into_raw(name.into()); let mut result_lib = std::ptr::null_mut(); let mut result_name = BNQualifiedName::default(); @@ -1824,7 +1824,7 @@ pub trait BinaryViewExt: BinaryViewBase { if !success { return None; } - let lib = unsafe { TypeLibrary::from_raw(NonNull::new(result_lib)?) }; + let lib = unsafe { TypeLibrary::ref_from_raw(NonNull::new(result_lib)?) }; let name = QualifiedName::from_owned_raw(result_name); Some((lib, name)) } diff --git a/rust/src/type_library.rs b/rust/src/type_library.rs index 6d09abfadd..7f94652d19 100644 --- a/rust/src/type_library.rs +++ b/rust/src/type_library.rs @@ -1,5 +1,6 @@ use binaryninjacore_sys::*; +use crate::rc::{Guard, RefCountable}; use crate::{ architecture::CoreArchitecture, metadata::Metadata, @@ -8,22 +9,21 @@ use crate::{ string::{BnString, IntoCStr}, types::{QualifiedName, QualifiedNameAndType, Type}, }; -use core::{ffi, mem, ptr}; use std::path::Path; +use std::ptr::NonNull; #[repr(transparent)] pub struct TypeLibrary { - handle: ptr::NonNull, + handle: NonNull, } impl TypeLibrary { - pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { + pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { Self { handle } } - pub(crate) unsafe fn ref_from_raw(handle: &*mut BNTypeLibrary) -> &Self { - assert!(!handle.is_null()); - mem::transmute(handle) + pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { + Ref::new(Self { handle }) } #[allow(clippy::mut_from_ref)] @@ -31,22 +31,15 @@ impl TypeLibrary { &mut *self.handle.as_ptr() } - pub fn new_reference(&self) -> Self { - unsafe { - Self::from_raw(ptr::NonNull::new(BNNewTypeLibraryReference(self.as_raw())).unwrap()) - } - } - - pub fn new_duplicated(&self) -> Self { - unsafe { Self::from_raw(ptr::NonNull::new(BNDuplicateTypeLibrary(self.as_raw())).unwrap()) } + pub fn new_duplicated(&self) -> Ref { + unsafe { Self::ref_from_raw(NonNull::new(BNDuplicateTypeLibrary(self.as_raw())).unwrap()) } } /// Creates an empty type library object with a random GUID and the provided name. - pub fn new(arch: CoreArchitecture, name: &str) -> TypeLibrary { + pub fn new(arch: CoreArchitecture, name: &str) -> Ref { let name = name.to_cstr(); - let new_lib = - unsafe { BNNewTypeLibrary(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) }; - unsafe { TypeLibrary::from_raw(ptr::NonNull::new(new_lib).unwrap()) } + let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ptr()) }; + unsafe { TypeLibrary::ref_from_raw(NonNull::new(new_lib).unwrap()) } } pub fn all(arch: CoreArchitecture) -> Array { @@ -60,47 +53,35 @@ impl TypeLibrary { pub fn decompress_to_file(path: &Path, output_path: &Path) -> bool { let path = path.to_cstr(); let output = output_path.to_cstr(); - unsafe { - BNTypeLibraryDecompressToFile( - path.as_ref().as_ptr() as *const ffi::c_char, - output.as_ref().as_ptr() as *const ffi::c_char, - ) - } + unsafe { BNTypeLibraryDecompressToFile(path.as_ptr(), output.as_ptr()) } } /// Loads a finalized type library instance from file - pub fn load_from_file(path: &Path) -> Option { + pub fn load_from_file(path: &Path) -> Option> { let path = path.to_cstr(); - let handle = - unsafe { BNLoadTypeLibraryFromFile(path.as_ref().as_ptr() as *const ffi::c_char) }; - ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ptr()) }; + NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } /// Saves a finalized type library instance to file pub fn write_to_file(&self, path: &Path) -> bool { let path = path.to_cstr(); - unsafe { - BNWriteTypeLibraryToFile(self.as_raw(), path.as_ref().as_ptr() as *const ffi::c_char) - } + unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ptr()) } } /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. - pub fn from_name(arch: CoreArchitecture, name: &str) -> Option { + pub fn from_name(arch: CoreArchitecture, name: &str) -> Option> { let name = name.to_cstr(); - let handle = unsafe { - BNLookupTypeLibraryByName(arch.handle, name.as_ref().as_ptr() as *const ffi::c_char) - }; - ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ptr()) }; + NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } /// Attempts to grab a type library associated with the provided Architecture and GUID pair - pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option { + pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option> { let guid = guid.to_cstr(); - let handle = unsafe { - BNLookupTypeLibraryByGuid(arch.handle, guid.as_ref().as_ptr() as *const ffi::c_char) - }; - ptr::NonNull::new(handle).map(|h| unsafe { TypeLibrary::from_raw(h) }) + let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ptr()) }; + NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } /// The Architecture this type library is associated with @@ -119,9 +100,7 @@ impl TypeLibrary { /// Sets the name of a type library instance that has not been finalized pub fn set_name(&self, value: &str) { let value = value.to_cstr(); - unsafe { - BNSetTypeLibraryName(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) - } + unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ptr()) } } /// The `dependency_name` of a library is the name used to record dependencies across @@ -137,12 +116,7 @@ impl TypeLibrary { /// Sets the dependency name of a type library instance that has not been finalized pub fn set_dependency_name(&self, value: &str) { let value = value.to_cstr(); - unsafe { - BNSetTypeLibraryDependencyName( - self.as_raw(), - value.as_ref().as_ptr() as *const ffi::c_char, - ) - } + unsafe { BNSetTypeLibraryDependencyName(self.as_raw(), value.as_ptr()) } } /// Returns the GUID associated with the type library @@ -154,9 +128,7 @@ impl TypeLibrary { /// Sets the GUID of a type library instance that has not been finalized pub fn set_guid(&self, value: &str) { let value = value.to_cstr(); - unsafe { - BNSetTypeLibraryGuid(self.as_raw(), value.as_ref().as_ptr() as *const ffi::c_char) - } + unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ptr()) } } /// A list of extra names that will be considered a match by [Platform::get_type_libraries_by_name] @@ -170,12 +142,7 @@ impl TypeLibrary { /// Adds an extra name to this type library used during library lookups and dependency resolution pub fn add_alternate_name(&self, value: &str) { let value = value.to_cstr(); - unsafe { - BNAddTypeLibraryAlternateName( - self.as_raw(), - value.as_ref().as_ptr() as *const ffi::c_char, - ) - } + unsafe { BNAddTypeLibraryAlternateName(self.as_raw(), value.as_ptr()) } } /// Returns a list of all platform names that this type library will register with during platform @@ -214,9 +181,7 @@ impl TypeLibrary { /// Retrieves a metadata associated with the given key stored in the type library pub fn query_metadata(&self, key: &str) -> Option { let key = key.to_cstr(); - let result = unsafe { - BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) - }; + let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ptr()) }; (!result.is_null()).then(|| unsafe { Metadata::from_raw(result) }) } @@ -233,21 +198,13 @@ impl TypeLibrary { /// * `md` - object to store. pub fn store_metadata(&self, key: &str, md: &Metadata) { let key = key.to_cstr(); - unsafe { - BNTypeLibraryStoreMetadata( - self.as_raw(), - key.as_ref().as_ptr() as *const ffi::c_char, - md.handle, - ) - } + unsafe { BNTypeLibraryStoreMetadata(self.as_raw(), key.as_ptr(), md.handle) } } /// Removes the metadata associated with key from the current type library. pub fn remove_metadata(&self, key: &str) { let key = key.to_cstr(); - unsafe { - BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char) - } + unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ptr()) } } /// Retrieves the metadata associated with the current type library. @@ -262,7 +219,7 @@ impl TypeLibrary { // /// The Type Container's Platform will be the first platform associated with the Type Library. // pub fn type_container(&self) -> TypeContainer { // let result = unsafe{ BNGetTypeLibraryTypeContainer(self.as_raw())}; - // unsafe{TypeContainer::from_raw(ptr::NonNull::new(result).unwrap())} + // unsafe{TypeContainer::from_raw(NonNull::new(result).unwrap())} // } /// Directly inserts a named object into the type library's object store. @@ -302,13 +259,7 @@ impl TypeLibrary { pub fn add_type_source(&self, name: QualifiedName, source: &str) { let source = source.to_cstr(); let mut raw_name = QualifiedName::into_raw(name); - unsafe { - BNAddTypeLibraryNamedTypeSource( - self.as_raw(), - &mut raw_name, - source.as_ref().as_ptr() as *const ffi::c_char, - ) - } + unsafe { BNAddTypeLibraryNamedTypeSource(self.as_raw(), &mut raw_name, source.as_ptr()) } QualifiedName::free_raw(raw_name); } @@ -349,16 +300,30 @@ impl TypeLibrary { } } -impl Drop for TypeLibrary { - fn drop(&mut self) { - unsafe { BNFreeTypeLibrary(self.as_raw()) } +unsafe impl RefCountable for TypeLibrary { + unsafe fn inc_ref(handle: &Self) -> Ref { + Ref::new(Self { + handle: NonNull::new(BNNewTypeLibraryReference(handle.handle.as_ptr())).unwrap(), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeTypeLibrary(handle.handle.as_ptr()); + } +} + +impl ToOwned for TypeLibrary { + type Owned = Ref; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } } } impl CoreArrayProvider for TypeLibrary { type Raw = *mut BNTypeLibrary; type Context = (); - type Wrapped<'a> = &'a Self; + type Wrapped<'a> = Guard<'a, Self>; } unsafe impl CoreArrayProviderInner for TypeLibrary { @@ -366,7 +331,7 @@ unsafe impl CoreArrayProviderInner for TypeLibrary { BNFreeTypeLibraryList(raw, count) } - unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { - Self::ref_from_raw(raw) + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { + Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context) } } From 24b8267795ae25719025e905363a2e1789a0c181 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:55:35 -0400 Subject: [PATCH 47/54] [Rust] Add `Display` and `Debug` impl to `Metadata` --- rust/src/metadata.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs index e541577de8..b6a88eef4f 100644 --- a/rust/src/metadata.rs +++ b/rust/src/metadata.rs @@ -2,6 +2,7 @@ use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, Re use crate::string::{raw_to_string, BnString, IntoCStr, IntoJson}; use binaryninjacore_sys::*; use std::collections::HashMap; +use std::fmt::{Debug, Display, Formatter}; use std::os::raw::c_char; use std::slice; @@ -311,6 +312,83 @@ impl Metadata { } } +impl Debug for Metadata { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Metadata") + .field("type", &self.get_type()) + .field("len", &self.len()) + // Display will give you the metadata value as a string. + .field("value", &self.to_string()) + .finish() + } +} + +impl Display for Metadata { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + // Display will give you the metadata value as a string. + match self.get_type() { + MetadataType::BooleanDataType => match self.get_boolean() { + Some(val) => write!(f, "{}", val), + None => write!(f, "null"), + }, + MetadataType::UnsignedIntegerDataType => match self.get_unsigned_integer() { + Some(val) => write!(f, "{}", val), + None => write!(f, "null"), + }, + MetadataType::SignedIntegerDataType => match self.get_signed_integer() { + Some(val) => write!(f, "{}", val), + None => write!(f, "null"), + }, + MetadataType::DoubleDataType => match self.get_double() { + Some(val) => write!(f, "{}", val), + None => write!(f, "null"), + }, + MetadataType::StringDataType => match self.get_string() { + Some(val) => write!(f, "{}", val.to_string_lossy()), + None => write!(f, "null"), + }, + MetadataType::ArrayDataType => { + match self.get_array() { + Some(array) => { + // TODO: This is extremely ugly + write!(f, "[")?; + for (i, val) in array.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", *val)?; + } + write!(f, "]")?; + Ok(()) + } + None => write!(f, "null"), + } + } + MetadataType::InvalidDataType => { + write!(f, "null") + } + MetadataType::KeyValueDataType => match self.get_value_store() { + Some(map) => { + write!(f, "{{")?; + for (i, (key, val)) in map.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}: {}", key, val)?; + } + write!(f, "}}")?; + Ok(()) + } + None => write!(f, "null"), + }, + MetadataType::RawDataType => match self.get_raw() { + Some(val) => write!(f, "{:x?}", val), + None => write!(f, "null"), + }, + } + } +} + unsafe impl Sync for Metadata {} unsafe impl Send for Metadata {} From 31c4d04aa48b28331c2d82457f473faf25b10591 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:55:46 -0400 Subject: [PATCH 48/54] [Rust] Misc type library cleanup --- rust/src/type_library.rs | 50 +++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/rust/src/type_library.rs b/rust/src/type_library.rs index 7f94652d19..89f5e48f43 100644 --- a/rust/src/type_library.rs +++ b/rust/src/type_library.rs @@ -1,4 +1,5 @@ use binaryninjacore_sys::*; +use std::fmt::{Debug, Formatter}; use crate::rc::{Guard, RefCountable}; use crate::{ @@ -71,13 +72,20 @@ impl TypeLibrary { /// Looks up the first type library found with a matching name. Keep in mind that names are not /// necessarily unique. + /// + /// NOTE: If the type library architecture's associated platform has not been initialized, this will + /// return `None`. To make sure that the platform has been initialized, one should instead get the type + /// libraries through [`Platform::get_type_libraries_by_name`]. pub fn from_name(arch: CoreArchitecture, name: &str) -> Option> { let name = name.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ptr()) }; NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) }) } - /// Attempts to grab a type library associated with the provided Architecture and GUID pair + /// Attempts to grab a type library associated with the provided Architecture and GUID pair. + /// + /// NOTE: If the associated platform for the architecture has not been initialized, + /// this will return `None`. Avoid calling this outside of a view context. pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option> { let guid = guid.to_cstr(); let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ptr()) }; @@ -92,9 +100,10 @@ impl TypeLibrary { } /// The primary name associated with this type library - pub fn name(&self) -> Option { + pub fn name(&self) -> String { let result = unsafe { BNGetTypeLibraryName(self.as_raw()) }; - (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + assert!(!result.is_null()); + unsafe { BnString::into_string(result) } } /// Sets the name of a type library instance that has not been finalized @@ -108,9 +117,10 @@ impl TypeLibrary { /// dependencies on it recorded as "libc_generic", allowing a type library to be used across /// multiple platforms where each has a specific libc that also provides the name "libc_generic" /// as an `alternate_name`. - pub fn dependency_name(&self) -> Option { + pub fn dependency_name(&self) -> String { let result = unsafe { BNGetTypeLibraryDependencyName(self.as_raw()) }; - (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + assert!(!result.is_null()); + unsafe { BnString::into_string(result) } } /// Sets the dependency name of a type library instance that has not been finalized @@ -120,9 +130,10 @@ impl TypeLibrary { } /// Returns the GUID associated with the type library - pub fn guid(&self) -> Option { + pub fn guid(&self) -> String { let result = unsafe { BNGetTypeLibraryGuid(self.as_raw()) }; - (!result.is_null()).then(|| unsafe { BnString::from_raw(result) }) + assert!(!result.is_null()); + unsafe { BnString::into_string(result) } } /// Sets the GUID of a type library instance that has not been finalized @@ -179,10 +190,10 @@ impl TypeLibrary { } /// Retrieves a metadata associated with the given key stored in the type library - pub fn query_metadata(&self, key: &str) -> Option { + pub fn query_metadata(&self, key: &str) -> Option> { let key = key.to_cstr(); let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ptr()) }; - (!result.is_null()).then(|| unsafe { Metadata::from_raw(result) }) + (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) }) } /// Stores an object for the given key in the current type library. Objects stored using @@ -208,10 +219,10 @@ impl TypeLibrary { } /// Retrieves the metadata associated with the current type library. - pub fn metadata(&self) -> Metadata { + pub fn metadata(&self) -> Ref { let md_handle = unsafe { BNTypeLibraryGetMetadata(self.as_raw()) }; assert!(!md_handle.is_null()); - unsafe { Metadata::from_raw(md_handle) } + unsafe { Metadata::ref_from_raw(md_handle) } } // TODO: implement TypeContainer @@ -300,6 +311,23 @@ impl TypeLibrary { } } +impl Debug for TypeLibrary { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TypeLibrary") + .field("name", &self.name()) + .field("dependency_name", &self.dependency_name()) + .field("arch", &self.arch()) + .field("guid", &self.guid()) + .field("alternate_names", &self.alternate_names().to_vec()) + .field("platform_names", &self.platform_names().to_vec()) + .field("metadata", &self.metadata()) + // These two are too verbose. + // .field("named_objects", &self.named_objects().to_vec()) + // .field("named_types", &self.named_types().to_vec()) + .finish() + } +} + unsafe impl RefCountable for TypeLibrary { unsafe fn inc_ref(handle: &Self) -> Ref { Ref::new(Self { From e2e09ba7d4ac113f8f68115e3cda625ca7c128c5 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:56:14 -0400 Subject: [PATCH 49/54] [Rust] Enclose the `BnString` with "" in the `Debug` impl --- rust/src/string.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/src/string.rs b/rust/src/string.rs index 6083d3006a..0a1191d5df 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -165,7 +165,7 @@ impl Eq for BnString {} impl fmt::Debug for BnString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_string_lossy()) + self.to_string_lossy().fmt(f) } } From 196142d291d620aae3412e4dec4ec37bcc65121c Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:56:33 -0400 Subject: [PATCH 50/54] [Rust] Add `Platform::get_type_library_by_name` --- rust/src/platform.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rust/src/platform.rs b/rust/src/platform.rs index 013f709d6a..1bbdef4e93 100644 --- a/rust/src/platform.rs +++ b/rust/src/platform.rs @@ -173,6 +173,10 @@ impl Platform { unsafe { TypeContainer::from_raw(type_container_ptr.unwrap()) } } + /// Get all the type libraries that have been registered with the name. + /// + /// NOTE: This is a list because libraries can have `alternate_names`, use [`Platform::get_type_library_by_name`] + /// if you want to get _the_ type library with that name, skipping alternate names. pub fn get_type_libraries_by_name(&self, name: &str) -> Array { let mut count = 0; let name = name.to_cstr(); @@ -182,6 +186,17 @@ impl Platform { unsafe { Array::new(result, count, ()) } } + /// Get the type library with the given name. + /// + /// NOTE: This finds the first type library that has the given name, skipping alternate names. + pub fn get_type_library_by_name(&self, name: &str) -> Option> { + let libraries = self.get_type_libraries_by_name(name); + libraries + .iter() + .find(|lib| lib.name() == name) + .map(|lib| lib.to_owned()) + } + pub fn register_os(&self, os: &str) { let os = os.to_cstr(); unsafe { From 57000698af445c505c09c92f2d9571fd406a25c8 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:56:47 -0400 Subject: [PATCH 51/54] [Rust] Add type library tests --- rust/tests/type_library.rs | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 rust/tests/type_library.rs diff --git a/rust/tests/type_library.rs b/rust/tests/type_library.rs new file mode 100644 index 0000000000..83937386e0 --- /dev/null +++ b/rust/tests/type_library.rs @@ -0,0 +1,101 @@ +use binaryninja::binary_view::BinaryViewExt; +use binaryninja::headless::Session; +use binaryninja::platform::Platform; +use binaryninja::type_library::TypeLibrary; +use binaryninja::types::{Type, TypeClass}; +use std::path::PathBuf; + +#[test] +fn test_type_library() { + let _session = Session::new().expect("Failed to initialize session"); + let platform = Platform::by_name("windows-x86").expect("windows-x86 exists"); + let library = platform + .get_type_library_by_name("crypt32.dll") + .expect("crypt32.dll exists"); + + println!("{:#?}", library); + assert_eq!(library.name(), "crypt32.dll"); + assert_eq!(library.dependency_name(), "crypt32.dll"); + assert!(library.alternate_names().is_empty()); + assert_eq!(library.platform_names().to_vec(), vec!["windows-x86"]); + + // Check some types. + let type_0 = library + .get_named_type("SIP_ADD_NEWPROVIDER".into()) + .unwrap(); + println!("{:#?}", type_0); + assert_eq!(type_0.width(), 48); + assert_eq!(type_0.type_class(), TypeClass::StructureTypeClass); +} + +#[test] +fn test_applying_type_library() { + let _session = Session::new().expect("Failed to initialize session"); + let platform = Platform::by_name("windows-x86").expect("windows-x86 exists"); + let library = platform + .get_type_library_by_name("crypt32.dll") + .expect("crypt32.dll exists"); + + let out_dir = env!("OUT_DIR").parse::().unwrap(); + let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view"); + view.add_type_library(&library); + + let view_library = view + .type_library_by_name("crypt32.dll") + .expect("crypt32.dll exists"); + assert_eq!(view_library.name(), "crypt32.dll"); + + // Type library types don't exist in the view until they are imported. + // Adding the type library to the view will let you import types from it without necessarily knowing "where" they came from. + let found_lib_type = view + .import_type_library("SIP_ADD_NEWPROVIDER", None) + .expect("SIP_ADD_NEWPROVIDER exists"); + assert_eq!(found_lib_type.width(), 48); + // Per docs type is returned as a NamedTypeReferenceClass. + assert_eq!( + found_lib_type.type_class(), + TypeClass::NamedTypeReferenceClass + ); + + // Check that the type is actually in the view now. + view.type_by_name("SIP_ADD_NEWPROVIDER") + .expect("SIP_ADD_NEWPROVIDER exists"); +} + +#[test] +fn test_create_type_library() { + let _session = Session::new().expect("Failed to initialize session"); + let platform = Platform::by_name("windows-x86").expect("windows-x86 exists"); + let arch = platform.arch(); + + // Create the new type library. + let my_library = TypeLibrary::new(arch, "test_type_lib"); + my_library.add_alternate_name("alternate_test"); + my_library.add_platform(&platform); + my_library.add_named_type("test_type".into(), &Type::int(7, true)); + + // Write the library to a file. + let temp_dir = tempfile::tempdir().expect("Failed to create temp dir"); + let my_library_path = temp_dir.path().join("test_type_lib.bntl"); + assert!(my_library.write_to_file(&my_library_path)); + + // Verify the contents of the created file. + let loaded_library = + TypeLibrary::load_from_file(&my_library_path).expect("Failed to load type library"); + assert_eq!(loaded_library.name(), "test_type_lib"); + assert_eq!( + loaded_library.alternate_names().to_vec(), + vec!["alternate_test"] + ); + assert_eq!( + loaded_library.platform_names().to_vec(), + vec!["windows-x86"] + ); + assert_eq!( + loaded_library + .get_named_type("test_type".into()) + .unwrap() + .width(), + 7 + ); +} From 6cbe261498350c4d42fd2c308a9e5a377f7e9f43 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 15:56:58 -0400 Subject: [PATCH 52/54] [Rust] Add type library example --- rust/examples/dump_type_library.rs | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 rust/examples/dump_type_library.rs diff --git a/rust/examples/dump_type_library.rs b/rust/examples/dump_type_library.rs new file mode 100644 index 0000000000..00e7fb097f --- /dev/null +++ b/rust/examples/dump_type_library.rs @@ -0,0 +1,44 @@ +// Usage: cargo run --example dump_type_library + +use binaryninja::binary_view::BinaryView; +use binaryninja::file_metadata::FileMetadata; +use binaryninja::type_library::TypeLibrary; +use binaryninja::type_printer::{CoreTypePrinter, TokenEscapingType}; + +fn main() { + let type_lib_str = std::env::args().nth(1).expect("No type library provided"); + let type_lib_path = std::path::Path::new(&type_lib_str); + + println!("Starting session..."); + // This loads all the core architecture, platform, etc plugins + let _headless_session = + binaryninja::headless::Session::new().expect("Failed to initialize session"); + + let type_lib = TypeLibrary::load_from_file(type_lib_path).expect("Failed to load type library"); + let named_types = type_lib.named_types(); + println!("Name: `{}`", type_lib.name()); + println!("GUID: `{}`", type_lib.guid()); + + // Print out all the types as a c header. + let type_lib_header_path = type_lib_path.with_extension("h"); + println!( + "Dumping {} types to: `{:?}`", + named_types.len(), + type_lib_header_path + ); + let type_printer = CoreTypePrinter::default(); + let empty_bv = + BinaryView::from_data(&FileMetadata::new(), &[]).expect("Failed to create empty view"); + let printed_types = type_printer + .print_all_types( + &type_lib.named_types(), + &empty_bv, + 4, + TokenEscapingType::NoTokenEscapingType, + ) + .expect("Failed to print types"); + + // Write the header to disk. + std::fs::write(type_lib_header_path, printed_types) + .expect("Failed to write type library header"); +} From 2b334df0773a9dbda90b1f57f1e95ca62986cc19 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 16:40:30 -0400 Subject: [PATCH 53/54] [Rust] Keep `TypeArchiveSnapshotId` as a c_str when passing to core --- rust/src/type_archive.rs | 108 ++++++++++++++------------------------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/rust/src/type_archive.rs b/rust/src/type_archive.rs index f4d1087c4e..5f7ffb84ad 100644 --- a/rust/src/type_archive.rs +++ b/rust/src/type_archive.rs @@ -133,9 +133,8 @@ impl TypeArchive { /// Revert the type archive's current snapshot to the given snapshot pub fn set_current_snapshot_id(&self, id: &TypeArchiveSnapshotId) { - unsafe { - BNSetTypeArchiveCurrentSnapshot(self.handle.as_ptr(), id.0.as_ptr() as *const c_char) - } + let snapshot = id.clone().to_cstr(); + unsafe { BNSetTypeArchiveCurrentSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) } } /// Get a list of every snapshot's id @@ -152,12 +151,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Option> { let mut count = 0; + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveSnapshotParentIds( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - &mut count, - ) + BNGetTypeArchiveSnapshotParentIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) }; (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) }) } @@ -168,12 +164,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Option> { let mut count = 0; + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveSnapshotChildIds( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - &mut count, - ) + BNGetTypeArchiveSnapshotChildIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) }; (!result.is_null()).then(|| unsafe { Array::new(result, count, ()) }) } @@ -267,12 +260,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Option> { let raw_name = QualifiedName::into_raw(name); + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveTypeByName( - self.handle.as_ptr(), - &raw_name, - snapshot.0.as_ptr() as *const c_char, - ) + BNGetTypeArchiveTypeByName(self.handle.as_ptr(), &raw_name, snapshot.as_ptr()) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) @@ -295,12 +285,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Option> { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveTypeById( - self.handle.as_ptr(), - id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - ) + BNGetTypeArchiveTypeById(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr()) }; (!result.is_null()).then(|| unsafe { Type::ref_from_raw(result) }) } @@ -322,12 +309,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> QualifiedName { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveTypeName( - self.handle.as_ptr(), - id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - ) + BNGetTypeArchiveTypeName(self.handle.as_ptr(), id.as_ptr(), snapshot.as_ptr()) }; QualifiedName::from_owned_raw(result) } @@ -349,13 +333,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Option { let raw_name = QualifiedName::into_raw(name); - let result = unsafe { - BNGetTypeArchiveTypeId( - self.handle.as_ptr(), - &raw_name, - snapshot.0.as_ptr() as *const c_char, - ) - }; + let snapshot = snapshot.clone().to_cstr(); + let result = + unsafe { BNGetTypeArchiveTypeId(self.handle.as_ptr(), &raw_name, snapshot.as_ptr()) }; QualifiedName::free_raw(raw_name); (!result.is_null()).then(|| unsafe { BnString::into_string(result) }) } @@ -373,13 +353,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let mut count = 0; - let result = unsafe { - BNGetTypeArchiveTypes( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - &mut count, - ) - }; + let snapshot = snapshot.clone().to_cstr(); + let result = + unsafe { BNGetTypeArchiveTypes(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -394,13 +370,9 @@ impl TypeArchive { /// * `snapshot` - Snapshot id to search for types pub fn get_type_ids_from_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> Array { let mut count = 0; - let result = unsafe { - BNGetTypeArchiveTypeIds( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - &mut count, - ) - }; + let snapshot = snapshot.clone().to_cstr(); + let result = + unsafe { BNGetTypeArchiveTypeIds(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } } @@ -418,12 +390,9 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let mut count = 0; + let snapshot = snapshot.clone().to_cstr(); let result = unsafe { - BNGetTypeArchiveTypeNames( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - &mut count, - ) + BNGetTypeArchiveTypeNames(self.handle.as_ptr(), snapshot.as_ptr(), &mut count) }; assert!(!result.is_null()); unsafe { Array::new(result, count, ()) } @@ -442,12 +411,13 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> (Array, Array) { let mut count = 0; + let snapshot = snapshot.clone().to_cstr(); let mut names = std::ptr::null_mut(); let mut ids = std::ptr::null_mut(); let result = unsafe { BNGetTypeArchiveTypeNamesAndIds( self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, + snapshot.as_ptr(), &mut names, &mut ids, &mut count, @@ -476,12 +446,13 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingDirectTypeReferences( self.handle.as_ptr(), id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, + snapshot.as_ptr(), &mut count, ) }; @@ -506,12 +477,13 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveOutgoingRecursiveTypeReferences( self.handle.as_ptr(), id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, + snapshot.as_ptr(), &mut count, ) }; @@ -536,12 +508,13 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingDirectTypeReferences( self.handle.as_ptr(), id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, + snapshot.as_ptr(), &mut count, ) }; @@ -566,12 +539,13 @@ impl TypeArchive { snapshot: &TypeArchiveSnapshotId, ) -> Array { let id = id.to_cstr(); + let snapshot = snapshot.clone().to_cstr(); let mut count = 0; let result = unsafe { BNGetTypeArchiveIncomingRecursiveTypeReferences( self.handle.as_ptr(), id.as_ptr(), - snapshot.0.as_ptr() as *const c_char, + snapshot.as_ptr(), &mut count, ) }; @@ -605,12 +579,9 @@ impl TypeArchive { /// Turn a given `snapshot` id into a data stream pub fn serialize_snapshot(&self, snapshot: &TypeArchiveSnapshotId) -> DataBuffer { - let result = unsafe { - BNTypeArchiveSerializeSnapshot( - self.handle.as_ptr(), - snapshot.0.as_ptr() as *const c_char, - ) - }; + let snapshot = snapshot.clone().to_cstr(); + let result = + unsafe { BNTypeArchiveSerializeSnapshot(self.handle.as_ptr(), snapshot.as_ptr()) }; assert!(!result.is_null()); DataBuffer::from_raw(result) } @@ -712,15 +683,14 @@ impl TypeArchive { fun(&TypeArchiveSnapshotId(id_str)) } - // SAFETY TypeArchiveSnapshotId and `*const c_char` are transparent - let parents_raw = parents.as_ptr() as *const *const c_char; - + let parents_cstr: Vec<_> = parents.iter().map(|p| p.clone().to_cstr()).collect(); + let parents_raw: Vec<_> = parents_cstr.iter().map(|p| p.as_ptr()).collect(); let result = unsafe { BNTypeArchiveNewSnapshotTransaction( self.handle.as_ptr(), Some(cb_callback::), &mut function as *mut F as *mut c_void, - parents_raw, + parents_raw.as_ptr(), parents.len(), ) }; From 32ca34a03f53867493beaf793dfcb06e95a66a1b Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 12 May 2025 16:43:42 -0400 Subject: [PATCH 54/54] [Rust] Misc cleanup regarding c strings --- rust/src/function.rs | 13 +++++++------ rust/src/interaction/report.rs | 19 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust/src/function.rs b/rust/src/function.rs index 58b310c745..60c8970c3d 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -48,10 +48,11 @@ use crate::variable::{ StackVariableReference, Variable, }; use crate::workflow::Workflow; +use std::ffi::CStr; use std::fmt::{Debug, Formatter}; use std::ptr::NonNull; use std::time::Duration; -use std::{ffi::c_char, hash::Hash, ops::Range}; +use std::{hash::Hash, ops::Range}; /// Used to describe a location within a [`Function`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -2213,17 +2214,17 @@ impl Function { /// /// * `name` - Name of the debug report pub fn request_debug_report(&self, name: &str) { - const DEBUG_REPORT_ALIAS: &[(&str, &str)] = &[ - ("stack", "stack_adjust_graph\x00"), - ("mlil", "mlil_translator\x00"), - ("hlil", "high_level_il\x00"), + const DEBUG_REPORT_ALIAS: &[(&str, &CStr)] = &[ + ("stack", c"stack_adjust_graph"), + ("mlil", c"mlil_translator"), + ("hlil", c"high_level_il"), ]; if let Some(alias_idx) = DEBUG_REPORT_ALIAS .iter() .position(|(alias, _value)| *alias == name) { - let name = DEBUG_REPORT_ALIAS[alias_idx].1.as_ptr() as *const c_char; + let name = DEBUG_REPORT_ALIAS[alias_idx].1.as_ptr(); unsafe { BNRequestFunctionDebugReport(self.handle, name) } } else { let name = std::ffi::CString::new(name.to_string()).unwrap(); diff --git a/rust/src/interaction/report.rs b/rust/src/interaction/report.rs index 689b815bb5..415845db75 100644 --- a/rust/src/interaction/report.rs +++ b/rust/src/interaction/report.rs @@ -1,4 +1,3 @@ -use std::ffi::c_char; use std::ptr::NonNull; use binaryninjacore_sys::*; @@ -81,8 +80,8 @@ impl ReportCollection { BNAddPlainTextReportToCollection( self.handle.as_ptr(), view.handle, - title.as_ref().as_ptr() as *const c_char, - contents.as_ref().as_ptr() as *const c_char, + title.as_ptr(), + contents.as_ptr(), ) } } @@ -95,9 +94,9 @@ impl ReportCollection { BNAddMarkdownReportToCollection( self.handle.as_ptr(), view.handle, - title.as_ref().as_ptr() as *const c_char, - contents.as_ref().as_ptr() as *const c_char, - plaintext.as_ref().as_ptr() as *const c_char, + title.as_ptr(), + contents.as_ptr(), + plaintext.as_ptr(), ) } } @@ -110,9 +109,9 @@ impl ReportCollection { BNAddHTMLReportToCollection( self.handle.as_ptr(), view.handle, - title.as_ref().as_ptr() as *const c_char, - contents.as_ref().as_ptr() as *const c_char, - plaintext.as_ref().as_ptr() as *const c_char, + title.as_ptr(), + contents.as_ptr(), + plaintext.as_ptr(), ) } } @@ -123,7 +122,7 @@ impl ReportCollection { BNAddGraphReportToCollection( self.handle.as_ptr(), view.handle, - title.as_ref().as_ptr() as *const c_char, + title.as_ptr(), graph.handle, ) }