probe_rs_debug/language/
c.rs

1use probe_rs::MemoryInterface;
2
3use crate::{
4    Bitfield, DebugError, Variable, VariableCache, VariableLocation, VariableName, VariableType,
5    VariableValue,
6    language::{
7        ProgrammingLanguage,
8        value::{Value, format_float},
9    },
10};
11use std::fmt::{Display, Write};
12
13#[derive(Debug, Clone)]
14pub struct C;
15
16impl ProgrammingLanguage for C {
17    fn read_variable_value(
18        &self,
19        variable: &Variable,
20        memory: &mut dyn MemoryInterface,
21        variable_cache: &VariableCache,
22    ) -> VariableValue {
23        match variable.type_name.inner() {
24            _ if variable.memory_location == VariableLocation::Unknown => VariableValue::Empty,
25
26            VariableType::Base(name) => match name.as_str() {
27                "_Bool" => UnsignedInt::get_value(variable, None, memory, variable_cache).into(),
28                "char" => CChar::get_value(variable, memory, variable_cache).into(),
29
30                "unsigned char"
31                | "unsigned int"
32                | "short unsigned int"
33                | "long unsigned int"
34                | "long long unsigned int" => {
35                    UnsignedInt::get_value(variable, None, memory, variable_cache).into()
36                }
37                "signed char"
38                | "int"
39                | "short int"
40                | "long int"
41                | "long long int"
42                | "signed int"
43                | "short signed int"
44                | "long signed int"
45                | "long long signed int" => {
46                    SignedInt::get_value(variable, None, memory, variable_cache).into()
47                }
48
49                "float" => match variable.byte_size {
50                    Some(4) | None => f32::get_value(variable, memory, variable_cache)
51                        .map(|f| format_float(f as f64))
52                        .into(),
53                    Some(size) => {
54                        VariableValue::Error(format!("Invalid byte size for float: {size}"))
55                    }
56                },
57                "double" => match variable.byte_size {
58                    Some(8) | None => f64::get_value(variable, memory, variable_cache)
59                        .map(format_float)
60                        .into(),
61                    Some(size) => {
62                        VariableValue::Error(format!("Invalid byte size for double: {size}"))
63                    }
64                },
65                _undetermined_value => VariableValue::Empty,
66            },
67
68            VariableType::Bitfield(bitfield, name) => match name.inner() {
69                VariableType::Base(name) => {
70                    if name.as_str().contains("unsigned") {
71                        UnsignedInt::get_value(variable, Some(*bitfield), memory, variable_cache)
72                            .into()
73                    } else {
74                        SignedInt::get_value(variable, Some(*bitfield), memory, variable_cache)
75                            .into()
76                    }
77                }
78
79                _undetermined_value => VariableValue::Empty,
80            },
81
82            _other => VariableValue::Empty,
83        }
84    }
85
86    fn update_variable(
87        &self,
88        variable: &Variable,
89        memory: &mut dyn MemoryInterface,
90        new_value: &str,
91    ) -> Result<(), DebugError> {
92        match variable.type_name.inner() {
93            VariableType::Base(name) => match name.as_str() {
94                "_Bool" => UnsignedInt::update_value(variable, None, memory, new_value),
95                "char" => CChar::update_value(variable, memory, new_value),
96                "unsigned char" | "unsigned int" | "short unsigned int" | "long unsigned int" => {
97                    UnsignedInt::update_value(variable, None, memory, new_value)
98                }
99                "signed char" | "int" | "short int" | "long int" | "signed int"
100                | "short signed int" | "long signed int" => {
101                    SignedInt::update_value(variable, None, memory, new_value)
102                }
103                "float" => f32::update_value(variable, memory, new_value),
104                // TODO: doubles
105                other => Err(DebugError::WarnAndContinue {
106                    message: format!("Updating {other} variables is not yet supported."),
107                }),
108            },
109
110            VariableType::Bitfield(bitfield, name) => match name.inner() {
111                VariableType::Base(name) => {
112                    if name.as_str().contains("unsigned") {
113                        UnsignedInt::update_value(variable, Some(*bitfield), memory, new_value)
114                    } else {
115                        SignedInt::update_value(variable, Some(*bitfield), memory, new_value)
116                    }
117                }
118
119                other => Err(DebugError::WarnAndContinue {
120                    message: format!(
121                        "Updating {} bitfield variables is not yet supported.",
122                        other.kind()
123                    ),
124                }),
125            },
126
127            other => Err(DebugError::WarnAndContinue {
128                message: format!("Updating {} variables is not yet supported.", other.kind()),
129            }),
130        }
131    }
132
133    fn format_array_type(&self, item_type: &str, length: usize) -> String {
134        format!("{item_type}[{length}]")
135    }
136
137    fn format_enum_value(&self, _type_name: &VariableType, value: &VariableName) -> VariableValue {
138        VariableValue::Valid(value.to_string())
139    }
140
141    fn format_pointer_type(&self, pointee: Option<&str>) -> String {
142        format!("{}*", pointee.unwrap_or("void"))
143    }
144
145    fn process_tag_with_no_type(&self, variable: &Variable, tag: gimli::DwTag) -> VariableValue {
146        match tag {
147            gimli::DW_TAG_const_type => VariableValue::Valid("const void".to_string()),
148            gimli::DW_TAG_pointer_type => {
149                let name = if let VariableLocation::Address(addr) = variable.memory_location {
150                    format!("void* @ {addr:X}")
151                } else {
152                    "void*".to_string()
153                };
154
155                VariableValue::Valid(name)
156            }
157            _ => VariableValue::Error(format!("Error: Failed to decode {tag} type reference")),
158        }
159    }
160}
161
162struct CChar(u8);
163
164impl Display for CChar {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        let c = self.0;
167        if c.is_ascii() {
168            f.write_char(c as char)
169        } else {
170            f.write_fmt(format_args!("\\x{c:02x}"))
171        }
172    }
173}
174
175impl Value for CChar {
176    fn get_value(
177        variable: &Variable,
178        memory: &mut dyn MemoryInterface,
179        _variable_cache: &VariableCache,
180    ) -> Result<Self, DebugError>
181    where
182        Self: Sized,
183    {
184        let buff = u8::get_value(variable, memory, _variable_cache)?;
185
186        Ok(Self(buff))
187    }
188
189    fn update_value(
190        variable: &Variable,
191        memory: &mut dyn MemoryInterface,
192        new_value: &str,
193    ) -> Result<(), DebugError> {
194        fn input_error(value: &str) -> DebugError {
195            DebugError::WarnAndContinue {
196                message: format!(
197                    "Invalid value for char: {value}. Please provide a single character."
198                ),
199            }
200        }
201
202        // TODO: what do we want to support here exactly? This is now symmetrical with get_value
203        // but we could be somewhat smarter, too.
204        let new_value = if new_value.len() == 1 && new_value.is_ascii() {
205            new_value.as_bytes()[0]
206        } else if new_value.starts_with("\\x") && [3, 4].contains(&new_value.len()) {
207            u8::from_str_radix(&new_value[2..], 16).map_err(|_| input_error(new_value))?
208        } else {
209            return Err(input_error(new_value));
210        };
211
212        memory.write_word_8(variable.memory_location.memory_address()?, new_value)?;
213
214        Ok(())
215    }
216}
217
218struct UnsignedInt(u128);
219
220impl Display for UnsignedInt {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        f.write_fmt(format_args!("{}", self.0))
223    }
224}
225
226impl UnsignedInt {
227    fn get_value(
228        variable: &Variable,
229        bitfield: Option<Bitfield>,
230        memory: &mut dyn MemoryInterface,
231        _variable_cache: &VariableCache,
232    ) -> Result<Self, DebugError>
233    where
234        Self: Sized,
235    {
236        // Read the bits. The actual count is encoded in the variable type.
237        let mut buff = [0u8; 16];
238        let bytes = variable.byte_size.unwrap_or(1).min(16) as usize;
239        if let VariableLocation::RegisterValue(value) = variable.memory_location {
240            // The value is in a register, we just need to extract the bytes.
241            let reg_bytes = TryInto::<u128>::try_into(value)?.to_le_bytes();
242
243            buff[..bytes].copy_from_slice(&reg_bytes[..bytes]);
244        } else {
245            // We only have an address, we need to read the value from memory.
246            memory.read(
247                variable.memory_location.memory_address()?,
248                &mut buff[..bytes],
249            )?;
250        }
251
252        let value = u128::from_le_bytes(buff);
253
254        // Extract bitfield bits
255        let value = match bitfield {
256            Some(bitfield) => bitfield.extract(value),
257            None => value,
258        };
259
260        Ok(Self(value))
261    }
262
263    fn update_value(
264        variable: &Variable,
265        bitfield: Option<Bitfield>,
266        memory: &mut dyn MemoryInterface,
267        new_value: &str,
268    ) -> Result<(), DebugError> {
269        match parse_int::parse::<u128>(new_value) {
270            Ok(value) => write_unsigned_bytes(variable, bitfield, memory, value),
271            Err(e) => Err(DebugError::WarnAndContinue {
272                message: format!("Invalid data conversion from value: {new_value:?}. {e:?}"),
273            }),
274        }
275    }
276}
277
278fn write_unsigned_bytes(
279    variable: &Variable,
280    bitfield: Option<Bitfield>,
281    memory: &mut dyn MemoryInterface,
282    unsigned: u128,
283) -> Result<(), DebugError> {
284    // TODO: check that value actually fits into `bytes` number of bytes
285    let bytes = variable.byte_size.unwrap_or(1) as usize;
286
287    // Figure out the bitfield offset & bit count
288    let Some(bitfield) = bitfield else {
289        let buff = unsigned.to_le_bytes();
290        memory.write_8(variable.memory_location.memory_address()?, &buff[..bytes])?;
291        return Ok(());
292    };
293
294    // We are writing a bitfield, we need to do a read-modify-write operation.
295
296    // Read the bits
297    let mut buff = [0u8; 16];
298    memory.read(
299        variable.memory_location.memory_address()?,
300        &mut buff[..bytes],
301    )?;
302    let read_value = u128::from_le_bytes(buff);
303
304    let new_value = bitfield.insert(read_value, unsigned);
305
306    // Write the new value
307    let buff = new_value.to_le_bytes();
308    memory.write_8(variable.memory_location.memory_address()?, &buff[..bytes])?;
309
310    Ok(())
311}
312
313struct SignedInt(i128);
314
315impl Display for SignedInt {
316    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317        f.write_fmt(format_args!("{}", self.0))
318    }
319}
320
321impl SignedInt {
322    fn get_value(
323        variable: &Variable,
324        bitfield: Option<Bitfield>,
325        memory: &mut dyn MemoryInterface,
326        variable_cache: &VariableCache,
327    ) -> Result<Self, DebugError>
328    where
329        Self: Sized,
330    {
331        // We read the number as Unsigned first, to avoid duplicating the bitfield handling.
332        let unsigned = UnsignedInt::get_value(variable, bitfield, memory, variable_cache)?.0;
333        let bytes = variable.byte_size.unwrap_or(1).min(16) as usize;
334
335        // Sign extend
336        let sign_bit_shift = match bitfield {
337            Some(bitfield) => bitfield.length() as usize - 1,
338            None => (bytes * 8) - 1,
339        };
340
341        let negative = unsigned & (1 << sign_bit_shift) != 0;
342        let value = if negative {
343            (unsigned | (!0 << sign_bit_shift)) as i128
344        } else {
345            unsigned as i128
346        };
347
348        Ok(Self(value))
349    }
350
351    fn update_value(
352        variable: &Variable,
353        bitfield: Option<Bitfield>,
354        memory: &mut dyn MemoryInterface,
355        new_value: &str,
356    ) -> Result<(), DebugError> {
357        match parse_int::parse::<i128>(new_value) {
358            Ok(value) => write_unsigned_bytes(variable, bitfield, memory, value as u128),
359            Err(e) => Err(DebugError::WarnAndContinue {
360                message: format!("Invalid data conversion from value: {new_value:?}. {e:?}"),
361            }),
362        }
363    }
364}
365
366impl From<Result<UnsignedInt, DebugError>> for VariableValue {
367    fn from(val: Result<UnsignedInt, DebugError>) -> Self {
368        val.map_or_else(
369            |err| VariableValue::Error(format!("{err:?}")),
370            |value| VariableValue::Valid(value.to_string()),
371        )
372    }
373}
374
375impl From<Result<SignedInt, DebugError>> for VariableValue {
376    fn from(val: Result<SignedInt, DebugError>) -> Self {
377        val.map_or_else(
378            |err| VariableValue::Error(format!("{err:?}")),
379            |value| VariableValue::Valid(value.to_string()),
380        )
381    }
382}