|
14 | 14 |
|
15 | 15 | use std::borrow::Cow; |
16 | 16 | use std::fmt; |
17 | | - |
| 17 | +use std::fmt::{Display, Formatter}; |
18 | 18 | // TODO : provide some way to forbid emitting register reads for certain registers |
19 | 19 | // also writing for certain registers (e.g. zero register must prohibit il.set_reg and il.reg |
20 | 20 | // (replace with nop or const(0) respectively) |
@@ -89,6 +89,12 @@ impl fmt::Debug for LowLevelILTempRegister { |
89 | 89 | } |
90 | 90 | } |
91 | 91 |
|
| 92 | +impl fmt::Display for LowLevelILTempRegister { |
| 93 | + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 94 | + fmt::Debug::fmt(self, f) |
| 95 | + } |
| 96 | +} |
| 97 | + |
92 | 98 | impl TryFrom<RegisterId> for LowLevelILTempRegister { |
93 | 99 | type Error = (); |
94 | 100 |
|
@@ -146,54 +152,145 @@ impl<R: ArchReg> fmt::Debug for LowLevelILRegisterKind<R> { |
146 | 152 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
147 | 153 | match *self { |
148 | 154 | LowLevelILRegisterKind::Arch(ref r) => r.fmt(f), |
149 | | - LowLevelILRegisterKind::Temp(id) => id.fmt(f), |
| 155 | + LowLevelILRegisterKind::Temp(ref id) => fmt::Debug::fmt(id, f), |
150 | 156 | } |
151 | 157 | } |
152 | 158 | } |
153 | 159 |
|
| 160 | +impl<R: ArchReg> fmt::Display for LowLevelILRegisterKind<R> { |
| 161 | + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 162 | + fmt::Debug::fmt(self, f) |
| 163 | + } |
| 164 | +} |
| 165 | + |
154 | 166 | impl From<LowLevelILTempRegister> for LowLevelILRegisterKind<CoreRegister> { |
155 | 167 | fn from(reg: LowLevelILTempRegister) -> Self { |
156 | 168 | LowLevelILRegisterKind::Temp(reg) |
157 | 169 | } |
158 | 170 | } |
159 | 171 |
|
| 172 | +#[derive(Copy, Clone, Debug)] |
| 173 | +pub struct LowLevelILSSARegister<R: ArchReg> { |
| 174 | + pub reg: LowLevelILRegisterKind<R>, |
| 175 | + /// The SSA version of the register. |
| 176 | + pub version: u32, |
| 177 | +} |
| 178 | + |
| 179 | +impl<R: ArchReg> LowLevelILSSARegister<R> { |
| 180 | + pub fn new(reg: LowLevelILRegisterKind<R>, version: u32) -> Self { |
| 181 | + Self { reg, version } |
| 182 | + } |
| 183 | + |
| 184 | + pub fn name(&self) -> Cow<'_, str> { |
| 185 | + self.reg.name() |
| 186 | + } |
| 187 | + |
| 188 | + pub fn id(&self) -> RegisterId { |
| 189 | + self.reg.id() |
| 190 | + } |
| 191 | +} |
| 192 | + |
| 193 | +impl<R: ArchReg> Display for LowLevelILSSARegister<R> { |
| 194 | + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 195 | + write!(f, "{}#{}", self.reg, self.version) |
| 196 | + } |
| 197 | +} |
| 198 | + |
| 199 | +/// The kind of SSA register. |
| 200 | +/// |
| 201 | +/// An SSA register can exist in two states: |
| 202 | +/// |
| 203 | +/// - Full, e.g. `eax` on x86 |
| 204 | +/// - Partial, e.g. `al` on x86 |
| 205 | +/// |
| 206 | +/// If you intend to query for the ssa uses or definitions you must retrieve the physical register |
| 207 | +/// using the function [`LowLevelILSSARegisterKind::physical_reg`] which will give you the actual |
| 208 | +/// [`LowLevelILSSARegister`]. |
160 | 209 | #[derive(Copy, Clone, Debug)] |
161 | 210 | pub enum LowLevelILSSARegisterKind<R: ArchReg> { |
162 | | - Full { |
163 | | - kind: LowLevelILRegisterKind<R>, |
164 | | - version: u32, |
165 | | - }, |
| 211 | + /// A full register is one that is not aliasing another, such as `eax` on x86 or `rax` on x86_64. |
| 212 | + Full(LowLevelILSSARegister<R>), |
166 | 213 | Partial { |
167 | | - full_reg: CoreRegister, |
| 214 | + /// This is the non-aliased register. |
| 215 | + /// |
| 216 | + /// This register is what is used for dataflow, otherwise the backing storage of aliased registers |
| 217 | + /// like `al` on x86 would contain separate value information from the physical register `eax`. |
| 218 | + /// |
| 219 | + /// NOTE: While this is a [`LowLevelILSSARegister`] temporary registers are not allowed in partial |
| 220 | + /// assignments, so this will always be an actual architecture register. |
| 221 | + full_reg: LowLevelILSSARegister<R>, |
| 222 | + /// This is the aliased register. |
| 223 | + /// |
| 224 | + /// On x86 if the register `al` is used that would be considered a partial register, with the |
| 225 | + /// full register `eax` being used as the backing storage. |
168 | 226 | partial_reg: CoreRegister, |
169 | | - version: u32, |
170 | 227 | }, |
171 | 228 | } |
172 | 229 |
|
173 | 230 | impl<R: ArchReg> LowLevelILSSARegisterKind<R> { |
174 | 231 | pub fn new_full(kind: LowLevelILRegisterKind<R>, version: u32) -> Self { |
175 | | - Self::Full { kind, version } |
| 232 | + Self::Full(LowLevelILSSARegister::new(kind, version)) |
176 | 233 | } |
177 | 234 |
|
178 | | - pub fn new_partial(full_reg: CoreRegister, partial_reg: CoreRegister, version: u32) -> Self { |
| 235 | + pub fn new_partial( |
| 236 | + full_reg: LowLevelILRegisterKind<R>, |
| 237 | + version: u32, |
| 238 | + partial_reg: CoreRegister, |
| 239 | + ) -> Self { |
179 | 240 | Self::Partial { |
180 | | - full_reg, |
| 241 | + full_reg: LowLevelILSSARegister::new(full_reg, version), |
181 | 242 | partial_reg, |
182 | | - version, |
183 | 243 | } |
184 | 244 | } |
185 | 245 |
|
186 | | - pub fn version(&self) -> u32 { |
| 246 | + /// This is the non-aliased register used. This should be called when you intend to actually |
| 247 | + /// query for SSA dataflow information, as a partial register is prohibited from being used. |
| 248 | + /// |
| 249 | + /// # Example |
| 250 | + /// |
| 251 | + /// On x86 `al` in the LLIL SSA will have a physical register of `eax`. |
| 252 | + pub fn physical_reg(&self) -> LowLevelILSSARegister<R> { |
187 | 253 | match *self { |
188 | | - LowLevelILSSARegisterKind::Full { version, .. } |
189 | | - | LowLevelILSSARegisterKind::Partial { version, .. } => version, |
| 254 | + LowLevelILSSARegisterKind::Full(reg) => reg, |
| 255 | + LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg, |
190 | 256 | } |
191 | 257 | } |
192 | 258 |
|
193 | | - pub fn id(&self) -> RegisterId { |
| 259 | + /// Gets the displayable register, for partial this will be the partial register name. |
| 260 | + /// |
| 261 | + /// # Example |
| 262 | + /// |
| 263 | + /// On x86 this will display "al" not "eax". |
| 264 | + pub fn name(&self) -> Cow<'_, str> { |
194 | 265 | match *self { |
195 | | - LowLevelILSSARegisterKind::Full { kind, .. } => kind.id(), |
196 | | - LowLevelILSSARegisterKind::Partial { partial_reg, .. } => partial_reg.id(), |
| 266 | + LowLevelILSSARegisterKind::Full(ref reg) => reg.reg.name(), |
| 267 | + LowLevelILSSARegisterKind::Partial { |
| 268 | + ref partial_reg, .. |
| 269 | + } => partial_reg.name(), |
| 270 | + } |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +impl<R: ArchReg> AsRef<LowLevelILSSARegister<R>> for LowLevelILSSARegisterKind<R> { |
| 275 | + fn as_ref(&self) -> &LowLevelILSSARegister<R> { |
| 276 | + match self { |
| 277 | + LowLevelILSSARegisterKind::Full(reg) => reg, |
| 278 | + LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg, |
| 279 | + } |
| 280 | + } |
| 281 | +} |
| 282 | + |
| 283 | +impl<R: ArchReg> From<LowLevelILSSARegister<R>> for LowLevelILSSARegisterKind<R> { |
| 284 | + fn from(value: LowLevelILSSARegister<R>) -> Self { |
| 285 | + LowLevelILSSARegisterKind::Full(value) |
| 286 | + } |
| 287 | +} |
| 288 | + |
| 289 | +impl<R: ArchReg> From<LowLevelILSSARegisterKind<R>> for LowLevelILSSARegister<R> { |
| 290 | + fn from(value: LowLevelILSSARegisterKind<R>) -> Self { |
| 291 | + match value { |
| 292 | + LowLevelILSSARegisterKind::Full(reg) => reg, |
| 293 | + LowLevelILSSARegisterKind::Partial { full_reg, .. } => full_reg, |
197 | 294 | } |
198 | 295 | } |
199 | 296 | } |
|
0 commit comments