| use std::ptr; |
| |
| use libc::c_uint; |
| use rustc_abi::Align; |
| |
| use crate::llvm::debuginfo::DIBuilder; |
| use crate::llvm::{self, Module, ToLlvmBool}; |
| |
| /// Owning pointer to a `DIBuilder<'ll>` that will dispose of the builder |
| /// when dropped. Use `.as_ref()` to get the underlying `&DIBuilder` |
| /// needed for debuginfo FFI calls. |
| pub(crate) struct DIBuilderBox<'ll> { |
| raw: ptr::NonNull<DIBuilder<'ll>>, |
| } |
| |
| impl<'ll> DIBuilderBox<'ll> { |
| pub(crate) fn new(llmod: &'ll Module) -> Self { |
| let raw = unsafe { llvm::LLVMCreateDIBuilder(llmod) }; |
| let raw = ptr::NonNull::new(raw).unwrap(); |
| Self { raw } |
| } |
| |
| pub(crate) fn as_ref(&self) -> &DIBuilder<'ll> { |
| // SAFETY: This is an owning pointer, so `&DIBuilder` is valid |
| // for as long as `&self` is. |
| unsafe { self.raw.as_ref() } |
| } |
| } |
| |
| impl<'ll> Drop for DIBuilderBox<'ll> { |
| fn drop(&mut self) { |
| unsafe { llvm::LLVMDisposeDIBuilder(self.raw) }; |
| } |
| } |
| |
| /// Extension trait for defining safe wrappers and helper methods on |
| /// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate. |
| pub(crate) trait DIBuilderExt<'ll> { |
| fn as_di_builder(&self) -> &DIBuilder<'ll>; |
| |
| fn create_expression(&self, addr_ops: &[u64]) -> &'ll llvm::Metadata { |
| let this = self.as_di_builder(); |
| unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) } |
| } |
| |
| fn create_static_variable( |
| &self, |
| scope: Option<&'ll llvm::Metadata>, |
| name: &str, |
| linkage_name: &str, |
| file: &'ll llvm::Metadata, |
| line_number: c_uint, |
| ty: &'ll llvm::Metadata, |
| is_local_to_unit: bool, |
| val: &'ll llvm::Value, |
| decl: Option<&'ll llvm::Metadata>, |
| align: Option<Align>, |
| ) -> &'ll llvm::Metadata { |
| let this = self.as_di_builder(); |
| let align_in_bits = align.map_or(0, |align| align.bits() as u32); |
| |
| // `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we |
| // gave it a null `Expr` pointer, so give it an empty expression |
| // instead, which is what the C++ `createGlobalVariableExpression` |
| // method would do if given a null `DIExpression` pointer. |
| let expr = self.create_expression(&[]); |
| |
| let global_var_expr = unsafe { |
| llvm::LLVMDIBuilderCreateGlobalVariableExpression( |
| this, |
| scope, |
| name.as_ptr(), |
| name.len(), |
| linkage_name.as_ptr(), |
| linkage_name.len(), |
| file, |
| line_number, |
| ty, |
| is_local_to_unit.to_llvm_bool(), |
| expr, |
| decl, |
| align_in_bits, |
| ) |
| }; |
| |
| unsafe { llvm::LLVMGlobalSetMetadata(val, llvm::MD_dbg, global_var_expr) }; |
| |
| global_var_expr |
| } |
| } |
| |
| impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> { |
| fn as_di_builder(&self) -> &DIBuilder<'ll> { |
| self |
| } |
| |
| // All other methods have default bodies that rely on `as_di_builder`. |
| } |