* dw2gencfi.c (cfi_parse_arg): Only use tc_regname_to_dw2regnum if
[external/binutils.git] / gas / dw2gencfi.c
1 /* dw2gencfi.c - Support for generating Dwarf2 CFI information.
2    Copyright 2003 Free Software Foundation, Inc.
3    Contributed by Michal Ludvig <mludvig@suse.cz>
4
5    This file is part of GAS, the GNU Assembler.
6
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)
10    any later version.
11
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.
16
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
20    02111-1307, USA.  */
21
22 #include <errno.h>
23 #include "as.h"
24 #include "dw2gencfi.h"
25
26 /* Current target config.  */
27 static struct cfi_config current_config;
28
29 /* This is the main entry point to the CFI machinery.  */
30 static void dot_cfi (int arg);
31
32 const pseudo_typeS cfi_pseudo_table[] =
33   {
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 },
42     { NULL, NULL, 0 }
43   };
44
45 static const char *
46 cfi_insn_str (enum cfi_insn insn)
47 {
48   switch (insn)
49     {
50     case CFA_nop:
51       return "CFA_nop";
52     case CFA_set_loc:
53       return "CFA_set_loc";
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";
64     case CFA_undefined:
65       return "CFA_undefined";
66     case CFA_same_value:
67       return "CFA_same_value";
68     case CFA_register:
69       return "CFA_register";
70     case CFA_remember_state:
71       return "CFA_remember_state";
72     case CFA_restore_state:
73       return "CFA_restore_state";
74     case CFA_def_cfa:
75       return "CFA_def_cfa";
76     case CFA_def_cfa_register:
77       return "CFA_def_cfa_register";
78     case CFA_def_cfa_offset:
79       return "CFA_def_cfa_offset";
80     case CFA_advance_loc:
81       return "CFA_advance_loc";
82     case CFA_offset:
83       return "CFA_offset";
84     case CFA_restore:
85       return "CFA_restore";
86     default:
87       break;
88     }
89
90   return "CFA_unknown";
91 }
92
93 struct cfi_data
94 {
95   enum cfi_insn insn;
96   long param[2];
97   struct cfi_data *next;
98 };
99
100 struct cfi_info
101 {
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;
108 };
109
110 static struct cfi_info *cfi_info;
111
112 static struct cfi_data *
113 alloc_cfi_data (void)
114 {
115   return (struct cfi_data *) xcalloc (sizeof (struct cfi_info), 1);
116 }
117
118 static struct cfi_info *
119 alloc_cfi_info (void)
120 {
121   return (struct cfi_info *) xcalloc (sizeof (struct cfi_info), 1);
122 }
123
124 /* Parse arguments.  */
125 static int
126 cfi_parse_arg (long *param, int resolvereg)
127 {
128   long value;
129   int retval = -1;
130   int nchars;
131
132   assert (param != NULL);
133   SKIP_WHITESPACE ();
134
135   if (sscanf (input_line_pointer, "%li%n", &value, &nchars) >= 1)
136     {
137       input_line_pointer += nchars;
138       retval = 1;
139     }
140 #ifdef tc_regname_to_dw2regnum
141   else if (resolvereg && (is_name_beginner (*input_line_pointer)))
142     {
143       char *name, c, *p;
144
145       name = input_line_pointer;
146       c = get_symbol_end ();
147       p = input_line_pointer;
148
149       if ((value = tc_regname_to_dw2regnum (name)) >= 0)
150         retval = 1;
151
152       *p = c;
153     }
154 #endif
155   else
156     as_bad (resolvereg ?
157             _("can't convert argument to a register number") :
158             _("can't convert argument to an integer"));
159
160   if (retval > 0)
161     *param = value;
162
163   SKIP_WHITESPACE ();
164   if (*input_line_pointer == ',')
165     {
166       input_line_pointer++;
167       SKIP_WHITESPACE ();
168     }
169
170   return retval;
171 }
172
173 static int
174 cfi_parse_reg (long *param)
175 {
176   return cfi_parse_arg (param, 1);
177 }
178
179 static int
180 cfi_parse_const (long *param)
181 {
182   return cfi_parse_arg (param, 0);
183 }
184
185 void
186 cfi_add_insn (enum cfi_insn insn, long param0, long param1)
187 {
188   struct cfi_data *data_ptr;
189
190   if (!cfi_info->data)
191     {
192       cfi_info->data = alloc_cfi_data ();
193       data_ptr = cfi_info->data;
194     }
195   else
196     {
197       data_ptr = cfi_info->data;
198
199       while (data_ptr && data_ptr->next)
200         data_ptr = data_ptr->next;
201
202       data_ptr->next = alloc_cfi_data ();
203
204       data_ptr = data_ptr->next;
205     }
206
207   data_ptr->insn = insn;
208   data_ptr->param[0] = param0;
209   data_ptr->param[1] = param1;
210 }
211
212 static void
213 cfi_advance_loc (void)
214 {
215   addressT curr_address = frag_now_fix ();
216   if (cfi_info->last_address == curr_address)
217     return;
218   cfi_add_insn (CFA_advance_loc,
219                 (long) (curr_address - cfi_info->last_address), 0);
220   cfi_info->last_address = curr_address;
221 }
222
223 static long
224 get_current_offset (struct cfi_info *info)
225 {
226   long current_offset = 0;
227   struct cfi_data *data = info->data;
228
229   current_offset = 0;
230   while (data)
231     {
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];
236       data = data->next;
237     }
238
239   return current_offset;
240 }
241
242 static void
243 cfi_make_insn (int arg)
244 {
245   long param[2] = { 0, 0 };
246
247   if (!cfi_info)
248     {
249       as_bad (_("CFI instruction used without previous .cfi_startproc"));
250       return;
251     }
252
253   cfi_advance_loc ();
254
255   switch (arg)
256     {
257       /* Instructions that take two arguments (register, integer). */
258     case CFA_offset:
259     case CFA_def_cfa:
260       if (cfi_parse_reg (&param[0]) < 0)
261         {
262           as_bad (_("first argument to %s is not a register"),
263                   cfi_insn_str (arg));
264           return;
265         }
266       if (cfi_parse_const (&param[1]) < 0)
267         {
268           as_bad (_("second argument to %s is not a number"),
269                   cfi_insn_str (arg));
270           return;
271         }
272       break;
273
274       /* Instructions that take one register argument.  */
275     case CFA_def_cfa_register:
276       if (cfi_parse_reg (&param[0]) < 0)
277         {
278           as_bad (_("argument to %s is not a register"), cfi_insn_str (arg));
279           return;
280         }
281       break;
282
283       /* Instructions that take one integer argument.  */
284     case CFA_def_cfa_offset:
285       if (cfi_parse_const (&param[0]) < 0)
286         {
287           as_bad (_("argument to %s is not a number"), cfi_insn_str (arg));
288           return;
289         }
290       break;
291
292       /* Special handling for pseudo-instruction.  */
293     case CFI_adjust_cfa_offset:
294       if (cfi_parse_const (&param[0]) < 0)
295         {
296           as_bad (_("argument to %s is not a number"),
297                     ".cfi_adjust_cfa_offset");
298           return;
299         }
300       param[0] += get_current_offset (cfi_info);
301       arg = CFA_def_cfa_offset;
302       break;
303
304     default:
305       as_bad (_("unknown CFI instruction %d (%s)"), arg, cfi_insn_str (arg));
306       return;
307     }
308   cfi_add_insn (arg, param[0], param[1]);
309 }
310
311 static symbolS *
312 cfi_get_label (void)
313 {
314   char symname[40], *symbase=".Llbl_cfi";
315   symbolS *symbolP;
316   unsigned int i = 0;
317
318   snprintf (symname, sizeof (symname), "%s_0x%lx",
319             symbase, (long) frag_now_fix ());
320   while ((symbolP = symbol_find (symname)))
321     {
322       if ((S_GET_VALUE (symbolP) == frag_now_fix ())
323           && (S_GET_SEGMENT (symbolP) == now_seg))
324         {
325           return symbolP;
326         }
327       snprintf (symname, sizeof (symname), "%s_0x%lx_%u",
328                 symbase, (long) frag_now_fix (), i++);
329     }
330   symbolP = (symbolS *) local_symbol_make (symname, now_seg,
331                                            (valueT) frag_now_fix (),
332                                            frag_now);
333   return symbolP;
334 }
335
336 static void
337 dot_cfi_startproc (void)
338 {
339   if (cfi_info)
340     {
341       as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
342       return;
343     }
344
345   cfi_info = alloc_cfi_info ();
346
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 ());
350
351 #ifdef tc_cfi_frame_initial_instructions
352   tc_cfi_frame_initial_instructions ();
353 #endif
354 }
355
356 #define cfi_is_advance_insn(insn)                               \
357   ((insn >= CFA_set_loc && insn <= CFA_advance_loc4)            \
358    || insn == CFA_advance_loc)
359
360 enum data_types
361   {
362     t_ascii = 0,
363     t_byte = 1,
364     t_half = 2,
365     t_long = 4,
366     t_quad = 8,
367     t_uleb128 = 0x10,
368     t_sleb128 = 0x11
369   };
370
371 /* Output CFI instructions to the file.  */
372
373 static int
374 output_data (char **p, unsigned long *size, enum data_types type, long value)
375 {
376   char *ptr = *p;
377   unsigned int ret_size;
378
379   switch (type)
380     {
381     case t_byte:
382       ret_size = 1;
383       break;
384     case t_half:
385       ret_size = 2;
386       break;
387     case t_long:
388       ret_size = 4;
389       break;
390     case t_quad:
391     case t_uleb128:
392     case t_sleb128:
393       ret_size = 8;
394       break;
395     default:
396       as_warn (_("unknown type %d"), type);
397       return 0;
398     }
399
400   if (*size < ret_size)
401     {
402       as_bad (_("output_data buffer is too small"));
403       return 0;
404     }
405
406   switch (type)
407     {
408     case t_byte:
409       *ptr = (char) value;
410       if (verbose)
411         printf ("\t.byte\t0x%x\n", (unsigned char) *ptr);
412       break;
413     case t_half:
414       *(short *) ptr = (short) value & 0xFFFF;
415       if (verbose)
416         printf ("\t.half\t0x%x\n", (unsigned short) *ptr);
417       break;
418     case t_long:
419       *(int *) ptr = (int) value & 0xFFFFFFFF;
420       if (verbose)
421         printf ("\t.long\t0x%x\n", (unsigned int) *ptr);
422       break;
423     case t_quad:
424       *(long long *) ptr = (long long) value & 0xFFFFFFFF;
425       if (verbose)
426         printf ("\t.quad\t0x%x\n", (unsigned int) *ptr);
427       break;
428     case t_uleb128:
429     case t_sleb128:
430       ret_size = output_leb128 (ptr, value, type == t_sleb128);
431       if (verbose)
432         printf ("\t.%s\t0x%lx\n",
433                 type == t_sleb128 ? "sleb128" : "uleb128",
434                 value);
435       break;
436     default:
437       as_warn ("unknown type %d", type);
438       return 0;
439     }
440
441   *size -= ret_size;
442   *p += ret_size;
443
444   return ret_size;
445 }
446
447 static int
448 cfi_output_insn (struct cfi_data *data, char **buf, unsigned long *buf_size)
449 {
450   char **pbuf = buf, *orig_buf = *buf;
451   unsigned long size;
452
453   if (!data || !buf)
454     as_fatal (_("cfi_output_insn called with NULL pointer"));
455
456   switch (data->insn)
457     {
458     case CFA_advance_loc:
459       if (verbose)
460         printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
461                 data->param[0]);
462       if (data->param[0] <= 0x3F)
463         {
464           output_data (pbuf, buf_size, t_byte, CFA_advance_loc +
465                        (data->param[0] / current_config.code_align));
466         }
467       else if (data->param[0] <= 0xFF)
468         {
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);
472         }
473       else if (data->param[0] <= 0xFFFF)
474         {
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);
478         }
479       else
480         {
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);
484         }
485       break;
486
487     case CFA_def_cfa:
488       if (verbose)
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]);
493       break;
494
495     case CFA_def_cfa_register:
496     case CFA_def_cfa_offset:
497       if (verbose)
498         printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
499                 data->param[0]);
500       output_data (pbuf, buf_size, t_byte, data->insn);
501       output_data (pbuf, buf_size, t_uleb128, data->param[0]);
502       break;
503
504     case CFA_offset:
505       if (verbose)
506         printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data->insn),
507                 data->param[0], data->param[1]);
508
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]);
512       else
513         {
514           output_data (pbuf, buf_size, t_byte, CFA_offset_extended);
515           output_data (pbuf, buf_size, t_uleb128, data->param[0]);
516         }
517       output_data (pbuf, buf_size, t_uleb128,
518                    data->param[1] / current_config.data_align);
519       break;
520
521     case CFA_nop:
522       if (verbose)
523         printf ("\t# CFA_nop\n");
524       output_data (pbuf, buf_size, t_byte, CFA_nop);
525       break;
526
527     default:
528       as_warn ("CFA_unknown[%d](%ld,%ld)", data->insn,
529                data->param[0], data->param[1]);
530     }
531   size = *pbuf - orig_buf;
532   *buf = *pbuf;
533   *buf_size -= size;
534   return size;
535 }
536
537 static void
538 dot_cfi_endproc (void)
539 {
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;
545   expressionS exp;
546
547   if (! cfi_info)
548     {
549       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
550       return;
551     }
552   cfi_info->end_address = frag_now_fix ();
553
554   /* Open .eh_frame section.  */
555   saved_seg = now_seg;
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);
560
561   /* Build CIE.  */
562   cie_buf = xcalloc (1024, 1);
563   /* Skip space for CIE length.  */
564   pbuf = cie_buf + 4;
565   buf_size = 1020;
566
567   if (verbose)
568     printf ("# CIE *****\n");
569
570   /* CIE id.  */
571   output_data (&pbuf, &buf_size, t_long, 0x0);
572   /* Version.  */
573   output_data (&pbuf, &buf_size, t_byte, 1);
574   /* Augmentation.  */
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);
582
583   /* Build CFI instructions.  */
584   data_ptr = cfi_info->data;
585   while (data_ptr && !cfi_is_advance_insn (data_ptr->insn))
586     {
587       cfi_output_insn (data_ptr, &pbuf, &buf_size);
588       data_ptr = data_ptr->next;
589     }
590
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;
594
595   /* CIE length.  */
596   pbuf = cie_buf;
597   output_data (&pbuf, &buf_size, t_long, cie_size - 4);
598
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);
603
604   /* Clean up.  */
605   free (cie_buf);
606
607   /* Build the FDE...  */
608   fde_buf = xcalloc (1024, 1);
609   pbuf = fde_buf;
610   buf_size = 1024;
611
612   if (verbose)
613     {
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));
618     }
619
620   /* FDE length (t_long, 4 bytes) - will be set later.  */
621   fde_len_offset = pbuf - fde_buf;
622   pbuf += 4;
623   buf_size -= 4;
624
625   /* CIE pointer - offset from here.  */
626   output_data (&pbuf, &buf_size, t_long, cie_size + 4);
627
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);
632
633   /* FDE address range.  */
634   output_data (&pbuf, &buf_size, current_config.addr_length,
635                cfi_info->end_address - cfi_info->start_address);
636
637   while (data_ptr)
638     {
639       cfi_output_insn (data_ptr, &pbuf, &buf_size);
640       data_ptr = data_ptr->next;
641     }
642
643   fde_size = pbuf - fde_buf;
644   fde_size += current_config.eh_align - fde_size % current_config.eh_align;
645
646   /* Now we can set FDE length.  */
647   pbuf = fde_buf + fde_len_offset;
648   buf_size = 4;
649   output_data (&pbuf, &buf_size, t_long, fde_size - 4);
650
651   /* Adjust initloc offset.  */
652   fde_initloc_offset += frag_now_fix ();
653
654   /* Copy FDE to objfile.  */
655   where = (unsigned char *) frag_more (fde_size);
656   memcpy (where, fde_buf, fde_size);
657
658   /* Set relocation for initial address.  */
659   buf_size = current_config.addr_length;
660   memset (&exp, 0, sizeof (exp));
661   exp.X_op = O_symbol;
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);
666
667   /* Clean up.  */
668   free (fde_buf);
669
670   free (cfi_info);
671   cfi_info = NULL;
672
673   /* Restore previous segment.  */
674   subseg_set (saved_seg, 0);
675 }
676
677 void
678 dot_cfi (int arg)
679 {
680   long param;
681
682   switch (arg)
683     {
684     case CFI_startproc:
685       dot_cfi_startproc ();
686       break;
687     case CFI_endproc:
688       dot_cfi_endproc ();
689       break;
690     case CFA_def_cfa:
691     case CFA_def_cfa_register:
692     case CFA_def_cfa_offset:
693     case CFA_offset:
694     case CFI_adjust_cfa_offset:
695       cfi_make_insn (arg);
696       break;
697     case CFI_verbose:
698       if (cfi_parse_const (&param) >= 0)
699         verbose = (int) param;
700       else
701         verbose = 1;
702       break;
703     default:
704       as_bad (_("unknown CFI code 0x%x (%s)"), arg, cfi_insn_str (arg));
705       break;
706     }
707   ignore_rest_of_line ();
708 }
709
710 void
711 cfi_set_config (struct cfi_config *cfg)
712 {
713   assert (cfg != NULL);
714   assert (cfg->addr_length > 0);
715
716   current_config = *cfg;
717 }
718
719 void
720 cfi_finish (void)
721 {
722   if (cfi_info)
723     as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
724 }