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"
31 struct cie_entry
*next
;
38 struct cfi_data
*next
;
43 addressT start_address
;
45 addressT last_address
;
46 const char *labelname
;
47 struct cfi_data
*data
;
48 struct cfi_info
*next
;
51 /* Current open CFI entry. */
52 static struct cfi_info
*cfi_info
;
54 /* List of CIEs so that they could be reused. */
55 static struct cie_entry
*cie_root
;
57 /* Current target config. */
58 static struct cfi_config current_config
;
60 /* This is the main entry point to the CFI machinery. */
61 static void dot_cfi (int arg
);
63 const pseudo_typeS cfi_pseudo_table
[] =
65 { "cfi_verbose", dot_cfi
, CFI_verbose
},
66 { "cfi_startproc", dot_cfi
, CFI_startproc
},
67 { "cfi_endproc", dot_cfi
, CFI_endproc
},
68 { "cfi_def_cfa", dot_cfi
, CFA_def_cfa
},
69 { "cfi_def_cfa_register", dot_cfi
, CFA_def_cfa_register
},
70 { "cfi_def_cfa_offset", dot_cfi
, CFA_def_cfa_offset
},
71 { "cfi_adjust_cfa_offset", dot_cfi
, CFI_adjust_cfa_offset
},
72 { "cfi_offset", dot_cfi
, CFA_offset
},
73 { "cfi_register", dot_cfi
, CFA_register
},
78 cfi_insn_str (enum cfi_insn insn
)
86 case CFA_advance_loc1
:
87 return "CFA_advance_loc1";
88 case CFA_advance_loc2
:
89 return "CFA_advance_loc2";
90 case CFA_advance_loc4
:
91 return "CFA_advance_loc4";
92 case CFA_offset_extended
:
93 return "CFA_offset_extended";
94 case CFA_resotre_extended
:
95 return "CFA_resotre_extended";
97 return "CFA_undefined";
99 return "CFA_same_value";
101 return "CFA_register";
102 case CFA_remember_state
:
103 return "CFA_remember_state";
104 case CFA_restore_state
:
105 return "CFA_restore_state";
107 return "CFA_def_cfa";
108 case CFA_def_cfa_register
:
109 return "CFA_def_cfa_register";
110 case CFA_def_cfa_offset
:
111 return "CFA_def_cfa_offset";
112 case CFA_advance_loc
:
113 return "CFA_advance_loc";
117 return "CFA_restore";
122 return "CFA_unknown";
125 static struct cfi_data
*
126 alloc_cfi_data (void)
128 return (struct cfi_data
*) xcalloc (sizeof (struct cfi_info
), 1);
131 static struct cfi_info
*
132 alloc_cfi_info (void)
134 return (struct cfi_info
*) xcalloc (sizeof (struct cfi_info
), 1);
137 /* Parse arguments. */
139 cfi_parse_arg (long *param
, int resolvereg
)
145 assert (param
!= NULL
);
148 if (sscanf (input_line_pointer
, "%li%n", &value
, &nchars
) >= 1)
150 input_line_pointer
+= nchars
;
153 #ifdef tc_regname_to_dw2regnum
154 else if (resolvereg
&& ((is_name_beginner (*input_line_pointer
))
155 || (*input_line_pointer
== '%'
156 && is_name_beginner (*(++input_line_pointer
)))))
160 name
= input_line_pointer
;
161 c
= get_symbol_end ();
162 p
= input_line_pointer
;
164 if ((value
= tc_regname_to_dw2regnum (name
)) >= 0)
172 _("can't convert argument to a register number") :
173 _("can't convert argument to an integer"));
179 if (*input_line_pointer
== ',')
181 input_line_pointer
++;
189 cfi_parse_reg (long *param
)
191 return cfi_parse_arg (param
, 1);
195 cfi_parse_const (long *param
)
197 return cfi_parse_arg (param
, 0);
201 cfi_add_insn (enum cfi_insn insn
, long param0
, long param1
)
203 struct cfi_data
*data_ptr
;
207 cfi_info
->data
= alloc_cfi_data ();
208 data_ptr
= cfi_info
->data
;
212 data_ptr
= cfi_info
->data
;
214 while (data_ptr
&& data_ptr
->next
)
215 data_ptr
= data_ptr
->next
;
217 data_ptr
->next
= alloc_cfi_data ();
219 data_ptr
= data_ptr
->next
;
222 data_ptr
->insn
= insn
;
223 data_ptr
->param
[0] = param0
;
224 data_ptr
->param
[1] = param1
;
228 cfi_advance_loc (void)
230 addressT curr_address
= frag_now_fix ();
231 if (cfi_info
->last_address
== curr_address
)
233 cfi_add_insn (CFA_advance_loc
,
234 (long) (curr_address
- cfi_info
->last_address
), 0);
235 cfi_info
->last_address
= curr_address
;
239 get_current_offset (struct cfi_info
*info
)
241 long current_offset
= 0;
242 struct cfi_data
*data
= info
->data
;
247 if (data
->insn
== CFA_def_cfa
)
248 current_offset
= data
->param
[1];
249 else if (data
->insn
== CFA_def_cfa_offset
)
250 current_offset
= data
->param
[0];
254 return current_offset
;
258 cfi_make_insn (int arg
)
260 long param
[2] = { 0, 0 };
264 as_bad (_("CFI instruction used without previous .cfi_startproc"));
272 /* Instructions that take two arguments (register, integer). */
275 if (cfi_parse_reg (¶m
[0]) < 0)
277 as_bad (_("first argument to %s is not a register"),
281 if (cfi_parse_const (¶m
[1]) < 0)
283 as_bad (_("second argument to %s is not a number"),
290 if (cfi_parse_reg (¶m
[0]) < 0)
292 as_bad (_("first argument to %s is not a register"),
296 if (cfi_parse_reg (¶m
[1]) < 0)
298 as_bad (_("second argument to %s is not a register"),
304 /* Instructions that take one register argument. */
305 case CFA_def_cfa_register
:
306 if (cfi_parse_reg (¶m
[0]) < 0)
308 as_bad (_("argument to %s is not a register"), cfi_insn_str (arg
));
313 /* Instructions that take one integer argument. */
314 case CFA_def_cfa_offset
:
315 if (cfi_parse_const (¶m
[0]) < 0)
317 as_bad (_("argument to %s is not a number"), cfi_insn_str (arg
));
322 /* Special handling for pseudo-instruction. */
323 case CFI_adjust_cfa_offset
:
324 if (cfi_parse_const (¶m
[0]) < 0)
326 as_bad (_("argument to %s is not a number"),
327 ".cfi_adjust_cfa_offset");
330 param
[0] += get_current_offset (cfi_info
);
331 arg
= CFA_def_cfa_offset
;
335 as_bad (_("unknown CFI instruction %d (%s)"), arg
, cfi_insn_str (arg
));
338 cfi_add_insn (arg
, param
[0], param
[1]);
344 char symname
[40], *symbase
=".Llbl_cfi";
348 snprintf (symname
, sizeof (symname
), "%s_0x%lx",
349 symbase
, (long) frag_now_fix ());
350 while ((symbolP
= symbol_find (symname
)))
352 if ((S_GET_VALUE (symbolP
) == frag_now_fix ())
353 && (S_GET_SEGMENT (symbolP
) == now_seg
))
357 snprintf (symname
, sizeof (symname
), "%s_0x%lx_%u",
358 symbase
, (long) frag_now_fix (), i
++);
360 symbolP
= (symbolS
*) local_symbol_make (symname
, now_seg
,
361 (valueT
) frag_now_fix (),
367 dot_cfi_startproc (void)
369 const char *simple
= "simple";
373 as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
377 #if defined(TARGET_USE_CFIPOP)
378 /* Because this file is linked even for architectures that
379 don't use CFI, we must wrap this call. */
380 if (current_config
.addr_length
== 0)
384 cfi_info
= alloc_cfi_info ();
386 cfi_info
->start_address
= frag_now_fix ();
387 cfi_info
->last_address
= cfi_info
->start_address
;
388 cfi_info
->labelname
= S_GET_NAME (cfi_get_label ());
391 #ifdef tc_cfi_frame_initial_instructions
392 if (strncmp (simple
, input_line_pointer
, strlen (simple
)) != 0)
393 tc_cfi_frame_initial_instructions ();
395 input_line_pointer
+= strlen (simple
);
399 #define cfi_is_advance_insn(insn) \
400 ((insn >= CFA_set_loc && insn <= CFA_advance_loc4) \
401 || insn == CFA_advance_loc)
403 /* Output CFI instructions to the file. */
417 output_data (char **p
, unsigned long *size
, enum data_types type
, long value
)
420 unsigned int ret_size
;
439 /* This should never happen - throw an internal error. */
440 as_fatal (_("unknown type %d"), type
);
444 if (*size
< ret_size
)
446 as_bad (_("output_data buffer is too small"));
455 printf ("\t.byte\t0x%x\n", (unsigned char) *ptr
);
458 *(short *) ptr
= (short) value
& 0xFFFF;
460 printf ("\t.half\t0x%x\n", (unsigned short) *ptr
);
463 *(int *) ptr
= (int) value
& 0xFFFFFFFF;
465 printf ("\t.long\t0x%x\n", (unsigned int) *ptr
);
468 *(long long *) ptr
= (long long) value
& 0xFFFFFFFF;
470 printf ("\t.quad\t0x%x\n", (unsigned int) *ptr
);
474 ret_size
= output_leb128 (ptr
, value
, type
== t_sleb128
);
476 printf ("\t.%s\t0x%lx\n",
477 type
== t_sleb128
? "sleb128" : "uleb128",
481 as_fatal (_("unknown type %d"), type
);
492 cfi_output_insn (struct cfi_data
*data
, char **buf
, unsigned long *buf_size
)
494 char **pbuf
= buf
, *orig_buf
= *buf
;
498 as_fatal (_("cfi_output_insn called with NULL pointer"));
502 case CFA_advance_loc
:
504 printf ("\t# %s(%ld)\n", cfi_insn_str (data
->insn
),
506 if (data
->param
[0] <= 0x3F)
508 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc
+
509 (data
->param
[0] / current_config
.code_align
));
511 else if (data
->param
[0] <= 0xFF)
513 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc1
);
514 output_data (pbuf
, buf_size
, t_byte
,
515 data
->param
[0] / current_config
.code_align
);
517 else if (data
->param
[0] <= 0xFFFF)
519 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc2
);
520 output_data (pbuf
, buf_size
, t_half
,
521 data
->param
[0] / current_config
.code_align
);
525 output_data (pbuf
, buf_size
, t_byte
, CFA_advance_loc4
);
526 output_data (pbuf
, buf_size
, t_long
,
527 data
->param
[0] / current_config
.code_align
);
533 printf ("\t# CFA_def_cfa(%ld,%ld)\n",
534 data
->param
[0], data
->param
[1]);
535 output_data (pbuf
, buf_size
, t_byte
, CFA_def_cfa
);
536 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
537 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[1]);
540 case CFA_def_cfa_register
:
541 case CFA_def_cfa_offset
:
543 printf ("\t# %s(%ld)\n", cfi_insn_str (data
->insn
),
545 output_data (pbuf
, buf_size
, t_byte
, data
->insn
);
546 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
551 printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data
->insn
),
552 data
->param
[0], data
->param
[1]);
554 /* Check whether to use CFA_offset or CFA_offset_extended. */
555 if (data
->param
[0] <= 0x3F)
556 output_data (pbuf
, buf_size
, t_byte
, CFA_offset
+ data
->param
[0]);
559 output_data (pbuf
, buf_size
, t_byte
, CFA_offset_extended
);
560 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
562 output_data (pbuf
, buf_size
, t_uleb128
,
563 data
->param
[1] / current_config
.data_align
);
568 printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data
->insn
),
569 data
->param
[0], data
->param
[1]);
570 output_data (pbuf
, buf_size
, t_byte
, CFA_register
);
571 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[0]);
572 output_data (pbuf
, buf_size
, t_uleb128
, data
->param
[1]);
577 printf ("\t# CFA_nop\n");
578 output_data (pbuf
, buf_size
, t_byte
, CFA_nop
);
582 as_warn ("CFA_unknown[%d](%ld,%ld)", data
->insn
,
583 data
->param
[0], data
->param
[1]);
585 size
= *pbuf
- orig_buf
;
592 dot_cfi_endproc (void)
594 struct cfi_data
*data_ptr
;
595 struct cie_entry
*cie_ptr
;
596 char *cie_buf
, *fde_buf
, *pbuf
, *where
;
597 unsigned long buf_size
, cie_size
, fde_size
, last_cie_offset
;
598 unsigned long fde_initloc_offset
, fde_len_offset
, fde_offset
;
599 void *saved_seg
, *cfi_seg
;
604 as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
607 cfi_info
->end_address
= frag_now_fix ();
609 /* Open .eh_frame section. */
611 cfi_seg
= subseg_new (".eh_frame", 0);
612 bfd_set_section_flags (stdoutput
, cfi_seg
,
613 SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
| SEC_DATA
);
614 subseg_set (cfi_seg
, 0);
617 cie_buf
= xcalloc (1024, 1);
618 /* Skip space for CIE length. */
623 printf ("# CIE *****\n");
626 output_data (&pbuf
, &buf_size
, t_long
, 0x0);
628 output_data (&pbuf
, &buf_size
, t_byte
, 1);
630 output_data (&pbuf
, &buf_size
, t_byte
, 0);
631 /* Code alignment. */
632 output_data (&pbuf
, &buf_size
, t_uleb128
, current_config
.code_align
);
633 /* Data alignment. */
634 output_data (&pbuf
, &buf_size
, t_sleb128
, current_config
.data_align
);
635 /* Return address column. */
636 output_data (&pbuf
, &buf_size
, t_byte
, current_config
.ra_column
);
638 /* Build CFI instructions. */
639 data_ptr
= cfi_info
->data
;
640 while (data_ptr
&& !cfi_is_advance_insn (data_ptr
->insn
))
642 cfi_output_insn (data_ptr
, &pbuf
, &buf_size
);
643 data_ptr
= data_ptr
->next
;
646 /* Align the whole data to current_config.eh_align. */
647 cie_size
= pbuf
- cie_buf
;
648 cie_size
+= current_config
.eh_align
- cie_size
% current_config
.eh_align
;
652 output_data (&pbuf
, &buf_size
, t_long
, cie_size
- 4);
654 /* OK, we built the CIE. Let's write it to the file... */
655 last_cie_offset
= frag_now_fix ();
657 /* Check if we have already emitted the exactly same CIE.
658 If yes then use its offset instead and don't put out
663 if (cie_ptr
->size
== cie_size
- 4
664 && memcmp (cie_ptr
->data
, cie_buf
+ 4, cie_ptr
->size
) == 0)
666 cie_ptr
= cie_ptr
->next
;
669 /* If we have found the same CIE, use it... */
673 printf ("# Duplicate CIE found. Previous is at offset %lu\n",
675 last_cie_offset
= cie_ptr
->offset
;
679 /* Otherwise join this CIE to the list. */
680 where
= (unsigned char *) frag_more (cie_size
);
681 memcpy (where
, cie_buf
, cie_size
);
685 while (cie_ptr
->next
)
686 cie_ptr
= cie_ptr
->next
;
687 cie_ptr
->next
= calloc (sizeof (struct cie_entry
), 1);
688 cie_ptr
= cie_ptr
->next
;
692 cie_root
= calloc (sizeof (struct cie_entry
), 1);
696 cie_ptr
->size
= cie_size
- 4;
697 cie_ptr
->data
= calloc (cie_ptr
->size
, 1);
698 cie_ptr
->offset
= last_cie_offset
;
699 memcpy (cie_ptr
->data
, cie_buf
+ 4, cie_ptr
->size
);
705 /* Build the FDE... */
706 fde_buf
= xcalloc (1024, 1);
710 /* Offset of this FDE in current fragment. */
711 fde_offset
= frag_now_fix ();
715 printf ("# FDE: start=0x%lx, end=0x%lx, delta=%d\n",
716 (long) cfi_info
->start_address
,
717 (long) cfi_info
->end_address
,
718 (int) (cfi_info
->end_address
- cfi_info
->start_address
));
721 /* FDE length (t_long, 4 bytes) - will be set later. */
722 fde_len_offset
= pbuf
- fde_buf
;
726 /* CIE pointer - offset from here. */
727 output_data (&pbuf
, &buf_size
, t_long
, fde_offset
- last_cie_offset
+ 4);
729 /* FDE initial location - this must be set relocatable! */
730 fde_initloc_offset
= pbuf
- fde_buf
+ fde_offset
;
731 output_data (&pbuf
, &buf_size
, current_config
.addr_length
,
732 cfi_info
->start_address
);
734 /* FDE address range. */
735 output_data (&pbuf
, &buf_size
, current_config
.addr_length
,
736 cfi_info
->end_address
- cfi_info
->start_address
);
740 cfi_output_insn (data_ptr
, &pbuf
, &buf_size
);
741 data_ptr
= data_ptr
->next
;
744 fde_size
= pbuf
- fde_buf
;
745 fde_size
+= current_config
.eh_align
- fde_size
% current_config
.eh_align
;
747 /* Now we can set FDE length. */
748 pbuf
= fde_buf
+ fde_len_offset
;
750 output_data (&pbuf
, &buf_size
, t_long
, fde_size
- 4);
752 /* Copy FDE to objfile. */
753 where
= (unsigned char *) frag_more (fde_size
);
754 memcpy (where
, fde_buf
, fde_size
);
756 /* Set relocation for initial address. */
757 buf_size
= current_config
.addr_length
;
758 memset (&exp
, 0, sizeof (exp
));
760 exp
.X_add_symbol
= symbol_find (cfi_info
->labelname
);
761 fix_new_exp (frag_now
, fde_initloc_offset
,
762 current_config
.addr_length
,
763 &exp
, 0, current_config
.reloc_type
);
771 /* Restore previous segment. */
772 subseg_set (saved_seg
, 0);
783 dot_cfi_startproc ();
789 case CFA_def_cfa_register
:
790 case CFA_def_cfa_offset
:
793 case CFI_adjust_cfa_offset
:
797 if (cfi_parse_const (¶m
) >= 0)
798 verbose
= (int) param
;
803 as_bad (_("unknown CFI code 0x%x (%s)"), arg
, cfi_insn_str (arg
));
806 ignore_rest_of_line ();
810 cfi_set_config (struct cfi_config
*cfg
)
812 assert (cfg
!= NULL
);
813 assert (cfg
->addr_length
> 0);
815 current_config
= *cfg
;
822 as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));