mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-28 03:57:55 +00:00
experimental: support for debug info (#118)
Signed-off-by: wpt967 <matt.aw@parity.io> Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
@@ -1,7 +1,43 @@
|
||||
//! The LLVM debug information.
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use inkwell::debug_info::AsDIScope;
|
||||
use num::Zero;
|
||||
use inkwell::debug_info::DIScope;
|
||||
|
||||
/// Debug info scope stack
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ScopeStack<'ctx> {
|
||||
stack: Vec<DIScope<'ctx>>,
|
||||
}
|
||||
|
||||
// Abstract the type of the DIScope stack.
|
||||
impl<'ctx> ScopeStack<'ctx> {
|
||||
pub fn from(item: DIScope<'ctx>) -> Self {
|
||||
Self { stack: vec![item] }
|
||||
}
|
||||
|
||||
/// Return the top of the scope stack, or None if the stack is empty.
|
||||
pub fn top(&self) -> Option<DIScope<'ctx>> {
|
||||
self.stack.last().copied()
|
||||
}
|
||||
|
||||
/// Push a scope onto the stack.
|
||||
pub fn push(&mut self, scope: DIScope<'ctx>) {
|
||||
self.stack.push(scope)
|
||||
}
|
||||
|
||||
/// Pop the scope at the top of the stack and return it.
|
||||
/// Return None if the stack is empty.
|
||||
pub fn pop(&mut self) -> Option<DIScope<'ctx>> {
|
||||
self.stack.pop()
|
||||
}
|
||||
|
||||
/// Return the number of scopes on the stack.
|
||||
pub fn len(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// The LLVM debug information.
|
||||
pub struct DebugInfo<'ctx> {
|
||||
@@ -9,6 +45,8 @@ pub struct DebugInfo<'ctx> {
|
||||
compile_unit: inkwell::debug_info::DICompileUnit<'ctx>,
|
||||
/// The debug info builder.
|
||||
builder: inkwell::debug_info::DebugInfoBuilder<'ctx>,
|
||||
/// Enclosing debug info scopes.
|
||||
scope_stack: RefCell<ScopeStack<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'ctx> DebugInfo<'ctx> {
|
||||
@@ -35,19 +73,43 @@ impl<'ctx> DebugInfo<'ctx> {
|
||||
Self {
|
||||
compile_unit,
|
||||
builder,
|
||||
scope_stack: RefCell::new(ScopeStack::from(compile_unit.as_debug_info_scope())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare an LLVM-IR module for debug-info generation
|
||||
pub fn initialize_module(
|
||||
&self,
|
||||
llvm: &'ctx inkwell::context::Context,
|
||||
module: &inkwell::module::Module<'ctx>,
|
||||
) {
|
||||
let debug_metadata_value = llvm
|
||||
.i32_type()
|
||||
.const_int(inkwell::debug_info::debug_metadata_version() as u64, false);
|
||||
module.add_basic_value_flag(
|
||||
"Debug Info Version",
|
||||
inkwell::module::FlagBehavior::Warning,
|
||||
debug_metadata_value,
|
||||
);
|
||||
self.push_scope(self.compilation_unit().get_file().as_debug_info_scope());
|
||||
}
|
||||
|
||||
/// Finalize debug-info for an LLVM-IR module.
|
||||
pub fn finalize_module(&self) {
|
||||
self.builder().finalize()
|
||||
}
|
||||
|
||||
/// Creates a function info.
|
||||
pub fn create_function(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> {
|
||||
let flags = inkwell::debug_info::DIFlagsConstants::ZERO;
|
||||
let subroutine_type = self.builder.create_subroutine_type(
|
||||
self.compile_unit.get_file(),
|
||||
Some(self.create_type(revive_common::BIT_LENGTH_FIELD)?),
|
||||
Some(self.create_word_type(Some(flags))?.as_type()),
|
||||
&[],
|
||||
inkwell::debug_info::DIFlags::zero(),
|
||||
flags,
|
||||
);
|
||||
|
||||
let function = self.builder.create_function(
|
||||
@@ -60,7 +122,7 @@ impl<'ctx> DebugInfo<'ctx> {
|
||||
true,
|
||||
false,
|
||||
1,
|
||||
inkwell::debug_info::DIFlags::zero(),
|
||||
flags,
|
||||
false,
|
||||
);
|
||||
|
||||
@@ -74,24 +136,55 @@ impl<'ctx> DebugInfo<'ctx> {
|
||||
Ok(function)
|
||||
}
|
||||
|
||||
/// Creates a primitive type info.
|
||||
pub fn create_type(
|
||||
/// Creates primitive integer type debug-info.
|
||||
pub fn create_primitive_type(
|
||||
&self,
|
||||
bit_length: usize,
|
||||
) -> anyhow::Result<inkwell::debug_info::DIType<'ctx>> {
|
||||
flags: Option<inkwell::debug_info::DIFlags>,
|
||||
) -> anyhow::Result<inkwell::debug_info::DIBasicType<'ctx>> {
|
||||
let di_flags = flags.unwrap_or(inkwell::debug_info::DIFlagsConstants::ZERO);
|
||||
let di_encoding: u32 = 0;
|
||||
let type_name = String::from("U") + bit_length.to_string().as_str();
|
||||
self.builder
|
||||
.create_basic_type(
|
||||
"U256",
|
||||
bit_length as u64,
|
||||
0,
|
||||
inkwell::debug_info::DIFlags::zero(),
|
||||
)
|
||||
.map(|basic_type| basic_type.as_type())
|
||||
.create_basic_type(type_name.as_str(), bit_length as u64, di_encoding, di_flags)
|
||||
.map_err(|error| anyhow::anyhow!("Debug info error: {}", error))
|
||||
}
|
||||
|
||||
/// Finalizes the builder.
|
||||
pub fn finalize(&self) {
|
||||
self.builder.finalize();
|
||||
/// Returns the debug-info model of word-sized integer types.
|
||||
pub fn create_word_type(
|
||||
&self,
|
||||
flags: Option<inkwell::debug_info::DIFlags>,
|
||||
) -> anyhow::Result<inkwell::debug_info::DIBasicType<'ctx>> {
|
||||
self.create_primitive_type(revive_common::BIT_LENGTH_WORD, flags)
|
||||
}
|
||||
|
||||
/// Return the DIBuilder.
|
||||
pub fn builder(&self) -> &inkwell::debug_info::DebugInfoBuilder<'ctx> {
|
||||
&self.builder
|
||||
}
|
||||
|
||||
/// Return the compilation unit. {
|
||||
pub fn compilation_unit(&self) -> &inkwell::debug_info::DICompileUnit<'ctx> {
|
||||
&self.compile_unit
|
||||
}
|
||||
|
||||
/// Push a debug-info scope onto the stack.
|
||||
pub fn push_scope(&self, scope: DIScope<'ctx>) {
|
||||
self.scope_stack.borrow_mut().push(scope)
|
||||
}
|
||||
|
||||
/// Pop the top of the debug-info scope stack and return it.
|
||||
pub fn pop_scope(&self) -> Option<DIScope<'ctx>> {
|
||||
self.scope_stack.borrow_mut().pop()
|
||||
}
|
||||
|
||||
/// Return the top of the debug-info scope stack.
|
||||
pub fn top_scope(&self) -> Option<DIScope<'ctx>> {
|
||||
self.scope_stack.borrow().top()
|
||||
}
|
||||
|
||||
/// Return the number of debug-info scopes on the scope stack.
|
||||
pub fn num_scopes(&self) -> usize {
|
||||
self.scope_stack.borrow().len()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user