use crate::debugger;
use crate::debugger::TypeDeclaration;
use crate::debugger::debugee::dwarf::eval::EvaluationContext;
use crate::debugger::debugee::dwarf::r#type::{ComplexType, StructureMember, TypeId, TypeIdentity};
use crate::debugger::variable::ObjectBinaryRepr;
use crate::debugger::variable::value::AssumeError::NoType;
use crate::debugger::variable::value::ParsingError::ReadDebugeeMemory;
use crate::debugger::variable::value::{AssumeError, ParsingError};
use fallible_iterator::FallibleIterator;
use std::mem;
use std::ptr::NonNull;
const B: usize = 6;
fn assert_member_name(member: &StructureMember, starts_with: &str) -> bool {
member
.name
.as_ref()
.map(|name| name.starts_with(starts_with))
.unwrap_or_default()
}
struct LeafNodeMarkup {
parent: StructureMember,
parent_idx: StructureMember,
len: StructureMember,
keys: StructureMember,
vals: StructureMember,
size: usize,
}
impl LeafNodeMarkup {
fn from_type(
r#type: &ComplexType,
map_id: TypeId,
key_type_id: TypeId,
value_type_id: TypeId,
) -> Option<LeafNodeMarkup> {
let mut iterator = r#type.bfs_iterator(map_id);
let (members, byte_size) = iterator.find_map(|type_decl| {
if let TypeDeclaration::Structure {
name,
members,
byte_size,
type_params,
..
} = type_decl
&& name.as_ref()?.starts_with("LeafNode")
{
let v_found = type_params
.iter()
.any(|(_, &type_id)| type_id == Some(value_type_id));
let k_found = type_params
.iter()
.any(|(_, &type_id)| type_id == Some(key_type_id));
if v_found & k_found {
return Some((members, byte_size));
}
}
None
})?;
let size = (*byte_size)? as usize;
let parent_member = members.iter().find(|&m| assert_member_name(m, "parent"))?;
let parent_idx_member = members
.iter()
.find(|&m| assert_member_name(m, "parent_idx"))?;
let len_member = members.iter().find(|&m| assert_member_name(m, "len"))?;
let keys_member = members.iter().find(|&m| assert_member_name(m, "keys"))?;
let vals_member = members.iter().find(|&m| assert_member_name(m, "vals"))?;
Some(LeafNodeMarkup {
parent: parent_member.clone(),
parent_idx: parent_idx_member.clone(),
len: len_member.clone(),
keys: keys_member.clone(),
vals: vals_member.clone(),
size,
})
}
}
struct InternalNodeMarkup {
data: StructureMember,
edges: StructureMember,
size: usize,
}
impl InternalNodeMarkup {
fn from_type(
r#type: &ComplexType,
map_id: TypeId,
key_type_id: TypeId,
value_type_id: TypeId,
) -> Option<InternalNodeMarkup> {
let mut iterator = r#type.bfs_iterator(map_id);
let (members, byte_size) = iterator.find_map(|type_decl| {
if let TypeDeclaration::Structure {
name,
members,
byte_size,
type_params,
..
} = type_decl
&& name.as_ref()?.starts_with("InternalNode")
{
let v_found = type_params
.iter()
.any(|(_, &type_id)| type_id == Some(value_type_id));
let k_found = type_params
.iter()
.any(|(_, &type_id)| type_id == Some(key_type_id));
if v_found & k_found {
return Some((members, byte_size));
}
}
None
})?;
let size = (*byte_size)? as usize;
let data_member = members.iter().find(|&m| assert_member_name(m, "data"))?;
let edges_member = members.iter().find(|&m| assert_member_name(m, "edges"))?;
Some(InternalNodeMarkup {
data: data_member.clone(),
edges: edges_member.clone(),
size,
})
}
}
struct Leaf {
parent: Option<NonNull<()>>,
parent_idx: u16,
len: u16,
keys_debugee_location: Option<usize>,
keys_raw: Vec<u8>,
vals_debugee_location: Option<usize>,
vals_raw: Vec<u8>,
}
impl Leaf {
fn from_markup(
evcx: &EvaluationContext,
r#type: &ComplexType,
ptr: *const (),
markup: &LeafNodeMarkup,
) -> Result<Leaf, ParsingError> {
let leaf_bytes =
debugger::read_memory_by_pid(evcx.ecx.pid_on_focus(), ptr as usize, markup.size)
.map_err(ReadDebugeeMemory)?;
let data = ObjectBinaryRepr {
raw_data: bytes::Bytes::from(leaf_bytes),
address: Some(ptr as usize),
size: markup.size,
};
Ok(Self::from_bytes(evcx, r#type, data, markup)?)
}
fn from_bytes(
evcx: &EvaluationContext,
r#type: &ComplexType,
data: ObjectBinaryRepr,
markup: &LeafNodeMarkup,
) -> Result<Leaf, AssumeError> {
let parent = unsafe {
const EXPECTED_SIZE: usize = mem::size_of::<Option<NonNull<()>>>();
mem::transmute::<[u8; EXPECTED_SIZE], Option<NonNull<()>>>(
markup
.parent
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("leaf node (parent)"))?
.raw_data
.to_vec()
.try_into()
.map_err(|data: Vec<_>| {
AssumeError::UnexpectedBinaryRepr(
"leaf node (parent)",
EXPECTED_SIZE,
data.len(),
)
})?,
)
};
let len_bytes = markup
.len
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("leaf node (len)"))?
.raw_data
.to_vec();
let len = u16::from_ne_bytes(len_bytes.try_into().map_err(|data: Vec<_>| {
AssumeError::UnexpectedBinaryRepr("leaf node len", 2, data.len())
})?);
let parent_idx_bytes = markup
.parent_idx
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("leaf node (parent index)"))?
.raw_data
.to_vec();
let parent_idx =
u16::from_ne_bytes(parent_idx_bytes.try_into().map_err(|data: Vec<_>| {
AssumeError::UnexpectedBinaryRepr("leaf node parent index", 2, data.len())
})?);
let keys_data = markup
.keys
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("leaf node (keys)"))?;
let vals_data = markup
.vals
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("leaf node (vals)"))?;
Ok(Leaf {
parent,
parent_idx,
len,
keys_debugee_location: keys_data.address,
keys_raw: keys_data.raw_data.to_vec(),
vals_debugee_location: vals_data.address,
vals_raw: vals_data.raw_data.to_vec(),
})
}
}
struct Internal {
leaf: Leaf,
edges: [*const (); 2 * B],
}
impl Internal {
fn from_markup(
evcx: &EvaluationContext,
r#type: &ComplexType,
ptr: *const (),
l_markup: &LeafNodeMarkup,
i_markup: &InternalNodeMarkup,
) -> Result<Self, ParsingError> {
let bytes =
debugger::read_memory_by_pid(evcx.ecx.pid_on_focus(), ptr as usize, i_markup.size)
.map_err(ReadDebugeeMemory)?;
let data = ObjectBinaryRepr {
raw_data: bytes::Bytes::from(bytes),
address: Some(ptr as usize),
size: i_markup.size,
};
let edges_v = i_markup
.edges
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("internal node (edges_v)"))?
.raw_data
.to_vec()
.chunks_exact(mem::size_of::<usize>())
.map(|chunk| {
usize::from_ne_bytes(
chunk
.try_into()
.expect("unreachable: 8 bytes chunk must be convertible for usize"),
) as *const ()
})
.collect::<Vec<_>>();
let edges: [*const (); B * 2] = edges_v
.try_into()
.map_err(|_edges: Vec<_>| AssumeError::NoData("internal node (edges_v)"))?;
let leaf_bytes = i_markup
.data
.value(evcx, r#type, &data)
.ok_or(AssumeError::NoData("internal node (leaf_bytes)"))?;
Ok(Internal {
leaf: Leaf::from_bytes(evcx, r#type, leaf_bytes, l_markup)?,
edges,
})
}
}
enum LeafOrInternal {
Leaf(Leaf),
Internal(Internal),
}
impl LeafOrInternal {
fn len(&self) -> u16 {
match self {
LeafOrInternal::Leaf(leaf) => leaf.len,
LeafOrInternal::Internal(internal) => internal.leaf.len,
}
}
fn leaf(&self) -> &Leaf {
match self {
LeafOrInternal::Leaf(leaf) => leaf,
LeafOrInternal::Internal(internal) => &internal.leaf,
}
}
fn internal(&self) -> &Internal {
match self {
LeafOrInternal::Leaf(_) => panic!("not an internal"),
LeafOrInternal::Internal(internal) => internal,
}
}
}
pub(super) struct Node {
data: LeafOrInternal,
height: usize,
}
struct Handle {
node: Node,
idx: usize,
}
impl Handle {
fn node_is_leaf(&self) -> bool {
self.node.height == 0
}
fn is_right_kv(&self) -> bool {
let len = self.node.data.len() as usize;
self.idx < len
}
fn data(
&self,
k_size: usize,
v_size: usize,
) -> nix::Result<(ObjectBinaryRepr, ObjectBinaryRepr)> {
let leaf = self.node.data.leaf();
let key_offset = k_size * self.idx;
let key_raw = leaf.keys_raw[key_offset..k_size * (self.idx + 1)].to_vec();
let key_data = ObjectBinaryRepr {
raw_data: bytes::Bytes::from(key_raw),
address: leaf.keys_debugee_location.map(|addr| addr + key_offset),
size: k_size,
};
let val_offset = v_size * self.idx;
let val_raw = leaf.vals_raw[val_offset..v_size * (self.idx + 1)].to_vec();
let val_data = ObjectBinaryRepr {
raw_data: bytes::Bytes::from(val_raw),
address: leaf.vals_debugee_location.map(|addr| addr + val_offset),
size: v_size,
};
Ok((key_data, val_data))
}
fn next_leaf_edge(
self,
evcx: &EvaluationContext,
reflection: &BTreeReflection,
) -> Result<Self, ParsingError> {
if self.node_is_leaf() {
Ok(Handle {
node: self.node,
idx: self.idx + 1,
})
} else {
let mut idx = self.idx + 1;
let internal = self.node.data.internal();
let mut node = reflection.make_node(evcx, internal.edges[idx], self.node.height - 1)?;
while node.height != 0 {
idx = 0;
let internal = node.data.internal();
node = reflection.make_node(evcx, internal.edges[idx], node.height - 1)?;
}
if node.height == 0 {
idx = 0;
}
Ok(Handle { node, idx })
}
}
fn first_leaf_edge(
self,
evcx: &EvaluationContext,
reflection: &BTreeReflection,
) -> Result<Handle, ParsingError> {
let mut handle = self;
while !handle.node_is_leaf() {
let internal = handle.node.data.internal();
handle = Handle {
node: reflection.make_node(evcx, internal.edges[0], handle.node.height - 1)?,
idx: 0,
}
}
Ok(handle)
}
pub(crate) fn try_ascend(
&self,
evcx: &EvaluationContext,
reflection: &BTreeReflection,
) -> Result<Option<Handle>, ParsingError> {
let leaf = self.node.data.leaf();
let parent = match leaf.parent {
None => return Ok(None),
Some(p) => p,
};
Ok(Some(Handle {
node: reflection.make_node(evcx, parent.as_ptr(), self.node.height + 1)?,
idx: leaf.parent_idx as usize,
}))
}
}
pub struct BTreeReflection<'a> {
root: *const (),
root_h: usize,
internal_markup: InternalNodeMarkup,
leaf_markup: LeafNodeMarkup,
r#type: &'a ComplexType,
k_type_id: TypeId,
v_type_id: TypeId,
}
impl<'a> BTreeReflection<'a> {
pub fn new(
r#type: &'a ComplexType,
root_ptr: *const (),
root_height: usize,
map_id: TypeId,
k_type_id: TypeId,
v_type_id: TypeId,
) -> Result<Self, AssumeError> {
Ok(Self {
root: root_ptr,
root_h: root_height,
internal_markup: InternalNodeMarkup::from_type(r#type, map_id, k_type_id, v_type_id)
.ok_or(NoType("internal node"))?,
leaf_markup: LeafNodeMarkup::from_type(r#type, map_id, k_type_id, v_type_id)
.ok_or(NoType("leaf node"))?,
r#type,
k_type_id,
v_type_id,
})
}
fn make_node(
&self,
evcx: &EvaluationContext,
node_ptr: *const (),
height: usize,
) -> Result<Node, ParsingError> {
let data = if height == 0 {
LeafOrInternal::Leaf(Leaf::from_markup(
evcx,
self.r#type,
node_ptr,
&self.leaf_markup,
)?)
} else {
LeafOrInternal::Internal(Internal::from_markup(
evcx,
self.r#type,
node_ptr,
&self.leaf_markup,
&self.internal_markup,
)?)
};
Ok(Node { data, height })
}
pub fn iter(self, evcx: &'a EvaluationContext) -> Result<KVIterator<'a>, AssumeError> {
let k_size = self.r#type.type_size_in_bytes(evcx, self.k_type_id).ok_or(
AssumeError::UnknownSize(TypeIdentity::no_namespace("btree key type")),
)?;
let v_size = self.r#type.type_size_in_bytes(evcx, self.v_type_id).ok_or(
AssumeError::UnknownSize(TypeIdentity::no_namespace("btree value type")),
)?;
Ok(KVIterator {
reflection: self,
handle: None,
evcx,
k_size: k_size as usize,
v_size: v_size as usize,
})
}
}
pub struct KVIterator<'a> {
reflection: BTreeReflection<'a>,
evcx: &'a EvaluationContext<'a>,
handle: Option<Handle>,
k_size: usize,
v_size: usize,
}
impl FallibleIterator for KVIterator<'_> {
type Item = (ObjectBinaryRepr, ObjectBinaryRepr);
type Error = ParsingError;
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
let mut handle = match self.handle.take() {
None => Handle {
node: self.reflection.make_node(
self.evcx,
self.reflection.root,
self.reflection.root_h,
)?,
idx: 0,
}
.first_leaf_edge(self.evcx, &self.reflection)?,
Some(handle) => handle,
};
loop {
let is_kv = handle.is_right_kv();
if !is_kv {
handle = match handle.try_ascend(self.evcx, &self.reflection)? {
None => return Ok(None),
Some(h) => h,
};
continue;
}
let data = handle.data(self.k_size, self.v_size)?;
self.handle = Some(handle.next_leaf_edge(self.evcx, &self.reflection)?);
return Ok(Some(data));
}
}
}