1 /* dw2gencfi.c - Support for generating Dwarf2 CFI information.
2 Copyright 2003 Free Software Foundation, Inc.
3 Contributed by Michal Ludvig <mludvig@suse.cz>
5 This file is part of GAS, the GNU Assembler.
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "dw2gencfi.h"
26 /* Current target config. */
27 static struct cfi_config current_config
;
29 /* This is the main entry point to the CFI machinery. */
30 static void dot_cfi (int arg
);
32 const pseudo_typeS cfi_pseudo_table
[] =
34 { "cfi_verbose", dot_cfi
, CFI_verbose
},
35 { "cfi_startproc", dot_cfi
, CFI_startproc
},
36 { "cfi_endproc", dot_cfi
, CFI_endproc
},
37 { "cfi_def_cfa", dot_cfi
, CFA_def_cfa
},
38 { "cfi_def_cfa_register", dot_cfi
, CFA_def_cfa_register
},
39 { "cfi_def_cfa_offset", dot_cfi
, CFA_def_cfa_offset
},
40 { "cfi_adjust_cfa_offset", dot_cfi
, CFI_adjust_cfa_offset
},
41 { "cfi_offset", dot_cfi
, CFA_offset
},
46 cfi_insn_str (enum cfi_insn insn
)
54 case CFA_advance_loc1
:
55 return "CFA_advance_loc1";
56 case CFA_advance_loc2
:
57 return "CFA_advance_loc2";
58 case CFA_advance_loc4
:
59 return "CFA_advance_loc4";
60 case CFA_offset_extended
:
61 return "CFA_offset_extended";
62 case CFA_resotre_extended
:
63 return "CFA_resotre_extended";
65 return "CFA_undefined";
67 return "CFA_same_value";
69 return "CFA_register";
70 case CFA_remember_state
:
71 return "CFA_remember_state";
72 case CFA_restore_state
:
73 return "CFA_restore_state";
76 case CFA_def_cfa_register
:
77 return "CFA_def_cfa_register";
78 case CFA_def_cfa_offset
:
79 return "CFA_def_cfa_offset";
81 return "CFA_advance_loc";
97 struct cfi_data
*next
;
102 addressT start_address
;
103 addressT end_address
;
104 addressT last_address
;
105 const char *labelname
;
106 struct cfi_data
*data
;
107 struct cfi_info
*next
;
110 static struct cfi_info
*cfi_info
;
112 static struct cfi_data
*
113 alloc_cfi_data (void)
115 return (struct cfi_data
*) xcalloc (sizeof (struct cfi_info
), 1);
118 static struct cfi_info
*
119 alloc_cfi_info (void)
121 return (struct cfi_info
*) xcalloc (sizeof (struct cfi_info
), 1);
124 /* Parse arguments. */
126 cfi_parse_arg (long *param
, int resolvereg
)
132 assert (param
!= NULL
);
135 if (sscanf (input_line_pointer
, "%li%n", &value
, &nchars
) >= 1)
137 input_line_pointer
+= nchars
;
140 #ifdef tc_regname_to_dw2regnum
141 else if (resolvereg
&& (is_name_beginner (*input_line_pointer
)))
145 name
= input_line_pointer
;
146 c
= get_symbol_end ();
147 p
= input_line_pointer
;
149 if ((value
= tc_regname_to_dw2regnum (name
)) >= 0)
157 _("can't convert argument to a register number") :
158 _("can't convert argument to an integer"));
164 if (*input_line_pointer
== ',')
166 input_line_pointer
++;
174 cfi_parse_reg (long *param
)
176 return cfi_parse_arg (param
, 1);
180 cfi_parse_const (long *param
)
182 return cfi_parse_arg (param
, 0);
186 cfi_add_insn (enum cfi_insn insn
, long param0
, long param1
)
188 struct cfi_data
*data_ptr
;
192 cfi_info
->data
= alloc_cfi_data ();
193 data_ptr
= cfi_info
->data
;
197 data_ptr
= cfi_info
->data
;
199 while (data_ptr
&& data_ptr
->next
)
200 data_ptr
= data_ptr
->next
;
202 data_ptr
->next
= alloc_cfi_data ();
204 data_ptr
= data_ptr
->next
;
207 data_ptr
->insn
= insn
;
208 data_ptr
->param
[0] = param0
;
209 data_ptr
->param
[1] = param1
;
213 cfi_advance_loc (void)
215 addressT curr_address
= frag_now_fix ();
216 if (cfi_info
->last_address
== curr_address
)
218 cfi_add_insn (CFA_advance_loc
,
219 (long) (curr_address
- cfi_info
->last_address
), 0);
220 cfi_info
->last_address
= curr_address
;
224 get_current_offset (struct cfi_info
*info
)
226 long current_offset
= 0;
227 struct cfi_data
*data
= info
->data
;
232 if (data
->insn
== CFA_def_cfa
)
233 current_offset
= data
->param
[1];
234 else if (data
->insn
== CFA_def_cfa_offset
)
235 current_offset
= data
->param
[0];
239 return current_offset
;
243 cfi_make_insn (int arg
)
245 long param
[2] = { 0, 0 };
249 as_bad (_("CFI instruction used without previous .cfi_startproc"));
257 /* Instructions that take two arguments (register, integer). */
260 if (cfi_parse_reg (¶m
[0]) < 0)
262 as_bad (_("first argument to %s is not a register"),
266 if (cfi_parse_const (¶m
[1]) < 0)
268 as_bad (_("second argument to %s is not a number"),
274 /* Instructions that take one register argument. */
275 case CFA_def_cfa_register
:
276 if (cfi_parse_reg (¶m
[0]) < 0)
278 as_bad (_("argument to %s is not a register"), cfi_insn_str (arg
));
283 /* Instructions that take one integer argument. */
284 case CFA_def_cfa_offset
:
285 if (cfi_parse_const (¶m
[0]) < 0)
287 as_bad (_("argument to %s is not a number"), cfi_insn_str (arg
));
292 /* Special handling for pseudo-instruction. */
293 case CFI_adjust_cfa_offset
:
294 if (cfi_parse_const (¶m
[0]) < 0)
296 as_bad (_("argument to %s is not a number"),
297 ".cfi_adjust_cfa_offset");
300 param
[0] += get_current_offset (cfi_info
);
301 arg
= CFA_def_cfa_offset
;
305 as_bad (_("unknown CFI instruction %d (%s)"), arg
, cfi_insn_str (arg
));
308 cfi_add_insn (arg
, param
[0], param
[1]);
314 char symname
[40], *symbase
=".Llbl_cfi";
318 snprintf (symname
, sizeof (symname
), "%s_0x%lx",
319 symbase
, (long) frag_now_fix ());
320 while ((symbolP
= symbol_find (symname
)))
322 if ((S_GET_VALUE (symbolP
) == frag_now_fix ())
323 && (S_GET_SEGMENT (symbolP
) == now_seg
))
327 snprintf (symname
, sizeof (symname
), "%s_0x%lx_%u",
328 symbase
, (long) frag_now_fix (), i
++);
330 symbolP
= (symbolS
*) local_symbol_make (symname
, now_seg
,
331 (valueT
) frag_now_fix (),
337 dot_cfi_startproc (void)
341 as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
345 cfi_info
= alloc_cfi_info ();
347 cfi_info
->start_address
= frag_now_fix ();
348 cfi_info
->last_address
= cfi_info
->start_address
;
349 cfi_info
->labelname
= S_GET_NAME (cfi_get_label ());
351 #ifdef tc_cfi_frame_initial_instructions
352 tc_cfi_frame_initial_instructions ();
356 #define cfi_is_advance_insn(insn) \
357 ((insn >= CFA_set_loc && insn <= CFA_advance_loc4) \
358 || insn == CFA_advance_loc)
371 /* Output CFI instructions to the file. */
374 output_data (char **p
, unsigned long *size
, enum data_types type
, long value
)
377 unsigned int ret_size
;
396 as_warn (_("unknown type %d"), type
);
400 if (*size
< ret_size
)
402 as_bad (_("output_data buffer is too small"));
411 printf ("\t.byte\t0x%x\n", (unsigned char) *ptr
);
414 *(short *) ptr
= (short) value
& 0xFFFF;
416 printf ("\t.half\t0x%x\n", (unsigned short) *ptr
);
419 *(int *) ptr
= (int) value
& 0xFFFFFFFF;
421 printf ("\t.long\t0x%x\n", (unsigned int) *ptr
);
424 *(long long *) ptr
= (long long) value
& 0xFFFFFFFF;
426 printf ("\t.quad\t0x%x\n", (unsigned int) *ptr
);
430 ret_size
= output_leb128 (ptr
, value
, type
== t_sleb128
);
432 printf ("\t.%s\t0x%lx\n",
433 type
== t_sleb128
? "sleb128" : "uleb128",
437 as_warn ("unknown type %d", type
);
448 cfi_output_insn (struct cfi_data
*data
, char **buf
, unsigned long *buf_size
)
450 char **pbuf
= buf
, *orig_buf
= *buf
;
454 as_fatal (_("cfi_output_insn called with NULL pointer"));
458 case CFA_advance_loc
:
460 printf ("\t# %s(%ld)\n", cfi_insn_str (data
->insn
),
462 if (data
->param
[0] <= 0x3F)
464 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc
+
465 (data
->param
[0] / current_config
.code_align
));
467 else if (data
->param
[0] <= 0xFF)
469 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc1
);
470 output_data (pbuf
, buf_size
, t_byte
,
471 data
->param
[0] / current_config
.code_align
);
473 else if (data
->param
[0] <= 0xFFFF)
475 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc2
);
476 output_data (pbuf
, buf_size
, t_half
,
477 data
->param
[0] / current_config
.code_align
);
481 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc4
);
482 output_data (pbuf
, buf_size
, t_long
,
483 data
->param
[0] / current_config
.code_align
);
489 printf ("\t# CFA_def_cfa(%ld,%ld)\n", data
->param
[0], data
->param
[1]);
490 output_data (pbuf
, buf_size
, t_byte
, CFA_def_cfa
);
491 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
492 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[1]);
495 case CFA_def_cfa_register
:
496 case CFA_def_cfa_offset
:
498 printf ("\t# %s(%ld)\n", cfi_insn_str (data
->insn
),
500 output_data (pbuf
, buf_size
, t_byte
, data
->insn
);
501 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
506 printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data
->insn
),
507 data
->param
[0], data
->param
[1]);
509 /* Check whether to use CFA_offset or CFA_offset_extended. */
510 if (data
->param
[0] <= 0x3F)
511 output_data (pbuf
, buf_size
, t_byte
, CFA_offset
+ data
->param
[0]);
514 output_data (pbuf
, buf_size
, t_byte
, CFA_offset_extended
);
515 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
517 output_data (pbuf
, buf_size
, t_uleb128
,
518 data
->param
[1] / current_config
.data_align
);
523 printf ("\t# CFA_nop\n");
524 output_data (pbuf
, buf_size
, t_byte
, CFA_nop
);
528 as_warn ("CFA_unknown[%d](%ld,%ld)", data
->insn
,
529 data
->param
[0], data
->param
[1]);
531 size
= *pbuf
- orig_buf
;
538 dot_cfi_endproc (void)
540 struct cfi_data
*data_ptr
;
541 char *cie_buf
, *fde_buf
, *pbuf
, *where
;
542 unsigned long buf_size
, cie_size
, fde_size
, last_cie_offset
;
543 unsigned long fde_initloc_offset
, fde_len_offset
;
544 void *saved_seg
, *cfi_seg
;
549 as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
552 cfi_info
->end_address
= frag_now_fix ();
554 /* Open .eh_frame section. */
556 cfi_seg
= subseg_new (".eh_frame", 0);
557 bfd_set_section_flags (stdoutput
, cfi_seg
,
558 SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
| SEC_DATA
);
559 subseg_set (cfi_seg
, 0);
562 cie_buf
= xcalloc (1024, 1);
563 /* Skip space for CIE length. */
568 printf ("# CIE *****\n");
571 output_data (&pbuf
, &buf_size
, t_long
, 0x0);
573 output_data (&pbuf
, &buf_size
, t_byte
, 1);
575 output_data (&pbuf
, &buf_size
, t_byte
, 0);
576 /* Code alignment. */
577 output_data (&pbuf
, &buf_size
, t_uleb128
, current_config
.code_align
);
578 /* Data alignment. */
579 output_data (&pbuf
, &buf_size
, t_sleb128
, current_config
.data_align
);
580 /* Return address column. */
581 output_data (&pbuf
, &buf_size
, t_byte
, current_config
.ra_column
);
583 /* Build CFI instructions. */
584 data_ptr
= cfi_info
->data
;
585 while (data_ptr
&& !cfi_is_advance_insn (data_ptr
->insn
))
587 cfi_output_insn (data_ptr
, &pbuf
, &buf_size
);
588 data_ptr
= data_ptr
->next
;
591 /* Align the whole data to current_config.eh_align. */
592 cie_size
= pbuf
- cie_buf
;
593 cie_size
+= current_config
.eh_align
- cie_size
% current_config
.eh_align
;
597 output_data (&pbuf
, &buf_size
, t_long
, cie_size
- 4);
599 /* OK, we built the CIE. Let's write it to the file... */
600 last_cie_offset
= frag_now_fix ();
601 where
= (unsigned char *) frag_more (cie_size
);
602 memcpy (where
, cie_buf
, cie_size
);
607 /* Build the FDE... */
608 fde_buf
= xcalloc (1024, 1);
614 printf ("# FDE: start=0x%lx, end=0x%lx, delta=%d\n",
615 (long) cfi_info
->start_address
,
616 (long) cfi_info
->end_address
,
617 (int) (cfi_info
->end_address
- cfi_info
->start_address
));
620 /* FDE length (t_long, 4 bytes) - will be set later. */
621 fde_len_offset
= pbuf
- fde_buf
;
625 /* CIE pointer - offset from here. */
626 output_data (&pbuf
, &buf_size
, t_long
, cie_size
+ 4);
628 /* FDE initial location - this must be set relocatable! */
629 fde_initloc_offset
= pbuf
- fde_buf
;
630 output_data (&pbuf
, &buf_size
, current_config
.addr_length
,
631 cfi_info
->start_address
);
633 /* FDE address range. */
634 output_data (&pbuf
, &buf_size
, current_config
.addr_length
,
635 cfi_info
->end_address
- cfi_info
->start_address
);
639 cfi_output_insn (data_ptr
, &pbuf
, &buf_size
);
640 data_ptr
= data_ptr
->next
;
643 fde_size
= pbuf
- fde_buf
;
644 fde_size
+= current_config
.eh_align
- fde_size
% current_config
.eh_align
;
646 /* Now we can set FDE length. */
647 pbuf
= fde_buf
+ fde_len_offset
;
649 output_data (&pbuf
, &buf_size
, t_long
, fde_size
- 4);
651 /* Adjust initloc offset. */
652 fde_initloc_offset
+= frag_now_fix ();
654 /* Copy FDE to objfile. */
655 where
= (unsigned char *) frag_more (fde_size
);
656 memcpy (where
, fde_buf
, fde_size
);
658 /* Set relocation for initial address. */
659 buf_size
= current_config
.addr_length
;
660 memset (&exp
, 0, sizeof (exp
));
662 exp
.X_add_symbol
= symbol_find (cfi_info
->labelname
);
663 fix_new_exp (frag_now
, fde_initloc_offset
,
664 current_config
.addr_length
,
665 &exp
, 0, current_config
.reloc_type
);
673 /* Restore previous segment. */
674 subseg_set (saved_seg
, 0);
685 dot_cfi_startproc ();
691 case CFA_def_cfa_register
:
692 case CFA_def_cfa_offset
:
694 case CFI_adjust_cfa_offset
:
698 if (cfi_parse_const (¶m
) >= 0)
699 verbose
= (int) param
;
704 as_bad (_("unknown CFI code 0x%x (%s)"), arg
, cfi_insn_str (arg
));
707 ignore_rest_of_line ();
711 cfi_set_config (struct cfi_config
*cfg
)
713 assert (cfg
!= NULL
);
714 assert (cfg
->addr_length
> 0);
716 current_config
= *cfg
;
723 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));