From cc9d3be2116747d0d9d1445d3116c69ce041ae57 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 25 Apr 2012 23:01:59 +0200 Subject: [PATCH] dwarf: initial support for callframe and params - We now always output dwarf3 so we can use DW_OP_call_frame_cfa and avoid construction location lists, but just reuse the callframe info lists. - Backends have to emit debug info as callframe calculation changes: The ia32 backend has a preliminary implementation which assumes esp offset of frame_type_size at the beginning of a block (currently always true), the no-omit-fp mode assumes ebp relative addressing (which is correct except for the prolog/epilogue insns) --- ir/be/TEMPLATE/TEMPLATE_emitter.c | 2 +- ir/be/amd64/amd64_emitter.c | 2 +- ir/be/arm/arm_emitter.c | 2 +- ir/be/arm/arm_transform.c | 1 - ir/be/beabi.c | 18 +- ir/be/bedwarf.c | 202 +++++++++++++++++--- ir/be/bedwarf.h | 28 ++- ir/be/bedwarf_t.h | 297 +++++++++++++++--------------- ir/be/begnuas.c | 14 +- ir/be/begnuas.h | 7 +- ir/be/beirg.h | 1 - ir/be/ia32/ia32_emitter.c | 77 +++++++- ir/be/sparc/sparc_emitter.c | 2 +- 13 files changed, 457 insertions(+), 196 deletions(-) diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.c b/ir/be/TEMPLATE/TEMPLATE_emitter.c index 752d348b8..f4a2ac234 100644 --- a/ir/be/TEMPLATE/TEMPLATE_emitter.c +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.c @@ -257,7 +257,7 @@ void TEMPLATE_emit_routine(ir_graph *irg) block_schedule = be_create_block_schedule(irg); /* emit assembler prolog */ - be_gas_emit_function_prolog(entity, 4); + be_gas_emit_function_prolog(entity, 4, NULL); /* populate jump link fields with their destinations */ irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL); diff --git a/ir/be/amd64/amd64_emitter.c b/ir/be/amd64/amd64_emitter.c index 1e4b3701b..264642ae4 100644 --- a/ir/be/amd64/amd64_emitter.c +++ b/ir/be/amd64/amd64_emitter.c @@ -579,7 +579,7 @@ void amd64_gen_routine(ir_graph *irg) blk_sched = be_create_block_schedule(irg); - be_gas_emit_function_prolog(entity, 4); + be_gas_emit_function_prolog(entity, 4, NULL); irg_block_walk_graph(irg, amd64_gen_labels, NULL, NULL); diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index 3fab154b5..4695a5751 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -955,7 +955,7 @@ void arm_gen_routine(ir_graph *irg) /* create the block schedule */ blk_sched = be_create_block_schedule(irg); - be_gas_emit_function_prolog(entity, 4); + be_gas_emit_function_prolog(entity, 4, NULL); irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL); diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index 95deec9e6..48e3dc18a 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -1695,7 +1695,6 @@ static void create_stacklayout(ir_graph *irg) layout->frame_type = get_irg_frame_type(irg); layout->between_type = arm_get_between_type(); layout->arg_type = arg_type; - layout->param_map = NULL; /* TODO */ layout->initial_offset = 0; layout->initial_bias = 0; layout->sp_relative = true; diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 7b47d0357..2f6ab5c46 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -313,13 +313,11 @@ static void be_abi_call_free(be_abi_call_t *call) * @param args the stack argument layout type * @param between the between layout type * @param locals the method frame type - * @param param_map an array mapping method argument positions to the stack argument type * * @return the initialized stack layout */ static be_stack_layout_t *stack_frame_init(be_stack_layout_t *frame, ir_type *args, - ir_type *between, ir_type *locals, - ir_entity *param_map[]) + ir_type *between, ir_type *locals) { frame->arg_type = args; frame->between_type = between; @@ -327,7 +325,6 @@ static be_stack_layout_t *stack_frame_init(be_stack_layout_t *frame, ir_type *ar frame->initial_offset = 0; frame->initial_bias = 0; frame->order[1] = between; - frame->param_map = param_map; /* typical decreasing stack: locals have the * lowest addresses, arguments the highest */ @@ -1107,13 +1104,11 @@ static void process_calls(ir_graph *irg) * * @param call the current call ABI * @param method_type the method type - * @param param_map an array mapping method arguments to the stack layout - * type * * @return the stack argument layout type */ static ir_type *compute_arg_type(ir_graph *irg, be_abi_call_t *call, - ir_type *method_type, ir_entity ***param_map) + ir_type *method_type) { struct obstack *obst = be_get_be_obst(irg); ir_type *frame_type = get_irg_frame_type(irg); @@ -1125,9 +1120,7 @@ static ir_type *compute_arg_type(ir_graph *irg, be_abi_call_t *call, ir_type *res; size_t i; - ir_entity **map; - - *param_map = map = OALLOCNZ(obst, ir_entity*, n_params); + ir_entity **map = OALLOCNZ(obst, ir_entity*, n_params); res = new_type_struct(new_id_from_chars("arg_type", 8)); /* collect existing entities for value_param_types */ @@ -1430,7 +1423,6 @@ static void modify_irg(ir_graph *irg) const ir_edge_t *edge; ir_type *arg_type, *bet_type; lower_frame_sels_env_t ctx; - ir_entity **param_map; DBG((dbg, LEVEL_1, "introducing abi on %+F\n", irg)); @@ -1438,7 +1430,7 @@ static void modify_irg(ir_graph *irg) irp_reserve_resources(irp, IRP_RESOURCE_ENTITY_LINK); - arg_type = compute_arg_type(irg, call, method_type, ¶m_map); + arg_type = compute_arg_type(irg, call, method_type); /* Convert the Sel nodes in the irg to frame addr nodes: */ ctx.frame = get_irg_frame(irg); @@ -1482,7 +1474,7 @@ static void modify_irg(ir_graph *irg) stack_layout->sp_relative = call->flags.bits.try_omit_fp; bet_type = call->cb->get_between_type(irg); stack_frame_init(stack_layout, arg_type, bet_type, - get_irg_frame_type(irg), param_map); + get_irg_frame_type(irg)); /* Count the register params and add them to the number of Projs for the RegParams node */ for (i = 0; i < n_params; ++i) { diff --git a/ir/be/bedwarf.c b/ir/be/bedwarf.c index 12a86d83c..c9f4e46d6 100644 --- a/ir/be/bedwarf.c +++ b/ir/be/bedwarf.c @@ -65,7 +65,9 @@ static int debug_level = LEVEL_NONE; 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; @@ -74,7 +76,6 @@ typedef enum custom_abbrevs { */ typedef struct dwarf_t { 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; @@ -101,6 +102,7 @@ static unsigned insert_file(const char *filename) 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; @@ -140,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(); } @@ -307,6 +326,33 @@ void be_dwarf_location(dbg_info *dbgi) 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); @@ -337,38 +383,147 @@ static void emit_dbginfo(const dbg_info *dbgi) 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(); +} + +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); } -void be_dwarf_method_begin(const ir_entity *entity) +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) { + 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(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); + + emit_function_parameters(entity, parameter_infos); + emit_int8(0); ARR_APP1(const ir_entity*, env.pubnames_list, entity); env.cur_ent = entity; + } +} + +void be_dwarf_method_begin(void) +{ + if (debug_level < LEVEL_FRAMEINFO) + return; + be_emit_cstring("\t.cfi_startproc\n"); + be_emit_write_line(); } void be_dwarf_method_end(void) @@ -378,9 +533,12 @@ void be_dwarf_method_end(void) 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 emit_type(ir_type *type); + if (debug_level >= LEVEL_FRAMEINFO) { + be_emit_cstring("\t.cfi_endproc\n"); + be_emit_write_line(); + } +} static void emit_base_type_abbrev(void) { @@ -397,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]; @@ -694,6 +844,9 @@ void be_dwarf_variable(const ir_entity *entity) 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); @@ -756,9 +909,9 @@ void be_dwarf_unit_begin(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); @@ -771,6 +924,13 @@ void be_dwarf_unit_begin(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(); } void be_dwarf_unit_end(void) diff --git a/ir/be/bedwarf.h b/ir/be/bedwarf.h index a795f60e6..49f4cc468 100644 --- a/ir/be/bedwarf.h +++ b/ir/be/bedwarf.h @@ -27,6 +27,11 @@ #include "beabi.h" +typedef struct parameter_dbg_info_t { + const ir_entity *entity; + const arch_register_t *reg; +} parameter_dbg_info_t; + /** initialize and open debug handle */ void be_dwarf_open(void); @@ -39,8 +44,12 @@ void be_dwarf_unit_begin(const char *filename); /** end compilation unit */ void be_dwarf_unit_end(void); -/** debug for a method begin */ -void be_dwarf_method_begin(const ir_entity *ent); +/** output debug info necessary right before defining a method */ +void be_dwarf_method_before(const ir_entity *ent, + const parameter_dbg_info_t *infos); + +/** output debug info right before beginning to output assembly instructions */ +void be_dwarf_method_begin(void); /** debug for a method end */ void be_dwarf_method_end(void); @@ -52,4 +61,19 @@ void be_dwarf_variable(const ir_entity *ent); * assembly instructions */ void be_dwarf_location(dbg_info *dbgi); +/** set base register that points to callframe */ +void be_dwarf_callframe_register(const arch_register_t *reg); + +/** set offset from base register that points to the callframe. + * Note: callframe is defined as in the dwarf documentation here which is the + * stackpointer before the call has happened. (Which would be the beginning of + * the between type in our backend) */ +void be_dwarf_callframe_offset(int offset); + +/** + * Indicate at which offset (relative to the CFA) a caller saved register has + * been saved. + */ +void be_dwarf_callframe_spilloffset(const arch_register_t *reg, int offset); + #endif diff --git a/ir/be/bedwarf_t.h b/ir/be/bedwarf_t.h index d1996167d..ccd7e5ce1 100644 --- a/ir/be/bedwarf_t.h +++ b/ir/be/bedwarf_t.h @@ -217,151 +217,158 @@ typedef enum dwarf_line_number_x_ops { } dwarf_line_number_x_ops; typedef enum dwarf_location_op { - DW_OP_addr = 0x03, - DW_OP_deref = 0x06, - DW_OP_const1u = 0x08, - DW_OP_const1s = 0x09, - DW_OP_const2u = 0x0A, - DW_OP_const2s = 0x0B, - DW_OP_const4u = 0x0C, - DW_OP_const4s = 0x0D, - DW_OP_const8u = 0x0E, - DW_OP_const8s = 0x0F, - DW_OP_constu = 0x10, - DW_OP_consts = 0x11, - DW_OP_dup = 0x12, - DW_OP_drop = 0x13, - DW_OP_over = 0x14, - DW_OP_pick = 0x15, - DW_OP_swap = 0x16, - DW_OP_rot = 0x17, - DW_OP_xderef = 0x18, - DW_OP_abs = 0x19, - DW_OP_and = 0x1A, - DW_OP_div = 0x1B, - DW_OP_minus = 0x1C, - DW_OP_mod = 0x1D, - DW_OP_mul = 0x1E, - DW_OP_neg = 0x1F, - DW_OP_not = 0x20, - DW_OP_or = 0x21, - DW_OP_plus = 0x22, - DW_OP_plus_uconst = 0x23, - DW_OP_shl = 0x24, - DW_OP_shr = 0x25, - DW_OP_shra = 0x26, - DW_OP_xor = 0x27, - DW_OP_bra = 0x28, - DW_OP_eq = 0x29, - DW_OP_ge = 0x2A, - DW_OP_gt = 0x2B, - DW_OP_le = 0x2C, - DW_OP_lt = 0x2D, - DW_OP_ne = 0x2E, - DW_OP_skip = 0x2F, - DW_OP_lit0 = 0x30, - DW_OP_lit1 = 0x31, - DW_OP_lit2 = 0x32, - DW_OP_lit3 = 0x33, - DW_OP_lit4 = 0x34, - DW_OP_lit5 = 0x35, - DW_OP_lit6 = 0x36, - DW_OP_lit7 = 0x37, - DW_OP_lit8 = 0x38, - DW_OP_lit9 = 0x39, - DW_OP_lit10 = 0x3A, - DW_OP_lit11 = 0x3B, - DW_OP_lit12 = 0x3C, - DW_OP_lit13 = 0x3D, - DW_OP_lit14 = 0x3E, - DW_OP_lit15 = 0x3F, - DW_OP_lit16 = 0x40, - DW_OP_lit17 = 0x41, - DW_OP_lit18 = 0x42, - DW_OP_lit19 = 0x43, - DW_OP_lit20 = 0x44, - DW_OP_lit21 = 0x45, - DW_OP_lit22 = 0x46, - DW_OP_lit23 = 0x47, - DW_OP_lit24 = 0x48, - DW_OP_lit25 = 0x49, - DW_OP_lit26 = 0x4A, - DW_OP_lit27 = 0x4B, - DW_OP_lit28 = 0x4C, - DW_OP_lit29 = 0x4D, - DW_OP_lit30 = 0x4E, - DW_OP_lit31 = 0x4F, - DW_OP_reg0 = 0x50, - DW_OP_reg1 = 0x51, - DW_OP_reg2 = 0x52, - DW_OP_reg3 = 0x53, - DW_OP_reg4 = 0x54, - DW_OP_reg5 = 0x55, - DW_OP_reg6 = 0x56, - DW_OP_reg7 = 0x57, - DW_OP_reg8 = 0x58, - DW_OP_reg9 = 0x59, - DW_OP_reg10 = 0x5A, - DW_OP_reg11 = 0x5B, - DW_OP_reg12 = 0x5C, - DW_OP_reg13 = 0x5D, - DW_OP_reg14 = 0x5E, - DW_OP_reg15 = 0x5F, - DW_OP_reg16 = 0x60, - DW_OP_reg17 = 0x61, - DW_OP_reg18 = 0x62, - DW_OP_reg19 = 0x63, - DW_OP_reg20 = 0x64, - DW_OP_reg21 = 0x65, - DW_OP_reg22 = 0x66, - DW_OP_reg23 = 0x67, - DW_OP_reg24 = 0x68, - DW_OP_reg25 = 0x69, - DW_OP_reg26 = 0x6A, - DW_OP_reg27 = 0x6B, - DW_OP_reg28 = 0x6C, - DW_OP_reg29 = 0x6D, - DW_OP_reg30 = 0x6E, - DW_OP_reg31 = 0x6F, - DW_OP_breg0 = 0x70, - DW_OP_breg1 = 0x71, - DW_OP_breg2 = 0x72, - DW_OP_breg3 = 0x73, - DW_OP_breg4 = 0x74, - DW_OP_breg5 = 0x75, - DW_OP_breg6 = 0x76, - DW_OP_breg7 = 0x77, - DW_OP_breg8 = 0x78, - DW_OP_breg9 = 0x79, - DW_OP_breg10 = 0x7A, - DW_OP_breg11 = 0x7B, - DW_OP_breg12 = 0x7C, - DW_OP_breg13 = 0x7D, - DW_OP_breg14 = 0x7E, - DW_OP_breg15 = 0x7F, - DW_OP_breg16 = 0x80, - DW_OP_breg17 = 0x81, - DW_OP_breg18 = 0x82, - DW_OP_breg19 = 0x83, - DW_OP_breg20 = 0x84, - DW_OP_breg21 = 0x85, - DW_OP_breg22 = 0x86, - DW_OP_breg23 = 0x87, - DW_OP_breg24 = 0x88, - DW_OP_breg25 = 0x89, - DW_OP_breg26 = 0x8A, - DW_OP_breg27 = 0x8B, - DW_OP_breg28 = 0x8C, - DW_OP_breg29 = 0x8D, - DW_OP_breg30 = 0x8E, - DW_OP_breg31 = 0x8F, - DW_OP_regx = 0x90, - DW_OP_fbreg = 0x91, - DW_OP_bregx = 0x92, - DW_OP_piece = 0x93, - DW_OP_deref_size = 0x94, - DW_OP_xderef_size = 0x95, - DW_OP_nop = 0x96, + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0A, + DW_OP_const2s = 0x0B, + DW_OP_const4u = 0x0C, + DW_OP_const4s = 0x0D, + DW_OP_const8u = 0x0E, + DW_OP_const8s = 0x0F, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1A, + DW_OP_div = 0x1B, + DW_OP_minus = 0x1C, + DW_OP_mod = 0x1D, + DW_OP_mul = 0x1E, + DW_OP_neg = 0x1F, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2A, + DW_OP_gt = 0x2B, + DW_OP_le = 0x2C, + DW_OP_lt = 0x2D, + DW_OP_ne = 0x2E, + DW_OP_skip = 0x2F, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3A, + DW_OP_lit11 = 0x3B, + DW_OP_lit12 = 0x3C, + DW_OP_lit13 = 0x3D, + DW_OP_lit14 = 0x3E, + DW_OP_lit15 = 0x3F, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4A, + DW_OP_lit27 = 0x4B, + DW_OP_lit28 = 0x4C, + DW_OP_lit29 = 0x4D, + DW_OP_lit30 = 0x4E, + DW_OP_lit31 = 0x4F, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5A, + DW_OP_reg11 = 0x5B, + DW_OP_reg12 = 0x5C, + DW_OP_reg13 = 0x5D, + DW_OP_reg14 = 0x5E, + DW_OP_reg15 = 0x5F, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6A, + DW_OP_reg27 = 0x6B, + DW_OP_reg28 = 0x6C, + DW_OP_reg29 = 0x6D, + DW_OP_reg30 = 0x6E, + DW_OP_reg31 = 0x6F, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7A, + DW_OP_breg11 = 0x7B, + DW_OP_breg12 = 0x7C, + DW_OP_breg13 = 0x7D, + DW_OP_breg14 = 0x7E, + DW_OP_breg15 = 0x7F, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8A, + DW_OP_breg27 = 0x8B, + DW_OP_breg28 = 0x8C, + DW_OP_breg29 = 0x8D, + DW_OP_breg30 = 0x8E, + DW_OP_breg31 = 0x8F, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b, + DW_OP_call_frame_cfa = 0x9c, + DW_OP_bit_piece = 0x9d, } dwarf_location_op; #endif diff --git a/ir/be/begnuas.c b/ir/be/begnuas.c index b55f5856e..1839def49 100644 --- a/ir/be/begnuas.c +++ b/ir/be/begnuas.c @@ -89,6 +89,7 @@ static void emit_section_macho(be_gas_section_t section) case GAS_SECTION_DEBUG_ABBREV: name = "section __DWARF,__debug_abbrev,regular,debug"; break; case GAS_SECTION_DEBUG_LINE: name = "section __DWARF,__debug_line,regular,debug"; break; case GAS_SECTION_DEBUG_PUBNAMES: name = "section __DWARF,__debug_pubnames,regular,debug"; break; + case GAS_SECTION_DEBUG_FRAME: name = "section __DWARF,__debug_frame,regular,debug"; break; default: panic("unsupported scetion type 0x%X", section); } be_emit_irprintf("\t.%s\n", name); @@ -127,6 +128,7 @@ static void emit_section_sparc(be_gas_section_t section, const ir_entity *entity "debug_abbrev", "debug_line", "debug_pubnames" + "debug_frame", }; if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT)) @@ -193,6 +195,7 @@ static void emit_section(be_gas_section_t section, const ir_entity *entity) { "debug_abbrev", "progbits", "" }, { "debug_line", "progbits", "" }, { "debug_pubnames", "progbits", "" }, + { "debug_frame", "progbits", "" }, }; if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) { @@ -528,18 +531,17 @@ static void emit_visibility(const ir_entity *entity) } } -void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment) +void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment, const parameter_dbg_info_t *parameter_infos) { be_gas_section_t section; - be_dwarf_method_begin(entity); + be_dwarf_method_before(entity, parameter_infos); section = determine_section(NULL, entity); emit_section(section, entity); /* write the begin line (makes the life easier for scripts parsing the * assembler) */ - be_emit_write_line(); be_emit_cstring("# -- Begin "); be_gas_emit_entity(entity); be_emit_char('\n'); @@ -585,10 +587,14 @@ void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment) be_gas_emit_entity(entity); be_emit_cstring(":\n"); be_emit_write_line(); + + be_dwarf_method_begin(); } void be_gas_emit_function_epilog(const ir_entity *entity) { + be_dwarf_method_end(); + if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) { be_emit_cstring("\t.size\t"); be_gas_emit_entity(entity); @@ -603,8 +609,6 @@ void be_gas_emit_function_epilog(const ir_entity *entity) be_emit_char('\n'); be_emit_write_line(); - be_dwarf_method_end(); - be_emit_char('\n'); be_emit_write_line(); } diff --git a/ir/be/begnuas.h b/ir/be/begnuas.h index 12e2aa769..43aa2e425 100644 --- a/ir/be/begnuas.h +++ b/ir/be/begnuas.h @@ -29,6 +29,7 @@ #include #include "be_types.h" #include "beemitter.h" +#include "bedwarf.h" typedef enum { GAS_SECTION_TEXT, /**< text section - program code */ @@ -44,7 +45,8 @@ typedef enum { GAS_SECTION_DEBUG_ABBREV, /**< dwarf debug abbrev */ GAS_SECTION_DEBUG_LINE, /**< dwarf debug line */ GAS_SECTION_DEBUG_PUBNAMES, /**< dwarf pub names */ - GAS_SECTION_LAST = GAS_SECTION_DEBUG_PUBNAMES, + GAS_SECTION_DEBUG_FRAME, /**< dwarf callframe infos */ + GAS_SECTION_LAST = GAS_SECTION_DEBUG_FRAME, GAS_SECTION_TYPE_MASK = 0xFF, GAS_SECTION_FLAG_TLS = 1 << 8, /**< thread local flag */ @@ -86,7 +88,8 @@ void be_gas_emit_switch_section(be_gas_section_t section); * emit assembler instructions necessary before starting function code */ void be_gas_emit_function_prolog(const ir_entity *entity, - unsigned po2alignment); + unsigned po2alignment, + const parameter_dbg_info_t *paramter_infos); void be_gas_emit_function_epilog(const ir_entity *entity); diff --git a/ir/be/beirg.h b/ir/be/beirg.h index 8b4e19e6f..b2b184d13 100644 --- a/ir/be/beirg.h +++ b/ir/be/beirg.h @@ -72,7 +72,6 @@ struct be_stack_layout_t { ir_type *order[N_FRAME_TYPES]; /**< arg, between and frame types ordered. */ - ir_entity **param_map; /**< An array mapping type parameters to arg_type entries */ int initial_offset; /**< the initial difference between stack pointer and frame pointer */ int initial_bias; /**< the initial stack bias */ bool sp_relative : 1; /**< entities are addressed relative to diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 05fa271f7..d5c4e87e1 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -89,6 +89,10 @@ static ir_label_t exc_label_id; static int mark_spill_reload = 0; static int do_pic; +static bool sp_relative; +static int frame_type_size; +static int callframe_offset; + /** Return the next block in Block schedule */ static ir_node *get_prev_block_sched(const ir_node *block) { @@ -1661,6 +1665,15 @@ static void ia32_emit_node(ir_node *node) ir_fprintf(stderr, "Error: No emit handler for node %+F (%+G, graph %+F)\n", node, node, current_ir_graph); abort(); } + + if (sp_relative) { + int sp_change = arch_get_sp_bias(node); + if (sp_change != 0) { + assert(sp_change != SP_BIAS_RESET); + callframe_offset += sp_change; + be_dwarf_callframe_offset(callframe_offset); + } + } } /** @@ -1812,6 +1825,16 @@ static void ia32_gen_block(ir_node *block) ia32_emit_block_header(block); + if (sp_relative) { + ir_graph *irg = get_irn_irg(block); + callframe_offset = 4; /* 4 bytes for the return address */ + /* ESP guessing, TODO perform a real ESP simulation */ + if (block != get_irg_start_block(irg)) { + callframe_offset += frame_type_size; + } + be_dwarf_callframe_offset(callframe_offset); + } + /* emit the contents of the block */ be_dwarf_location(get_irn_dbg_info(block)); sched_foreach(block, node) { @@ -1864,6 +1887,33 @@ static int cmp_exc_entry(const void *a, const void *b) return +1; } +static parameter_dbg_info_t *construct_parameter_infos(ir_graph *irg) +{ + ir_entity *entity = get_irg_entity(irg); + ir_type *type = get_entity_type(entity); + size_t n_params = get_method_n_params(type); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + ir_type *arg_type = layout->arg_type; + size_t n_members = get_compound_n_members(arg_type); + parameter_dbg_info_t *infos = XMALLOCNZ(parameter_dbg_info_t, n_params); + size_t i; + + for (i = 0; i < n_members; ++i) { + ir_entity *member = get_compound_member(arg_type, i); + size_t param; + if (!is_parameter_entity(member)) + continue; + param = get_entity_parameter_number(member); + if (param == IR_VA_START_PARAMETER_NUMBER) + continue; + assert(infos[param].entity == NULL && infos[param].reg == NULL); + infos[param].reg = NULL; + infos[param].entity = member; + } + + return infos; +} + /** * Main driver. Emits the code for one routine. */ @@ -1874,6 +1924,8 @@ void ia32_gen_routine(ir_graph *irg) const arch_env_t *arch_env = be_get_irg_arch_env(irg); ia32_irg_data_t *irg_data = ia32_get_irg_data(irg); ir_node **blk_sched = irg_data->blk_sched; + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + parameter_dbg_info_t *infos; int i, n; isa = (ia32_isa_t*) arch_env; @@ -1885,7 +1937,24 @@ void ia32_gen_routine(ir_graph *irg) get_unique_label(pic_base_label, sizeof(pic_base_label), "PIC_BASE"); - be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment); + infos = construct_parameter_infos(irg); + be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment, + infos); + xfree(infos); + + sp_relative = layout->sp_relative; + if (layout->sp_relative) { + ir_type *frame_type = get_irg_frame_type(irg); + frame_type_size = get_type_size_bytes(frame_type); + be_dwarf_callframe_register(&ia32_registers[REG_ESP]); + } else { + /* well not entirely correct here, we should emit this after the + * "movl esp, ebp" */ + be_dwarf_callframe_register(&ia32_registers[REG_EBP]); + /* TODO: do not hardcode the following */ + be_dwarf_callframe_offset(8); + be_dwarf_callframe_spilloffset(&ia32_registers[REG_EBP], -8); + } /* we use links to point to target blocks */ ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK); @@ -3814,12 +3883,16 @@ void ia32_gen_binary_routine(ir_graph *irg) ia32_irg_data_t *irg_data = ia32_get_irg_data(irg); ir_node **blk_sched = irg_data->blk_sched; size_t i, n; + parameter_dbg_info_t *infos; isa = (ia32_isa_t*) arch_env; ia32_register_binary_emitters(); - be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment); + infos = construct_parameter_infos(irg); + be_gas_emit_function_prolog(entity, ia32_cg_config.function_alignment, + NULL); + xfree(infos); /* we use links to point to target blocks */ ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK); diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index f548d7c6b..213eec124 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -1330,7 +1330,7 @@ static void sparc_emit_block(ir_node *block, ir_node *prev) static void sparc_emit_func_prolog(ir_graph *irg) { ir_entity *entity = get_irg_entity(irg); - be_gas_emit_function_prolog(entity, 4); + be_gas_emit_function_prolog(entity, 4, NULL); } /** -- 2.20.1