binaryninja/
tags.rs

1// Copyright 2022-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 creating and modifying tags in a BinaryView.
16
17use binaryninjacore_sys::*;
18use std::fmt::{Debug, Formatter};
19
20use crate::architecture::CoreArchitecture;
21use crate::binary_view::BinaryView;
22
23use crate::function::Function;
24use crate::rc::*;
25use crate::string::*;
26
27pub type TagTypeType = BNTagTypeType;
28pub type TagReferenceType = BNTagReferenceType;
29
30pub struct Tag {
31    pub(crate) handle: *mut BNTag,
32}
33
34impl Tag {
35    pub(crate) unsafe fn from_raw(handle: *mut BNTag) -> Self {
36        debug_assert!(!handle.is_null());
37        Self { handle }
38    }
39
40    pub(crate) unsafe fn ref_from_raw(handle: *mut BNTag) -> Ref<Self> {
41        debug_assert!(!handle.is_null());
42        Ref::new(Self { handle })
43    }
44
45    pub fn new(t: &TagType, data: &str) -> Ref<Self> {
46        let data = data.to_cstr();
47        unsafe { Self::ref_from_raw(BNCreateTag(t.handle, data.as_ptr())) }
48    }
49
50    pub fn id(&self) -> String {
51        unsafe { BnString::into_string(BNTagGetId(self.handle)) }
52    }
53
54    pub fn data(&self) -> String {
55        unsafe { BnString::into_string(BNTagGetData(self.handle)) }
56    }
57
58    pub fn ty(&self) -> Ref<TagType> {
59        unsafe { TagType::ref_from_raw(BNTagGetType(self.handle)) }
60    }
61
62    pub fn set_data(&self, data: &str) {
63        let data = data.to_cstr();
64        unsafe {
65            BNTagSetData(self.handle, data.as_ptr());
66        }
67    }
68}
69
70impl Debug for Tag {
71    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72        f.debug_struct("Tag")
73            .field("id", &self.id())
74            .field("data", &self.data())
75            .field("type", &self.ty())
76            .finish()
77    }
78}
79
80impl PartialEq for Tag {
81    fn eq(&self, other: &Self) -> bool {
82        self.id() == other.id()
83    }
84}
85
86impl Eq for Tag {}
87
88unsafe impl RefCountable for Tag {
89    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
90        Ref::new(Self {
91            handle: BNNewTagReference(handle.handle),
92        })
93    }
94
95    unsafe fn dec_ref(handle: &Self) {
96        BNFreeTag(handle.handle);
97    }
98}
99
100impl ToOwned for Tag {
101    type Owned = Ref<Self>;
102
103    fn to_owned(&self) -> Self::Owned {
104        unsafe { RefCountable::inc_ref(self) }
105    }
106}
107
108impl CoreArrayProvider for Tag {
109    type Raw = *mut BNTag;
110    type Context = ();
111    type Wrapped<'a> = Guard<'a, Tag>;
112}
113
114unsafe impl CoreArrayProviderInner for Tag {
115    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
116        BNFreeTagList(raw, count)
117    }
118
119    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
120        Guard::new(Self { handle: *raw }, &context)
121    }
122}
123
124unsafe impl Send for Tag {}
125unsafe impl Sync for Tag {}
126
127pub struct TagType {
128    pub(crate) handle: *mut BNTagType,
129}
130
131impl TagType {
132    pub(crate) unsafe fn ref_from_raw(handle: *mut BNTagType) -> Ref<Self> {
133        debug_assert!(!handle.is_null());
134        Ref::new(Self { handle })
135    }
136
137    pub fn create(view: &BinaryView, name: &str, icon: &str) -> Ref<Self> {
138        let tag_type = unsafe { Self::ref_from_raw(BNCreateTagType(view.handle)) };
139        tag_type.set_name(name);
140        tag_type.set_icon(icon);
141        tag_type.set_type(TagTypeType::UserTagType);
142        tag_type
143    }
144
145    pub fn id(&self) -> String {
146        unsafe { BnString::into_string(BNTagTypeGetId(self.handle)) }
147    }
148
149    pub fn icon(&self) -> String {
150        unsafe { BnString::into_string(BNTagTypeGetIcon(self.handle)) }
151    }
152
153    pub fn set_icon(&self, icon: &str) {
154        let icon = icon.to_cstr();
155        unsafe {
156            BNTagTypeSetIcon(self.handle, icon.as_ptr());
157        }
158    }
159
160    pub fn name(&self) -> String {
161        unsafe { BnString::into_string(BNTagTypeGetName(self.handle)) }
162    }
163
164    pub fn set_name(&self, name: &str) {
165        let name = name.to_cstr();
166        unsafe {
167            BNTagTypeSetName(self.handle, name.as_ptr());
168        }
169    }
170
171    pub fn visible(&self) -> bool {
172        unsafe { BNTagTypeGetVisible(self.handle) }
173    }
174
175    pub fn set_visible(&self, visible: bool) {
176        unsafe { BNTagTypeSetVisible(self.handle, visible) }
177    }
178
179    pub fn ty(&self) -> TagTypeType {
180        unsafe { BNTagTypeGetType(self.handle) }
181    }
182
183    pub fn set_type(&self, ty: TagTypeType) {
184        unsafe {
185            BNTagTypeSetType(self.handle, ty);
186        }
187    }
188
189    pub fn view(&self) -> Ref<BinaryView> {
190        unsafe { BinaryView::ref_from_raw(BNTagTypeGetView(self.handle)) }
191    }
192}
193
194impl Debug for TagType {
195    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
196        f.debug_struct("TagType")
197            .field("id", &self.id())
198            .field("name", &self.name())
199            .field("icon", &self.icon())
200            .field("visible", &self.visible())
201            .field("type", &self.ty())
202            .finish()
203    }
204}
205
206impl PartialEq for TagType {
207    fn eq(&self, other: &Self) -> bool {
208        self.id() == other.id()
209    }
210}
211
212impl Eq for TagType {}
213
214unsafe impl RefCountable for TagType {
215    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
216        Ref::new(Self {
217            handle: BNNewTagTypeReference(handle.handle),
218        })
219    }
220
221    unsafe fn dec_ref(handle: &Self) {
222        BNFreeTagType(handle.handle);
223    }
224}
225
226impl ToOwned for TagType {
227    type Owned = Ref<Self>;
228
229    fn to_owned(&self) -> Self::Owned {
230        unsafe { RefCountable::inc_ref(self) }
231    }
232}
233
234unsafe impl Send for TagType {}
235unsafe impl Sync for TagType {}
236
237#[derive(Clone, PartialEq)]
238pub struct TagReference {
239    pub arch: CoreArchitecture,
240    pub func: Ref<Function>,
241    pub addr: u64,
242    pub auto_defined: bool,
243    pub reference_type: TagReferenceType,
244    pub tag: Ref<Tag>,
245}
246
247impl From<&BNTagReference> for TagReference {
248    fn from(value: &BNTagReference) -> Self {
249        Self {
250            reference_type: value.refType,
251            auto_defined: value.autoDefined,
252            tag: unsafe { Tag::from_raw(value.tag).to_owned() },
253            arch: unsafe { CoreArchitecture::from_raw(value.arch) },
254            func: unsafe { Function::from_raw(value.func).to_owned() },
255            addr: value.addr,
256        }
257    }
258}
259
260impl Debug for TagReference {
261    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
262        f.debug_struct("TagReference")
263            .field("addr", &self.addr)
264            .field("auto_defined", &self.auto_defined)
265            .field("reference_type", &self.reference_type)
266            .field("tag", &self.tag)
267            .finish()
268    }
269}
270
271impl CoreArrayProvider for TagReference {
272    type Raw = BNTagReference;
273    type Context = ();
274    type Wrapped<'a> = Self;
275}
276
277unsafe impl CoreArrayProviderInner for TagReference {
278    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
279        BNFreeTagReferences(raw, count)
280    }
281
282    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
283        raw.into()
284    }
285}