1414
1515use std:: borrow:: Cow ;
1616use std:: fmt;
17-
17+ use std :: fmt :: { Debug , Display } ;
1818// TODO : provide some way to forbid emitting register reads for certain registers
1919// also writing for certain registers (e.g. zero register must prohibit il.set_reg and il.reg
2020// (replace with nop or const(0) respectively)
@@ -83,12 +83,18 @@ impl LowLevelILTempRegister {
8383 }
8484}
8585
86- impl fmt :: Debug for LowLevelILTempRegister {
87- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
86+ impl Debug for LowLevelILTempRegister {
87+ fn fmt ( & self , f : & mut std :: fmt:: Formatter ) -> std :: fmt:: Result {
8888 write ! ( f, "temp{}" , self . temp_id)
8989 }
9090}
9191
92+ impl Display for LowLevelILTempRegister {
93+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
94+ Debug :: fmt ( self , f)
95+ }
96+ }
97+
9298impl TryFrom < RegisterId > for LowLevelILTempRegister {
9399 type Error = ( ) ;
94100
@@ -142,11 +148,20 @@ impl<R: ArchReg> LowLevelILRegisterKind<R> {
142148 }
143149}
144150
145- impl < R : ArchReg > fmt :: Debug for LowLevelILRegisterKind < R > {
146- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
151+ impl < R : ArchReg > Debug for LowLevelILRegisterKind < R > {
152+ fn fmt ( & self , f : & mut std :: fmt:: Formatter ) -> std :: fmt:: Result {
147153 match * self {
148154 LowLevelILRegisterKind :: Arch ( ref r) => r. fmt ( f) ,
149- LowLevelILRegisterKind :: Temp ( id) => id. fmt ( f) ,
155+ LowLevelILRegisterKind :: Temp ( ref id) => Debug :: fmt ( id, f) ,
156+ }
157+ }
158+ }
159+
160+ impl < R : ArchReg > Display for LowLevelILRegisterKind < R > {
161+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
162+ match * self {
163+ LowLevelILRegisterKind :: Arch ( ref r) => write ! ( f, "{}" , r. name( ) ) ,
164+ LowLevelILRegisterKind :: Temp ( ref id) => Display :: fmt ( id, f) ,
150165 }
151166 }
152167}
@@ -157,36 +172,128 @@ impl From<LowLevelILTempRegister> for LowLevelILRegisterKind<CoreRegister> {
157172 }
158173}
159174
175+ #[ derive( Copy , Clone , Debug ) ]
176+ pub struct LowLevelILSSARegister < R : ArchReg > {
177+ pub reg : LowLevelILRegisterKind < R > ,
178+ /// The SSA version of the register.
179+ pub version : u32 ,
180+ }
181+
182+ impl < R : ArchReg > LowLevelILSSARegister < R > {
183+ pub fn new ( reg : LowLevelILRegisterKind < R > , version : u32 ) -> Self {
184+ Self { reg, version }
185+ }
186+
187+ pub fn name ( & self ) -> Cow < ' _ , str > {
188+ self . reg . name ( )
189+ }
190+
191+ pub fn id ( & self ) -> RegisterId {
192+ self . reg . id ( )
193+ }
194+ }
195+
196+ impl < R : ArchReg > Display for LowLevelILSSARegister < R > {
197+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
198+ write ! ( f, "{}#{}" , self . reg, self . version)
199+ }
200+ }
201+
202+ /// The kind of SSA register.
203+ ///
204+ /// An SSA register can exist in two states:
205+ ///
206+ /// - Full, e.g. `eax` on x86
207+ /// - Partial, e.g. `al` on x86
208+ ///
209+ /// If you intend to query for the ssa uses or definitions you must retrieve the physical register
210+ /// using the function [`LowLevelILSSARegisterKind::physical_reg`] which will give you the actual
211+ /// [`LowLevelILSSARegister`].
160212#[ derive( Copy , Clone , Debug ) ]
161213pub enum LowLevelILSSARegisterKind < R : ArchReg > {
162- Full {
163- kind : LowLevelILRegisterKind < R > ,
164- version : u32 ,
165- } ,
214+ /// A full register is one that is not aliasing another, such as `eax` on x86 or `rax` on x86_64.
215+ Full ( LowLevelILSSARegister < R > ) ,
166216 Partial {
167- full_reg : CoreRegister ,
217+ /// This is the non-aliased register.
218+ ///
219+ /// This register is what is used for dataflow, otherwise the backing storage of aliased registers
220+ /// like `al` on x86 would contain separate value information from the physical register `eax`.
221+ ///
222+ /// NOTE: While this is a [`LowLevelILSSARegister`] temporary registers are not allowed in partial
223+ /// assignments, so this will always be an actual architecture register.
224+ full_reg : LowLevelILSSARegister < R > ,
225+ /// This is the aliased register.
226+ ///
227+ /// On x86 if the register `al` is used that would be considered a partial register, with the
228+ /// full register `eax` being used as the backing storage.
168229 partial_reg : CoreRegister ,
169- version : u32 ,
170230 } ,
171231}
172232
173233impl < R : ArchReg > LowLevelILSSARegisterKind < R > {
174234 pub fn new_full ( kind : LowLevelILRegisterKind < R > , version : u32 ) -> Self {
175- Self :: Full { kind, version }
235+ Self :: Full ( LowLevelILSSARegister :: new ( kind, version) )
176236 }
177237
178- pub fn new_partial ( full_reg : CoreRegister , partial_reg : CoreRegister , version : u32 ) -> Self {
238+ pub fn new_partial (
239+ full_reg : LowLevelILRegisterKind < R > ,
240+ version : u32 ,
241+ partial_reg : CoreRegister ,
242+ ) -> Self {
179243 Self :: Partial {
180- full_reg,
244+ full_reg : LowLevelILSSARegister :: new ( full_reg , version ) ,
181245 partial_reg,
182- version,
183246 }
184247 }
185248
186- pub fn version ( & self ) -> u32 {
249+ /// This is the non-aliased register used. This should be called when you intend to actually
250+ /// query for SSA dataflow information, as a partial register is prohibited from being used.
251+ ///
252+ /// # Example
253+ ///
254+ /// On x86 `al` in the LLIL SSA will have a physical register of `eax`.
255+ pub fn physical_reg ( & self ) -> LowLevelILSSARegister < R > {
187256 match * self {
188- LowLevelILSSARegisterKind :: Full { version, .. }
189- | LowLevelILSSARegisterKind :: Partial { version, .. } => version,
257+ LowLevelILSSARegisterKind :: Full ( reg) => reg,
258+ LowLevelILSSARegisterKind :: Partial { full_reg, .. } => full_reg,
259+ }
260+ }
261+
262+ /// Gets the displayable register, for partial this will be the partial register name.
263+ ///
264+ /// # Example
265+ ///
266+ /// On x86 this will display "al" not "eax".
267+ pub fn name ( & self ) -> Cow < ' _ , str > {
268+ match * self {
269+ LowLevelILSSARegisterKind :: Full ( ref reg) => reg. reg . name ( ) ,
270+ LowLevelILSSARegisterKind :: Partial {
271+ ref partial_reg, ..
272+ } => partial_reg. name ( ) ,
273+ }
274+ }
275+ }
276+
277+ impl < R : ArchReg > AsRef < LowLevelILSSARegister < R > > for LowLevelILSSARegisterKind < R > {
278+ fn as_ref ( & self ) -> & LowLevelILSSARegister < R > {
279+ match self {
280+ LowLevelILSSARegisterKind :: Full ( reg) => reg,
281+ LowLevelILSSARegisterKind :: Partial { full_reg, .. } => full_reg,
282+ }
283+ }
284+ }
285+
286+ impl < R : ArchReg > From < LowLevelILSSARegister < R > > for LowLevelILSSARegisterKind < R > {
287+ fn from ( value : LowLevelILSSARegister < R > ) -> Self {
288+ LowLevelILSSARegisterKind :: Full ( value)
289+ }
290+ }
291+
292+ impl < R : ArchReg > From < LowLevelILSSARegisterKind < R > > for LowLevelILSSARegister < R > {
293+ fn from ( value : LowLevelILSSARegisterKind < R > ) -> Self {
294+ match value {
295+ LowLevelILSSARegisterKind :: Full ( reg) => reg,
296+ LowLevelILSSARegisterKind :: Partial { full_reg, .. } => full_reg,
190297 }
191298 }
192299}
0 commit comments