binaryninja/
section.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//! 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    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    /// # use binaryninja::binary_view::BinaryViewExt;
85    /// let bv = binaryninja::load("example").unwrap();
86    /// bv.add_section(Section::builder("example".to_string(), 0..1024).align(4).entry_size(4))
87    /// ```
88    pub fn builder(name: String, range: Range<u64>) -> SectionBuilder {
89        SectionBuilder::new(name, range)
90    }
91
92    pub fn name(&self) -> BnString {
93        unsafe { BnString::from_raw(BNSectionGetName(self.handle)) }
94    }
95
96    pub fn section_type(&self) -> String {
97        unsafe { BnString::into_string(BNSectionGetType(self.handle)) }
98    }
99
100    pub fn start(&self) -> u64 {
101        unsafe { BNSectionGetStart(self.handle) }
102    }
103
104    pub fn end(&self) -> u64 {
105        unsafe { BNSectionGetEnd(self.handle) }
106    }
107
108    pub fn len(&self) -> usize {
109        unsafe { BNSectionGetLength(self.handle) as usize }
110    }
111
112    pub fn is_empty(&self) -> bool {
113        self.len() == 0
114    }
115
116    pub fn address_range(&self) -> Range<u64> {
117        self.start()..self.end()
118    }
119
120    pub fn semantics(&self) -> Semantics {
121        unsafe { BNSectionGetSemantics(self.handle).into() }
122    }
123
124    pub fn linked_section(&self) -> BnString {
125        unsafe { BnString::from_raw(BNSectionGetLinkedSection(self.handle)) }
126    }
127
128    pub fn info_section(&self) -> BnString {
129        unsafe { BnString::from_raw(BNSectionGetInfoSection(self.handle)) }
130    }
131
132    pub fn info_data(&self) -> u64 {
133        unsafe { BNSectionGetInfoData(self.handle) }
134    }
135
136    pub fn align(&self) -> u64 {
137        unsafe { BNSectionGetAlign(self.handle) }
138    }
139
140    pub fn entry_size(&self) -> usize {
141        unsafe { BNSectionGetEntrySize(self.handle) as usize }
142    }
143
144    pub fn auto_defined(&self) -> bool {
145        unsafe { BNSectionIsAutoDefined(self.handle) }
146    }
147}
148
149impl fmt::Debug for Section {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        f.debug_struct("Section")
152            .field("name", &self.name())
153            .field("address_range", &self.address_range())
154            .field("section_type", &self.section_type())
155            .field("semantics", &self.semantics())
156            .field("linked_section", &self.linked_section())
157            .field("align", &self.align())
158            .field("entry_size", &self.entry_size())
159            .field("auto_defined", &self.auto_defined())
160            .finish()
161    }
162}
163
164impl PartialEq for Section {
165    fn eq(&self, other: &Self) -> bool {
166        // TODO: Do we want to make this complete match like this?
167        self.name() == other.name()
168            && self.address_range() == other.address_range()
169            && self.semantics() == other.semantics()
170            && self.linked_section() == other.linked_section()
171            && self.info_section() == other.info_section()
172            && self.info_data() == other.info_data()
173            && self.align() == other.align()
174            && self.entry_size() == other.entry_size()
175            && self.auto_defined() == other.auto_defined()
176    }
177}
178
179impl Eq for Section {}
180
181impl Hash for Section {
182    fn hash<H: Hasher>(&self, state: &mut H) {
183        self.name().hash(state);
184        self.address_range().hash(state);
185    }
186}
187
188impl ToOwned for Section {
189    type Owned = Ref<Self>;
190
191    fn to_owned(&self) -> Self::Owned {
192        unsafe { RefCountable::inc_ref(self) }
193    }
194}
195
196unsafe impl RefCountable for Section {
197    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
198        Ref::new(Self {
199            handle: BNNewSectionReference(handle.handle),
200        })
201    }
202
203    unsafe fn dec_ref(handle: &Self) {
204        BNFreeSection(handle.handle);
205    }
206}
207
208impl CoreArrayProvider for Section {
209    type Raw = *mut BNSection;
210    type Context = ();
211    type Wrapped<'a> = Guard<'a, Section>;
212}
213
214unsafe impl CoreArrayProviderInner for Section {
215    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
216        BNFreeSectionList(raw, count);
217    }
218
219    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
220        Guard::new(Section::from_raw(*raw), context)
221    }
222}
223
224#[must_use]
225#[derive(Clone, Debug, PartialEq, Eq, Hash)]
226pub struct SectionBuilder {
227    is_auto: bool,
228    name: String,
229    range: Range<u64>,
230    semantics: Semantics,
231    ty: String,
232    align: u64,
233    entry_size: u64,
234    linked_section: String,
235    info_section: String,
236    info_data: u64,
237}
238
239impl SectionBuilder {
240    pub fn new(name: String, range: Range<u64>) -> Self {
241        Self {
242            is_auto: false,
243            name,
244            range,
245            semantics: Semantics::DefaultSection,
246            ty: "".to_string(),
247            align: 1,
248            entry_size: 1,
249            linked_section: "".to_string(),
250            info_section: "".to_string(),
251            info_data: 0,
252        }
253    }
254
255    pub fn semantics(mut self, semantics: Semantics) -> Self {
256        self.semantics = semantics;
257        self
258    }
259
260    pub fn section_type(mut self, ty: String) -> Self {
261        self.ty = ty;
262        self
263    }
264
265    pub fn align(mut self, align: u64) -> Self {
266        self.align = align;
267        self
268    }
269
270    pub fn entry_size(mut self, entry_size: u64) -> Self {
271        self.entry_size = entry_size;
272        self
273    }
274
275    pub fn linked_section(mut self, linked_section: String) -> Self {
276        self.linked_section = linked_section;
277        self
278    }
279
280    pub fn info_section(mut self, info_section: String) -> Self {
281        self.info_section = info_section;
282        self
283    }
284
285    pub fn info_data(mut self, info_data: u64) -> Self {
286        self.info_data = info_data;
287        self
288    }
289
290    pub fn is_auto(mut self, is_auto: bool) -> Self {
291        self.is_auto = is_auto;
292        self
293    }
294
295    pub(crate) fn create(self, view: &BinaryView) {
296        let name = self.name.to_cstr();
297        let ty = self.ty.to_cstr();
298        let linked_section = self.linked_section.to_cstr();
299        let info_section = self.info_section.to_cstr();
300
301        let start = self.range.start;
302        let len = self.range.end.wrapping_sub(start);
303
304        unsafe {
305            if self.is_auto {
306                BNAddAutoSection(
307                    view.handle,
308                    name.as_ptr(),
309                    start,
310                    len,
311                    self.semantics.into(),
312                    ty.as_ptr(),
313                    self.align,
314                    self.entry_size,
315                    linked_section.as_ptr(),
316                    info_section.as_ptr(),
317                    self.info_data,
318                );
319            } else {
320                BNAddUserSection(
321                    view.handle,
322                    name.as_ptr(),
323                    start,
324                    len,
325                    self.semantics.into(),
326                    ty.as_ptr(),
327                    self.align,
328                    self.entry_size,
329                    linked_section.as_ptr(),
330                    info_section.as_ptr(),
331                    self.info_data,
332                );
333            }
334        }
335    }
336}
337
338impl<T: AsRef<Section>> From<T> for SectionBuilder {
339    fn from(value: T) -> Self {
340        let value = value.as_ref();
341        let name = value.name().to_string_lossy().to_string();
342        let ty = value.section_type().to_string();
343        let linked_section = value.linked_section().to_string_lossy().to_string();
344        let info_section = value.info_section().to_string_lossy().to_string();
345
346        Self {
347            is_auto: value.auto_defined(),
348            name,
349            range: value.address_range(),
350            semantics: value.semantics(),
351            ty,
352            align: value.align(),
353            entry_size: value.entry_size() as u64,
354            linked_section,
355            info_section,
356            info_data: value.info_data(),
357        }
358    }
359}