1use std::borrow::Cow;
15
16use jstd::Identifier;
17
18use crate::{
19 context::{Context, Shared},
20 error::Result,
21 space::{Space, SpaceId, SpaceRef},
22 value::{
23 Value, ValueId,
24 util::{
25 base_ref::{BaseRef, WithCtx, WithShared},
26 named::{Named, Renameable, update_context_name},
27 },
28 },
29};
30
31pub mod register;
32
33#[derive(Identifier)]
34pub struct VarnodeId(usize);
35
36#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
44pub struct Varnode<'str> {
45 name: Option<Cow<'str, str>>,
46
47 label: Option<u32>,
51
52 address: i64,
54
55 size: usize,
57
58 space: SpaceId,
60}
61
62impl<'str> Varnode<'str> {
63 pub fn size_bytes(&self) -> usize {
65 self.size
66 }
67
68 fn new(base: i64, size: usize, space: SpaceId) -> Self {
69 Self {
70 name: None,
71 label: None,
72 address: base,
73 size,
74 space,
75 }
76 }
77
78 pub fn make<'ctx>(
80 ctx: &'ctx mut Context<'str>,
81 base: i64,
82 size: usize,
83 space: SpaceId,
84 ) -> VarnodeMutRef<'str, 'ctx> {
85 let id = ctx
86 .shared
87 .values
88 .varnodes
89 .push(Varnode::new(base, size, space));
90 VarnodeMutRef::from_id(ctx, id)
91 }
92
93 pub fn from_id<'ctx>(
97 src: impl crate::value::util::base_ref::AsShared<'ctx, 'str>,
98 id: VarnodeId,
99 ) -> VarnodeRef<'str, 'ctx> {
100 VarnodeRef::from_id(src, id)
101 }
102
103 pub fn from_id_mut<'ctx>(
105 ctx: &'ctx mut Context<'str>,
106 id: VarnodeId,
107 ) -> VarnodeMutRef<'str, 'ctx> {
108 VarnodeMutRef::from_id(ctx, id)
109 }
110}
111
112impl<'s, 'ctx: 's, 'str: 'ctx, Ctx> BaseRef<Ctx, VarnodeId>
113where
114 Self: WithShared<'s, 'ctx, 'str>,
115{
116 fn inner(&'s self) -> &'ctx Varnode<'str> {
117 &self.shared().values.varnodes[self.id]
118 }
119
120 fn fmt(&'s self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 if let Some(name) = self.name() {
122 write!(f, "{}", name)
123 } else if let Some(label) = self.inner().label {
124 write!(f, "v{label}")
126 } else {
127 write!(f, "[{}]:{} {}", *self.space(), self.size(), self.address())
128 }
129 }
130
131 pub fn space(&'s self) -> SpaceRef<'ctx> {
133 Space::from_id(self.shared(), self.inner().space)
134 }
135
136 pub fn address(&'s self) -> i64 {
138 self.inner().address
139 }
140
141 pub fn size(&'s self) -> usize {
143 self.inner().size
144 }
145
146 pub fn name(&'s self) -> Option<&'ctx str> {
150 self.inner().name.as_deref()
151 }
152
153 pub fn label(&'s self) -> Option<u32> {
156 self.inner().label
157 }
158}
159
160pub type VarnodeRef<'str, 'ctx> = BaseRef<&'ctx Shared<'str>, VarnodeId>;
161
162impl<'s, 'ctx: 's, 'str: 'ctx> WithShared<'s, 'ctx, 'str> for VarnodeRef<'str, 'ctx> {
163 fn shared(&'s self) -> &'ctx Shared<'str> {
164 self.ctx
165 }
166}
167
168impl Named for VarnodeRef<'_, '_> {
169 fn name(&self) -> Option<&str> {
170 self.name()
171 }
172}
173
174impl std::fmt::Display for VarnodeRef<'_, '_> {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 self.fmt(f)
177 }
178}
179
180impl<'str, 'ctx> Value<'str, 'ctx> for VarnodeRef<'str, 'ctx> {
181 fn id(&self) -> ValueId {
182 self.id()
183 }
184
185 fn size(&self) -> usize {
186 self.size()
187 }
188}
189
190pub type VarnodeMutRef<'str, 'ctx> = BaseRef<&'ctx mut Context<'str>, VarnodeId>;
191
192impl<'str, 'ctx> VarnodeMutRef<'str, 'ctx> {
193 fn inner_mut(&mut self) -> &mut Varnode<'str> {
194 &mut self.ctx.shared.values.varnodes[self.id]
195 }
196
197 pub fn set_label(&mut self, label: u32) {
201 self.inner_mut().label = Some(label);
202 }
203}
204
205impl<'s, 'ctx: 's, 'str: 'ctx> WithCtx<'s, 's, 'str> for VarnodeMutRef<'str, 'ctx> {
206 fn ctx(&'s self) -> &'s Context<'str> {
207 self.ctx
208 }
209}
210
211impl<'s, 'ctx: 's, 'str: 'ctx> WithShared<'s, 's, 'str> for VarnodeMutRef<'str, 'ctx> {
212 fn shared(&'s self) -> &'s Shared<'str> {
213 &self.ctx.shared
214 }
215}
216
217impl Named for VarnodeMutRef<'_, '_> {
218 fn name(&self) -> Option<&str> {
219 self.name()
220 }
221}
222
223impl std::fmt::Display for VarnodeMutRef<'_, '_> {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 self.fmt(f)
226 }
227}
228
229impl<'str, 'ctx> Value<'str, 'ctx> for VarnodeMutRef<'str, 'ctx> {
230 fn id(&self) -> ValueId {
231 self.id()
232 }
233
234 fn size(&self) -> usize {
235 self.size()
236 }
237}
238
239impl<'str, 'ctx> Renameable<'str, 'ctx> for VarnodeMutRef<'str, 'ctx> {
240 fn rename(&mut self, name: Cow<'str, str>) -> Result<()> {
241 let id = self.id.into();
242 let old_name = self.inner_mut().name.take();
243 update_context_name(id, self.ctx, name.clone(), old_name.as_deref())?;
244 self.ctx.shared.values.varnodes[self.id].name = Some(name);
245 Ok(())
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use wazabin_qcode_macro::qcode;
252
253 use crate::{
254 context::Context,
255 value::{ModuleView, TempRef},
256 };
257
258 #[test]
259 fn body_local_temp_name() {
260 let mut ctx = Context::new();
261 qcode!(ctx, "<block> varnode i64 ptr; goto <0x1001>;");
262
263 let temp = TempRef::new(ModuleView::new(&ctx), ptr);
264 assert_eq!(temp.name(), Some("ptr"));
265 assert_eq!(temp.space().name(), Some("ptr"));
266 }
267}