rust_debug/evaluate/
mod.rs

1/// Contains functions for retrieving the values of some of the DWARF attributes.
2pub mod attributes;
3
4/// Contains structs representing the different Rust data types and more.
5pub mod evaluate;
6
7use crate::call_stack::MemoryAccess;
8use crate::registers::Registers;
9use anyhow::{anyhow, Result};
10use evaluate::{convert_to_gimli_value, BaseTypeValue, EvaluatorValue};
11use gimli::{
12    AttributeValue::UnitRef,
13    DebuggingInformationEntry, DieReference, Dwarf, Evaluation, EvaluationResult,
14    EvaluationResult::{
15        Complete, RequiresAtLocation, RequiresBaseType, RequiresCallFrameCfa, RequiresEntryValue,
16        RequiresFrameBase, RequiresIndexedAddress, RequiresMemory, RequiresParameterRef,
17        RequiresRegister, RequiresRelocatedAddress, RequiresTls,
18    },
19    Expression, Reader, Unit, UnitOffset,
20};
21use log::{error, info};
22use std::convert::TryInto;
23
24/// Will find the DIE representing the type can evaluate the variable.
25///
26/// Description:
27///
28/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
29/// * `pc` - A machine code address, usually the current code location.
30/// * `expr` - The expression to be evaluated.
31/// * `frame_base` - The frame base address value.
32/// * `unit` - A compilation unit which contains the given DIE.
33/// * `die` - The DIE the is used to find the DIE representing the type.
34/// * `registers` - A register struct for accessing the register values.
35/// * `mem` - A struct for accessing the memory of the debug target.
36///
37/// This function is used to find the DIE representing the type and then to evaluate the value of
38/// the given DIE>
39pub fn call_evaluate<R: Reader<Offset = usize>, T: MemoryAccess>(
40    dwarf: &Dwarf<R>,
41    pc: u32,
42    expr: gimli::Expression<R>,
43    frame_base: Option<u64>,
44    unit: &Unit<R>,
45    die: &DebuggingInformationEntry<R>,
46    registers: &Registers,
47    mem: &mut T,
48) -> Result<EvaluatorValue<R>> {
49    if let Ok(Some(tattr)) = die.attr_value(gimli::DW_AT_type) {
50        match tattr {
51            gimli::AttributeValue::UnitRef(offset) => {
52                let die = unit.entry(offset)?;
53                return evaluate(
54                    dwarf,
55                    unit,
56                    pc,
57                    expr,
58                    frame_base,
59                    Some(unit),
60                    Some(&die),
61                    registers,
62                    mem,
63                );
64            }
65            gimli::AttributeValue::DebugInfoRef(di_offset) => {
66                let offset = gimli::UnitSectionOffset::DebugInfoOffset(di_offset);
67                let mut iter = dwarf.debug_info.units();
68                while let Ok(Some(header)) = iter.next() {
69                    let type_unit = dwarf.unit(header)?;
70                    if let Some(offset) = offset.to_unit_offset(&type_unit) {
71                        let die = type_unit.entry(offset)?;
72                        return evaluate(
73                            dwarf,
74                            unit,
75                            pc,
76                            expr,
77                            frame_base,
78                            Some(&type_unit),
79                            Some(&die),
80                            registers,
81                            mem,
82                        );
83                    }
84                }
85
86                error!("Unreachable");
87                return Err(anyhow!("Unreachable"));
88            }
89            attribute => {
90                error!("Unimplemented for attribute {:?}", attribute);
91                return Err(anyhow!("Unimplemented for attribute {:?}", attribute));
92            }
93        };
94    } else if let Ok(Some(die_offset)) = die.attr_value(gimli::DW_AT_abstract_origin) {
95        match die_offset {
96            UnitRef(offset) => {
97                if let Ok(ndie) = unit.entry(offset) {
98                    return call_evaluate(dwarf, pc, expr, frame_base, unit, &ndie, registers, mem);
99                }
100            }
101            _ => {
102                error!("Unimplemented");
103                return Err(anyhow!("Unimplemented"));
104            }
105        };
106    }
107
108    error!("Unreachable");
109    Err(anyhow!("Unreachable"))
110}
111
112/// Will evaluate the value of the given DWARF expression.
113///
114/// Description:
115///
116/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
117/// * `unit` - A compilation unit which contains the given DIE.
118/// * `pc` - A machine code address, usually the current code location.
119/// * `expr` - The expression to be evaluated.
120/// * `frame_base` - The frame base address value.
121/// * `type_unit` - A compilation unit which contains the given DIE which represents the type of
122/// the given expression. None if the expression does not have a type.
123/// * `type_die` - The DIE the represents the type of the given expression. None if the expression
124/// does not have a type.
125/// * `registers` - A register struct for accessing the register values.
126/// * `mem` - A struct for accessing the memory of the debug target.
127///
128/// This function will first evaluate the expression into gimli-rs `Piece`s.
129/// Then it will use the pieces and the type too evaluate and parse the value.
130pub fn evaluate<R: Reader<Offset = usize>, T: MemoryAccess>(
131    dwarf: &Dwarf<R>,
132    unit: &Unit<R>,
133    pc: u32,
134    expr: Expression<R>,
135    frame_base: Option<u64>,
136    type_unit: Option<&gimli::Unit<R>>,
137    type_die: Option<&gimli::DebuggingInformationEntry<'_, '_, R>>,
138    registers: &Registers,
139    mem: &mut T,
140) -> Result<EvaluatorValue<R>> {
141    let pieces = evaluate_pieces(dwarf, unit, pc, expr, frame_base, registers, mem)?;
142    info!("Got pieces");
143    evaluate_value(dwarf, pieces, type_unit, type_die, registers, mem)
144}
145
146/// Will evaluate the value of the given list of gimli-rs `Piece`s.
147///
148/// Description:
149///
150/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
151/// * `pieces` - A list of gimli-rs pieces containing the location information..
152/// * `type_unit` - A compilation unit which contains the given DIE which represents the type of
153/// the given expression. None if the expression does not have a type.
154/// * `type_die` - The DIE the represents the type of the given expression. None if the expression
155/// does not have a type.
156/// * `registers` - A register struct for accessing the register values.
157/// * `mem` - A struct for accessing the memory of the debug target.
158///
159/// Then it will use the pieces and the type too evaluate and parse the value.
160pub fn evaluate_value<R: Reader<Offset = usize>, T: MemoryAccess>(
161    dwarf: &Dwarf<R>,
162    pieces: Vec<gimli::Piece<R>>,
163    type_unit: Option<&gimli::Unit<R>>,
164    type_die: Option<&gimli::DebuggingInformationEntry<'_, '_, R>>,
165    registers: &Registers,
166    mem: &mut T,
167) -> Result<EvaluatorValue<R>> {
168    match type_unit {
169        Some(unit) => match type_die {
170            Some(die) => {
171                info!("with type info");
172                return EvaluatorValue::evaluate_variable_with_type(
173                    dwarf,
174                    registers,
175                    mem,
176                    &pieces,
177                    unit.header.offset(),
178                    die.offset(),
179                );
180            }
181            None => (),
182        },
183        None => (),
184    };
185    info!("without type info");
186    EvaluatorValue::evaluate_variable(registers, mem, &pieces)
187}
188
189/// Evaluates a gimli-rs `Expression` into a `Vec` of `Piece`s.
190///
191/// Description:
192///
193/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
194/// * `unit` - A compilation unit which contains the given DIE.
195/// * `pc` - A machine code address, usually the current code location.
196/// * `expr` - The expression to be evaluated into `Piece`s.
197/// * `frame_base` - The frame base address value.
198/// * `registers` - A register struct for accessing the register values.
199/// * `mem` - A struct for accessing the memory of the debug target.
200///
201/// This function will evaluate the given expression into a list of pieces.
202/// These pieces describe the size and location of the variable the given expression is from.
203pub fn evaluate_pieces<R: Reader<Offset = usize>, T: MemoryAccess>(
204    dwarf: &Dwarf<R>,
205    unit: &Unit<R>,
206    pc: u32,
207    expr: Expression<R>,
208    frame_base: Option<u64>,
209    registers: &Registers,
210    mem: &mut T,
211) -> Result<Vec<gimli::Piece<R>>> {
212    let mut eval = expr.evaluation(unit.encoding());
213    let mut result = eval.evaluate()?;
214
215    loop {
216        match result {
217            Complete => break,
218            RequiresMemory {
219                address,
220                size,
221                space: _, // Do not know what this is used for.
222                base_type,
223            } => match mem.get_address(&(address as u32), size as usize) {
224                Some(data) => {
225                    let value = eval_base_type(unit, data, base_type)?;
226                    result = eval.resume_with_memory(convert_to_gimli_value(value))?;
227                }
228                None => {
229                    return Err(anyhow!("Requires Memory"));
230                }
231            },
232
233            RequiresRegister {
234                register,
235                base_type,
236            } => match registers.get_register_value(&register.0) {
237                Some(data) => {
238                    let bytes = data.to_le_bytes().to_vec();
239                    let value = eval_base_type(unit, bytes, base_type)?;
240                    result = eval.resume_with_register(convert_to_gimli_value(value))?;
241                }
242                None => {
243                    return Err(anyhow!("Requires register {}", register.0));
244                }
245            },
246
247            RequiresFrameBase => {
248                result = eval.resume_with_frame_base(match frame_base {
249                    Some(val) => val,
250                    None => {
251                        error!("Requires frame base");
252                        return Err(anyhow!("Requires frame base"));
253                    }
254                })?;
255            }
256
257            RequiresTls(_tls) => {
258                error!("Unimplemented");
259                return Err(anyhow!("Unimplemented")); // TODO
260            }
261
262            RequiresCallFrameCfa => {
263                result = eval.resume_with_call_frame_cfa(
264                    registers.cfa.ok_or_else(|| anyhow!("Requires CFA"))? as u64,
265                )?;
266            }
267
268            RequiresAtLocation(die_ref) => match die_ref {
269                DieReference::UnitRef(unit_offset) => help_at_location(
270                    dwarf,
271                    unit,
272                    pc,
273                    &mut eval,
274                    &mut result,
275                    frame_base,
276                    unit_offset,
277                    registers,
278                    mem,
279                )?,
280
281                DieReference::DebugInfoRef(debug_info_offset) => {
282                    let unit_header = dwarf.debug_info.header_from_offset(debug_info_offset)?;
283                    if let Some(unit_offset) = debug_info_offset.to_unit_offset(&unit_header) {
284                        let new_unit = dwarf.unit(unit_header)?;
285                        help_at_location(
286                            dwarf,
287                            &new_unit,
288                            pc,
289                            &mut eval,
290                            &mut result,
291                            frame_base,
292                            unit_offset,
293                            registers,
294                            mem,
295                        )?;
296                    } else {
297                        return Err(anyhow!("Could not find at location"));
298                    }
299                }
300            },
301
302            RequiresEntryValue(entry) => {
303                let entry_value = evaluate(
304                    dwarf, unit, pc, entry, frame_base, None, None, registers, mem,
305                )?;
306
307                result = eval.resume_with_entry_value(convert_to_gimli_value(match entry_value
308                    .to_value()
309                {
310                    Some(val) => val,
311                    None => {
312                        error!("Optimized Out");
313                        return Err(anyhow!("Optimized Out"));
314                    }
315                }))?;
316            }
317
318            RequiresParameterRef(unit_offset) => {
319                let die = unit.entry(unit_offset)?;
320                let call_value = match die.attr_value(gimli::DW_AT_call_value)? {
321                    Some(val) => val,
322                    None => {
323                        error!("Could not find required paramter");
324                        return Err(anyhow!("Could not find required parameter"));
325                    }
326                };
327
328                let expr = match call_value.exprloc_value() {
329                    Some(val) => val,
330                    None => {
331                        error!("Could not find required paramter");
332                        return Err(anyhow!("Could not find required parameter"));
333                    }
334                };
335                let value = evaluate(
336                    dwarf,
337                    unit,
338                    pc,
339                    expr,
340                    frame_base,
341                    Some(unit),
342                    Some(&die),
343                    registers,
344                    mem,
345                )?;
346
347                if let EvaluatorValue::Value(BaseTypeValue::U64(val), _) = value {
348                    result = eval.resume_with_parameter_ref(val)?;
349                } else {
350                    error!("Could not find required paramter");
351                    return Err(anyhow!("Could not find required parameter"));
352                }
353            }
354
355            RequiresRelocatedAddress(_num) => {
356                error!("Unimplemented");
357                return Err(anyhow!("Unimplemented"));
358                //                result = eval.resume_with_relocated_address(num)?; // TODO: Check and test if correct.
359            }
360
361            RequiresIndexedAddress {
362                index: _,
363                relocate: _,
364            } => {
365                // TODO: Check and test if correct. Also handle relocate flag
366                error!("Unimplemented");
367                return Err(anyhow!("Unimplemented"));
368                //                result = eval.resume_with_indexed_address(dwarf.address(unit, index)?)?;
369            }
370
371            RequiresBaseType(unit_offset) => {
372                let die = unit.entry(unit_offset)?;
373                let mut attrs = die.attrs();
374                while let Some(attr) = match attrs.next() {
375                    Ok(val) => val,
376                    Err(err) => {
377                        error!("{:?}", err);
378                        return Err(anyhow!("{:?}", err));
379                    }
380                } {
381                    println!("Attribute name = {:?}", attr.name());
382                    println!("Attribute value = {:?}", attr.value());
383                }
384
385                error!("Unimplemented");
386                return Err(anyhow!("Unimplemented"));
387            }
388        };
389    }
390
391    Ok(eval.result())
392}
393
394/// Will parse the value of a `DW_TAG_base_type`.
395///
396/// Description:
397///
398/// * `unit` - A compilation unit which contains the type DIE pointed to by the given offset.
399/// * `unit` - The value to parse in bytes.
400/// * `base_type` - A offset into the given compilation unit which points to a DIE with the tag
401/// `DW_TAG_base_type`.
402///
403/// This function will parse the given value into the type given by the offset `base_type`.
404fn eval_base_type<R>(
405    unit: &gimli::Unit<R>,
406    data: Vec<u8>,
407    base_type: gimli::UnitOffset<usize>,
408) -> Result<BaseTypeValue>
409where
410    R: Reader<Offset = usize>,
411{
412    if base_type.0 == 0 {
413        // NOTE: length can't be more then one word
414        let value = match data.len() {
415            0 => 0,
416            1 => u8::from_le_bytes(match data.try_into() {
417                Ok(val) => val,
418                Err(err) => {
419                    error!("{:?}", err);
420                    return Err(anyhow!("{:?}", err));
421                }
422            }) as u64,
423            2 => u16::from_le_bytes(match data.try_into() {
424                Ok(val) => val,
425                Err(err) => {
426                    error!("{:?}", err);
427                    return Err(anyhow!("{:?}", err));
428                }
429            }) as u64,
430            4 => u32::from_le_bytes(match data.try_into() {
431                Ok(val) => val,
432                Err(err) => {
433                    error!("{:?}", err);
434                    return Err(anyhow!("{:?}", err));
435                }
436            }) as u64,
437            8 => u64::from_le_bytes(match data.try_into() {
438                Ok(val) => val,
439                Err(err) => {
440                    error!("{:?}", err);
441                    return Err(anyhow!("{:?}", err));
442                }
443            }),
444            _ => {
445                error!("Unreachable");
446                return Err(anyhow!("Unreachable"));
447            }
448        };
449        return Ok(BaseTypeValue::Generic(value));
450    }
451    let die = unit.entry(base_type)?;
452
453    // I think that the die returned must be a base type tag.
454    if die.tag() != gimli::DW_TAG_base_type {
455        error!("Requires at the die has tag DW_TAG_base_type");
456        return Err(anyhow!("Requires at the die has tag DW_TAG_base_type"));
457    }
458
459    let encoding = match die.attr_value(gimli::DW_AT_encoding)? {
460        Some(gimli::AttributeValue::Encoding(dwate)) => dwate,
461        _ => {
462            error!("Expected base type die to have attribute DW_AT_encoding");
463            return Err(anyhow!(
464                "Expected base type die to have attribute DW_AT_encoding"
465            ));
466        }
467    };
468
469    BaseTypeValue::parse_base_type(data, encoding)
470}
471
472/// Will evaluate a value that is required when evaluating a expression into pieces.
473///
474/// Description:
475///
476/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
477/// * `unit` - A compilation unit which contains the given DIE.
478/// * `pc` - A machine code address, usually the current code location.
479/// * `eval` - A gimli-rs `Evaluation` that will be continued with the new value.
480/// * `result` - A gimli-rs `EvaluationResult` that will be updated with the new evaluation result.
481/// * `frame_base` - The frame base address value.
482/// * `unit_offset` - A offset to the DIE that will be evaluated and added to the given `Evaluation` struct.
483/// * `registers` - A register struct for accessing the register values.
484/// * `mem` - A struct for accessing the memory of the debug target.
485///
486/// This function is a helper function for continuing a `Piece` evaluation where another value
487/// needs to be evaluated first.
488fn help_at_location<R: Reader<Offset = usize>, T: MemoryAccess>(
489    dwarf: &Dwarf<R>,
490    unit: &Unit<R>,
491    pc: u32,
492    eval: &mut Evaluation<R>,
493    result: &mut EvaluationResult<R>,
494    frame_base: Option<u64>,
495    unit_offset: UnitOffset<usize>,
496    registers: &Registers,
497    mem: &mut T,
498) -> Result<()>
499where
500    R: Reader<Offset = usize>,
501{
502    let die = unit.entry(unit_offset)?;
503    let location = match die.attr_value(gimli::DW_AT_location)? {
504        Some(val) => val,
505        None => {
506            error!("Could not find location attribute");
507            return Err(anyhow!("Could not find location attribute"));
508        }
509    };
510    if let Some(expr) = location.exprloc_value() {
511        let val = call_evaluate(dwarf, pc, expr, frame_base, unit, &die, registers, mem)?;
512
513        if let EvaluatorValue::Bytes(b) = val {
514            *result = eval.resume_with_at_location(b)?;
515            Ok(())
516        } else {
517            error!("Error expected bytes");
518            Err(anyhow!("Error expected bytes"))
519        }
520    } else {
521        error!("die has no at location");
522        Err(anyhow!("die has no at location"))
523    }
524}