X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbedwarf.c;h=0c11b4fb785fbdd3f0fabe3bfbdf6c967cf4d726;hb=34e3b8d50bce639e760da7233524a4db85c80290;hp=fba835eac7b94bb3dc64e362c543b012136f420a;hpb=fc0226bb6efed18fbc823d9ebd6c6b3707b6f3d5;p=libfirm diff --git a/ir/be/bedwarf.c b/ir/be/bedwarf.c index fba835eac..0c11b4fb7 100644 --- a/ir/be/bedwarf.c +++ b/ir/be/bedwarf.c @@ -1,20 +1,6 @@ /* - * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved. - * * This file is part of libFirm. - * - * This file may be distributed and/or modified under the terms of the - * GNU General Public License version 2 as published by the Free Software - * Foundation and appearing in the file LICENSE.GPL included in the - * packaging of this file. - * - * Licensees holding valid libFirm Professional Edition licenses may use - * this file in accordance with the libFirm Commercial License. - * Agreement provided with the Software. - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE. + * Copyright (C) 2012 University of Karlsruhe. */ /** @@ -28,7 +14,9 @@ #include #include +#include "bearch.h" #include "bedwarf_t.h" +#include "error.h" #include "obst.h" #include "irprog.h" #include "irgraph.h" @@ -40,20 +28,56 @@ #include "util.h" #include "obst.h" #include "array_t.h" -#include "be_dbgout_t.h" +#include "irtools.h" +#include "lc_opts.h" +#include "lc_opts_enum.h" #include "beabi.h" #include "bemodule.h" #include "beemitter.h" #include "dbginfo.h" #include "begnuas.h" +#include "typerep.h" + +enum { + LEVEL_NONE, + LEVEL_BASIC, + LEVEL_LOCATIONS, + LEVEL_FRAMEINFO +}; +static int debug_level = LEVEL_NONE; + +/** + * Usually we simply use the DW_TAG_xxx numbers for our abbrev IDs, but for + * the cases where we need multiple ids with the same DW_TAG we define new IDs + * here + */ +typedef enum custom_abbrevs { + abbrev_void_subprogram = 1, + abbrev_subprogram, + abbrev_formal_parameter, + abbrev_unnamed_formal_parameter, + abbrev_formal_parameter_no_location, + abbrev_variable, + abbrev_compile_unit, + abbrev_base_type, + abbrev_pointer_type, + abbrev_void_pointer_type, + abbrev_array_type, + abbrev_subrange_type, + abbrev_structure_type, + abbrev_union_type, + abbrev_class_type, + abbrev_member, + abbrev_bitfield_member, + abbrev_subroutine_type, + abbrev_void_subroutine_type, +} custom_abbrevs; /** * The dwarf handle. */ typedef struct dwarf_t { - dbg_handle base; /**< the base class */ const ir_entity *cur_ent; /**< current method entity */ - const be_stack_layout_t *layout; /**< current stack layout */ unsigned next_type_nr; /**< next type number */ pmap *file_map; /**< a map from file names to number in file list */ const char **file_list; @@ -65,19 +89,22 @@ typedef struct dwarf_t { unsigned last_line; } dwarf_t; +static dwarf_t env; + static dwarf_source_language language; -static const char *comp_dir; +static char *comp_dir; -static unsigned insert_file(dwarf_t *env, const char *filename) +static unsigned insert_file(const char *filename) { unsigned num; - void *entry = pmap_get(env->file_map, filename); + void *entry = pmap_get(void, env.file_map, filename); if (entry != NULL) { return PTR_TO_INT(entry); } - ARR_APP1(const char*, env->file_list, filename); - num = (unsigned)ARR_LEN(env->file_list); - pmap_insert(env->file_map, filename, INT_TO_PTR(num)); + ARR_APP1(const char*, env.file_list, filename); + num = (unsigned)ARR_LEN(env.file_list); + pmap_insert(env.file_map, filename, INT_TO_PTR(num)); + /* TODO: quote chars in string */ be_emit_irprintf("\t.file %u \"%s\"\n", num, filename); return num; @@ -117,12 +144,22 @@ static unsigned get_uleb128_size(unsigned value) return size; } -static void emit_string(const char *string) +static void emit_sleb128(long value) { - be_emit_irprintf("\t.asciz \"%s\"\n", string); + be_emit_irprintf("\t.sleb128 %ld\n", value); be_emit_write_line(); } +static unsigned get_sleb128_size(long value) +{ + unsigned size = 0; + do { + value >>= 7; + size += 1; + } while (value != 0 && value != -1); + return size; +} + static void emit_ref(const ir_entity *entity) { be_emit_cstring("\t.long "); @@ -178,7 +215,8 @@ static void register_attribute(dwarf_attribute attribute, dwarf_form form) emit_uleb128(form); } -static void begin_abbrev(unsigned code, dwarf_tag tag, dw_children children) +static void begin_abbrev(custom_abbrevs code, dwarf_tag tag, + dw_children children) { emit_uleb128(code); emit_uleb128(tag); @@ -191,7 +229,7 @@ static void end_abbrev(void) emit_uleb128(0); } -static void emit_line_info(dwarf_t *env) +static void emit_line_info(void) { be_gas_emit_switch_section(GAS_SECTION_DEBUG_LINE); @@ -223,12 +261,12 @@ static void emit_line_info(dwarf_t *env) emit_uleb128(1); /* include directory list */ - emit_string("/foo/bar"); + be_gas_emit_cstring("/foo/bar"); emit_int8(0); /* file list */ - for (i = 0; i < ARR_LEN(env->file_list); ++i) { - emit_string(env->file_list[0]); + for (i = 0; i < ARR_LEN(env.file_list); ++i) { + be_gas_emit_cstring(env.file_list[i]); emit_uleb128(1); /* directory */ emit_uleb128(0); /* modification time */ emit_uleb128(0); /* file length */ @@ -243,7 +281,7 @@ static void emit_line_info(dwarf_t *env) } } -static void emit_pubnames(dwarf_t *env) +static void emit_pubnames(void) { size_t i; @@ -256,37 +294,65 @@ static void emit_pubnames(dwarf_t *env) emit_size("info_section_begin", "info_begin"); emit_size("compile_unit_begin", "compile_unit_end"); - for (i = 0; i < ARR_LEN(env->pubnames_list); ++i) { - const ir_entity *entity = env->pubnames_list[i]; + for (i = 0; i < ARR_LEN(env.pubnames_list); ++i) { + const ir_entity *entity = env.pubnames_list[i]; be_emit_irprintf("\t.long %sE%ld - %sinfo_begin\n", be_gas_get_private_prefix(), get_entity_nr(entity), be_gas_get_private_prefix()); - emit_string(get_entity_name(entity)); + be_gas_emit_cstring(get_entity_name(entity)); } emit_int32(0); emit_label("pubnames_end"); } -static void dwarf_set_dbg_info(dbg_handle *h, dbg_info *dbgi) +void be_dwarf_location(dbg_info *dbgi) { - dwarf_t *const env = (dwarf_t*)h; - src_loc_t const loc = ir_retrieve_dbg_info(dbgi); - unsigned filenum; + src_loc_t loc; + unsigned filenum; + if (debug_level < LEVEL_LOCATIONS) + return; + loc = ir_retrieve_dbg_info(dbgi); if (!loc.file) return; - filenum = insert_file(env, loc.file); + filenum = insert_file(loc.file); be_emit_irprintf("\t.loc %u %u %u\n", filenum, loc.line, loc.column); be_emit_write_line(); } +void be_dwarf_callframe_register(const arch_register_t *reg) +{ + if (debug_level < LEVEL_FRAMEINFO) + return; + be_emit_cstring("\t.cfi_def_cfa_register "); + be_emit_irprintf("%d\n", reg->dwarf_number); + be_emit_write_line(); +} + +void be_dwarf_callframe_offset(int offset) +{ + if (debug_level < LEVEL_FRAMEINFO) + return; + be_emit_cstring("\t.cfi_def_cfa_offset "); + be_emit_irprintf("%d\n", offset); + be_emit_write_line(); +} + +void be_dwarf_callframe_spilloffset(const arch_register_t *reg, int offset) +{ + if (debug_level < LEVEL_FRAMEINFO) + return; + be_emit_cstring("\t.cfi_offset "); + be_emit_irprintf("%d, %d\n", reg->dwarf_number, offset); + be_emit_write_line(); +} + static bool is_extern_entity(const ir_entity *entity) { ir_visited_t visibility = get_entity_visibility(entity); - return visibility == ir_visibility_default - || visibility == ir_visibility_external; + return visibility == ir_visibility_external; } static void emit_entity_label(const ir_entity *entity) @@ -303,77 +369,172 @@ static void register_dbginfo_attributes(void) register_attribute(DW_AT_decl_column, DW_FORM_udata); } -/** - * Emit values for DW_AT_decl_file, DW_AT_decl_line and DW_AT_decl_column. - */ -static void emit_dbginfo(dwarf_t *env, const dbg_info *dbgi) +static void emit_dbginfo(const dbg_info *dbgi) { src_loc_t const loc = ir_retrieve_dbg_info(dbgi); - unsigned const file = loc.file ? insert_file(env, loc.file) : 0; + unsigned const file = loc.file ? insert_file(loc.file) : 0; emit_uleb128(file); emit_uleb128(loc.line); emit_uleb128(loc.column); } +static void emit_type_address(const ir_type *type) +{ + be_emit_irprintf("\t.long %sT%ld - %sinfo_begin\n", + be_gas_get_private_prefix(), + get_type_nr(type), be_gas_get_private_prefix()); + be_emit_write_line(); +} + static void emit_subprogram_abbrev(void) { - begin_abbrev(DW_TAG_subprogram, DW_TAG_subprogram, DW_CHILDREN_no); + begin_abbrev(abbrev_subprogram, DW_TAG_subprogram, DW_CHILDREN_yes); register_attribute(DW_AT_name, DW_FORM_string); register_dbginfo_attributes(); + register_attribute(DW_AT_type, DW_FORM_ref4); + register_attribute(DW_AT_external, DW_FORM_flag); + register_attribute(DW_AT_low_pc, DW_FORM_addr); + register_attribute(DW_AT_high_pc, DW_FORM_addr); //register_attribute(DW_AT_prototyped, DW_FORM_flag); - //register_attribute(DW_AT_type, DW_FORM_ref4); - register_attribute(DW_AT_external, DW_FORM_flag); - register_attribute(DW_AT_low_pc, DW_FORM_addr); - register_attribute(DW_AT_high_pc, DW_FORM_addr); - //register_attribute(DW_AT_frame_base, DW_FORM_block1); + if (debug_level >= LEVEL_FRAMEINFO) + register_attribute(DW_AT_frame_base, DW_FORM_block1); + end_abbrev(); + + begin_abbrev(abbrev_void_subprogram, DW_TAG_subprogram, DW_CHILDREN_yes); + register_attribute(DW_AT_name, DW_FORM_string); + register_dbginfo_attributes(); + register_attribute(DW_AT_external, DW_FORM_flag); + register_attribute(DW_AT_low_pc, DW_FORM_addr); + register_attribute(DW_AT_high_pc, DW_FORM_addr); + //register_attribute(DW_AT_prototyped, DW_FORM_flag); + if (debug_level >= LEVEL_FRAMEINFO) + register_attribute(DW_AT_frame_base, DW_FORM_block1); + end_abbrev(); + + begin_abbrev(abbrev_formal_parameter, DW_TAG_formal_parameter, + DW_CHILDREN_no); + register_attribute(DW_AT_name, DW_FORM_string); + register_dbginfo_attributes(); + register_attribute(DW_AT_type, DW_FORM_ref4); + register_attribute(DW_AT_location, DW_FORM_block1); + end_abbrev(); + + begin_abbrev(abbrev_formal_parameter_no_location, DW_TAG_formal_parameter, + DW_CHILDREN_no); + register_attribute(DW_AT_name, DW_FORM_string); + register_dbginfo_attributes(); + register_attribute(DW_AT_type, DW_FORM_ref4); end_abbrev(); } -/** - * dump the drwarf for a method begin - */ -static void dwarf_method_begin(dbg_handle *handle, const ir_entity *entity) +static void emit_type(ir_type *type); + +static void emit_stack_location(long offset) +{ + unsigned size = 1 + get_sleb128_size(offset); + emit_int8(size); + emit_int8(DW_OP_fbreg); + emit_sleb128(offset); +} + +static void emit_function_parameters(const ir_entity *entity, + const parameter_dbg_info_t *infos) +{ + ir_type *type = get_entity_type(entity); + size_t n_params = get_method_n_params(type); + dbg_info *dbgi = get_entity_dbg_info(entity); + size_t i; + for (i = 0; i < n_params; ++i) { + ir_type *param_type = get_method_param_type(type, i); + + if (infos != NULL && infos[i].entity != NULL) { + long const offset = get_entity_offset(infos[i].entity); + emit_uleb128(abbrev_formal_parameter); + emit_string_printf("arg%u", (unsigned)i); + emit_dbginfo(dbgi); + emit_type_address(param_type); + emit_stack_location(offset); + } else { + emit_uleb128(abbrev_formal_parameter_no_location); + emit_string_printf("arg%u", (unsigned)i); + emit_dbginfo(dbgi); + emit_type_address(param_type); + } + } +} + +void be_dwarf_method_before(const ir_entity *entity, + const parameter_dbg_info_t *parameter_infos) { - dwarf_t *env = (dwarf_t*)handle; + if (debug_level < LEVEL_BASIC) + return; + { + ir_type *type = get_entity_type(entity); + size_t n_ress = get_method_n_ress(type); + size_t n_params = get_method_n_params(type); + size_t i; be_gas_emit_switch_section(GAS_SECTION_DEBUG_INFO); + if (n_ress > 0) { + ir_type *res = get_method_res_type(type, 0); + emit_type(res); + } + for (i = 0; i < n_params; ++i) { + ir_type *param_type = get_method_param_type(type, i); + emit_type(param_type); + } + emit_entity_label(entity); - emit_uleb128(DW_TAG_subprogram); - emit_string(get_entity_ld_name(entity)); - emit_dbginfo(env, get_entity_dbg_info(entity)); + emit_uleb128(n_ress == 0 ? abbrev_void_subprogram : abbrev_subprogram); + be_gas_emit_cstring(get_entity_ld_name(entity)); + emit_dbginfo(get_entity_dbg_info(entity)); + if (n_ress > 0) { + ir_type *res = get_method_res_type(type, 0); + emit_type_address(res); + } emit_int8(is_extern_entity(entity)); emit_ref(entity); be_emit_irprintf("\t.long %smethod_end_%s\n", be_gas_get_private_prefix(), get_entity_ld_name(entity)); + /* frame_base prog */ + emit_int8(1); + emit_int8(DW_OP_call_frame_cfa); - ARR_APP1(const ir_entity*, env->pubnames_list, entity); + emit_function_parameters(entity, parameter_infos); + emit_int8(0); + + ARR_APP1(const ir_entity*, env.pubnames_list, entity); - env->cur_ent = entity; + env.cur_ent = entity; + } } -/** - * dump the drwarf for a method end - */ -static void dwarf_method_end(dbg_handle *handle) +void be_dwarf_method_begin(void) { - dwarf_t *env = (dwarf_t*)handle; - const ir_entity *entity = env->cur_ent; + if (debug_level < LEVEL_FRAMEINFO) + return; + be_emit_cstring("\t.cfi_startproc\n"); + be_emit_write_line(); +} +void be_dwarf_method_end(void) +{ + if (debug_level < LEVEL_BASIC) + return; + const ir_entity *entity = env.cur_ent; be_emit_irprintf("%smethod_end_%s:\n", be_gas_get_private_prefix(), get_entity_ld_name(entity)); -} -static void dwarf_types(dbg_handle *handle) -{ - (void)handle; + if (debug_level >= LEVEL_FRAMEINFO) { + be_emit_cstring("\t.cfi_endproc\n"); + be_emit_write_line(); + } } -static void emit_type(dwarf_t *env, ir_type *type); - static void emit_base_type_abbrev(void) { - begin_abbrev(DW_TAG_base_type, DW_TAG_base_type, DW_CHILDREN_no); + begin_abbrev(abbrev_base_type, DW_TAG_base_type, DW_CHILDREN_no); register_attribute(DW_AT_encoding, DW_FORM_data1); register_attribute(DW_AT_byte_size, DW_FORM_data1); register_attribute(DW_AT_name, DW_FORM_string); @@ -386,14 +547,6 @@ static void emit_type_label(const ir_type *type) be_emit_write_line(); } -static void emit_type_address(const ir_type *type) -{ - be_emit_irprintf("\t.long %sT%ld - %sinfo_begin\n", - be_gas_get_private_prefix(), - get_type_nr(type), be_gas_get_private_prefix()); - be_emit_write_line(); -} - static void emit_base_type(const ir_type *type) { char buf[128]; @@ -401,7 +554,7 @@ static void emit_base_type(const ir_type *type) ir_print_type(buf, sizeof(buf), type); emit_type_label(type); - emit_uleb128(DW_TAG_base_type); + emit_uleb128(abbrev_base_type); if (mode_is_int(mode)) { /* bool hack */ if (strcmp(buf, "_Bool")==0 || strcmp(buf, "bool")==0) { @@ -417,12 +570,12 @@ static void emit_base_type(const ir_type *type) panic("mode not implemented yet"); } emit_int8(get_mode_size_bytes(mode)); - emit_string(buf); + be_gas_emit_cstring(buf); } static void emit_pointer_type_abbrev(void) { - begin_abbrev(DW_TAG_pointer_type, DW_TAG_pointer_type, DW_CHILDREN_no); + begin_abbrev(abbrev_pointer_type, DW_TAG_pointer_type, DW_CHILDREN_no); register_attribute(DW_AT_type, DW_FORM_ref4); register_attribute(DW_AT_byte_size, DW_FORM_data1); end_abbrev(); @@ -433,17 +586,17 @@ static void emit_pointer_type_abbrev(void) end_abbrev(); } -static void emit_pointer_type(dwarf_t *env, const ir_type *type) +static void emit_pointer_type(const ir_type *type) { ir_type *points_to = get_pointer_points_to_type(type); unsigned size = get_type_size_bytes(type); assert(size < 256); if (!is_Primitive_type(points_to) || get_type_mode(points_to) != mode_ANY) { - emit_type(env, points_to); + emit_type(points_to); emit_type_label(type); - emit_uleb128(DW_TAG_pointer_type); + emit_uleb128(abbrev_pointer_type); emit_type_address(points_to); } else { emit_type_label(type); @@ -454,31 +607,31 @@ static void emit_pointer_type(dwarf_t *env, const ir_type *type) static void emit_array_type_abbrev(void) { - begin_abbrev(DW_TAG_array_type, DW_TAG_array_type, DW_CHILDREN_yes); + begin_abbrev(abbrev_array_type, DW_TAG_array_type, DW_CHILDREN_yes); register_attribute(DW_AT_type, DW_FORM_ref4); end_abbrev(); - begin_abbrev(DW_TAG_subrange_type, DW_TAG_subrange_type, DW_CHILDREN_no); + begin_abbrev(abbrev_subrange_type, DW_TAG_subrange_type, DW_CHILDREN_no); register_attribute(DW_AT_upper_bound, DW_FORM_udata); end_abbrev(); } -static void emit_array_type(dwarf_t *env, const ir_type *type) +static void emit_array_type(const ir_type *type) { ir_type *element_type = get_array_element_type(type); if (get_array_n_dimensions(type) != 1) - panic("dwarf: multidimensional arrays no supported yet"); + panic("multidimensional arrays no supported yet"); - emit_type(env, element_type); + emit_type(element_type); emit_type_label(type); - emit_uleb128(DW_TAG_array_type); + emit_uleb128(abbrev_array_type); emit_type_address(element_type); if (has_array_upper_bound(type, 0)) { int bound = get_array_upper_bound_int(type, 0); - emit_uleb128(DW_TAG_subrange_type); + emit_uleb128(abbrev_subrange_type); emit_uleb128(bound); } @@ -487,22 +640,22 @@ static void emit_array_type(dwarf_t *env, const ir_type *type) static void emit_compound_type_abbrev(void) { - begin_abbrev(DW_TAG_structure_type, DW_TAG_structure_type, DW_CHILDREN_yes); + begin_abbrev(abbrev_structure_type, DW_TAG_structure_type, DW_CHILDREN_yes); register_attribute(DW_AT_byte_size, DW_FORM_udata); // TODO register_dbginfo_attributes(); end_abbrev(); - begin_abbrev(DW_TAG_union_type, DW_TAG_union_type, DW_CHILDREN_yes); + begin_abbrev(abbrev_union_type, DW_TAG_union_type, DW_CHILDREN_yes); register_attribute(DW_AT_byte_size, DW_FORM_udata); // TODO register_dbginfo_attributes(); end_abbrev(); - begin_abbrev(DW_TAG_class_type, DW_TAG_class_type, DW_CHILDREN_yes); + begin_abbrev(abbrev_class_type, DW_TAG_class_type, DW_CHILDREN_yes); register_attribute(DW_AT_byte_size, DW_FORM_udata); // TODO register_dbginfo_attributes(); end_abbrev(); - begin_abbrev(DW_TAG_member, DW_TAG_member, DW_CHILDREN_no); + begin_abbrev(abbrev_member, DW_TAG_member, DW_CHILDREN_no); register_attribute(DW_AT_type, DW_FORM_ref4); register_attribute(DW_AT_name, DW_FORM_string); register_dbginfo_attributes(); @@ -526,7 +679,7 @@ static void emit_op_plus_uconst(unsigned value) emit_uleb128(value); } -static void emit_compound_type(dwarf_t *env, const ir_type *type) +static void emit_compound_type(const ir_type *type) { size_t i; size_t n_members = get_compound_n_members(type); @@ -539,17 +692,17 @@ static void emit_compound_type(dwarf_t *env, const ir_type *type) if (base != NULL) member_type = base; } - emit_type(env, member_type); + emit_type(member_type); } emit_type_label(type); if (is_Struct_type(type)) { - emit_uleb128(DW_TAG_structure_type); + emit_uleb128(abbrev_structure_type); } else if (is_Union_type(type)) { - emit_uleb128(DW_TAG_union_type); + emit_uleb128(abbrev_union_type); } else { assert(is_Class_type(type)); - emit_uleb128(DW_TAG_class_type); + emit_uleb128(abbrev_class_type); } emit_uleb128(get_type_size_bytes(type)); for (i = 0; i < n_members; ++i) { @@ -573,12 +726,12 @@ static void emit_compound_type(dwarf_t *env, const ir_type *type) emit_uleb128(bit_offset); member_type = base; } else { - emit_uleb128(DW_TAG_member); + emit_uleb128(abbrev_member); } emit_type_address(member_type); - emit_string(get_entity_name(member)); - emit_dbginfo(env, get_entity_dbg_info(member)); + be_gas_emit_cstring(get_entity_name(member)); + emit_dbginfo(get_entity_dbg_info(member)); assert(offset >= 0); emit_int8(1 + get_uleb128_size(offset)); emit_op_plus_uconst(offset); @@ -589,7 +742,7 @@ static void emit_compound_type(dwarf_t *env, const ir_type *type) static void emit_subroutine_type_abbrev(void) { - begin_abbrev(DW_TAG_subroutine_type, + begin_abbrev(abbrev_subroutine_type, DW_TAG_subroutine_type, DW_CHILDREN_yes); register_attribute(DW_AT_prototyped, DW_FORM_flag); register_attribute(DW_AT_type, DW_FORM_ref4); @@ -606,22 +759,22 @@ static void emit_subroutine_type_abbrev(void) end_abbrev(); } -static void emit_subroutine_type(dwarf_t *env, const ir_type *type) +static void emit_subroutine_type(const ir_type *type) { size_t n_params = get_method_n_params(type); size_t n_ress = get_method_n_ress(type); size_t i; for (i = 0; i < n_params; ++i) { ir_type *param_type = get_method_param_type(type, i); - emit_type(env, param_type); + emit_type(param_type); } for (i = 0; i < n_ress; ++i) { ir_type *res_type = get_method_res_type(type, i); - emit_type(env, res_type); + emit_type(res_type); } emit_type_label(type); - emit_uleb128(n_ress == 0 ? abbrev_void_subroutine_type : DW_TAG_subroutine_type); + emit_uleb128(n_ress == 0 ? abbrev_void_subroutine_type : abbrev_subroutine_type); emit_int8(1); /* prototyped */ if (n_ress > 0) { /* dwarf only supports 1 return type */ @@ -637,21 +790,21 @@ static void emit_subroutine_type(dwarf_t *env, const ir_type *type) emit_int8(0); } -static void emit_type(dwarf_t *env, ir_type *type) +static void emit_type(ir_type *type) { - if (pset_new_insert(&env->emitted_types, type)) + if (!pset_new_insert(&env.emitted_types, type)) return; switch (get_type_tpop_code(type)) { - case tpo_primitive: emit_base_type(type); break; - case tpo_pointer: emit_pointer_type(env, type); break; - case tpo_array: emit_array_type(env, type); break; + case tpo_primitive: emit_base_type(type); break; + case tpo_pointer: emit_pointer_type(type); break; + case tpo_array: emit_array_type(type); break; case tpo_class: case tpo_struct: - case tpo_union: emit_compound_type(env, type); break; - case tpo_method: emit_subroutine_type(env, type); break; + case tpo_union: emit_compound_type(type); break; + case tpo_method: emit_subroutine_type(type); break; default: - panic("bedwarf: type %+F not implemented yet", type); + panic("type %+F not implemented yet", type); } } @@ -666,7 +819,7 @@ static void emit_op_addr(const ir_entity *entity) static void emit_variable_abbrev(void) { - begin_abbrev(DW_TAG_variable, DW_TAG_variable, DW_CHILDREN_no); + begin_abbrev(abbrev_variable, DW_TAG_variable, DW_CHILDREN_no); register_attribute(DW_AT_name, DW_FORM_string); register_attribute(DW_AT_type, DW_FORM_ref4); register_attribute(DW_AT_external, DW_FORM_flag); @@ -675,34 +828,37 @@ static void emit_variable_abbrev(void) end_abbrev(); } -static void dwarf_variable(dbg_handle *handle, const ir_entity *entity) +void be_dwarf_variable(const ir_entity *entity) { - dwarf_t *env = (dwarf_t*) handle; - ir_type *type = get_entity_type(entity); + ir_type *type = get_entity_type(entity); + if (debug_level < LEVEL_BASIC) + return; if (get_entity_ld_name(entity)[0] == '\0') return; + if (!entity_has_definition(entity)) + return; be_gas_emit_switch_section(GAS_SECTION_DEBUG_INFO); - emit_type(env, type); + emit_type(type); emit_entity_label(entity); - emit_uleb128(DW_TAG_variable); - emit_string(get_entity_ld_name(entity)); + emit_uleb128(abbrev_variable); + be_gas_emit_cstring(get_entity_ld_name(entity)); emit_type_address(type); emit_int8(is_extern_entity(entity)); - emit_dbginfo(env, get_entity_dbg_info(entity)); + emit_dbginfo(get_entity_dbg_info(entity)); /* DW_AT_location */ emit_int8(5); /* block length */ emit_op_addr(entity); - ARR_APP1(const ir_entity*, env->pubnames_list, entity); + ARR_APP1(const ir_entity*, env.pubnames_list, entity); } static void emit_compile_unit_abbrev(void) { - begin_abbrev(DW_TAG_compile_unit, DW_TAG_compile_unit, DW_CHILDREN_yes); + begin_abbrev(abbrev_compile_unit, DW_TAG_compile_unit, DW_CHILDREN_yes); register_attribute(DW_AT_stmt_list, DW_FORM_data4); register_attribute(DW_AT_producer, DW_FORM_string); register_attribute(DW_AT_name, DW_FORM_string); @@ -731,43 +887,48 @@ static void emit_abbrev(void) emit_uleb128(0); } -/** - * start a new source object (compilation unit) - */ -static void dwarf_unit_begin(dbg_handle *handle, const char *filename) +void be_dwarf_unit_begin(const char *filename) { - (void) handle; - + if (debug_level < LEVEL_BASIC) + return; emit_abbrev(); be_gas_emit_switch_section(GAS_SECTION_DEBUG_INFO); emit_label("info_section_begin"); emit_label("info_begin"); + const backend_params *be_params = be_get_backend_param(); + /* length of compilation unit info */ emit_size("compile_unit_begin", "compile_unit_end"); emit_label("compile_unit_begin"); - emit_int16(2); /* dwarf version */ + emit_int16(3); /* dwarf version */ emit_address("abbrev_begin"); - emit_int8(4); /* pointer size */ + emit_int8(be_params->machine_size / 8); /* pointer size */ /* compile_unit die */ - emit_uleb128(DW_TAG_compile_unit); + emit_uleb128(abbrev_compile_unit); emit_address("line_section_begin"); emit_string_printf("libFirm (%u.%u %s)", ir_get_version_major(), - ir_get_version_minor(), - ir_get_version_revision()); - emit_string(filename); + ir_get_version_minor(), ir_get_version_revision()); + be_gas_emit_cstring(filename); if (language != 0) - emit_int16(DW_LANG_C_plus_plus); + emit_int16(language); if (comp_dir != NULL) - emit_string(comp_dir); + be_gas_emit_cstring(comp_dir); + + /* tell gas to emit cfi in debug_frame + * TODO: if we produce exception handling code then this should be + * .eh_frame (I also wonder if bad things happen if simply always + * use eh_frame) */ + be_emit_cstring("\t.cfi_sections .debug_frame\n"); + be_emit_write_line(); } -static void dwarf_unit_end(dbg_handle *handle) +void be_dwarf_unit_end(void) { - dwarf_t *env = (dwarf_t*)handle; - + if (debug_level < LEVEL_BASIC) + return; be_gas_emit_switch_section(GAS_SECTION_TEXT); emit_label("section_end"); @@ -776,53 +937,29 @@ static void dwarf_unit_end(dbg_handle *handle) emit_label("compile_unit_end"); - emit_line_info(env); - emit_pubnames(env); + emit_line_info(); + emit_pubnames(); } -/** - * Close the drwarf handler. - */ -static void dwarf_close(dbg_handle *handle) -{ - dwarf_t *h = (dwarf_t *)handle; - pmap_destroy(h->file_map); - DEL_ARR_F(h->file_list); - DEL_ARR_F(h->pubnames_list); - pset_new_destroy(&h->emitted_types); - free(h); -} - -/** The drwarf operations. */ -static const debug_ops dwarf_ops = { - dwarf_close, - dwarf_unit_begin, - dwarf_unit_end, - dwarf_method_begin, - dwarf_method_end, - dwarf_types, - dwarf_variable, - dwarf_set_dbg_info -}; - -/* Opens a drwarf handler */ -static dbg_handle *be_dwarf_open(void) +void be_dwarf_close(void) { - dwarf_t *h = XMALLOCZ(dwarf_t); - - h->base.ops = &dwarf_ops; - h->file_map = pmap_create(); - h->file_list = NEW_ARR_F(const char*, 0); - h->pubnames_list = NEW_ARR_F(const ir_entity*, 0); - pset_new_init(&h->emitted_types); - - return &h->base; + if (debug_level < LEVEL_BASIC) + return; + pmap_destroy(env.file_map); + DEL_ARR_F(env.file_list); + DEL_ARR_F(env.pubnames_list); + pset_new_destroy(&env.emitted_types); } -BE_REGISTER_MODULE_CONSTRUCTOR(be_init_dwarf) -void be_init_dwarf(void) +/* Opens a dwarf handler */ +void be_dwarf_open(void) { - be_register_dbgout_module("dwarf", be_dwarf_open); + if (debug_level < LEVEL_BASIC) + return; + env.file_map = pmap_create(); + env.file_list = NEW_ARR_F(const char*, 0); + env.pubnames_list = NEW_ARR_F(const ir_entity*, 0); + pset_new_init(&env.emitted_types); } void be_dwarf_set_source_language(dwarf_source_language new_language) @@ -832,5 +969,28 @@ void be_dwarf_set_source_language(dwarf_source_language new_language) void be_dwarf_set_compilation_directory(const char *new_comp_dir) { - comp_dir = new_comp_dir; + xfree(comp_dir); + comp_dir = xstrdup(new_comp_dir); +} + +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_dwarf) +void be_init_dwarf(void) +{ + static const lc_opt_enum_int_items_t level_items[] = { + { "none", LEVEL_NONE }, + { "basic", LEVEL_BASIC }, + { "locations", LEVEL_LOCATIONS }, + { "frameinfo", LEVEL_FRAMEINFO }, + { NULL, 0 } + }; + static lc_opt_enum_int_var_t debug_level_opt = { + &debug_level, level_items + }; + static lc_opt_table_entry_t be_main_options[] = { + LC_OPT_ENT_ENUM_INT("debug", "debug output (dwarf) level", + &debug_level_opt), + LC_OPT_LAST + }; + lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be"); + lc_opt_add_table(be_grp, be_main_options); }