use crate::debugger::debugee::dwarf::r#type::{TypeId, TypeIdentity};
use crate::debugger::variable::ObjectBinaryRepr;
use crate::debugger::variable::render::RenderValue;
use crate::debugger::variable::value::AssumeError::{
TypeParameterNotFound, TypeParameterTypeNotFound, UnexpectedType,
};
use crate::debugger::variable::value::ParsingError::Assume;
use crate::debugger::variable::value::parser::{ParseContext, ValueParser};
use crate::debugger::variable::value::specialization::btree::BTreeReflection;
use crate::debugger::variable::value::specialization::hashbrown::HashmapReflection;
use crate::debugger::variable::value::{
ArrayItem, ArrayValue, AssumeError, FieldOrIndex, Member, ParsingError, ScalarValue,
SupportedScalar,
};
use crate::debugger::variable::value::{PointerValue, StructValue, Value};
use crate::version::RustVersion;
use crate::{debugger, version_switch, weak_error};
use AssumeError::{FieldNotFound, IncompleteInterp, UnknownSize};
use anyhow::Context;
use bytes::Bytes;
use fallible_iterator::FallibleIterator;
use indexmap::IndexMap;
mod btree;
mod hashbrown;
const LEN_GUARD: i64 = 10_000;
const CAP_GUARD: i64 = 10_000;
fn guard_len(len: i64) -> i64 {
if len > LEN_GUARD { LEN_GUARD } else { len }
}
fn guard_cap(cap: i64) -> i64 {
if cap > CAP_GUARD { CAP_GUARD } else { cap }
}
#[derive(Clone, PartialEq)]
pub struct VecValue {
pub structure: StructValue,
}
impl VecValue {
pub fn slice(&mut self, left: Option<usize>, right: Option<usize>) {
debug_assert!(matches!(
self.structure.members.get_mut(0).map(|m| &m.value),
Some(Value::Array(_))
));
if let Some(Member {
value: Value::Array(array),
..
}) = self.structure.members.get_mut(0)
{
array.slice(left, right);
}
}
}
#[derive(Clone, PartialEq)]
pub struct StringVariable {
pub value: String,
}
#[derive(Clone, PartialEq)]
pub struct HashMapVariable {
pub type_ident: TypeIdentity,
pub kv_items: Vec<(Value, Value)>,
}
#[derive(Clone, PartialEq)]
pub struct HashSetVariable {
pub type_ident: TypeIdentity,
pub items: Vec<Value>,
}
#[derive(Clone, PartialEq)]
pub struct StrVariable {
pub value: String,
}
#[derive(Clone, PartialEq)]
pub struct TlsVariable {
pub inner_value: Option<Box<Value>>,
pub inner_type: TypeIdentity,
}
#[derive(Clone, PartialEq)]
pub enum SpecializedValue {
Vector(VecValue),
VecDeque(VecValue),
HashMap(HashMapVariable),
HashSet(HashSetVariable),
BTreeMap(HashMapVariable),
BTreeSet(HashSetVariable),
String(StringVariable),
Str(StrVariable),
Tls(TlsVariable),
Cell(Box<Value>),
RefCell(Box<Value>),
Rc(PointerValue),
Arc(PointerValue),
Uuid([u8; 16]),
SystemTime((i64, u32)),
Instant((i64, u32)),
}
pub struct VariableParserExtension<'a> {
parser: &'a ValueParser,
}
impl<'a> VariableParserExtension<'a> {
pub fn new(parser: &'a ValueParser) -> Self {
Self { parser }
}
pub fn parse_str(
&self,
pcx: &ParseContext,
structure: &StructValue,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_str_inner(pcx, Value::Struct(structure.clone()))
.context("&str interpretation")
)
.map(SpecializedValue::Str)
}
fn parse_str_inner(&self, pcx: &ParseContext, val: Value) -> Result<StrVariable, ParsingError> {
let len = val.assume_field_as_scalar_number("length")?;
let len = guard_len(len);
let data_ptr = val.assume_field_as_pointer("data_ptr")?;
let data = debugger::read_memory_by_pid(
pcx.evcx.ecx.pid_on_focus(),
data_ptr as usize,
len as usize,
)
.map(Bytes::from)?;
Ok(StrVariable {
value: String::from_utf8(data.to_vec()).map_err(AssumeError::from)?,
})
}
pub fn parse_string(
&self,
pcx: &ParseContext,
structure: &StructValue,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_string_inner(pcx, Value::Struct(structure.clone()))
.context("String interpretation")
)
.map(SpecializedValue::String)
}
fn parse_string_inner(
&self,
pcx: &ParseContext,
val: Value,
) -> Result<StringVariable, ParsingError> {
let len = val.assume_field_as_scalar_number("len")?;
let len = guard_len(len);
let data_ptr = val.assume_field_as_pointer("pointer")?;
let data = debugger::read_memory_by_pid(
pcx.evcx.ecx.pid_on_focus(),
data_ptr as usize,
len as usize,
)?;
Ok(StringVariable {
value: String::from_utf8(data).map_err(AssumeError::from)?,
})
}
pub fn parse_vector(
&self,
pcx: &ParseContext,
structure: &StructValue,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_vector_inner(pcx, Value::Struct(structure.clone()), type_params)
.context("Vec<T> interpretation")
)
.map(SpecializedValue::Vector)
}
fn parse_vector_inner(
&self,
pcx: &ParseContext,
val: Value,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<VecValue, ParsingError> {
let inner_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let len = val.assume_field_as_scalar_number("len")?;
let len = guard_len(len);
let cap = extract_capacity(pcx, &val)? as i64;
let cap = guard_cap(cap);
let data_ptr = val.assume_field_as_pointer("pointer")? as usize;
let el_type = pcx.type_graph;
let el_type_size = el_type
.type_size_in_bytes(pcx.evcx, inner_type)
.ok_or(UnknownSize(el_type.identity(inner_type)))? as usize;
let raw_data = debugger::read_memory_by_pid(
pcx.evcx.ecx.pid_on_focus(),
data_ptr,
len as usize * el_type_size,
)
.map(Bytes::from)?;
let (mut bytes_chunks, mut empty_chunks);
let raw_items_iter: &mut dyn Iterator<Item = (usize, &[u8])> = if el_type_size != 0 {
bytes_chunks = raw_data.chunks(el_type_size).enumerate();
&mut bytes_chunks
} else {
let v: Vec<&[u8]> = vec![&[]; len as usize];
empty_chunks = v.into_iter().enumerate();
&mut empty_chunks
};
let items = raw_items_iter
.filter_map(|(i, chunk)| {
let data = ObjectBinaryRepr {
raw_data: raw_data.slice_ref(chunk),
address: Some(data_ptr + (i * el_type_size)),
size: el_type_size,
};
Some(ArrayItem {
index: i as i64,
value: self.parser.parse_inner(pcx, Some(data), inner_type)?,
})
})
.collect::<Vec<_>>();
Ok(VecValue {
structure: StructValue {
type_id: None,
type_ident: val.r#type().clone(),
members: vec![
Member {
field_name: Some("buf".to_owned()),
value: Value::Array(ArrayValue {
type_id: None,
type_ident: pcx.type_graph.identity(inner_type).as_array_type(),
items: Some(items),
raw_address: None,
}),
},
Member {
field_name: Some("cap".to_owned()),
value: Value::Scalar(ScalarValue {
type_id: None,
type_ident: TypeIdentity::no_namespace("usize"),
value: Some(SupportedScalar::Usize(cap as usize)),
raw_address: None,
}),
},
],
type_params: type_params.clone(),
raw_address: None,
},
})
}
pub fn parse_tls_old(
&self,
pcx: &ParseContext,
structure: &StructValue,
type_params: &IndexMap<String, Option<TypeId>>,
is_const_initialized: bool,
) -> Option<SpecializedValue> {
let tls_var = if is_const_initialized {
self.parse_const_init_tls_inner(pcx, Value::Struct(structure.clone()), type_params)
} else {
self.parse_tls_inner_old(pcx, Value::Struct(structure.clone()), type_params)
};
weak_error!(tls_var.context("TLS variable interpretation")).map(SpecializedValue::Tls)
}
fn parse_const_init_tls_inner(
&self,
pcx: &ParseContext,
inner: Value,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<TlsVariable, ParsingError> {
let value_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let value = inner.field("value");
Ok(TlsVariable {
inner_value: value.map(Box::new),
inner_type: pcx.type_graph.identity(value_type),
})
}
fn parse_tls_inner_old(
&self,
pcx: &ParseContext,
inner_val: Value,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<TlsVariable, ParsingError> {
let inner_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let inner = inner_val
.bfs_iterator()
.find_map(|(field, child)| {
(field == FieldOrIndex::Field(Some("inner"))).then_some(child)
})
.ok_or(FieldNotFound("inner"))?;
let inner_option = inner.assume_field_as_rust_enum("value")?;
let inner_value = inner_option.value.ok_or(IncompleteInterp("value"))?;
if let Value::Struct(ref opt_variant) = inner_value.value {
let tls_value = if opt_variant.type_ident.name() == Some("None") {
None
} else {
Some(Box::new(
inner_value
.value
.bfs_iterator()
.find_map(|(field, child)| {
(field == FieldOrIndex::Field(Some("__0"))).then_some(child)
})
.ok_or(FieldNotFound("__0"))?
.clone(),
))
};
return Ok(TlsVariable {
inner_value: tls_value,
inner_type: pcx.type_graph.identity(inner_type),
});
}
Err(ParsingError::Assume(IncompleteInterp(
"expect TLS inner value as option",
)))
}
pub fn parse_tls(
&self,
pcx: &ParseContext,
structure: &StructValue,
type_params: &IndexMap<String, Option<TypeId>>,
rv: RustVersion,
) -> Result<Option<TlsVariable>, ParsingError> {
if structure.type_ident.namespace().contains(&["eager"]) {
self.parse_const_tls_inner(pcx, Value::Struct(structure.clone()), type_params)
} else {
self.parse_tls_inner(pcx, Value::Struct(structure.clone()), type_params, rv)
}
}
fn parse_tls_inner(
&self,
pcx: &ParseContext,
inner_val: Value,
type_params: &IndexMap<String, Option<TypeId>>,
rv: RustVersion,
) -> Result<Option<TlsVariable>, ParsingError> {
if type_params.is_empty() {
return Ok(None);
}
let inner_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let state = inner_val
.bfs_iterator()
.find_map(|(field, child)| {
(field == FieldOrIndex::Field(Some("state"))).then_some(child)
})
.ok_or(FieldNotFound("state"))?;
let state = state.assume_field_as_rust_enum("value")?;
if let Some(member) = state.value {
let tls_val = if member.field_name.as_deref() == Some("Alive") {
version_switch!(
rv,
.. (1 . 89) => member.value.field("__0").map(Box::new),
(1 . 89) .. (1 . 94) => {
let get_val_from_storage = || {
let Value::Struct(storage) = inner_val else {
return None;
};
storage.field("value")?.field("value")?
.field("value")?
.field("value")
.map(Box::new)
};
get_val_from_storage()
},
(1 . 94) .. => {
let get_val_from_storage = || {
let Value::Struct(storage) = inner_val else {
return None;
};
storage.field("value")?.field("value")?
.field("value")?
.field("value")?
.field("__0")
.map(Box::new)
};
get_val_from_storage()
}
)
.expect("all rust versions are covered")
} else {
return Ok(None);
};
return Ok(Some(TlsVariable {
inner_value: tls_val,
inner_type: pcx.type_graph.identity(inner_type),
}));
};
Ok(None)
}
fn parse_const_tls_inner(
&self,
pcx: &ParseContext,
inner_val: Value,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<Option<TlsVariable>, ParsingError> {
let inner_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
if let Some(val) = inner_val.field("val") {
return Ok(Some(TlsVariable {
inner_value: val.field("value").map(Box::new),
inner_type: pcx.type_graph.identity(inner_type),
}));
}
Err(ParsingError::Assume(IncompleteInterp(
"expect TLS inner value as `val` field",
)))
}
pub fn parse_hashmap(
&self,
pcx: &ParseContext,
structure: &StructValue,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_hashmap_inner(pcx, Value::Struct(structure.clone()))
.context("HashMap<K, V> interpretation")
)
.map(SpecializedValue::HashMap)
}
fn parse_hashmap_inner(
&self,
pcx: &ParseContext,
val: Value,
) -> Result<HashMapVariable, ParsingError> {
let ctrl = val.assume_field_as_pointer("pointer")?;
let bucket_mask = val.assume_field_as_scalar_number("bucket_mask")?;
let table = val.assume_field_as_struct("table")?;
let kv_type = table
.type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let r#type = pcx.type_graph;
let kv_size = r#type
.type_size_in_bytes(pcx.evcx, kv_type)
.ok_or(UnknownSize(r#type.identity(kv_type)))?;
let reflection =
HashmapReflection::new(ctrl as *mut u8, bucket_mask as usize, kv_size as usize);
let iterator = reflection.iter(pcx.evcx.ecx.pid_on_focus())?;
let kv_items = iterator
.map_err(ParsingError::from)
.filter_map(|bucket| {
let raw_data = bucket.read(pcx.evcx.ecx.pid_on_focus());
let data = weak_error!(raw_data).map(|d| ObjectBinaryRepr {
raw_data: Bytes::from(d),
address: Some(bucket.location()),
size: bucket.size(),
});
let tuple = self.parser.parse_inner(pcx, data, kv_type);
if let Some(Value::Struct(mut tuple)) = tuple
&& tuple.members.len() == 2
{
let v = tuple.members.pop();
let k = tuple.members.pop();
return Ok(Some((k.unwrap().value, v.unwrap().value)));
}
Err(Assume(UnexpectedType("hashmap bucket")))
})
.collect()?;
Ok(HashMapVariable {
type_ident: val.r#type().to_owned(),
kv_items,
})
}
pub fn parse_hashset(
&self,
pcx: &ParseContext,
structure: &StructValue,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_hashset_inner(pcx, Value::Struct(structure.clone()))
.context("HashSet<T> interpretation")
)
.map(SpecializedValue::HashSet)
}
fn parse_hashset_inner(
&self,
pcx: &ParseContext,
val: Value,
) -> Result<HashSetVariable, ParsingError> {
let ctrl = val.assume_field_as_pointer("pointer")?;
let bucket_mask = val.assume_field_as_scalar_number("bucket_mask")?;
let table = val.assume_field_as_struct("table")?;
let kv_type = table
.type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let r#type = pcx.type_graph;
let kv_size = r#type
.type_size_in_bytes(pcx.evcx, kv_type)
.ok_or_else(|| UnknownSize(r#type.identity(kv_type)))?;
let reflection =
HashmapReflection::new(ctrl as *mut u8, bucket_mask as usize, kv_size as usize);
let iterator = reflection.iter(pcx.evcx.ecx.pid_on_focus())?;
let items = iterator
.map_err(ParsingError::from)
.filter_map(|bucket| {
let raw_data = bucket.read(pcx.evcx.ecx.pid_on_focus());
let data = weak_error!(raw_data).map(|d| ObjectBinaryRepr {
raw_data: Bytes::from(d),
address: Some(bucket.location()),
size: bucket.size(),
});
let tuple = self.parser.parse_inner(pcx, data, kv_type);
if let Some(Value::Struct(mut tuple)) = tuple
&& tuple.members.len() == 2
{
let _ = tuple.members.pop();
let k = tuple.members.pop().unwrap();
return Ok(Some(k.value));
}
Err(Assume(UnexpectedType("hashset bucket")))
})
.collect()?;
Ok(HashSetVariable {
type_ident: val.r#type().to_owned(),
items,
})
}
pub fn parse_btree_map(
&self,
pcx: &ParseContext,
structure: &StructValue,
identity: TypeId,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_btree_map_inner(
pcx,
Value::Struct(structure.clone()),
identity,
type_params
)
.context("BTreeMap<K, V> interpretation")
)
.map(SpecializedValue::BTreeMap)
}
fn parse_btree_map_inner(
&self,
pcx: &ParseContext,
val: Value,
identity: TypeId,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<HashMapVariable, ParsingError> {
let height = val.assume_field_as_scalar_number("height")?;
let ptr = val.assume_field_as_pointer("pointer")?;
let k_type = type_params
.get("K")
.ok_or(TypeParameterNotFound("K"))?
.ok_or(TypeParameterTypeNotFound("K"))?;
let v_type = type_params
.get("V")
.ok_or(TypeParameterNotFound("V"))?
.ok_or(TypeParameterTypeNotFound("V"))?;
let reflection = BTreeReflection::new(
pcx.type_graph,
ptr,
height as usize,
identity,
k_type,
v_type,
)?;
let iterator = reflection.iter(pcx.evcx)?;
let kv_items = iterator
.map_err(ParsingError::from)
.filter_map(|(k, v)| {
let Some(key) = self.parser.parse_inner(pcx, Some(k), k_type) else {
return Ok(None);
};
let Some(value) = self.parser.parse_inner(pcx, Some(v), v_type) else {
return Ok(None);
};
Ok(Some((key, value)))
})
.collect::<Vec<_>>()?;
Ok(HashMapVariable {
type_ident: val.r#type().to_owned(),
kv_items,
})
}
pub fn parse_btree_set(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_btree_set_inner(Value::Struct(structure.clone()))
.context("BTreeSet interpretation")
)
.map(SpecializedValue::BTreeSet)
}
fn parse_btree_set_inner(&self, val: Value) -> Result<HashSetVariable, ParsingError> {
let inner_map = val
.bfs_iterator()
.find_map(|(field_or_idx, child)| {
if let Value::Specialized {
value: Some(SpecializedValue::BTreeMap(map)),
..
} = child
&& field_or_idx == FieldOrIndex::Field(Some("map"))
{
return Some(map.clone());
}
None
})
.ok_or(IncompleteInterp("BTreeSet"))?;
Ok(HashSetVariable {
type_ident: val.r#type().to_owned(),
items: inner_map.kv_items.into_iter().map(|(k, _)| k).collect(),
})
}
pub fn parse_vec_dequeue(
&self,
pcx: &ParseContext,
structure: &StructValue,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Option<SpecializedValue> {
weak_error!(
self.parse_vec_dequeue_inner(pcx, Value::Struct(structure.clone()), type_params)
.context("VeqDequeue<T> interpretation")
)
.map(SpecializedValue::VecDeque)
}
fn parse_vec_dequeue_inner(
&self,
pcx: &ParseContext,
val: Value,
type_params: &IndexMap<String, Option<TypeId>>,
) -> Result<VecValue, ParsingError> {
let inner_type = type_params
.get("T")
.ok_or(TypeParameterNotFound("T"))?
.ok_or(TypeParameterTypeNotFound("T"))?;
let len = val.assume_field_as_scalar_number("len")? as usize;
let len = guard_len(len as i64) as usize;
let r#type = pcx.type_graph;
let el_type_size = r#type
.type_size_in_bytes(pcx.evcx, inner_type)
.ok_or_else(|| UnknownSize(r#type.identity(inner_type)))?
as usize;
let cap = if el_type_size == 0 {
usize::MAX
} else {
guard_cap(extract_capacity(pcx, &val)? as i64) as usize
};
let head = val.assume_field_as_scalar_number("head")? as usize;
let wrapped_start = if cap == 0 { 0 } else { head % cap };
let head_len = cap - wrapped_start;
let slice_ranges = if head_len >= len {
(wrapped_start..wrapped_start + len, 0..0)
} else {
let tail_len = len - head_len;
(wrapped_start..cap, 0..tail_len)
};
let data_ptr = val.assume_field_as_pointer("pointer")? as usize;
let data =
debugger::read_memory_by_pid(pcx.evcx.ecx.pid_on_focus(), data_ptr, cap * el_type_size)
.map(Bytes::from)?;
let items = slice_ranges
.0
.chain(slice_ranges.1)
.enumerate()
.filter_map(|(i, real_idx)| {
let offset = real_idx * el_type_size;
let el_raw_data = &data[offset..(real_idx + 1) * el_type_size];
let el_data = ObjectBinaryRepr {
raw_data: data.slice_ref(el_raw_data),
address: Some(data_ptr + offset),
size: el_type_size,
};
Some(ArrayItem {
index: i as i64,
value: self.parser.parse_inner(pcx, Some(el_data), inner_type)?,
})
})
.collect::<Vec<_>>();
Ok(VecValue {
structure: StructValue {
type_id: None,
type_ident: val.r#type().to_owned(),
members: vec![
Member {
field_name: Some("buf".to_owned()),
value: Value::Array(ArrayValue {
type_id: None,
type_ident: pcx.type_graph.identity(inner_type).as_array_type(),
items: Some(items),
raw_address: None,
}),
},
Member {
field_name: Some("cap".to_owned()),
value: Value::Scalar(ScalarValue {
type_id: None,
type_ident: TypeIdentity::no_namespace("usize"),
value: Some(SupportedScalar::Usize(if el_type_size == 0 {
0
} else {
cap
})),
raw_address: None,
}),
},
],
type_params: type_params.clone(),
raw_address: None,
},
})
}
pub fn parse_cell(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_cell_inner(Value::Struct(structure.clone()))
.context("Cell<T> interpretation")
)
.map(Box::new)
.map(SpecializedValue::Cell)
}
fn parse_cell_inner(&self, val: Value) -> Result<Value, ParsingError> {
let unsafe_cell = val.assume_field_as_struct("value")?;
let member = unsafe_cell
.members
.first()
.ok_or(IncompleteInterp("UnsafeCell"))?;
Ok(member.value.clone())
}
pub fn parse_refcell(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_refcell_inner(Value::Struct(structure.clone()))
.context("RefCell<T> interpretation")
)
.map(Box::new)
.map(SpecializedValue::RefCell)
}
fn parse_refcell_inner(&self, val: Value) -> Result<Value, ParsingError> {
let borrow = val
.bfs_iterator()
.find_map(|(_, child)| {
if let Value::Specialized {
value: Some(SpecializedValue::Cell(val)),
..
} = child
{
return Some(val.clone());
}
None
})
.ok_or(IncompleteInterp("Cell"))?;
let Value::Scalar(var) = *borrow else {
return Err(IncompleteInterp("Cell").into());
};
let borrow = Value::Scalar(var);
let unsafe_cell = val.assume_field_as_struct("value")?;
let value = unsafe_cell
.members
.first()
.ok_or(IncompleteInterp("UnsafeCell"))?;
Ok(Value::Struct(StructValue {
type_id: None,
type_ident: val.r#type().to_owned(),
members: vec![
Member {
field_name: Some("borrow".to_string()),
value: borrow,
},
value.clone(),
],
type_params: Default::default(),
raw_address: None,
}))
}
pub fn parse_rc(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_rc_inner(Value::Struct(structure.clone()))
.context("Rc<T> interpretation")
)
.map(SpecializedValue::Rc)
}
fn parse_rc_inner(&self, val: Value) -> Result<PointerValue, ParsingError> {
Ok(val
.bfs_iterator()
.find_map(|(field_or_idx, child)| {
if let Value::Pointer(pointer) = child
&& field_or_idx == FieldOrIndex::Field(Some("pointer"))
{
let new_pointer = pointer.clone();
return Some(new_pointer);
}
None
})
.ok_or(IncompleteInterp("rc"))?)
}
pub fn parse_arc(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_arc_inner(Value::Struct(structure.clone()))
.context("Arc<T> interpretation")
)
.map(SpecializedValue::Arc)
}
fn parse_arc_inner(&self, val: Value) -> Result<PointerValue, ParsingError> {
Ok(val
.bfs_iterator()
.find_map(|(field_or_idx, child)| {
if let Value::Pointer(pointer) = child
&& field_or_idx == FieldOrIndex::Field(Some("pointer"))
{
let new_pointer = pointer.clone();
return Some(new_pointer);
}
None
})
.ok_or(IncompleteInterp("Arc"))?)
}
pub fn parse_uuid(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_uuid_inner(structure)
.context("Uuid interpretation")
)
.map(SpecializedValue::Uuid)
}
fn parse_uuid_inner(&self, structure: &StructValue) -> Result<[u8; 16], ParsingError> {
let member0 = structure.members.first().ok_or(FieldNotFound("member 0"))?;
let Value::Array(ref arr) = member0.value else {
return Err(UnexpectedType("uuid struct member must be an array").into());
};
let items = arr
.items
.as_ref()
.ok_or(AssumeError::NoData("uuid items"))?;
if items.len() != 16 {
return Err(AssumeError::UnexpectedType("uuid struct member must be [u8; 16]").into());
}
let mut bytes_repr = [0; 16];
for (i, item) in items.iter().enumerate() {
let Value::Scalar(ScalarValue {
value: Some(SupportedScalar::U8(byte)),
..
}) = item.value
else {
return Err(UnexpectedType("uuid struct member must be [u8; 16]").into());
};
bytes_repr[i] = byte;
}
Ok(bytes_repr)
}
fn parse_timespec(&self, timespec: &StructValue) -> Result<(i64, u32), ParsingError> {
let &[
Member {
value: Value::Scalar(secs),
..
},
Member {
value: Value::Struct(n_secs),
..
},
] = ×pec.members.as_slice()
else {
let err = "`Timespec` should contains secs and n_secs fields";
return Err(UnexpectedType(err).into());
};
let &[
Member {
value: Value::Scalar(n_secs),
..
},
] = &n_secs.members.as_slice()
else {
let err = "`Nanoseconds` should contains u32 field";
return Err(UnexpectedType(err).into());
};
let secs = secs
.try_as_number()
.ok_or(UnexpectedType("`Timespec::tv_sec` not an int"))?;
let n_secs = n_secs
.try_as_number()
.ok_or(UnexpectedType("Timespec::tv_nsec` not an int"))? as u32;
Ok((secs, n_secs))
}
pub fn parse_sys_time(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_sys_time_inner(structure)
.context("SystemTime interpretation")
)
.map(SpecializedValue::SystemTime)
}
fn parse_sys_time_inner(&self, structure: &StructValue) -> Result<(i64, u32), ParsingError> {
let &[
Member {
value: Value::Struct(time_instant),
..
},
] = &structure.members.as_slice()
else {
let err = "`std::time::SystemTime` should contains a `time::SystemTime` field";
return Err(UnexpectedType(err).into());
};
let &[
Member {
value: Value::Struct(timespec),
..
},
] = &time_instant.members.as_slice()
else {
let err = "`time::SystemTime` should contains a `Timespec` field";
return Err(UnexpectedType(err).into());
};
self.parse_timespec(timespec)
}
pub fn parse_instant(&self, structure: &StructValue) -> Option<SpecializedValue> {
weak_error!(
self.parse_instant_inner(structure)
.context("Instant interpretation")
)
.map(SpecializedValue::Instant)
}
fn parse_instant_inner(&self, structure: &StructValue) -> Result<(i64, u32), ParsingError> {
let &[
Member {
value: Value::Struct(time_instant),
..
},
] = &structure.members.as_slice()
else {
let err = "`std::time::Instant` should contains a `time::Instant` field";
return Err(UnexpectedType(err).into());
};
let &[
Member {
value: Value::Struct(timespec),
..
},
] = &time_instant.members.as_slice()
else {
let err = "`time::Instant` should contains a `Timespec` field";
return Err(UnexpectedType(err).into());
};
self.parse_timespec(timespec)
}
}
fn extract_capacity(pcx: &ParseContext, val: &Value) -> Result<usize, ParsingError> {
let rust_version = pcx
.evcx
.rustc_version()
.ok_or(ParsingError::UnsupportedVersion)?;
version_switch!(
rust_version,
.. (1 . 76) => val.assume_field_as_scalar_number("cap")? as usize,
(1 . 76) .. => {
let cap_s = val.assume_field_as_struct("cap")?;
let cap = &cap_s.members.first().ok_or(IncompleteInterp("Vec"))?.value;
if let Value::Scalar(ScalarValue {value: Some(SupportedScalar::Usize(cap)), ..}) = cap {
Ok(*cap)
} else {
Err(AssumeError::FieldNotANumber("cap"))
}?
},
)
.ok_or(ParsingError::UnsupportedVersion)
}