X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbedwarf.c;h=c9f4e46d684fa44bf2f92aee6bfdf5680b8b62bc;hb=cc9d3be2116747d0d9d1445d3116c69ce041ae57;hp=aaa57b126e3b836337d12823a746a47c65ba9184;hpb=440587fd69a480aa3f08a02b0cdf39cb9d5ac634;p=libfirm diff --git a/ir/be/bedwarf.c b/ir/be/bedwarf.c index aaa57b126..c9f4e46d6 100644 --- a/ir/be/bedwarf.c +++ b/ir/be/bedwarf.c @@ -40,13 +40,23 @@ #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" +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 @@ -55,7 +65,9 @@ typedef enum custom_abbrevs { abbrev_void_pointer_type = 100, abbrev_unnamed_formal_parameter, + abbrev_formal_parameter_no_location, abbrev_void_subroutine_type, + abbrev_void_subprogram, abbrev_bitfield_member, } custom_abbrevs; @@ -63,9 +75,7 @@ typedef enum 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; @@ -77,19 +87,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 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(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; @@ -129,8 +142,25 @@ static unsigned get_uleb128_size(unsigned value) return size; } +static void emit_sleb128(long value) +{ + 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_string(const char *string) { + /* TODO: quote special chars */ be_emit_irprintf("\t.asciz \"%s\"\n", string); be_emit_write_line(); } @@ -203,7 +233,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); @@ -239,8 +269,8 @@ static void emit_line_info(dwarf_t *env) emit_int8(0); /* file list */ - for (i = 0; i < ARR_LEN(env->file_list); ++i) { - emit_string(env->file_list[i]); + for (i = 0; i < ARR_LEN(env.file_list); ++i) { + emit_string(env.file_list[i]); emit_uleb128(1); /* directory */ emit_uleb128(0); /* modification time */ emit_uleb128(0); /* file length */ @@ -255,7 +285,7 @@ static void emit_line_info(dwarf_t *env) } } -static void emit_pubnames(dwarf_t *env) +static void emit_pubnames(void) { size_t i; @@ -268,8 +298,8 @@ 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()); @@ -280,20 +310,49 @@ static void emit_pubnames(dwarf_t *env) emit_label("pubnames_end"); } -static void dwarf_location(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); @@ -315,74 +374,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(DW_TAG_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(DW_TAG_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 dwarf 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) { - dwarf_t *env = (dwarf_t*)handle; + 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) { + const ir_entity *entity = infos[i].entity; + long offset = get_entity_offset(entity); + emit_uleb128(DW_TAG_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) +{ + 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; + + (void)parameter_infos; 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_uleb128(n_ress == 0 ? abbrev_void_subprogram : DW_TAG_subprogram); emit_string(get_entity_ld_name(entity)); - emit_dbginfo(env, get_entity_dbg_info(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 dwarf 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); @@ -398,14 +555,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]; @@ -445,14 +594,14 @@ 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); @@ -475,14 +624,14 @@ static void emit_array_type_abbrev(void) 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"); - emit_type(env, element_type); + emit_type(element_type); emit_type_label(type); emit_uleb128(DW_TAG_array_type); @@ -538,7 +687,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); @@ -551,7 +700,7 @@ 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); @@ -590,7 +739,7 @@ static void emit_compound_type(dwarf_t *env, const ir_type *type) emit_type_address(member_type); emit_string(get_entity_name(member)); - emit_dbginfo(env, get_entity_dbg_info(member)); + emit_dbginfo(get_entity_dbg_info(member)); assert(offset >= 0); emit_int8(1 + get_uleb128_size(offset)); emit_op_plus_uconst(offset); @@ -618,18 +767,18 @@ 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); @@ -649,19 +798,19 @@ 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); } @@ -687,29 +836,33 @@ 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; + /* skip external variables */ + if (get_entity_visibility(entity) == ir_visibility_external) + 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_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) @@ -743,13 +896,10 @@ 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); @@ -759,9 +909,9 @@ static void dwarf_unit_begin(dbg_handle *handle, const char *filename) /* 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(4); /* pointer size, TODO: query backend */ /* compile_unit die */ emit_uleb128(DW_TAG_compile_unit); @@ -774,12 +924,19 @@ static void dwarf_unit_begin(dbg_handle *handle, const char *filename) emit_int16(language); if (comp_dir != NULL) emit_string(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"); @@ -788,53 +945,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 dwarf 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 dwarf 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_location, -}; - -/* Opens a dwarf 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) @@ -846,3 +979,25 @@ void be_dwarf_set_compilation_directory(const char *new_comp_dir) { comp_dir = 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); +}