binaryninja/
section.rs

1// Copyright 2021-2026 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//! Sections are [crate::segment::Segment]s that are loaded into memory at run time
16
17use std::fmt;
18use std::hash::{Hash, Hasher};
19use std::ops::Range;
20
21use binaryninjacore_sys::*;
22
23use crate::binary_view::BinaryView;
24use crate::rc::*;
25use crate::string::*;
26
27#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
28pub enum Semantics {
29    #[default]
30    DefaultSection,
31    ReadOnlyCode,
32    ReadOnlyData,
33    ReadWriteData,
34    External,
35}
36
37impl From<BNSectionSemantics> for Semantics {
38    fn from(bn: BNSectionSemantics) -> Self {
39        use self::BNSectionSemantics::*;
40
41        match bn {
42            DefaultSectionSemantics => Semantics::DefaultSection,
43            ReadOnlyCodeSectionSemantics => Semantics::ReadOnlyCode,
44            ReadOnlyDataSectionSemantics => Semantics::ReadOnlyData,
45            ReadWriteDataSectionSemantics => Semantics::ReadWriteData,
46            ExternalSectionSemantics => Semantics::External,
47        }
48    }
49}
50
51impl From<Semantics> for BNSectionSemantics {
52    fn from(semantics: Semantics) -> Self {
53        use self::BNSectionSemantics::*;
54
55        match semantics {
56            Semantics::DefaultSection => DefaultSectionSemantics,
57            Semantics::ReadOnlyCode => ReadOnlyCodeSectionSemantics,
58            Semantics::ReadOnlyData => ReadOnlyDataSectionSemantics,
59            Semantics::ReadWriteData => ReadWriteDataSectionSemantics,
60            Semantics::External => ExternalSectionSemantics,
61        }
62    }
63}
64
65pub struct Section {
66    handle: *mut BNSection,
67}
68
69impl Section {
70    pub(crate) unsafe fn from_raw(handle: *mut BNSection) -> Self {
71        debug_assert!(!handle.is_null());
72        Self { handle }
73    }
74
75    pub(crate) unsafe fn ref_from_raw(handle: *mut BNSection) -> Ref<Self> {
76        debug_assert!(!handle.is_null());
77        Ref::new(Self { handle })
78    }
79
80    /// You need to create a section builder, customize that section, then add it to a binary view:
81    ///
82    /// ```no_run
83    /// # use binaryninja::section::Section;
84    /// let bv = binaryninja::load("example").unwrap();
85    /// bv.add_section(Section::builder("example".to_string(), 0..1024).align(4).entry_size(4))
86    /// ```
87    pub fn builder(name: String, range: Range<u64>) -> SectionBuilder {
88        SectionBuilder::new(name, range)
89    }
90
91    pub fn name(&self) -> BnString {
92        unsafe { BnString::from_raw(BNSectionGetName(self.handle)) }
93    }
94
95    pub fn section_type(&self) -> String {
96        unsafe { BnString::into_string(BNSectionGetType(self.handle)) }
97    }
98
99    pub fn start(&self) -> u64 {
100        unsafe { BNSectionGetStart(self.handle) }
101    }
102
103    pub fn end(&self) -> u64 {
104        unsafe { BNSectionGetEnd(self.handle) }
105    }
106
107    pub fn len(&self) -> usize {
108        unsafe { BNSectionGetLength(self.handle) as usize }
109    }
110
111    pub fn is_empty(&self) -> bool {
112        self.len() == 0
113    }
114
115    pub fn address_range(&self) -> Range<u64> {
116        self.start()..self.end()
117    }
118
119    pub fn semantics(&self) -> Semantics {
120        unsafe { BNSectionGetSemantics(self.handle).into() }
121    }
122
123    pub fn linked_section(&self) -> BnString {
124        unsafe { BnString::from_raw(BNSectionGetLinkedSection(self.handle)) }
125    }
126
127    pub fn info_section(&self) -> BnString {
128        unsafe { BnString::from_raw(BNSectionGetInfoSection(self.handle)) }
129    }
130
131    pub fn info_data(&self) -> u64 {
132        unsafe { BNSectionGetInfoData(self.handle) }
133    }
134
135    pub fn align(&self) -> u64 {
136        unsafe { BNSectionGetAlign(self.handle) }
137    }
138
139    pub fn entry_size(&self) -> usize {
140        unsafe { BNSectionGetEntrySize(self.handle) as usize }
141    }
142
143    pub fn auto_defined(&self) -> bool {
144        unsafe { BNSectionIsAutoDefined(self.handle) }
145    }
146}
147
148impl fmt::Debug for Section {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        f.debug_struct("Section")
151            .field("name", &self.name())
152            .field("address_range", &self.address_range())
153            .field("section_type", &self.section_type())
154            .field("semantics", &self.semantics())
155            .field("linked_section", &self.linked_section())
156            .field("align", &self.align())
157            .field("entry_size", &self.entry_size())
158            .field("auto_defined", &self.auto_defined())
159            .finish()
160    }
161}
162
163impl PartialEq for Section {
164    fn eq(&self, other: &Self) -> bool {
165        // TODO: Do we want to make this complete match like this?
166        self.name() == other.name()
167            && self.address_range() == other.address_range()
168            && self.semantics() == other.semantics()
169            && self.linked_section() == other.linked_section()
170            && self.info_section() == other.info_section()
171            && self.info_data() == other.info_data()
172            && self.align() == other.align()
173            && self.entry_size() == other.entry_size()
174            && self.auto_defined() == other.auto_defined()
175    }
176}
177
178impl Eq for Section {}
179
180impl Hash for Section {
181    fn hash<H: Hasher>(&self, state: &mut H) {
182        self.name().hash(state);
183        self.address_range().hash(state);
184    }
185}
186
187impl ToOwned for Section {
188    type Owned = Ref<Self>;
189
190    fn to_owned(&self) -> Self::Owned {
191        unsafe { RefCountable::inc_ref(self) }
192    }
193}
194
195unsafe impl RefCountable for Section {
196    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
197        Ref::new(Self {
198            handle: BNNewSectionReference(handle.handle),
199        })
200    }
201
202    unsafe fn dec_ref(handle: &Self) {
203        BNFreeSection(handle.handle);
204    }
205}
206
207impl CoreArrayProvider for Section {
208    type Raw = *mut BNSection;
209    type Context = ();
210    type Wrapped<'a> = Guard<'a, Section>;
211}
212
213unsafe impl CoreArrayProviderInner for Section {
214    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
215        BNFreeSectionList(raw, count);
216    }
217
218    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
219        Guard::new(Section::from_raw(*raw), context)
220    }
221}
222
223#[must_use]
224#[derive(Clone, Debug, PartialEq, Eq, Hash)]
225pub struct SectionBuilder {
226    is_auto: bool,
227    name: String,
228    range: Range<u64>,
229    semantics: Semantics,
230    ty: String,
231    align: u64,
232    entry_size: u64,
233    linked_section: String,
234    info_section: String,
235    info_data: u64,
236}
237
238impl SectionBuilder {
239    pub fn new(name: String, range: Range<u64>) -> Self {
240        Self {
241            is_auto: false,
242            name,
243            range,
244            semantics: Semantics::DefaultSection,
245            ty: "".to_string(),
246            align: 1,
247            entry_size: 1,
248            linked_section: "".to_string(),
249            info_section: "".to_string(),
250            info_data: 0,
251        }
252    }
253
254    pub fn semantics(mut self, semantics: Semantics) -> Self {
255        self.semantics = semantics;
256        self
257    }
258
259    pub fn section_type(mut self, ty: String) -> Self {
260        self.ty = ty;
261        self
262    }
263
264    pub fn align(mut self, align: u64) -> Self {
265        self.align = align;
266        self
267    }
268
269    pub fn entry_size(mut self, entry_size: u64) -> Self {
270        self.entry_size = entry_size;
271        self
272    }
273
274    pub fn linked_section(mut self, linked_section: String) -> Self {
275        self.linked_section = linked_section;
276        self
277    }
278
279    pub fn info_section(mut self, info_section: String) -> Self {
280        self.info_section = info_section;
281        self
282    }
283
284    pub fn info_data(mut self, info_data: u64) -> Self {
285        self.info_data = info_data;
286        self
287    }
288
289    pub fn is_auto(mut self, is_auto: bool) -> Self {
290        self.is_auto = is_auto;
291        self
292    }
293
294    pub(crate) fn create(self, view: &BinaryView) {
295        let name = self.name.to_cstr();
296        let ty = self.ty.to_cstr();
297        let linked_section = self.linked_section.to_cstr();
298        let info_section = self.info_section.to_cstr();
299
300        let start = self.range.start;
301        let len = self.range.end.wrapping_sub(start);
302
303        unsafe {
304            if self.is_auto {
305                BNAddAutoSection(
306                    view.handle,
307                    name.as_ptr(),
308                    start,
309                    len,
310                    self.semantics.into(),
311                    ty.as_ptr(),
312                    self.align,
313                    self.entry_size,
314                    linked_section.as_ptr(),
315                    info_section.as_ptr(),
316                    self.info_data,
317                );
318            } else {
319                BNAddUserSection(
320                    view.handle,
321                    name.as_ptr(),
322                    start,
323                    len,
324                    self.semantics.into(),
325                    ty.as_ptr(),
326                    self.align,
327                    self.entry_size,
328                    linked_section.as_ptr(),
329                    info_section.as_ptr(),
330                    self.info_data,
331                );
332            }
333        }
334    }
335}
336
337impl<T: AsRef<Section>> From<T> for SectionBuilder {
338    fn from(value: T) -> Self {
339        let value = value.as_ref();
340        let name = value.name().to_string_lossy().to_string();
341        let ty = value.section_type().to_string();
342        let linked_section = value.linked_section().to_string_lossy().to_string();
343        let info_section = value.info_section().to_string_lossy().to_string();
344
345        Self {
346            is_auto: value.auto_defined(),
347            name,
348            range: value.address_range(),
349            semantics: value.semantics(),
350            ty,
351            align: value.align(),
352            entry_size: value.entry_size() as u64,
353            linked_section,
354            info_section,
355            info_data: value.info_data(),
356        }
357    }
358}