Skip to content

Commit

Permalink
[DEBUG] starting debug information
Browse files Browse the repository at this point in the history
  • Loading branch information
Cr0a3 committed Sep 26, 2024
1 parent 9131b0a commit 830fb6a
Show file tree
Hide file tree
Showing 12 changed files with 344 additions and 20 deletions.
75 changes: 75 additions & 0 deletions examples/debug_metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::{error::Error, fs::OpenOptions, path::{Path, PathBuf}};
use gimli::DW_LANG_C;
use ygen::{prelude::*, Support::ColorProfile, Target::initializeAllTargets};


// hello_world.c:
// 1 #include <stdout.h>
// 2
// 3 int main() {
// 4 printf("Hello World!");
// 5 return 0;
// 6 }

pub fn main() -> Result<(), Box<dyn Error>> {
let mut module = Module();
module.init_dbg("ygen example".to_owned(), DW_LANG_C, &PathBuf::from("hello_world.c"));

let mut builder = IRBuilder();

let other = module.add("printf", &FnTy(vec![TypeMetadata::ptr], TypeMetadata::Void));
other.import();
let other = other.clone();

let string = module.addConst("str");
string.set("Hello World!\n\0".as_bytes().to_vec());
let string = string.clone();

let ty = FnTy(vec![], TypeMetadata::Void);

let func = module.add(
"main", &ty
);

func.extrn();

let entry = func.addBlock("entry");
builder.positionAtEnd(entry);

builder.BuildDebug(4, 0, PathBuf::from("hello_world.c"));
let string = builder.BuildAssign(&string);
builder.BuildCall( &other, vec![string] );

builder.BuildDebug(5, 0, PathBuf::from("hello_world.c"));
builder.BuildRet( Type::Void );

module.verify()?;

eprintln!(
"{}", module.dumpColored(ColorProfile::default())
);

let triple = Triple::host();

module.emitToAsmFile(
triple,
&mut initializeAllTargets(triple)?,
Path::new("out.o")
)?;

let (mut object, debug) = module
.emitMachineCode(
triple,
&mut initializeAllTargets(triple)?,
true // turns on debugging information
)?;

object.debug = true; // additionaly we need to turn debugging information in the object file on

object.emit(
OpenOptions::new().write(true).create(true).open("out.o")?,
debug
)?;

Ok(())
}
7 changes: 4 additions & 3 deletions examples/helloworld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ pub fn main() -> Result<(), Box<dyn Error>> {
module.emitToAsmFile(
triple,
&mut initializeAllTargets(triple)?,
Path::new("out.asm")
Path::new("out.o")
)?;

module
.emitMachineCode(
triple,
&mut initializeAllTargets(triple)?
)?.emit(
&mut initializeAllTargets(triple)?,
false
)?.0.emit(
OpenOptions::new().write(true).create(true).open("out.o")?, None
)?;

Expand Down
5 changes: 3 additions & 2 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ pub fn main() -> Result<(), Box<dyn Error>> {
module
.emitMachineCode(
triple,
&mut initializeAllTargets(triple)?
)?.emit(
&mut initializeAllTargets(triple)?,
false
)?.0.emit(
OpenOptions::new().write(true).create(true).open("out.o")?, None
)?;

Expand Down
6 changes: 6 additions & 0 deletions hello_world.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdout.h>

int main() {
printf("Hello World!");
return 0;
}
15 changes: 15 additions & 0 deletions src/CodeGen/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ impl Display for MachineInstr {
}
}


/// a low level operand which is portable over platforms
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MachineOperand {
Expand Down Expand Up @@ -202,6 +203,20 @@ impl Clone for Box<dyn MCInstr> {
}
}

impl PartialEq for Box<dyn MCInstr> {
fn eq(&self, other: &Self) -> bool {
self.dump().unwrap_or(vec![]) == other.dump().unwrap_or(vec![])
}
}

impl Eq for Box<dyn MCInstr> {}

impl std::hash::Hash for Box<dyn MCInstr> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.dump().unwrap_or(vec![]).hash(state);
}
}

/// a doc comment in the generated assembly code
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MCDocInstr {
Expand Down
25 changes: 24 additions & 1 deletion src/CodeGen/ir_area.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::prelude::Ir;
use crate::debug::DebugLocation;
use crate::prelude::{DebugNode, Ir};
use crate::CodeGen::MachineInstr;

use crate::IR::{ir, Block, Const, Function, Type, TypeMetadata, Var};
Expand All @@ -9,6 +10,7 @@ use super::CompilationHelper;
#[derive(Debug, Clone, Eq)]
pub struct IrCodeGenArea {
pub(crate) node: Option<Box<dyn Ir>>,
pub(crate) debug_info: Option<DebugLocation>,
pub(crate) compiled: Vec<MachineInstr>,
}

Expand All @@ -22,6 +24,7 @@ impl PartialEq for IrCodeGenArea {
pub struct IrCodeGenHelper {
pub(crate) compiled: Vec<IrCodeGenArea>,
pub(crate) helper: CompilationHelper,
pub(crate) debug_program: Option<DebugNode>,
}

impl IrCodeGenHelper {
Expand All @@ -30,8 +33,27 @@ impl IrCodeGenHelper {
Self {
compiled: vec![],
helper: compiler,
debug_program: None,
}
}

pub(crate) fn set_location_node(&mut self, node: &DebugNode) {
self.debug_program = Some(node.to_owned());
}

pub(crate) fn get_location(&self) -> Option<DebugLocation> {
if let Some(prog) = &self.debug_program {
Some(
DebugLocation {
line: prog.line as u64,
col: prog.coloumn as u64,
epilog: false,
prolog: false,
adr: 0
}
)
} else { None }
}
}

macro_rules! ir_codegen_wrap {
Expand All @@ -41,6 +63,7 @@ macro_rules! ir_codegen_wrap {
let mut area = IrCodeGenArea {
node: Some(node.clone_box()),
compiled: Vec::new(),
debug_info: self.get_location(),
};

self.helper.$func(node, &mut area.compiled, block);
Expand Down
45 changes: 41 additions & 4 deletions src/IR/module.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::{prelude::Triple, CodeGen::MachineInstr, Obj::{Decl, Link, Linkage, ObjectBuilder}, Optimizations::PassManager, Support::{ColorClass, ColorProfile}, Target::TargetRegistry};
use gimli::DwLang;

use crate::{debug::{DebugLocation, DebugRegistry}, prelude::Triple, CodeGen::MachineInstr, Obj::{Decl, Link, Linkage, ObjectBuilder}, Optimizations::PassManager, Support::{ColorClass, ColorProfile}, Target::TargetRegistry};

use super::{func::FunctionType, Const, Function, VerifyError};
use std::{collections::{BTreeMap, HashMap}, error::Error, fs::OpenOptions, io::Write, path::Path};
use std::{collections::{BTreeMap, HashMap}, error::Error, fmt::Debug, fs::OpenOptions, io::Write, path::Path};

/// ## The Module
/// The main class for handeling functions
#[derive(Debug, Clone)]
pub struct Module {
pub(crate) funcs: HashMap<String, Function>,
pub(crate) consts: HashMap<String, Const>,
pub(crate) dbg_registry: Option<DebugRegistry>,
}

impl Module {
Expand All @@ -17,9 +20,15 @@ impl Module {
Self {
funcs: HashMap::new(),
consts: HashMap::new(),
dbg_registry: None,
}
}

/// Initializes debugging metadata
pub fn init_dbg(&mut self, producer: String, lang: DwLang, infile: &Path) {
self.dbg_registry = Some(DebugRegistry::new(producer, lang, infile));
}

/// Adds a new function to the module
pub fn add(&mut self, name: &str, ty: &FunctionType) -> &mut Function {
self.funcs
Expand Down Expand Up @@ -139,7 +148,7 @@ impl Module {
}

/// emits the machine code of the module into an object file (in the form of an object builder)
pub fn emitMachineCode(&self, triple: Triple, registry: &mut TargetRegistry) -> Result<ObjectBuilder, Box<dyn Error>> {
pub fn emitMachineCode(&mut self, triple: Triple, registry: &mut TargetRegistry, debug: bool) -> Result<(ObjectBuilder, Option<DebugRegistry>), Box<dyn Error>> {
let mut obj = ObjectBuilder::new(triple);

for (_, consta) in &self.consts {
Expand Down Expand Up @@ -172,6 +181,34 @@ impl Module {
for instr in mc_instrs {
comp.extend_from_slice(&instr.encode()?.0);
}

if debug {
if let Some(reg) = self.dbg_registry.as_mut() {
reg.add_location(&func.name, DebugLocation {
line: 0,
col: 0,
epilog: false,
prolog: true,
adr: 0,
});
} else {
panic!("you need to initialize debugging information for the registry in order to use debugging information")
}
}
}

if debug {
let mut debug_info = registry.buildDebugInfo(triple.arch, block, &func)?;

for dbg in &mut debug_info {
dbg.adr += comp.len() as u64 + 1;

if let Some(reg) = self.dbg_registry.as_mut() {
reg.add_location(&func.name, *dbg);
} else {
panic!("you need to initialize debugging information for the registry in order to use debugging information")
}
}
}

blocks.insert(block.name.to_owned(), (compiled, links));
Expand Down Expand Up @@ -231,7 +268,7 @@ impl Module {
obj.define(&name, comp);
}

Ok(obj)
Ok((obj, self.dbg_registry.to_owned()))
}

/// emits all function into one asm file
Expand Down
81 changes: 81 additions & 0 deletions src/IR/nodes/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::path::PathBuf;

use crate::{Support::ColorClass, IR::IRBuilder};

use super::Ir;

/// A node which startes a debugging line programm
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DebugNode {
/// the code line
pub line: i64,
/// the code coloumn
pub coloumn: i64,
/// the file path
pub file: PathBuf,
}

impl Ir for DebugNode {
fn dump(&self) -> String {
format!("!dbg {}:{} in {:?}", self.line, self.coloumn, self.file.to_str().unwrap())
}

fn dumpColored(&self, profile: crate::Support::ColorProfile) -> String {
format!("{}: {}:{} {} {}",
profile.markup("!dbg", ColorClass::Instr),
profile.markup(&self.line.to_string(), ColorClass::Value),
profile.markup(&self.coloumn.to_string(), ColorClass::Value),
profile.markup("in", ColorClass::Instr),
profile.markup(&self.file.to_str().unwrap(), ColorClass::Value),
)
}

fn as_any(&self) -> &dyn std::any::Any {
self
}

fn verify(&self, _: crate::prelude::FunctionType) -> Result<(), crate::prelude::VerifyError> {
Ok(())
}

fn clone_box(&self) -> Box<dyn Ir> {
Box::from( self.clone() )
}

fn compile(&self, _: &mut crate::Target::TargetBackendDescr) {
// NOTHING TODO for an normal build
}

fn compile_dir(&self, compiler: &mut crate::CodeGen::IrCodeGenHelper, _: &crate::prelude::Block) {
compiler.set_location_node(self)
}

fn maybe_inline(&self, _: &std::collections::HashMap<String, crate::prelude::Type>) -> Option<Box<dyn Ir>> {
None
}

fn eval(&self) -> Option<Box<dyn Ir>> {
None
}

fn inputs(&self) -> Vec<crate::prelude::Var> {
vec![]
}

fn output(&self) -> Option<crate::prelude::Var> {
None
}
}

impl IRBuilder<'_> {
/// Sets the source location for debugging (all of the ir nodes will respond to the location till an new location is set)
pub fn BuildDebug(&mut self, line: i64, coloumn: i64, file: PathBuf) {
let block = self.blocks.get_mut(self.curr).expect("the IRBuilder needs to have an current block\nConsider creating one");

block.push_ir( Box::new( DebugNode {
line: line,
coloumn: coloumn,
file: file
} ));
}
}
2 changes: 2 additions & 0 deletions src/IR/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod cmp;
mod alloca;
mod store;
mod load;
mod debug;

pub use assign::*;
pub use call::*;
Expand All @@ -21,6 +22,7 @@ pub use ret::*;
pub use br::*;
pub use cmp::*;
pub use store::*;
pub use debug::*;

macro_rules! IrTypeWith3 {
($name:tt, $param1:tt, $param2:tt, $param3:tt) => {
Expand Down
Loading

0 comments on commit 830fb6a

Please sign in to comment.