sleigh_rs/semantic/inner/
varnode.rs

1use crate::semantic::meaning::Meaning;
2use crate::semantic::varnode::ContextAttach;
3use crate::semantic::Context as FinalContext;
4use crate::semantic::{
5    syntax, Bitrange, BitrangeId, ContextId, GlobalScope, UserFunction,
6    UserFunctionId, Varnode, VarnodeId,
7};
8use crate::{FieldBits, NumberNonZeroUnsigned, NumberUnsigned, SleighError};
9
10use super::execution::FieldSize;
11use super::{PrintFlags, Sleigh};
12
13#[derive(Debug)]
14pub struct Context {
15    pub name: String,
16    pub bitrange: Bitrange,
17    pub noflow_set: bool,
18    pub print_flags: PrintFlags,
19    pub attach: Option<ContextAttach>,
20}
21
22impl Context {
23    pub fn attach(&mut self, meaning: Meaning) -> Result<(), SleighError> {
24        if self.attach.is_some() {
25            //once attached, can't attach again
26            return Err(SleighError::AttachMultiple(
27                self.bitrange.location.clone(),
28            ));
29        }
30        if self.print_flags.signed_set {
31            todo!("Is allowed to attach to signed value?");
32        }
33        if meaning.is_number() && self.print_flags.base.is_some() {
34            todo!("Is allowed to attach varnode/literal if base is set?");
35        }
36        let attach = match meaning {
37            Meaning::NoAttach(_) => unreachable!(),
38            Meaning::Varnode(x) => ContextAttach::Varnode(x),
39            Meaning::Literal(x) => ContextAttach::Literal(x),
40            Meaning::Number(_, _x) => {
41                // attach to number is uncessary, probably a mistake
42                return Err(SleighError::ContextAttachNumber(
43                    self.bitrange.location.clone(),
44                ));
45            }
46        };
47        //TODO what if print_flags are set?
48        self.attach = Some(attach);
49        Ok(())
50    }
51
52    pub fn exec_out_value_bits(&self, sleigh: &Sleigh) -> FieldSize {
53        match self.attach {
54            //don't have speacial meaning, or the meaning just use the raw value
55            Some(ContextAttach::NoAttach(_)) => unreachable!(),
56            Some(ContextAttach::Literal(_)) | None => FieldSize::default()
57                .set_min(self.bitrange.bits.len())
58                .unwrap(),
59            Some(ContextAttach::Varnode(attach_id)) => {
60                let varnodes = sleigh.attach_varnode(attach_id);
61                //all varnodes have the same len
62                varnodes.execution_len(sleigh)
63            }
64        }
65    }
66
67    pub fn convert(self) -> FinalContext {
68        //default to literal if unset
69        let attach = self
70            .attach
71            .unwrap_or(ContextAttach::NoAttach(self.print_flags.into()));
72        FinalContext {
73            name: self.name.into(),
74            bitrange: self.bitrange,
75            noflow: self.noflow_set,
76            attach,
77        }
78    }
79}
80
81impl Sleigh {
82    pub fn create_memory(
83        &mut self,
84        varnode: syntax::define::Varnode,
85    ) -> Result<(), SleighError> {
86        let space = self
87            .get_global(&varnode.space_name)
88            .ok_or_else(|| {
89                SleighError::SpaceUndefined(varnode.space_span.clone())
90            })?
91            .space()
92            .ok_or_else(|| {
93                SleighError::SpaceInvalid(varnode.space_span.clone())
94            })?;
95        let varnode_bytes = NumberNonZeroUnsigned::new(varnode.value_bytes)
96            .ok_or_else(|| {
97                SleighError::VarnodeInvalidSize(varnode.space_span.clone())
98            })?;
99
100        if varnode.names.is_empty() {
101            //TODO verify that on syntax parsing?
102            todo!("TODO ERROR here")
103        }
104        for (index, (varnode_name, location)) in
105            varnode.names.into_iter().enumerate()
106        {
107            let Some(varnode_name) = varnode_name else {
108                // no varnode at this address, next one
109                continue;
110            };
111            let address = index as NumberUnsigned * varnode_bytes.get();
112            let location = location.clone();
113            let varnode = Varnode {
114                name: varnode_name.clone().into(),
115                location,
116                address,
117                len_bytes: varnode_bytes,
118                space,
119            };
120            self.varnodes.push(varnode);
121            let varnode_id = VarnodeId(self.varnodes.len() - 1);
122            self.global_scope
123                .insert(varnode_name, GlobalScope::Varnode(varnode_id))
124                .map(|_| Err(SleighError::NameDuplicated))
125                .unwrap_or(Ok(()))?;
126        }
127        Ok(())
128    }
129    pub fn create_bitrange(
130        &mut self,
131        bitrange: syntax::define::BitRangeDef,
132    ) -> Result<(), SleighError> {
133        for field in bitrange.into_iter() {
134            let varnode_id = self
135                .get_global(&field.varnode_name)
136                .ok_or_else(|| {
137                    SleighError::VarnodeUndefined(field.src.clone())
138                })?
139                .varnode()
140                .ok_or_else(|| {
141                    SleighError::VarnodeInvalid(field.src.clone())
142                })?;
143            let varnode = self.varnode(varnode_id);
144            let bits: FieldBits = field.range.try_into()?;
145
146            //bitrange need to point to a varnode, we allow anything that have a
147            //value_size, but tecnicatly we need to verify if this point to a
148            //varnode, but I'm not doing this right now...
149            let varnode_size = varnode.len_bytes.get() * 8;
150            //bitrange can't be bigger than the varnode
151            if bits.field_min_len().get() > varnode_size {
152                return Err(SleighError::VarnodeInvalidSize(field.src.clone()));
153            }
154
155            let bitrange = Bitrange {
156                location: field.src,
157                bits,
158                varnode: varnode_id,
159            };
160
161            self.bitranges.push(bitrange);
162            let bitrange_id = BitrangeId(self.bitranges.len() - 1);
163            self.global_scope
164                .insert(field.name, GlobalScope::Bitrange(bitrange_id))
165                .map(|_| Err(SleighError::NameDuplicated))
166                .unwrap_or(Ok(()))?;
167        }
168        Ok(())
169    }
170    pub fn create_user_function(
171        &mut self,
172        input: syntax::define::UserFunction,
173    ) -> Result<(), SleighError> {
174        let user_function = UserFunction(input.src);
175        self.user_functions.push(user_function);
176        let user_function_id = UserFunctionId(self.user_functions.len() - 1);
177        self.global_scope
178            .insert(input.name, GlobalScope::UserFunction(user_function_id))
179            .map(|_| Err(SleighError::NameDuplicated))
180            .unwrap_or(Ok(()))
181    }
182    pub fn create_context(
183        &mut self,
184        input: syntax::define::Context,
185    ) -> Result<(), SleighError> {
186        let varnode_id = self
187            .get_global(&input.varnode_name)
188            .ok_or_else(|| {
189                SleighError::VarnodeUndefined(input.varnode_span.clone())
190            })?
191            .varnode()
192            .ok_or_else(|| {
193                SleighError::VarnodeInvalid(input.varnode_span.clone())
194            })?;
195        let varnode_len_bits = self.varnode(varnode_id).len_bytes.get() * 8;
196        for field in input.fields.into_iter() {
197            //check for valid range
198            let bits: FieldBits = field.range.try_into()?;
199            //don't need make checked add/sub, don't question it
200            //range can't be bigger than the varnode
201            if bits.field_min_len().get() > varnode_len_bits {
202                return Err(SleighError::ContextInvalidSize(field.src.clone()));
203            }
204            let print_flags = PrintFlags::from_token_att(
205                &field.src,
206                field.attributes.iter().filter_map(|att| match att {
207                    syntax::define::ContextFieldAttribute::Token(att) => {
208                        Some(att)
209                    }
210                    syntax::define::ContextFieldAttribute::Noflow => None,
211                }),
212            )?;
213            //make sure that multiple noflow declaration is detected
214            let noflow = field
215                .attributes
216                .iter()
217                .filter(|att| {
218                    matches!(att, syntax::define::ContextFieldAttribute::Noflow)
219                })
220                .count();
221            let noflow_set = match noflow {
222                0 => false,
223                1 => true,
224                _ => return Err(SleighError::ContextAttDup(field.src.clone())),
225            };
226
227            //default to hex print fmt
228            let context = Context {
229                name: field.name.clone(),
230                bitrange: Bitrange {
231                    location: field.src,
232                    bits,
233                    varnode: varnode_id,
234                },
235                noflow_set,
236                print_flags,
237                attach: None,
238            };
239            self.contexts.push(context);
240            let context_id = ContextId(self.contexts.len() - 1);
241            self.global_scope
242                .insert(field.name, GlobalScope::Context(context_id))
243                .map(|_| Err(SleighError::NameDuplicated))
244                .unwrap_or(Ok(()))?;
245        }
246        Ok(())
247    }
248}