Add debug info for globals. Misc debug info cleanup.

This commit is contained in:
lachsinc
2018-09-26 02:01:03 +10:00
parent 1ee0fe7457
commit 0f6c1f3482
2 changed files with 130 additions and 32 deletions
+77 -23
View File
@@ -26,6 +26,8 @@ struct irModule {
Map<irValue *> anonymous_proc_lits; // Key: Ast * Map<irValue *> anonymous_proc_lits; // Key: Ast *
irDebugInfo * debug_compile_unit; irDebugInfo * debug_compile_unit;
irDebugInfo * debug_all_enums; // irDebugInfoArray
irDebugInfo * debug_all_globals; // irDebugInfoArray
@@ -517,7 +519,6 @@ enum irDebugEncoding {
irDebugBasicEncoding_enumeration_type = 4, irDebugBasicEncoding_enumeration_type = 4,
irDebugBasicEncoding_structure_type = 19, irDebugBasicEncoding_structure_type = 19,
irDebugBasicEncoding_union_type = 23, irDebugBasicEncoding_union_type = 23,
}; };
enum irDebugInfoKind { enum irDebugInfoKind {
@@ -534,6 +535,7 @@ enum irDebugInfoKind {
irDebugInfo_DerivedType, // pointer, typedef irDebugInfo_DerivedType, // pointer, typedef
irDebugInfo_CompositeType, // array, struct, enum, (raw_)union irDebugInfo_CompositeType, // array, struct, enum, (raw_)union
irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum
irDebugInfo_GlobalVariableExpression, // for describe if global is const or not
irDebugInfo_GlobalVariable, irDebugInfo_GlobalVariable,
irDebugInfo_LocalVariable, irDebugInfo_LocalVariable,
@@ -617,14 +619,18 @@ struct irDebugInfo {
String name; String name;
i64 value; i64 value;
} Enumerator; } Enumerator;
struct {
irDebugInfo *var;
} GlobalVariableExpression;
struct { struct {
String name; String name;
String linkage_name; String linkage_name;
irDebugInfo *scope; irDebugInfo *scope;
irDebugInfo *file; irDebugInfo *file;
TokenPos pos; TokenPos pos;
irDebugInfo *type;
irValue *variable; irValue *variable;
irDebugInfo *declaration; // irDebugInfo *declaration;
} GlobalVariable; } GlobalVariable;
struct { struct {
String name; String name;
@@ -1543,11 +1549,17 @@ irDebugInfo *ir_add_debug_info_array(irModule *module, isize count, isize capaci
return di; return di;
} }
irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { irDebugInfo *ir_add_debug_info_file(irModule *module, AstFile *file) {
// if (!proc->module->generate_debug_info) { // if (!proc->module->generate_debug_info) {
// return nullptr; // return nullptr;
// } // }
irDebugInfo **existing = map_get(&module->debug_info, hash_ast_file(file));
if (existing != nullptr) {
GB_ASSERT((*existing)->kind == irDebugInfo_File);
return *existing;
}
GB_ASSERT(file != nullptr); GB_ASSERT(file != nullptr);
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_File); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_File);
di->File.file = file; di->File.file = file;
@@ -1570,7 +1582,7 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
di->File.filename = filename; di->File.filename = filename;
di->File.directory = directory; di->File.directory = directory;
map_set(&proc->module->debug_info, hash_ast_file(file), di); map_set(&module->debug_info, hash_ast_file(file), di);
return di; return di;
} }
@@ -1612,12 +1624,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
case Basic_any: case Basic_any:
case Basic_rawptr: case Basic_rawptr:
case Basic_cstring: // TODO(lachsinc)
return irDebugBasicEncoding_address; return irDebugBasicEncoding_address;
// case Basic_complex32: // case Basic_complex32:
case Basic_complex64: case Basic_complex64:
case Basic_complex128: case Basic_complex128:
case Basic_cstring:
case Basic_string: case Basic_string:
break; // not a "DIBasicType" break; // not a "DIBasicType"
} }
@@ -1692,9 +1704,9 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop
// TODO(lachsinc): Necessary ? // TODO(lachsinc): Necessary ?
di->CompositeType.size = 8*cast(i32)(type_size_of(t_rawptr) + di->CompositeType.size = 8*cast(i32)(type_size_of(t_rawptr) +
type_size_of(t_int) + type_size_of(t_int) +
type_size_of(t_int) + type_size_of(t_int) +
type_size_of(t_allocator)); // TODO(lachsinc): Allocator is correct size?? type_size_of(t_allocator)); // TODO(lachsinc): Allocator is correct size??
di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr);
di->CompositeType.elements = ir_add_debug_info_array(module, 0, 4); di->CompositeType.elements = ir_add_debug_info_array(module, 0, 4);
@@ -1847,7 +1859,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity
for_array(field_index, base->Struct.fields) { for_array(field_index, base->Struct.fields) {
array_add(&di->CompositeType.elements->DebugInfoArray.elements, array_add(&di->CompositeType.elements->DebugInfoArray.elements,
ir_add_debug_info_field(module, di, base->Struct.fields[field_index], cast(i32)field_index, ir_add_debug_info_field(module, di, base->Struct.fields[field_index], cast(i32)field_index,
base->Struct.fields[field_index]->type, file)); base->Struct.fields[field_index]->type, file));
} }
di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.tag = irDebugBasicEncoding_structure_type;
} else if (is_type_union(type)) { } else if (is_type_union(type)) {
@@ -1865,6 +1877,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity
ir_add_debug_info_enumerator(module, base->Enum.fields[field_index])); ir_add_debug_info_enumerator(module, base->Enum.fields[field_index]));
} }
di->CompositeType.tag = irDebugBasicEncoding_enumeration_type; di->CompositeType.tag = irDebugBasicEncoding_enumeration_type;
// TODO(lachsinc): Do we want to ensure this is an enum in the global scope before
// adding it into the modules enum array ??
array_add(&module->debug_all_enums->DebugInfoArray.elements, di);
} }
return di; return di;
@@ -1902,10 +1918,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity
return di; return di;
} }
// TODO(lachsinc): Not sure if correct.. Also cleanup
// NOTE(lachsinc): For now dynamic arrays are just a pointer to their data.
// We could get fancy and use a composite type along with
// DW_TAG_class_type / template debug stuff eventually.
if (is_type_dynamic_array(type)) { if (is_type_dynamic_array(type)) {
return ir_add_debug_info_dynamic_array(module, scope, e, type, file); return ir_add_debug_info_dynamic_array(module, scope, e, type, file);
} }
@@ -1960,6 +1972,36 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity
} }
} }
irDebugInfo *ir_add_debug_info_global(irModule *module, irDebugInfo *scope, irValue *v) {
// if (!proc->module->generate_debug_info) {
// return nullptr;
// }
Entity *e = v->Global.entity;
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_GlobalVariableExpression);
irDebugInfo *var_di = ir_alloc_debug_info(irDebugInfo_GlobalVariable);
var_di->GlobalVariable.name = e->token.string;
var_di->GlobalVariable.scope = scope;
var_di->GlobalVariable.file = scope;
var_di->GlobalVariable.pos = e->token.pos;
var_di->GlobalVariable.type = ir_add_debug_info_type(module, scope, e, e->type, scope);
var_di->GlobalVariable.variable = v;
// NOTE(lachsinc): The "DIGlobalVariableExpression" owns us, and is what we refer to from other
// locations in the ir source, so we will reserve the "e" hash for it, and use something else
// unique for the DIGlobalVariable's hash.
map_set(&module->debug_info, hash_pointer(var_di), var_di);
di->GlobalVariableExpression.var = var_di;
map_set(&module->debug_info, hash_entity(e), di);
array_add(&module->debug_all_globals->DebugInfoArray.elements, di);
return di;
}
irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *e, i32 arg_id) { irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *e, i32 arg_id) {
// if (!proc->module->generate_debug_info) { // if (!proc->module->generate_debug_info) {
// return nullptr; // return nullptr;
@@ -7997,16 +8039,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
proc->is_export = e->Procedure.is_export; proc->is_export = e->Procedure.is_export;
proc->is_foreign = e->Procedure.is_foreign; proc->is_foreign = e->Procedure.is_foreign;
irDebugInfo *di_file = nullptr; irDebugInfo *di_file = ir_add_debug_info_file(m, f);
irDebugInfo **di_file_found = map_get(&m->debug_info, hash_ast_file(f));
if (di_file_found) {
di_file = *di_file_found;
GB_ASSERT(di_file->kind == irDebugInfo_File);
} else {
di_file = ir_add_debug_info_file(proc, f);
}
ir_add_debug_info_proc(proc, e, proc->name, di_file); ir_add_debug_info_proc(proc, e, proc->name, di_file);
} }
@@ -8083,6 +8116,17 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
void ir_module_add_value(irModule *m, Entity *e, irValue *v) { void ir_module_add_value(irModule *m, Entity *e, irValue *v) {
map_set(&m->values, hash_entity(e), v); map_set(&m->values, hash_entity(e), v);
// TODO(lachsinc): This may not be the most sensible place to do this!
// it may be more sensible to look for more specific locations that call ir_value_global and assign it a value? maybe?
// ir_value_global itself doesn't have access to module and I'm trying to minimise changes to non-debug ir stuff.
if (v->kind == irValue_Global && v->Global.value != nullptr && e->state == EntityState_Resolved) {
CheckerInfo *info = m->info;
String filename = e->token.pos.file;
AstFile *f = ast_file_of_filename(info, filename);
GB_ASSERT(f);
irDebugInfo *di_file = ir_add_debug_info_file(m, f);
ir_add_debug_info_global(m, di_file, v);
}
} }
void ir_init_module(irModule *m, Checker *c) { void ir_init_module(irModule *m, Checker *c) {
@@ -8203,6 +8247,16 @@ void ir_init_module(irModule *m, Checker *c) {
map_set(&m->debug_info, hash_pointer(m), di); map_set(&m->debug_info, hash_pointer(m), di);
m->debug_compile_unit = di; m->debug_compile_unit = di;
irDebugInfo *enums_di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray);
array_init(&enums_di->DebugInfoArray.elements, heap_allocator()); // TODO(lachsinc): ir_allocator() ??
map_set(&m->debug_info, hash_pointer(enums_di), enums_di); // TODO(lachsinc): Safe to hash this pointer for key?
m->debug_all_enums = enums_di;
irDebugInfo *globals_di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray);
array_init(&globals_di->DebugInfoArray.elements, heap_allocator()); // TODO(lachsinc): ir_allocator() ??
map_set(&m->debug_info, hash_pointer(globals_di), globals_di); // TODO(lachsinc): Safe to hash this pointer for key?
m->debug_all_globals = globals_di;
} }
} }
+53 -9
View File
@@ -1902,6 +1902,15 @@ void print_llvm_ir(irGen *ir) {
} else { } else {
ir_write_string(f, str_lit("zeroinitializer")); ir_write_string(f, str_lit("zeroinitializer"));
} }
if (m->generate_debug_info) {
irDebugInfo **di_lookup = map_get(&m->debug_info, hash_entity(g->entity));
if (di_lookup != nullptr) {
irDebugInfo *di = *di_lookup;
GB_ASSERT(di);
GB_ASSERT(di->kind == irDebugInfo_GlobalVariableExpression);
ir_fprintf(f, ", !dbg !%d", di->id);
}
}
} }
ir_write_byte(f, '\n'); ir_write_byte(f, '\n');
} }
@@ -1946,11 +1955,14 @@ void print_llvm_ir(irGen *ir) {
", runtimeVersion: 0" ", runtimeVersion: 0"
", isOptimized: false" ", isOptimized: false"
", emissionKind: FullDebug" ", emissionKind: FullDebug"
", retainedTypes: !0" ", retainedTypes: !0" // TODO(lachsinc)
", enums: !0" ", enums: !%d"
", globals: !0" ", globals: !%d"
")", ")",
file->id, LIT(build_context.ODIN_VERSION)); file->id,
LIT(build_context.ODIN_VERSION),
m->debug_all_enums->id,
m->debug_all_globals->id);
break; break;
} }
case irDebugInfo_File: case irDebugInfo_File:
@@ -1961,7 +1973,7 @@ void print_llvm_ir(irGen *ir) {
ir_fprintf(f, ")"); ir_fprintf(f, ")");
break; break;
case irDebugInfo_Proc: case irDebugInfo_Proc:
// TODO(lach): We need to store scope info inside di, not just file info, for procs. // TODO(lachsinc): We need to store scope info inside di, not just file info, for procs.
ir_fprintf(f, "distinct !DISubprogram(" ir_fprintf(f, "distinct !DISubprogram("
"name: \"%.*s\"" "name: \"%.*s\""
", linkageName: \"%.*s\"" ", linkageName: \"%.*s\""
@@ -1970,7 +1982,7 @@ void print_llvm_ir(irGen *ir) {
", line: %td" ", line: %td"
", scopeLine: %td" ", scopeLine: %td"
", isDefinition: true" ", isDefinition: true"
", isLocal: false" // TODO(lach): This used to be always set to true, pretend no local for now. We need to check if scope == file. ", isLocal: false" // TODO(lachsinc): This used to be always set to true, pretend no local for now. We need to check if scope == file.
", flags: DIFlagPrototyped" ", flags: DIFlagPrototyped"
", isOptimized: false" ", isOptimized: false"
", unit: !%d" ", unit: !%d"
@@ -1985,6 +1997,39 @@ void print_llvm_ir(irGen *ir) {
di->Proc.types->id); di->Proc.types->id);
ir_write_byte(f, ')'); // !DISubprogram( ir_write_byte(f, ')'); // !DISubprogram(
break; break;
case irDebugInfo_GlobalVariableExpression: {
ir_fprintf(f, "!DIGlobalVariableExpression("
"var: !%d"
", expr: !DIExpression(",
di->GlobalVariableExpression.var->id);
if (di->GlobalVariableExpression.var->GlobalVariable.variable->Global.is_constant) {
ir_write_str_lit(f, "DW_OP_constu, ");
// TODO(lachsinc): Confirm this prints the type as llvm expects eg. hex representation for float is safe etc.
ir_print_value(f, m, di->GlobalVariable.variable, ir_type(di->GlobalVariable.variable));
ir_write_str_lit(f, ", DW_OP_stack_value");
} else {
// NOTE(lachsinc): non-const globals expect empty "!DIExpression()"
}
ir_write_byte(f, ')'); // !DIExpression(
ir_write_byte(f, ')'); // !DIGlobalVariableExpression(
break;
}
case irDebugInfo_GlobalVariable: {
ir_fprintf(f, "distinct !DIGlobalVariable("
"name: \"%.*s\""
", scope: !%d"
", file: !%d"
", line: %d"
", type: !%d"
", isLocal: true" // TODO(lachsinc): Check is_foreign ??
", isDefinition: true)", // TODO(lachsinc): Check is_foreign ??
LIT(di->GlobalVariable.name),
di->GlobalVariable.scope->id,
di->GlobalVariable.file->id,
di->GlobalVariable.pos.line,
di->GlobalVariable.type->id);
break;
}
case irDebugInfo_LocalVariable: { case irDebugInfo_LocalVariable: {
ir_fprintf(f, "!DILocalVariable(" ir_fprintf(f, "!DILocalVariable("
"name: \"%.*s\"" "name: \"%.*s\""
@@ -2082,13 +2127,12 @@ void print_llvm_ir(irGen *ir) {
case irDebugInfo_Enumerator: { case irDebugInfo_Enumerator: {
ir_fprintf(f, "!DIEnumerator(" ir_fprintf(f, "!DIEnumerator("
"name: \"%.*s\"" "name: \"%.*s\""
", value: %d", // TODO(lachsinc): PRId64 equiv? ", value: %d)", // TODO(lachsinc): PRId64 equiv?
LIT(di->Enumerator.name), LIT(di->Enumerator.name),
di->Enumerator.value); di->Enumerator.value);
ir_write_byte(f, ')');
break; break;
} }
// TODO(lach): Merge w/ DebugInfoArray // TODO(lachsinc): Merge w/ DebugInfoArray
case irDebugInfo_AllProcs: case irDebugInfo_AllProcs:
ir_fprintf(f, "!{"); ir_fprintf(f, "!{");
for_array(proc_index, di->AllProcs.procs) { for_array(proc_index, di->AllProcs.procs) {