use super::*;
use anyhow::anyhow;
use gimli::{DebugInfoOffset, UnitOffset};
use num_traits::Zero;
use std::str::FromStr;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum VariantRole {
VariantPart(u64),
Variant(u64),
NonVariant,
}
impl Default for VariantRole {
fn default() -> Self {
VariantRole::NonVariant
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum VariableValue {
Valid(String),
Error(String),
Empty,
}
impl Default for VariableValue {
fn default() -> Self {
VariableValue::Empty
}
}
impl std::fmt::Display for VariableValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VariableValue::Valid(value) => value.fmt(f),
VariableValue::Error(error) => write!(f, "< {error} >",),
VariableValue::Empty => write!(
f,
"Value not set. Please use Variable::get_value() to infer a human readable variable value"
),
}
}
}
impl VariableValue {
pub fn is_valid(&self) -> bool {
!matches!(self, VariableValue::Error(_))
}
pub fn is_empty(&self) -> bool {
matches!(self, VariableValue::Empty)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum VariableName {
StaticScopeRoot,
RegistersRoot,
LocalScopeRoot,
PeripheralScopeRoot,
Artifical,
AnonymousNamespace,
Namespace(String),
Named(String),
Unknown,
}
impl Default for VariableName {
fn default() -> Self {
VariableName::Unknown
}
}
impl std::fmt::Display for VariableName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VariableName::StaticScopeRoot => write!(f, "Static Variable"),
VariableName::RegistersRoot => write!(f, "Platform Register"),
VariableName::LocalScopeRoot => write!(f, "Function Variable"),
VariableName::PeripheralScopeRoot => write!(f, "Peripheral Variable"),
VariableName::Artifical => write!(f, "<artifical>"),
VariableName::AnonymousNamespace => write!(f, "<anonymous_namespace>"),
VariableName::Namespace(name) => name.fmt(f),
VariableName::Named(name) => name.fmt(f),
VariableName::Unknown => write!(f, "<unknown>"),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum VariableNodeType {
ReferenceOffset(UnitOffset),
TypeOffset(UnitOffset),
DirectLookup,
DoNotRecurse,
RecurseToBaseType,
SvdPeripheral,
SvdRegister,
SvdField,
}
impl VariableNodeType {
pub fn is_deferred(&self) -> bool {
match self {
VariableNodeType::ReferenceOffset(_)
| VariableNodeType::TypeOffset(_)
| VariableNodeType::DirectLookup => true,
_other => false,
}
}
}
impl Default for VariableNodeType {
fn default() -> Self {
VariableNodeType::RecurseToBaseType
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariableType {
Base(String),
Struct(String),
Enum(String),
Namespace,
Pointer(Option<String>),
Array {
entry_type: VariableName,
count: usize,
},
Unknown,
Other(String),
}
impl Default for VariableType {
fn default() -> Self {
VariableType::Unknown
}
}
impl VariableType {
pub fn is_phantom_data(&self) -> bool {
match self {
VariableType::Struct(name) => name.starts_with("PhantomData"),
_ => false,
}
}
pub fn is_reference(&self) -> bool {
match self {
VariableType::Pointer(Some(name)) => name.starts_with('&'),
_ => false,
}
}
pub fn is_array(&self) -> bool {
matches!(self, VariableType::Array { .. })
}
}
impl std::fmt::Display for VariableType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VariableType::Base(base) => base.fmt(f),
VariableType::Struct(struct_name) => struct_name.fmt(f),
VariableType::Enum(enum_name) => enum_name.fmt(f),
VariableType::Namespace => "<namespace>".fmt(f),
VariableType::Pointer(pointer_name) => pointer_name
.clone()
.unwrap_or_else(|| "<unnamed>".to_string())
.fmt(f),
VariableType::Array { entry_type, count } => write!(f, "[{entry_type}; {count}]"),
VariableType::Unknown => "<unknown>".fmt(f),
VariableType::Other(other) => other.fmt(f),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariableLocation {
Unknown,
Unavailable,
Address(u64),
Value,
Error(String),
Unsupported(String),
}
impl VariableLocation {
pub fn memory_address(&self) -> Result<u64, DebugError> {
match self {
VariableLocation::Address(address) => Ok(*address),
other => Err(DebugError::UnwindIncompleteResults {
message: format!("Variable does not have a memory location: location={other:?}"),
}),
}
}
pub fn valid(&self) -> bool {
match self {
VariableLocation::Address(_) | VariableLocation::Value | VariableLocation::Unknown => {
true
}
_other => false,
}
}
}
impl std::fmt::Display for VariableLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VariableLocation::Unknown => "<unknown value>".fmt(f),
VariableLocation::Unavailable => "<value not available>".fmt(f),
VariableLocation::Address(address) => write!(f, "{address:#010X}"),
VariableLocation::Value => "<not applicable - statically stored value>".fmt(f),
VariableLocation::Error(error) => error.fmt(f),
VariableLocation::Unsupported(reason) => reason.fmt(f),
}
}
}
impl Default for VariableLocation {
fn default() -> Self {
VariableLocation::Unknown
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Variable {
pub variable_key: i64,
pub parent_key: Option<i64>,
pub name: VariableName,
value: VariableValue,
pub source_location: Option<SourceLocation>,
pub type_name: VariableType,
pub unit_header_offset: Option<DebugInfoOffset>,
pub variable_unit_offset: Option<UnitOffset>,
pub variable_node_type: VariableNodeType,
pub memory_location: VariableLocation,
pub byte_size: u64,
pub member_index: Option<i64>,
pub range_lower_bound: i64,
pub range_upper_bound: i64,
pub role: VariantRole,
}
impl Variable {
pub fn new(
header_offset: Option<DebugInfoOffset>,
entries_offset: Option<UnitOffset>,
) -> Variable {
Variable {
unit_header_offset: header_offset,
variable_unit_offset: entries_offset,
..Default::default()
}
}
pub fn set_value(&mut self, new_value: VariableValue) {
#[allow(clippy::if_same_then_else)]
if new_value.is_valid() {
self.value = new_value;
} else if self.value.is_valid() {
self.value = new_value;
} else {
self.value = VariableValue::Error(format!("{} : {}", self.value, new_value));
}
}
pub fn update_value(
&self,
core: &mut Core,
variable_cache: &mut variable_cache::VariableCache,
new_value: String,
) -> Result<String, DebugError> {
let variable_name = if let VariableName::Named(variable_name) = &self.name {
variable_name.clone()
} else {
String::new()
};
let updated_value = if !self.is_valid()
|| self.type_name == VariableType::Unknown
|| !self.memory_location.valid()
{
return Err(anyhow!(
"Cannot update variable: {:?}, with supplied information (value={:?}, type={:?}, memory location={:#010x?}).",
self.name, self.value, self.type_name, self.memory_location).into());
} else if variable_name.starts_with('*') {
return Err(anyhow!("Please only update variables with a base data type. Updating pointer variable types is not yet supported.").into());
} else {
let update_result = match &self.type_name {
VariableType::Base(name) => match name.as_str() {
"bool" => bool::update_value(self, core, new_value.as_str()),
"char" => char::update_value(self, core, new_value.as_str()),
"i8" => i8::update_value(self, core, new_value.as_str()),
"i16" => i16::update_value(self, core, new_value.as_str()),
"i32" => i32::update_value(self, core, new_value.as_str()),
"i64" => i64::update_value(self, core, new_value.as_str()),
"i128" => i128::update_value(self, core, new_value.as_str()),
"isize" => isize::update_value(self, core, new_value.as_str()),
"u8" => u8::update_value(self, core, new_value.as_str()),
"u16" => u16::update_value(self, core, new_value.as_str()),
"u32" => u32::update_value(self, core, new_value.as_str()),
"u64" => u64::update_value(self, core, new_value.as_str()),
"u128" => u128::update_value(self, core, new_value.as_str()),
"usize" => usize::update_value(self, core, new_value.as_str()),
"f32" => f32::update_value(self, core, new_value.as_str()),
"f64" => f64::update_value(self, core, new_value.as_str()),
other => Err(DebugError::UnwindIncompleteResults {
message: format!("Unsupported datatype: {other}. Please only update variables with a base data type."),
}),
},
other => Err(DebugError::UnwindIncompleteResults { message: format!("Unsupported variable type {other:?}. Only base variables can be updated.")}),
};
match update_result {
Ok(()) => {
let mut cache_variable = self.clone();
cache_variable.value = VariableValue::Valid(new_value.clone());
variable_cache.cache_variable(
cache_variable.parent_key,
cache_variable,
core,
)?;
new_value
}
Err(error) => {
return Err(DebugError::UnwindIncompleteResults {
message: format!("Invalid data value={new_value:?}: {error}"),
});
}
}
};
Ok(updated_value)
}
pub fn get_value(&self, variable_cache: &variable_cache::VariableCache) -> String {
#[allow(clippy::if_same_then_else)]
if VariableNodeType::SvdRegister == self.variable_node_type {
if let VariableValue::Valid(register_value) = &self.value {
if let Ok(register_u32_value) = register_value.parse::<u32>() {
format!(
"{:032b} @ {:#010X}",
register_u32_value,
self.memory_location.memory_address().unwrap_or(u64::MAX) )
} else {
format!("Invalid register value {register_value}")
}
} else {
format!("{}", self.value)
}
} else if VariableNodeType::SvdField == self.variable_node_type {
if let VariableValue::Valid(register_value) = &self.value {
if let Ok(register_u32_value) = register_value.parse::<u32>() {
let mut bit_value: u32 = register_u32_value;
bit_value <<= 32 - self.range_upper_bound;
bit_value >>= 32 - (self.range_upper_bound - self.range_lower_bound);
format!(
"{:0width$b} @ {:#010X}:{}..{}",
bit_value,
self.memory_location.memory_address().unwrap_or(u64::MAX),
self.range_lower_bound,
self.range_upper_bound,
width = (self.range_upper_bound - self.range_lower_bound) as usize
)
} else {
format!(
"Invalid bit range {}..{} from value {}",
self.range_lower_bound, self.range_upper_bound, register_value
)
}
} else {
format!("{}", self.value)
}
} else if !self.value.is_empty() {
format!("{}", self.value)
} else if let VariableName::AnonymousNamespace = self.name {
String::new()
} else if let VariableName::Namespace(_) = self.name {
String::new()
} else {
match variable_cache.has_children(self) {
Ok(has_children) => {
if has_children {
self.formatted_variable_value(variable_cache, 0_usize, false)
} else if self.type_name == VariableType::Unknown
|| !self.memory_location.valid()
{
if self.variable_node_type.is_deferred() {
format!("{:?}", self.type_name.clone())
} else {
"Error: This is a bug! Attempted to evaluate a Variable with no type or no memory location".to_string()
}
} else if self.type_name == VariableType::Struct("None".to_string()) {
"None".to_string()
} else {
format!(
"Unimplemented: Evaluate type {:?} of ({} bytes) at location 0x{:08x?}",
self.type_name, self.byte_size, self.memory_location
)
}
}
Err(error) => format!(
"Failed to determine children for `Variable`:{}. {:?}",
self.name, error
),
}
}
}
pub fn extract_value(
&mut self,
core: &mut Core<'_>,
variable_cache: &variable_cache::VariableCache,
) {
if let VariableValue::Error(_) = self.value {
return;
} else if self.variable_node_type == VariableNodeType::SvdRegister
|| self.variable_node_type == VariableNodeType::SvdField
{
match core.read_word_32(self.memory_location.memory_address().unwrap_or(u64::MAX)) {
Ok(u32_value) => self.value = VariableValue::Valid(u32_value.to_le().to_string()),
Err(error) => {
self.value = VariableValue::Error(format!(
"Unable to read peripheral register value @ {:#010X} : {:?}",
self.memory_location.memory_address().unwrap_or(u64::MAX),
error
))
}
}
return;
} else if !self.value.is_empty()
|| !self.memory_location.valid()
|| self.type_name == VariableType::Unknown
{
return;
} else if self.variable_node_type.is_deferred() {
self.value =
VariableValue::Valid(format!("{} @ {}", self.type_name, self.memory_location));
return;
}
tracing::trace!(
"Extracting value for {:?}, type={:?}",
self.name,
self.type_name
);
let known_value = match &self.type_name {
VariableType::Base(name) => {
if self.memory_location == VariableLocation::Unknown {
self.value = VariableValue::Empty;
return;
}
match name.as_str() {
"!" => VariableValue::Valid("<Never returns>".to_string()),
"()" => VariableValue::Valid("()".to_string()),
"bool" => bool::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"char" => char::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"i8" => i8::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"i16" => i16::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"i32" => i32::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"i64" => i64::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"i128" => i128::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"isize" => isize::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"u8" => u8::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"u16" => u16::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"u32" => u32::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"u64" => u64::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"u128" => u128::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"usize" => usize::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"f32" => f32::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"f64" => f64::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
|value| VariableValue::Valid(value.to_string()),
),
"None" => VariableValue::Valid("None".to_string()),
_undetermined_value => VariableValue::Empty,
}
}
VariableType::Struct(name) if name == "&str" => {
String::get_value(self, core, variable_cache).map_or_else(
|err| VariableValue::Error(format!("{err:?}")),
VariableValue::Valid,
)
}
_other => VariableValue::Empty,
};
self.value = known_value;
}
pub fn is_indexed(&self) -> bool {
match &self.name {
VariableName::Named(name) => {
name.starts_with("__")
&& name
.find(char::is_numeric)
.map_or(false, |zero_based_position| zero_based_position == 2)
}
_ => false,
}
}
pub fn is_valid(&self) -> bool {
self.value.is_valid()
}
fn formatted_variable_value(
&self,
variable_cache: &variable_cache::VariableCache,
indentation: usize,
show_name: bool,
) -> String {
let line_feed = if indentation.is_zero() { "" } else { "\n" }.to_string();
#[allow(clippy::if_same_then_else)]
if !self.value.is_empty() {
if show_name {
format!(
"{}{:\t<indentation$}{}: {} = {}",
line_feed, "", self.name, self.type_name, self.value
)
} else {
format!("{}{:\t<indentation$}{}", line_feed, "", self.value)
}
} else if let VariableName::AnonymousNamespace = self.name {
String::new()
} else if let VariableName::Namespace(_) = self.name {
String::new()
} else {
let mut compound_value = String::new();
if let Ok(children) = variable_cache.get_children(Some(self.variable_key)) {
match &self.type_name {
VariableType::Pointer(_) => {
compound_value = format!(
"{}{}{:\t<indentation$}{}",
compound_value,
line_feed,
"",
if let Some(first_child) = children.first() {
first_child.formatted_variable_value(
variable_cache,
indentation + 1,
true,
)
} else {
"Unable to resolve referenced variable value".to_string()
}
);
compound_value
}
VariableType::Array { .. } => {
compound_value = format!(
"{}{}{:\t<indentation$}{}: {} = [",
compound_value,
line_feed,
"",
self.name,
self.type_name,
);
let mut child_count: usize = 0;
for child in children.iter() {
child_count += 1;
if child_count == children.len() {
compound_value = format!(
"{}{}",
compound_value,
child.formatted_variable_value(
variable_cache,
indentation + 1,
false
)
);
} else {
compound_value = format!(
"{}{}, ",
compound_value,
child.formatted_variable_value(
variable_cache,
indentation + 1,
false
)
);
}
}
format!("{}{}{:\t<indentation$}]", compound_value, line_feed, "")
}
VariableType::Struct(name)
if name.starts_with("Ok")
|| name.starts_with("Err") =>
{
compound_value = format!(
"{}{:\t<indentation$}{}: {} = {}(",
line_feed,
"",
self.name,
self.type_name,
compound_value
);
for child in children {
compound_value = format!(
"{}{}",
compound_value,
child.formatted_variable_value(
variable_cache,
indentation + 1,
false
)
);
}
format!("{}{}{:\t<indentation$})", compound_value, line_feed, "")
}
_ => {
if children.is_empty() {
format!("{}{:\t<indentation$}{}", line_feed, "", self.name)
} else {
let (mut pre_fix, mut post_fix): (Option<String>, Option<String>) =
(None, None);
let mut child_count: usize = 0;
let mut is_tuple = false;
for child in children.iter() {
child_count += 1;
if pre_fix.is_none() && post_fix.is_none() {
if let VariableName::Named(child_name) = &child.name {
if child_name.starts_with("__0") {
is_tuple = true;
pre_fix = Some(format!(
"{}{:\t<indentation$}{}: {}({}) = {}(",
line_feed,
"",
self.name,
self.type_name,
child.type_name,
self.type_name,
));
post_fix =
Some(format!("{}{:\t<indentation$})", line_feed, ""));
} else {
if show_name {
pre_fix = Some(format!(
"{}{:\t<indentation$}{}: {} = {} {{",
line_feed,
"",
self.name,
self.type_name,
self.type_name,
));
} else {
pre_fix = Some(format!(
"{}{:\t<indentation$}{} {{",
line_feed,
"",
self.type_name,
));
}
post_fix =
Some(format!("{}{:\t<indentation$}}}", line_feed, ""));
}
};
if let Some(pre_fix) = &pre_fix {
compound_value = format!("{compound_value}{pre_fix}");
};
}
let print_name = !is_tuple;
if child_count == children.len() {
compound_value = format!(
"{}{}",
compound_value,
child.formatted_variable_value(
variable_cache,
indentation + 1,
print_name
)
);
} else {
compound_value = format!(
"{}{}, ",
compound_value,
child.formatted_variable_value(
variable_cache,
indentation + 1,
print_name
)
);
}
}
if let Some(post_fix) = &post_fix {
compound_value = format!("{compound_value}{post_fix}");
};
compound_value
}
}
}
} else {
format!("{:\t<indentation$}{}", "", self.type_name)
}
}
}
}
trait Value {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError>
where
Self: Sized;
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError>;
}
impl Value for bool {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mem_data = core.read_word_8(variable.memory_location.memory_address()?)?;
let ret_value: bool = mem_data != 0;
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
core.write_word_8(
variable.memory_location.memory_address()?,
<bool as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})? as u8,
)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for char {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mem_data = core.read_word_32(variable.memory_location.memory_address()?)?;
if let Some(return_value) = char::from_u32(mem_data) {
Ok(return_value)
} else {
Ok('?')
}
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
core.write_word_32(
variable.memory_location.memory_address()?,
<char as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})? as u32,
)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for String {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut str_value: String = "".to_owned();
if let Ok(children) = variable_cache.get_children(Some(variable.variable_key)) {
if !children.is_empty() {
let mut string_length = match children.iter().find(|child_variable| {
child_variable.name == VariableName::Named("length".to_string())
}) {
Some(string_length) => {
if let VariableValue::Valid(length_value) = &string_length.value {
length_value.parse().unwrap_or(0_usize)
} else {
0_usize
}
}
None => 0_usize,
};
let string_location = match children.iter().find(|child_variable| {
child_variable.name == VariableName::Named("data_ptr".to_string())
}) {
Some(location_value) => {
if let Ok(child_variables) =
variable_cache.get_children(Some(location_value.variable_key))
{
if let Some(first_child) = child_variables.first() {
first_child.memory_location.memory_address()?
} else {
0_u64
}
} else {
0_u64
}
}
None => 0_u64,
};
if string_location.is_zero() {
str_value = "Error: Failed to determine &str memory location".to_string();
} else {
if string_length > 200 {
tracing::warn!(
"Very long string ({} bytes), truncating to 200 bytes.",
string_length
);
string_length = 200;
}
if string_length.is_zero() {
} else {
let mut buff = vec![0u8; string_length];
core.read(string_location, &mut buff)?;
str_value = core::str::from_utf8(&buff)?.to_owned();
}
}
} else {
str_value = "Error: Failed to evaluate &str value".to_string();
}
};
Ok(str_value)
}
fn update_value(
_variable: &Variable,
_core: &mut Core<'_>,
_new_value: &str,
) -> Result<(), DebugError> {
Err(DebugError::UnwindIncompleteResults { message:"Unsupported datatype: \"String\". Please only update variables with a base data type.".to_string()})
}
}
impl Value for i8 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 1];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i8::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
core.write_word_8(
variable.memory_location.memory_address()?,
<i8 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})? as u8,
)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for i16 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 2];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i16::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = i16::to_le_bytes(<i16 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for i32 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 4];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i32::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = i32::to_le_bytes(<i32 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for i64 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 8];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i64::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = i64::to_le_bytes(<i64 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for i128 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 16];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i128::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = i128::to_le_bytes(<i128 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for isize {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 4];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = i32::from_le_bytes(buff);
Ok(ret_value as isize)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff =
isize::to_le_bytes(<isize as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for u8 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 1];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u8::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
core.write_word_8(
variable.memory_location.memory_address()?,
<u8 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})?,
)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for u16 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 2];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u16::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = u16::to_le_bytes(<u16 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for u32 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 4];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u32::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = u32::to_le_bytes(<u32 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for u64 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 8];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u64::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = u64::to_le_bytes(<u64 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for u128 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 16];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u128::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = u128::to_le_bytes(<u128 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for usize {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 4];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = u32::from_le_bytes(buff);
Ok(ret_value as usize)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff =
usize::to_le_bytes(<usize as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!(
"Invalid data conversion from value: {new_value:?}. {error:?}"
),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for f32 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 4];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = f32::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = f32::to_le_bytes(<f32 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}
impl Value for f64 {
fn get_value(
variable: &Variable,
core: &mut Core<'_>,
_variable_cache: &variable_cache::VariableCache,
) -> Result<Self, DebugError> {
let mut buff = [0u8; 8];
core.read(variable.memory_location.memory_address()?, &mut buff)?;
let ret_value = f64::from_le_bytes(buff);
Ok(ret_value)
}
fn update_value(
variable: &Variable,
core: &mut Core<'_>,
new_value: &str,
) -> Result<(), DebugError> {
let buff = f64::to_le_bytes(<f64 as FromStr>::from_str(new_value).map_err(|error| {
DebugError::UnwindIncompleteResults {
message: format!("Invalid data conversion from value: {new_value:?}. {error:?}"),
}
})?);
core.write_8(variable.memory_location.memory_address()?, &buff)
.map_err(|error| DebugError::UnwindIncompleteResults {
message: format!("{error:?}"),
})
}
}