* dw2gencfi.c: Include dwarf2dbg.h.

(DWARF2_FORMAT): Define if not defined.
	(dot_cfi_sections): New function.
	(cfi_pseudo_table): Handle .cfi_sections.
	(CFI_EMIT_eh_frame, CFI_EMIT_debug_frame): Define.
	(cfi_sections): New variable.
	(output_cie, output_fde, select_cie_for_fde): Add eh_frame
	argument, add supporting for outputting .debug_frame
	section.
	(cfi_change_reg_numbers): New function or macro.
	(cfi_finish): Only emit .eh_frame if
	cfi_sections & CFI_EMIT_eh_frame.  Emit .debug_frame if
	cfi_sections & CFI_EMIT_debug_frame.
	* config/tc-ppc.h (md_reg_eh_frame_to_debug_frame): Define.
	* doc/as.texinfo (CFI directives): Document .cfi_sections.
This commit is contained in:
Jakub Jelinek 2009-10-02 11:33:50 +00:00
parent a263f14bb3
commit 38462edfa2
4 changed files with 289 additions and 58 deletions

View file

@ -1,3 +1,21 @@
2009-10-02 Jakub Jelinek <jakub@redhat.com>
* dw2gencfi.c: Include dwarf2dbg.h.
(DWARF2_FORMAT): Define if not defined.
(dot_cfi_sections): New function.
(cfi_pseudo_table): Handle .cfi_sections.
(CFI_EMIT_eh_frame, CFI_EMIT_debug_frame): Define.
(cfi_sections): New variable.
(output_cie, output_fde, select_cie_for_fde): Add eh_frame
argument, add supporting for outputting .debug_frame
section.
(cfi_change_reg_numbers): New function or macro.
(cfi_finish): Only emit .eh_frame if
cfi_sections & CFI_EMIT_eh_frame. Emit .debug_frame if
cfi_sections & CFI_EMIT_debug_frame.
* config/tc-ppc.h (md_reg_eh_frame_to_debug_frame): Define.
* doc/as.texinfo (CFI directives): Document .cfi_sections.
2009-10-01 Peter Bergner <bergner@vnet.ibm.com> 2009-10-01 Peter Bergner <bergner@vnet.ibm.com>
* config/tc-ppc.c (md_show_usage): Rename "ppca2" to "a2". * config/tc-ppc.c (md_show_usage): Rename "ppca2" to "a2".

View file

@ -249,6 +249,12 @@ extern int ppc_parse_name (const char *, struct expressionS *);
#define md_cleanup() ppc_cleanup () #define md_cleanup() ppc_cleanup ()
extern void ppc_cleanup (void); extern void ppc_cleanup (void);
/* ppc uses different register numbers between .eh_frame and .debug_frame.
This macro translates the .eh_frame register numbers to .debug_frame
register numbers. */
#define md_reg_eh_frame_to_debug_frame(regno) \
((regno) == 70 ? 64 /* cr2 */ : (regno))
#define TARGET_USE_CFIPOP 1 #define TARGET_USE_CFIPOP 1
#define tc_cfi_frame_initial_instructions ppc_cfi_frame_initial_instructions #define tc_cfi_frame_initial_instructions ppc_cfi_frame_initial_instructions

View file

@ -4197,6 +4197,15 @@ undefined.
Each expression is assembled into the next byte. Each expression is assembled into the next byte.
@node CFI directives @node CFI directives
@section @code{.cfi_sections @var{section_list}}
@cindex @code{cfi_sections} directive
@code{.cfi_sections} may be used to specify whether CFI directives
should emit @code{.eh_frame} section and/or @code{.debug_frame} section.
If @var{section_list} is @code{.eh_frame}, @code{.eh_frame} is emitted,
if @var{section_list} is @code{.debug_frame}, @code{.debug_frame} is emitted.
To emit both use @code{.eh_frame, .debug_frame}. The default if this
directive is not used is @code{.cfi_sections .eh_frame}.
@section @code{.cfi_startproc [simple]} @section @code{.cfi_startproc [simple]}
@cindex @code{cfi_startproc} directive @cindex @code{cfi_startproc} directive
@code{.cfi_startproc} is used at the beginning of each function that @code{.cfi_startproc} is used at the beginning of each function that

View file

@ -23,6 +23,7 @@
#include "as.h" #include "as.h"
#include "dw2gencfi.h" #include "dw2gencfi.h"
#include "subsegs.h" #include "subsegs.h"
#include "dwarf2dbg.h"
#ifdef TARGET_USE_CFIPOP #ifdef TARGET_USE_CFIPOP
@ -59,6 +60,10 @@
# define tc_cfi_frame_initial_instructions() ((void)0) # define tc_cfi_frame_initial_instructions() ((void)0)
#endif #endif
#ifndef DWARF2_FORMAT
# define DWARF2_FORMAT(SEC) dwarf2_format_32bit
#endif
#ifndef DWARF2_ADDR_SIZE #ifndef DWARF2_ADDR_SIZE
# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8) # define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
#endif #endif
@ -386,6 +391,7 @@ cfi_add_CFA_restore_state (void)
static void dot_cfi (int); static void dot_cfi (int);
static void dot_cfi_escape (int); static void dot_cfi_escape (int);
static void dot_cfi_sections (int);
static void dot_cfi_startproc (int); static void dot_cfi_startproc (int);
static void dot_cfi_endproc (int); static void dot_cfi_endproc (int);
static void dot_cfi_personality (int); static void dot_cfi_personality (int);
@ -402,6 +408,7 @@ static void dot_cfi_val_encoded_addr (int);
const pseudo_typeS cfi_pseudo_table[] = const pseudo_typeS cfi_pseudo_table[] =
{ {
{ "cfi_sections", dot_cfi_sections, 0 },
{ "cfi_startproc", dot_cfi_startproc, 0 }, { "cfi_startproc", dot_cfi_startproc, 0 },
{ "cfi_endproc", dot_cfi_endproc, 0 }, { "cfi_endproc", dot_cfi_endproc, 0 },
{ "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa }, { "cfi_def_cfa", dot_cfi, DW_CFA_def_cfa },
@ -864,6 +871,56 @@ dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED)
demand_empty_rest_of_line (); demand_empty_rest_of_line ();
} }
/* By default emit .eh_frame only, not .debug_frame. */
#define CFI_EMIT_eh_frame (1 << 0)
#define CFI_EMIT_debug_frame (1 << 1)
static int cfi_sections = CFI_EMIT_eh_frame;
static void
dot_cfi_sections (int ignored ATTRIBUTE_UNUSED)
{
int sections = 0;
SKIP_WHITESPACE ();
if (is_name_beginner (*input_line_pointer))
while (1)
{
char *name, c;
name = input_line_pointer;
c = get_symbol_end ();
if (strcmp (name, ".eh_frame") == 0)
sections |= CFI_EMIT_eh_frame;
else if (strcmp (name, ".debug_frame") == 0)
sections |= CFI_EMIT_debug_frame;
else
{
*input_line_pointer = c;
input_line_pointer = name;
break;
}
*input_line_pointer = c;
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
name = input_line_pointer++;
SKIP_WHITESPACE ();
if (!is_name_beginner (*input_line_pointer))
{
input_line_pointer = name;
break;
}
}
else if (is_name_beginner (*input_line_pointer))
break;
}
demand_empty_rest_of_line ();
cfi_sections = sections;
}
static void static void
dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED) dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
{ {
@ -1194,13 +1251,14 @@ encoding_size (unsigned char encoding)
} }
static void static void
output_cie (struct cie_entry *cie) output_cie (struct cie_entry *cie, bfd_boolean eh_frame, int align)
{ {
symbolS *after_size_address, *end_address; symbolS *after_size_address, *end_address;
expressionS exp; expressionS exp;
struct cfi_insn_data *i; struct cfi_insn_data *i;
offsetT augmentation_size; offsetT augmentation_size;
int enc; int enc;
enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
cie->start_address = symbol_temp_new_now (); cie->start_address = symbol_temp_new_now ();
after_size_address = symbol_temp_make (); after_size_address = symbol_temp_make ();
@ -1211,18 +1269,35 @@ output_cie (struct cie_entry *cie)
exp.X_op_symbol = after_size_address; exp.X_op_symbol = after_size_address;
exp.X_add_number = 0; exp.X_add_number = 0;
emit_expr (&exp, 4); /* Length. */ if (eh_frame || fmt == dwarf2_format_32bit)
emit_expr (&exp, 4); /* Length. */
else
{
if (fmt == dwarf2_format_64bit)
out_four (-1);
emit_expr (&exp, 8); /* Length. */
}
symbol_set_value_now (after_size_address); symbol_set_value_now (after_size_address);
out_four (0); /* CIE id. */ if (eh_frame)
out_four (0); /* CIE id. */
else
{
out_four (-1); /* CIE id. */
if (fmt != dwarf2_format_32bit)
out_four (-1);
}
out_one (DW_CIE_VERSION); /* Version. */ out_one (DW_CIE_VERSION); /* Version. */
out_one ('z'); /* Augmentation. */ if (eh_frame)
if (cie->per_encoding != DW_EH_PE_omit) {
out_one ('P'); out_one ('z'); /* Augmentation. */
if (cie->lsda_encoding != DW_EH_PE_omit) if (cie->per_encoding != DW_EH_PE_omit)
out_one ('L'); out_one ('P');
out_one ('R'); if (cie->lsda_encoding != DW_EH_PE_omit)
if (cie->signal_frame) out_one ('L');
out_one ('S'); out_one ('R');
if (cie->signal_frame)
out_one ('S');
}
out_one (0); out_one (0);
out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH); /* Code alignment. */ out_uleb128 (DWARF2_LINE_MIN_INSN_LENGTH); /* Code alignment. */
out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment. */ out_sleb128 (DWARF2_CIE_DATA_ALIGNMENT); /* Data alignment. */
@ -1230,10 +1305,13 @@ output_cie (struct cie_entry *cie)
out_one (cie->return_column); out_one (cie->return_column);
else else
out_uleb128 (cie->return_column); out_uleb128 (cie->return_column);
augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit); if (eh_frame)
if (cie->per_encoding != DW_EH_PE_omit) {
augmentation_size += 1 + encoding_size (cie->per_encoding); augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
out_uleb128 (augmentation_size); /* Augmentation size. */ if (cie->per_encoding != DW_EH_PE_omit)
augmentation_size += 1 + encoding_size (cie->per_encoding);
out_uleb128 (augmentation_size); /* Augmentation size. */
}
if (cie->per_encoding != DW_EH_PE_omit) if (cie->per_encoding != DW_EH_PE_omit)
{ {
offsetT size = encoding_size (cie->per_encoding); offsetT size = encoding_size (cie->per_encoding);
@ -1274,23 +1352,28 @@ output_cie (struct cie_entry *cie)
#if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
enc |= DW_EH_PE_pcrel; enc |= DW_EH_PE_pcrel;
#endif #endif
out_one (enc); if (eh_frame)
out_one (enc);
if (cie->first) if (cie->first)
for (i = cie->first; i != cie->last; i = i->next) for (i = cie->first; i != cie->last; i = i->next)
output_cfi_insn (i); output_cfi_insn (i);
frag_align (2, DW_CFA_nop, 0); frag_align (align, DW_CFA_nop, 0);
symbol_set_value_now (end_address); symbol_set_value_now (end_address);
} }
static void static void
output_fde (struct fde_entry *fde, struct cie_entry *cie, output_fde (struct fde_entry *fde, struct cie_entry *cie,
struct cfi_insn_data *first, int align) bfd_boolean eh_frame, struct cfi_insn_data *first,
int align)
{ {
symbolS *after_size_address, *end_address; symbolS *after_size_address, *end_address;
expressionS exp; expressionS exp;
offsetT augmentation_size; offsetT augmentation_size;
enum dwarf2_format fmt = DWARF2_FORMAT (now_seg);
int offset_size;
int addr_size;
after_size_address = symbol_temp_make (); after_size_address = symbol_temp_make ();
end_address = symbol_temp_make (); end_address = symbol_temp_make ();
@ -1299,35 +1382,63 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
exp.X_add_symbol = end_address; exp.X_add_symbol = end_address;
exp.X_op_symbol = after_size_address; exp.X_op_symbol = after_size_address;
exp.X_add_number = 0; exp.X_add_number = 0;
emit_expr (&exp, 4); /* Length. */ if (eh_frame || fmt == dwarf2_format_32bit)
offset_size = 4;
else
{
if (fmt == dwarf2_format_64bit)
out_four (-1);
offset_size = 8;
}
emit_expr (&exp, offset_size); /* Length. */
symbol_set_value_now (after_size_address); symbol_set_value_now (after_size_address);
exp.X_add_symbol = after_size_address; if (eh_frame)
exp.X_op_symbol = cie->start_address; {
emit_expr (&exp, 4); /* CIE offset. */ exp.X_add_symbol = after_size_address;
exp.X_op_symbol = cie->start_address;
}
else
{
exp.X_op = O_symbol;
exp.X_add_symbol = cie->start_address;
exp.X_op_symbol = NULL;
}
emit_expr (&exp, offset_size); /* CIE offset. */
if (eh_frame)
{
#if CFI_DIFF_EXPR_OK #if CFI_DIFF_EXPR_OK
exp.X_add_symbol = fde->start_address; exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = symbol_temp_new_now (); exp.X_op_symbol = symbol_temp_new_now ();
emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else #else
exp.X_op = O_symbol; exp.X_op = O_symbol;
exp.X_add_symbol = fde->start_address; exp.X_add_symbol = fde->start_address;
exp.X_op_symbol = NULL; exp.X_op_symbol = NULL;
#ifdef tc_cfi_emit_pcrel_expr #ifdef tc_cfi_emit_pcrel_expr
tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ tc_cfi_emit_pcrel_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#else #else
emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */ emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); /* Code offset. */
#endif #endif
exp.X_op = O_subtract;
#endif #endif
addr_size = DWARF2_FDE_RELOC_SIZE;
}
else
{
exp.X_add_symbol = fde->start_address;
addr_size = DWARF2_ADDR_SIZE (stdoutput);
emit_expr (&exp, addr_size);
}
exp.X_op = O_subtract;
exp.X_add_symbol = fde->end_address; exp.X_add_symbol = fde->end_address;
exp.X_op_symbol = fde->start_address; /* Code length. */ exp.X_op_symbol = fde->start_address; /* Code length. */
emit_expr (&exp, DWARF2_FDE_RELOC_SIZE); emit_expr (&exp, addr_size);
augmentation_size = encoding_size (fde->lsda_encoding); augmentation_size = encoding_size (fde->lsda_encoding);
out_uleb128 (augmentation_size); /* Augmentation size. */ if (eh_frame)
out_uleb128 (augmentation_size); /* Augmentation size. */
if (fde->lsda_encoding != DW_EH_PE_omit) if (fde->lsda_encoding != DW_EH_PE_omit)
{ {
@ -1356,7 +1467,8 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
} }
static struct cie_entry * static struct cie_entry *
select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst) select_cie_for_fde (struct fde_entry *fde, bfd_boolean eh_frame,
struct cfi_insn_data **pfirst, int align)
{ {
struct cfi_insn_data *i, *j; struct cfi_insn_data *i, *j;
struct cie_entry *cie; struct cie_entry *cie;
@ -1477,12 +1589,56 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
cie->last = i; cie->last = i;
*pfirst = i; *pfirst = i;
output_cie (cie); output_cie (cie, eh_frame, align);
return cie; return cie;
} }
#ifdef md_reg_eh_frame_to_debug_frame
static void
cfi_change_reg_numbers (struct cfi_insn_data *insn)
{
for (; insn; insn = insn->next)
switch (insn->insn)
{
case DW_CFA_advance_loc:
case DW_CFA_def_cfa_offset:
case DW_CFA_remember_state:
case DW_CFA_restore_state:
case DW_CFA_GNU_window_save:
case CFI_escape:
break;
case DW_CFA_def_cfa:
case DW_CFA_offset:
insn->u.ri.reg = md_reg_eh_frame_to_debug_frame (insn->u.ri.reg);
break;
case DW_CFA_def_cfa_register:
case DW_CFA_undefined:
case DW_CFA_same_value:
case DW_CFA_restore:
insn->u.r = md_reg_eh_frame_to_debug_frame (insn->u.r);
break;
case DW_CFA_register:
insn->u.rr.reg1 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg1);
insn->u.rr.reg2 = md_reg_eh_frame_to_debug_frame (insn->u.rr.reg2);
break;
case CFI_val_encoded_addr:
insn->u.ea.reg = md_reg_eh_frame_to_debug_frame (insn->u.ea.reg);
break;
default:
abort ();
}
}
#else
#define cfi_change_reg_numbers(insn) do { } while (0)
#endif
void void
cfi_finish (void) cfi_finish (void)
{ {
@ -1493,38 +1649,80 @@ cfi_finish (void)
if (all_fde_data == 0) if (all_fde_data == 0)
return; return;
/* Open .eh_frame section. */ if ((cfi_sections & CFI_EMIT_eh_frame) != 0)
cfi_seg = subseg_new (".eh_frame", 0); {
bfd_set_section_flags (stdoutput, cfi_seg, /* Open .eh_frame section. */
SEC_ALLOC | SEC_LOAD | SEC_DATA cfi_seg = subseg_new (".eh_frame", 0);
| DWARF2_EH_FRAME_READ_ONLY); bfd_set_section_flags (stdoutput, cfi_seg,
subseg_set (cfi_seg, 0); SEC_ALLOC | SEC_LOAD | SEC_DATA
record_alignment (cfi_seg, EH_FRAME_ALIGNMENT); | DWARF2_EH_FRAME_READ_ONLY);
subseg_set (cfi_seg, 0);
record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
#ifdef md_fix_up_eh_frame #ifdef md_fix_up_eh_frame
md_fix_up_eh_frame (cfi_seg); md_fix_up_eh_frame (cfi_seg);
#endif #endif
/* Make sure check_eh_frame doesn't do anything with our output. */ /* Make sure check_eh_frame doesn't do anything with our output. */
save_flag_traditional_format = flag_traditional_format; save_flag_traditional_format = flag_traditional_format;
flag_traditional_format = 1; flag_traditional_format = 1;
for (fde = all_fde_data; fde ; fde = fde->next) for (fde = all_fde_data; fde ; fde = fde->next)
{
struct cfi_insn_data *first;
struct cie_entry *cie;
if (fde->end_address == NULL)
{ {
as_bad (_("open CFI at the end of file; missing .cfi_endproc directive")); struct cfi_insn_data *first;
fde->end_address = fde->start_address; struct cie_entry *cie;
if (fde->end_address == NULL)
{
as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
fde->end_address = fde->start_address;
}
cie = select_cie_for_fde (fde, TRUE, &first, 2);
output_fde (fde, cie, TRUE, first,
fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
} }
cie = select_cie_for_fde (fde, &first); flag_traditional_format = save_flag_traditional_format;
output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
} }
flag_traditional_format = save_flag_traditional_format; if ((cfi_sections & CFI_EMIT_debug_frame) != 0)
{
struct cie_entry *cie, *cie_next;
int alignment = ffs (DWARF2_ADDR_SIZE (stdoutput)) - 1;
for (cie = cie_root; cie; cie = cie_next)
{
cie_next = cie->next;
free ((void *) cie);
}
cie_root = NULL;
/* Open .debug_frame section. */
cfi_seg = subseg_new (".debug_frame", 0);
bfd_set_section_flags (stdoutput, cfi_seg,
SEC_READONLY | SEC_DEBUGGING);
subseg_set (cfi_seg, 0);
record_alignment (cfi_seg, alignment);
for (fde = all_fde_data; fde ; fde = fde->next)
{
struct cfi_insn_data *first;
struct cie_entry *cie;
if (fde->end_address == NULL)
{
as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
fde->end_address = fde->start_address;
}
fde->per_encoding = DW_EH_PE_omit;
fde->lsda_encoding = DW_EH_PE_omit;
cfi_change_reg_numbers (fde->data);
cie = select_cie_for_fde (fde, FALSE, &first, alignment);
output_fde (fde, cie, FALSE, first, alignment);
}
}
} }
#else /* TARGET_USE_CFIPOP */ #else /* TARGET_USE_CFIPOP */