use std::{ cell::{RefCell, RefMut}, rc::Rc, }; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct DebugScopeValue(pub Vec); #[derive(Clone, Copy, Hash, PartialEq, Eq)] pub struct DebugLocationValue(pub DebugProgramValue, pub usize); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct DebugTypeValue(pub usize); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct DebugMetadataValue(pub usize); /// Represents either a subprogram, or the compilation context #[derive(Debug, 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, pub(crate) inner_scopes: Vec, pub(crate) locations: Vec, } #[derive(Debug, Clone)] pub struct DebugMetadataHolder { pub(crate) program: DebugProgramValue, pub(crate) value: DebugMetadataValue, pub(crate) data: DebugMetadata, } #[derive(Debug, 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>, locations: Rc>>, programs: Rc>>, metadata: Rc>>, types: Rc>>, } 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, program: &DebugProgramValue, kind: DebugMetadata) -> DebugMetadataValue { let mut metadata = self.metadata.borrow_mut(); let value = DebugMetadataValue(metadata.len()); metadata.push(DebugMetadataHolder { program: *program, value: value.clone(), data: kind, }); value } fn check_metadata(&self, scope: &DebugScopeValue, metadata: &DebugMetadata) { match &metadata { DebugMetadata::ParamVar(debug_param_variable) => todo!(), DebugMetadata::LocalVar(debug_local_variable) => todo!(), } } 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) -> Rc>> { self.metadata.clone() } // pub fn get_scopes(&self) -> Rc> { // self.scope.clone() // } pub fn get_subprograms(&self) -> Rc>> { self.programs.clone() } pub fn get_types(&self) -> Rc>> { self.types.clone() } pub fn get_locations(&self) -> Rc>> { self.locations.clone() } pub fn get_subprogram_data(&self, value: &DebugProgramValue) -> DebugSubprogramData { unsafe { self.programs .borrow() .get_unchecked(value.0 - 1) .data .clone() } } } #[derive(Debug, Clone, Copy, Default)] pub struct DebugLocation { pub line: u32, pub column: u32, } #[derive(Debug, Clone)] pub enum DebugMetadata { ParamVar(DebugParamVariable), LocalVar(DebugLocalVariable), } #[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, /// Used for line number pub location: DebugLocation, 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 location: DebugLocation, pub ty: DebugMetadataValue, pub always_preserve: bool, pub alignment: u32, } 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(Debug, Clone)] pub enum DebugTypeData { Basic(DebugBasicType), Subprogram(DebugSubprogramTypeData), } #[derive(Debug, 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(Debug, Clone)] pub struct DebugSubprogramTypeData { pub parameters: Vec, pub flags: DwarfFlags, } pub struct DebugSubprogramType { pub params: Vec, 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, }