use crate::error::{Error, Result};
use crate::types::{Array, BaseType, Field, Float, Integer, Struct, Type, TypeDatabase};
use btf::{
Array as BtfArray, Btf, Float as BtfFloat, Integer as BtfInteger, Struct as BtfStruct,
Type as BtfType,
};
use std::collections::HashMap;
impl TypeDatabase {
fn add_btf_void(&mut self, name: Option<&str>, num_refs: u32) -> Result<usize> {
let new_type = Type {
base_type: BaseType::Void,
num_refs,
};
self.add_type(name, &new_type)
}
fn add_btf_integer(
&mut self,
name: Option<&str>,
integer: &BtfInteger,
num_refs: u32,
) -> Result<usize> {
let base_type = BaseType::Integer(Integer {
used_bits: integer.used_bits,
bits: integer.bits,
is_signed: integer.is_signed,
});
let new_type = Type {
base_type,
num_refs,
};
self.add_type(name, &new_type)
}
fn add_btf_float(
&mut self,
name: Option<&str>,
float: &BtfFloat,
num_refs: u32,
) -> Result<usize> {
let base_type = BaseType::Float(Float { bits: float.bits });
let new_type = Type {
base_type,
num_refs,
};
self.add_type(name, &new_type)
}
fn add_btf_array(
&mut self,
name: Option<&str>,
array: &BtfArray,
num_refs: u32,
) -> Result<usize> {
let btf_id_name = format!(".btf.{}", array.elem_type_id);
let element_type_id = self
.get_type_id_by_name(&btf_id_name)
.ok_or(Error::NoConversion)?;
let base_type = BaseType::Array(Array::create(self, element_type_id, array.num_elements)?);
let new_type = Type {
base_type,
num_refs,
};
self.add_type(name, &new_type)
}
fn add_btf_struct(
&mut self,
name: Option<&str>,
structure: &BtfStruct,
num_refs: u32,
) -> Result<usize> {
let mut size = 0;
let mut fields = HashMap::with_capacity(structure.members.len());
for (i, member) in structure.members.iter().enumerate() {
let btf_id_name = format!(".btf.{}", member.type_id);
let type_id = self
.get_type_id_by_name(&btf_id_name)
.ok_or(Error::NoConversion)?;
let field = Field {
offset: member.offset,
type_id,
};
let field_type = self
.get_type_by_name(&btf_id_name)
.ok_or(Error::NoConversion)?;
let field_size = (member.offset + field_type.get_size() * 8) / 8;
if field_size > size {
size = field_size;
}
if let Some(member_name) = &member.name {
fields.insert(member_name.to_string(), field);
} else {
let member_name = format!("{}", i);
fields.insert(member_name, field);
}
}
let base_type = BaseType::Struct(Struct { size, fields });
let new_type = Type {
base_type,
num_refs,
};
self.add_type(name, &new_type)
}
fn add_btf_type(
&mut self,
name: Option<&str>,
btf_type: &BtfType,
num_refs: u32,
) -> Result<usize> {
match btf_type {
BtfType::Integer(integer) => self.add_btf_integer(name, integer, num_refs),
BtfType::Float(float) => self.add_btf_float(name, float, num_refs),
BtfType::Array(array) => self.add_btf_array(name, array, num_refs),
BtfType::Struct(structure) => self.add_btf_struct(name, structure, num_refs),
_ => self.add_btf_void(name, num_refs),
}
}
pub fn add_btf_types(&mut self, btf: &Btf) -> Result<()> {
for i in 0..btf.get_types().len() {
let btf_id_name = format!(".btf.{}", i);
self.add_btf_void(Some(&btf_id_name), 0)?;
}
for (i, btf_type) in btf.get_types().iter().enumerate() {
let btf_id_name = format!(".btf.{}", i);
self.add_btf_type(Some(&btf_id_name), &btf_type.base_type, btf_type.num_refs)?;
self.add_btf_type(
btf_type.name.as_deref(),
&btf_type.base_type,
btf_type.num_refs,
)?;
}
Ok(())
}
}