11use crate :: varnode:: { ResolvedIndirectVarNode , ResolvedVarnode } ;
22use jingle_sleigh:: {
3- GeneralizedVarNode , IndirectVarNode , Instruction , PcodeOperation , SleighArchInfo , VarNode ,
3+ GeneralizedVarNode , IndirectVarNode , Instruction , PcodeOperation , SleighArchInfo , SpaceType ,
4+ VarNode ,
45} ;
56use std:: fmt:: { Display , Formatter } ;
67use z3:: ast:: Ast ;
@@ -51,13 +52,17 @@ impl JingleDisplay<ResolvedIndirectVarNode> {
5152impl JingleDisplayable for VarNode {
5253 fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
5354 if self . space_index == VarNode :: CONST_SPACE_INDEX {
54- write ! ( f, "{:x}:{:x }" , self . offset, self . size)
55+ write ! ( f, "{:# x}:{}" , self . offset, self . size)
5556 } else if let Some ( name) = ctx. register_name ( self ) {
5657 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)
5762 } else {
5863 write ! (
5964 f,
60- "{}[{:x}]:{:x }" ,
65+ "[{}]{:#x}:{ }" ,
6166 ctx. get_space( self . space_index) . ok_or( std:: fmt:: Error ) ?. name,
6267 self . offset,
6368 self . size
@@ -70,12 +75,11 @@ impl JingleDisplayable for IndirectVarNode {
7075 fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
7176 write ! (
7277 f,
73- "*({}[{}]: {})" ,
78+ "{}( {})" ,
7479 ctx. get_space( self . pointer_space_index)
7580 . ok_or( std:: fmt:: Error ) ?
7681 . name,
77- self . pointer_location,
78- self . access_size_bytes
82+ self . pointer_location. display( ctx)
7983 )
8084 }
8185}
@@ -93,12 +97,11 @@ impl JingleDisplayable for ResolvedIndirectVarNode {
9397 fn fmt_jingle ( & self , f : & mut Formatter < ' _ > , ctx : & SleighArchInfo ) -> std:: fmt:: Result {
9498 write ! (
9599 f,
96- "{}[{}]:{} " ,
100+ "{}({}) " ,
97101 ctx. get_space( self . pointer_space_idx)
98102 . ok_or( std:: fmt:: Error ) ?
99103 . name,
100104 self . pointer. simplify( ) ,
101- self . access_size_bytes
102105 )
103106 }
104107}
@@ -136,3 +139,80 @@ impl JingleDisplayable for Instruction {
136139 Ok ( ( ) )
137140 }
138141}
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