From e80719f678589df9c53e3cbd9ae8c558090362aa Mon Sep 17 00:00:00 2001 From: TheCPP Date: Sat, 31 Aug 2024 21:51:52 +0200 Subject: [PATCH] [DEBUG] starting debug information --- Cargo.lock | 24 +++++++ Cargo.toml | 1 + src/Obj/wrapper.rs | 157 +++++++++++++++++++++++++++++++++++++++++---- src/debug.rs | 62 ++++++++++++++++++ src/lib.rs | 3 + 5 files changed, 234 insertions(+), 13 deletions(-) create mode 100644 src/debug.rs diff --git a/Cargo.lock b/Cargo.lock index db2ca9f7..70956844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "flate2" version = "1.0.30" @@ -69,6 +75,17 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -214,6 +231,12 @@ dependencies = [ "ygen", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -286,6 +309,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "ygen" version = "0.1.1" dependencies = [ + "gimli", "logos", "object", "proc", diff --git a/Cargo.toml b/Cargo.toml index 5b84298c..b65fac05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ keywords = ["compiler", "codegen", "llvm"] rustdoc-args = ["--allow", "warnings"] [dependencies] +gimli = { version = "0.31.0", features = ["write"] } logos = "0.14.0" object = { version = "0.36.1", features = ["write"] } proc = { workspace = true } diff --git a/src/Obj/wrapper.rs b/src/Obj/wrapper.rs index 2401da31..1a2824e3 100644 --- a/src/Obj/wrapper.rs +++ b/src/Obj/wrapper.rs @@ -1,6 +1,11 @@ -use object::write::{Relocation, SectionId, Symbol, SymbolId, SymbolSection}; -use object::{Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationFlags, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope}; - +use gimli::write::{Dwarf, DwarfUnit, EndianVec, RelocateWriter}; +use gimli::LittleEndian; +use object::write::{Object, Relocation, SectionId, Symbol, SymbolId, SymbolSection}; +use object::{Architecture, BinaryFormat, Endianness, RelocationEncoding, + RelocationFlags, RelocationKind, SectionKind, SymbolFlags, SymbolKind, + SymbolScope}; + +use crate::debug::DebugRegistry; use crate::prelude::Triple; use crate::Target::{self, Arch, CallConv}; use std::collections::BTreeMap; @@ -24,6 +29,39 @@ impl std::fmt::Display for ObjectError { impl std::error::Error for ObjectError {} +#[derive(Clone)] +struct Section { + data: EndianVec, + relocations: Vec, + id: Option, +} + +impl Section { + fn new() -> Self { + Self { + data: EndianVec::new(LittleEndian), + relocations: Vec::new(), + id: None, + } + } +} + +impl RelocateWriter for Section { + type Writer = EndianVec; + + fn writer(&self) -> &Self::Writer { + &self.data + } + + fn writer_mut(&mut self) -> &mut Self::Writer { + &mut self.data + } + + fn relocate(&mut self, relocation: gimli::write::Relocation) { + self.relocations.push(relocation); + } +} + /// A decl to say what's the label/func #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Decl { @@ -68,7 +106,10 @@ pub struct ObjectBuilder { decls: Vec<(String, Decl, Linkage)>, - triple: Triple + triple: Triple, + + /// include debugging information + debug: bool, } impl ObjectBuilder { @@ -78,10 +119,11 @@ impl ObjectBuilder { defines: BTreeMap::new(), links: vec![], - decls: vec![], - triple: triple + triple: triple, + + debug: false, } } @@ -108,8 +150,7 @@ impl ObjectBuilder { } /// Writes the object file into the the specified file - pub fn emit(&self, file: File) -> Result<(), Box> { - + pub fn emit(&self, file: File, debug: Option) -> Result<(), Box> { let align = 1; let mut obj = object::write::Object::new({ @@ -172,7 +213,7 @@ impl ObjectBuilder { let secData = obj.add_section(vec![], ".data".as_bytes().to_vec(), SectionKind::Data); let secConsts = obj.add_section(vec![], ".rodata".as_bytes().to_vec(), SectionKind::ReadOnlyData); - let mut syms: BTreeMap, Option, SymbolId, Decl)> = BTreeMap::new(); + let mut syms: BTreeMap, Option, SymbolId, Decl, /*size*/u64)> = BTreeMap::new(); for (name, data) in &self.defines { let name = name.to_owned(); @@ -247,15 +288,15 @@ impl ObjectBuilder { Decl::Constant => obj.add_symbol_data(sym, secConsts, &data, align), }; - syms.insert(name.clone(), (None, Some(def_offset), sym, *decl)); + syms.insert(name.clone(), (None, Some(def_offset), sym, *decl, data.len() as u64)); } else { - syms.insert(name.clone(), (None, None, sym, *decl)); + syms.insert(name.clone(), (None, None, sym, *decl, data.len() as u64)); } } for link in &self.links { - let (_, off, _, _) = syms.get(&link.from).unwrap(); - let (_, _, to_sym, ty) = syms.get(&link.to).unwrap(); + let (_, off, _, _, _) = syms.get(&link.from).unwrap(); + let (_, _, to_sym, ty, _) = syms.get(&link.to).unwrap(); let mut addend = 0; let mut offset = 0; @@ -291,8 +332,98 @@ impl ObjectBuilder { })?; } + if let Some(debug) = debug { + if self.debug { + self.emit_dwarf(&mut obj, &syms, debug)?; + } + } + obj.write_stream(file)?; Ok(()) } + + fn emit_debug_info(&self, dwarf: &mut DwarfUnit, name: &String, id: &SymbolId, size: u64, debug: &DebugRegistry) { + + } + + fn emit_dwarf(&self, obj: &mut Object<'_>, syms: &BTreeMap, Option, SymbolId, Decl, u64)>, debug: DebugRegistry) -> Result<(), Box> { + use gimli::write::*; + let encoding = gimli::Encoding { + address_size: 8, + format: gimli::Format::Dwarf32, + version: 5, + }; + + let mut dwarf = DwarfUnit::new(encoding); + let root = dwarf.unit.root(); + let entry = dwarf.unit.get_mut(root); + + entry.set(gimli::DW_AT_producer, + AttributeValue::String(debug.producer.as_bytes().to_vec()) + ); + + entry.set(gimli::DW_AT_language, + AttributeValue::Language(debug.lang) + ); + entry.set(gimli::DW_AT_name, AttributeValue::String(debug.file.as_bytes().to_vec())); + entry.set(gimli::DW_AT_comp_dir, AttributeValue::String(debug.dir.as_bytes().to_vec())); + + let mut sections = Sections::new(self::Section::new()); + dwarf.write(&mut sections)?; + + for (name, (_, _, id, decl, size)) in syms { + if *decl == Decl::Function { + self.emit_debug_info(&mut dwarf, name, id, *size, &debug); + } + } + + sections.for_each_mut(|id, section| -> object::write::Result<()> { + if section.data.len() == 0 { + return Ok(()); + } + let section_id = obj.add_section(Vec::new(), id.name().into(), object::SectionKind::Debug); + obj.set_section_data(section_id, section.data.take(), 1); + + section.id = Some(section_id); + Ok(()) + })?; + + sections.for_each(|_, section| -> object::write::Result<()> { + let Some(section_id) = section.id else { + debug_assert!(section.relocations.is_empty()); + return Ok(()); + }; + for reloc in §ion.relocations { + // The `eh_pe` field is not used in this example because we are not writing + // unwind information. + debug_assert!(reloc.eh_pe.is_none()); + let symbol = match reloc.target { + RelocationTarget::Section(id) => { + obj.section_symbol(sections.get(id).unwrap().id.unwrap()) + } + RelocationTarget::Symbol(_) => todo!(), + }; + obj.add_relocation( + section_id, + object::write::Relocation { + offset: reloc.offset as u64, + symbol, + addend: reloc.addend, + flags: object::RelocationFlags::Generic { + kind: match reloc.target { + RelocationTarget::Section(_) => object::RelocationKind::SectionOffset, + _ => object::RelocationKind::Absolute + }, + encoding: object::RelocationEncoding::Generic, + size: reloc.size * 8, + }, + }, + )?; + } + Ok(()) + })?; + + Ok(()) + } } \ No newline at end of file diff --git a/src/debug.rs b/src/debug.rs new file mode 100644 index 00000000..ce30a9b5 --- /dev/null +++ b/src/debug.rs @@ -0,0 +1,62 @@ +use std::path::Path; + +use gimli::DwLang; + +/// The debugging location +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DebugLocation { + /// the line which the debug location is refering to + pub line: u64, + /// the coloumn which the debug location is refering to + pub col: u64, +} + +/// A variable to debug +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DebugVariable { + pub(crate) name: String, +} + +impl DebugVariable { + /// Creates a new debug variable + pub fn new(name: String) -> Self { + Self { + name: name + } + } +} + +/// The debug register is used to store files and their file id +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DebugRegistry { + pub(crate) file: String, + pub(crate) dir: String, + current_id: u64, + + pub(crate) locs: Vec, + pub(crate) vars: Vec, + + pub(crate) producer: String, + pub(crate) lang: DwLang +} + +impl DebugRegistry { + /// Creates a new debug registry + pub fn new(producer: String, lang: DwLang, infile: &Path) -> Self { + let file = infile.file_name().expect("expected filename").to_str().unwrap().to_string(); + let mut tmp = format!("{}", file).chars().rev().collect::(); + tmp.remove(file.chars().count()); + Self { + file: file, + dir: tmp.chars().rev().collect::(), + locs: vec![], + vars: vec![], + + lang: lang, + + producer: producer, + + current_id: 0, + } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0693593c..cc1ae1ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,9 @@ pub mod Obj; /// Shared code generation classes (mainly used for register based architectures like x86_64, aarch64, ...) pub mod CodeGen; +/// Debugging information +pub mod debug; + /// Most common used functions, classes, enums of this Libary pub mod prelude { pub use crate::IR::*;