mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
cafca5eaa0
CFI label name can be freed only after use. * scfi.c (handle_scfi_dot_cfi): Free CFI label name after use. * scfidw2gen.c (scfi_process_cfi_label): Add a comment. Remove TODO on freeing CFI label name.
273 lines
6.7 KiB
C
273 lines
6.7 KiB
C
/* scfidw2gen.c - Support for emission of synthesized Dwarf2 CFI.
|
|
Copyright (C) 2023 Free Software Foundation, Inc.
|
|
|
|
This file is part of GAS, the GNU Assembler.
|
|
|
|
GAS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GAS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GAS; see the file COPYING. If not, write to the Free
|
|
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
|
|
02110-1301, USA. */
|
|
|
|
#include "as.h"
|
|
#include "ginsn.h"
|
|
#include "scfi.h"
|
|
#include "dw2gencfi.h"
|
|
#include "subsegs.h"
|
|
#include "scfidw2gen.h"
|
|
|
|
#if defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN)
|
|
|
|
static bool scfi_ignore_warn_once;
|
|
|
|
static void
|
|
dot_scfi_ignore (int ignored ATTRIBUTE_UNUSED)
|
|
{
|
|
gas_assert (flag_synth_cfi);
|
|
|
|
if (!scfi_ignore_warn_once)
|
|
{
|
|
as_warn (_("SCFI ignores most user-specified CFI directives"));
|
|
scfi_ignore_warn_once = true;
|
|
}
|
|
ignore_rest_of_line ();
|
|
}
|
|
|
|
static void
|
|
scfi_process_cfi_label (void)
|
|
{
|
|
char *name;
|
|
ginsnS *ginsn;
|
|
|
|
name = read_symbol_name ();
|
|
if (name == NULL)
|
|
return;
|
|
|
|
/* Add a new ginsn. */
|
|
ginsn = ginsn_new_phantom (symbol_temp_new_now ());
|
|
frch_ginsn_data_append (ginsn);
|
|
|
|
scfi_op_add_cfi_label (ginsn, name);
|
|
/* NB: Can't free NAME here since it will be used later. Free it in
|
|
handle_scfi_dot_cfi after it is unused. */
|
|
|
|
demand_empty_rest_of_line ();
|
|
}
|
|
|
|
static void
|
|
scfi_process_cfi_signal_frame (void)
|
|
{
|
|
ginsnS *ginsn;
|
|
|
|
ginsn = ginsn_new_phantom (symbol_temp_new_now ());
|
|
frch_ginsn_data_append (ginsn);
|
|
|
|
scfi_op_add_signal_frame (ginsn);
|
|
}
|
|
|
|
static void
|
|
dot_scfi (int arg)
|
|
{
|
|
switch (arg)
|
|
{
|
|
case CFI_label:
|
|
scfi_process_cfi_label ();
|
|
break;
|
|
case CFI_signal_frame:
|
|
scfi_process_cfi_signal_frame ();
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
const pseudo_typeS scfi_pseudo_table[] =
|
|
{
|
|
{ "cfi_sections", dot_cfi_sections, 0 }, /* No ignore. */
|
|
{ "cfi_signal_frame", dot_scfi, CFI_signal_frame }, /* No ignore. */
|
|
{ "cfi_label", dot_scfi, CFI_label }, /* No ignore. */
|
|
{ "cfi_startproc", dot_scfi_ignore, 0 },
|
|
{ "cfi_endproc", dot_scfi_ignore, 0 },
|
|
{ "cfi_fde_data", dot_scfi_ignore, 0 },
|
|
{ "cfi_def_cfa", dot_scfi_ignore, 0 },
|
|
{ "cfi_def_cfa_register", dot_scfi_ignore, 0 },
|
|
{ "cfi_def_cfa_offset", dot_scfi_ignore, 0 },
|
|
{ "cfi_adjust_cfa_offset", dot_scfi_ignore, 0 },
|
|
{ "cfi_offset", dot_scfi_ignore, 0 },
|
|
{ "cfi_rel_offset", dot_scfi_ignore, 0 },
|
|
{ "cfi_register", dot_scfi_ignore, 0 },
|
|
{ "cfi_return_column", dot_scfi_ignore, 0 },
|
|
{ "cfi_restore", dot_scfi_ignore, 0 },
|
|
{ "cfi_undefined", dot_scfi_ignore, 0 },
|
|
{ "cfi_same_value", dot_scfi_ignore, 0 },
|
|
{ "cfi_remember_state", dot_scfi_ignore, 0 },
|
|
{ "cfi_restore_state", dot_scfi_ignore, 0 },
|
|
{ "cfi_window_save", dot_scfi_ignore, 0 },
|
|
{ "cfi_negate_ra_state", dot_scfi_ignore, 0 },
|
|
{ "cfi_escape", dot_scfi_ignore, 0 },
|
|
{ "cfi_personality", dot_scfi_ignore, 0 },
|
|
{ "cfi_personality_id", dot_scfi_ignore, 0 },
|
|
{ "cfi_lsda", dot_scfi_ignore, 0 },
|
|
{ "cfi_val_encoded_addr", dot_scfi_ignore, 0 },
|
|
{ "cfi_inline_lsda", dot_scfi_ignore, 0 },
|
|
{ "cfi_val_offset", dot_scfi_ignore, 0 },
|
|
{ NULL, NULL, 0 }
|
|
};
|
|
|
|
void
|
|
scfi_dot_cfi_startproc (const symbolS *start_sym)
|
|
{
|
|
if (frchain_now->frch_cfi_data != NULL)
|
|
{
|
|
as_bad (_("SCFI: missing previous SCFI endproc marker"));
|
|
return;
|
|
}
|
|
|
|
cfi_new_fde ((symbolS *)start_sym);
|
|
|
|
cfi_set_sections ();
|
|
|
|
frchain_now->frch_cfi_data->cur_cfa_offset = 0;
|
|
|
|
/* By default, SCFI machinery assumes .cfi_startproc is used without
|
|
parameter simple. */
|
|
tc_cfi_frame_initial_instructions ();
|
|
|
|
if ((all_cfi_sections & CFI_EMIT_target) != 0)
|
|
tc_cfi_startproc ();
|
|
}
|
|
|
|
void
|
|
scfi_dot_cfi_endproc (const symbolS *end_sym)
|
|
{
|
|
struct fde_entry *fde_last;
|
|
|
|
if (frchain_now->frch_cfi_data == NULL)
|
|
{
|
|
as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
|
|
return;
|
|
}
|
|
|
|
fde_last = frchain_now->frch_cfi_data->cur_fde_data;
|
|
cfi_set_last_fde (fde_last);
|
|
|
|
cfi_end_fde ((symbolS *)end_sym);
|
|
|
|
if ((all_cfi_sections & CFI_EMIT_target) != 0)
|
|
tc_cfi_endproc (fde_last);
|
|
}
|
|
|
|
void
|
|
scfi_dot_cfi (int arg, unsigned reg1, unsigned reg2, offsetT offset,
|
|
const char *name, const symbolS *advloc)
|
|
{
|
|
if (frchain_now->frch_cfi_data == NULL)
|
|
{
|
|
as_bad (_("CFI instruction used without previous .cfi_startproc"));
|
|
return;
|
|
}
|
|
|
|
/* If the last address was not at the current PC, advance to current. */
|
|
if (frchain_now->frch_cfi_data->last_address != advloc)
|
|
cfi_add_advance_loc ((symbolS *)advloc);
|
|
|
|
switch (arg)
|
|
{
|
|
case DW_CFA_offset:
|
|
cfi_add_CFA_offset (reg1, offset);
|
|
break;
|
|
|
|
case DW_CFA_val_offset:
|
|
cfi_add_CFA_val_offset (reg1, offset);
|
|
break;
|
|
|
|
case CFI_rel_offset:
|
|
cfi_add_CFA_offset (reg1,
|
|
offset - frchain_now->frch_cfi_data->cur_cfa_offset);
|
|
break;
|
|
|
|
case DW_CFA_def_cfa:
|
|
cfi_add_CFA_def_cfa (reg1, offset);
|
|
break;
|
|
|
|
case DW_CFA_register:
|
|
cfi_add_CFA_register (reg1, reg2);
|
|
break;
|
|
|
|
case DW_CFA_def_cfa_register:
|
|
cfi_add_CFA_def_cfa_register (reg1);
|
|
break;
|
|
|
|
case DW_CFA_def_cfa_offset:
|
|
cfi_add_CFA_def_cfa_offset (offset);
|
|
break;
|
|
|
|
case CFI_adjust_cfa_offset:
|
|
cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset
|
|
+ offset);
|
|
break;
|
|
|
|
case DW_CFA_restore:
|
|
cfi_add_CFA_restore (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 CFI_label:
|
|
cfi_add_label (name);
|
|
break;
|
|
|
|
case CFI_signal_frame:
|
|
frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1;
|
|
break;
|
|
|
|
/*
|
|
case DW_CFA_undefined:
|
|
for (;;)
|
|
{
|
|
reg1 = cfi_parse_reg ();
|
|
cfi_add_CFA_undefined (reg1);
|
|
SKIP_WHITESPACE ();
|
|
if (*input_line_pointer != ',')
|
|
break;
|
|
++input_line_pointer;
|
|
}
|
|
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_GNU_window_save:
|
|
cfi_add_CFA_insn (DW_CFA_GNU_window_save);
|
|
break;
|
|
|
|
*/
|
|
default:
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
#endif
|