Skip to content

Commit 8a6e8a8

Browse files
authored
Merge pull request rust-lang#222 from ghaith/master
Add support for global variable expressions in debug info
2 parents 4e8c101 + fa9c363 commit 8a6e8a8

File tree

3 files changed

+154
-3
lines changed

3 files changed

+154
-3
lines changed

src/debug_info.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@
7878
//! /* current_scope */ lexical_block.as_debug_info_scope(),
7979
//! /* inlined_at */ None);
8080
//! builder.set_current_debug_location(&context, loc);
81+
//!
82+
//! // Create global variable
83+
//! let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::Global), "gv");
84+
//!
85+
//!
86+
//! let const_v = di.create_constant_expression(10);
87+
//!
88+
//! let gv_debug = di.create_global_variable_expression(cu.get_file().as_debug_info_scope(), "gv", "", cu.get_file(), 1, ditype.as_type(), true, Some(const_v), None, 8);
89+
//!
90+
//! let meta_value: inkwell::values::BasicMetadataValueEnum = gv_debug.as_metadata_value(&context).into();
91+
//! let metadata = context.metadata_node(&[meta_value]);
92+
//! gv.set_metadata(metadata, 0);//dbg
93+
//!
8194
//! ```
8295
//!
8396
//! ## Finalize debug info
@@ -91,7 +104,8 @@ use crate::basic_block::BasicBlock;
91104
use crate::context::Context;
92105
pub use crate::debug_info::flags::{DIFlags, DIFlagsConstants};
93106
use crate::module::Module;
94-
use crate::values::{AsValueRef, BasicValueEnum, InstructionValue, PointerValue};
107+
use crate::values::{AsValueRef, BasicValueEnum, InstructionValue, PointerValue, MetadataValue};
108+
95109
#[llvm_versions(8.0..=latest)]
96110
use llvm_sys::debuginfo::LLVMDIBuilderCreateTypedef;
97111
pub use llvm_sys::debuginfo::LLVMDWARFTypeEncoding;
@@ -104,14 +118,17 @@ use llvm_sys::debuginfo::{
104118
LLVMDIBuilderCreateAutoVariable, LLVMDIBuilderCreateBasicType, LLVMDIBuilderCreateCompileUnit,
105119
LLVMDIBuilderCreateDebugLocation, LLVMDIBuilderCreateExpression, LLVMDIBuilderCreateFile,
106120
LLVMDIBuilderCreateFunction, LLVMDIBuilderCreateLexicalBlock, LLVMDIBuilderCreateMemberType,
107-
LLVMDIBuilderCreateNameSpace, LLVMDIBuilderCreateParameterVariable,
121+
LLVMDIBuilderCreateNameSpace, LLVMDIBuilderCreateParameterVariable,
108122
LLVMDIBuilderCreateStructType, LLVMDIBuilderCreateSubroutineType, LLVMDIBuilderCreateUnionType,
109123
LLVMDIBuilderFinalize, LLVMDIBuilderInsertDbgValueBefore, LLVMDIBuilderInsertDeclareAtEnd,
110124
LLVMDIBuilderInsertDeclareBefore, LLVMDILocationGetColumn, LLVMDILocationGetLine,
111125
LLVMDILocationGetScope, LLVMDITypeGetAlignInBits, LLVMDITypeGetOffsetInBits,
112126
LLVMDITypeGetSizeInBits,
113127
};
128+
#[llvm_versions(8.0..=latest)]
129+
use llvm_sys::debuginfo::{LLVMDIBuilderCreateGlobalVariableExpression,LLVMDIBuilderCreateConstantValueExpression};
114130
use llvm_sys::prelude::{LLVMDIBuilderRef, LLVMMetadataRef};
131+
use llvm_sys::core::LLVMMetadataAsValue;
115132
use std::convert::TryInto;
116133
use std::marker::PhantomData;
117134

@@ -582,6 +599,63 @@ impl<'ctx> DebugInfoBuilder<'ctx> {
582599
}
583600
}
584601

602+
#[llvm_versions(8.0..=latest)]
603+
pub fn create_global_variable_expression(
604+
&self,
605+
scope: DIScope<'ctx>,
606+
name: &str,
607+
linkage: &str,
608+
file: DIFile<'ctx>,
609+
line_no: u32,
610+
ty: DIType<'ctx>,
611+
local_to_unit: bool,
612+
expression: Option<DIExpression>,
613+
declaration: Option<DIScope>,
614+
align_in_bits: u32,
615+
) -> DIGlobalVariableExpression<'ctx> {
616+
let expression_ptr = expression.map_or(std::ptr::null_mut(), |dt| dt.metadata_ref);
617+
let decl_ptr = declaration.map_or(std::ptr::null_mut(), |dt| dt.metadata_ref);
618+
let metadata_ref = unsafe {
619+
LLVMDIBuilderCreateGlobalVariableExpression(
620+
self.builder,
621+
scope.metadata_ref,
622+
name.as_ptr() as _,
623+
name.len(),
624+
linkage.as_ptr() as _,
625+
linkage.len(),
626+
file.metadata_ref,
627+
line_no,
628+
ty.metadata_ref,
629+
local_to_unit as _,
630+
expression_ptr,
631+
decl_ptr,
632+
align_in_bits,
633+
)
634+
};
635+
DIGlobalVariableExpression {
636+
metadata_ref,
637+
_marker: PhantomData,
638+
}
639+
}
640+
641+
#[llvm_versions(8.0..=latest)]
642+
pub fn create_constant_expression(
643+
&self,
644+
value : i64,
645+
) -> DIExpression<'ctx> {
646+
let metadata_ref = unsafe {
647+
LLVMDIBuilderCreateConstantValueExpression(
648+
self.builder,
649+
value,
650+
)
651+
};
652+
653+
DIExpression {
654+
metadata_ref,
655+
_marker: PhantomData,
656+
}
657+
}
658+
585659
/// Create function parameter variable.
586660
pub fn create_parameter_variable(
587661
&self,
@@ -1028,6 +1102,21 @@ pub struct DILocalVariable<'ctx> {
10281102
_marker: PhantomData<&'ctx Context>,
10291103
}
10301104

1105+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1106+
pub struct DIGlobalVariableExpression<'ctx> {
1107+
pub(crate) metadata_ref: LLVMMetadataRef,
1108+
_marker: PhantomData<&'ctx Context>,
1109+
}
1110+
1111+
impl <'ctx> DIGlobalVariableExpression<'ctx> {
1112+
pub fn as_metadata_value(&self, context: &Context) -> MetadataValue<'ctx> {
1113+
let value = unsafe {
1114+
LLVMMetadataAsValue(context.context, self.metadata_ref)
1115+
};
1116+
MetadataValue::new(value)
1117+
}
1118+
}
1119+
10311120
/// https://llvm.org/docs/LangRef.html#diexpression
10321121
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10331122
pub struct DIExpression<'ctx> {

src/values/global_value.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use llvm_sys::core::{LLVMHasUnnamedAddr, LLVMSetUnnamedAddr};
99
use llvm_sys::core::{LLVMGetUnnamedAddress, LLVMSetUnnamedAddress};
1010
#[llvm_versions(7.0..=latest)]
1111
use llvm_sys::LLVMUnnamedAddr;
12+
#[llvm_versions(8.0..=latest)]
13+
use llvm_sys::core::LLVMGlobalSetMetadata;
1214
use llvm_sys::prelude::LLVMValueRef;
1315

1416
use std::ffi::CStr;
@@ -20,6 +22,8 @@ use crate::support::{to_c_str, LLVMString};
2022
use crate::comdat::Comdat;
2123
use crate::values::traits::AsValueRef;
2224
use crate::values::{BasicValueEnum, BasicValue, PointerValue, Value};
25+
#[llvm_versions(8.0..=latest)]
26+
use crate::values::MetadataValue;
2327

2428
// REVIEW: GlobalValues are always PointerValues. With SubTypes, we should
2529
// compress this into a PointerValue<Global> type
@@ -265,6 +269,14 @@ impl<'ctx> GlobalValue<'ctx> {
265269
}
266270
}
267271

272+
/// Sets a metadata of the given type on the GlobalValue
273+
#[llvm_versions(8.0..=latest)]
274+
pub fn set_metadata(self, metadata: MetadataValue<'ctx>, kind_id: u32) {
275+
unsafe {
276+
LLVMGlobalSetMetadata(self.as_value_ref(), kind_id, metadata.as_metadata_ref())
277+
}
278+
}
279+
268280
/// Gets a `Comdat` assigned to this `GlobalValue`, if any.
269281
#[llvm_versions(7.0..=latest)]
270282
pub fn get_comdat(self) -> Option<Comdat> {

tests/all/test_debug_info.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use inkwell::context::Context;
22
use inkwell::debug_info::{
33
AsDIScope, DIFlags, DIFlagsConstants, DISubprogram, DWARFEmissionKind, DWARFSourceLanguage,
4-
DebugInfoBuilder,
54
};
5+
#[llvm_versions(8.0..=latest)]
6+
use inkwell::debug_info::DebugInfoBuilder;
67
use inkwell::module::FlagBehavior;
78

89
#[test]
@@ -301,3 +302,52 @@ fn test_anonymous_basic_type() {
301302
Err("basic types must have names")
302303
);
303304
}
305+
306+
#[llvm_versions(8.0..=latest)]
307+
#[test]
308+
fn test_global_expressions() {
309+
let context = Context::create();
310+
let module = context.create_module("bin");
311+
312+
let (dibuilder, compile_unit) = module.create_debug_info_builder(
313+
true,
314+
DWARFSourceLanguage::C,
315+
"source_file",
316+
".",
317+
"my llvm compiler frontend",
318+
false,
319+
"",
320+
0,
321+
"",
322+
DWARFEmissionKind::Full,
323+
0,
324+
false,
325+
false,
326+
);
327+
328+
let di_type = dibuilder.create_basic_type("type_name", 0_u64, 0x00, DIFlags::ZERO);
329+
let gv = module.add_global(context.i64_type(), Some(inkwell::AddressSpace::Global), "gv");
330+
331+
let const_v = dibuilder.create_constant_expression(10);
332+
333+
let gv_debug = dibuilder.create_global_variable_expression(
334+
compile_unit.as_debug_info_scope(),
335+
"gv",
336+
"",
337+
compile_unit.get_file(),
338+
1,
339+
di_type.unwrap().as_type(),
340+
true,
341+
Some(const_v),
342+
None,
343+
8,
344+
);
345+
346+
let metadata = context.metadata_node(&[gv_debug.as_metadata_value(&context).into()]);
347+
348+
gv.set_metadata(metadata, 0);
349+
350+
// TODO: Metadata set on the global values cannot be retrieved using the C api,
351+
// therefore, it's currently not possible to test that the data was set without generating the IR
352+
assert!(gv.print_to_string().to_string().contains("!dbg"), format!("expected !dbg but generated gv was {}",gv.print_to_string()));
353+
}

0 commit comments

Comments
 (0)