Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

Commit

Permalink
Dwarf: debug_info for call instruction and tracing locals (#415)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcivlin authored Mar 4, 2024
1 parent 5acd116 commit dc2fc34
Show file tree
Hide file tree
Showing 15 changed files with 1,438 additions and 462 deletions.
761 changes: 578 additions & 183 deletions language/solana/move-to-solana/src/stackless/dwarf.rs

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion language/solana/move-to-solana/src/stackless/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ impl<'mm, 'up> EntrypointGenerator<'mm, 'up> {
.llvm_builder
.load(self.retval, self.llvm_cx.int_type(64), "exit_code");
self.llvm_builder.build_return(ret);
self.llvm_module.verify();

if log_enabled!(target: "entry_point", Level::Debug) {
self.llvm_module.dump();
Expand Down
104 changes: 90 additions & 14 deletions language/solana/move-to-solana/src/stackless/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! - Hides weirdly mutable array pointers.
//! - Provides high-level instruction builders compatible with the stackless bytecode model.
use libc::abort;
use llvm_extra_sys::*;
use llvm_sys::{core::*, prelude::*, target::*, target_machine::*, LLVMOpcode, LLVMUnnamedAddr};
use log::debug;
Expand All @@ -39,7 +40,7 @@ pub use llvm_sys::{

use crate::stackless::{
dwarf::{from_raw_slice_to_string, DIBuilder},
GlobalContext,
GlobalContext, ModuleContext,
};

pub fn initialize_sbf() {
Expand Down Expand Up @@ -107,7 +108,7 @@ impl Context {
pub fn create_di_builder<'up>(
&'up self,
g_ctx: &'up GlobalContext,
module: &mut Module,
module: &Module,
source: &str,
debug: bool,
) -> DIBuilder {
Expand Down Expand Up @@ -257,7 +258,7 @@ impl Context {
pub struct TargetData(LLVMTargetDataRef);

#[derive(Debug)]
pub struct Module(LLVMModuleRef);
pub struct Module(pub LLVMModuleRef);

impl Drop for Module {
fn drop(&mut self) {
Expand Down Expand Up @@ -384,11 +385,20 @@ impl Module {
pub fn verify(&self) {
use llvm_sys::analysis::*;
unsafe {
LLVMVerifyModule(
let name = &self.get_module_id();
let addr = &self.0;
debug!(target: "module", "{name} module verification address {:#?}", addr);
if LLVMVerifyModule(
self.0,
LLVMVerifierFailureAction::LLVMAbortProcessAction,
LLVMVerifierFailureAction::LLVMPrintMessageAction,
ptr::null_mut(),
);
) == 1
{
println!("\n{} module verification failed\n", &self.get_module_id());
let module_info = &self.print_to_str();
debug!(target: "module", "Module content:\n{module_info}\n");
abort();
}
}
}

Expand Down Expand Up @@ -482,9 +492,17 @@ impl Module {

Ok(())
}

pub fn print_to_str(&self) -> &str {
unsafe {
CStr::from_ptr(LLVMPrintModuleToString(self.0))
.to_str()
.unwrap()
}
}
}

pub struct Builder(LLVMBuilderRef);
pub struct Builder(pub LLVMBuilderRef);

impl Drop for Builder {
fn drop(&mut self) {
Expand Down Expand Up @@ -534,9 +552,9 @@ impl Builder {
dst: Alloca,
) -> (*mut LLVMValue, *mut LLVMValue) {
unsafe {
let tmp_reg = LLVMBuildLoad2(self.0, ty.0, src.0, "load_store_tmp".cstr());
let store = LLVMBuildStore(self.0, tmp_reg, dst.0);
(tmp_reg, store)
let load = LLVMBuildLoad2(self.0, ty.0, src.0, "load_store_tmp".cstr());
let store = LLVMBuildStore(self.0, load, dst.0);
(load, store)
}
}

Expand Down Expand Up @@ -878,6 +896,7 @@ impl Builder {
fnval: Function,
args: &[(Type, Alloca)],
dst: &[(Type, Alloca)],
instr_dbg: super::dwarf::PublicInstruction<'_>,
) {
unsafe {
let args = args
Expand All @@ -888,7 +907,59 @@ impl Builder {
AnyValue(LLVMBuildLoad2(self.0, ty.0, val.0, name.cstr()))
})
.collect::<Vec<_>>();
self.call_store(fnval, &args, dst)
self.call_store_with_dst(fnval, &args, dst, instr_dbg)
}
}

fn call_store_with_dst(
&self,
fnval: Function,
args: &[AnyValue],
dst: &[(Type, Alloca)],
instr_dbg: super::dwarf::PublicInstruction<'_>,
) {
let fnty = fnval.llvm_type();

unsafe {
let mut args = args.iter().map(|a| a.0).collect::<Vec<_>>();
let func_name = get_name(fnval.0);
let ret = LLVMBuildCall2(
self.0,
fnty.0,
fnval.0,
args.as_mut_ptr(),
args.len() as libc::c_uint,
(if dst.is_empty() { "" } else { "retval" }).cstr(),
);
let ret_name = get_name(ret);
instr_dbg.create_call(ret);
debug!(target: "functions", "call_store function {} ret {}", &func_name, &ret_name);

if dst.is_empty() {
// No return values.
} else if dst.len() == 1 {
// Single return value.
let alloca = dst[0].1;
let alloca_name = alloca.get_name();
let ret = LLVMBuildStore(self.0, ret, dst[0].1 .0);
let ret_name = get_name(ret);
debug!(target: "functions", "call_store alloca_name {} ret {} alloca {:#?} ", &alloca_name, &ret_name, alloca);
} else {
// Multiple return values-- unwrap the struct.
let extracts = dst
.iter()
.enumerate()
.map(|(i, (_ty, dval))| {
let _name = dval.get_name();
let name = format!("extract_{i}");
let ev = LLVMBuildExtractValue(self.0, ret, i as libc::c_uint, name.cstr());
(ev, dval)
})
.collect::<Vec<_>>();
for (ev, dval) in extracts {
LLVMBuildStore(self.0, ev, dval.0);
}
}
}
}

Expand Down Expand Up @@ -1159,7 +1230,7 @@ impl FunctionType {
}

#[derive(Debug, Copy, Clone)]
pub struct Function(LLVMValueRef);
pub struct Function(pub LLVMValueRef);

impl Function {
pub fn as_gv(&self) -> Global {
Expand Down Expand Up @@ -1218,10 +1289,15 @@ impl Function {
unsafe { Type(LLVMGetReturnType(LLVMGlobalGetValueType(self.0))) }
}

pub fn verify(&self) {
pub fn verify(&self, module_cx: &ModuleContext<'_, '_>) {
use llvm_sys::analysis::*;
let module_info = module_cx.llvm_module.print_to_str();
debug!(target: "function", "Module content:\n{module_info}\n");
unsafe {
LLVMVerifyFunction(self.0, LLVMVerifierFailureAction::LLVMAbortProcessAction);
if LLVMVerifyFunction(self.0, LLVMVerifierFailureAction::LLVMPrintMessageAction) == 1 {
println!("{} function verifiction failed", &self.get_name());
abort();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ impl<'mm: 'up, 'up> ModuleContext<'mm, 'up> {
self.entrypoint_generator.add_entries(self);
}

self.llvm_module.verify();
self.llvm_di_builder
.print_log_unresoled_types(UnresolvedPrintLogLevel::Warning);
self.llvm_di_builder.finalize();
self.llvm_module.verify();
}

/// Generate LLVM IR struct declarations for all Move structures.
Expand Down
4 changes: 3 additions & 1 deletion language/solana/move-to-solana/src/stackless/rttydesc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ impl<'mm, 'up> RttyContext<'mm, 'up> {
let tyv_display = &mty.display(ty_display_ctx);
debug!(target: "rtty", "get_llvm_type_for_move_vector: {tyv_display}");
}
m_ctx.llvm_di_builder.create_vector(mvec, &ty, llmod, None);
m_ctx
.llvm_di_builder
.create_vector(m_ctx, mvec, &ty, llmod, None);
ty
}

Expand Down
43 changes: 24 additions & 19 deletions language/solana/move-to-solana/src/stackless/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ impl<'up> GlobalContext<'up> {
let Self { env, llvm_cx, .. } = self;

let m_env = env.get_module(id);
let llvm_builder = llvm_cx.create_builder();
let modname = m_env.llvm_module_name();
debug!(target: "dwarf", "Create DWARF for module {:#?} with source {:#?}", modname, source);
let mut module = self.llvm_cx.create_module(&modname);
let llvm_di_builder = llvm_cx.create_di_builder(self, &mut module, source, options.debug);
// DIBuilder does not depend on Builder and can be created first
let llvm_di_builder = llvm_cx.create_di_builder(self, llmod, source, options.debug);
let llvm_builder = llvm_cx.create_builder();
let rtty_cx = RttyContext::new(self.env, &self.llvm_cx, llmod);
ModuleContext {
env: self.env.get_module(id),
Expand Down Expand Up @@ -225,10 +225,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
let map_node_to_type: BTreeMap<mm::NodeId, move_model::ty::Type> = g_env
.get_nodes()
.iter()
.map(|nd| {
debug!(target: "nodes", "{:#?} {:#?}", nd, g_env.get_node_loc(*nd));
(*nd, g_env.get_node_type(*nd))
})
.map(|nd| (*nd, g_env.get_node_type(*nd)))
.collect();
debug!(target: "nodes", "\n{:#?}", &map_node_to_type);

Expand Down Expand Up @@ -293,7 +290,6 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
name = format!("local_{}__{}", i, s);
}
let llval = self.module_cx.llvm_builder.build_alloca(llty, &name);
debug!(target: "functions", "adding {i} local {}:\n {:#?}\n {:#?}\n {:#?}\n", &name, mty, llty, llval);
self.locals.push(Local {
mty: mty.instantiate(self.type_params),
llty,
Expand Down Expand Up @@ -349,14 +345,17 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
}
}

let di_func = self.module_cx.llvm_di_builder.create_function(&self, None);

// Translate instructions
for instr in &fn_data.code {
self.translate_instruction(instr);
}

ll_fn.verify();

self.module_cx.llvm_di_builder.create_function(&self, None);
self.module_cx
.llvm_di_builder
.finalize_function(&self, di_func);
ll_fn.verify(self.module_cx);
}

fn translate_instruction(&mut self, instr: &sbc::Bytecode) {
Expand All @@ -382,7 +381,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
| mty::PrimitiveType::U256,
) => {
let (load, store) = builder.load_store(llty, src_llval, dst_llval);
builder_di.create_load_store(instr_dbg, load, store, mty);
instr_dbg.create_load_store(load, store, mty, llty, src_llval, dst_llval);
}
mty::Type::Reference(_, _) => {
builder.load_store(llty, src_llval, dst_llval);
Expand Down Expand Up @@ -484,7 +483,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
}
}
sbc::Bytecode::Call(_, dst, op, src, None) => {
self.translate_call(dst, op, src);
self.translate_call(dst, op, src, instr, instr_dbg);
}
sbc::Bytecode::Ret(_, vals) => match vals.len() {
0 => {
Expand Down Expand Up @@ -531,7 +530,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
builder.position_at_end(llbb);
}
sbc::Bytecode::Abort(_, local) => {
self.emit_rtcall(RtCall::Abort(*local));
self.emit_rtcall(RtCall::Abort(*local), instr);
}
sbc::Bytecode::Nop(_) => {}
_ => {
Expand Down Expand Up @@ -1165,6 +1164,8 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
dst: &[mast::TempIndex],
op: &sbc::Operation,
src: &[mast::TempIndex],
instr: &sbc::Bytecode,
instr_dbg: super::dwarf::PublicInstruction<'_>,
) {
use sbc::Operation;
let emitter_nop: CheckEmitterFn = (|_, _| (), EmitterFnKind::PreCheck);
Expand All @@ -1176,7 +1177,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
let fn_name = &self.env.get_name_str();
debug!(target: "dwarf", "translate_call function {fn_name} op {:#?} dst {:#?} src {:#?} types {:#?}",
op, dst, src, &types);
self.translate_fun_call(*mod_id, *fun_id, &types, dst, src);
self.translate_fun_call(*mod_id, *fun_id, &types, dst, src, instr, instr_dbg);
}
Operation::BorrowLoc => {
assert_eq!(src.len(), 1);
Expand Down Expand Up @@ -1284,7 +1285,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
mty::Type::Struct(_, _, _) => ( /* nop */ ),
mty::Type::Reference(_, _) => { /* nop */ }
mty::Type::Vector(elt_mty) => {
self.emit_rtcall(RtCall::VecDestroy(idx, (**elt_mty).clone()));
self.emit_rtcall(RtCall::VecDestroy(idx, (**elt_mty).clone()), instr);
}
_ => todo!("{mty:?}"),
}
Expand Down Expand Up @@ -1526,6 +1527,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
types: &[mty::Type],
dst: &[mast::TempIndex],
src: &[mast::TempIndex],
_instr: &sbc::Bytecode,
) {
let types = mty::Type::instantiate_vec(types.to_vec(), self.type_params);
let typarams = self.module_cx.get_rttydesc_ptrs(&types);
Expand Down Expand Up @@ -1599,14 +1601,16 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
types: &[mty::Type],
dst: &[mast::TempIndex],
src: &[mast::TempIndex],
instr: &sbc::Bytecode,
instr_dbg: super::dwarf::PublicInstruction<'_>,
) {
// Handle native function calls specially.
{
let global_env = &self.env.module_env.env;
let fn_id = fun_id.qualified(mod_id);
let fn_env = global_env.get_function(fn_id);
if fn_env.is_native() {
return self.translate_native_fun_call(mod_id, fun_id, types, dst, src);
return self.translate_native_fun_call(mod_id, fun_id, types, dst, src, instr);
}
}

Expand Down Expand Up @@ -1658,7 +1662,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {

self.module_cx
.llvm_builder
.load_call_store(ll_fn, &src, &dst);
.load_call_store(ll_fn, &src, &dst, instr_dbg);
}

// Optional vec_mty is only used for a vector literal (i.e., Constant<Vector(Vec<Constant>))
Expand Down Expand Up @@ -1868,7 +1872,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
(res_val.llvm_type(), res_ptr)
}

fn emit_rtcall(&self, rtcall: RtCall) {
fn emit_rtcall(&self, rtcall: RtCall, _instr: &sbc::Bytecode) {
match &rtcall {
RtCall::Abort(local_idx) => {
let llfn = ModuleContext::get_runtime_function(
Expand All @@ -1883,6 +1887,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
llfn,
&[(local_llty, local_llval)],
&[],
super::dwarf::PublicInstruction::none(),
);
self.module_cx.llvm_builder.build_unreachable();
}
Expand Down
3 changes: 2 additions & 1 deletion language/tools/move-mv-llvm-compiler/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ fn main() -> anyhow::Result<()> {
Err(err) => eprintln!("Error creating directory: {}", err),
}
}
if let Some(module_di) = mod_cx.llvm_di_builder.module_di() {
if let Some(_module_di) = mod_cx.llvm_di_builder.module_di() {
let module_di = mod_cx.llvm_module.0;
let output_file = format!("{}.debug_info", output_file);
llvm_write_to_file(module_di, true, &output_file)?;
}
Expand Down
Loading

0 comments on commit dc2fc34

Please sign in to comment.