11use crate :: * ;
22use rustc_ast:: ast:: Mutability ;
33use rustc_middle:: ty:: layout:: LayoutOf as _;
4- use rustc_middle:: ty:: { self , TypeAndMut } ;
5- use rustc_span:: { BytePos , Symbol } ;
4+ use rustc_middle:: ty:: { self , Instance , TypeAndMut } ;
5+ use rustc_span:: { BytePos , Loc , Symbol } ;
66use rustc_target:: { abi:: Size , spec:: abi:: Abi } ;
77use std:: convert:: TryInto as _;
88
99impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
1010pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
11- fn handle_miri_get_backtrace (
11+ fn handle_miri_backtrace_size (
1212 & mut self ,
1313 abi : Abi ,
1414 link_name : Symbol ,
1515 args : & [ OpTy < ' tcx , Tag > ] ,
1616 dest : & PlaceTy < ' tcx , Tag > ,
1717 ) -> InterpResult < ' tcx > {
1818 let this = self . eval_context_mut ( ) ;
19- let tcx = this. tcx ;
2019 let & [ ref flags] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
2120
2221 let flags = this. read_scalar ( flags) ?. to_u64 ( ) ?;
2322 if flags != 0 {
24- throw_unsup_format ! ( "unknown `miri_get_backtrace ` flags {}" , flags) ;
23+ throw_unsup_format ! ( "unknown `miri_backtrace_size ` flags {}" , flags) ;
2524 }
2625
26+ let frame_count = this. active_thread_stack ( ) . len ( ) ;
27+
28+ this. write_scalar ( Scalar :: from_machine_usize ( frame_count. try_into ( ) . unwrap ( ) , this) , dest)
29+ }
30+
31+ fn handle_miri_get_backtrace (
32+ & mut self ,
33+ abi : Abi ,
34+ link_name : Symbol ,
35+ args : & [ OpTy < ' tcx , Tag > ] ,
36+ dest : & PlaceTy < ' tcx , Tag > ,
37+ ) -> InterpResult < ' tcx > {
38+ let this = self . eval_context_mut ( ) ;
39+ let tcx = this. tcx ;
40+
41+ let flags = if let Some ( flags_op) = args. get ( 0 ) {
42+ this. read_scalar ( flags_op) ?. to_u64 ( ) ?
43+ } else {
44+ throw_ub_format ! ( "expected at least 1 argument" )
45+ } ;
46+
2747 let mut data = Vec :: new ( ) ;
2848 for frame in this. active_thread_stack ( ) . iter ( ) . rev ( ) {
2949 let mut span = frame. current_span ( ) ;
@@ -49,46 +69,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4969 } )
5070 . collect ( ) ;
5171
52- let len = ptrs. len ( ) ;
72+ let len: u64 = ptrs. len ( ) . try_into ( ) . unwrap ( ) ;
5373
5474 let ptr_ty = tcx. mk_ptr ( TypeAndMut { ty : tcx. types . unit , mutbl : Mutability :: Mut } ) ;
5575
56- let array_ty = tcx. mk_array ( ptr_ty, ptrs . len ( ) . try_into ( ) . unwrap ( ) ) ;
76+ let array_layout = this . layout_of ( tcx. mk_array ( ptr_ty, len) ) . unwrap ( ) ;
5777
58- // Write pointers into array
59- let alloc =
60- this. allocate ( this. layout_of ( array_ty) . unwrap ( ) , MiriMemoryKind :: Rust . into ( ) ) ?;
61- for ( i, ptr) in ptrs. into_iter ( ) . enumerate ( ) {
62- let place = this. mplace_index ( & alloc, i as u64 ) ?;
63- this. write_pointer ( ptr, & place. into ( ) ) ?;
64- }
78+ match flags {
79+ // storage for pointers is allocated by miri
80+ // deallocating the slice is undefined behavior with a custom global allocator
81+ 0 => {
82+ let & [ _flags] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
83+
84+ let alloc = this. allocate ( array_layout, MiriMemoryKind :: Rust . into ( ) ) ?;
85+
86+ // Write pointers into array
87+ for ( i, ptr) in ptrs. into_iter ( ) . enumerate ( ) {
88+ let place = this. mplace_index ( & alloc, i as u64 ) ?;
89+
90+ this. write_pointer ( ptr, & place. into ( ) ) ?;
91+ }
92+
93+ this. write_immediate (
94+ Immediate :: new_slice ( Scalar :: from_maybe_pointer ( alloc. ptr , this) , len, this) ,
95+ dest,
96+ ) ?;
97+ }
98+ // storage for pointers is allocated by the caller
99+ 1 => {
100+ let & [ _flags, ref buf] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
101+
102+ let buf_place = this. deref_operand ( buf) ?;
103+
104+ let ptr_layout = this. layout_of ( ptr_ty) ?;
105+
106+ for ( i, ptr) in ptrs. into_iter ( ) . enumerate ( ) {
107+ let offset = ptr_layout. size * i. try_into ( ) . unwrap ( ) ;
108+
109+ let op_place =
110+ buf_place. offset ( offset, MemPlaceMeta :: None , ptr_layout, this) ?;
111+
112+ this. write_pointer ( ptr, & op_place. into ( ) ) ?;
113+ }
114+ }
115+ _ => throw_unsup_format ! ( "unknown `miri_get_backtrace` flags {}" , flags) ,
116+ } ;
65117
66- this. write_immediate (
67- Immediate :: new_slice (
68- Scalar :: from_maybe_pointer ( alloc. ptr , this) ,
69- len. try_into ( ) . unwrap ( ) ,
70- this,
71- ) ,
72- dest,
73- ) ?;
74118 Ok ( ( ) )
75119 }
76120
77- fn handle_miri_resolve_frame (
121+ fn resolve_frame_pointer (
78122 & mut self ,
79- abi : Abi ,
80- link_name : Symbol ,
81- args : & [ OpTy < ' tcx , Tag > ] ,
82- dest : & PlaceTy < ' tcx , Tag > ,
83- ) -> InterpResult < ' tcx > {
123+ ptr : & OpTy < ' tcx , Tag > ,
124+ ) -> InterpResult < ' tcx , ( Instance < ' tcx > , Loc , String , String ) > {
84125 let this = self . eval_context_mut ( ) ;
85- let tcx = this. tcx ;
86- let & [ ref ptr, ref flags] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
87-
88- let flags = this. read_scalar ( flags) ?. to_u64 ( ) ?;
89- if flags != 0 {
90- throw_unsup_format ! ( "unknown `miri_resolve_frame` flags {}" , flags) ;
91- }
92126
93127 let ptr = this. read_pointer ( ptr) ?;
94128 // Take apart the pointer, we need its pieces.
@@ -101,6 +135,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
101135 throw_ub_format ! ( "expected function pointer, found {:?}" , ptr) ;
102136 } ;
103137
138+ let lo =
139+ this. tcx . sess . source_map ( ) . lookup_char_pos ( BytePos ( offset. bytes ( ) . try_into ( ) . unwrap ( ) ) ) ;
140+
141+ let name = fn_instance. to_string ( ) ;
142+ let filename = lo. file . name . prefer_remapped ( ) . to_string ( ) ;
143+
144+ Ok ( ( fn_instance, lo, name, filename) )
145+ }
146+
147+ fn handle_miri_resolve_frame (
148+ & mut self ,
149+ abi : Abi ,
150+ link_name : Symbol ,
151+ args : & [ OpTy < ' tcx , Tag > ] ,
152+ dest : & PlaceTy < ' tcx , Tag > ,
153+ ) -> InterpResult < ' tcx > {
154+ let this = self . eval_context_mut ( ) ;
155+ let & [ ref ptr, ref flags] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
156+
157+ let flags = this. read_scalar ( flags) ?. to_u64 ( ) ?;
158+
159+ let ( fn_instance, lo, name, filename) = this. resolve_frame_pointer ( ptr) ?;
160+
104161 // Reconstruct the original function pointer,
105162 // which we pass to user code.
106163 let fn_ptr = this. memory . create_fn_alloc ( FnVal :: Instance ( fn_instance) ) ;
@@ -115,23 +172,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
115172 ) ;
116173 }
117174
118- let pos = BytePos ( offset. bytes ( ) . try_into ( ) . unwrap ( ) ) ;
119- let name = fn_instance. to_string ( ) ;
120-
121- let lo = tcx. sess . source_map ( ) . lookup_char_pos ( pos) ;
122-
123- let filename = lo. file . name . prefer_remapped ( ) . to_string ( ) ;
124175 let lineno: u32 = lo. line as u32 ;
125176 // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
126177 let colno: u32 = lo. col . 0 as u32 + 1 ;
127178
128- // These are "mutable" allocations as we consider them to be owned by the callee.
129- let name_alloc = this. allocate_str ( & name, MiriMemoryKind :: Rust . into ( ) , Mutability :: Mut ) ;
130- let filename_alloc =
131- this. allocate_str ( & filename, MiriMemoryKind :: Rust . into ( ) , Mutability :: Mut ) ;
132- let lineno_alloc = Scalar :: from_u32 ( lineno) ;
133- let colno_alloc = Scalar :: from_u32 ( colno) ;
134-
135179 let dest = this. force_allocation ( dest) ?;
136180 if let ty:: Adt ( adt, _) = dest. layout . ty . kind ( ) {
137181 if !adt. repr . c ( ) {
@@ -141,10 +185,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
141185 }
142186 }
143187
144- this. write_immediate ( name_alloc. to_ref ( this) , & this. mplace_field ( & dest, 0 ) ?. into ( ) ) ?;
145- this. write_immediate ( filename_alloc. to_ref ( this) , & this. mplace_field ( & dest, 1 ) ?. into ( ) ) ?;
146- this. write_scalar ( lineno_alloc, & this. mplace_field ( & dest, 2 ) ?. into ( ) ) ?;
147- this. write_scalar ( colno_alloc, & this. mplace_field ( & dest, 3 ) ?. into ( ) ) ?;
188+ match flags {
189+ 0 => {
190+ // These are "mutable" allocations as we consider them to be owned by the callee.
191+ let name_alloc =
192+ this. allocate_str ( & name, MiriMemoryKind :: Rust . into ( ) , Mutability :: Mut ) ;
193+ let filename_alloc =
194+ this. allocate_str ( & filename, MiriMemoryKind :: Rust . into ( ) , Mutability :: Mut ) ;
195+
196+ this. write_immediate (
197+ name_alloc. to_ref ( this) ,
198+ & this. mplace_field ( & dest, 0 ) ?. into ( ) ,
199+ ) ?;
200+ this. write_immediate (
201+ filename_alloc. to_ref ( this) ,
202+ & this. mplace_field ( & dest, 1 ) ?. into ( ) ,
203+ ) ?;
204+ }
205+ 1 => {
206+ this. write_scalar (
207+ Scalar :: from_machine_usize ( name. len ( ) . try_into ( ) . unwrap ( ) , this) ,
208+ & this. mplace_field ( & dest, 0 ) ?. into ( ) ,
209+ ) ?;
210+ this. write_scalar (
211+ Scalar :: from_machine_usize ( filename. len ( ) . try_into ( ) . unwrap ( ) , this) ,
212+ & this. mplace_field ( & dest, 1 ) ?. into ( ) ,
213+ ) ?;
214+ }
215+ _ => throw_unsup_format ! ( "unknown `miri_resolve_frame` flags {}" , flags) ,
216+ }
217+
218+ this. write_scalar ( Scalar :: from_u32 ( lineno) , & this. mplace_field ( & dest, 2 ) ?. into ( ) ) ?;
219+ this. write_scalar ( Scalar :: from_u32 ( colno) , & this. mplace_field ( & dest, 3 ) ?. into ( ) ) ?;
148220
149221 // Support a 4-field struct for now - this is deprecated
150222 // and slated for removal.
@@ -154,4 +226,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
154226
155227 Ok ( ( ) )
156228 }
229+
230+ fn handle_miri_resolve_frame_names (
231+ & mut self ,
232+ abi : Abi ,
233+ link_name : Symbol ,
234+ args : & [ OpTy < ' tcx , Tag > ] ,
235+ ) -> InterpResult < ' tcx > {
236+ let this = self . eval_context_mut ( ) ;
237+
238+ let & [ ref ptr, ref flags, ref name_ptr, ref filename_ptr] =
239+ this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
240+
241+ let flags = this. read_scalar ( flags) ?. to_u64 ( ) ?;
242+ if flags != 0 {
243+ throw_unsup_format ! ( "unknown `miri_backtrace_size` flags {}" , flags) ;
244+ }
245+
246+ let ( _, _, name, filename) = this. resolve_frame_pointer ( ptr) ?;
247+
248+ this. memory . write_bytes ( this. read_pointer ( name_ptr) ?, name. bytes ( ) ) ?;
249+ this. memory . write_bytes ( this. read_pointer ( filename_ptr) ?, filename. bytes ( ) ) ?;
250+
251+ Ok ( ( ) )
252+ }
157253}
0 commit comments