use crate::metadata::{
DICompileUnit, DIFile, DIGlobalVariable, DILocalVariable, DILocation, DISubprogram, DIType,
MetadataOperand, MetadataStore,
};
use crate::types::Type;
use crate::value::{valref, SubclassKind, Value, ValueRef};
pub const DW_LANG_C89: u32 = 0x0001;
pub const DW_LANG_C: u32 = 0x0002;
pub const DW_LANG_Ada83: u32 = 0x0003;
pub const DW_LANG_C_plus_plus: u32 = 0x0004;
pub const DW_LANG_Cobol74: u32 = 0x0005;
pub const DW_LANG_Cobol85: u32 = 0x0006;
pub const DW_LANG_Fortran77: u32 = 0x0007;
pub const DW_LANG_Fortran90: u32 = 0x0008;
pub const DW_LANG_Pascal83: u32 = 0x0009;
pub const DW_LANG_Modula2: u32 = 0x000A;
pub const DW_LANG_Java: u32 = 0x000B;
pub const DW_LANG_C99: u32 = 0x000C;
pub const DW_LANG_Ada95: u32 = 0x000D;
pub const DW_LANG_Fortran95: u32 = 0x000E;
pub const DW_LANG_PLI: u32 = 0x000F;
pub const DW_LANG_ObjC: u32 = 0x0010;
pub const DW_LANG_ObjC_plus_plus: u32 = 0x0011;
pub const DW_LANG_UPC: u32 = 0x0012;
pub const DW_LANG_D: u32 = 0x0013;
pub const DW_LANG_Python: u32 = 0x0014;
pub const DW_LANG_OpenCL: u32 = 0x0015;
pub const DW_LANG_Go: u32 = 0x0016;
pub const DW_LANG_Modula3: u32 = 0x0017;
pub const DW_LANG_Haskell: u32 = 0x0018;
pub const DW_LANG_C_plus_plus_03: u32 = 0x0019;
pub const DW_LANG_C_plus_plus_11: u32 = 0x001A;
pub const DW_LANG_OCaml: u32 = 0x001B;
pub const DW_LANG_Rust: u32 = 0x001C;
pub const DW_LANG_C11: u32 = 0x001D;
pub const DW_LANG_Swift: u32 = 0x001E;
pub const DW_LANG_Julia: u32 = 0x001F;
pub const DW_LANG_Dylan: u32 = 0x0020;
pub const DW_LANG_C_plus_plus_14: u32 = 0x0021;
pub const DW_LANG_Fortran03: u32 = 0x0022;
pub const DW_LANG_Fortran08: u32 = 0x0023;
pub const DW_LANG_RenderScript: u32 = 0x0024;
pub const DW_LANG_BLISS: u32 = 0x0025;
pub const DW_LANG_Metal: u32 = 0x0027;
pub const DW_LANG_Zig: u32 = 0x0030;
pub const DW_LANG_Mojo: u32 = 0x0032;
pub const DW_LANG_C17: u32 = 0x0033;
pub const DW_LANG_C_plus_plus_17: u32 = 0x0034;
pub const DW_LANG_C_plus_plus_20: u32 = 0x0035;
pub const DW_ATE_address: u32 = 0x01;
pub const DW_ATE_boolean: u32 = 0x02;
pub const DW_ATE_complex_float: u32 = 0x03;
pub const DW_ATE_float: u32 = 0x04;
pub const DW_ATE_signed: u32 = 0x05;
pub const DW_ATE_signed_char: u32 = 0x06;
pub const DW_ATE_unsigned: u32 = 0x07;
pub const DW_ATE_unsigned_char: u32 = 0x08;
pub const DW_ATE_UTF: u32 = 0x10;
pub const DW_TAG_array_type: u32 = 0x01;
pub const DW_TAG_class_type: u32 = 0x02;
pub const DW_TAG_entry_point: u32 = 0x03;
pub const DW_TAG_enumeration_type: u32 = 0x04;
pub const DW_TAG_formal_parameter: u32 = 0x05;
pub const DW_TAG_imported_declaration: u32 = 0x08;
pub const DW_TAG_label: u32 = 0x0A;
pub const DW_TAG_lexical_block: u32 = 0x0B;
pub const DW_TAG_member: u32 = 0x0D;
pub const DW_TAG_pointer_type: u32 = 0x0F;
pub const DW_TAG_reference_type: u32 = 0x10;
pub const DW_TAG_compile_unit: u32 = 0x11;
pub const DW_TAG_string_type: u32 = 0x12;
pub const DW_TAG_structure_type: u32 = 0x13;
pub const DW_TAG_subroutine_type: u32 = 0x15;
pub const DW_TAG_typedef: u32 = 0x16;
pub const DW_TAG_union_type: u32 = 0x17;
pub const DW_TAG_unspecified_parameters: u32 = 0x18;
pub const DW_TAG_variant: u32 = 0x19;
pub const DW_TAG_common_block: u32 = 0x1A;
pub const DW_TAG_common_inclusion: u32 = 0x1B;
pub const DW_TAG_inheritance: u32 = 0x1C;
pub const DW_TAG_inlined_subroutine: u32 = 0x1D;
pub const DW_TAG_module: u32 = 0x1E;
pub const DW_TAG_ptr_to_member_type: u32 = 0x1F;
pub const DW_TAG_set_type: u32 = 0x20;
pub const DW_TAG_subrange_type: u32 = 0x21;
pub const DW_TAG_auto_variable: u32 = 0x100;
pub const DW_TAG_arg_variable: u32 = 0x101;
pub const DW_TAG_template_type_parameter: u32 = 0x2F;
pub const DW_TAG_template_value_parameter: u32 = 0x30;
pub const DW_TAG_GNU_template_template_param: u32 = 0x4106;
pub const DW_TAG_GNU_template_parameter_pack: u32 = 0x4107;
pub const DW_FLAG_artificial: u32 = 0x01;
pub const DW_FLAG_prototyped: u32 = 0x02;
pub const DW_FLAG_object_pointer: u32 = 0x04;
pub const DW_FLAG_static_member: u32 = 0x08;
pub const DW_FLAG_bit_field: u32 = 0x10;
pub const DW_FLAG_vector: u32 = 0x20;
pub fn language_to_dwarf(lang: &str) -> u32 {
match lang.to_lowercase().as_str() {
"c" | "c89" => DW_LANG_C89,
"c99" => DW_LANG_C99,
"c11" => DW_LANG_C11,
"c17" => DW_LANG_C17,
"c++" | "c++98" | "cpp" => DW_LANG_C_plus_plus,
"c++03" | "cpp03" => DW_LANG_C_plus_plus_03,
"c++11" | "cpp11" => DW_LANG_C_plus_plus_11,
"c++14" | "cpp14" => DW_LANG_C_plus_plus_14,
"c++17" | "cpp17" => DW_LANG_C_plus_plus_17,
"c++20" | "cpp20" => DW_LANG_C_plus_plus_20,
"rust" => DW_LANG_Rust,
"swift" => DW_LANG_Swift,
"go" => DW_LANG_Go,
"fortran77" => DW_LANG_Fortran77,
"fortran90" => DW_LANG_Fortran90,
"fortran95" => DW_LANG_Fortran95,
"fortran03" => DW_LANG_Fortran03,
"fortran08" => DW_LANG_Fortran08,
"ada83" => DW_LANG_Ada83,
"ada95" => DW_LANG_Ada95,
"java" => DW_LANG_Java,
"python" => DW_LANG_Python,
"opencl" => DW_LANG_OpenCL,
"haskell" => DW_LANG_Haskell,
"ocaml" => DW_LANG_OCaml,
"julia" => DW_LANG_Julia,
"d" => DW_LANG_D,
"objc" => DW_LANG_ObjC,
"objc++" => DW_LANG_ObjC_plus_plus,
"zig" => DW_LANG_Zig,
_ => DW_LANG_C, }
}
#[derive(Debug, Clone)]
pub struct DebugInfoBuilder {
pub metadata_store: MetadataStore,
pub compile_units: Vec<u32>,
pub subprograms: Vec<u32>,
pub global_variables: Vec<u32>,
pub local_variables: Vec<u32>,
pub current_scope: Option<u32>,
pub current_location: Option<DILocation>,
pub current_file: Option<u32>,
pub allow_unresolved: bool,
}
impl DebugInfoBuilder {
pub fn new() -> Self {
Self {
metadata_store: MetadataStore::new(),
compile_units: Vec::new(),
subprograms: Vec::new(),
global_variables: Vec::new(),
local_variables: Vec::new(),
current_scope: None,
current_location: None,
current_file: None,
allow_unresolved: false,
}
}
pub fn create_compile_unit(
&mut self,
file: &str,
dir: &str,
producer: &str,
is_optimized: bool,
flags: &str,
runtime_version: u32,
) -> u32 {
let file_id = self.create_file(file, dir);
let lang = if flags.is_empty() {
DW_LANG_C
} else {
language_to_dwarf(flags)
};
let mut cu = DICompileUnit::new(lang, file_id, producer.to_string());
cu.is_optimized = is_optimized;
cu.flags = flags.to_string();
cu.runtime_version = runtime_version;
let id = self.metadata_store.add_debug_compile_unit(cu);
self.compile_units.push(id);
self.current_file = Some(file_id);
id
}
pub fn create_file(&mut self, filename: &str, directory: &str) -> u32 {
let di = DIFile::new(filename.to_string(), directory.to_string());
self.metadata_store.add_debug_file(di)
}
pub fn create_function(
&mut self,
scope: u32,
name: &str,
linkage_name: &str,
file: u32,
line: u32,
is_definition: bool,
is_local_to_unit: bool,
is_optimized: bool,
) -> u32 {
let mut sub = DISubprogram::new(name.to_string(), file, line, scope);
if !linkage_name.is_empty() {
sub.linkage_name = Some(linkage_name.to_string());
}
sub.is_definition = is_definition;
sub.is_local = is_local_to_unit;
sub.is_optimized = is_optimized;
let id = self.metadata_store.add_debug_subprogram(sub);
self.subprograms.push(id);
id
}
pub fn create_basic_type(&mut self, name: &str, size_in_bits: u64, encoding: u32) -> u32 {
let ty = DIType::new_basic(name.to_string(), size_in_bits, 0, encoding);
self.metadata_store.add_debug_type(ty)
}
pub fn create_pointer_type(
&mut self,
pointee_type: u32,
size_in_bits: u64,
align_in_bits: u32,
) -> u32 {
let ty = DIType {
name: String::new(),
size_in_bits,
align_in_bits,
offset_in_bits: 0,
encoding: 0,
base_type: Some(pointee_type),
file: None,
line: None,
tag: DW_TAG_pointer_type,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_struct_type(
&mut self,
_scope: u32,
name: &str,
file: u32,
line: u32,
size_in_bits: u64,
align_in_bits: u32,
elements: &[u32],
) -> u32 {
let ty = DIType {
name: name.to_string(),
size_in_bits,
align_in_bits,
offset_in_bits: 0,
encoding: 0,
base_type: elements.first().copied(),
file: Some(file),
line: Some(line),
tag: DW_TAG_structure_type,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_array_type(&mut self, elem_type: u32, _count: u64, size_in_bits: u64) -> u32 {
let ty = DIType {
name: String::new(),
size_in_bits,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(elem_type),
file: None,
line: None,
tag: DW_TAG_array_type,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_subroutine_type(&mut self, file: u32, param_types: &[u32]) -> u32 {
let ty = DIType {
name: String::new(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: param_types.first().copied(),
file: Some(file),
line: None,
tag: DW_TAG_subroutine_type,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_member_type(
&mut self,
_scope: u32,
name: &str,
file: u32,
line: u32,
size_in_bits: u64,
align_in_bits: u32,
offset_in_bits: u64,
ty: u32,
) -> u32 {
let member = DIType {
name: name.to_string(),
size_in_bits,
align_in_bits,
offset_in_bits,
encoding: 0,
base_type: Some(ty),
file: Some(file),
line: Some(line),
tag: DW_TAG_member,
flags: 0,
};
self.metadata_store.add_debug_type(member)
}
pub fn create_inheritance(&mut self, _scope: u32, base_type: u32, offset_in_bits: u64) -> u32 {
let ty = DIType {
name: String::new(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits,
encoding: 0,
base_type: Some(base_type),
file: None,
line: None,
tag: DW_TAG_inheritance,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_auto_variable(
&mut self,
scope: u32,
name: &str,
file: u32,
line: u32,
ty: u32,
) -> u32 {
let var = DILocalVariable::new(name.to_string(), scope, file, line, ty);
let id = self.metadata_store.add_debug_local_var(var);
self.local_variables.push(id);
id
}
pub fn create_parameter_variable(
&mut self,
scope: u32,
name: &str,
arg_no: u32,
file: u32,
line: u32,
ty: u32,
) -> u32 {
let mut var = DILocalVariable::new(name.to_string(), scope, file, line, ty);
var.arg = Some(arg_no);
let id = self.metadata_store.add_debug_local_var(var);
self.local_variables.push(id);
id
}
pub fn create_global_variable(
&mut self,
scope: u32,
name: &str,
linkage_name: &str,
file: u32,
line: u32,
ty: u32,
is_local_to_unit: bool,
) -> u32 {
let gv = DIGlobalVariable::new(
name.to_string(),
scope,
file,
line,
ty,
is_local_to_unit,
true,
);
let id = self.metadata_store.add_debug_global_var(gv);
self.global_variables.push(id);
id
}
pub fn create_lexical_block(
&mut self,
_scope: u32,
_file: u32,
_line: u32,
_column: u32,
) -> u32 {
self.metadata_store.create_md_node(Vec::new())
}
pub fn create_inlined_subroutine(
&mut self,
_scope: u32,
_subroutine: u32,
_file: u32,
_line: u32,
) -> u32 {
self.metadata_store.create_md_node(Vec::new())
}
pub fn create_debug_location(&mut self, scope: u32, _file: u32, line: u32, column: u32) -> u32 {
let loc = DILocation::new(line, column, scope);
let id = self.metadata_store.add_debug_location(loc.clone());
self.current_location = Some(loc);
id
}
pub fn insert_declare(&mut self, alloca: &ValueRef, _var: u32, _location: u32) -> ValueRef {
let dbg_call = Value {
name: "llvm.dbg.declare".to_string(),
ty: Type::void(),
vid: 0,
subclass: SubclassKind::Instruction,
uses: Vec::new(),
opcode: None,
num_operands: 2,
operands: vec![alloca.clone()],
parent: None,
return_type: None,
successors: Vec::new(),
subclass_data: 0,
subclass_extra: Vec::new(),
metadata: std::collections::HashMap::new(),
..Default::default()
};
valref(dbg_call)
}
pub fn insert_value(&mut self, val: &ValueRef, _var: u32, _location: u32) -> ValueRef {
let dbg_call = Value {
name: "llvm.dbg.value".to_string(),
ty: Type::void(),
vid: 0,
subclass: SubclassKind::Instruction,
uses: Vec::new(),
opcode: None,
num_operands: 2,
operands: vec![val.clone()],
parent: None,
return_type: None,
successors: Vec::new(),
subclass_data: 0,
metadata: std::collections::HashMap::new(),
..Default::default()
};
valref(dbg_call)
}
pub fn finalize(&mut self) {
}
pub fn emit_to_metadata_store(&mut self) -> MetadataStore {
self.metadata_store.clone()
}
}
impl Default for DebugInfoBuilder {
fn default() -> Self {
Self::new()
}
}
pub fn create_function_debug_info(
builder: &mut DebugInfoBuilder,
func_name: &str,
file: &str,
line: u32,
) -> u32 {
let file_idx = builder.create_file(file, ".");
let cu_idx = if builder.compile_units.is_empty() {
builder.create_compile_unit(file, ".", "llvm-native", false, "", 0)
} else {
builder.compile_units[0]
};
let sub_idx = builder.create_function(
cu_idx, func_name, func_name, file_idx, line, true, false, false, );
builder.current_scope = Some(sub_idx);
sub_idx
}
pub fn insert_debug_intrinsics(
builder: &mut DebugInfoBuilder,
_bb: &ValueRef,
location: u32,
) -> Vec<ValueRef> {
let mut intrinsics = Vec::new();
let var_count = builder.local_variables.len();
for _ in 0..var_count {
let placeholder = valref(Value {
name: "debug_placeholder".to_string(),
ty: Type::void(),
vid: 0,
subclass: SubclassKind::Value,
uses: Vec::new(),
opcode: None,
subclass_data: 0,
subclass_extra: Vec::new(),
metadata: std::collections::HashMap::new(),
is_used_by_md: false,
num_operands: 0,
operands: Vec::new(),
parent: None,
return_type: None,
successors: Vec::new(),
blocks: Vec::new(),
params: Vec::new(),
instructions: Vec::new(),
initializer: None,
is_constant: false,
is_vararg: false,
result: None,
is_internal: false,
});
let intrinsic = builder.insert_value(&placeholder, 0, location);
intrinsics.push(intrinsic);
}
intrinsics
}
pub const DW_OP_addr: u8 = 0x03;
pub const DW_OP_deref: u8 = 0x06;
pub const DW_OP_const1u: u8 = 0x08;
pub const DW_OP_const1s: u8 = 0x09;
pub const DW_OP_const2u: u8 = 0x0A;
pub const DW_OP_const2s: u8 = 0x0B;
pub const DW_OP_const4u: u8 = 0x0C;
pub const DW_OP_const4s: u8 = 0x0D;
pub const DW_OP_const8u: u8 = 0x0E;
pub const DW_OP_const8s: u8 = 0x0F;
pub const DW_OP_constu: u8 = 0x10;
pub const DW_OP_consts: u8 = 0x11;
pub const DW_OP_dup: u8 = 0x12;
pub const DW_OP_drop: u8 = 0x13;
pub const DW_OP_over: u8 = 0x14;
pub const DW_OP_pick: u8 = 0x15;
pub const DW_OP_swap: u8 = 0x16;
pub const DW_OP_rot: u8 = 0x17;
pub const DW_OP_xderef: u8 = 0x18;
pub const DW_OP_abs: u8 = 0x19;
pub const DW_OP_and: u8 = 0x1A;
pub const DW_OP_div: u8 = 0x1B;
pub const DW_OP_minus: u8 = 0x1C;
pub const DW_OP_mod: u8 = 0x1D;
pub const DW_OP_mul: u8 = 0x1E;
pub const DW_OP_neg: u8 = 0x1F;
pub const DW_OP_not: u8 = 0x20;
pub const DW_OP_or: u8 = 0x21;
pub const DW_OP_plus: u8 = 0x22;
pub const DW_OP_plus_uconst: u8 = 0x23;
pub const DW_OP_shl: u8 = 0x24;
pub const DW_OP_shr: u8 = 0x25;
pub const DW_OP_shra: u8 = 0x26;
pub const DW_OP_xor: u8 = 0x27;
pub const DW_OP_bra: u8 = 0x28;
pub const DW_OP_eq: u8 = 0x29;
pub const DW_OP_ge: u8 = 0x2A;
pub const DW_OP_gt: u8 = 0x2B;
pub const DW_OP_le: u8 = 0x2C;
pub const DW_OP_lt: u8 = 0x2D;
pub const DW_OP_ne: u8 = 0x2E;
pub const DW_OP_skip: u8 = 0x2F;
pub const DW_OP_lit0: u8 = 0x30; pub const DW_OP_reg0: u8 = 0x50; pub const DW_OP_breg0: u8 = 0x70; pub const DW_OP_regx: u8 = 0x90;
pub const DW_OP_fbreg: u8 = 0x91;
pub const DW_OP_bregx: u8 = 0x92;
pub const DW_OP_piece: u8 = 0x93;
pub const DW_OP_deref_size: u8 = 0x94;
pub const DW_OP_xderef_size: u8 = 0x95;
pub const DW_OP_nop: u8 = 0x96;
pub const DW_OP_push_object_address: u8 = 0x97;
pub const DW_OP_call2: u8 = 0x98;
pub const DW_OP_call4: u8 = 0x99;
pub const DW_OP_call_ref: u8 = 0x9A;
pub const DW_OP_form_tls_address: u8 = 0x9B;
pub const DW_OP_call_frame_cfa: u8 = 0x9C;
pub const DW_OP_bit_piece: u8 = 0x9D;
pub const DW_OP_implicit_value: u8 = 0x9E;
pub const DW_OP_stack_value: u8 = 0x9F;
pub const DW_OP_implicit_pointer: u8 = 0xA0;
pub const DW_OP_addrx: u8 = 0xA1;
pub const DW_OP_constx: u8 = 0xA2;
pub const DW_OP_entry_value: u8 = 0xA3;
pub const DW_OP_const_type: u8 = 0xA4;
pub const DW_OP_regval_type: u8 = 0xA5;
pub const DW_OP_deref_type: u8 = 0xA6;
pub const DW_OP_xderef_type: u8 = 0xA7;
pub const DW_OP_convert: u8 = 0xA8;
pub const DW_OP_reinterpret: u8 = 0xA9;
pub const fn dw_op_lit(n: u8) -> u8 {
assert!(n <= 31, "DW_OP_lit value must be in range 0..31");
0x30 + n
}
pub const fn dw_op_reg(n: u8) -> u8 {
assert!(n <= 31, "DW_OP_reg value must be in range 0..31");
0x50 + n
}
pub const fn dw_op_breg(n: u8) -> u8 {
assert!(n <= 31, "DW_OP_breg value must be in range 0..31");
0x70 + n
}
#[derive(Debug, Clone, Default)]
pub struct ExpressionBuilder {
bytes: Vec<u8>,
stack_depth: i32,
}
impl ExpressionBuilder {
pub fn new() -> Self {
Self {
bytes: Vec::new(),
stack_depth: 0,
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
pub fn stack_depth(&self) -> i32 {
self.stack_depth
}
pub fn clear(&mut self) -> &mut Self {
self.bytes.clear();
self.stack_depth = 0;
self
}
fn append_uleb128(&mut self, mut value: u64) {
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
self.bytes.push(byte);
if value == 0 {
break;
}
}
}
fn append_sleb128(&mut self, mut value: i64) {
loop {
let mut byte = (value as u8) & 0x7F;
value >>= 7;
let done = if value == 0 && (byte & 0x40) == 0 {
true
} else if value == -1 && (byte & 0x40) != 0 {
true
} else {
false
};
if !done {
byte |= 0x80;
}
self.bytes.push(byte);
if done {
break;
}
}
}
fn append_u8(&mut self, value: u8) {
self.bytes.push(value);
}
fn append_u16(&mut self, value: u16) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
fn append_u32(&mut self, value: u32) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
fn append_u64(&mut self, value: u64) {
self.bytes.extend_from_slice(&value.to_le_bytes());
}
fn append_bytes(&mut self, data: &[u8]) {
self.bytes.extend_from_slice(data);
}
fn push_stack(&mut self) {
self.stack_depth += 1;
}
fn pop_stack(&mut self) {
self.stack_depth = (self.stack_depth - 1).max(0);
}
pub fn op_addr(&mut self, addr: u64) -> &mut Self {
self.append_u8(DW_OP_addr);
self.append_u64(addr);
self.push_stack();
self
}
pub fn op_const1u(&mut self, value: u8) -> &mut Self {
self.append_u8(DW_OP_const1u);
self.append_u8(value);
self.push_stack();
self
}
pub fn op_const1s(&mut self, value: i8) -> &mut Self {
self.append_u8(DW_OP_const1s);
self.append_u8(value as u8);
self.push_stack();
self
}
pub fn op_const2u(&mut self, value: u16) -> &mut Self {
self.append_u8(DW_OP_const2u);
self.append_u16(value);
self.push_stack();
self
}
pub fn op_const2s(&mut self, value: i16) -> &mut Self {
self.append_u8(DW_OP_const2s);
self.append_u16(value as u16);
self.push_stack();
self
}
pub fn op_const4u(&mut self, value: u32) -> &mut Self {
self.append_u8(DW_OP_const4u);
self.append_u32(value);
self.push_stack();
self
}
pub fn op_const4s(&mut self, value: i32) -> &mut Self {
self.append_u8(DW_OP_const4s);
self.append_u32(value as u32);
self.push_stack();
self
}
pub fn op_const8u(&mut self, value: u64) -> &mut Self {
self.append_u8(DW_OP_const8u);
self.append_u64(value);
self.push_stack();
self
}
pub fn op_const8s(&mut self, value: i64) -> &mut Self {
self.append_u8(DW_OP_const8s);
self.append_u64(value as u64);
self.push_stack();
self
}
pub fn op_constu(&mut self, value: u64) -> &mut Self {
self.append_u8(DW_OP_constu);
self.append_uleb128(value);
self.push_stack();
self
}
pub fn op_consts(&mut self, value: i64) -> &mut Self {
self.append_u8(DW_OP_consts);
self.append_sleb128(value);
self.push_stack();
self
}
pub fn op_lit(&mut self, n: u8) -> &mut Self {
assert!(n <= 31, "DW_OP_lit value must be in range 0..31");
self.append_u8(dw_op_lit(n));
self.push_stack();
self
}
pub fn op_plus_uconst(&mut self, value: u64) -> &mut Self {
self.append_u8(DW_OP_plus_uconst);
self.append_uleb128(value);
self
}
pub fn op_reg(&mut self, n: u8) -> &mut Self {
assert!(n <= 31, "DW_OP_reg value must be in range 0..31");
self.append_u8(dw_op_reg(n));
self.push_stack();
self
}
pub fn op_breg(&mut self, n: u8, offset: i64) -> &mut Self {
assert!(n <= 31, "DW_OP_breg value must be in range 0..31");
self.append_u8(dw_op_breg(n));
self.append_sleb128(offset);
self.push_stack();
self
}
pub fn op_regx(&mut self, reg: u64) -> &mut Self {
self.append_u8(DW_OP_regx);
self.append_uleb128(reg);
self.push_stack();
self
}
pub fn op_bregx(&mut self, reg: u64, offset: i64) -> &mut Self {
self.append_u8(DW_OP_bregx);
self.append_uleb128(reg);
self.append_sleb128(offset);
self.push_stack();
self
}
pub fn op_fbreg(&mut self, offset: i64) -> &mut Self {
self.append_u8(DW_OP_fbreg);
self.append_sleb128(offset);
self.push_stack();
self
}
pub fn op_call_frame_cfa(&mut self) -> &mut Self {
self.append_u8(DW_OP_call_frame_cfa);
self.push_stack();
self
}
pub fn op_form_tls_address(&mut self) -> &mut Self {
self.append_u8(DW_OP_form_tls_address);
self
}
pub fn op_push_object_address(&mut self) -> &mut Self {
self.append_u8(DW_OP_push_object_address);
self.push_stack();
self
}
pub fn op_dup(&mut self) -> &mut Self {
self.append_u8(DW_OP_dup);
self.push_stack();
self
}
pub fn op_drop(&mut self) -> &mut Self {
self.append_u8(DW_OP_drop);
self.pop_stack();
self
}
pub fn op_over(&mut self) -> &mut Self {
self.append_u8(DW_OP_over);
self.push_stack();
self
}
pub fn op_pick(&mut self, index: u8) -> &mut Self {
self.append_u8(DW_OP_pick);
self.append_u8(index);
self.push_stack();
self
}
pub fn op_swap(&mut self) -> &mut Self {
self.append_u8(DW_OP_swap);
self
}
pub fn op_rot(&mut self) -> &mut Self {
self.append_u8(DW_OP_rot);
self
}
pub fn op_deref(&mut self) -> &mut Self {
self.append_u8(DW_OP_deref);
self
}
pub fn op_deref_size(&mut self, size_in_bytes: u8) -> &mut Self {
self.append_u8(DW_OP_deref_size);
self.append_u8(size_in_bytes);
self
}
pub fn op_xderef(&mut self) -> &mut Self {
self.append_u8(DW_OP_xderef);
self.pop_stack(); self
}
pub fn op_xderef_size(&mut self, size_in_bytes: u8) -> &mut Self {
self.append_u8(DW_OP_xderef_size);
self.append_u8(size_in_bytes);
self.pop_stack();
self
}
pub fn op_abs(&mut self) -> &mut Self {
self.append_u8(DW_OP_abs);
self
}
pub fn op_and(&mut self) -> &mut Self {
self.append_u8(DW_OP_and);
self.pop_stack();
self
}
pub fn op_div(&mut self) -> &mut Self {
self.append_u8(DW_OP_div);
self.pop_stack();
self
}
pub fn op_minus(&mut self) -> &mut Self {
self.append_u8(DW_OP_minus);
self.pop_stack();
self
}
pub fn op_mod(&mut self) -> &mut Self {
self.append_u8(DW_OP_mod);
self.pop_stack();
self
}
pub fn op_mul(&mut self) -> &mut Self {
self.append_u8(DW_OP_mul);
self.pop_stack();
self
}
pub fn op_neg(&mut self) -> &mut Self {
self.append_u8(DW_OP_neg);
self
}
pub fn op_not(&mut self) -> &mut Self {
self.append_u8(DW_OP_not);
self
}
pub fn op_or(&mut self) -> &mut Self {
self.append_u8(DW_OP_or);
self.pop_stack();
self
}
pub fn op_plus(&mut self) -> &mut Self {
self.append_u8(DW_OP_plus);
self.pop_stack();
self
}
pub fn op_shl(&mut self) -> &mut Self {
self.append_u8(DW_OP_shl);
self.pop_stack();
self
}
pub fn op_shr(&mut self) -> &mut Self {
self.append_u8(DW_OP_shr);
self.pop_stack();
self
}
pub fn op_shra(&mut self) -> &mut Self {
self.append_u8(DW_OP_shra);
self.pop_stack();
self
}
pub fn op_xor(&mut self) -> &mut Self {
self.append_u8(DW_OP_xor);
self.pop_stack();
self
}
pub fn op_bra(&mut self, target_offset: i16) -> &mut Self {
self.append_u8(DW_OP_bra);
self.append_u16(target_offset as u16);
self.pop_stack();
self
}
pub fn op_skip(&mut self, target_offset: i16) -> &mut Self {
self.append_u8(DW_OP_skip);
self.append_u16(target_offset as u16);
self
}
pub fn op_eq(&mut self) -> &mut Self {
self.append_u8(DW_OP_eq);
self.pop_stack();
self
}
pub fn op_ge(&mut self) -> &mut Self {
self.append_u8(DW_OP_ge);
self.pop_stack();
self
}
pub fn op_gt(&mut self) -> &mut Self {
self.append_u8(DW_OP_gt);
self.pop_stack();
self
}
pub fn op_le(&mut self) -> &mut Self {
self.append_u8(DW_OP_le);
self.pop_stack();
self
}
pub fn op_lt(&mut self) -> &mut Self {
self.append_u8(DW_OP_lt);
self.pop_stack();
self
}
pub fn op_ne(&mut self) -> &mut Self {
self.append_u8(DW_OP_ne);
self.pop_stack();
self
}
pub fn op_piece(&mut self, size_in_bytes: u64) -> &mut Self {
self.append_u8(DW_OP_piece);
self.append_uleb128(size_in_bytes);
self.pop_stack();
self
}
pub fn op_bit_piece(&mut self, size_in_bits: u64, offset_in_bits: u64) -> &mut Self {
self.append_u8(DW_OP_bit_piece);
self.append_uleb128(size_in_bits);
self.append_uleb128(offset_in_bits);
self.pop_stack();
self
}
pub fn op_stack_value(&mut self) -> &mut Self {
self.append_u8(DW_OP_stack_value);
self
}
pub fn op_implicit_value(&mut self, data: &[u8]) -> &mut Self {
self.append_u8(DW_OP_implicit_value);
self.append_uleb128(data.len() as u64);
self.append_bytes(data);
self.push_stack();
self
}
pub fn op_implicit_pointer(&mut self, die_offset: u32, byte_offset: i64) -> &mut Self {
self.append_u8(DW_OP_implicit_pointer);
self.append_u32(die_offset);
self.append_sleb128(byte_offset);
self.push_stack();
self
}
pub fn op_addrx(&mut self, index: u64) -> &mut Self {
self.append_u8(DW_OP_addrx);
self.append_uleb128(index);
self.push_stack();
self
}
pub fn op_constx(&mut self, index: u64) -> &mut Self {
self.append_u8(DW_OP_constx);
self.append_uleb128(index);
self.push_stack();
self
}
pub fn op_call2(&mut self, offset: u16) -> &mut Self {
self.append_u8(DW_OP_call2);
self.append_u16(offset);
self
}
pub fn op_call4(&mut self, offset: u32) -> &mut Self {
self.append_u8(DW_OP_call4);
self.append_u32(offset);
self
}
pub fn op_call_ref(&mut self, offset: u64, is_dwarf64: bool) -> &mut Self {
self.append_u8(DW_OP_call_ref);
if is_dwarf64 {
self.append_u64(offset);
} else {
self.append_u32(offset as u32);
}
self
}
pub fn op_entry_value(&mut self, expr_bytes: &[u8]) -> &mut Self {
self.append_u8(DW_OP_entry_value);
self.append_uleb128(expr_bytes.len() as u64);
self.append_bytes(expr_bytes);
self.push_stack();
self
}
pub fn op_const_type(&mut self, type_die_offset: u64, value_data: &[u8]) -> &mut Self {
self.append_u8(DW_OP_const_type);
self.append_uleb128(type_die_offset);
self.append_u8(value_data.len() as u8);
self.append_bytes(value_data);
self.push_stack();
self
}
pub fn op_regval_type(&mut self, reg: u64, type_die_offset: u64) -> &mut Self {
self.append_u8(DW_OP_regval_type);
self.append_uleb128(reg);
self.append_uleb128(type_die_offset);
self.push_stack();
self
}
pub fn op_deref_type(&mut self, size_in_bytes: u8, type_die_offset: u64) -> &mut Self {
self.append_u8(DW_OP_deref_type);
self.append_u8(size_in_bytes);
self.append_uleb128(type_die_offset);
self
}
pub fn op_xderef_type(&mut self, size_in_bytes: u8, type_die_offset: u64) -> &mut Self {
self.append_u8(DW_OP_xderef_type);
self.append_u8(size_in_bytes);
self.append_uleb128(type_die_offset);
self.pop_stack();
self
}
pub fn op_convert(&mut self, type_die_offset: u64) -> &mut Self {
self.append_u8(DW_OP_convert);
self.append_uleb128(type_die_offset);
self
}
pub fn op_reinterpret(&mut self, type_die_offset: u64) -> &mut Self {
self.append_u8(DW_OP_reinterpret);
self.append_uleb128(type_die_offset);
self
}
pub fn op_nop(&mut self) -> &mut Self {
self.append_u8(DW_OP_nop);
self
}
}
pub const DW_AT_sibling: u16 = 0x01;
pub const DW_AT_location: u16 = 0x02;
pub const DW_AT_name: u16 = 0x03;
pub const DW_AT_ordering: u16 = 0x09;
pub const DW_AT_byte_size: u16 = 0x0B;
pub const DW_AT_bit_offset: u16 = 0x0C;
pub const DW_AT_bit_size: u16 = 0x0D;
pub const DW_AT_stmt_list: u16 = 0x10;
pub const DW_AT_low_pc: u16 = 0x11;
pub const DW_AT_high_pc: u16 = 0x12;
pub const DW_AT_language: u16 = 0x13;
pub const DW_AT_discr: u16 = 0x15;
pub const DW_AT_discr_value: u16 = 0x16;
pub const DW_AT_visibility: u16 = 0x17;
pub const DW_AT_import: u16 = 0x18;
pub const DW_AT_string_length: u16 = 0x19;
pub const DW_AT_common_reference: u16 = 0x1A;
pub const DW_AT_comp_dir: u16 = 0x1B;
pub const DW_AT_const_value: u16 = 0x1C;
pub const DW_AT_containing_type: u16 = 0x1D;
pub const DW_AT_default_value: u16 = 0x1E;
pub const DW_AT_inline: u16 = 0x20;
pub const DW_AT_is_optional: u16 = 0x21;
pub const DW_AT_lower_bound: u16 = 0x22;
pub const DW_AT_producer: u16 = 0x25;
pub const DW_AT_prototyped: u16 = 0x27;
pub const DW_AT_return_addr: u16 = 0x2A;
pub const DW_AT_start_scope: u16 = 0x2C;
pub const DW_AT_bit_stride: u16 = 0x2E;
pub const DW_AT_upper_bound: u16 = 0x2F;
pub const DW_AT_abstract_origin: u16 = 0x31;
pub const DW_AT_accessibility: u16 = 0x32;
pub const DW_AT_address_class: u16 = 0x33;
pub const DW_AT_artificial: u16 = 0x34;
pub const DW_AT_base_types: u16 = 0x35;
pub const DW_AT_calling_convention: u16 = 0x36;
pub const DW_AT_count: u16 = 0x37;
pub const DW_AT_data_member_location: u16 = 0x38;
pub const DW_AT_decl_column: u16 = 0x39;
pub const DW_AT_decl_file: u16 = 0x3A;
pub const DW_AT_decl_line: u16 = 0x3B;
pub const DW_AT_declaration: u16 = 0x3C;
pub const DW_AT_discr_list: u16 = 0x3D;
pub const DW_AT_encoding: u16 = 0x3E;
pub const DW_AT_external: u16 = 0x3F;
pub const DW_AT_frame_base: u16 = 0x40;
pub const DW_AT_friend: u16 = 0x41;
pub const DW_AT_identifier_case: u16 = 0x42;
pub const DW_AT_macro_info: u16 = 0x43;
pub const DW_AT_namelist_item: u16 = 0x44;
pub const DW_AT_priority: u16 = 0x45;
pub const DW_AT_segment: u16 = 0x46;
pub const DW_AT_specification: u16 = 0x47;
pub const DW_AT_static_link: u16 = 0x48;
pub const DW_AT_type: u16 = 0x49;
pub const DW_AT_use_location: u16 = 0x4A;
pub const DW_AT_variable_parameter: u16 = 0x4B;
pub const DW_AT_virtuality: u16 = 0x4C;
pub const DW_AT_vtable_elem_location: u16 = 0x4D;
pub const DW_AT_MIPS_fde: u16 = 0x2001;
pub const DW_AT_MIPS_loop_begin: u16 = 0x2002;
pub const DW_AT_MIPS_tail_loop_begin: u16 = 0x2003;
pub const DW_AT_MIPS_epilog_begin: u16 = 0x2004;
pub const DW_AT_MIPS_loop_unroll_factor: u16 = 0x2005;
pub const DW_AT_MIPS_software_pipeline_depth: u16 = 0x2006;
pub const DW_AT_MIPS_linkage_name: u16 = 0x2007;
pub const DW_AT_MIPS_stride: u16 = 0x2008;
pub const DW_AT_MIPS_abstract_name: u16 = 0x2009;
pub const DW_AT_MIPS_clone_origin: u16 = 0x200A;
pub const DW_AT_MIPS_has_inlines: u16 = 0x200B;
pub const DW_AT_MIPS_stride_byte: u16 = 0x200C;
pub const DW_AT_MIPS_stride_elem: u16 = 0x200D;
pub const DW_AT_MIPS_ptr_dopetype: u16 = 0x200E;
pub const DW_AT_MIPS_allocatable_dopetype: u16 = 0x200F;
pub const DW_AT_MIPS_assumed_shape_dopetype: u16 = 0x2010;
pub const DW_AT_MIPS_assumed_size: u16 = 0x2011;
pub const DW_AT_linkage_name: u16 = 0x6E;
pub const DW_AT_description: u16 = 0x5A;
pub const DW_AT_ranges: u16 = 0x55;
pub const DW_AT_signature: u16 = 0x69;
pub const DW_AT_main_subprogram: u16 = 0x6A;
pub const DW_AT_data_bit_offset: u16 = 0x6B;
pub const DW_AT_const_expr: u16 = 0x6C;
pub const DW_AT_enum_class: u16 = 0x6D;
pub const DW_AT_object_pointer: u16 = 0x64;
pub const DW_AT_explicit: u16 = 0x63;
pub const DW_AT_elemental: u16 = 0x66;
pub const DW_AT_pure: u16 = 0x67;
pub const DW_AT_recursive: u16 = 0x68;
pub const DW_AT_allocated: u16 = 0x4E;
pub const DW_AT_associated: u16 = 0x4F;
pub const DW_AT_data_location: u16 = 0x50;
pub const DW_AT_byte_stride: u16 = 0x51;
pub const DW_AT_entry_pc: u16 = 0x52;
pub const DW_AT_use_UTF8: u16 = 0x53;
pub const DW_AT_extension: u16 = 0x54;
pub const DW_AT_trampoline: u16 = 0x56;
pub const DW_AT_call_column: u16 = 0x57;
pub const DW_AT_call_file: u16 = 0x58;
pub const DW_AT_call_line: u16 = 0x59;
pub const DW_AT_alignment: u16 = 0x6F;
pub const DW_FORM_addr: u16 = 0x01;
pub const DW_FORM_block2: u16 = 0x03;
pub const DW_FORM_block4: u16 = 0x04;
pub const DW_FORM_data2: u16 = 0x05;
pub const DW_FORM_data4: u16 = 0x06;
pub const DW_FORM_data8: u16 = 0x07;
pub const DW_FORM_string: u16 = 0x08;
pub const DW_FORM_block: u16 = 0x09;
pub const DW_FORM_block1: u16 = 0x0A;
pub const DW_FORM_data1: u16 = 0x0B;
pub const DW_FORM_flag: u16 = 0x0C;
pub const DW_FORM_sdata: u16 = 0x0D;
pub const DW_FORM_strp: u16 = 0x0E;
pub const DW_FORM_udata: u16 = 0x0F;
pub const DW_FORM_ref_addr: u16 = 0x10;
pub const DW_FORM_ref1: u16 = 0x11;
pub const DW_FORM_ref2: u16 = 0x12;
pub const DW_FORM_ref4: u16 = 0x13;
pub const DW_FORM_ref8: u16 = 0x14;
pub const DW_FORM_ref_udata: u16 = 0x15;
pub const DW_FORM_indirect: u16 = 0x16;
pub const DW_FORM_sec_offset: u16 = 0x17;
pub const DW_FORM_exprloc: u16 = 0x18;
pub const DW_FORM_flag_present: u16 = 0x19;
pub const DW_FORM_strx: u16 = 0x1A;
pub const DW_FORM_addrx: u16 = 0x1B;
pub const DW_FORM_ref_sup4: u16 = 0x1C;
pub const DW_FORM_strp_sup: u16 = 0x1D;
pub const DW_FORM_data16: u16 = 0x1E;
pub const DW_FORM_line_strp: u16 = 0x1F;
pub const DW_FORM_ref_sig8: u16 = 0x20;
pub const DW_FORM_implicit_const: u16 = 0x21;
pub const DW_FORM_loclistx: u16 = 0x22;
pub const DW_FORM_rnglistx: u16 = 0x23;
pub const DW_FORM_ref_sup8: u16 = 0x24;
pub const DW_FORM_strx1: u16 = 0x25;
pub const DW_FORM_strx2: u16 = 0x26;
pub const DW_FORM_strx3: u16 = 0x27;
pub const DW_FORM_strx4: u16 = 0x28;
pub const DW_FORM_addrx1: u16 = 0x29;
pub const DW_FORM_addrx2: u16 = 0x2A;
pub const DW_FORM_addrx3: u16 = 0x2B;
pub const DW_FORM_addrx4: u16 = 0x2C;
pub fn dw_form_name(form: u16) -> &'static str {
match form {
DW_FORM_addr => "DW_FORM_addr",
DW_FORM_block2 => "DW_FORM_block2",
DW_FORM_block4 => "DW_FORM_block4",
DW_FORM_data2 => "DW_FORM_data2",
DW_FORM_data4 => "DW_FORM_data4",
DW_FORM_data8 => "DW_FORM_data8",
DW_FORM_string => "DW_FORM_string",
DW_FORM_block => "DW_FORM_block",
DW_FORM_block1 => "DW_FORM_block1",
DW_FORM_data1 => "DW_FORM_data1",
DW_FORM_flag => "DW_FORM_flag",
DW_FORM_sdata => "DW_FORM_sdata",
DW_FORM_strp => "DW_FORM_strp",
DW_FORM_udata => "DW_FORM_udata",
DW_FORM_ref_addr => "DW_FORM_ref_addr",
DW_FORM_ref1 => "DW_FORM_ref1",
DW_FORM_ref2 => "DW_FORM_ref2",
DW_FORM_ref4 => "DW_FORM_ref4",
DW_FORM_ref8 => "DW_FORM_ref8",
DW_FORM_ref_udata => "DW_FORM_ref_udata",
DW_FORM_indirect => "DW_FORM_indirect",
DW_FORM_sec_offset => "DW_FORM_sec_offset",
DW_FORM_exprloc => "DW_FORM_exprloc",
DW_FORM_flag_present => "DW_FORM_flag_present",
DW_FORM_strx => "DW_FORM_strx",
DW_FORM_addrx => "DW_FORM_addrx",
DW_FORM_ref_sup4 => "DW_FORM_ref_sup4",
DW_FORM_strp_sup => "DW_FORM_strp_sup",
DW_FORM_data16 => "DW_FORM_data16",
DW_FORM_line_strp => "DW_FORM_line_strp",
DW_FORM_ref_sig8 => "DW_FORM_ref_sig8",
DW_FORM_implicit_const => "DW_FORM_implicit_const",
DW_FORM_loclistx => "DW_FORM_loclistx",
DW_FORM_rnglistx => "DW_FORM_rnglistx",
DW_FORM_ref_sup8 => "DW_FORM_ref_sup8",
DW_FORM_strx1 => "DW_FORM_strx1",
DW_FORM_strx2 => "DW_FORM_strx2",
DW_FORM_strx3 => "DW_FORM_strx3",
DW_FORM_strx4 => "DW_FORM_strx4",
DW_FORM_addrx1 => "DW_FORM_addrx1",
DW_FORM_addrx2 => "DW_FORM_addrx2",
DW_FORM_addrx3 => "DW_FORM_addrx3",
DW_FORM_addrx4 => "DW_FORM_addrx4",
_ => "<unknown DW_FORM>",
}
}
impl DebugInfoBuilder {
pub fn create_namespace(&mut self, scope: u32, name: &str, _export_symbols: bool) -> u32 {
let ty = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(scope),
file: None,
line: None,
tag: DW_TAG_module,
flags: 0,
};
self.metadata_store.add_debug_type(ty)
}
pub fn create_forward_decl(
&mut self,
tag: u32,
name: &str,
scope: u32,
file: u32,
line: u32,
) -> u32 {
let ty = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(scope),
file: Some(file),
line: Some(line),
tag,
flags: DW_FLAG_artificial, };
self.metadata_store.add_debug_type(ty)
}
pub fn create_template_type_parameter(&mut self, scope: u32, name: &str, ty: u32) -> u32 {
let param = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(ty),
file: None,
line: None,
tag: DW_TAG_template_type_parameter,
flags: 0,
};
let id = self.metadata_store.add_debug_type(param);
let _scope_md = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(scope),
MetadataOperand::Metadata(id),
MetadataOperand::Metadata(DW_TAG_template_type_parameter),
]);
let _ = _scope_md;
id
}
pub fn create_template_value_parameter(
&mut self,
scope: u32,
name: &str,
ty: u32,
_value: u64,
) -> u32 {
let param = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(ty),
file: None,
line: None,
tag: DW_TAG_template_value_parameter,
flags: 0,
};
let id = self.metadata_store.add_debug_type(param);
let _scope_md = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(scope),
MetadataOperand::Metadata(id),
MetadataOperand::Metadata(DW_TAG_template_value_parameter),
]);
let _ = _scope_md;
id
}
pub fn create_static_member_type(
&mut self,
scope: u32,
name: &str,
file: u32,
line: u32,
ty: u32,
) -> u32 {
let member = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(ty),
file: Some(file),
line: Some(line),
tag: DW_TAG_member,
flags: DW_FLAG_static_member,
};
let id = self.metadata_store.add_debug_type(member);
let _scope_md = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(scope),
MetadataOperand::Metadata(id),
]);
let _ = _scope_md;
id
}
pub fn create_objc_property(
&mut self,
name: &str,
file: u32,
line: u32,
_getter_name: &str,
_setter_name: &str,
_property_attributes: u32,
ty: u32,
) -> u32 {
let property = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(ty),
file: Some(file),
line: Some(line),
tag: 0x41, flags: 0,
};
self.metadata_store.add_debug_type(property)
}
pub fn create_imported_entity(
&mut self,
scope: u32,
_decl: u32,
file: u32,
line: u32,
name: &str,
) -> u32 {
let imported = DIType {
name: name.to_string(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(scope),
file: Some(file),
line: Some(line),
tag: DW_TAG_imported_declaration,
flags: 0,
};
self.metadata_store.add_debug_type(imported)
}
pub fn create_artificial_type(&mut self, base_type: u32) -> u32 {
let artificial = DIType {
name: String::new(),
size_in_bits: 0,
align_in_bits: 0,
offset_in_bits: 0,
encoding: 0,
base_type: Some(base_type),
file: None,
line: None,
tag: 0, flags: DW_FLAG_artificial,
};
self.metadata_store.add_debug_type(artificial)
}
pub fn set_current_scope(&mut self, scope: u32) {
self.current_scope = Some(scope);
}
pub fn get_current_scope(&self) -> Option<u32> {
self.current_scope
}
pub fn push_scope(&mut self, new_scope: u32) {
if let Some(prev) = self.current_scope {
let _saved = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(prev),
MetadataOperand::Metadata(new_scope),
]);
let _ = _saved;
}
self.current_scope = Some(new_scope);
}
pub fn pop_scope(&mut self) {
self.current_scope = self.compile_units.first().copied();
}
pub fn begin_instruction(
&mut self,
_label: &ValueRef,
file: u32,
line: u32,
column: u32,
) -> u32 {
let scope = self.current_scope.unwrap_or(0);
self.create_debug_location(scope, file, line, column)
}
pub fn end_instruction(&mut self, _label: &ValueRef, file: u32, line: u32, column: u32) -> u32 {
let scope = self.current_scope.unwrap_or(0);
self.create_debug_location(scope, file, line, column)
}
pub fn finalize_subprogram(&mut self, sp: u32) -> u32 {
if !self.subprograms.contains(&sp) {
self.subprograms.push(sp);
}
for &cu_id in &self.compile_units {
let _sub_md = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(cu_id),
MetadataOperand::Metadata(sp),
]);
let _ = _sub_md;
}
sp
}
pub fn retain_type(&mut self, ty: u32) {
for &cu_id in &self.compile_units {
let _retain_md = self.metadata_store.create_md_node(vec![
MetadataOperand::Metadata(cu_id),
MetadataOperand::Metadata(ty),
]);
let _ = _retain_md;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_builder_empty() {
let builder = DebugInfoBuilder::new();
assert!(builder.compile_units.is_empty());
assert!(builder.subprograms.is_empty());
assert!(builder.local_variables.is_empty());
assert!(builder.global_variables.is_empty());
assert!(builder.current_scope.is_none());
assert!(builder.metadata_store.is_empty());
}
#[test]
fn test_create_file() {
let mut builder = DebugInfoBuilder::new();
let idx = builder.create_file("test.c", "/home/user");
let idx2 = builder.create_file("other.c", "/tmp");
assert_ne!(idx, idx2);
let file = builder.metadata_store.get_debug_file(idx);
assert!(file.is_some());
assert_eq!(file.unwrap().filename, "test.c");
}
#[test]
fn test_create_compile_unit() {
let mut builder = DebugInfoBuilder::new();
let idx = builder.create_compile_unit("main.c", "/src", "clang", false, "", 0);
assert_eq!(builder.compile_units.len(), 1);
assert_eq!(builder.compile_units[0], idx);
let cu = builder.metadata_store.get_debug_compile_unit(idx);
assert!(cu.is_some());
assert_eq!(cu.unwrap().language, DW_LANG_C);
assert_eq!(cu.unwrap().producer, "clang");
}
#[test]
fn test_create_compile_unit_with_language() {
let mut builder = DebugInfoBuilder::new();
let idx = builder.create_compile_unit("main.rs", "/src", "rustc", false, "rust", 0);
let cu = builder.metadata_store.get_debug_compile_unit(idx);
assert!(cu.is_some());
assert_eq!(cu.unwrap().language, DW_LANG_Rust);
}
#[test]
fn test_create_function() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("main.c", "/src");
let cu_idx = builder.create_compile_unit("main.c", "/src", "clang", false, "", 0);
let sub_idx =
builder.create_function(cu_idx, "main", "main", file_idx, 42, true, false, false);
assert_eq!(builder.subprograms.len(), 1);
assert_eq!(builder.subprograms[0], sub_idx);
let sub = builder.metadata_store.get_debug_subprogram(sub_idx);
assert!(sub.is_some());
assert_eq!(sub.unwrap().name, "main");
assert_eq!(sub.unwrap().line, 42);
assert!(sub.unwrap().is_definition);
}
#[test]
fn test_create_basic_type() {
let mut builder = DebugInfoBuilder::new();
let ty_idx = builder.create_basic_type("int", 32, DW_ATE_signed);
let ty = builder.metadata_store.get_debug_type(ty_idx);
assert!(ty.is_some());
assert_eq!(ty.unwrap().name, "int");
}
#[test]
fn test_create_pointer_type() {
let mut builder = DebugInfoBuilder::new();
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let ptr_ty = builder.create_pointer_type(int_ty, 64, 64);
let ty = builder.metadata_store.get_debug_type(ptr_ty);
assert!(ty.is_some());
}
#[test]
fn test_create_struct_type() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let float_ty = builder.create_basic_type("float", 32, DW_ATE_float);
let struct_idx = builder.create_struct_type(
0, "Point",
file_idx,
10,
64,
64,
&[int_ty, float_ty],
);
let ty = builder.metadata_store.get_debug_type(struct_idx);
assert!(ty.is_some());
assert_eq!(ty.unwrap().name, "Point");
}
#[test]
fn test_create_array_type() {
let mut builder = DebugInfoBuilder::new();
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let arr_idx = builder.create_array_type(int_ty, 10, 320);
let ty = builder.metadata_store.get_debug_type(arr_idx);
assert!(ty.is_some());
assert_eq!(ty.unwrap().size_in_bits, 320);
}
#[test]
fn test_create_subroutine_type() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let float_ty = builder.create_basic_type("float", 32, DW_ATE_float);
let subr_idx = builder.create_subroutine_type(file_idx, &[int_ty, float_ty]);
let ty = builder.metadata_store.get_debug_type(subr_idx);
assert!(ty.is_some());
}
#[test]
fn test_create_member_type() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let member_idx = builder.create_member_type(
0, "x", file_idx, 11, 32, 32, 0, int_ty,
);
let ty = builder.metadata_store.get_debug_type(member_idx);
assert!(ty.is_some());
assert_eq!(ty.unwrap().name, "x");
}
#[test]
fn test_create_inheritance() {
let mut builder = DebugInfoBuilder::new();
let base_ty = builder.create_basic_type("Base", 64, DW_ATE_signed);
let inh_idx = builder.create_inheritance(0, base_ty, 0);
let ty = builder.metadata_store.get_debug_type(inh_idx);
assert!(ty.is_some());
}
#[test]
fn test_create_auto_variable() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let cu_idx = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
let sub_idx =
builder.create_function(cu_idx, "foo", "foo", file_idx, 5, true, false, false);
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let var_idx = builder.create_auto_variable(sub_idx, "x", file_idx, 7, int_ty);
assert_eq!(builder.local_variables.len(), 1);
assert_eq!(builder.local_variables[0], var_idx);
let var = builder.metadata_store.get_debug_local_var(var_idx);
assert!(var.is_some());
assert_eq!(var.unwrap().name, "x");
}
#[test]
fn test_create_parameter_variable() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let cu_idx = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
let sub_idx =
builder.create_function(cu_idx, "foo", "foo", file_idx, 5, true, false, false);
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let param_idx = builder.create_parameter_variable(sub_idx, "argc", 1, file_idx, 5, int_ty);
assert_eq!(builder.local_variables.len(), 1);
let var = builder.metadata_store.get_debug_local_var(param_idx);
assert!(var.is_some());
assert_eq!(var.unwrap().name, "argc");
assert_eq!(var.unwrap().arg, Some(1));
}
#[test]
fn test_create_global_variable() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let cu_idx = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let gv_idx = builder.create_global_variable(
cu_idx,
"g_counter",
"g_counter",
file_idx,
1,
int_ty,
false,
);
assert_eq!(builder.global_variables.len(), 1);
let gv = builder.metadata_store.get_debug_global_var(gv_idx);
assert!(gv.is_some());
assert_eq!(gv.unwrap().name, "g_counter");
}
#[test]
fn test_create_lexical_block() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let block_idx = builder.create_lexical_block(0, file_idx, 10, 5);
assert!(block_idx < 10_000_000); }
#[test]
fn test_create_inlined_subroutine() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let inline_idx = builder.create_inlined_subroutine(0, 1, file_idx, 15);
assert!(inline_idx < 10_000_000);
}
#[test]
fn test_create_debug_location() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let loc_idx = builder.create_debug_location(0, file_idx, 42, 8);
let loc = builder.metadata_store.get_debug_location(loc_idx);
assert!(loc.is_some());
assert_eq!(loc.unwrap().line, 42);
}
#[test]
fn test_insert_declare_and_value() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let cu_idx = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
let sub_idx =
builder.create_function(cu_idx, "foo", "foo", file_idx, 5, true, false, false);
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
let var_idx = builder.create_auto_variable(sub_idx, "x", file_idx, 7, int_ty);
let loc_idx = builder.create_debug_location(sub_idx, file_idx, 7, 4);
let alloca = valref(Value::new(Type::pointer(0)));
let declare = builder.insert_declare(&alloca, var_idx, loc_idx);
assert_eq!(declare.borrow().name, "llvm.dbg.declare");
let value = valref(Value::new(Type::i32()));
let dbg_val = builder.insert_value(&value, var_idx, loc_idx);
assert_eq!(dbg_val.borrow().name, "llvm.dbg.value");
}
#[test]
fn test_finalize_and_emit() {
let mut builder = DebugInfoBuilder::new();
let file_id = builder.create_file("test.c", "/src");
let cu_id = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
builder.finalize();
let store = builder.emit_to_metadata_store();
let file = store.get_debug_file(file_id);
assert!(file.is_some());
assert_eq!(file.unwrap().filename, "test.c");
let cu = store.get_debug_compile_unit(cu_id);
assert!(cu.is_some());
}
#[test]
fn test_language_to_dwarf() {
assert_eq!(language_to_dwarf("c"), DW_LANG_C89);
assert_eq!(language_to_dwarf("c99"), DW_LANG_C99);
assert_eq!(language_to_dwarf("c11"), DW_LANG_C11);
assert_eq!(language_to_dwarf("c17"), DW_LANG_C17);
assert_eq!(language_to_dwarf("c++"), DW_LANG_C_plus_plus);
assert_eq!(language_to_dwarf("c++11"), DW_LANG_C_plus_plus_11);
assert_eq!(language_to_dwarf("c++14"), DW_LANG_C_plus_plus_14);
assert_eq!(language_to_dwarf("c++17"), DW_LANG_C_plus_plus_17);
assert_eq!(language_to_dwarf("c++20"), DW_LANG_C_plus_plus_20);
assert_eq!(language_to_dwarf("rust"), DW_LANG_Rust);
assert_eq!(language_to_dwarf("swift"), DW_LANG_Swift);
assert_eq!(language_to_dwarf("go"), DW_LANG_Go);
assert_eq!(language_to_dwarf("java"), DW_LANG_Java);
assert_eq!(language_to_dwarf("python"), DW_LANG_Python);
assert_eq!(language_to_dwarf("opencl"), DW_LANG_OpenCL);
assert_eq!(language_to_dwarf("haskell"), DW_LANG_Haskell);
assert_eq!(language_to_dwarf("ocaml"), DW_LANG_OCaml);
assert_eq!(language_to_dwarf("julia"), DW_LANG_Julia);
assert_eq!(language_to_dwarf("d"), DW_LANG_D);
assert_eq!(language_to_dwarf("objc"), DW_LANG_ObjC);
assert_eq!(language_to_dwarf("objc++"), DW_LANG_ObjC_plus_plus);
assert_eq!(language_to_dwarf("zig"), DW_LANG_Zig);
assert_eq!(language_to_dwarf("unknown_lang"), DW_LANG_C);
assert_eq!(language_to_dwarf("RUST"), DW_LANG_Rust);
assert_eq!(language_to_dwarf("Go"), DW_LANG_Go);
}
#[test]
fn test_create_function_debug_info_convenience() {
let mut builder = DebugInfoBuilder::new();
let sub_idx = create_function_debug_info(&mut builder, "my_func", "source.c", 100);
assert_eq!(builder.subprograms.len(), 1);
assert_eq!(builder.subprograms[0], sub_idx);
assert_eq!(builder.current_scope, Some(sub_idx));
assert_eq!(builder.compile_units.len(), 1);
let sub = builder.metadata_store.get_debug_subprogram(sub_idx);
assert!(sub.is_some());
assert_eq!(sub.unwrap().name, "my_func");
assert_eq!(sub.unwrap().line, 100);
}
#[test]
fn test_insert_debug_intrinsics_convenience() {
let mut builder = DebugInfoBuilder::new();
let file_idx = builder.create_file("test.c", "/src");
let cu_idx = builder.create_compile_unit("test.c", "/src", "clang", false, "", 0);
let sub_idx =
builder.create_function(cu_idx, "foo", "foo", file_idx, 5, true, false, false);
let int_ty = builder.create_basic_type("int", 32, DW_ATE_signed);
builder.create_auto_variable(sub_idx, "x", file_idx, 7, int_ty);
builder.create_auto_variable(sub_idx, "y", file_idx, 8, int_ty);
let loc_idx = builder.create_debug_location(sub_idx, file_idx, 9, 4);
let bb = valref(Value::new(Type::label()).with_subclass(SubclassKind::BasicBlock));
let intrinsics = insert_debug_intrinsics(&mut builder, &bb, loc_idx);
assert_eq!(intrinsics.len(), 2);
for intrinsic in &intrinsics {
assert_eq!(intrinsic.borrow().name, "llvm.dbg.value");
}
}
}