Re: PR27723, Internal error in select_cie_for_fde
Let's make sure what we allow in the CIE initial instructions and what select_cie_for_fde compares for a match is always in sync. Also correct the previous patch that allowed DW_CFA_GNU_window_save to be part of the CIE initial instructions, which was likely a mistake. PR 27723 * dw2gencfi.c (initial_cie_insn): New function, extracted from.. (select_cie_for_fde): ..here. Simplify.
This commit is contained in:
parent
c48a248e33
commit
d20eb46617
@ -1,3 +1,9 @@
|
|||||||
|
2021-04-14 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
PR 27723
|
||||||
|
* dw2gencfi.c (initial_cie_insn): New function, extracted from..
|
||||||
|
(select_cie_for_fde): ..here. Simplify.
|
||||||
|
|
||||||
2021-04-14 Alan Modra <amodra@gmail.com>
|
2021-04-14 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
PR 27723
|
PR 27723
|
||||||
|
129
gas/dw2gencfi.c
129
gas/dw2gencfi.c
@ -2043,6 +2043,63 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
|
|||||||
symbol_set_value_now (end_address);
|
symbol_set_value_now (end_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allow these insns to be put in the initial sequence of a CIE.
|
||||||
|
If J is non-NULL, then compare I and J insns for a match. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
initial_cie_insn (const struct cfi_insn_data *i, const struct cfi_insn_data *j)
|
||||||
|
{
|
||||||
|
if (j && i->insn != j->insn)
|
||||||
|
return false;
|
||||||
|
switch (i->insn)
|
||||||
|
{
|
||||||
|
case DW_CFA_offset:
|
||||||
|
case DW_CFA_def_cfa:
|
||||||
|
case DW_CFA_val_offset:
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
if (i->u.ri.reg != j->u.ri.reg)
|
||||||
|
return false;
|
||||||
|
if (i->u.ri.offset != j->u.ri.offset)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_CFA_register:
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
if (i->u.rr.reg1 != j->u.rr.reg1)
|
||||||
|
return false;
|
||||||
|
if (i->u.rr.reg2 != j->u.rr.reg2)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_CFA_def_cfa_register:
|
||||||
|
case DW_CFA_restore:
|
||||||
|
case DW_CFA_undefined:
|
||||||
|
case DW_CFA_same_value:
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
if (i->u.r != j->u.r)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DW_CFA_def_cfa_offset:
|
||||||
|
if (j)
|
||||||
|
{
|
||||||
|
if (i->u.i != j->u.i)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct cie_entry *
|
static struct cie_entry *
|
||||||
select_cie_for_fde (struct fde_entry *fde, bool eh_frame,
|
select_cie_for_fde (struct fde_entry *fde, bool eh_frame,
|
||||||
struct cfi_insn_data **pfirst, int align)
|
struct cfi_insn_data **pfirst, int align)
|
||||||
@ -2088,75 +2145,15 @@ select_cie_for_fde (struct fde_entry *fde, bool eh_frame,
|
|||||||
i != cie->last && j != NULL;
|
i != cie->last && j != NULL;
|
||||||
i = i->next, j = j->next)
|
i = i->next, j = j->next)
|
||||||
{
|
{
|
||||||
if (i->insn != j->insn)
|
if (!initial_cie_insn (i, j))
|
||||||
goto fail;
|
break;
|
||||||
switch (i->insn)
|
|
||||||
{
|
|
||||||
case DW_CFA_advance_loc:
|
|
||||||
case DW_CFA_remember_state:
|
|
||||||
/* We reached the first advance/remember in the FDE,
|
|
||||||
but did not reach the end of the CIE list. */
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
case DW_CFA_offset:
|
|
||||||
case DW_CFA_def_cfa:
|
|
||||||
case DW_CFA_val_offset:
|
|
||||||
if (i->u.ri.reg != j->u.ri.reg)
|
|
||||||
goto fail;
|
|
||||||
if (i->u.ri.offset != j->u.ri.offset)
|
|
||||||
goto fail;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DW_CFA_register:
|
|
||||||
if (i->u.rr.reg1 != j->u.rr.reg1)
|
|
||||||
goto fail;
|
|
||||||
if (i->u.rr.reg2 != j->u.rr.reg2)
|
|
||||||
goto fail;
|
|
||||||
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;
|
|
||||||
|
|
||||||
case DW_CFA_def_cfa_offset:
|
|
||||||
if (i->u.i != j->u.i)
|
|
||||||
goto fail;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CFI_escape:
|
|
||||||
case CFI_val_encoded_addr:
|
|
||||||
case CFI_label:
|
|
||||||
case DW_CFA_restore_state:
|
|
||||||
case DW_CFA_GNU_window_save:
|
|
||||||
/* Don't bother matching these for now. */
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Success if we reached the end of the CIE list, and we've either
|
if (i == cie->last)
|
||||||
run out of FDE entries or we've encountered an advance,
|
|
||||||
remember, or escape. */
|
|
||||||
if (i == cie->last
|
|
||||||
&& (!j
|
|
||||||
|| j->insn == DW_CFA_advance_loc
|
|
||||||
|| j->insn == DW_CFA_remember_state
|
|
||||||
|| j->insn == DW_CFA_GNU_window_save
|
|
||||||
|| j->insn == CFI_escape
|
|
||||||
|| j->insn == CFI_val_encoded_addr
|
|
||||||
|| j->insn == CFI_label))
|
|
||||||
{
|
{
|
||||||
*pfirst = j;
|
*pfirst = j;
|
||||||
return cie;
|
return cie;
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cie = XNEW (struct cie_entry);
|
cie = XNEW (struct cie_entry);
|
||||||
@ -2174,11 +2171,7 @@ select_cie_for_fde (struct fde_entry *fde, bool eh_frame,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = cie->first; i ; i = i->next)
|
for (i = cie->first; i ; i = i->next)
|
||||||
if (i->insn == DW_CFA_advance_loc
|
if (!initial_cie_insn (i, NULL))
|
||||||
|| i->insn == DW_CFA_remember_state
|
|
||||||
|| i->insn == CFI_escape
|
|
||||||
|| i->insn == CFI_val_encoded_addr
|
|
||||||
|| i->insn == CFI_label)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cie->last = i;
|
cie->last = i;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user