Fix dw3gencfi.c so that it will build on targets that do not define BFD_ASSEMBLER.
[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 struct cie_entry
27 {
28   unsigned long offset;
29   size_t size;
30   void *data;
31   struct cie_entry *next;
32 };
33
34 struct cfi_data
35 {
36   enum cfi_insn insn;
37   long param[2];
38   struct cfi_data *next;
39 };
40
41 struct cfi_info
42 {
43   addressT start_address;
44   addressT end_address;
45   addressT last_address;
46   const char *labelname;
47   struct cfi_data *data;
48   struct cfi_info *next;
49 };
50
51 /* Current open CFI entry.  */
52 static struct cfi_info *cfi_info;
53
54 /* List of CIEs so that they could be reused.  */
55 static struct cie_entry *cie_root;
56
57 /* Current target config.  */
58 static struct cfi_config current_config;
59
60 /* This is the main entry point to the CFI machinery.  */
61 static void dot_cfi (int arg);
62
63 const pseudo_typeS cfi_pseudo_table[] =
64   {
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 },
74     { NULL, NULL, 0 }
75   };
76
77 static const char *
78 cfi_insn_str (enum cfi_insn insn)
79 {
80   switch (insn)
81     {
82     case CFA_nop:
83       return "CFA_nop";
84     case CFA_set_loc:
85       return "CFA_set_loc";
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";
96     case CFA_undefined:
97       return "CFA_undefined";
98     case CFA_same_value:
99       return "CFA_same_value";
100     case CFA_register:
101       return "CFA_register";
102     case CFA_remember_state:
103       return "CFA_remember_state";
104     case CFA_restore_state:
105       return "CFA_restore_state";
106     case CFA_def_cfa:
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";
114     case CFA_offset:
115       return "CFA_offset";
116     case CFA_restore:
117       return "CFA_restore";
118     default:
119       break;
120     }
121
122   return "CFA_unknown";
123 }
124
125 static struct cfi_data *
126 alloc_cfi_data (void)
127 {
128   return (struct cfi_data *) xcalloc (sizeof (struct cfi_info), 1);
129 }
130
131 static struct cfi_info *
132 alloc_cfi_info (void)
133 {
134   return (struct cfi_info *) xcalloc (sizeof (struct cfi_info), 1);
135 }
136
137 /* Parse arguments.  */
138 static int
139 cfi_parse_arg (long *param, int resolvereg)
140 {
141   long value;
142   int retval = -1;
143   int nchars;
144
145   assert (param != NULL);
146   SKIP_WHITESPACE ();
147
148   if (sscanf (input_line_pointer, "%li%n", &value, &nchars) >= 1)
149     {
150       input_line_pointer += nchars;
151       retval = 1;
152     }
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)))))
157     {
158       char *name, c, *p;
159
160       name = input_line_pointer;
161       c = get_symbol_end ();
162       p = input_line_pointer;
163
164       if ((value = tc_regname_to_dw2regnum (name)) >= 0)
165         retval = 1;
166
167       *p = c;
168     }
169 #endif
170   else
171     as_bad (resolvereg ?
172             _("can't convert argument to a register number") :
173             _("can't convert argument to an integer"));
174
175   if (retval > 0)
176     *param = value;
177
178   SKIP_WHITESPACE ();
179   if (*input_line_pointer == ',')
180     {
181       input_line_pointer++;
182       SKIP_WHITESPACE ();
183     }
184
185   return retval;
186 }
187
188 static int
189 cfi_parse_reg (long *param)
190 {
191   return cfi_parse_arg (param, 1);
192 }
193
194 static int
195 cfi_parse_const (long *param)
196 {
197   return cfi_parse_arg (param, 0);
198 }
199
200 void
201 cfi_add_insn (enum cfi_insn insn, long param0, long param1)
202 {
203   struct cfi_data *data_ptr;
204
205   if (!cfi_info->data)
206     {
207       cfi_info->data = alloc_cfi_data ();
208       data_ptr = cfi_info->data;
209     }
210   else
211     {
212       data_ptr = cfi_info->data;
213
214       while (data_ptr && data_ptr->next)
215         data_ptr = data_ptr->next;
216
217       data_ptr->next = alloc_cfi_data ();
218
219       data_ptr = data_ptr->next;
220     }
221
222   data_ptr->insn = insn;
223   data_ptr->param[0] = param0;
224   data_ptr->param[1] = param1;
225 }
226
227 static void
228 cfi_advance_loc (void)
229 {
230   addressT curr_address = frag_now_fix ();
231   if (cfi_info->last_address == curr_address)
232     return;
233   cfi_add_insn (CFA_advance_loc,
234                 (long) (curr_address - cfi_info->last_address), 0);
235   cfi_info->last_address = curr_address;
236 }
237
238 static long
239 get_current_offset (struct cfi_info *info)
240 {
241   long current_offset = 0;
242   struct cfi_data *data = info->data;
243
244   current_offset = 0;
245   while (data)
246     {
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];
251       data = data->next;
252     }
253
254   return current_offset;
255 }
256
257 static void
258 cfi_make_insn (int arg)
259 {
260   long param[2] = { 0, 0 };
261
262   if (!cfi_info)
263     {
264       as_bad (_("CFI instruction used without previous .cfi_startproc"));
265       return;
266     }
267
268   cfi_advance_loc ();
269
270   switch (arg)
271     {
272       /* Instructions that take two arguments (register, integer). */
273     case CFA_offset:
274     case CFA_def_cfa:
275       if (cfi_parse_reg (&param[0]) < 0)
276         {
277           as_bad (_("first argument to %s is not a register"),
278                   cfi_insn_str (arg));
279           return;
280         }
281       if (cfi_parse_const (&param[1]) < 0)
282         {
283           as_bad (_("second argument to %s is not a number"),
284                   cfi_insn_str (arg));
285           return;
286         }
287       break;
288
289     case CFA_register:
290       if (cfi_parse_reg (&param[0]) < 0)
291         {
292           as_bad (_("first argument to %s is not a register"),
293                   cfi_insn_str (arg));
294           return;
295         }
296       if (cfi_parse_reg (&param[1]) < 0)
297         {
298           as_bad (_("second argument to %s is not a register"),
299                   cfi_insn_str (arg));
300           return;
301         }
302       break;
303
304       /* Instructions that take one register argument.  */
305     case CFA_def_cfa_register:
306       if (cfi_parse_reg (&param[0]) < 0)
307         {
308           as_bad (_("argument to %s is not a register"), cfi_insn_str (arg));
309           return;
310         }
311       break;
312
313       /* Instructions that take one integer argument.  */
314     case CFA_def_cfa_offset:
315       if (cfi_parse_const (&param[0]) < 0)
316         {
317           as_bad (_("argument to %s is not a number"), cfi_insn_str (arg));
318           return;
319         }
320       break;
321
322       /* Special handling for pseudo-instruction.  */
323     case CFI_adjust_cfa_offset:
324       if (cfi_parse_const (&param[0]) < 0)
325         {
326           as_bad (_("argument to %s is not a number"),
327                     ".cfi_adjust_cfa_offset");
328           return;
329         }
330       param[0] += get_current_offset (cfi_info);
331       arg = CFA_def_cfa_offset;
332       break;
333
334     default:
335       as_bad (_("unknown CFI instruction %d (%s)"), arg, cfi_insn_str (arg));
336       return;
337     }
338   cfi_add_insn (arg, param[0], param[1]);
339 }
340
341 static symbolS *
342 cfi_get_label (void)
343 {
344   char symname[40], *symbase=".Llbl_cfi";
345   symbolS *symbolP;
346   unsigned int i = 0;
347
348   snprintf (symname, sizeof (symname), "%s_0x%lx",
349             symbase, (long) frag_now_fix ());
350   while ((symbolP = symbol_find (symname)))
351     {
352       if ((S_GET_VALUE (symbolP) == frag_now_fix ())
353           && (S_GET_SEGMENT (symbolP) == now_seg))
354         return symbolP;
355
356       snprintf (symname, sizeof (symname), "%s_0x%lx_%u",
357                 symbase, (long) frag_now_fix (), i++);
358     }
359 #ifdef BFD_ASSEMBLER
360   symbolP = (symbolS *) local_symbol_make (symname, now_seg,
361                                            (valueT) frag_now_fix (),
362                                            frag_now);
363 #else
364   symbolP = symbol_make (symname);
365 #endif
366   return symbolP;
367 }
368
369 static void
370 dot_cfi_startproc (void)
371 {
372 #ifdef tc_cfi_frame_initial_instructions
373   const char *simple = "simple";
374 #endif
375
376   if (cfi_info)
377     {
378       as_bad (_("previous CFI entry not closed (missing .cfi_endproc)"));
379       return;
380     }
381
382 #if defined(TARGET_USE_CFIPOP)
383   /* Because this file is linked even for architectures that 
384      don't use CFI, we must wrap this call.  */
385   if (current_config.addr_length == 0)
386     tc_cfi_init ();
387 #endif
388
389   cfi_info = alloc_cfi_info ();
390
391   cfi_info->start_address = frag_now_fix ();
392   cfi_info->last_address = cfi_info->start_address;
393   cfi_info->labelname = S_GET_NAME (cfi_get_label ());
394
395   SKIP_WHITESPACE ();
396 #ifdef tc_cfi_frame_initial_instructions
397   if (strncmp (simple, input_line_pointer, strlen (simple)) != 0)
398     tc_cfi_frame_initial_instructions ();
399   else
400     input_line_pointer += strlen (simple);
401 #endif
402 }
403
404 #define cfi_is_advance_insn(insn)                               \
405   ((insn >= CFA_set_loc && insn <= CFA_advance_loc4)            \
406    || insn == CFA_advance_loc)
407
408 /* Output CFI instructions to the file.  */
409
410 enum data_types
411   {
412     t_ascii = 0,
413     t_byte = 1,
414     t_half = 2,
415     t_long = 4,
416     t_quad = 8,
417     t_uleb128 = 0x10,
418     t_sleb128 = 0x11
419   };
420
421 static int
422 output_data (char **p, unsigned long *size, enum data_types type, long value)
423 {
424   char *ptr = *p;
425   unsigned int ret_size;
426
427   switch (type)
428     {
429     case t_byte:
430       ret_size = 1;
431       break;
432     case t_half:
433       ret_size = 2;
434       break;
435     case t_long:
436       ret_size = 4;
437       break;
438     case t_quad:
439     case t_uleb128:
440     case t_sleb128:
441       ret_size = 8;
442       break;
443     default:
444       /* This should never happen - throw an internal error.  */
445       as_fatal (_("unknown type %d"), type);
446       return 0;
447     }
448
449   if (*size < ret_size)
450     {
451       as_bad (_("output_data buffer is too small"));
452       return 0;
453     }
454
455   switch (type)
456     {
457     case t_byte:
458       *ptr = (char) value;
459       if (verbose)
460         printf ("\t.byte\t0x%x\n", (unsigned char) *ptr);
461       break;
462     case t_half:
463       *(short *) ptr = (short) value & 0xFFFF;
464       if (verbose)
465         printf ("\t.half\t0x%x\n", (unsigned short) *ptr);
466       break;
467     case t_long:
468       *(int *) ptr = (int) value & 0xFFFFFFFF;
469       if (verbose)
470         printf ("\t.long\t0x%x\n", (unsigned int) *ptr);
471       break;
472     case t_quad:
473       *(long long *) ptr = (long long) value & 0xFFFFFFFF;
474       if (verbose)
475         printf ("\t.quad\t0x%x\n", (unsigned int) *ptr);
476       break;
477     case t_uleb128:
478     case t_sleb128:
479       ret_size = output_leb128 (ptr, value, type == t_sleb128);
480       if (verbose)
481         printf ("\t.%s\t0x%lx\n",
482                 type == t_sleb128 ? "sleb128" : "uleb128",
483                 value);
484       break;
485     default:
486       as_fatal (_("unknown type %d"), type);
487       return 0;
488     }
489
490   *size -= ret_size;
491   *p += ret_size;
492
493   return ret_size;
494 }
495
496 static int
497 cfi_output_insn (struct cfi_data *data, char **buf, unsigned long *buf_size)
498 {
499   char **pbuf = buf, *orig_buf = *buf;
500   unsigned long size;
501
502   if (!data || !buf)
503     as_fatal (_("cfi_output_insn called with NULL pointer"));
504
505   switch (data->insn)
506     {
507     case CFA_advance_loc:
508       if (verbose)
509         printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
510                 data->param[0]);
511       if (data->param[0] <= 0x3F)
512         {
513           output_data (pbuf, buf_size, t_byte, CFA_advance_loc +
514                        (data->param[0] / current_config.code_align));
515         }
516       else if (data->param[0] <= 0xFF)
517         {
518           output_data (pbuf, buf_size, t_byte, CFA_advance_loc1);
519           output_data (pbuf, buf_size, t_byte,
520                        data->param[0] / current_config.code_align);
521         }
522       else if (data->param[0] <= 0xFFFF)
523         {
524           output_data (pbuf, buf_size, t_byte, CFA_advance_loc2);
525           output_data (pbuf, buf_size, t_half,
526                        data->param[0] / current_config.code_align);
527         }
528       else
529         {
530           output_data (pbuf, buf_size, t_byte, CFA_advance_loc4);
531           output_data (pbuf, buf_size, t_long,
532                        data->param[0] / current_config.code_align);
533         }
534       break;
535
536     case CFA_def_cfa:
537       if (verbose)
538         printf ("\t# CFA_def_cfa(%ld,%ld)\n",
539                 data->param[0], data->param[1]);
540       output_data (pbuf, buf_size, t_byte, CFA_def_cfa);
541       output_data (pbuf, buf_size, t_uleb128, data->param[0]);
542       output_data (pbuf, buf_size, t_uleb128, data->param[1]);
543       break;
544
545     case CFA_def_cfa_register:
546     case CFA_def_cfa_offset:
547       if (verbose)
548         printf ("\t# %s(%ld)\n", cfi_insn_str (data->insn),
549                 data->param[0]);
550       output_data (pbuf, buf_size, t_byte, data->insn);
551       output_data (pbuf, buf_size, t_uleb128, data->param[0]);
552       break;
553
554     case CFA_offset:
555       if (verbose)
556         printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data->insn),
557                 data->param[0], data->param[1]);
558
559       /* Check whether to use CFA_offset or CFA_offset_extended.  */
560       if (data->param[0] <= 0x3F)
561         output_data (pbuf, buf_size, t_byte, CFA_offset + data->param[0]);
562       else
563         {
564           output_data (pbuf, buf_size, t_byte, CFA_offset_extended);
565           output_data (pbuf, buf_size, t_uleb128, data->param[0]);
566         }
567       output_data (pbuf, buf_size, t_uleb128,
568                    data->param[1] / current_config.data_align);
569       break;
570
571     case CFA_register:
572       if (verbose)
573         printf ("\t# %s(%ld,%ld)\n", cfi_insn_str (data->insn),
574                 data->param[0], data->param[1]);
575       output_data (pbuf, buf_size, t_byte, CFA_register);
576       output_data (pbuf, buf_size, t_uleb128, data->param[0]);
577       output_data (pbuf, buf_size, t_uleb128, data->param[1]);
578       break;
579
580     case CFA_nop:
581       if (verbose)
582         printf ("\t# CFA_nop\n");
583       output_data (pbuf, buf_size, t_byte, CFA_nop);
584       break;
585
586     default:
587       as_warn ("CFA_unknown[%d](%ld,%ld)", data->insn,
588                data->param[0], data->param[1]);
589     }
590   size = *pbuf - orig_buf;
591   *buf = *pbuf;
592   *buf_size -= size;
593   return size;
594 }
595
596 static void
597 dot_cfi_endproc (void)
598 {
599   struct cfi_data *data_ptr;
600   struct cie_entry *cie_ptr;
601   char *cie_buf, *fde_buf, *pbuf, *where;
602   unsigned long buf_size, cie_size, fde_size, last_cie_offset;
603   unsigned long fde_initloc_offset, fde_len_offset, fde_offset;
604   segT saved_seg, cfi_seg;
605   expressionS exp;
606
607   if (! cfi_info)
608     {
609       as_bad (_(".cfi_endproc without corresponding .cfi_startproc"));
610       return;
611     }
612   cfi_info->end_address = frag_now_fix ();
613
614   /* Open .eh_frame section.  */
615   saved_seg = now_seg;
616   cfi_seg = subseg_new (".eh_frame", 0);
617 #ifdef BFD_ASSEMBLER
618   bfd_set_section_flags (stdoutput, cfi_seg,
619                          SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
620 #endif
621   subseg_set (cfi_seg, 0);
622
623   /* Build CIE.  */
624   cie_buf = xcalloc (1024, 1);
625   /* Skip space for CIE length.  */
626   pbuf = cie_buf + 4;
627   buf_size = 1020;
628
629   if (verbose)
630     printf ("# CIE *****\n");
631
632   /* CIE id.  */
633   output_data (&pbuf, &buf_size, t_long, 0x0);
634   /* Version.  */
635   output_data (&pbuf, &buf_size, t_byte, 1);
636   /* Augmentation.  */
637   output_data (&pbuf, &buf_size, t_byte, 0);
638   /* Code alignment.  */
639   output_data (&pbuf, &buf_size, t_uleb128, current_config.code_align);
640   /* Data alignment.  */
641   output_data (&pbuf, &buf_size, t_sleb128, current_config.data_align);
642   /* Return address column.  */
643   output_data (&pbuf, &buf_size, t_byte, current_config.ra_column);
644
645   /* Build CFI instructions.  */
646   data_ptr = cfi_info->data;
647   while (data_ptr && !cfi_is_advance_insn (data_ptr->insn))
648     {
649       cfi_output_insn (data_ptr, &pbuf, &buf_size);
650       data_ptr = data_ptr->next;
651     }
652
653   /* Align the whole data to current_config.eh_align.  */
654   cie_size = pbuf - cie_buf;
655   cie_size += current_config.eh_align - cie_size % current_config.eh_align;
656
657   /* CIE length.  */
658   pbuf = cie_buf;
659   output_data (&pbuf, &buf_size, t_long, cie_size - 4);
660
661   /* OK, we built the CIE. Let's write it to the file...  */
662   last_cie_offset = frag_now_fix ();
663
664   /* Check if we have already emitted the exactly same CIE. 
665      If yes then use its offset instead and don't put out 
666      the new one.  */
667   cie_ptr = cie_root;
668   while (cie_ptr)
669     {
670       if (cie_ptr->size == cie_size - 4
671           && memcmp (cie_ptr->data, cie_buf + 4, cie_ptr->size) == 0)
672         break;
673       cie_ptr = cie_ptr->next;
674     }
675
676   /* If we have found the same CIE, use it...  */
677   if (cie_ptr)
678     {
679       if (verbose)
680         printf ("# Duplicate CIE found. Previous is at offset %lu\n",
681                 cie_ptr->offset);
682       last_cie_offset = cie_ptr->offset;
683     }
684   else
685     {
686       /* Otherwise join this CIE to the list.  */
687       where = (unsigned char *) frag_more (cie_size);
688       memcpy (where, cie_buf, cie_size);
689       if (cie_root)
690         {
691           cie_ptr = cie_root;
692           while (cie_ptr->next)
693             cie_ptr = cie_ptr->next;
694           cie_ptr->next = calloc (sizeof (struct cie_entry), 1);
695           cie_ptr = cie_ptr->next;
696         }
697       else
698         {
699           cie_root = calloc (sizeof (struct cie_entry), 1);
700           cie_ptr = cie_root;
701         }
702
703       cie_ptr->size = cie_size - 4;
704       cie_ptr->data = calloc (cie_ptr->size, 1);
705       cie_ptr->offset = last_cie_offset;
706       memcpy (cie_ptr->data, cie_buf + 4, cie_ptr->size);
707     }
708
709   /* Clean up.  */
710   free (cie_buf);
711
712   /* Build the FDE...  */
713   fde_buf = xcalloc (1024, 1);
714   pbuf = fde_buf;
715   buf_size = 1024;
716
717   /* Offset of this FDE in current fragment.  */
718   fde_offset = frag_now_fix ();
719
720   if (verbose)
721     {
722       printf ("# FDE: start=0x%lx, end=0x%lx, delta=%d\n",
723               (long) cfi_info->start_address,
724               (long) cfi_info->end_address,
725               (int) (cfi_info->end_address - cfi_info->start_address));
726     }
727
728   /* FDE length (t_long, 4 bytes) - will be set later.  */
729   fde_len_offset = pbuf - fde_buf;
730   pbuf += 4;
731   buf_size -= 4;
732
733   /* CIE pointer - offset from here.  */
734   output_data (&pbuf, &buf_size, t_long, fde_offset - last_cie_offset + 4);
735
736   /* FDE initial location - this must be set relocatable!  */
737   fde_initloc_offset = pbuf - fde_buf + fde_offset;
738   output_data (&pbuf, &buf_size, current_config.addr_length,
739                cfi_info->start_address);
740
741   /* FDE address range.  */
742   output_data (&pbuf, &buf_size, current_config.addr_length,
743                cfi_info->end_address - cfi_info->start_address);
744
745   while (data_ptr)
746     {
747       cfi_output_insn (data_ptr, &pbuf, &buf_size);
748       data_ptr = data_ptr->next;
749     }
750
751   fde_size = pbuf - fde_buf;
752   fde_size += current_config.eh_align - fde_size % current_config.eh_align;
753
754   /* Now we can set FDE length.  */
755   pbuf = fde_buf + fde_len_offset;
756   buf_size = 4;
757   output_data (&pbuf, &buf_size, t_long, fde_size - 4);
758
759   /* Copy FDE to objfile.  */
760   where = (unsigned char *) frag_more (fde_size);
761   memcpy (where, fde_buf, fde_size);
762
763   /* Set relocation for initial address.  */
764   buf_size = current_config.addr_length;
765   memset (&exp, 0, sizeof (exp));
766   exp.X_op = O_symbol;
767   exp.X_add_symbol = symbol_find (cfi_info->labelname);
768   fix_new_exp (frag_now, fde_initloc_offset,
769                current_config.addr_length,
770                &exp, 0, current_config.reloc_type);
771
772   /* Clean up.  */
773   free (fde_buf);
774
775   free (cfi_info);
776   cfi_info = NULL;
777
778   /* Restore previous segment.  */
779   subseg_set (saved_seg, 0);
780 }
781
782 void
783 dot_cfi (int arg)
784 {
785   long param;
786
787   switch (arg)
788     {
789     case CFI_startproc:
790       dot_cfi_startproc ();
791       break;
792     case CFI_endproc:
793       dot_cfi_endproc ();
794       break;
795     case CFA_def_cfa:
796     case CFA_def_cfa_register:
797     case CFA_def_cfa_offset:
798     case CFA_offset:
799     case CFA_register:
800     case CFI_adjust_cfa_offset:
801       cfi_make_insn (arg);
802       break;
803     case CFI_verbose:
804       if (cfi_parse_const (&param) >= 0)
805         verbose = (int) param;
806       else
807         verbose = 1;
808       break;
809     default:
810       as_bad (_("unknown CFI code 0x%x (%s)"), arg, cfi_insn_str (arg));
811       break;
812     }
813   ignore_rest_of_line ();
814 }
815
816 void
817 cfi_set_config (struct cfi_config *cfg)
818 {
819   assert (cfg != NULL);
820   assert (cfg->addr_length > 0);
821
822   current_config = *cfg;
823 }
824
825 void
826 cfi_finish (void)
827 {
828   if (cfi_info)
829     as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
830 }