diff options
Diffstat (limited to 'gas/dw2gencfi.c')
-rw-r--r-- | gas/dw2gencfi.c | 200 |
1 files changed, 160 insertions, 40 deletions
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index a224524..5e37833 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -164,6 +164,54 @@ cfi_set_return_column (unsigned regno) cur_fde_data->return_column = regno; } +/* Universal functions to store new instructions. */ + +static void +cfi_add_CFA_insn(int insn) +{ + struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data (); + + insn_ptr->insn = insn; +} + +static void +cfi_add_CFA_insn_reg (int insn, unsigned regno) +{ + struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data (); + + insn_ptr->insn = insn; + insn_ptr->u.r = regno; +} + +static void +cfi_add_CFA_insn_offset (int insn, offsetT offset) +{ + struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data (); + + insn_ptr->insn = insn; + insn_ptr->u.i = offset; +} + +static void +cfi_add_CFA_insn_reg_reg (int insn, unsigned reg1, unsigned reg2) +{ + struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data (); + + insn_ptr->insn = insn; + insn_ptr->u.rr.reg1 = reg1; + insn_ptr->u.rr.reg2 = reg2; +} + +static void +cfi_add_CFA_insn_reg_offset (int insn, unsigned regno, offsetT offset) +{ + struct cfi_insn_data *insn_ptr = alloc_cfi_insn_data (); + + insn_ptr->insn = insn; + insn_ptr->u.ri.reg = regno; + insn_ptr->u.ri.offset = offset; +} + /* Add a CFI insn to advance the PC from the last address to LABEL. */ void @@ -183,11 +231,7 @@ cfi_add_advance_loc (symbolS *label) void cfi_add_CFA_offset (unsigned regno, offsetT offset) { - struct cfi_insn_data *insn = alloc_cfi_insn_data (); - - insn->insn = DW_CFA_offset; - insn->u.ri.reg = regno; - insn->u.ri.offset = offset; + cfi_add_CFA_insn_reg_offset (DW_CFA_offset, regno, offset); } /* Add a DW_CFA_def_cfa record to the CFI data. */ @@ -195,12 +239,7 @@ cfi_add_CFA_offset (unsigned regno, offsetT offset) void cfi_add_CFA_def_cfa (unsigned regno, offsetT offset) { - struct cfi_insn_data *insn = alloc_cfi_insn_data (); - - insn->insn = DW_CFA_def_cfa; - insn->u.ri.reg = regno; - insn->u.ri.offset = offset; - + cfi_add_CFA_insn_reg_offset (DW_CFA_def_cfa, regno, offset); cur_cfa_offset = offset; } @@ -209,11 +248,7 @@ cfi_add_CFA_def_cfa (unsigned regno, offsetT offset) void cfi_add_CFA_register (unsigned reg1, unsigned reg2) { - struct cfi_insn_data *insn = alloc_cfi_insn_data (); - - insn->insn = DW_CFA_register; - insn->u.rr.reg1 = reg1; - insn->u.rr.reg2 = reg2; + cfi_add_CFA_insn_reg_reg (DW_CFA_register, reg1, reg2); } /* Add a DW_CFA_def_cfa_register record to the CFI data. */ @@ -221,10 +256,7 @@ cfi_add_CFA_register (unsigned reg1, unsigned reg2) void cfi_add_CFA_def_cfa_register (unsigned regno) { - struct cfi_insn_data *insn = alloc_cfi_insn_data (); - - insn->insn = DW_CFA_def_cfa_register; - insn->u.r = regno; + cfi_add_CFA_insn_reg (DW_CFA_def_cfa_register, regno); } /* Add a DW_CFA_def_cfa_offset record to the CFI data. */ @@ -232,14 +264,46 @@ cfi_add_CFA_def_cfa_register (unsigned regno) void cfi_add_CFA_def_cfa_offset (offsetT offset) { - struct cfi_insn_data *insn = alloc_cfi_insn_data (); - - insn->insn = DW_CFA_def_cfa_offset; - insn->u.i = offset; - + cfi_add_CFA_insn_offset (DW_CFA_def_cfa_offset, offset); cur_cfa_offset = offset; } +void +cfi_add_CFA_restore (unsigned regno) +{ + cfi_add_CFA_insn_reg (DW_CFA_restore, regno); +} + +void +cfi_add_CFA_undefined (unsigned regno) +{ + cfi_add_CFA_insn_reg (DW_CFA_undefined, regno); +} + +void +cfi_add_CFA_same_value (unsigned regno) +{ + cfi_add_CFA_insn_reg (DW_CFA_same_value, regno); +} + +void +cfi_add_CFA_remember_state (void) +{ + cfi_add_CFA_insn (DW_CFA_remember_state); +} + +void +cfi_add_CFA_restore_state (void) +{ + cfi_add_CFA_insn (DW_CFA_restore_state); +} + +void +cfi_add_CFA_nop (void) +{ + cfi_add_CFA_insn (DW_CFA_nop); +} + /* Parse CFI assembler directives. */ @@ -248,7 +312,8 @@ static void dot_cfi_startproc (int); static void dot_cfi_endproc (int); /* Fake CFI type; outside the byte range of any real CFI insn. */ -#define CFI_adjust_cfa_offset 0x100 +#define CFI_adjust_cfa_offset 0x100 +#define CFI_return_column 0x101 const pseudo_typeS cfi_pseudo_table[] = { @@ -260,6 +325,13 @@ const pseudo_typeS cfi_pseudo_table[] = { "cfi_adjust_cfa_offset", dot_cfi, CFI_adjust_cfa_offset }, { "cfi_offset", dot_cfi, DW_CFA_offset }, { "cfi_register", dot_cfi, DW_CFA_register }, + { "cfi_return_column", dot_cfi, CFI_return_column }, + { "cfi_restore", dot_cfi, DW_CFA_restore }, + { "cfi_undefined", dot_cfi, DW_CFA_undefined }, + { "cfi_same_value", dot_cfi, DW_CFA_same_value }, + { "cfi_remember_state", dot_cfi, DW_CFA_remember_state }, + { "cfi_restore_state", dot_cfi, DW_CFA_restore_state }, + { "cfi_nop", dot_cfi, DW_CFA_nop }, { NULL, NULL, 0 } }; @@ -343,46 +415,74 @@ dot_cfi (int arg) switch (arg) { - /* Instructions that take two arguments (register, integer). */ case DW_CFA_offset: - case DW_CFA_def_cfa: reg1 = cfi_parse_reg (); cfi_parse_separator (); offset = cfi_parse_const (); + cfi_add_CFA_offset (reg1, offset); + break; - if (arg == DW_CFA_def_cfa) - cfi_add_CFA_def_cfa (reg1, offset); - else - cfi_add_CFA_offset (reg1, offset); + case DW_CFA_def_cfa: + reg1 = cfi_parse_reg (); + cfi_parse_separator (); + offset = cfi_parse_const (); + cfi_add_CFA_def_cfa (reg1, offset); break; - /* Instructions that take two arguments (register, register). */ case DW_CFA_register: reg1 = cfi_parse_reg (); cfi_parse_separator (); reg2 = cfi_parse_reg (); - cfi_add_CFA_register (reg1, reg2); break; - /* Instructions that take one register argument. */ case DW_CFA_def_cfa_register: reg1 = cfi_parse_reg (); cfi_add_CFA_def_cfa_register (reg1); break; - /* Instructions that take one integer argument. */ case DW_CFA_def_cfa_offset: offset = cfi_parse_const (); cfi_add_CFA_def_cfa_offset (offset); break; - /* Special handling for pseudo-instruction. */ case CFI_adjust_cfa_offset: offset = cfi_parse_const (); cfi_add_CFA_def_cfa_offset (cur_cfa_offset + offset); break; + case DW_CFA_restore: + reg1 = cfi_parse_reg (); + cfi_add_CFA_restore (reg1); + break; + + case DW_CFA_undefined: + reg1 = cfi_parse_reg (); + cfi_add_CFA_undefined (reg1); + break; + + case DW_CFA_same_value: + reg1 = cfi_parse_reg (); + cfi_add_CFA_same_value (reg1); + break; + + case CFI_return_column: + reg1 = cfi_parse_reg (); + cfi_set_return_column (reg1); + break; + + case DW_CFA_remember_state: + cfi_add_CFA_remember_state (); + break; + + case DW_CFA_restore_state: + cfi_add_CFA_restore_state (); + break; + + case DW_CFA_nop: + cfi_add_CFA_nop (); + break; + default: abort (); } @@ -553,8 +653,10 @@ output_cfi_insn (struct cfi_insn_data *insn) break; case DW_CFA_def_cfa_register: - out_one (DW_CFA_def_cfa_register); - out_uleb128 (insn->u.i); + case DW_CFA_undefined: + case DW_CFA_same_value: + out_one (insn->insn); + out_uleb128 (insn->u.r); break; case DW_CFA_def_cfa_offset: @@ -571,6 +673,19 @@ output_cfi_insn (struct cfi_insn_data *insn) } break; + case DW_CFA_restore: + regno = insn->u.r; + if (regno <= 0x3F) + { + out_one (DW_CFA_restore + regno); + } + else + { + out_one (DW_CFA_restore_extended); + out_uleb128 (regno); + } + break; + case DW_CFA_offset: regno = insn->u.ri.reg; offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; @@ -599,8 +714,10 @@ output_cfi_insn (struct cfi_insn_data *insn) out_uleb128 (insn->u.rr.reg2); break; + case DW_CFA_remember_state: + case DW_CFA_restore_state: case DW_CFA_nop: - out_one (DW_CFA_nop); + out_one (insn->insn); break; default: @@ -722,6 +839,9 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst) break; case DW_CFA_def_cfa_register: + case DW_CFA_restore: + case DW_CFA_undefined: + case DW_CFA_same_value: if (i->u.r != j->u.r) goto fail; break; |