reid-llvm/reid-llvm-lib/src/debug_information.rs

383 lines
10 KiB
Rust

use std::{cell::RefCell, collections::hash_map::Values, rc::Rc};
use crate::builder::InstructionValue;
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct DebugScopeValue(pub Vec<usize>);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugLocationValue(pub DebugProgramValue, pub usize);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugTypeValue(pub usize);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugMetadataValue(pub usize);
/// Represents either a subprogram, or the compilation context
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugProgramValue(pub usize);
#[derive(Debug, Clone)]
pub struct DebugFileData {
pub name: String,
pub directory: String,
}
#[derive(Debug, Clone)]
pub(crate) struct DebugScopeHolder {
pub(crate) value: DebugScopeValue,
pub(crate) location: Option<DebugLocation>,
pub(crate) inner_scopes: Vec<DebugScopeHolder>,
pub(crate) locations: Vec<DebugLocationHolder>,
}
#[derive(Debug, Clone)]
pub struct DebugMetadataHolder {
pub(crate) location: DebugLocation,
pub(crate) value: DebugMetadataValue,
pub(crate) data: DebugMetadata,
}
#[derive(Clone)]
pub struct DebugTypeHolder {
pub(crate) value: DebugTypeValue,
pub(crate) data: DebugTypeData,
}
#[derive(Debug, Clone)]
pub struct DebugSubprogramHolder {
pub(crate) _value: DebugProgramValue,
pub(crate) data: DebugSubprogramData,
}
#[derive(Debug, Clone)]
pub(crate) struct DebugLocationHolder {
pub(crate) program: DebugProgramValue,
pub(crate) value: DebugLocationValue,
pub(crate) location: DebugLocation,
}
#[derive(Debug, Clone)]
pub struct DebugInformation {
pub file: DebugFileData,
// scope: Rc<RefCell<DebugScopeHolder>>,
locations: Rc<RefCell<Vec<DebugLocationHolder>>>,
programs: Rc<RefCell<Vec<DebugSubprogramHolder>>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
}
impl DebugInformation {
pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugProgramValue) {
(
DebugInformation {
file,
// scope: Rc::new(RefCell::new(DebugScopeHolder {
// value: scope_value.clone(),
// inner_scopes: Vec::new(),
// locations: Vec::new(),
// location: None,
// })),
locations: Rc::new(RefCell::new(Vec::new())),
metadata: Rc::new(RefCell::new(Vec::new())),
programs: Rc::new(RefCell::new(Vec::new())),
types: Rc::new(RefCell::new(Vec::new())),
},
DebugProgramValue(0),
)
}
// pub fn inner_scope(
// &self,
// parent: &DebugScopeValue,
// location: DebugLocation,
// ) -> DebugScopeValue {
// unsafe {
// let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
// for i in &parent.0 {
// v = v.inner_scopes.get_unchecked_mut(*i);
// }
// v
// });
// let mut arr = parent.0.clone();
// arr.push(parent.0.len());
// let value = DebugScopeValue(arr);
// outer_scope.inner_scopes.push(DebugScopeHolder {
// value: value.clone(),
// inner_scopes: Vec::new(),
// locations: Vec::new(),
// location: Some(location),
// });
// value
// }
// }
pub fn location(
&self,
program_value: &DebugProgramValue,
location: DebugLocation,
) -> DebugLocationValue {
let value = DebugLocationValue(program_value.clone(), self.locations.borrow().len());
let location = DebugLocationHolder {
program: *program_value,
value: value.clone(),
location,
};
self.locations.borrow_mut().push(location);
value
}
pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue {
let mut types = self.types.borrow_mut();
let value = DebugTypeValue(types.len());
types.push(DebugTypeHolder {
value: value.clone(),
data: kind,
});
value
}
pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue {
let mut metadata = self.metadata.borrow_mut();
let value = DebugMetadataValue(metadata.len());
metadata.push(DebugMetadataHolder {
location: *location,
value: value.clone(),
data: kind,
});
value
}
pub fn subprogram(&self, kind: DebugSubprogramData) -> DebugProgramValue {
let mut subprogram = self.programs.borrow_mut();
let value = DebugProgramValue(subprogram.len() + 1);
subprogram.push(DebugSubprogramHolder {
_value: value.clone(),
data: kind,
});
value
}
pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata {
unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation {
unsafe { self.metadata.borrow().get_unchecked(value.0).location }
}
pub fn get_subprogram_data(&self, value: DebugProgramValue) -> Option<DebugSubprogramData> {
if value.0 == 0 {
None
} else {
Some(self.get_subprogram_data_unchecked(&value))
}
}
pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData {
unsafe { self.types.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_location(&self, value: DebugLocationValue) -> DebugLocation {
unsafe {
self.locations
.borrow()
.get_unchecked(value.1)
.location
.clone()
}
}
pub fn get_metadatas(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> {
self.metadata.clone()
}
// pub fn get_scopes(&self) -> Rc<RefCell<DebugScopeHolder>> {
// self.scope.clone()
// }
pub fn get_subprograms(&self) -> Rc<RefCell<Vec<DebugSubprogramHolder>>> {
self.programs.clone()
}
pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> {
self.types.clone()
}
pub(crate) fn get_locations(&self) -> Rc<RefCell<Vec<DebugLocationHolder>>> {
self.locations.clone()
}
pub fn get_subprogram_data_unchecked(&self, value: &DebugProgramValue) -> DebugSubprogramData {
unsafe {
self.programs
.borrow()
.get_unchecked(value.0 - 1)
.data
.clone()
}
}
}
#[derive(Clone, Copy)]
pub struct DebugLocation {
pub scope: DebugProgramValue,
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone)]
pub enum DebugMetadata {
ParamVar(DebugParamVariable),
LocalVar(DebugLocalVariable),
VarAssignment,
}
#[derive(Debug, Clone)]
pub struct DebugParamVariable {
pub name: String,
/// the index (starting from 1) of this variable in the subprogram
/// parameters. arg_idx should not conflict with other parameters of the
/// same subprogram.
pub arg_idx: u32,
pub ty: DebugTypeValue,
/// If this variable will be referenced from its containing subprogram, and
/// will survive some optimizations.
pub always_preserve: bool,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone)]
pub struct DebugLocalVariable {
pub name: String,
pub ty: DebugTypeValue,
pub always_preserve: bool,
pub flags: DwarfFlags,
}
impl Default for DebugSubprogramOptionals {
fn default() -> Self {
Self {
scope_line: 0,
is_local: false,
is_definition: true,
is_optimized: false,
flags: DwarfFlags,
}
}
}
#[derive(Debug, Clone)]
pub struct DwarfFlags;
#[derive(Clone)]
pub enum DebugTypeData {
Basic(DebugBasicType),
Subprogram(DebugSubprogramType),
Pointer(DebugPointerType),
Array(DebugArrayType),
Struct(DebugStructType),
}
#[derive(Clone)]
pub struct DebugBasicType {
pub name: String,
/// Size of the type.
pub size_bits: u64,
/// DWARF encoding code, e.g., dwarf::DW_ATE_float.
pub encoding: DwarfEncoding,
/// Optional DWARF attributes, e.g., DW_AT_endianity.
pub flags: DwarfFlags,
}
#[derive(Clone)]
pub struct DebugArrayType {
pub size_bits: u64,
pub align_bits: u32,
pub element_type: DebugTypeValue,
pub length: u64,
}
#[derive(Clone)]
pub struct DebugPointerType {
pub name: String,
pub pointee: DebugTypeValue,
pub size_bits: u64,
}
#[derive(Clone)]
pub struct DebugStructType {
pub name: String,
pub location: DebugLocation,
pub size_bits: u64,
pub flags: DwarfFlags,
pub fields: Vec<DebugFieldType>,
}
#[derive(Clone)]
pub struct DebugFieldType {
pub name: String,
pub location: DebugLocation,
pub size_bits: u64,
pub offset: u64,
pub flags: DwarfFlags,
pub ty: DebugTypeValue,
}
#[derive(Clone)]
pub struct DebugSubprogramType {
pub parameters: Vec<DebugTypeValue>,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone, Copy)]
pub enum DwarfEncoding {
Address = 1,
Boolean = 2,
Float = 4,
Signed = 5,
SignedChar = 6,
Unsigned = 7,
UnsignedChar = 8,
}
#[derive(Debug, Clone)]
pub struct DebugSubprogramData {
/// Function name.
pub name: String,
pub outer_scope: DebugProgramValue,
/// Used for line number.
pub location: DebugLocation,
/// Function type.
pub ty: DebugTypeValue,
pub opts: DebugSubprogramOptionals,
}
#[derive(Debug, Clone)]
pub struct DebugSubprogramOptionals {
/// Set to the beginning of the scope this starts
pub scope_line: u32,
pub is_local: bool,
pub is_definition: bool,
pub is_optimized: bool,
/// These flags are used to emit dwarf attributes. e.g. is this function
/// prototyped or not.
pub flags: DwarfFlags,
}
#[derive(Clone)]
pub struct InstructionDebugRecordData {
pub scope: DebugProgramValue,
pub variable: DebugMetadataValue,
pub location: DebugLocation,
pub kind: DebugRecordKind,
}
#[derive(Clone, Copy)]
pub enum DebugRecordKind {
Declare(InstructionValue),
Value(InstructionValue),
}