binaryninja/
symbol.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Interfaces for the various kinds of symbols in a binary.
16
17use std::fmt;
18use std::fmt::Debug;
19use std::hash::{Hash, Hasher};
20use std::ptr;
21
22use crate::rc::*;
23use crate::string::*;
24use binaryninjacore_sys::*;
25
26// TODO : Rename
27#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
28pub enum SymbolType {
29    Function,
30    LibraryFunction,
31    ImportAddress,
32    ImportedFunction,
33    Data,
34    ImportedData,
35    External,
36    Symbolic,
37    LocalLabel,
38}
39
40impl From<BNSymbolType> for SymbolType {
41    fn from(bn: BNSymbolType) -> SymbolType {
42        use self::BNSymbolType::*;
43
44        match bn {
45            FunctionSymbol => SymbolType::Function,
46            LibraryFunctionSymbol => SymbolType::LibraryFunction,
47            ImportAddressSymbol => SymbolType::ImportAddress,
48            ImportedFunctionSymbol => SymbolType::ImportedFunction,
49            DataSymbol => SymbolType::Data,
50            ImportedDataSymbol => SymbolType::ImportedData,
51            ExternalSymbol => SymbolType::External,
52            SymbolicFunctionSymbol => SymbolType::Symbolic,
53            LocalLabelSymbol => SymbolType::LocalLabel,
54        }
55    }
56}
57
58impl From<SymbolType> for BNSymbolType {
59    fn from(symbol_type: SymbolType) -> Self {
60        use self::BNSymbolType::*;
61
62        match symbol_type {
63            SymbolType::Function => FunctionSymbol,
64            SymbolType::LibraryFunction => LibraryFunctionSymbol,
65            SymbolType::ImportAddress => ImportAddressSymbol,
66            SymbolType::ImportedFunction => ImportedFunctionSymbol,
67            SymbolType::Data => DataSymbol,
68            SymbolType::ImportedData => ImportedDataSymbol,
69            SymbolType::External => ExternalSymbol,
70            SymbolType::Symbolic => SymbolicFunctionSymbol,
71            SymbolType::LocalLabel => LocalLabelSymbol,
72        }
73    }
74}
75
76#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
77pub enum Binding {
78    None,
79    Local,
80    Global,
81    Weak,
82}
83
84impl From<BNSymbolBinding> for Binding {
85    fn from(bn: BNSymbolBinding) -> Binding {
86        use self::BNSymbolBinding::*;
87
88        match bn {
89            NoBinding => Binding::None,
90            LocalBinding => Binding::Local,
91            GlobalBinding => Binding::Global,
92            WeakBinding => Binding::Weak,
93        }
94    }
95}
96
97impl From<Binding> for BNSymbolBinding {
98    fn from(binding: Binding) -> Self {
99        use self::BNSymbolBinding::*;
100
101        match binding {
102            Binding::None => NoBinding,
103            Binding::Local => LocalBinding,
104            Binding::Global => GlobalBinding,
105            Binding::Weak => WeakBinding,
106        }
107    }
108}
109
110// TODO : Clean this up
111#[must_use]
112pub struct SymbolBuilder {
113    ty: SymbolType,
114    binding: Binding,
115    addr: u64,
116    raw_name: String,
117    short_name: Option<String>,
118    full_name: Option<String>,
119    ordinal: u64,
120}
121
122impl SymbolBuilder {
123    pub fn new<T: Into<String>>(ty: SymbolType, raw_name: T, addr: u64) -> Self {
124        Self {
125            ty,
126            binding: Binding::None,
127            addr,
128            raw_name: raw_name.into(),
129            short_name: None,
130            full_name: None,
131            ordinal: 0,
132        }
133    }
134
135    pub fn binding(mut self, binding: Binding) -> Self {
136        self.binding = binding;
137        self
138    }
139
140    pub fn short_name<T: Into<String>>(mut self, short_name: T) -> Self {
141        self.short_name = Some(short_name.into());
142        self
143    }
144
145    pub fn full_name<T: Into<String>>(mut self, full_name: T) -> Self {
146        self.full_name = Some(full_name.into());
147        self
148    }
149
150    pub fn ordinal(mut self, ordinal: u64) -> Self {
151        self.ordinal = ordinal;
152        self
153    }
154
155    pub fn create(self) -> Ref<Symbol> {
156        let raw_name = self.raw_name.to_cstr();
157        let short_name = self.short_name.map(|s| s.to_cstr());
158        let full_name = self.full_name.map(|s| s.to_cstr());
159
160        // Lifetimes, man
161        let raw_name = raw_name.as_ptr() as _;
162        unsafe {
163            if let Some(short_name) = short_name {
164                if let Some(full_name) = full_name {
165                    let res = BNCreateSymbol(
166                        self.ty.into(),
167                        short_name.as_ptr() as _,
168                        full_name.as_ptr() as _,
169                        raw_name,
170                        self.addr,
171                        self.binding.into(),
172                        ptr::null_mut(),
173                        self.ordinal,
174                    );
175                    Symbol::ref_from_raw(res)
176                } else {
177                    let res = BNCreateSymbol(
178                        self.ty.into(),
179                        short_name.as_ptr() as _,
180                        raw_name,
181                        raw_name,
182                        self.addr,
183                        self.binding.into(),
184                        ptr::null_mut(),
185                        self.ordinal,
186                    );
187                    Symbol::ref_from_raw(res)
188                }
189            } else if let Some(full_name) = full_name {
190                let res = BNCreateSymbol(
191                    self.ty.into(),
192                    raw_name,
193                    full_name.as_ptr() as _,
194                    raw_name,
195                    self.addr,
196                    self.binding.into(),
197                    ptr::null_mut(),
198                    self.ordinal,
199                );
200                Symbol::ref_from_raw(res)
201            } else {
202                let res = BNCreateSymbol(
203                    self.ty.into(),
204                    raw_name,
205                    raw_name,
206                    raw_name,
207                    self.addr,
208                    self.binding.into(),
209                    ptr::null_mut(),
210                    self.ordinal,
211                );
212                Symbol::ref_from_raw(res)
213            }
214        }
215    }
216}
217
218#[derive(Eq)]
219pub struct Symbol {
220    pub handle: *mut BNSymbol,
221}
222
223impl Symbol {
224    pub(crate) unsafe fn ref_from_raw(raw: *mut BNSymbol) -> Ref<Self> {
225        Ref::new(Self { handle: raw })
226    }
227
228    pub(crate) unsafe fn from_raw(raw: *mut BNSymbol) -> Self {
229        Self { handle: raw }
230    }
231
232    /// To create a new symbol, you need to create a symbol builder, customize that symbol, then add `SymbolBuilder::create` it into a `Ref<Symbol>`:
233    ///
234    /// ```no_run
235    /// # use binaryninja::symbol::Symbol;
236    /// # use binaryninja::symbol::SymbolType;
237    /// Symbol::builder(SymbolType::Data, "hello", 0x1337)
238    ///     .short_name("hello")
239    ///     .full_name("hello")
240    ///     .create();
241    /// ```
242    pub fn builder(ty: SymbolType, raw_name: &str, addr: u64) -> SymbolBuilder {
243        SymbolBuilder::new(ty, raw_name, addr)
244    }
245
246    pub fn sym_type(&self) -> SymbolType {
247        unsafe { BNGetSymbolType(self.handle).into() }
248    }
249
250    pub fn binding(&self) -> Binding {
251        unsafe { BNGetSymbolBinding(self.handle).into() }
252    }
253
254    pub fn full_name(&self) -> BnString {
255        unsafe { BnString::from_raw(BNGetSymbolFullName(self.handle)) }
256    }
257
258    pub fn short_name(&self) -> BnString {
259        unsafe { BnString::from_raw(BNGetSymbolShortName(self.handle)) }
260    }
261
262    pub fn raw_name(&self) -> BnString {
263        unsafe { BnString::from_raw(BNGetSymbolRawName(self.handle)) }
264    }
265
266    pub fn address(&self) -> u64 {
267        unsafe { BNGetSymbolAddress(self.handle) }
268    }
269
270    pub fn auto_defined(&self) -> bool {
271        unsafe { BNIsSymbolAutoDefined(self.handle) }
272    }
273
274    /// Whether this symbol has external linkage
275    pub fn external(&self) -> bool {
276        self.binding() == Binding::Weak || self.binding() == Binding::Global
277    }
278
279    pub fn imported_function_from_import_address_symbol(sym: &Symbol, addr: u64) -> Ref<Symbol> {
280        unsafe {
281            let res = BNImportedFunctionFromImportAddressSymbol(sym.handle, addr);
282            Symbol::ref_from_raw(res)
283        }
284    }
285}
286
287unsafe impl Send for Symbol {}
288unsafe impl Sync for Symbol {}
289
290impl Debug for Symbol {
291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292        f.debug_struct("Symbol")
293            .field("type", &self.sym_type())
294            .field("binding", &self.binding())
295            .field("full_name", &self.full_name())
296            .field("short_name", &self.short_name())
297            .field("raw_name", &self.raw_name())
298            .field("address", &self.address())
299            .field("auto_defined", &self.auto_defined())
300            .field("external", &self.external())
301            .finish()
302    }
303}
304
305impl ToOwned for Symbol {
306    type Owned = Ref<Self>;
307
308    fn to_owned(&self) -> Self::Owned {
309        unsafe { RefCountable::inc_ref(self) }
310    }
311}
312
313unsafe impl RefCountable for Symbol {
314    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
315        Ref::new(Self {
316            handle: BNNewSymbolReference(handle.handle),
317        })
318    }
319
320    unsafe fn dec_ref(handle: &Self) {
321        BNFreeSymbol(handle.handle);
322    }
323}
324
325impl CoreArrayProvider for Symbol {
326    type Raw = *mut BNSymbol;
327    type Context = ();
328    type Wrapped<'a> = Guard<'a, Symbol>;
329}
330
331unsafe impl CoreArrayProviderInner for Symbol {
332    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
333        BNFreeSymbolList(raw, count);
334    }
335
336    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
337        Guard::new(Symbol::from_raw(*raw), context)
338    }
339}
340
341impl Hash for Symbol {
342    fn hash<H: Hasher>(&self, state: &mut H) {
343        self.handle.hash(state);
344    }
345}
346
347impl PartialEq for Symbol {
348    fn eq(&self, other: &Self) -> bool {
349        self.handle == other.handle
350    }
351}