1 use super::address_transform::AddressTransform;
2 use crate::debug::ModuleMemoryOffset;
3 use anyhow::{Context, Error, Result};
4 use cranelift_codegen::ir::{LabelValueLoc, StackSlots, ValueLabel, ValueLoc};
5 use cranelift_codegen::isa::TargetIsa;
6 use cranelift_codegen::ValueLabelsRanges;
7 use cranelift_wasm::get_vmctx_value_label;
8 use gimli::{self, write, Expression, Operation, Reader, ReaderOffset, X86_64};
9 use more_asserts::{assert_le, assert_lt};
10 use std::cmp::PartialEq;
11 use std::collections::{HashMap, HashSet};
12 use std::hash::{Hash, Hasher};
13 use std::rc::Rc;
14 use wasmtime_environ::{DefinedFuncIndex, EntityRef};
15 
16 #[derive(Debug)]
17 pub struct FunctionFrameInfo<'a> {
18     pub value_ranges: &'a ValueLabelsRanges,
19     pub memory_offset: ModuleMemoryOffset,
20     pub stack_slots: &'a StackSlots,
21 }
22 
23 impl<'a> FunctionFrameInfo<'a> {
24     fn vmctx_memory_offset(&self) -> Option<i64> {
25         match self.memory_offset {
26             ModuleMemoryOffset::Defined(x) => Some(x as i64),
27             ModuleMemoryOffset::Imported(_) => {
28                 // TODO implement memory offset for imported memory
29                 None
30             }
31             ModuleMemoryOffset::None => None,
32         }
33     }
34 }
35 
36 struct ExpressionWriter(write::EndianVec<gimli::RunTimeEndian>);
37 
38 impl ExpressionWriter {
39     pub fn new() -> Self {
40         let endian = gimli::RunTimeEndian::Little;
41         let writer = write::EndianVec::new(endian);
42         ExpressionWriter(writer)
43     }
44 
45     pub fn write_op(&mut self, op: gimli::DwOp) -> write::Result<()> {
46         self.write_u8(op.0 as u8)
47     }
48 
49     pub fn write_op_reg(&mut self, reg: u16) -> write::Result<()> {
50         if reg < 32 {
51             self.write_u8(gimli::constants::DW_OP_reg0.0 as u8 + reg as u8)
52         } else {
53             self.write_op(gimli::constants::DW_OP_regx)?;
54             self.write_uleb128(reg.into())
55         }
56     }
57 
58     pub fn write_op_breg(&mut self, reg: u16) -> write::Result<()> {
59         if reg < 32 {
60             self.write_u8(gimli::constants::DW_OP_breg0.0 as u8 + reg as u8)
61         } else {
62             self.write_op(gimli::constants::DW_OP_bregx)?;
63             self.write_uleb128(reg.into())
64         }
65     }
66 
67     pub fn write_u8(&mut self, b: u8) -> write::Result<()> {
68         write::Writer::write_u8(&mut self.0, b)
69     }
70 
71     pub fn write_u32(&mut self, b: u32) -> write::Result<()> {
72         write::Writer::write_u32(&mut self.0, b)
73     }
74 
75     pub fn write_uleb128(&mut self, i: u64) -> write::Result<()> {
76         write::Writer::write_uleb128(&mut self.0, i)
77     }
78 
79     pub fn write_sleb128(&mut self, i: i64) -> write::Result<()> {
80         write::Writer::write_sleb128(&mut self.0, i)
81     }
82 
83     pub fn into_vec(self) -> Vec<u8> {
84         self.0.into_vec()
85     }
86 }
87 
88 #[derive(Debug, Clone, PartialEq)]
89 enum CompiledExpressionPart {
90     // Untranslated DWARF expression.
91     Code(Vec<u8>),
92     // The wasm-local DWARF operator. The label points to `ValueLabel`.
93     // The trailing field denotes that the operator was last in sequence,
94     // and it is the DWARF location (not a pointer).
95     Local {
96         label: ValueLabel,
97         trailing: bool,
98     },
99     // Dereference is needed.
100     Deref,
101     // Jumping in the expression.
102     Jump {
103         conditionally: bool,
104         target: JumpTargetMarker,
105     },
106     // Floating landing pad.
107     LandingPad(JumpTargetMarker),
108 }
109 
110 #[derive(Debug, Clone, PartialEq)]
111 pub struct CompiledExpression {
112     parts: Vec<CompiledExpressionPart>,
113     need_deref: bool,
114 }
115 
116 impl CompiledExpression {
117     pub fn vmctx() -> CompiledExpression {
118         CompiledExpression::from_label(get_vmctx_value_label())
119     }
120 
121     pub fn from_label(label: ValueLabel) -> CompiledExpression {
122         CompiledExpression {
123             parts: vec![CompiledExpressionPart::Local {
124                 label,
125                 trailing: true,
126             }],
127             need_deref: false,
128         }
129     }
130 }
131 
132 const X86_64_STACK_OFFSET: i64 = 16;
133 
134 fn translate_loc(
135     loc: LabelValueLoc,
136     frame_info: Option<&FunctionFrameInfo>,
137     isa: &dyn TargetIsa,
138     add_stack_value: bool,
139 ) -> Result<Option<Vec<u8>>> {
140     Ok(match loc {
141         LabelValueLoc::ValueLoc(ValueLoc::Reg(reg)) => {
142             let machine_reg = isa.map_dwarf_register(reg)?;
143             let mut writer = ExpressionWriter::new();
144             if add_stack_value {
145                 writer.write_op_reg(machine_reg)?;
146             } else {
147                 writer.write_op_breg(machine_reg)?;
148                 writer.write_sleb128(0)?;
149             }
150             Some(writer.into_vec())
151         }
152         LabelValueLoc::ValueLoc(ValueLoc::Stack(ss)) => {
153             if let Some(frame_info) = frame_info {
154                 if let Some(ss_offset) = frame_info.stack_slots[ss].offset {
155                     let mut writer = ExpressionWriter::new();
156                     writer.write_op_breg(X86_64::RBP.0)?;
157                     writer.write_sleb128(ss_offset as i64 + X86_64_STACK_OFFSET)?;
158                     if !add_stack_value {
159                         writer.write_op(gimli::constants::DW_OP_deref)?;
160                     }
161                     return Ok(Some(writer.into_vec()));
162                 }
163             }
164             None
165         }
166         LabelValueLoc::Reg(r) => {
167             let machine_reg = isa.map_regalloc_reg_to_dwarf(r)?;
168             let mut writer = ExpressionWriter::new();
169             if add_stack_value {
170                 writer.write_op_reg(machine_reg)?;
171             } else {
172                 writer.write_op_breg(machine_reg)?;
173                 writer.write_sleb128(0)?;
174             }
175             Some(writer.into_vec())
176         }
177         LabelValueLoc::SPOffset(off) => {
178             let mut writer = ExpressionWriter::new();
179             writer.write_op_breg(X86_64::RSP.0)?;
180             writer.write_sleb128(off)?;
181             if !add_stack_value {
182                 writer.write_op(gimli::constants::DW_OP_deref)?;
183             }
184             return Ok(Some(writer.into_vec()));
185         }
186 
187         _ => None,
188     })
189 }
190 
191 fn append_memory_deref(
192     buf: &mut Vec<u8>,
193     frame_info: &FunctionFrameInfo,
194     vmctx_loc: LabelValueLoc,
195     isa: &dyn TargetIsa,
196 ) -> Result<bool> {
197     let mut writer = ExpressionWriter::new();
198     // FIXME for imported memory
199     match vmctx_loc {
200         LabelValueLoc::ValueLoc(ValueLoc::Reg(vmctx_reg)) => {
201             let reg = isa.map_dwarf_register(vmctx_reg)? as u8;
202             writer.write_u8(gimli::constants::DW_OP_breg0.0 + reg)?;
203             let memory_offset = match frame_info.vmctx_memory_offset() {
204                 Some(offset) => offset,
205                 None => {
206                     return Ok(false);
207                 }
208             };
209             writer.write_sleb128(memory_offset)?;
210         }
211         LabelValueLoc::ValueLoc(ValueLoc::Stack(ss)) => {
212             if let Some(ss_offset) = frame_info.stack_slots[ss].offset {
213                 writer.write_op_breg(X86_64::RBP.0)?;
214                 writer.write_sleb128(ss_offset as i64 + X86_64_STACK_OFFSET)?;
215                 writer.write_op(gimli::constants::DW_OP_deref)?;
216                 writer.write_op(gimli::constants::DW_OP_consts)?;
217                 let memory_offset = match frame_info.vmctx_memory_offset() {
218                     Some(offset) => offset,
219                     None => {
220                         return Ok(false);
221                     }
222                 };
223                 writer.write_sleb128(memory_offset)?;
224                 writer.write_op(gimli::constants::DW_OP_plus)?;
225             } else {
226                 return Ok(false);
227             }
228         }
229         LabelValueLoc::Reg(r) => {
230             let reg = isa.map_regalloc_reg_to_dwarf(r)?;
231             writer.write_op_breg(reg)?;
232             let memory_offset = match frame_info.vmctx_memory_offset() {
233                 Some(offset) => offset,
234                 None => {
235                     return Ok(false);
236                 }
237             };
238             writer.write_sleb128(memory_offset)?;
239         }
240         LabelValueLoc::SPOffset(off) => {
241             writer.write_op_breg(X86_64::RSP.0)?;
242             writer.write_sleb128(off)?;
243             writer.write_op(gimli::constants::DW_OP_deref)?;
244             writer.write_op(gimli::constants::DW_OP_consts)?;
245             let memory_offset = match frame_info.vmctx_memory_offset() {
246                 Some(offset) => offset,
247                 None => {
248                     return Ok(false);
249                 }
250             };
251             writer.write_sleb128(memory_offset)?;
252             writer.write_op(gimli::constants::DW_OP_plus)?;
253         }
254         _ => {
255             return Ok(false);
256         }
257     }
258     writer.write_op(gimli::constants::DW_OP_deref)?;
259     writer.write_op(gimli::constants::DW_OP_swap)?;
260     writer.write_op(gimli::constants::DW_OP_const4u)?;
261     writer.write_u32(0xffff_ffff)?;
262     writer.write_op(gimli::constants::DW_OP_and)?;
263     writer.write_op(gimli::constants::DW_OP_plus)?;
264     buf.extend(writer.into_vec());
265     Ok(true)
266 }
267 
268 impl CompiledExpression {
269     pub fn is_simple(&self) -> bool {
270         if let [CompiledExpressionPart::Code(_)] = self.parts.as_slice() {
271             true
272         } else {
273             self.parts.is_empty()
274         }
275     }
276 
277     pub fn build(&self) -> Option<write::Expression> {
278         if let [CompiledExpressionPart::Code(code)] = self.parts.as_slice() {
279             return Some(write::Expression::raw(code.to_vec()));
280         }
281         // locals found, not supported
282         None
283     }
284 
285     pub fn build_with_locals<'a>(
286         &'a self,
287         scope: &'a [(u64, u64)], // wasm ranges
288         addr_tr: &'a AddressTransform,
289         frame_info: Option<&'a FunctionFrameInfo>,
290         isa: &'a dyn TargetIsa,
291     ) -> impl Iterator<Item = Result<(write::Address, u64, write::Expression)>> + 'a {
292         enum BuildWithLocalsResult<'a> {
293             Empty,
294             Simple(
295                 Box<dyn Iterator<Item = (write::Address, u64)> + 'a>,
296                 Vec<u8>,
297             ),
298             Ranges(
299                 Box<dyn Iterator<Item = Result<(DefinedFuncIndex, usize, usize, Vec<u8>)>> + 'a>,
300             ),
301         }
302         impl Iterator for BuildWithLocalsResult<'_> {
303             type Item = Result<(write::Address, u64, write::Expression)>;
304             fn next(&mut self) -> Option<Self::Item> {
305                 match self {
306                     BuildWithLocalsResult::Empty => None,
307                     BuildWithLocalsResult::Simple(it, code) => it
308                         .next()
309                         .map(|(addr, len)| Ok((addr, len, write::Expression::raw(code.to_vec())))),
310                     BuildWithLocalsResult::Ranges(it) => it.next().map(|r| {
311                         r.map(|(func_index, start, end, code_buf)| {
312                             (
313                                 write::Address::Symbol {
314                                     symbol: func_index.index(),
315                                     addend: start as i64,
316                                 },
317                                 (end - start) as u64,
318                                 write::Expression::raw(code_buf),
319                             )
320                         })
321                     }),
322                 }
323             }
324         }
325 
326         if scope.is_empty() {
327             return BuildWithLocalsResult::Empty;
328         }
329 
330         // If it a simple DWARF code, no need in locals processing. Just translate
331         // the scope ranges.
332         if let [CompiledExpressionPart::Code(code)] = self.parts.as_slice() {
333             return BuildWithLocalsResult::Simple(
334                 Box::new(scope.iter().flat_map(move |(wasm_start, wasm_end)| {
335                     addr_tr.translate_ranges(*wasm_start, *wasm_end)
336                 })),
337                 code.clone(),
338             );
339         }
340 
341         let vmctx_label = get_vmctx_value_label();
342 
343         // Some locals are present, preparing and divided ranges based on the scope
344         // and frame_info data.
345         let mut ranges_builder = ValueLabelRangesBuilder::new(scope, addr_tr, frame_info);
346         for p in self.parts.iter() {
347             match p {
348                 CompiledExpressionPart::Code(_)
349                 | CompiledExpressionPart::Jump { .. }
350                 | CompiledExpressionPart::LandingPad { .. } => (),
351                 CompiledExpressionPart::Local { label, .. } => ranges_builder.process_label(*label),
352                 CompiledExpressionPart::Deref => ranges_builder.process_label(vmctx_label),
353             }
354         }
355         if self.need_deref {
356             ranges_builder.process_label(vmctx_label);
357         }
358         let ranges = ranges_builder.into_ranges();
359 
360         return BuildWithLocalsResult::Ranges(Box::new(
361             ranges
362                 .into_iter()
363                 .map(
364                     move |CachedValueLabelRange {
365                               func_index,
366                               start,
367                               end,
368                               label_location,
369                           }| {
370                         // build expression
371                         let mut code_buf = Vec::new();
372                         let mut jump_positions = Vec::new();
373                         let mut landing_positions = HashMap::new();
374 
375                         macro_rules! deref {
376                             () => {
377                                 if let (Some(vmctx_loc), Some(frame_info)) =
378                                     (label_location.get(&vmctx_label), frame_info)
379                                 {
380                                     if !append_memory_deref(
381                                         &mut code_buf,
382                                         frame_info,
383                                         *vmctx_loc,
384                                         isa,
385                                     )? {
386                                         return Ok(None);
387                                     }
388                                 } else {
389                                     return Ok(None);
390                                 }
391                             };
392                         }
393                         for part in &self.parts {
394                             match part {
395                                 CompiledExpressionPart::Code(c) => {
396                                     code_buf.extend_from_slice(c.as_slice())
397                                 }
398                                 CompiledExpressionPart::LandingPad(marker) => {
399                                     landing_positions.insert(marker.clone(), code_buf.len());
400                                 }
401                                 CompiledExpressionPart::Jump {
402                                     conditionally,
403                                     target,
404                                 } => {
405                                     code_buf.push(
406                                         match conditionally {
407                                             true => gimli::constants::DW_OP_bra,
408                                             false => gimli::constants::DW_OP_skip,
409                                         }
410                                         .0 as u8,
411                                     );
412                                     code_buf.push(!0);
413                                     code_buf.push(!0); // these will be relocated below
414                                     jump_positions.push((target.clone(), code_buf.len()));
415                                 }
416                                 CompiledExpressionPart::Local { label, trailing } => {
417                                     let loc =
418                                         *label_location.get(&label).context("label_location")?;
419                                     if let Some(expr) =
420                                         translate_loc(loc, frame_info, isa, *trailing)?
421                                     {
422                                         code_buf.extend_from_slice(&expr)
423                                     } else {
424                                         return Ok(None);
425                                     }
426                                 }
427                                 CompiledExpressionPart::Deref => deref!(),
428                             }
429                         }
430                         if self.need_deref {
431                             deref!();
432                         }
433 
434                         for (marker, new_from) in jump_positions {
435                             // relocate jump targets
436                             let new_to = landing_positions[&marker];
437                             let new_diff = new_to as isize - new_from as isize;
438                             // FIXME: use encoding? LittleEndian for now...
439                             code_buf[new_from - 2..new_from]
440                                 .copy_from_slice(&(new_diff as i16).to_le_bytes());
441                         }
442                         Ok(Some((func_index, start, end, code_buf)))
443                     },
444                 )
445                 .filter_map(Result::transpose),
446         ));
447     }
448 }
449 
450 fn is_old_expression_format(buf: &[u8]) -> bool {
451     // Heuristic to detect old variable expression format without DW_OP_fbreg:
452     // DW_OP_plus_uconst op must be present, but not DW_OP_fbreg.
453     if buf.contains(&(gimli::constants::DW_OP_fbreg.0 as u8)) {
454         // Stop check if DW_OP_fbreg exist.
455         return false;
456     }
457     buf.contains(&(gimli::constants::DW_OP_plus_uconst.0 as u8))
458 }
459 
460 pub fn compile_expression<R>(
461     expr: &Expression<R>,
462     encoding: gimli::Encoding,
463     frame_base: Option<&CompiledExpression>,
464 ) -> Result<Option<CompiledExpression>, Error>
465 where
466     R: Reader,
467 {
468     // Bail when `frame_base` is complicated.
469     if let Some(expr) = frame_base {
470         if expr.parts.iter().any(|p| match p {
471             CompiledExpressionPart::Jump { .. } => true,
472             _ => false,
473         }) {
474             return Ok(None);
475         }
476     }
477 
478     // jump_targets key is offset in buf starting from the end
479     // (see also `unread_bytes` below)
480     let mut jump_targets: HashMap<u64, JumpTargetMarker> = HashMap::new();
481     let mut pc = expr.0.clone();
482 
483     let buf = expr.0.to_slice()?;
484     let mut parts = Vec::new();
485     macro_rules! push {
486         ($part:expr) => {{
487             let part = $part;
488             if let (CompiledExpressionPart::Code(cc2), Some(CompiledExpressionPart::Code(cc1))) =
489                 (&part, parts.last_mut())
490             {
491                 cc1.extend_from_slice(cc2);
492             } else {
493                 parts.push(part)
494             }
495         }};
496     }
497     let mut need_deref = false;
498     if is_old_expression_format(&buf) && frame_base.is_some() {
499         // Still supporting old DWARF variable expressions without fbreg.
500         parts.extend_from_slice(&frame_base.unwrap().parts);
501         if let Some(CompiledExpressionPart::Local { trailing, .. }) = parts.last_mut() {
502             *trailing = false;
503         }
504         need_deref = frame_base.unwrap().need_deref;
505     }
506     let mut code_chunk = Vec::new();
507     macro_rules! flush_code_chunk {
508         () => {
509             if !code_chunk.is_empty() {
510                 push!(CompiledExpressionPart::Code(code_chunk));
511                 code_chunk = Vec::new();
512                 let _ = code_chunk; // suppresses warning for final flush
513             }
514         };
515     }
516 
517     // Find all landing pads by scanning bytes, do not care about
518     // false location at this moment.
519     // Looks hacky but it is fast; does not need to be really exact.
520     if buf.len() > 2 {
521         for i in 0..buf.len() - 2 {
522             let op = buf[i];
523             if op == gimli::constants::DW_OP_bra.0 || op == gimli::constants::DW_OP_skip.0 {
524                 // TODO fix for big-endian
525                 let offset = i16::from_le_bytes([buf[i + 1], buf[i + 2]]);
526                 let origin = i + 3;
527                 // Discarding out-of-bounds jumps (also some of falsely detected ops)
528                 if (offset >= 0 && offset as usize + origin <= buf.len())
529                     || (offset < 0 && -offset as usize <= origin)
530                 {
531                     let target = buf.len() as isize - origin as isize - offset as isize;
532                     jump_targets.insert(target as u64, JumpTargetMarker::new());
533                 }
534             }
535         }
536     }
537 
538     while !pc.is_empty() {
539         let unread_bytes = pc.len().into_u64();
540         if let Some(marker) = jump_targets.get(&unread_bytes) {
541             flush_code_chunk!();
542             parts.push(CompiledExpressionPart::LandingPad(marker.clone()));
543         }
544 
545         need_deref = true;
546 
547         let pos = pc.offset_from(&expr.0).into_u64() as usize;
548         let op = Operation::parse(&mut pc, encoding)?;
549         match op {
550             Operation::FrameOffset { offset } => {
551                 // Expand DW_OP_fbreg into frame location and DW_OP_plus_uconst.
552                 if frame_base.is_some() {
553                     // Add frame base expressions.
554                     flush_code_chunk!();
555                     parts.extend_from_slice(&frame_base.unwrap().parts);
556                 }
557                 if let Some(CompiledExpressionPart::Local { trailing, .. }) = parts.last_mut() {
558                     // Reset local trailing flag.
559                     *trailing = false;
560                 }
561                 // Append DW_OP_plus_uconst part.
562                 let mut writer = ExpressionWriter::new();
563                 writer.write_op(gimli::constants::DW_OP_plus_uconst)?;
564                 writer.write_uleb128(offset as u64)?;
565                 code_chunk.extend(writer.into_vec());
566                 continue;
567             }
568             Operation::Drop { .. }
569             | Operation::Pick { .. }
570             | Operation::Swap { .. }
571             | Operation::Rot { .. }
572             | Operation::Nop { .. }
573             | Operation::UnsignedConstant { .. }
574             | Operation::SignedConstant { .. }
575             | Operation::ConstantIndex { .. }
576             | Operation::PlusConstant { .. }
577             | Operation::Abs { .. }
578             | Operation::And { .. }
579             | Operation::Or { .. }
580             | Operation::Xor { .. }
581             | Operation::Shl { .. }
582             | Operation::Plus { .. }
583             | Operation::Minus { .. }
584             | Operation::Div { .. }
585             | Operation::Mod { .. }
586             | Operation::Mul { .. }
587             | Operation::Neg { .. }
588             | Operation::Not { .. }
589             | Operation::Lt { .. }
590             | Operation::Gt { .. }
591             | Operation::Le { .. }
592             | Operation::Ge { .. }
593             | Operation::Eq { .. }
594             | Operation::Ne { .. }
595             | Operation::TypedLiteral { .. }
596             | Operation::Convert { .. }
597             | Operation::Reinterpret { .. }
598             | Operation::Piece { .. } => (),
599             Operation::Bra { target } | Operation::Skip { target } => {
600                 flush_code_chunk!();
601                 let arc_to = (pc.len().into_u64() as isize - target as isize) as u64;
602                 let marker = match jump_targets.get(&arc_to) {
603                     Some(m) => m.clone(),
604                     None => {
605                         // Marker not found: probably out of bounds.
606                         return Ok(None);
607                     }
608                 };
609                 push!(CompiledExpressionPart::Jump {
610                     conditionally: match op {
611                         Operation::Bra { .. } => true,
612                         _ => false,
613                     },
614                     target: marker,
615                 });
616                 continue;
617             }
618             Operation::StackValue => {
619                 need_deref = false;
620 
621                 // Find extra stack_value, that follow wasm-local operators,
622                 // and mark such locals with special flag.
623                 if let (Some(CompiledExpressionPart::Local { trailing, .. }), true) =
624                     (parts.last_mut(), code_chunk.is_empty())
625                 {
626                     *trailing = true;
627                     continue;
628                 }
629             }
630             Operation::Deref { .. } => {
631                 flush_code_chunk!();
632                 push!(CompiledExpressionPart::Deref);
633                 // Don't re-enter the loop here (i.e. continue), because the
634                 // DW_OP_deref still needs to be kept.
635             }
636             Operation::WasmLocal { index } => {
637                 flush_code_chunk!();
638                 let label = ValueLabel::from_u32(index as u32);
639                 push!(CompiledExpressionPart::Local {
640                     label,
641                     trailing: false,
642                 });
643                 continue;
644             }
645             Operation::Shr { .. } | Operation::Shra { .. } => {
646                 // Insert value normalisation part.
647                 // The semantic value is 32 bits (TODO: check unit)
648                 // but the target architecture is 64-bits. So we'll
649                 // clean out the upper 32 bits (in a sign-correct way)
650                 // to avoid contamination of the result with randomness.
651                 let mut writer = ExpressionWriter::new();
652                 writer.write_op(gimli::constants::DW_OP_plus_uconst)?;
653                 writer.write_uleb128(32)?; // increase shift amount
654                 writer.write_op(gimli::constants::DW_OP_swap)?;
655                 writer.write_op(gimli::constants::DW_OP_const1u)?;
656                 writer.write_u8(32)?;
657                 writer.write_op(gimli::constants::DW_OP_shl)?;
658                 writer.write_op(gimli::constants::DW_OP_swap)?;
659                 code_chunk.extend(writer.into_vec());
660                 // Don't re-enter the loop here (i.e. continue), because the
661                 // DW_OP_shr* still needs to be kept.
662             }
663             Operation::Address { .. }
664             | Operation::AddressIndex { .. }
665             | Operation::Call { .. }
666             | Operation::Register { .. }
667             | Operation::RegisterOffset { .. }
668             | Operation::CallFrameCFA
669             | Operation::PushObjectAddress
670             | Operation::TLS
671             | Operation::ImplicitValue { .. }
672             | Operation::ImplicitPointer { .. }
673             | Operation::EntryValue { .. }
674             | Operation::ParameterRef { .. } => {
675                 return Ok(None);
676             }
677             Operation::WasmGlobal { index: _ } | Operation::WasmStack { index: _ } => {
678                 // TODO support those two
679                 return Ok(None);
680             }
681         }
682         let chunk = &buf[pos..pc.offset_from(&expr.0).into_u64() as usize];
683         code_chunk.extend_from_slice(chunk);
684     }
685 
686     flush_code_chunk!();
687     if let Some(marker) = jump_targets.get(&0) {
688         parts.push(CompiledExpressionPart::LandingPad(marker.clone()));
689     }
690 
691     Ok(Some(CompiledExpression { parts, need_deref }))
692 }
693 
694 #[derive(Debug, Clone)]
695 struct CachedValueLabelRange {
696     func_index: DefinedFuncIndex,
697     start: usize,
698     end: usize,
699     label_location: HashMap<ValueLabel, LabelValueLoc>,
700 }
701 
702 struct ValueLabelRangesBuilder<'a, 'b> {
703     ranges: Vec<CachedValueLabelRange>,
704     frame_info: Option<&'a FunctionFrameInfo<'b>>,
705     processed_labels: HashSet<ValueLabel>,
706 }
707 
708 impl<'a, 'b> ValueLabelRangesBuilder<'a, 'b> {
709     pub fn new(
710         scope: &[(u64, u64)], // wasm ranges
711         addr_tr: &'a AddressTransform,
712         frame_info: Option<&'a FunctionFrameInfo<'b>>,
713     ) -> Self {
714         let mut ranges = Vec::new();
715         for (wasm_start, wasm_end) in scope {
716             if let Some((func_index, tr)) = addr_tr.translate_ranges_raw(*wasm_start, *wasm_end) {
717                 ranges.extend(tr.into_iter().map(|(start, end)| CachedValueLabelRange {
718                     func_index,
719                     start,
720                     end,
721                     label_location: HashMap::new(),
722                 }));
723             }
724         }
725         ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start));
726         ValueLabelRangesBuilder {
727             ranges,
728             frame_info,
729             processed_labels: HashSet::new(),
730         }
731     }
732 
733     fn process_label(&mut self, label: ValueLabel) {
734         if self.processed_labels.contains(&label) {
735             return;
736         }
737         self.processed_labels.insert(label);
738 
739         let value_ranges = match self.frame_info.and_then(|fi| fi.value_ranges.get(&label)) {
740             Some(value_ranges) => value_ranges,
741             None => {
742                 return;
743             }
744         };
745 
746         let ranges = &mut self.ranges;
747         for value_range in value_ranges {
748             let range_start = value_range.start as usize;
749             let range_end = value_range.end as usize;
750             let loc = value_range.loc;
751             if range_start == range_end {
752                 continue;
753             }
754             assert_lt!(range_start, range_end);
755 
756             // Find acceptable scope of ranges to intersect with.
757             let i = match ranges.binary_search_by(|s| s.start.cmp(&range_start)) {
758                 Ok(i) => i,
759                 Err(i) => {
760                     if i > 0 && range_start < ranges[i - 1].end {
761                         i - 1
762                     } else {
763                         i
764                     }
765                 }
766             };
767             let j = match ranges.binary_search_by(|s| s.start.cmp(&range_end)) {
768                 Ok(i) | Err(i) => i,
769             };
770             // Starting from the end, intersect (range_start..range_end) with
771             // self.ranges array.
772             for i in (i..j).rev() {
773                 if range_end <= ranges[i].start || ranges[i].end <= range_start {
774                     continue;
775                 }
776                 if range_end < ranges[i].end {
777                     // Cutting some of the range from the end.
778                     let mut tail = ranges[i].clone();
779                     ranges[i].end = range_end;
780                     tail.start = range_end;
781                     ranges.insert(i + 1, tail);
782                 }
783                 assert_le!(ranges[i].end, range_end);
784                 if range_start <= ranges[i].start {
785                     ranges[i].label_location.insert(label, loc);
786                     continue;
787                 }
788                 // Cutting some of the range from the start.
789                 let mut tail = ranges[i].clone();
790                 ranges[i].end = range_start;
791                 tail.start = range_start;
792                 tail.label_location.insert(label, loc);
793                 ranges.insert(i + 1, tail);
794             }
795         }
796     }
797 
798     pub fn into_ranges(self) -> impl Iterator<Item = CachedValueLabelRange> {
799         // Ranges with not-enough labels are discarded.
800         let processed_labels_len = self.processed_labels.len();
801         self.ranges
802             .into_iter()
803             .filter(move |r| r.label_location.len() == processed_labels_len)
804     }
805 }
806 
807 /// Marker for tracking incoming jumps.
808 /// Different when created new, and the same when cloned.
809 #[derive(Clone, Eq)]
810 struct JumpTargetMarker(Rc<u32>);
811 
812 impl JumpTargetMarker {
813     fn new() -> JumpTargetMarker {
814         // Create somewhat unique hash data -- using part of
815         // the pointer of the RcBox.
816         let mut rc = Rc::new(0);
817         let hash_data = rc.as_ref() as *const u32 as usize as u32;
818         *Rc::get_mut(&mut rc).unwrap() = hash_data;
819         JumpTargetMarker(rc)
820     }
821 }
822 
823 impl PartialEq for JumpTargetMarker {
824     fn eq(&self, other: &JumpTargetMarker) -> bool {
825         Rc::ptr_eq(&self.0, &other.0)
826     }
827 }
828 
829 impl Hash for JumpTargetMarker {
830     fn hash<H: Hasher>(&self, hasher: &mut H) {
831         hasher.write_u32(*self.0);
832     }
833 }
834 impl std::fmt::Debug for JumpTargetMarker {
835     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
836         write!(
837             f,
838             "JumpMarker<{:08x}>",
839             self.0.as_ref() as *const u32 as usize
840         )
841     }
842 }
843 
844 #[cfg(test)]
845 mod tests {
846     use super::{
847         compile_expression, AddressTransform, CompiledExpression, CompiledExpressionPart,
848         FunctionFrameInfo, JumpTargetMarker, ValueLabel, ValueLabelsRanges,
849     };
850     use crate::CompiledFunction;
851     use gimli::{self, constants, Encoding, EndianSlice, Expression, RunTimeEndian};
852     use wasmtime_environ::FilePos;
853 
854     macro_rules! dw_op {
855         (DW_OP_WASM_location) => {
856             0xed
857         };
858         ($i:literal) => {
859             $i
860         };
861         ($d:ident) => {
862             constants::$d.0 as u8
863         };
864         ($e:expr) => {
865             $e as u8
866         };
867     }
868 
869     macro_rules! expression {
870         ($($t:tt),*) => {
871             Expression(EndianSlice::new(
872                 &[$(dw_op!($t)),*],
873                 RunTimeEndian::Little,
874             ))
875         }
876     }
877 
878     fn find_jump_targets<'a>(ce: &'a CompiledExpression) -> Vec<&'a JumpTargetMarker> {
879         ce.parts
880             .iter()
881             .filter_map(|p| {
882                 if let CompiledExpressionPart::LandingPad(t) = p {
883                     Some(t)
884                 } else {
885                     None
886                 }
887             })
888             .collect::<Vec<_>>()
889     }
890 
891     static DWARF_ENCODING: Encoding = Encoding {
892         address_size: 4,
893         format: gimli::Format::Dwarf32,
894         version: 4,
895     };
896 
897     #[test]
898     fn test_debug_expression_jump_target() {
899         let m1 = JumpTargetMarker::new();
900         let m2 = JumpTargetMarker::new();
901         assert!(m1 != m2);
902         assert!(m1 == m1.clone());
903 
904         // Internal hash_data test (theoretically can fail intermittently).
905         assert!(m1.0 != m2.0);
906     }
907 
908     #[test]
909     fn test_debug_parse_expressions() {
910         use cranelift_entity::EntityRef;
911 
912         let (val1, val3, val20) = (ValueLabel::new(1), ValueLabel::new(3), ValueLabel::new(20));
913 
914         let e = expression!(DW_OP_WASM_location, 0x0, 20, DW_OP_stack_value);
915         let ce = compile_expression(&e, DWARF_ENCODING, None)
916             .expect("non-error")
917             .expect("expression");
918         assert_eq!(
919             ce,
920             CompiledExpression {
921                 parts: vec![CompiledExpressionPart::Local {
922                     label: val20,
923                     trailing: true
924                 }],
925                 need_deref: false,
926             }
927         );
928 
929         let e = expression!(
930             DW_OP_WASM_location,
931             0x0,
932             1,
933             DW_OP_plus_uconst,
934             0x10,
935             DW_OP_stack_value
936         );
937         let ce = compile_expression(&e, DWARF_ENCODING, None)
938             .expect("non-error")
939             .expect("expression");
940         assert_eq!(
941             ce,
942             CompiledExpression {
943                 parts: vec![
944                     CompiledExpressionPart::Local {
945                         label: val1,
946                         trailing: false
947                     },
948                     CompiledExpressionPart::Code(vec![35, 16, 159])
949                 ],
950                 need_deref: false,
951             }
952         );
953 
954         let e = expression!(DW_OP_WASM_location, 0x0, 3, DW_OP_stack_value);
955         let fe = compile_expression(&e, DWARF_ENCODING, None).expect("non-error");
956         let e = expression!(DW_OP_fbreg, 0x12);
957         let ce = compile_expression(&e, DWARF_ENCODING, fe.as_ref())
958             .expect("non-error")
959             .expect("expression");
960         assert_eq!(
961             ce,
962             CompiledExpression {
963                 parts: vec![
964                     CompiledExpressionPart::Local {
965                         label: val3,
966                         trailing: false
967                     },
968                     CompiledExpressionPart::Code(vec![35, 18])
969                 ],
970                 need_deref: true,
971             }
972         );
973 
974         let e = expression!(
975             DW_OP_WASM_location,
976             0x0,
977             1,
978             DW_OP_plus_uconst,
979             5,
980             DW_OP_deref,
981             DW_OP_stack_value
982         );
983         let ce = compile_expression(&e, DWARF_ENCODING, None)
984             .expect("non-error")
985             .expect("expression");
986         assert_eq!(
987             ce,
988             CompiledExpression {
989                 parts: vec![
990                     CompiledExpressionPart::Local {
991                         label: val1,
992                         trailing: false
993                     },
994                     CompiledExpressionPart::Code(vec![35, 5]),
995                     CompiledExpressionPart::Deref,
996                     CompiledExpressionPart::Code(vec![6, 159])
997                 ],
998                 need_deref: false,
999             }
1000         );
1001 
1002         let e = expression!(
1003             DW_OP_WASM_location,
1004             0x0,
1005             1,
1006             DW_OP_lit16,
1007             DW_OP_shra,
1008             DW_OP_stack_value
1009         );
1010         let ce = compile_expression(&e, DWARF_ENCODING, None)
1011             .expect("non-error")
1012             .expect("expression");
1013         assert_eq!(
1014             ce,
1015             CompiledExpression {
1016                 parts: vec![
1017                     CompiledExpressionPart::Local {
1018                         label: val1,
1019                         trailing: false
1020                     },
1021                     CompiledExpressionPart::Code(vec![64, 35, 32, 22, 8, 32, 36, 22, 38, 159])
1022                 ],
1023                 need_deref: false,
1024             }
1025         );
1026 
1027         let e = expression!(
1028             DW_OP_lit1,
1029             DW_OP_dup,
1030             DW_OP_WASM_location,
1031             0x0,
1032             1,
1033             DW_OP_and,
1034             DW_OP_bra,
1035             5,
1036             0, // --> pointer
1037             DW_OP_swap,
1038             DW_OP_shr,
1039             DW_OP_skip,
1040             2,
1041             0, // --> done
1042             // pointer:
1043             DW_OP_plus,
1044             DW_OP_deref,
1045             // done:
1046             DW_OP_stack_value
1047         );
1048         let ce = compile_expression(&e, DWARF_ENCODING, None)
1049             .expect("non-error")
1050             .expect("expression");
1051         let targets = find_jump_targets(&ce);
1052         assert_eq!(targets.len(), 2);
1053         assert_eq!(
1054             ce,
1055             CompiledExpression {
1056                 parts: vec![
1057                     CompiledExpressionPart::Code(vec![49, 18]),
1058                     CompiledExpressionPart::Local {
1059                         label: val1,
1060                         trailing: false
1061                     },
1062                     CompiledExpressionPart::Code(vec![26]),
1063                     CompiledExpressionPart::Jump {
1064                         conditionally: true,
1065                         target: targets[0].clone(),
1066                     },
1067                     CompiledExpressionPart::Code(vec![22, 35, 32, 22, 8, 32, 36, 22, 37]),
1068                     CompiledExpressionPart::Jump {
1069                         conditionally: false,
1070                         target: targets[1].clone(),
1071                     },
1072                     CompiledExpressionPart::LandingPad(targets[0].clone()), // capture from
1073                     CompiledExpressionPart::Code(vec![34]),
1074                     CompiledExpressionPart::Deref,
1075                     CompiledExpressionPart::Code(vec![6]),
1076                     CompiledExpressionPart::LandingPad(targets[1].clone()), // capture to
1077                     CompiledExpressionPart::Code(vec![159])
1078                 ],
1079                 need_deref: false,
1080             }
1081         );
1082 
1083         let e = expression!(
1084             DW_OP_lit1,
1085             DW_OP_dup,
1086             DW_OP_bra,
1087             2,
1088             0, // --> target
1089             DW_OP_deref,
1090             DW_OP_lit0,
1091             // target:
1092             DW_OP_stack_value
1093         );
1094         let ce = compile_expression(&e, DWARF_ENCODING, None)
1095             .expect("non-error")
1096             .expect("expression");
1097         let targets = find_jump_targets(&ce);
1098         assert_eq!(targets.len(), 1);
1099         assert_eq!(
1100             ce,
1101             CompiledExpression {
1102                 parts: vec![
1103                     CompiledExpressionPart::Code(vec![49, 18]),
1104                     CompiledExpressionPart::Jump {
1105                         conditionally: true,
1106                         target: targets[0].clone(),
1107                     },
1108                     CompiledExpressionPart::Deref,
1109                     CompiledExpressionPart::Code(vec![6, 48]),
1110                     CompiledExpressionPart::LandingPad(targets[0].clone()), // capture to
1111                     CompiledExpressionPart::Code(vec![159])
1112                 ],
1113                 need_deref: false,
1114             }
1115         );
1116 
1117         let e = expression!(
1118             DW_OP_lit1,
1119             /* loop */ DW_OP_dup,
1120             DW_OP_lit25,
1121             DW_OP_ge,
1122             DW_OP_bra,
1123             5,
1124             0, // --> done
1125             DW_OP_plus_uconst,
1126             1,
1127             DW_OP_skip,
1128             (-11 as i8),
1129             (!0), // --> loop
1130             /* done */ DW_OP_stack_value
1131         );
1132         let ce = compile_expression(&e, DWARF_ENCODING, None)
1133             .expect("non-error")
1134             .expect("expression");
1135         let targets = find_jump_targets(&ce);
1136         assert_eq!(targets.len(), 2);
1137         assert_eq!(
1138             ce,
1139             CompiledExpression {
1140                 parts: vec![
1141                     CompiledExpressionPart::Code(vec![49]),
1142                     CompiledExpressionPart::LandingPad(targets[0].clone()),
1143                     CompiledExpressionPart::Code(vec![18, 73, 42]),
1144                     CompiledExpressionPart::Jump {
1145                         conditionally: true,
1146                         target: targets[1].clone(),
1147                     },
1148                     CompiledExpressionPart::Code(vec![35, 1]),
1149                     CompiledExpressionPart::Jump {
1150                         conditionally: false,
1151                         target: targets[0].clone(),
1152                     },
1153                     CompiledExpressionPart::LandingPad(targets[1].clone()),
1154                     CompiledExpressionPart::Code(vec![159])
1155                 ],
1156                 need_deref: false,
1157             }
1158         );
1159 
1160         let e = expression!(DW_OP_WASM_location, 0x0, 1, DW_OP_plus_uconst, 5);
1161         let ce = compile_expression(&e, DWARF_ENCODING, None)
1162             .expect("non-error")
1163             .expect("expression");
1164         assert_eq!(
1165             ce,
1166             CompiledExpression {
1167                 parts: vec![
1168                     CompiledExpressionPart::Local {
1169                         label: val1,
1170                         trailing: false
1171                     },
1172                     CompiledExpressionPart::Code(vec![35, 5])
1173                 ],
1174                 need_deref: true,
1175             }
1176         );
1177     }
1178 
1179     fn create_mock_address_transform() -> AddressTransform {
1180         use crate::FunctionAddressMap;
1181         use cranelift_entity::PrimaryMap;
1182         use wasmtime_environ::InstructionAddressMap;
1183         use wasmtime_environ::WasmFileInfo;
1184         let mut module_map = PrimaryMap::new();
1185         let code_section_offset: u32 = 100;
1186         module_map.push(CompiledFunction {
1187             address_map: FunctionAddressMap {
1188                 instructions: vec![
1189                     InstructionAddressMap {
1190                         srcloc: FilePos::new(code_section_offset + 12),
1191                         code_offset: 5,
1192                     },
1193                     InstructionAddressMap {
1194                         srcloc: FilePos::default(),
1195                         code_offset: 8,
1196                     },
1197                     InstructionAddressMap {
1198                         srcloc: FilePos::new(code_section_offset + 17),
1199                         code_offset: 15,
1200                     },
1201                     InstructionAddressMap {
1202                         srcloc: FilePos::default(),
1203                         code_offset: 23,
1204                     },
1205                 ]
1206                 .into(),
1207                 start_srcloc: FilePos::new(code_section_offset + 10),
1208                 end_srcloc: FilePos::new(code_section_offset + 20),
1209                 body_offset: 0,
1210                 body_len: 30,
1211             },
1212             ..Default::default()
1213         });
1214         let fi = WasmFileInfo {
1215             code_section_offset: code_section_offset.into(),
1216             funcs: Vec::new(),
1217             imported_func_count: 0,
1218             path: None,
1219         };
1220         AddressTransform::new(&module_map, &fi)
1221     }
1222 
1223     fn create_mock_value_ranges() -> (ValueLabelsRanges, (ValueLabel, ValueLabel, ValueLabel)) {
1224         use cranelift_codegen::ir::{LabelValueLoc, ValueLoc};
1225         use cranelift_codegen::ValueLocRange;
1226         use cranelift_entity::EntityRef;
1227         use std::collections::HashMap;
1228         let mut value_ranges = HashMap::new();
1229         let value_0 = ValueLabel::new(0);
1230         let value_1 = ValueLabel::new(1);
1231         let value_2 = ValueLabel::new(2);
1232         value_ranges.insert(
1233             value_0,
1234             vec![ValueLocRange {
1235                 loc: LabelValueLoc::ValueLoc(ValueLoc::Unassigned),
1236                 start: 0,
1237                 end: 25,
1238             }],
1239         );
1240         value_ranges.insert(
1241             value_1,
1242             vec![ValueLocRange {
1243                 loc: LabelValueLoc::ValueLoc(ValueLoc::Unassigned),
1244                 start: 5,
1245                 end: 30,
1246             }],
1247         );
1248         value_ranges.insert(
1249             value_2,
1250             vec![
1251                 ValueLocRange {
1252                     loc: LabelValueLoc::ValueLoc(ValueLoc::Unassigned),
1253                     start: 0,
1254                     end: 10,
1255                 },
1256                 ValueLocRange {
1257                     loc: LabelValueLoc::ValueLoc(ValueLoc::Unassigned),
1258                     start: 20,
1259                     end: 30,
1260                 },
1261             ],
1262         );
1263         (value_ranges, (value_0, value_1, value_2))
1264     }
1265 
1266     #[test]
1267     fn test_debug_value_range_builder() {
1268         use super::ValueLabelRangesBuilder;
1269         use crate::debug::ModuleMemoryOffset;
1270         use cranelift_codegen::ir::StackSlots;
1271         use wasmtime_environ::{DefinedFuncIndex, EntityRef};
1272 
1273         let addr_tr = create_mock_address_transform();
1274         let stack_slots = StackSlots::new();
1275         let (value_ranges, value_labels) = create_mock_value_ranges();
1276         let fi = FunctionFrameInfo {
1277             memory_offset: ModuleMemoryOffset::None,
1278             stack_slots: &stack_slots,
1279             value_ranges: &value_ranges,
1280         };
1281 
1282         // No value labels, testing if entire function range coming through.
1283         let builder = ValueLabelRangesBuilder::new(&[(10, 20)], &addr_tr, Some(&fi));
1284         let ranges = builder.into_ranges().collect::<Vec<_>>();
1285         assert_eq!(ranges.len(), 1);
1286         assert_eq!(ranges[0].func_index, DefinedFuncIndex::new(0));
1287         assert_eq!(ranges[0].start, 0);
1288         assert_eq!(ranges[0].end, 30);
1289 
1290         // Two labels ([email protected] and [email protected]), their common lifetime intersect at 5..25.
1291         let mut builder = ValueLabelRangesBuilder::new(&[(10, 20)], &addr_tr, Some(&fi));
1292         builder.process_label(value_labels.0);
1293         builder.process_label(value_labels.1);
1294         let ranges = builder.into_ranges().collect::<Vec<_>>();
1295         assert_eq!(ranges.len(), 1);
1296         assert_eq!(ranges[0].start, 5);
1297         assert_eq!(ranges[0].end, 25);
1298 
1299         // Adds val2 with complex lifetime @0..10 and @20..30 to the previous test, and
1300         // also narrows range.
1301         let mut builder = ValueLabelRangesBuilder::new(&[(11, 17)], &addr_tr, Some(&fi));
1302         builder.process_label(value_labels.0);
1303         builder.process_label(value_labels.1);
1304         builder.process_label(value_labels.2);
1305         let ranges = builder.into_ranges().collect::<Vec<_>>();
1306         // Result is two ranges @5..10 and @20..23
1307         assert_eq!(ranges.len(), 2);
1308         assert_eq!(ranges[0].start, 5);
1309         assert_eq!(ranges[0].end, 10);
1310         assert_eq!(ranges[1].start, 20);
1311         assert_eq!(ranges[1].end, 23);
1312     }
1313 }
1314