11use crate :: varnode:: { ResolvedIndirectVarNode , ResolvedVarnode } ;
2- use jingle_sleigh:: {
3- GeneralizedVarNode , IndirectVarNode , Instruction , PcodeOperation , SleighArchInfo , SpaceType ,
4- VarNode ,
5- } ;
6- use std:: fmt:: { Display , Formatter } ;
2+ use jingle_sleigh:: SleighArchInfo ;
3+ pub use jingle_sleigh:: { JingleDisplay , JingleDisplayWrapper } ;
4+ use std:: fmt:: Formatter ;
75use z3:: ast:: Ast ;
86
9- pub trait JingleDisplayable : Sized + Clone {
10- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , info : & SleighArchInfo ) -> std:: fmt:: Result ;
11-
12- fn display ( & self , info : & SleighArchInfo ) -> JingleDisplay < Self > {
13- JingleDisplay {
14- info : info. clone ( ) ,
15- inner : self . clone ( ) ,
16- }
17- }
18- }
19-
20- #[ derive( Clone ) ]
21- pub struct JingleDisplay < T > {
22- info : SleighArchInfo ,
23- inner : T ,
24- }
25-
26- impl < T > JingleDisplay < T > {
27- pub fn inner ( & self ) -> & T {
28- & self . inner
29- }
30-
31- pub fn info ( & self ) -> & SleighArchInfo {
32- & self . info
33- }
34- }
35-
36- impl < T : JingleDisplayable > Display for JingleDisplay < T > {
37- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
38- self . inner . fmt_jingle ( f, & self . info )
39- }
40- }
41-
42- impl JingleDisplay < ResolvedIndirectVarNode > {
43- pub fn space_name ( & self ) -> & str {
44- self . info
45- . get_space ( self . inner . pointer_space_idx )
46- . unwrap ( )
47- . name
48- . as_str ( )
49- }
50- }
51-
52- impl JingleDisplayable for VarNode {
53- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
54- if self . space_index == VarNode :: CONST_SPACE_INDEX {
55- write ! ( f, "{:#x}:{}" , self . offset, self . size)
56- } else if let Some ( name) = ctx. register_name ( self ) {
57- write ! ( f, "{name}" )
58- } else if let Some ( SpaceType :: IPTR_INTERNAL ) =
59- ctx. get_space ( self . space_index ) . map ( |s| s. _type )
60- {
61- write ! ( f, "$U{:x}:{}" , self . offset, self . size)
62- } else {
63- write ! (
64- f,
65- "[{}]{:#x}:{}" ,
66- ctx. get_space( self . space_index) . ok_or( std:: fmt:: Error ) ?. name,
67- self . offset,
68- self . size
69- )
70- }
71- }
72- }
73-
74- impl JingleDisplayable for IndirectVarNode {
75- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
76- write ! (
77- f,
78- "{}({})" ,
79- ctx. get_space( self . pointer_space_index)
80- . ok_or( std:: fmt:: Error ) ?
81- . name,
82- self . pointer_location. display( ctx)
83- )
84- }
85- }
86-
87- impl JingleDisplayable for GeneralizedVarNode {
88- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
89- match self {
90- GeneralizedVarNode :: Direct ( d) => d. fmt_jingle ( f, ctx) ,
91- GeneralizedVarNode :: Indirect ( i) => i. fmt_jingle ( f, ctx) ,
92- }
93- }
94- }
95-
96- impl JingleDisplayable for ResolvedIndirectVarNode {
7+ impl JingleDisplay for ResolvedIndirectVarNode {
978 fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
989 write ! (
9910 f,
@@ -106,113 +17,11 @@ impl JingleDisplayable for ResolvedIndirectVarNode {
10617 }
10718}
10819
109- impl JingleDisplayable for ResolvedVarnode {
20+ impl JingleDisplay for ResolvedVarnode {
11021 fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
11122 match self {
11223 ResolvedVarnode :: Direct ( a) => a. fmt_jingle ( f, ctx) ,
11324 ResolvedVarnode :: Indirect ( i) => i. fmt_jingle ( f, ctx) ,
11425 }
11526 }
11627}
117-
118- impl JingleDisplayable for PcodeOperation {
119- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
120- if let Some ( o) = self . output ( ) {
121- write ! ( f, "{} = " , o. display( ctx) ) ?;
122- }
123- write ! ( f, "{} " , self . opcode( ) ) ?;
124- let mut args: Vec < String > = vec ! [ ] ;
125- for x in self . inputs ( ) {
126- args. push ( format ! ( "{}" , x. display( ctx) ) ) ;
127- }
128- write ! ( f, "{}" , args. join( ", " ) ) ?;
129- Ok ( ( ) )
130- }
131- }
132-
133- impl JingleDisplayable for Instruction {
134- fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
135- writeln ! ( f, "{} {}" , self . disassembly. mnemonic, self . disassembly. args) ?;
136- for x in & self . ops {
137- writeln ! ( f, "\t {}" , x. display( ctx) ) ?;
138- }
139- Ok ( ( ) )
140- }
141- }
142-
143- #[ cfg( test) ]
144- mod tests {
145- use super :: * ;
146- use jingle_sleigh:: context:: SleighContextBuilder ;
147- use jingle_sleigh:: { PcodeOperation , VarNode } ;
148-
149- fn make_sleigh ( ) -> jingle_sleigh:: context:: SleighContext {
150- // Mirrors other tests in the repo which expect a local Ghidra checkout at this path.
151- let ctx_builder =
152- SleighContextBuilder :: load_ghidra_installation ( "/Applications/ghidra" ) . unwrap ( ) ;
153- ctx_builder. build ( "x86:LE:64:default" ) . unwrap ( )
154- }
155-
156- #[ test]
157- fn test_varnode_display_cases ( ) {
158- let sleigh = make_sleigh ( ) ;
159- let info = sleigh. arch_info ( ) . clone ( ) ;
160-
161- // const varnode should display as "<hex_offset>:<size>"
162- let const_vn = VarNode {
163- space_index : VarNode :: CONST_SPACE_INDEX ,
164- offset : 0x42 ,
165- size : 1 ,
166- } ;
167- assert_eq ! ( format!( "{}" , const_vn. display( & info) ) , "0x42:1" ) ;
168-
169- // registers: if registers exist, pretty display should equal the register name
170- let regs: Vec < _ > = sleigh. arch_info ( ) . registers ( ) . collect ( ) ;
171- if !regs. is_empty ( ) {
172- let ( vn, name) = regs[ 0 ] . clone ( ) ;
173- assert_eq ! ( format!( "{}" , vn. display( & info) ) , name) ;
174- }
175-
176- // other space: we expect a bracketed form like "[<space>]offset:size" or internal $U...
177- let other = VarNode {
178- space_index : 1 ,
179- offset : 0x10 ,
180- size : 4 ,
181- } ;
182- let s = format ! ( "{}" , other. display( & info) ) ;
183- // be permissive: ensure it contains the size and either bracket or unique prefix
184- assert ! ( s. contains( ":4" ) ) ;
185- }
186-
187- #[ test]
188- fn test_pcode_display_and_round_trip_copy ( ) {
189- let sleigh = make_sleigh ( ) ;
190- let info = sleigh. arch_info ( ) . clone ( ) ;
191-
192- let output = VarNode {
193- space_index : 4 ,
194- offset : 0x20 ,
195- size : 4 ,
196- } ;
197- let input = VarNode {
198- space_index : VarNode :: CONST_SPACE_INDEX ,
199- offset : 0x1 ,
200- size : 4 ,
201- } ;
202-
203- let op = PcodeOperation :: Copy {
204- input : input. clone ( ) ,
205- output : output. clone ( ) ,
206- } ;
207-
208- // display formatting contains the opcode name and operands
209- let s = format ! ( "{}" , op. display( & info) ) ;
210- assert_eq ! ( s, "ESP = COPY 0x1:4" ) ;
211- // Try to round-trip: render to textual pcode and parse with SleighContext.parse_pcode_listing
212- // Use the same textual format that `display` produces for varnodes.
213-
214- let parsed = sleigh. parse_pcode_listing ( s) . unwrap ( ) ;
215- assert_eq ! ( parsed. len( ) , 1 ) ;
216- assert_eq ! ( parsed[ 0 ] , op) ;
217- }
218- }
0 commit comments