idalib/
name.rs

1use std::ffi::CStr;
2use std::marker::PhantomData;
3
4use bitflags::bitflags;
5
6use crate::ffi::BADADDR;
7use crate::ffi::name::{
8    get_nlist_ea, get_nlist_idx, get_nlist_name, get_nlist_size, is_in_nlist, is_public_name,
9    is_weak_name,
10};
11
12use crate::Address;
13use crate::idb::IDB;
14
15pub type NameIndex = usize;
16
17pub struct NameList<'a> {
18    _marker: PhantomData<&'a IDB>,
19}
20
21bitflags! {
22    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23    pub struct NameProperties: u8 {
24        const PUBLIC = 0x01;
25        const WEAK = 0x02;
26    }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct Name {
31    address: Address,
32    name: String,
33    index: NameIndex,
34    properties: NameProperties,
35}
36
37impl Name {
38    pub fn address(&self) -> Address {
39        self.address
40    }
41
42    pub fn name(&self) -> &str {
43        &self.name
44    }
45
46    pub fn is_public(&self) -> bool {
47        self.properties.contains(NameProperties::PUBLIC)
48    }
49
50    pub fn is_weak(&self) -> bool {
51        self.properties.contains(NameProperties::WEAK)
52    }
53}
54
55impl<'a> NameList<'a> {
56    pub(crate) fn new(_: &'a IDB) -> Self {
57        Self {
58            _marker: PhantomData,
59        }
60    }
61
62    pub fn get_by_index(&self, index: NameIndex) -> Option<Name> {
63        let addr = self.get_address_by_index(index)?;
64        let name = unsafe { get_nlist_name(index) };
65        if name.is_null() {
66            return None;
67        }
68
69        let name = unsafe { CStr::from_ptr(name) }.to_string_lossy().into_owned();
70
71        let mut properties = NameProperties::empty();
72
73        if unsafe { is_public_name(addr.into()) } {
74            properties.insert(NameProperties::PUBLIC);
75        }
76
77        if unsafe { is_weak_name(addr.into()) } {
78            properties.insert(NameProperties::WEAK);
79        }
80
81        Some(Name {
82            address: addr,
83            name,
84            index,
85            properties,
86        })
87    }
88
89    pub fn get_closest_by_address(&self, address: Address) -> Option<Name> {
90        let index = unsafe { get_nlist_idx(address.into()) };
91        self.get_by_index(index)
92    }
93
94    pub fn get_address_by_index(&self, index: NameIndex) -> Option<Address> {
95        let addr = unsafe { get_nlist_ea(index) };
96        if addr == BADADDR {
97            None
98        } else {
99            Some(addr.into())
100        }
101    }
102
103    pub fn has_name(&self, address: Address) -> bool {
104        unsafe { is_in_nlist(address.into()) }
105    }
106
107    pub fn len(&self) -> usize {
108        unsafe { get_nlist_size() }
109    }
110
111    pub fn is_empty(&self) -> bool {
112        self.len() == 0
113    }
114
115    pub fn iter(&self) -> NameListIter<'_, 'a> {
116        NameListIter {
117            name_list: self,
118            current_index: 0,
119        }
120    }
121}
122
123pub struct NameListIter<'s, 'a> {
124    name_list: &'s NameList<'a>,
125    current_index: NameIndex,
126}
127
128impl<'s, 'a> Iterator for NameListIter<'s, 'a> {
129    type Item = Name;
130
131    fn next(&mut self) -> Option<Self::Item> {
132        while self.current_index < self.name_list.len() {
133            let name = self.name_list.get_by_index(self.current_index);
134
135            self.current_index += 1;
136
137            if name.is_some() {
138                return name;
139            }
140        }
141        None
142    }
143}